diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h index fc0375b75533fcb8b9b9c17d30522ace09905d7d..0b875ed6881014f9adcd3beb327d3fb2f5fc3d52 100644 --- a/bolt/include/bolt/Core/BinaryFunction.h +++ b/bolt/include/bolt/Core/BinaryFunction.h @@ -386,6 +386,9 @@ private: /// Raw branch count for this function in the profile. uint64_t RawBranchCount{0}; + /// Dynamically executed function bytes, used for density computation. + uint64_t SampleCountInBytes{0}; + /// Indicates the type of profile the function is using. uint16_t ProfileFlags{PF_NONE}; @@ -1844,6 +1847,9 @@ public: /// to this function. void setRawBranchCount(uint64_t Count) { RawBranchCount = Count; } + /// Return the number of dynamically executed bytes, from raw perf data. + uint64_t getSampleCountInBytes() const { return SampleCountInBytes; } + /// Return the execution count for functions with known profile. /// Return 0 if the function has no profile. uint64_t getKnownExecutionCount() const { diff --git a/bolt/include/bolt/Utils/CommandLineOpts.h b/bolt/include/bolt/Utils/CommandLineOpts.h index baabeab577fb5e439ac28468bf98511cbd4ac5eb..04bf7db5de9527f7c4f08b2b7de4b2653568a9eb 100644 --- a/bolt/include/bolt/Utils/CommandLineOpts.h +++ b/bolt/include/bolt/Utils/CommandLineOpts.h @@ -55,6 +55,7 @@ extern llvm::cl::opt PrintSections; enum ProfileFormatKind { PF_Fdata, PF_YAML }; extern llvm::cl::opt ProfileFormat; +extern llvm::cl::opt ShowDensity; extern llvm::cl::opt SplitEH; extern llvm::cl::opt StrictMode; extern llvm::cl::opt TimeOpts; diff --git a/bolt/lib/Passes/BinaryPasses.cpp b/bolt/lib/Passes/BinaryPasses.cpp index fa95ad7324ac1cda944c386df94deabe72dbb007..5a676185227ec1b00112ea847268928d983bcafc 100644 --- a/bolt/lib/Passes/BinaryPasses.cpp +++ b/bolt/lib/Passes/BinaryPasses.cpp @@ -15,6 +15,7 @@ #include "bolt/Core/ParallelUtilities.h" #include "bolt/Passes/ReorderAlgorithm.h" #include "bolt/Passes/ReorderFunctions.h" +#include "bolt/Utils/CommandLineOpts.h" #include "llvm/Support/CommandLine.h" #include #include @@ -223,6 +224,18 @@ static cl::opt TopCalledLimit( "functions section"), cl::init(100), cl::Hidden, cl::cat(BoltCategory)); +// Profile density options, synced with llvm-profgen/ProfileGenerator.cpp +static cl::opt ProfileDensityCutOffHot( + "profile-density-cutoff-hot", cl::init(990000), + cl::desc("Total samples cutoff for functions used to calculate " + "profile density.")); + +static cl::opt ProfileDensityThreshold( + "profile-density-threshold", cl::init(60), + cl::desc("If the profile density is below the given threshold, it " + "will be suggested to increase the sampling rate."), + cl::Optional); + } // namespace opts namespace llvm { @@ -1383,6 +1396,7 @@ Error PrintProgramStats::runOnFunctions(BinaryContext &BC) { uint64_t StaleSampleCount = 0; uint64_t InferredSampleCount = 0; std::vector ProfiledFunctions; + std::vector> FuncDensityList; const char *StaleFuncsHeader = "BOLT-INFO: Functions with stale profile:\n"; for (auto &BFI : BC.getBinaryFunctions()) { const BinaryFunction &Function = BFI.second; @@ -1441,6 +1455,22 @@ Error PrintProgramStats::runOnFunctions(BinaryContext &BC) { StaleSampleCount += SampleCount; ++NumAllStaleFunctions; } + + if (opts::ShowDensity) { + uint64_t Size = Function.getSize(); + // In case of BOLT split functions registered in BAT, executed traces are + // automatically attributed to the main fragment. Add up function sizes + // for all fragments. + if (IsHotParentOfBOLTSplitFunction) + for (const BinaryFunction *Fragment : Function.getFragments()) + Size += Fragment->getSize(); + double Density = (double)1.0 * Function.getSampleCountInBytes() / Size; + FuncDensityList.emplace_back(Density, SampleCount); + LLVM_DEBUG(BC.outs() << Function << ": executed bytes " + << Function.getSampleCountInBytes() << ", size (b) " + << Size << ", density " << Density + << ", sample count " << SampleCount << '\n'); + } } BC.NumProfiledFuncs = ProfiledFunctions.size(); BC.NumStaleProfileFuncs = NumStaleProfileFunctions; @@ -1684,6 +1714,50 @@ Error PrintProgramStats::runOnFunctions(BinaryContext &BC) { BC.outs() << ". Use -print-unknown to see the list."; BC.outs() << '\n'; } + + if (opts::ShowDensity) { + double Density = 0.0; + // Sorted by the density in descending order. + llvm::stable_sort(FuncDensityList, + [&](const std::pair &A, + const std::pair &B) { + if (A.first != B.first) + return A.first > B.first; + return A.second < B.second; + }); + + uint64_t AccumulatedSamples = 0; + uint32_t I = 0; + assert(opts::ProfileDensityCutOffHot <= 1000000 && + "The cutoff value is greater than 1000000(100%)"); + while (AccumulatedSamples < + TotalSampleCount * + static_cast(opts::ProfileDensityCutOffHot) / + 1000000 && + I < FuncDensityList.size()) { + AccumulatedSamples += FuncDensityList[I].second; + Density = FuncDensityList[I].first; + I++; + } + if (Density == 0.0) { + BC.errs() << "BOLT-WARNING: the output profile is empty or the " + "--profile-density-cutoff-hot option is " + "set too low. Please check your command.\n"; + } else if (Density < opts::ProfileDensityThreshold) { + BC.errs() + << "BOLT-WARNING: BOLT is estimated to optimize better with " + << format("%.1f", opts::ProfileDensityThreshold / Density) + << "x more samples. Please consider increasing sampling rate or " + "profiling for longer duration to get more samples.\n"; + } + + BC.outs() << "BOLT-INFO: Functions with density >= " + << format("%.1f", Density) << " account for " + << format("%.2f", + static_cast(opts::ProfileDensityCutOffHot) / + 10000) + << "% total sample counts.\n"; + } return Error::success(); } diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index 0a63148379d9006c09c727f481c9dc16bd76b15f..ffd693f9bbaed480935f328b366691809a1aebff 100644 --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -638,8 +638,12 @@ void DataAggregator::processProfile(BinaryContext &BC) { : BinaryFunction::PF_LBR; for (auto &BFI : BC.getBinaryFunctions()) { BinaryFunction &BF = BFI.second; - if (getBranchData(BF) || getFuncSampleData(BF.getNames())) + FuncBranchData *FBD = getBranchData(BF); + if (FBD || getFuncSampleData(BF.getNames())) { BF.markProfiled(Flags); + if (FBD) + BF.RawBranchCount = FBD->getNumExecutedBranches(); + } } for (auto &FuncBranches : NamesToBranches) @@ -845,6 +849,12 @@ bool DataAggregator::doTrace(const LBREntry &First, const LBREntry &Second, return false; } + // Set ParentFunc to BAT parent function or FromFunc itself. + BinaryFunction *ParentFunc = getBATParentFunction(*FromFunc); + if (!ParentFunc) + ParentFunc = FromFunc; + ParentFunc->SampleCountInBytes += Count * (Second.From - First.To); + std::optional FTs = BAT ? BAT->getFallthroughsInTrace(FromFunc->getAddress(), First.To, Second.From) @@ -864,13 +874,12 @@ bool DataAggregator::doTrace(const LBREntry &First, const LBREntry &Second, << FromFunc->getPrintName() << ":" << Twine::utohexstr(First.To) << " to " << Twine::utohexstr(Second.From) << ".\n"); - BinaryFunction *ParentFunc = getBATParentFunction(*FromFunc); for (auto [From, To] : *FTs) { if (BAT) { From = BAT->translate(FromFunc->getAddress(), From, /*IsBranchSrc=*/true); To = BAT->translate(FromFunc->getAddress(), To, /*IsBranchSrc=*/false); } - doIntraBranch(ParentFunc ? *ParentFunc : *FromFunc, From, To, Count, false); + doIntraBranch(*ParentFunc, From, To, Count, false); } return true; diff --git a/bolt/lib/Utils/CommandLineOpts.cpp b/bolt/lib/Utils/CommandLineOpts.cpp index 435a8fa9cafcaedf46ae0a3ca577878cdd71c862..de82420a1671310628467bc23e8eb61d208f5640 100644 --- a/bolt/lib/Utils/CommandLineOpts.cpp +++ b/bolt/lib/Utils/CommandLineOpts.cpp @@ -175,6 +175,10 @@ cl::opt SaveProfile("w", cl::desc("save recorded profile to a file"), cl::cat(BoltOutputCategory)); +cl::opt ShowDensity("show-density", + cl::desc("show profile density details"), + cl::Optional, cl::cat(AggregatorCategory)); + cl::opt SplitEH("split-eh", cl::desc("split C++ exception handling code"), cl::Hidden, cl::cat(BoltOptCategory)); diff --git a/bolt/test/X86/pre-aggregated-perf.test b/bolt/test/X86/pre-aggregated-perf.test index 90252f9ff68daa066b95b7a8735cdc1526fea27c..cf745ca7bf7b62a643952ae02ca71db2f37e409e 100644 --- a/bolt/test/X86/pre-aggregated-perf.test +++ b/bolt/test/X86/pre-aggregated-perf.test @@ -11,7 +11,21 @@ REQUIRES: system-linux RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe RUN: perf2bolt %t.exe -o %t --pa -p %p/Inputs/pre-aggregated.txt -w %t.new \ -RUN: --profile-use-dfs | FileCheck %s +RUN: --show-density \ +RUN: --profile-density-threshold=9 --profile-density-cutoff-hot=970000 \ +RUN: --profile-use-dfs | FileCheck %s --check-prefix=CHECK-P2B + +CHECK-P2B: BOLT-INFO: 4 out of 7 functions in the binary (57.1%) have non-empty execution profile +CHECK-P2B: BOLT-INFO: Functions with density >= 21.7 account for 97.00% total sample counts. + +RUN: perf2bolt %t.exe -o %t --pa -p %p/Inputs/pre-aggregated.txt -w %t.new \ +RUN: --show-density \ +RUN: --profile-density-cutoff-hot=970000 \ +RUN: --profile-use-dfs 2>&1 | FileCheck %s --check-prefix=CHECK-WARNING + +CHECK-WARNING: BOLT-INFO: 4 out of 7 functions in the binary (57.1%) have non-empty execution profile +CHECK-WARNING: BOLT-WARNING: BOLT is estimated to optimize better with 2.8x more samples. +CHECK-WARNING: BOLT-INFO: Functions with density >= 21.7 account for 97.00% total sample counts. RUN: llvm-bolt %t.exe -data %t -o %t.null | FileCheck %s RUN: llvm-bolt %t.exe -data %t.new -o %t.null | FileCheck %s diff --git a/bolt/tools/driver/llvm-bolt.cpp b/bolt/tools/driver/llvm-bolt.cpp index a8d1ac6480893001917c84e7275c97dea2fa3cab..efa06cd68cb997df116b5c09292c08a9f5b6eb9c 100644 --- a/bolt/tools/driver/llvm-bolt.cpp +++ b/bolt/tools/driver/llvm-bolt.cpp @@ -129,6 +129,7 @@ void perf2boltMode(int argc, char **argv) { exit(1); } opts::AggregateOnly = true; + opts::ShowDensity = true; } void boltDiffMode(int argc, char **argv) { diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index 9120c4b6c0d9ae9016d6e0f3fea45c17dae70ff3..33ac65e715ce811ad9b23c47b366654a1bd5b1cc 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -49,6 +49,7 @@ #include "MultipleStatementMacroCheck.h" #include "NoEscapeCheck.h" #include "NonZeroEnumToBoolConversionCheck.h" +#include "NondeterministicPointerIterationOrderCheck.h" #include "NotNullTerminatedResultCheck.h" #include "OptionalValueConversionCheck.h" #include "ParentVirtualCallCheck.h" @@ -174,6 +175,8 @@ public: "bugprone-multiple-new-in-one-expression"); CheckFactories.registerCheck( "bugprone-multiple-statement-macro"); + CheckFactories.registerCheck( + "bugprone-nondeterministic-pointer-iteration-order"); CheckFactories.registerCheck( "bugprone-optional-value-conversion"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index f0667bbfdd87f7f4542ac11c7a1a84fad4a938a4..b0a2318acc05970cf7979e312412f2773c92420e 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -45,6 +45,7 @@ add_clang_library(clangTidyBugproneModule STATIC MultipleNewInOneExpressionCheck.cpp MultipleStatementMacroCheck.cpp NoEscapeCheck.cpp + NondeterministicPointerIterationOrderCheck.cpp NonZeroEnumToBoolConversionCheck.cpp NotNullTerminatedResultCheck.cpp OptionalValueConversionCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/NondeterministicPointerIterationOrderCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/NondeterministicPointerIterationOrderCheck.cpp new file mode 100644 index 0000000000000000000000000000000000000000..22ecd689614696fa2df07be0cb9a4b51a3735ca4 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/NondeterministicPointerIterationOrderCheck.cpp @@ -0,0 +1,78 @@ +//===----- NondeterministicPointerIterationOrderCheck.cpp - clang-tidy ----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "NondeterministicPointerIterationOrderCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +void NondeterministicPointerIterationOrderCheck::registerMatchers( + MatchFinder *Finder) { + + auto LoopVariable = varDecl(hasType( + qualType(hasCanonicalType(anyOf(referenceType(), pointerType()))))); + + auto RangeInit = declRefExpr(to(varDecl( + hasType(recordDecl(hasAnyName("std::unordered_set", "std::unordered_map", + "std::unordered_multiset", + "std::unordered_multimap")) + .bind("recorddecl"))))); + + Finder->addMatcher(cxxForRangeStmt(hasLoopVariable(LoopVariable), + hasRangeInit(RangeInit.bind("rangeinit"))) + .bind("cxxForRangeStmt"), + this); + + auto SortFuncM = callee(functionDecl(hasAnyName( + "std::is_sorted", "std::nth_element", "std::sort", "std::partial_sort", + "std::partition", "std::stable_partition", "std::stable_sort"))); + + auto IteratesPointerEltsM = hasArgument( + 0, + cxxMemberCallExpr(on(hasType(cxxRecordDecl(has(fieldDecl(hasType(qualType( + hasCanonicalType(pointsTo(hasCanonicalType(pointerType())))))))))))); + + Finder->addMatcher( + callExpr(allOf(SortFuncM, IteratesPointerEltsM)).bind("sortsemantic"), + this); +} + +void NondeterministicPointerIterationOrderCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *ForRangePointers = + Result.Nodes.getNodeAs("cxxForRangeStmt"); + + if ((ForRangePointers) && !(ForRangePointers->getBeginLoc().isMacroID())) { + const auto *RangeInit = Result.Nodes.getNodeAs("rangeinit"); + if (const auto *ClassTemplate = + Result.Nodes.getNodeAs( + "recorddecl")) { + const TemplateArgumentList &TemplateArgs = + ClassTemplate->getTemplateArgs(); + const bool IsAlgoArgPointer = + TemplateArgs[0].getAsType()->isPointerType(); + + if (IsAlgoArgPointer) { + SourceRange R = RangeInit->getSourceRange(); + diag(R.getBegin(), "iteration of pointers is nondeterministic") << R; + } + } + return; + } + const auto *SortPointers = Result.Nodes.getNodeAs("sortsemantic"); + + if ((SortPointers) && !(SortPointers->getBeginLoc().isMacroID())) { + SourceRange R = SortPointers->getSourceRange(); + diag(R.getBegin(), "sorting pointers is nondeterministic") << R; + } +} + +} // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/NondeterministicPointerIterationOrderCheck.h b/clang-tools-extra/clang-tidy/bugprone/NondeterministicPointerIterationOrderCheck.h new file mode 100644 index 0000000000000000000000000000000000000000..698872fefca90424cd1e2a8b2edafe2597ce3aa2 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/NondeterministicPointerIterationOrderCheck.h @@ -0,0 +1,39 @@ +//=== NondeterministicPointerIterationOrderCheck.h - clang-tidy -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_NONDETERMINISTIC_POINTER_ITERATION_ORDER_CHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_NONDETERMINISTIC_POINTER_ITERATION_ORDER_CHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::bugprone { + +/// Finds nondeterministic usages of pointers in unordered containers. The +/// check also finds calls to sorting-like algorithms on a container of +/// pointers. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/nondeterministic-pointer-iteration-order.html +class NondeterministicPointerIterationOrderCheck : public ClangTidyCheck { +public: + NondeterministicPointerIterationOrderCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + std::optional getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } +}; + +} // namespace clang::tidy::bugprone + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_NONDETERMINISTIC_POINTER_ITERATION_ORDER_CHECK_H diff --git a/clang-tools-extra/clang-tidy/readability/ContainerContainsCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerContainsCheck.cpp index 05d4c87bc73cef9b49501bf74267eb8155cf4b4d..fb68c7d334b7f8ace5a0635db9c637c74dfe8f23 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerContainsCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerContainsCheck.cpp @@ -62,44 +62,44 @@ void ContainerContainsCheck::registerMatchers(MatchFinder *Finder) { .bind("positiveComparison"), this); AddSimpleMatcher( - binaryOperator(hasOperatorName("!="), hasOperands(CountCall, Literal0)) + binaryOperation(hasOperatorName("!="), hasOperands(CountCall, Literal0)) .bind("positiveComparison")); AddSimpleMatcher( - binaryOperator(hasLHS(CountCall), hasOperatorName(">"), hasRHS(Literal0)) + binaryOperation(hasLHS(CountCall), hasOperatorName(">"), hasRHS(Literal0)) .bind("positiveComparison")); AddSimpleMatcher( - binaryOperator(hasLHS(Literal0), hasOperatorName("<"), hasRHS(CountCall)) - .bind("positiveComparison")); - AddSimpleMatcher( - binaryOperator(hasLHS(CountCall), hasOperatorName(">="), hasRHS(Literal1)) - .bind("positiveComparison")); - AddSimpleMatcher( - binaryOperator(hasLHS(Literal1), hasOperatorName("<="), hasRHS(CountCall)) + binaryOperation(hasLHS(Literal0), hasOperatorName("<"), hasRHS(CountCall)) .bind("positiveComparison")); + AddSimpleMatcher(binaryOperation(hasLHS(CountCall), hasOperatorName(">="), + hasRHS(Literal1)) + .bind("positiveComparison")); + AddSimpleMatcher(binaryOperation(hasLHS(Literal1), hasOperatorName("<="), + hasRHS(CountCall)) + .bind("positiveComparison")); // Find inverted membership tests which use `count()`. AddSimpleMatcher( - binaryOperator(hasOperatorName("=="), hasOperands(CountCall, Literal0)) - .bind("negativeComparison")); - AddSimpleMatcher( - binaryOperator(hasLHS(CountCall), hasOperatorName("<="), hasRHS(Literal0)) - .bind("negativeComparison")); - AddSimpleMatcher( - binaryOperator(hasLHS(Literal0), hasOperatorName(">="), hasRHS(CountCall)) + binaryOperation(hasOperatorName("=="), hasOperands(CountCall, Literal0)) .bind("negativeComparison")); + AddSimpleMatcher(binaryOperation(hasLHS(CountCall), hasOperatorName("<="), + hasRHS(Literal0)) + .bind("negativeComparison")); + AddSimpleMatcher(binaryOperation(hasLHS(Literal0), hasOperatorName(">="), + hasRHS(CountCall)) + .bind("negativeComparison")); AddSimpleMatcher( - binaryOperator(hasLHS(CountCall), hasOperatorName("<"), hasRHS(Literal1)) + binaryOperation(hasLHS(CountCall), hasOperatorName("<"), hasRHS(Literal1)) .bind("negativeComparison")); AddSimpleMatcher( - binaryOperator(hasLHS(Literal1), hasOperatorName(">"), hasRHS(CountCall)) + binaryOperation(hasLHS(Literal1), hasOperatorName(">"), hasRHS(CountCall)) .bind("negativeComparison")); // Find membership tests based on `find() == end()`. AddSimpleMatcher( - binaryOperator(hasOperatorName("!="), hasOperands(FindCall, EndCall)) + binaryOperation(hasOperatorName("!="), hasOperands(FindCall, EndCall)) .bind("positiveComparison")); AddSimpleMatcher( - binaryOperator(hasOperatorName("=="), hasOperands(FindCall, EndCall)) + binaryOperation(hasOperatorName("=="), hasOperands(FindCall, EndCall)) .bind("negativeComparison")); } diff --git a/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp b/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp index 1cb95c2b2347b7655ea32137e7eb9be01d22327f..e0b9939681794f70689ad5523031bee30ce2804a 100644 --- a/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp @@ -123,6 +123,13 @@ AST_MATCHER(EnumDecl, hasSequentialInitialValues) { return !AllEnumeratorsArePowersOfTwo; } +std::string getName(const EnumDecl *Decl) { + if (!Decl->getDeclName()) + return ""; + + return Decl->getQualifiedNameAsString(); +} + } // namespace EnumInitialValueCheck::EnumInitialValueCheck(StringRef Name, @@ -160,10 +167,11 @@ void EnumInitialValueCheck::registerMatchers(MatchFinder *Finder) { void EnumInitialValueCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *Enum = Result.Nodes.getNodeAs("inconsistent")) { DiagnosticBuilder Diag = - diag(Enum->getBeginLoc(), - "initial values in enum %0 are not consistent, consider explicit " - "initialization of all, none or only the first enumerator") - << Enum; + diag( + Enum->getBeginLoc(), + "initial values in enum '%0' are not consistent, consider explicit " + "initialization of all, none or only the first enumerator") + << getName(Enum); for (const EnumConstantDecl *ECD : Enum->enumerators()) if (ECD->getInitExpr() == nullptr) { const SourceLocation EndLoc = Lexer::getLocForEndOfToken( @@ -183,16 +191,16 @@ void EnumInitialValueCheck::check(const MatchFinder::MatchResult &Result) { if (Loc.isInvalid() || Loc.isMacroID()) return; DiagnosticBuilder Diag = diag(Loc, "zero initial value for the first " - "enumerator in %0 can be disregarded") - << Enum; + "enumerator in '%0' can be disregarded") + << getName(Enum); cleanInitialValue(Diag, ECD, *Result.SourceManager, getLangOpts()); return; } if (const auto *Enum = Result.Nodes.getNodeAs("sequential")) { DiagnosticBuilder Diag = diag(Enum->getBeginLoc(), - "sequential initial value in %0 can be ignored") - << Enum; + "sequential initial value in '%0' can be ignored") + << getName(Enum); for (const EnumConstantDecl *ECD : llvm::drop_begin(Enum->enumerators())) cleanInitialValue(Diag, ECD, *Result.SourceManager, getLangOpts()); return; diff --git a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp index 968a4a55a6d79888fa84bb580b9635a47f7df733..f9fd1d903e231e1550f7097280506293313d947e 100644 --- a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp @@ -10,6 +10,7 @@ #include "../utils/FixItHintUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Lex/Lexer.h" #include "clang/Tooling/FixIt.h" #include @@ -26,6 +27,8 @@ AST_MATCHER(Stmt, isMacroExpansion) { return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc); } +AST_MATCHER(Stmt, isC23) { return Finder->getASTContext().getLangOpts().C23; } + bool isNULLMacroExpansion(const Stmt *Statement, ASTContext &Context) { SourceManager &SM = Context.getSourceManager(); const LangOptions &LO = Context.getLangOpts(); @@ -298,6 +301,11 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) { hasCastKind(CK_FloatingToBoolean), hasCastKind(CK_PointerToBoolean), hasCastKind(CK_MemberPointerToBoolean)), + // Exclude cases of C23 comparison result. + unless(allOf(isC23(), + hasSourceExpression(ignoringParens( + binaryOperator(hasAnyOperatorName( + ">", ">=", "==", "!=", "<", "<=")))))), // Exclude case of using if or while statements with variable // declaration, e.g.: // if (int var = functionCall()) {} diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 9afe497fb3d8bf07ab9dbf8951f0062cc7e0792f..54118e5f92f417348c3e8b158036b0915fade943 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -119,6 +119,12 @@ New checks Warns about code that tries to cast between pointers by means of ``std::bit_cast`` or ``memcpy``. +- New :doc:`bugprone-nondeterministic-pointer-iteration-order + ` + check. + + Finds nondeterministic usages of pointers in unordered containers. + - New :doc:`bugprone-tagged-union-member-count ` check. @@ -238,17 +244,20 @@ Changes in existing checks - Improved :doc:`readability-container-contains ` check to let it work on - any class that has a ``contains`` method. + any class that has a ``contains`` method. Fix some false negatives in the + ``find()`` case. - Improved :doc:`readability-enum-initial-value ` check by only issuing - diagnostics for the definition of an ``enum``, and by fixing a typo in the + diagnostics for the definition of an ``enum``, by not emitting a redundant + file path for anonymous enums in the diagnostic, and by fixing a typo in the diagnostic. - Improved :doc:`readability-implicit-bool-conversion ` check by adding the option `UseUpperCaseLiteralSuffix` to select the - case of the literal suffix in fixes. + case of the literal suffix in fixes and fixing false positive for implicit + conversion of comparison result in C23. - Improved :doc:`readability-redundant-smartptr-get ` check to diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/nondeterministic-pointer-iteration-order.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/nondeterministic-pointer-iteration-order.rst new file mode 100644 index 0000000000000000000000000000000000000000..41be0bf1c677ec55579a85aa3dbd1dc3f0ecec11 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/nondeterministic-pointer-iteration-order.rst @@ -0,0 +1,44 @@ +.. title:: clang-tidy - bugprone-nondeterministic-pointer-iteration-order + +bugprone-nondeterministic-pointer-iteration-order +================================================= + +Finds nondeterministic usages of pointers in unordered containers. + +One canonical example is iteration across a container of pointers. + +.. code-block:: c++ + + { + int a = 1, b = 2; + std::unordered_set UnorderedPtrSet = {&a, &b}; + for (auto i : UnorderedPtrSet) + f(i); + } + +Another such example is sorting a container of pointers. + +.. code-block:: c++ + + { + int a = 1, b = 2; + std::vector VectorOfPtr = {&a, &b}; + std::sort(VectorOfPtr.begin(), VectorOfPtr.end()); + } + +Iteration of a containers of pointers may present the order of different +pointers differently across different runs of a program. In some cases this +may be acceptable behavior, in others this may be unexpected behavior. This +check is advisory for this reason. + +This check only detects range-based for loops over unordered sets and maps. It +also detects calls sorting-like algorithms on containers holding pointers. +Other similar usages will not be found and are false negatives. + +Limitations: + +* This check currently does not check if a nondeterministic iteration order is + likely to be a mistake, and instead marks all such iterations as bugprone. +* std::reference_wrapper is not considered yet. +* Only for loops are considered, other iterators can be included in + improvements. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 0082234f5ed31bd5827c0354909685d7e4c19aac..d731b13fc0df4469e846949a1394d47ab3d40427 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -115,6 +115,7 @@ Clang-Tidy Checks :doc:`bugprone-multiple-new-in-one-expression `, :doc:`bugprone-multiple-statement-macro `, :doc:`bugprone-no-escape `, + :doc:`bugprone-nondeterministic-pointer-iteration-order `, :doc:`bugprone-non-zero-enum-to-bool-conversion `, :doc:`bugprone-not-null-terminated-result `, "Yes" :doc:`bugprone-optional-value-conversion `, "Yes" diff --git a/clang-tools-extra/modularize/CoverageChecker.cpp b/clang-tools-extra/modularize/CoverageChecker.cpp index 0e76c539aa3c839f87de6058c7115ca7d3af6afb..b536ee00497c03fe75246877c795b074a251007f 100644 --- a/clang-tools-extra/modularize/CoverageChecker.cpp +++ b/clang-tools-extra/modularize/CoverageChecker.cpp @@ -223,10 +223,9 @@ bool CoverageChecker::collectModuleHeaders(const Module &Mod) { return false; } - for (auto &HeaderKind : Mod.Headers) - for (auto &Header : HeaderKind) - ModuleMapHeadersSet.insert( - ModularizeUtilities::getCanonicalPath(Header.Entry.getName())); + for (const auto &Header : Mod.getAllHeaders()) + ModuleMapHeadersSet.insert( + ModularizeUtilities::getCanonicalPath(Header.Entry.getName())); for (auto *Submodule : Mod.submodules()) collectModuleHeaders(*Submodule); diff --git a/clang-tools-extra/modularize/ModularizeUtilities.cpp b/clang-tools-extra/modularize/ModularizeUtilities.cpp index b202b3aae8f8a3a5488bb019a30553ef3fa0df2e..476e13770a94f6c7692ffc9fa8c1ffa6b9d45edb 100644 --- a/clang-tools-extra/modularize/ModularizeUtilities.cpp +++ b/clang-tools-extra/modularize/ModularizeUtilities.cpp @@ -358,7 +358,7 @@ bool ModularizeUtilities::collectModuleHeaders(const clang::Module &Mod) { } else if (std::optional UmbrellaDir = Mod.getUmbrellaDirAsWritten()) { // If there normal headers, assume these are umbrellas and skip collection. - if (Mod.Headers->size() == 0) { + if (Mod.getHeaders(Module::HK_Normal).empty()) { // Collect headers in umbrella directory. if (!collectUmbrellaHeaders(UmbrellaDir->Entry.getName(), UmbrellaDependents)) @@ -371,16 +371,8 @@ bool ModularizeUtilities::collectModuleHeaders(const clang::Module &Mod) { // modules or because they are meant to be included by another header, // and thus should be ignored by modularize. - int NormalHeaderCount = Mod.Headers[clang::Module::HK_Normal].size(); - - for (int Index = 0; Index < NormalHeaderCount; ++Index) { - DependentsVector NormalDependents; - // Collect normal header. - const clang::Module::Header &Header( - Mod.Headers[clang::Module::HK_Normal][Index]); - std::string HeaderPath = getCanonicalPath(Header.Entry.getName()); - HeaderFileNames.push_back(HeaderPath); - } + for (const auto &Header : Mod.getHeaders(clang::Module::HK_Normal)) + HeaderFileNames.push_back(getCanonicalPath(Header.Entry.getName())); int MissingCountThisModule = Mod.MissingHeaders.size(); diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_algorithm b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_algorithm new file mode 100644 index 0000000000000000000000000000000000000000..6dbca55a8e365fffd0b1cf8db99e361b09657bce --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_algorithm @@ -0,0 +1,31 @@ +#ifndef _SIM_ALGORITHM +#define _SIM_ALGORITHM + +#pragma clang system_header + +namespace std { + +template +bool is_sorted(ForwardIt first, ForwardIt last); + +template +void nth_element(RandomIt first, RandomIt nth, RandomIt last); + +template +void partial_sort(RandomIt first, RandomIt middle, RandomIt last); + +template +void sort (RandomIt first, RandomIt last); + +template +void stable_sort(RandomIt first, RandomIt last); + +template +BidirIt partition(BidirIt first, BidirIt last, UnaryPredicate p); + +template +BidirIt stable_partition(BidirIt first, BidirIt last, UnaryPredicate p); + +} // namespace std + +#endif // _SIM_ALGORITHM diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_c++config.h b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_c++config.h new file mode 100644 index 0000000000000000000000000000000000000000..ba98e0cc2208babf392b1fa2d8a0177e001bafe7 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_c++config.h @@ -0,0 +1,11 @@ +#ifndef _SIM_CPP_CONFIG_H +#define _SIM_CPP_CONFIG_H + +#pragma clang system_header + +typedef unsigned char uint8_t; + +typedef __typeof__(sizeof(int)) size_t; +typedef __typeof__((char*)0-(char*)0) ptrdiff_t; + +#endif // _SIM_CPP_CONFIG_H diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_initializer_list b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_initializer_list new file mode 100644 index 0000000000000000000000000000000000000000..e4d9d534b3bd78c1faf28645b37c7c32af6d14d1 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_initializer_list @@ -0,0 +1,39 @@ +#ifndef _INITIALIZER_LIST +#define _INITIALIZER_LIST + +#pragma clang system_header +# +#include "sim_c++config.h" // size_t + +namespace std { + +template +class initializer_list { + const _E* __begin_; + size_t __size_; + + initializer_list(const _E* __b, size_t __s) + : __begin_(__b), + __size_(__s) + {} + +public: + typedef _E value_type; + typedef const _E& reference; + typedef const _E& const_reference; + typedef size_t size_type; + + typedef const _E* iterator; + typedef const _E* const_iterator; + + initializer_list() : __begin_(0), __size_(0) {} + + size_t size() const {return __size_;} + const _E* begin() const {return __begin_;} + const _E* end() const {return __begin_ + __size_;} + +}; // class initializer_list + +} // namespace std + +#endif // _INITIALIZER_LIST diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_iterator_base b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_iterator_base new file mode 100644 index 0000000000000000000000000000000000000000..3b205d1722c9ddc4a121b541595061ac9533bf48 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_iterator_base @@ -0,0 +1,22 @@ +#ifndef _SIM_ITERATOR_BASE +#define _SIM_ITERATOR_BASE + +namespace std { + +struct input_iterator_tag { }; +struct output_iterator_tag { }; +struct forward_iterator_tag : public input_iterator_tag { }; +struct bidirectional_iterator_tag : public forward_iterator_tag { }; +struct random_access_iterator_tag : public bidirectional_iterator_tag { }; + +template struct iterator_traits { + typedef typename Iterator::difference_type difference_type; + typedef typename Iterator::value_type value_type; + typedef typename Iterator::pointer pointer; + typedef typename Iterator::reference reference; + typedef typename Iterator::iterator_category iterator_category; +}; + +} // namespace std + +#endif // _SIM_ITERATOR_BASE diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_map b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_map new file mode 100644 index 0000000000000000000000000000000000000000..8c57f5c71f8814ac671d37ee6009369c8fcb9c7b --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_map @@ -0,0 +1,34 @@ + +#ifndef _SIM_MAP +#define _SIM_MAP + +#pragma clang system_header +#include "sim_stl_pair" + +namespace std { + +template +class map { + public: + using value_type = pair; + map(); + map(initializer_list> initList); + value_type& operator[](const Key& key); + value_type& operator[](Key&& key); + class iterator { + public: + iterator(Key *key): ptr(key) {} + iterator& operator++() { ++ptr; return *this; } + bool operator!=(const iterator &other) const { return ptr != other.ptr; } + const Key &operator*() const { return *ptr; } + private: + Key *ptr; + }; + Key *val; + iterator begin() const { return iterator(val); } + iterator end() const { return iterator(val + 1); } +}; + +} // namespace std + +#endif // _SIM_MAP diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_set b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_set new file mode 100644 index 0000000000000000000000000000000000000000..f2f70095538925b9af5285bd1ac3393acb8d56f6 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_set @@ -0,0 +1,44 @@ + +#ifndef _SIM_SET +#define _SIM_SET + +#pragma clang system_header +#include "sim_initializer_list" + +namespace std { + +template< class T = void > +struct less; + +template< class T > +struct allocator; + +template< class Key > +struct hash; + +template< + class Key, + class Compare = std::less, + class Alloc = std::allocator +> class set { + public: + set(initializer_list __list) {} + + class iterator { + public: + iterator(Key *key): ptr(key) {} + iterator& operator++() { ++ptr; return *this; } + bool operator!=(const iterator &other) const { return ptr != other.ptr; } + const Key &operator*() const { return *ptr; } + private: + Key *ptr; + }; + + Key *val; + iterator begin() const { return iterator(val); } + iterator end() const { return iterator(val + 1); } +}; + +} // namespace std + +#endif // _SIM_SET diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_stl_pair b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_stl_pair new file mode 100644 index 0000000000000000000000000000000000000000..d244bb363b861a094f96bdcf5b7273c02678463e --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_stl_pair @@ -0,0 +1,32 @@ +#ifndef _SIM_STL_PAIR +#define _SIM_STL_PAIR + +#pragma clang system_header + +#include "sim_type_traits" + +namespace std { + +template +struct pair { + T1 first; + T2 second; + + pair() : first(), second() {} + pair(const T1 &a, const T2 &b) : first(a), second(b) {} + + template + pair(const pair &other) : first(other.first), + second(other.second) {} +}; + +template +pair::type, typename remove_reference::type> +make_pair(T1 &&, T2 &&) { + return {}; +}; + +} // namespace std + +#endif // _SIM_STL_PAIR + diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_type_traits b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_type_traits new file mode 100644 index 0000000000000000000000000000000000000000..f066767c4d985895e7fe371d32cf2d3c19744dee --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_type_traits @@ -0,0 +1,19 @@ + +#ifndef _SIM_TYPE_TRAITS +#define _SIM_TYPE_TRAITS + +#pragma clang system_header +namespace std { + +template< class T > struct remove_reference {typedef T type;}; +template< class T > struct remove_reference {typedef T type;}; +template< class T > struct remove_reference {typedef T type;}; + +template typename remove_reference::type&& move(T&& a); + +template< class T > +using remove_reference_t = typename remove_reference::type; + +} // namespace std + +#endif // _SIM_TYPE_TRAITS diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_unordered_map b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_unordered_map new file mode 100644 index 0000000000000000000000000000000000000000..fabd8e7fd2d748668e128cdf2f356901663c434e --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_unordered_map @@ -0,0 +1,33 @@ +#ifndef _SIM_UNORDERED_MAP +#define _SIM_UNORDERED_MAP + +#pragma clang system_header +#include "sim_initializer_list" + +namespace std { + +template +class unordered_map { +public: + using value_type = pair; + unordered_map(); + unordered_map(initializer_list> initList); + value_type& operator[](const Key& key); + value_type& operator[](Key&& key); + class iterator { + public: + iterator(Key *key): ptr(key) {} + iterator& operator++() { ++ptr; return *this; } + bool operator!=(const iterator &other) const { return ptr != other.ptr; } + const Key &operator*() const { return *ptr; } + private: + Key *ptr; + }; + Key *val; + iterator begin() const { return iterator(val); } + iterator end() const { return iterator(val + 1); } +}; + +} // namespace std + +#endif // _SIM_UNORDERED_MAP diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_unordered_set b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_unordered_set new file mode 100644 index 0000000000000000000000000000000000000000..a077507bbdcbcb1b40571e5cbc1595148870b64f --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_unordered_set @@ -0,0 +1,35 @@ +#ifndef _SIM_UNORDERED_SET +#define _SIM_UNORDERED_SET + +#pragma clang system_header +#include "sim_initializer_list" + +namespace std { + +template< + class Key, + class Hash = std::hash, + class Compare = std::less, + class Alloc = std::allocator +> class unordered_set { + public: + unordered_set(initializer_list __list) {} + + class iterator { + public: + iterator(Key *key): ptr(key) {} + iterator& operator++() { ++ptr; return *this; } + bool operator!=(const iterator &other) const { return ptr != other.ptr; } + const Key &operator*() const { return *ptr; } + private: + Key *ptr; + }; + + Key *val; + iterator begin() const { return iterator(val); } + iterator end() const { return iterator(val + 1); } +}; + +} // namespace std + +#endif // _SIM_UNORDERED_SET diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_vector b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_vector new file mode 100644 index 0000000000000000000000000000000000000000..dfa9abfb8863ecce49158693aa44a3835f315160 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/system-header-simulator/sim_vector @@ -0,0 +1,150 @@ +#ifndef _SIM_VECTOR +#define _SIM_VECTOR + +#pragma clang system_header + +#include "sim_iterator_base" + +namespace std { + +template struct __vector_iterator { + typedef __vector_iterator iterator; + typedef __vector_iterator const_iterator; + + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef Ptr pointer; + typedef Ref reference; + typedef std::random_access_iterator_tag iterator_category; + + __vector_iterator(const Ptr p = 0) : ptr(p) {} + __vector_iterator(const iterator &rhs): ptr(rhs.base()) {} + __vector_iterator& operator++() { ++ ptr; return *this; } + __vector_iterator operator++(int) { + auto tmp = *this; + ++ ptr; + return tmp; + } + __vector_iterator operator--() { -- ptr; return *this; } + __vector_iterator operator--(int) { + auto tmp = *this; -- ptr; + return tmp; + } + __vector_iterator operator+(difference_type n) { + return ptr + n; + } + friend __vector_iterator operator+( + difference_type n, + const __vector_iterator &iter) { + return n + iter.ptr; + } + __vector_iterator operator-(difference_type n) { + return ptr - n; + } + __vector_iterator operator+=(difference_type n) { + return ptr += n; + } + __vector_iterator operator-=(difference_type n) { + return ptr -= n; + } + + template + difference_type operator-(const __vector_iterator &rhs); + + Ref operator*() const { return *ptr; } + Ptr operator->() const { return ptr; } + + Ref operator[](difference_type n) { + return *(ptr+n); + } + + bool operator==(const iterator &rhs) const { return ptr == rhs.ptr; } + bool operator==(const const_iterator &rhs) const { return ptr == rhs.ptr; } + + bool operator!=(const iterator &rhs) const { return ptr != rhs.ptr; } + bool operator!=(const const_iterator &rhs) const { return ptr != rhs.ptr; } + + const Ptr& base() const { return ptr; } + +private: + Ptr ptr; +}; + +template +class vector { + T *_start; + T *_finish; + T *_end_of_storage; + +public: + typedef T value_type; + typedef size_t size_type; + typedef __vector_iterator iterator; + typedef __vector_iterator const_iterator; + + vector() : _start(0), _finish(0), _end_of_storage(0) {} + template + vector(InputIterator first, InputIterator last); + vector(const vector &other); + vector(vector &&other); + ~vector(); + + size_t size() const { + return size_t(_finish - _start); + } + + vector& operator=(const vector &other); + vector& operator=(vector &&other); + vector& operator=(std::initializer_list ilist); + + void assign(size_type count, const T &value); + template + void assign(InputIterator first, InputIterator last); + void assign(std::initializer_list ilist); + + void clear(); + + void push_back(const T &value); + void push_back(T &&value); + template + void emplace_back(Args&&... args); + void pop_back(); + + iterator insert(const_iterator position, const value_type &val); + iterator insert(const_iterator position, size_type n, + const value_type &val); + template + iterator insert(const_iterator position, InputIterator first, + InputIterator last); + iterator insert(const_iterator position, value_type &&val); + iterator insert(const_iterator position, initializer_list il); + + template + iterator emplace(const_iterator position, Args&&... args); + + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + + T &operator[](size_t n) { + return _start[n]; + } + + const T &operator[](size_t n) const { + return _start[n]; + } + + iterator begin() { return iterator(_start); } + const_iterator begin() const { return const_iterator(_start); } + const_iterator cbegin() const { return const_iterator(_start); } + iterator end() { return iterator(_finish); } + const_iterator end() const { return const_iterator(_finish); } + const_iterator cend() const { return const_iterator(_finish); } + T& front() { return *begin(); } + const T& front() const { return *begin(); } + T& back() { return *(end() - 1); } + const T& back() const { return *(end() - 1); } +}; + +} // namespace std + +#endif // _SIM_VECTOR diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/nondeterministic-pointer-iteration-order.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/nondeterministic-pointer-iteration-order.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91853874d0afc91f5e661dd64d3e33a1ee2a834e --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/nondeterministic-pointer-iteration-order.cpp @@ -0,0 +1,84 @@ +// RUN: %check_clang_tidy %s bugprone-nondeterministic-pointer-iteration-order %t -- -- -I%S -std=c++!4 + +#include "Inputs/system-header-simulator/sim_set" +#include "Inputs/system-header-simulator/sim_unordered_set" +#include "Inputs/system-header-simulator/sim_map" +#include "Inputs/system-header-simulator/sim_unordered_map" +#include "Inputs/system-header-simulator/sim_vector" +#include "Inputs/system-header-simulator/sim_algorithm" + +template +void f(T x); + +void PointerIteration() { + int a = 1, b = 2; + std::set OrderedIntSet = {a, b}; + std::set OrderedPtrSet = {&a, &b}; + std::unordered_set UnorderedIntSet = {a, b}; + std::unordered_set UnorderedPtrSet = {&a, &b}; + std::map IntMap = { std::make_pair(a,a), std::make_pair(b,b) }; + std::map PtrMap = { std::make_pair(&a,&a), std::make_pair(&b,&b) }; + std::unordered_map IntUnorderedMap = { std::make_pair(a,a), std::make_pair(b,b) }; + std::unordered_map PtrUnorderedMap = { std::make_pair(&a,&a), std::make_pair(&b,&b) }; + + for (auto i : OrderedIntSet) // no-warning + f(i); + + for (auto i : OrderedPtrSet) // no-warning + f(i); + + for (auto i : UnorderedIntSet) // no-warning + f(i); + + for (auto i : UnorderedPtrSet) + f(i); + // CHECK-MESSAGES: :[[@LINE-2]]:17: warning: iteration of pointers is nondeterministic + + for (auto &i : UnorderedPtrSet) + f(i); + // CHECK-MESSAGES: :[[@LINE-2]]:18: warning: iteration of pointers is nondeterministic + + for (auto &i : IntMap) // no-warning + f(i); + + for (auto &i : PtrMap) // no-warning + f(i); + + for (auto &i : IntUnorderedMap) // no-warning + f(i); + + for (auto &i : PtrUnorderedMap) + f(i); + // CHECK-MESSAGES: :[[@LINE-2]]:18: warning: iteration of pointers is nondeterministic +} + +bool g (int *x) { return true; } +bool h (int x) { return true; } + +void PointerSorting() { + int a = 1, b = 2, c = 3; + std::vector V1 = {a, b}; + std::vector V2 = {&a, &b}; + + std::is_sorted(V1.begin(), V1.end()); // no-warning + std::nth_element(V1.begin(), V1.begin() + 1, V1.end()); // no-warning + std::partial_sort(V1.begin(), V1.begin() + 1, V1.end()); // no-warning + std::sort(V1.begin(), V1.end()); // no-warning + std::stable_sort(V1.begin(), V1.end()); // no-warning + std::partition(V1.begin(), V1.end(), h); // no-warning + std::stable_partition(V1.begin(), V1.end(), h); // no-warning + std::is_sorted(V2.begin(), V2.end()); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: sorting pointers is nondeterministic + std::nth_element(V2.begin(), V2.begin() + 1, V2.end()); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: sorting pointers is nondeterministic + std::partial_sort(V2.begin(), V2.begin() + 1, V2.end()); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: sorting pointers is nondeterministic + std::sort(V2.begin(), V2.end()); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: sorting pointers is nondeterministic + std::stable_sort(V2.begin(), V2.end()); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: sorting pointers is nondeterministic + std::partition(V2.begin(), V2.end(), g); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: sorting pointers is nondeterministic + std::stable_partition(V2.begin(), V2.end(), g); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: sorting pointers is nondeterministic +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/container-contains.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/container-contains.cpp index 9a9b233e07229bf4e8197282f5bbdf435e8cdbd3..f345b3e7768a8af905c4ebd766b9359c8f3bc255 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/container-contains.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/container-contains.cpp @@ -1,14 +1,19 @@ -// RUN: %check_clang_tidy -std=c++20-or-later %s readability-container-contains %t +// RUN: %check_clang_tidy -std=c++11-or-later %s readability-container-contains %t // Some *very* simplified versions of `map` etc. namespace std { template struct map { + struct iterator { + bool operator==(const iterator &Other) const; + bool operator!=(const iterator &Other) const; + }; + unsigned count(const Key &K) const; bool contains(const Key &K) const; - void *find(const Key &K); - void *end(); + iterator find(const Key &K); + iterator end(); }; template diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.c b/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.c index b9a34d0683d7f304ac7ea0236bf63db664e197e2..54108585f030f87ff185b412abc3431304267a2a 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.c +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.c @@ -53,6 +53,17 @@ enum EMacro2 { // CHECK-FIXES: EMacro2_c = 3, }; + +enum { + // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: initial values in enum '' are not consistent + // CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: initial values in enum '' are not consistent + EAnonymous_a = 1, + EAnonymous_b, + // CHECK-FIXES: EAnonymous_b = 2, + EAnonymous_c = 3, +}; + + enum EnumZeroFirstInitialValue { EnumZeroFirstInitialValue_0 = 0, // CHECK-MESSAGES-ENABLE: :[[@LINE-1]]:3: warning: zero initial value for the first enumerator in 'EnumZeroFirstInitialValue' can be disregarded @@ -114,4 +125,3 @@ enum WithFwdDeclSequential : int { EFS2 = 4, // CHECK-FIXES-ENABLE: EFS2 , }; - diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c b/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c index f3dc32c10d640ae4581946d50fa462c9ffa686f1..0b231d10adf8fc6b7cdb9ac850ad746f1d7faae6 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/implicit-bool-conversion.c @@ -304,6 +304,15 @@ void implicitConversionToBoolFromUnaryMinusAndZeroLiterals() { // CHECK-FIXES: functionTakingBool((-0.0) != 0.0); } +void ignoreImplicitCastToBoolForComparisonResult() { + bool boolFromComparison0 = 1 != 0; + bool boolFromComparison1 = 1 == 0; + bool boolFromComparison2 = 1 > 0; + bool boolFromComparison3 = 1 >= 0; + bool boolFromComparison4 = 1 < 0; + bool boolFromComparison5 = 1 <= 0; +} + void ignoreExplicitCastsToBool() { int integer = 10; bool boolComingFromInt = (bool)integer; diff --git a/clang/Maintainers.rst b/clang/Maintainers.rst index ee5334b02f7000a2b03d3b4e57d0e61066f72c6f..54690452681a608449367e569562ea8caab423d8 100644 --- a/clang/Maintainers.rst +++ b/clang/Maintainers.rst @@ -226,6 +226,12 @@ C++ conformance | hubert.reinterpretcast\@gmail.com (email), hubert.reinterpretcast (Phabricator), hubert-reinterpretcast (GitHub) +C++ Defect Reports +~~~~~~~~~~~~~~~~~~ +| Vlad Serebrennikov +| serebrennikov.vladislav\@gmail.com (email), Endilll (GitHub), Endill (Discord), Endill (Discourse) + + Objective-C/C++ conformance ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | John McCall @@ -244,6 +250,12 @@ OpenCL conformance | anastasia\@compiler-experts.com (email), Anastasia (Phabricator), AnastasiaStulova (GitHub) +OpenACC +~~~~~~~ +| Erich Keane +| ekeane\@nvidia.com (email), ErichKeane (Phabricator), erichkeane (GitHub) + + SYCL conformance ~~~~~~~~~~~~~~~~ | Alexey Bader diff --git a/clang/docs/AddressSanitizer.rst b/clang/docs/AddressSanitizer.rst index 76fdf559950599c50c5074b66e2e07c47a99e1af..d937cbfdf583c4b377c6e8be91997104fdda5874 100644 --- a/clang/docs/AddressSanitizer.rst +++ b/clang/docs/AddressSanitizer.rst @@ -26,7 +26,7 @@ Typical slowdown introduced by AddressSanitizer is **2x**. How to build ============ -Build LLVM/Clang with `CMake ` and enable +Build LLVM/Clang with `CMake `_ and enable the ``compiler-rt`` runtime. An example CMake configuration that will allow for the use/testing of AddressSanitizer: diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index f36a5472b7e17d64b011b96a95ef9d054e560d01..9ef1fd5f36d1d34119b813ed472dc6849c6eb199 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -4663,6 +4663,14 @@ the configuration (without a prefix: ``Auto``). **KeepEmptyLinesAtTheStartOfBlocks** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` This option is deprecated. See ``AtStartOfBlock`` of ``KeepEmptyLines``. +.. _KeepFormFeed: + +**KeepFormFeed** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ ` + Keep the form feed character if it's immediately preceded and followed by + a newline. Multiple form feeds and newlines within a whitespace range are + replaced with a single newline and form feed followed by the remaining + newlines. + .. _LambdaBodyIndentation: **LambdaBodyIndentation** (``LambdaBodyIndentationKind``) :versionbadge:`clang-format 13` :ref:`¶ ` diff --git a/clang/docs/FunctionEffectAnalysis.rst b/clang/docs/FunctionEffectAnalysis.rst new file mode 100644 index 0000000000000000000000000000000000000000..3f2c4db7bad0cb7a68ad1ae62a05a9417412042d --- /dev/null +++ b/clang/docs/FunctionEffectAnalysis.rst @@ -0,0 +1,535 @@ +======================== +Function Effect Analysis +======================== + +.. contents:: + :depth: 3 + :local: + + +Introduction +============ + +Clang Function Effect Analysis is a language extension which can warn about "unsafe" +constructs. The feature is currently tailored for the Performance Constraint attributes +``nonblocking`` and ``nonallocating``; functions with these attributes are verified as not +containing any language constructs or calls to other functions which violate the constraint. +(See :doc:`AttributeReference`.) + + +The ``nonblocking`` and ``nonallocating`` attributes +==================================================== + +Attribute syntax +---------------- + +The ``nonblocking`` and ``nonallocating`` attributes apply to function types, allowing them to be +attached to functions, blocks, function pointers, lambdas, and member functions. + +.. code-block:: c++ + + // Functions + void nonblockingFunction() [[clang::nonblocking]]; + void nonallocatingFunction() [[clang::nonallocating]]; + + // Function pointers + void (*nonblockingFunctionPtr)() [[clang::nonblocking]]; + + // Typedefs, type aliases. + typedef void (*NBFunctionPtrTypedef)() [[clang::nonblocking]]; + using NBFunctionPtrTypeAlias_gnu = __attribute__((nonblocking)) void (*)(); + using NBFunctionPtrTypeAlias_std = void (*)() [[clang::nonblocking]]; + + // C++ methods + struct Struct { + void NBMethod() [[clang::nonblocking]]; + }; + + // C++ lambdas + auto nbLambda = []() [[clang::nonblocking]] {}; + + // Blocks + void (^nbBlock)() = ^() [[clang::nonblocking]] {}; + +The attribute applies only to the function itself. In particular, it does not apply to any nested +functions or declarations, such as blocks, lambdas, and local classes. + +This document uses the C++/C23 syntax ``[[clang::nonblocking]]``, since it parallels the placement +of the ``noexcept`` specifier, and the attributes have other similarities to ``noexcept``. The GNU +``__attribute__((nonblocking))`` syntax is also supported. Note that it requires a different +placement on a C++ type alias. + +Like ``noexcept``, ``nonblocking`` and ``nonallocating`` have an optional argument, a compile-time +constant boolean expression. By default, the argument is ``true``, so ``[[clang::nonblocking]]`` +is equivalent to ``[[clang::nonblocking(true)]]``, and declares the function type as never blocking. + + +Attribute semantics +------------------- + +Together with ``noexcept``, the ``nonallocating`` and ``nonblocking`` attributes define an ordered +series of performance constraints. From weakest to strongest: + +- ``noexcept`` (as per the C++ standard): The function type will never throw an exception. +- ``nonallocating``: The function type will never allocate memory on the heap or throw an + exception. +- ``nonblocking``: The function type will never block on a lock, allocate memory on the heap, + or throw an exception. + +``nonblocking`` includes the ``nonallocating`` guarantee. + +While ``nonblocking`` and ``nonallocating`` are conceptually a superset of ``noexcept``, neither +attribute implicitly specifies ``noexcept``. Further, ``noexcept`` has a specified runtime behavior of +aborting if an exception is thrown, while the ``nonallocating`` and ``nonblocking`` attributes are +mainly for compile-time analysis and have no runtime behavior, except in code built +with Clang's :doc:`RealtimeSanitizer`. Nonetheless, Clang emits a +warning if, in C++, a function is declared ``nonblocking`` or ``nonallocating`` without +``noexcept``. This diagnostic is controlled by ``-Wperf-constraint-implies-noexcept``. + +``nonblocking(true)`` and ``nonallocating(true)`` apply to function *types*, and by extension, to +function-like declarations. When applied to a declaration with a body, the compiler verifies the +function, as described in the section "Analysis and warnings", below. + +``blocking`` and ``allocating`` are synonyms for ``nonblocking(false)`` and +``nonallocating(false)``, respectively. They can be used on a function-like declaration to +explicitly disable any potential inference of ``nonblocking`` or ``nonallocating`` during +verification. (Inference is described later in this document). ``nonblocking(false)`` and +``nonallocating(false)`` are legal, but superfluous when applied to a function *type* +that is not part of a declarator: ``float (int) [[nonblocking(false)]]`` and +``float (int)`` are identical types. + +For functions with no explicit performance constraint, the worst is assumed: the function +allocates memory and potentially blocks, unless it can be inferred otherwise. This is detailed in the +discussion of verification. + +The following example describes the meanings of all permutations of the two attributes and arguments: + +.. code-block:: c++ + + void nb1_na1() [[clang::nonblocking(true)]] [[clang::nonallocating(true)]]; + // Valid; nonallocating(true) is superfluous but doesn't contradict the guarantee. + + void nb1_na0() [[clang::nonblocking(true)]] [[clang::nonallocating(false)]]; + // error: 'allocating' and 'nonblocking' attributes are not compatible + + void nb0_na1() [[clang::nonblocking(false)]] [[clang::nonallocating(true)]]; + // Valid; the function does not allocate memory, but may lock for other reasons. + + void nb0_na0() [[clang::nonblocking(false)]] [[clang::nonallocating(false)]]; + // Valid. + + +Type conversions +---------------- + +A performance constraint can be removed or weakened via an implicit conversion. An attempt to add +or strengthen a performance constraint is unsafe and results in a warning. The rules for this +are comparable to that for ``noexcept`` in C++17 and later. + +.. code-block:: c++ + + void unannotated(); + void nonblocking() [[clang::nonblocking]]; + void nonallocating() [[clang::nonallocating]]; + + void example() + { + // It's fine to remove a performance constraint. + void (*fp_plain)(); + fp_plain = unannotated; + fp_plain = nonblocking; + fp_plain = nonallocating; + + // Adding/spoofing nonblocking is unsafe. + void (*fp_nonblocking)() [[clang::nonblocking]]; + fp_nonblocking = nullptr; + fp_nonblocking = nonblocking; + fp_nonblocking = unannotated; + // ^ warning: attribute 'nonblocking' should not be added via type conversion + fp_nonblocking = nonallocating; + // ^ warning: attribute 'nonblocking' should not be added via type conversion + + // Adding/spoofing nonallocating is unsafe. + void (*fp_nonallocating)() [[clang::nonallocating]]; + fp_nonallocating = nullptr; + fp_nonallocating = nonallocating; + fp_nonallocating = nonblocking; // no warning because nonblocking includes nonallocating + fp_nonallocating = unannotated; + // ^ warning: attribute 'nonallocating' should not be added via type conversion + } + +Virtual methods +--------------- + +In C++, when a virtual method has a performance constraint, overriding methods in +subclasses inherit the constraint. + +.. code-block:: c++ + + struct Base { + virtual void unsafe(); + virtual void safe() noexcept [[clang::nonblocking]]; + }; + + struct Derived : public Base { + void unsafe() [[clang::nonblocking]] override; + // It's okay for an overridden method to be more constrained + + void safe() noexcept override; + // This method is implicitly declared `nonblocking`, inherited from Base. + }; + +Redeclarations, overloads, and name mangling +-------------------------------------------- + +The ``nonblocking`` and ``nonallocating`` attributes, like ``noexcept``, do not factor into +argument-dependent lookup and overloaded functions/methods. + +First, consider that ``noexcept`` is integral to a function's type: + +.. code-block:: c++ + + void f1(int); + void f1(int) noexcept; + // error: exception specification in declaration does not match previous + // declaration + +Unlike ``noexcept``, a redeclaration of ``f2`` with an added or stronger performance constraint is +legal and propagates the attribute to the previous declaration: + +.. code-block:: c++ + + int f2(); + int f2() [[clang::nonblocking]]; // redeclaration with stronger constraint is OK. + +This greatly eases adoption by making it possible to annotate functions in external libraries +without modifying library headers. + +A redeclaration with a removed or weaker performance constraint produces a warning, paralleling +the behavior of ``noexcept``: + +.. code-block:: c++ + + int f2() { return 42; } + // warning: attribute 'nonblocking' on function does not match previous declaration + +In C++14, the following two declarations of `f3` are identical (a single function). In C++17 they +are separate overloads: + +.. code-block:: c++ + + void f3(void (*)()); + void f3(void (*)() noexcept); + +Similarly, the following two declarations of `f4` are separate overloads. This pattern may pose +difficulties due to ambiguity: + +.. code-block:: c++ + + void f4(void (*)()); + void f4(void (*)() [[clang::nonblocking]]); + +The attributes have no effect on the mangling of function and method names. + +Objective-C +----------- + +The attributes are currently unsupported on Objective-C methods. + +Analysis and warnings +===================== + +Constraints +----------- + +Functions declared ``nonallocating`` or ``nonblocking``, when defined, are verified according to the +following rules. Such functions: + +1. May not allocate or deallocate memory on the heap. The analysis follows the calls to + ``operator new`` and ``operator delete`` generated by the ``new`` and ``delete`` keywords, and + treats them like any other function call. The global ``operator new`` and ``operator delete`` + aren't declared ``nonblocking`` or ``nonallocating`` and so they are considered unsafe. (This + is correct because most memory allocators are not lock-free. Note that the placement form of + ``operator new`` is implemented inline in libc++'s ```` header, and is verifiably + ``nonblocking``, since it merely casts the supplied pointer to the result type.) + +2. May not throw or catch exceptions. To throw, the compiler must allocate the exception on the + heap. (Also, many subclasses of ``std::exception`` allocate a string). Exceptions are + deallocated when caught. + +3. May not make any indirect function call, via a virtual method, function pointer, or + pointer-to-member function, unless the target is explicitly declared with the same + ``nonblocking`` or ``nonallocating`` attribute (or stronger). + +4. May not make direct calls to any other function, with the following exceptions: + + a. The callee is also explicitly declared with the same ``nonblocking`` or ``nonallocating`` + attribute (or stronger). + b. The callee is defined in the same translation unit as the caller, does not have the ``false`` + form of the required attribute, and can be verified to have the same attribute or stronger, + according to these same rules. + c. The callee is a built-in function that is known not to block or allocate. + d. The callee is declared ``noreturn`` and, if compiling C++, the callee is also declared + ``noexcept``. This special case excludes functions such as ``abort()`` and ``std::terminate()`` + from the analysis. (The reason for requiring ``noexcept`` in C++ is that a function declared + ``noreturn`` could be a wrapper for ``throw``.) + +5. May not invoke or access an Objective-C method or property, since ``objc_msgSend()`` calls into + the Objective-C runtime, which may allocate memory or otherwise block. + +6. May not access thread-local variables. Typically, thread-local variables are allocated on the + heap when first accessed. + +Functions declared ``nonblocking`` have an additional constraint: + +7. May not declare static local variables (e.g. Meyers singletons). The compiler generates a lock + protecting the initialization of the variable. + +Violations of any of these rules result in warnings, in the ``-Wfunction-effects`` category: + +.. code-block:: c++ + + void notInline(); + + void example() [[clang::nonblocking]] + { + auto* x = new int; + // warning: function with 'nonblocking' attribute must not allocate or deallocate + // memory + + if (x == nullptr) { + static Logger* logger = createLogger(); + // warning: function with 'nonblocking' attribute must not have static local variables + + throw std::runtime_warning{ "null" }; + // warning: 'nonblocking" function 'example' must not throw exceptions + } + notInline(); + // warning: 'function with 'nonblocking' attribute must not call non-'nonblocking' function + // 'notInline' + // note (on notInline()): declaration cannot be inferred 'nonblocking' because it has no + // definition in this translation unit + } + +Inferring ``nonblocking`` or ``nonallocating`` +---------------------------------------------- + +In the absence of a ``nonblocking`` or ``nonallocating`` attribute (whether ``true`` or ``false``), +a function that is called from a performance-constrained function may be analyzed to +infer whether it has a desired attribute. This analysis happens when the function is not a virtual +method, and it has a visible definition within the current translation unit (i.e. its body can be +traversed). + +.. code-block:: c++ + + void notInline(); + int implicitlySafe() { return 42; } + void implicitlyUnsafe() { notInline(); } + + void example() [[clang::nonblocking]] + { + int x = implicitlySafe(); // OK + implicitlyUnsafe(); + // warning: function with 'nonblocking' attribute must not call non-'nonblocking' function + // 'implicitlyUnsafe' + // note (on implicitlyUnsafe): function cannot be inferred 'nonblocking' because it calls + // non-'nonblocking' function 'notInline' + // note (on notInline()): declaration cannot be inferred 'nonblocking' because it has no + // definition in this translation unit + } + +Lambdas and blocks +------------------ + +As mentioned earlier, the performance constraint attributes apply only to a single function and not +to any code nested inside it, including blocks, lambdas, and local classes. It is possible for a +nonblocking function to schedule the execution of a blocking lambda on another thread. Similarly, a +blocking function may create a ``nonblocking`` lambda for use in a realtime context. + +Operations which create, destroy, copy, and move lambdas and blocks are analyzed in terms of the +underlying function calls. For example, the creation of a lambda with captures generates a function +call to an anonymous struct's constructor, passing the captures as parameters. + +Implicit function calls in the AST +---------------------------------- + +The ``nonblocking`` / ``nonallocating`` analysis occurs at the Sema phase of analysis in Clang. +During Sema, there are some constructs which will eventually become function calls, but do not +appear as function calls in the AST. For example, ``auto* foo = new Foo;`` becomes a declaration +containing a ``CXXNewExpr`` which is understood as a function call to the global ``operator new`` +(in this example), and a ``CXXConstructExpr``, which, for analysis purposes, is a function call to +``Foo``'s constructor. Most gaps in the analysis would be due to incomplete knowledge of AST +constructs which become function calls. + +Disabling diagnostics +--------------------- + +Function effect diagnostics are controlled by ``-Wfunction-effects``. + +A construct like this can be used to exempt code from the checks described here: + +.. code-block:: c++ + + #define NONBLOCKING_UNSAFE(...) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wunknown-warning-option\"") \ + _Pragma("clang diagnostic ignored \"-Wfunction-effects\"") \ + __VA_ARGS__ \ + _Pragma("clang diagnostic pop") + +Disabling the diagnostic allows for: + +- constructs which do block, but which in practice are used in ways to avoid unbounded blocking, + e.g. a thread pool with semaphores to coordinate multiple realtime threads; +- using libraries which are safe but not yet annotated; +- incremental adoption in a large codebase. + +Adoption +======== + +There are a few common issues that arise when adopting the ``nonblocking`` and ``nonallocating`` +attributes. + +C++ exceptions +-------------- + +Exceptions pose a challenge to the adoption of the performance constraints. Common library functions +which throw exceptions include: + ++----------------------------------+-----------------------------------------------------------------------+ +| Method | Alternative | ++==================================+=======================================================================+ +| ``std::vector::at()`` | ``operator[](size_t)``, after verifying that the index is in range. | ++----------------------------------+-----------------------------------------------------------------------+ +| ``std::optional::value()`` | ``operator*``, after checking ``has_value()`` or ``operator bool()``. | ++----------------------------------+-----------------------------------------------------------------------+ +| ``std::expected::value()`` | Same as for ``std::optional::value()``. | ++----------------------------------+-----------------------------------------------------------------------+ + + +``std::function`` +----------------------------- + +``std::function`` is generally incompatible with ``nonblocking`` and ``nonallocating`` +code, because a typical implementation may allocate heap memory in the constructor. + +Alternatives: + +- ``std::function_ref`` (available in C++26 or as ``llvm::function_ref``). This is appropriate and + optimal when a functor's lifetime does not need to extend past the function that created it. + +- ``inplace_function`` from WG14. This solves the allocation problem by giving the functor wrapper + a fixed size known at compile time and using an inline buffer. + +While these alternatives both address the heap allocation of ``std::function``, they are still +obstacles to ``nonblocking/nonallocating`` verification, for reasons detailed in the next section. + + +Interactions with type-erasure techniques +----------------------------------------- + +``std::function`` illustrates a common C++ type-erasure technique. Using template +argument deduction, it decomposes a function type into its return and parameter types. Additional +components of the function type, including ``noexcept``, ``nonblocking``, ``nonallocating``, and any +other attributes, are discarded. + +Standard library support for these components of a function type is not immediately forthcoming. + +Code can work around this limitation in either of two ways: + +1. Avoid abstractions like ``std::function`` and instead work directly with the original lambda type. + +2. Create a specialized alternative, e.g. ``nonblocking_function_ref`` where all function + pointers used in the implementation and its interface are ``nonblocking``. + +As an example of the first approach, when using a lambda as a *Callable* template parameter, the +attribute is preserved: + +.. code-block:: c++ + + std::sort(vec.begin(), vec.end(), + [](const Elem& a, const Elem& b) [[clang::nonblocking]] { return a.mem < b.mem; }); + +Here, the type of the ``Compare`` template parameter is an anonymous class generated from the +lambda, with an ``operator()`` method holding the ``nonblocking`` attribute. + +A complication arises when a *Callable* template parameter, instead of being a lambda or class +implementing ``operator()``, is a function pointer: + +.. code-block:: c++ + + static bool compare_elems(const Elem& a, const Elem& b) [[clang::nonblocking]] { + return a.mem < b.mem; }; + + std::sort(vec.begin(), vec.end(), compare_elems); + +Here, the type of ``compare_elems`` is decomposed to ``bool(const Elem&, const Elem&)``, without +``nonblocking``, when forming the template parameter. This can be solved using the second approach, +creating a specialized alternative which explicitly requires the attribute. In this case, it's +possible to use a small wrapper to transform the function pointer into a functor: + +.. code-block:: c++ + + template + class nonblocking_fp; + + template + class nonblocking_fp { + public: + using impl_t = R (*)(Args...) [[clang::nonblocking]]; + + private: + impl_t mImpl{ nullptr_t }; + public: + nonblocking_fp() = default; + nonblocking_fp(impl_t f) : mImpl{ f } {} + + R operator()(Args... args) const + { + return mImpl(std::forward(args)...); + } + }; + + // deduction guide (like std::function's) + template< class R, class... ArgTypes > + nonblocking_fp( R(*)(ArgTypes...) ) -> nonblocking_fp; + + // -- + + // Wrap the function pointer in a functor which preserves ``nonblocking``. + std::sort(vec.begin(), vec.end(), nonblocking_fp{ compare_elems }); + +Now, the ``nonblocking`` attribute of ``compare_elems`` is verified when it is converted to a +``nonblocking`` function pointer, as the argument to ``nonblocking_fp``'s constructor. The template +parameter is the functor class ``nonblocking_fp``. + + +Static local variables +---------------------- + +Static local variables are often used for lazily-constructed globals (Meyers singletons). Beyond the +compiler's use of a lock to ensure thread-safe initialization, it is dangerously easy to +inadvertently trigger initialization, involving heap allocation, from a ``nonblocking`` or +``nonallocating`` context. + +Generally, such singletons need to be replaced by globals, and care must be taken to ensure their +initialization before they are used from ``nonblocking`` or ``nonallocating`` contexts. + + +Annotating libraries +-------------------- + +It can be surprising that the analysis does not depend on knowledge of any primitives; it simply +assumes the worst, that all function calls are unsafe unless explicitly marked as safe or able to be +inferred as safe. With ``nonblocking``, this appears to suffice for all but the most primitive of +spinlocks. + +At least for an operating system's C functions, it is possible to define an override header which +redeclares safe common functions (e.g. ``pthread_self()``) with the addition of ``nonblocking``. +This may help in adopting the feature incrementally. + +It also helps that many of the functions in the standard C libraries (notably ````) +are treated as built-in functions by Clang, which the diagnosis understands to be safe. + +Much of the C++ standard library consists of inline templated functions which work well with +inference. A small number of primitives may need explicit ``nonblocking/nonallocating`` attributes. diff --git a/clang/docs/RealtimeSanitizer.rst b/clang/docs/RealtimeSanitizer.rst index 103842e055db700f909153070ec98e9d2d346159..41b8bbb33baf1442f9b6b52a85c769bb44ab1c2b 100644 --- a/clang/docs/RealtimeSanitizer.rst +++ b/clang/docs/RealtimeSanitizer.rst @@ -21,7 +21,7 @@ The runtime slowdown introduced by RealtimeSanitizer is negligible. How to build ============ -Build LLVM/Clang with `CMake ` and enable the +Build LLVM/Clang with `CMake `_ and enable the ``compiler-rt`` runtime. An example CMake configuration that will allow for the use/testing of RealtimeSanitizer: @@ -183,6 +183,10 @@ A **partial** list of flags RealtimeSanitizer respects: - ``true`` - boolean - If set, use the symbolizer to turn virtual addresses to file/line locations. If false, can greatly speed up the error reporting. + * - ``suppressions`` + - "" + - path + - If set to a valid suppressions file, will suppress issue reporting. See details in "Disabling", below. Some issues with flags can be debugged using the ``verbosity=$NUM`` flag: @@ -194,12 +198,43 @@ Some issues with flags can be debugged using the ``verbosity=$NUM`` flag: misspelled_flag ... -Disabling ---------- +Disabling and suppressing +------------------------- -In some circumstances, you may want to suppress error reporting in a specific scope. +There are multiple ways to disable error reporting when using RealtimeSanitizer. -In C++, this is achieved via ``__rtsan::ScopedDisabler``. Within the scope where the ``ScopedDisabler`` object is instantiated, all sanitizer error reports are suppressed. This suppression applies to the current scope as well as all invoked functions, including any functions called transitively. +In general, ``ScopedDisabler`` should be preferred, as it is the most performant. + +.. list-table:: Suppression methods + :widths: 30 15 15 10 70 + :header-rows: 1 + + * - Method + - Specified at? + - Scope + - Run-time cost + - Description + * - ``ScopedDisabler`` + - Compile-time + - Stack + - Very low + - Violations are ignored for the lifetime of the ``ScopedDisabler`` object. + * - ``function-name-matches`` suppression + - Run-time + - Single function + - Medium + - Suppresses intercepted and ``[[clang::blocking]]`` function calls by name. + * - ``call-stack-contains`` suppression + - Run-time + - Stack + - High + - Suppresses any stack trace contaning the specified pattern. + + +``ScopedDisabler`` +################## + +At compile time, RealtimeSanitizer may be disabled using ``__rtsan::ScopedDisabler``. RTSan ignores any errors originating within the ``ScopedDisabler`` instance variable scope. .. code-block:: c++ @@ -233,6 +268,31 @@ In C, you can use the ``__rtsan_disable()`` and ``rtsan_enable()`` functions to Each call to ``__rtsan_disable()`` must be paired with a subsequent call to ``__rtsan_enable()`` to restore normal sanitizer functionality. If a corresponding ``rtsan_enable()`` call is not made, the behavior is undefined. +Suppression file +################ + +At run-time, suppressions may be specified using a suppressions file passed in ``RTSAN_OPTIONS``. Run-time suppression may be useful if the source cannot be changed. + +.. code-block:: console + + > cat suppressions.supp + call-stack-contains:MallocViolation + call-stack-contains:std::*vector + function-name-matches:free + function-name-matches:CustomMarkedBlocking* + > RTSAN_OPTIONS="suppressions=suppressions.supp" ./a.out + ... + +Suppressions specified in this file are one of two flavors. + +``function-name-matches`` suppresses reporting of any intercepted library call, or function marked ``[[clang::blocking]]`` by name. If, for instance, you know that ``malloc`` is real-time safe on your system, you can disable the check for it via ``function-name-matches:malloc``. + +``call-stack-contains`` suppresses reporting of errors in any stack that contains a string matching the pattern specified. For example, suppressing error reporting of any non-real-time-safe behavior in ``std::vector`` may be specified ``call-stack-contains:std::*vector``. You must include symbols in your build for this method to be effective, unsymbolicated stack traces cannot be matched. ``call-stack-contains`` has the highest run-time cost of any method of suppression. + +Patterns may be exact matches or are "regex-light" patterns, containing special characters such as ``^$*``. + +The number of potential errors suppressed via this method may be seen on exit when using the ``print_stats_on_exit`` flag. + Compile-time sanitizer detection -------------------------------- diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 28bb83a1c9d60f4a17b012e5a804637df2852169..a39ffc8366dda41fd501bfcbd4133443ca9ac642 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -46,6 +46,12 @@ code bases. - The ``clang-rename`` tool has been removed. +- Removed support for RenderScript targets. This technology is + `officially deprecated `_ + and users are encouraged to + `migrate to Vulkan `_ + or other options. + C/C++ Language Potentially Breaking Changes ------------------------------------------- @@ -133,6 +139,15 @@ C++ Specific Potentially Breaking Changes // Fixed version: unsigned operator""_udl_name(unsigned long long); +- Clang will now produce an error diagnostic when [[clang::lifetimebound]] is + applied on a parameter of a function that returns void. This was previously + ignored and had no effect. (#GH107556) + + .. code-block:: c++ + + // Now diagnoses with an error. + void f(int& i [[clang::lifetimebound]]); + ABI Changes in This Version --------------------------- @@ -302,6 +317,16 @@ Modified Compiler Flags the ``promoted`` algorithm for complex division when possible rather than the less basic (limited range) algorithm. +- The ``-fveclib`` option has been updated to enable ``-fno-math-errno`` for + ``-fveclib=ArmPL`` and ``-fveclib=SLEEF``. This gives Clang more opportunities + to utilize these vector libraries. The behavior for all other vector function + libraries remains unchanged. + +- The ``-Wnontrivial-memaccess`` warning has been updated to also warn about + passing non-trivially-copyable destrination parameter to ``memcpy``, + ``memset`` and similar functions for which it is a documented undefined + behavior. + Removed Compiler Flags ------------------------- @@ -424,6 +449,8 @@ Improvements to Clang's diagnostics name was a reserved name, which we improperly allowed to suppress the diagnostic. +- Clang now diagnoses ``[[deprecated]]`` attribute usage on local variables (#GH90073). + Improvements to Clang's time-trace ---------------------------------- @@ -544,6 +571,8 @@ Bug Fixes to C++ Support - Clang incorrectly considered a class with an anonymous union member to not be const-default-constructible even if a union member has a default member initializer. (#GH95854). +- Fixed an assertion failure when evaluating an invalid expression in an array initializer. (#GH112140) +- Fixed an assertion failure in range calculations for conditional throw expressions. (#GH111854) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -611,6 +640,10 @@ X86 Support * Supported MINMAX intrinsics of ``*_(mask(z)))_minmax(ne)_p[s|d|h|bh]`` and ``*_(mask(z)))_minmax_s[s|d|h]``. +- Supported intrinsics for ``SM4 and AVX10.2``. + * Supported SM4 intrinsics of ``_mm512_sm4key4_epi32`` and + ``_mm512_sm4rnds4_epi32``. + - All intrinsics in adcintrin.h can now be used in constant expressions. - All intrinsics in adxintrin.h can now be used in constant expressions. @@ -623,6 +656,9 @@ X86 Support - All intrinsics in tbmintrin.h can now be used in constant expressions. +- Supported intrinsics for ``MOVRS AND AVX10.2``. + * Supported intrinsics of ``_mm(256|512)_(mask(z))_loadrs_epi(8|16|32|64)``. + Arm and AArch64 Support ^^^^^^^^^^^^^^^^^^^^^^^ @@ -670,6 +706,15 @@ NetBSD Support WebAssembly Support ^^^^^^^^^^^^^^^^^^^ +The default target CPU, "generic", now enables the `-mnontrapping-fptoint` +and `-mbulk-memory` flags, which correspond to the [Bulk Memory Operations] +and [Non-trapping float-to-int Conversions] language features, which are +[widely implemented in engines]. + +[Bulk Memory Operations]: https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md +[Non-trapping float-to-int Conversions]: https://github.com/WebAssembly/spec/blob/master/proposals/nontrapping-float-to-int-conversion/Overview.md +[widely implemented in engines]: https://webassembly.org/features/ + AVR Support ^^^^^^^^^^^ @@ -710,6 +755,7 @@ clang-format multi-line comments without touching their contents, renames ``false`` to ``Never``, and ``true`` to ``Always``. - Adds ``RemoveEmptyLinesInUnwrappedLines`` option. +- Adds ``KeepFormFeed`` option and set it to ``true`` for ``GNU`` style. libclang -------- @@ -752,6 +798,12 @@ Moved checkers To detect too large arguments passed to malloc, consider using the checker ``alpha.taint.TaintedAlloc``. +- The checkers ``alpha.nondeterministic.PointerSorting`` and + ``alpha.nondeterministic.PointerIteration`` were moved to a new bugprone + checker named ``bugprone-nondeterministic-pointer-iteration-order``. The + original checkers were implemented only using AST matching and make more + sense as a single clang-tidy check. + .. _release-notes-sanitizers: Sanitizers diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 58dbd686a6dc9fb60eec488a991f553bdb663ca7..87b03438e6e0b97142a286558a8cdd54f7dfd0af 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -3447,37 +3447,6 @@ Limitations: More details at the corresponding `GitHub issue `_. -.. _alpha-nondeterminism-PointerIteration: - -alpha.nondeterminism.PointerIteration (C++) -""""""""""""""""""""""""""""""""""""""""""" -Check for non-determinism caused by iterating unordered containers of pointers. - -.. code-block:: c - - void test() { - int a = 1, b = 2; - std::unordered_set UnorderedPtrSet = {&a, &b}; - - for (auto i : UnorderedPtrSet) // warn - f(i); - } - -.. _alpha-nondeterminism-PointerSorting: - -alpha.nondeterminism.PointerSorting (C++) -""""""""""""""""""""""""""""""""""""""""" -Check for non-determinism caused by sorting of pointers. - -.. code-block:: c - - void test() { - int a = 1, b = 2; - std::vector V = {&a, &b}; - std::sort(V.begin(), V.end()); // warn - } - - alpha.WebKit ^^^^^^^^^^^^ diff --git a/clang/docs/analyzer/user-docs.rst b/clang/docs/analyzer/user-docs.rst index 08cb5119e810bd87978c7ca5565ad5615637f211..dd53ae143148c01a60ceed952593d147fb21d164 100644 --- a/clang/docs/analyzer/user-docs.rst +++ b/clang/docs/analyzer/user-docs.rst @@ -12,3 +12,4 @@ Contents: user-docs/FilingBugs user-docs/CrossTranslationUnit user-docs/TaintAnalysisConfiguration + user-docs/FAQ diff --git a/clang/docs/analyzer/user-docs/FAQ.rst b/clang/docs/analyzer/user-docs/FAQ.rst new file mode 100644 index 0000000000000000000000000000000000000000..af52e99c91d68bfd15865ae6b3a1f0dab1b5f451 --- /dev/null +++ b/clang/docs/analyzer/user-docs/FAQ.rst @@ -0,0 +1,208 @@ +FAQ and How to Deal with Common False Positives +=============================================== + +.. contents:: + :local: + +Custom Assertions +----------------- + +Q: How do I tell the analyzer that I do not want the bug being reported here since my custom error handler will safely end the execution before the bug is reached? + +You can tell the analyzer that this path is unreachable by teaching it about your `custom assertion handlers `_. For example, you can modify the code segment as following: + +.. code-block:: c + + void customAssert() __attribute__((analyzer_noreturn)); + int foo(int *b) { + if (!b) + customAssert(); + return *b; + } + +Null Pointer Dereference +------------------------ + +Q: The analyzer reports a null dereference, but I know that the pointer is never null. How can I tell the analyzer that a pointer can never be null? + +The reason the analyzer often thinks that a pointer can be null is because the preceding code checked compared it against null. If you are absolutely sure that it cannot be null, remove the preceding check and, preferably, add an assertion as well. For example: + +.. code-block:: c + + void usePointer(int *b); + int foo(int *b) { + usePointer(b); + return *b; + } + +Dead Store +---------- + +Q: How do I tell the static analyzer that I don't care about a specific dead store? + +When the analyzer sees that a value stored into a variable is never used, it's going to produce a message similar to this one: + +.. code-block:: none + + Value stored to 'x' is never read + +You can use the ``(void)x;`` idiom to acknowledge that there is a dead store in your code but you do not want it to be reported in the future. + +Unused Instance Variable +------------------------ + +Q: How do I tell the static analyzer that I don't care about a specific unused instance variable in Objective-C? + +When the analyzer sees that a value stored into a variable is never used, it is going to produce a message similar to this one: + +.. code-block:: none + + Instance variable 'commonName' in class 'HappyBird' is never used by the methods in its @implementation + +You can add ``__attribute__((unused))`` to the instance variable declaration to suppress the warning. + +Unlocalized String +------------------ + +Q: How do I tell the static analyzer that I don't care about a specific unlocalized string? + +When the analyzer sees that an unlocalized string is passed to a method that will present that string to the user, it is going to produce a message similar to this one: + +.. code-block:: none + + User-facing text should use localized string macro + +If your project deliberately uses unlocalized user-facing strings (for example, in a debugging UI that is never shown to users), you can suppress the analyzer warnings (and document your intent) with a function that just returns its input but is annotated to return a localized string: + +.. code-block:: objc + + __attribute__((annotate("returns_localized_nsstring"))) + static inline NSString *LocalizationNotNeeded(NSString *s) { + return s; + } + +You can then call this function when creating your debugging UI: + +.. code-block:: objc + + [field setStringValue:LocalizationNotNeeded(@"Debug")]; + +Some projects may also find it useful to use NSLocalizedString but add "DNL" or "Do Not Localize" to the string contents as a convention: + +.. code-block:: objc + + UILabel *testLabel = [[UILabel alloc] init]; + NSString *s = NSLocalizedString(@"Hello ", @"For debug purposes"); + [testLabel setText:s]; + +Dealloc in Manual Retain/Release +-------------------------------- + +Q: How do I tell the analyzer that my instance variable does not need to be released in -dealloc under Manual Retain/Release? + +If your class only uses an instance variable for part of its lifetime, it may maintain an invariant guaranteeing that the instance variable is always released before -dealloc. In this case, you can silence a warning about a missing release by either adding ``assert(_ivar == nil)`` or an explicit release ``[_ivar release]`` (which will be a no-op when the variable is nil) in -dealloc. + +Deciding Nullability +-------------------- + +Q: How do I decide whether a method's return type should be _Nullable or _Nonnull? + +Depending on the implementation of the method, this puts you in one of five situations: + +1. You actually never return nil. +2. You do return nil sometimes, and callers are supposed to handle that. This includes cases where your method is documented to return nil given certain inputs. +3. You return nil based on some external condition (such as an out-of-memory error), but the client can't do anything about it either. +4. You return nil only when the caller passes input documented to be invalid. That means it's the client's fault. +5. You return nil in some totally undocumented case. + +In (1) you should annotate the method as returning a ``_Nonnull`` object. + +In (2) the method should be marked ``_Nullable``. + +In (3) you should probably annotate the method ``_Nonnull``. Why? Because no callers will actually check for nil, given that they can't do anything about the situation and don't know what went wrong. At this point things have gone so poorly that there's basically no way to recover. + +The least happy case is (4) because the resulting program will almost certainly either crash or just silently do the wrong thing. If this is a new method or you control the callers, you can use ``NSParameterAssert()`` (or the equivalent) to check the precondition and remove the nil return. But if you don't control the callers and they rely on this behavior, you should return mark the method ``_Nonnull`` and return nil cast to _Nonnull anyway. + +If you're in (5), document it, then figure out if you're now in (2), (3), or (4). + +Intentional Nullability Violation +--------------------------------- + +Q: How do I tell the analyzer that I am intentionally violating nullability? + +In some cases, it may make sense for methods to intentionally violate nullability. For example, your method may — for reasons of backward compatibility — chose to return nil and log an error message in a method with a non-null return type when the client violated a documented precondition rather than check the precondition with ``NSAssert()``. In these cases, you can suppress the analyzer warning with a cast: + +.. code-block:: objc + + return (id _Nonnull)nil; + +Note that this cast does not affect code generation. + +Ensuring Loop Body Execution +---------------------------- + +Q: The analyzer assumes that a loop body is never entered. How can I tell it that the loop body will be entered at least once? + +In cases where you know that a loop will always be entered at least once, you can use assertions to inform the analyzer. For example: + +.. code-block:: c + + int foo(int length) { + int x = 0; + assert(length > 0); + for (int i = 0; i < length; i++) + x += 1; + return length/x; + } + +By adding ``assert(length > 0)`` in the beginning of the function, you tell the analyzer that your code is never expecting a zero or a negative value, so it won't need to test the correctness of those paths. + +Suppressing Specific Warnings +----------------------------- + +Q: How can I suppress a specific analyzer warning? + +When you encounter an analyzer bug/false positive, check if it's one of the issues discussed above or if the analyzer `annotations `_ can resolve the issue by helping the static analyzer understand the code better. Second, please `report it `_ to help us improve user experience. + +Sometimes there's really no "good" way to eliminate the issue. In such cases you can "silence" it directly by annotating the problematic line of code with the help of Clang attribute 'suppress': + +.. code-block:: c + + int foo() { + int *x = nullptr; + ... + [[clang::suppress]] { + // all warnings in this scope are suppressed + int y = *x; + } + + // null pointer dereference warning suppressed on the next line + [[clang::suppress]] + return *x + } + + int bar(bool coin_flip) { + // suppress all memory leak warnings about this allocation + [[clang::suppress]] + int *result = (int *)malloc(sizeof(int)); + + if (coin_flip) + return 0; // including this leak path + + return *result; // as well as this leak path + } + +Excluding Code from Analysis +---------------------------- + +Q: How can I selectively exclude code the analyzer examines? + +When the static analyzer is using clang to parse source files, it implicitly defines the preprocessor macro ``__clang_analyzer__``. One can use this macro to selectively exclude code the analyzer examines. Here is an example: + +.. code-block:: c + + #ifndef __clang_analyzer__ + // Code not to be analyzed + #endif + +This usage is discouraged because it makes the code dead to the analyzer from now on. Instead, we prefer that users file bugs against the analyzer when it flags false positives. diff --git a/clang/docs/index.rst b/clang/docs/index.rst index 0f6fb36c4d3352b9f9db1b39c9ab94f56730dc00..1096432813fac523d26d9bdbbb8fd1a5ebebebbc 100644 --- a/clang/docs/index.rst +++ b/clang/docs/index.rst @@ -27,6 +27,7 @@ Using Clang as a Compiler ThreadSafetyAnalysis SafeBuffers DataFlowAnalysisIntro + FunctionEffectAnalysis AddressSanitizer ThreadSanitizer MemorySanitizer diff --git a/clang/include/clang/AST/CommentSema.h b/clang/include/clang/AST/CommentSema.h index 03f13283ac0d977ef1263951a04728fc3faa4c8b..916d7945329c5b535dedc4ea9761c3eeb1a50dfa 100644 --- a/clang/include/clang/AST/CommentSema.h +++ b/clang/include/clang/AST/CommentSema.h @@ -80,7 +80,7 @@ public: ArrayRef copyArray(ArrayRef Source) { if (!Source.empty()) return Source.copy(Allocator); - return std::nullopt; + return {}; } ParagraphComment *actOnParagraphComment( diff --git a/clang/include/clang/AST/DeclFriend.h b/clang/include/clang/AST/DeclFriend.h index 095f14a81fd5747c70f1bc2402cdad2ec7c551e1..1578580c89cd87d3d7296c6423d061ad9e1625fe 100644 --- a/clang/include/clang/AST/DeclFriend.h +++ b/clang/include/clang/AST/DeclFriend.h @@ -115,7 +115,7 @@ public: static FriendDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend_, SourceLocation FriendL, SourceLocation EllipsisLoc = {}, - ArrayRef FriendTypeTPLists = std::nullopt); + ArrayRef FriendTypeTPLists = {}); static FriendDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned FriendTypeNumTPLists); diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index 1cda70530d7d83c038a745408454568e50926667..4663603f797545a43881f9cf271fd90b3ed2a00c 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -386,7 +386,7 @@ public: /// If the method is implicit (not coming from source) \p SelLocs is /// ignored. void setMethodParams(ASTContext &C, ArrayRef Params, - ArrayRef SelLocs = std::nullopt); + ArrayRef SelLocs = {}); // Iterator access to parameter types. struct GetTypeFn { diff --git a/clang/include/clang/AST/DeclOpenMP.h b/clang/include/clang/AST/DeclOpenMP.h index 868662208efa1fe28f885af7ad947f5e8f632fee..cf383889c0ad90dedafa36a5ee9d6d9eb82bce68 100644 --- a/clang/include/clang/AST/DeclOpenMP.h +++ b/clang/include/clang/AST/DeclOpenMP.h @@ -34,7 +34,7 @@ template class OMPDeclarativeDirective : public U { /// Get the clauses storage. MutableArrayRef getClauses() { if (!Data) - return std::nullopt; + return {}; return Data->getClauses(); } @@ -90,7 +90,7 @@ public: ArrayRef clauses() const { if (!Data) - return std::nullopt; + return {}; return Data->getClauses(); } }; diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index cfe3938f83847b0353eb5c959e2bbf8f151285cc..57ab94bcb2010f333bb88906b2fb0f24fa57a7c0 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -4306,11 +4306,11 @@ class SizeOfPackExpr final : Expr(SizeOfPackExprClass, Empty), Length(NumPartialArgs) {} public: - static SizeOfPackExpr * - Create(ASTContext &Context, SourceLocation OperatorLoc, NamedDecl *Pack, - SourceLocation PackLoc, SourceLocation RParenLoc, - std::optional Length = std::nullopt, - ArrayRef PartialArgs = std::nullopt); + static SizeOfPackExpr *Create(ASTContext &Context, SourceLocation OperatorLoc, + NamedDecl *Pack, SourceLocation PackLoc, + SourceLocation RParenLoc, + std::optional Length = std::nullopt, + ArrayRef PartialArgs = {}); static SizeOfPackExpr *CreateDeserialized(ASTContext &Context, unsigned NumPartialArgs); diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 58193c2dd325e3dd1a304a0697ecbbc58947b3b3..1d429fd9fe2b9f4d3ebca25bf473ec3c5ca36b8e 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -6270,14 +6270,14 @@ public: return const_component_lists_iterator( getUniqueDeclsRef(), getDeclNumListsRef(), getComponentListSizesRef(), getComponentsRef(), SupportsMapper, - SupportsMapper ? getUDMapperRefs() : std::nullopt); + SupportsMapper ? getUDMapperRefs() : ArrayRef()); } const_component_lists_iterator component_lists_end() const { return const_component_lists_iterator( ArrayRef(), ArrayRef(), ArrayRef(), MappableExprComponentListRef(getComponentsRef().end(), getComponentsRef().end()), - SupportsMapper, std::nullopt); + SupportsMapper, {}); } const_component_lists_range component_lists() const { return {component_lists_begin(), component_lists_end()}; @@ -6290,7 +6290,7 @@ public: return const_component_lists_iterator( VD, getUniqueDeclsRef(), getDeclNumListsRef(), getComponentListSizesRef(), getComponentsRef(), SupportsMapper, - SupportsMapper ? getUDMapperRefs() : std::nullopt); + SupportsMapper ? getUDMapperRefs() : ArrayRef()); } const_component_lists_iterator decl_component_lists_end() const { return component_lists_end(); diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h index 6b9c1d7994d82c71fa4a0e8bbe7aeab7486ecc47..9958a93bf1160770a147528cea5b0f8c7338a5a2 100644 --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -277,7 +277,7 @@ class OMPExecutableDirective : public Stmt { /// Get the clauses storage. MutableArrayRef getClauses() { if (!Data) - return std::nullopt; + return {}; return Data->getClauses(); } @@ -572,7 +572,7 @@ public: ArrayRef clauses() const { if (!Data) - return std::nullopt; + return {}; return Data->getClauses(); } diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h index 0eaa4b0eedb35f7f293be48f1af9cc1b752c4796..a8f0263d5505ac461bacde3ed6ce1509b184342e 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -283,7 +283,7 @@ public: } static TemplateArgument getEmptyPack() { - return TemplateArgument(std::nullopt); + return TemplateArgument(ArrayRef()); } /// Create a new template argument pack by copying the given set of diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index c1cc63fdb7433f7c01a771521bde51f41e8a24b0..ab8b146453e761ab14f80cdc7b902d7068dab2f6 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -121,7 +121,7 @@ template struct TypeListContainsSuperOf { template )> struct VariadicFunction { - ResultT operator()() const { return Func(std::nullopt); } + ResultT operator()() const { return Func({}); } template ResultT operator()(const ArgT &Arg1, const ArgsT &... Args) const { @@ -1949,35 +1949,35 @@ inline ArrayRef getTemplateSpecializationArgs(const FunctionDecl &FD) { if (const auto* TemplateArgs = FD.getTemplateSpecializationArgs()) return TemplateArgs->asArray(); - return std::nullopt; + return {}; } inline ArrayRef getTemplateArgsWritten(const ClassTemplateSpecializationDecl &D) { if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten()) return Args->arguments(); - return std::nullopt; + return {}; } inline ArrayRef getTemplateArgsWritten(const VarTemplateSpecializationDecl &D) { if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten()) return Args->arguments(); - return std::nullopt; + return {}; } inline ArrayRef getTemplateArgsWritten(const FunctionDecl &FD) { if (const auto *Args = FD.getTemplateSpecializationArgsAsWritten()) return Args->arguments(); - return std::nullopt; + return {}; } inline ArrayRef getTemplateArgsWritten(const DeclRefExpr &DRE) { if (const auto *Args = DRE.getTemplateArgs()) return {Args, DRE.getNumTemplateArgs()}; - return std::nullopt; + return {}; } inline SmallVector diff --git a/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h b/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h index 65dd66ee093fe4c96b3a2388585a947a0e6d037e..2f202607bd3fa993b9654998a961bfee4edf432c 100644 --- a/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h +++ b/clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h @@ -1470,7 +1470,7 @@ public: static bool classof(const SExpr *E) { return E->opcode() == COP_Return; } /// Return an empty list. - ArrayRef successors() { return std::nullopt; } + ArrayRef successors() { return {}; } SExpr *returnValue() { return Retval; } const SExpr *returnValue() const { return Retval; } @@ -1496,7 +1496,7 @@ inline ArrayRef Terminator::successors() { case COP_Branch: return cast(this)->successors(); case COP_Return: return cast(this)->successors(); default: - return std::nullopt; + return {}; } } diff --git a/clang/include/clang/Analysis/AnyCall.h b/clang/include/clang/Analysis/AnyCall.h index 48abce062d133089c39b80e4f3f6d326f9a79316..3e95366c985956351f49891ddf30297cd838b7be 100644 --- a/clang/include/clang/Analysis/AnyCall.h +++ b/clang/include/clang/Analysis/AnyCall.h @@ -143,7 +143,7 @@ public: /// \returns formal parameters for direct calls (including virtual calls) ArrayRef parameters() const { if (!D) - return std::nullopt; + return {}; if (const auto *FD = dyn_cast(D)) { return FD->parameters(); @@ -152,7 +152,7 @@ public: } else if (const auto *BD = dyn_cast(D)) { return BD->parameters(); } else { - return std::nullopt; + return {}; } } diff --git a/clang/include/clang/Analysis/FlowSensitive/CachedConstAccessorsLattice.h b/clang/include/clang/Analysis/FlowSensitive/CachedConstAccessorsLattice.h index 3402d105746e88f3f8ccd41b1089c76be2fd2022..48c5287367739a2ae42611ba9bce87827d6b0d82 100644 --- a/clang/include/clang/Analysis/FlowSensitive/CachedConstAccessorsLattice.h +++ b/clang/include/clang/Analysis/FlowSensitive/CachedConstAccessorsLattice.h @@ -154,11 +154,12 @@ LatticeEffect CachedConstAccessorsLattice::join( // are non-identical but equivalent. This is likely to be sufficient in // practice, and it reduces implementation complexity considerably. - ConstMethodReturnValues = internal::joinConstMethodMap( - ConstMethodReturnValues, Other.ConstMethodReturnValues, Effect); + ConstMethodReturnValues = + clang::dataflow::internal::joinConstMethodMap( + ConstMethodReturnValues, Other.ConstMethodReturnValues, Effect); ConstMethodReturnStorageLocations = - internal::joinConstMethodMap( + clang::dataflow::internal::joinConstMethodMap( ConstMethodReturnStorageLocations, Other.ConstMethodReturnStorageLocations, Effect); diff --git a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h index 9d81cacb507351abfd0b434de9f8d54ef7ee30dd..713494178b97bdb2789f9b95723a59090af01cfa 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h +++ b/clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h @@ -37,6 +37,14 @@ struct UncheckedOptionalAccessModelOptions { /// can't identify when their results are used safely (across calls), /// resulting in false positives in all such cases. Note: this option does not /// cover access through `operator[]`. + /// FIXME: we currently cache and equate the result of const accessors + /// returning pointers, so cover the case of operator-> followed by + /// operator->, which covers the common case of smart pointers. We also cover + /// some limited cases of returning references (if return type is an optional + /// type), so cover some cases of operator* followed by operator*. We don't + /// cover mixing operator-> and operator*. Once we are confident in this const + /// accessor caching, we shouldn't need the IgnoreSmartPointerDereference + /// option anymore. bool IgnoreSmartPointerDereference = false; }; diff --git a/clang/include/clang/Analysis/FlowSensitive/NoopLattice.h b/clang/include/clang/Analysis/FlowSensitive/NoopLattice.h index 0192193281119832563db78bf48ca103aea23826..96c695473b67a198280fdde4f38d4593212cb09a 100644 --- a/clang/include/clang/Analysis/FlowSensitive/NoopLattice.h +++ b/clang/include/clang/Analysis/FlowSensitive/NoopLattice.h @@ -14,6 +14,8 @@ #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOP_LATTICE_H #include "clang/Analysis/FlowSensitive/DataflowLattice.h" +#include "clang/Support/Compiler.h" +#include "llvm/ADT/Any.h" #include namespace clang { @@ -38,4 +40,13 @@ inline std::ostream &operator<<(std::ostream &OS, const NoopLattice &) { } // namespace dataflow } // namespace clang +namespace llvm { +// This needs to be exported for ClangAnalysisFlowSensitiveTests so any_cast +// uses the correct address of Any::TypeId from the clang shared library instead +// of creating one in the test executable. when building with +// CLANG_LINK_CLANG_DYLIB +extern template struct CLANG_TEMPLATE_ABI + Any::TypeId; +} // namespace llvm + #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOP_LATTICE_H diff --git a/clang/include/clang/Basic/AArch64SVEACLETypes.def b/clang/include/clang/Basic/AArch64SVEACLETypes.def index 25abf5f3f86b7d234f12c2552c0dc3ab9260f07f..62f6087e96246626b468468e79322c91557ceca2 100644 --- a/clang/include/clang/Basic/AArch64SVEACLETypes.def +++ b/clang/include/clang/Basic/AArch64SVEACLETypes.def @@ -107,7 +107,6 @@ AARCH64_VECTOR_TYPE(Name, MangledName, Id, SingletonId) #endif - //===- Vector point types -----------------------------------------------===// SVE_VECTOR_TYPE_INT("__SVInt8_t", "__SVInt8_t", SveInt8, SveInt8Ty, 16, 8, 1, true) @@ -201,6 +200,7 @@ SVE_PREDICATE_TYPE_ALL("__clang_svboolx4_t", "svboolx4_t", SveBoolx4, SveBoolx4T SVE_OPAQUE_TYPE("__SVCount_t", "__SVCount_t", SveCount, SveCountTy) +AARCH64_VECTOR_TYPE_MFLOAT("__MFloat8_t", "__MFloat8_t", MFloat8, MFloat8Ty, 1, 8, 1) AARCH64_VECTOR_TYPE_MFLOAT("__MFloat8x8_t", "__MFloat8x8_t", MFloat8x8, MFloat8x8Ty, 8, 8, 1) AARCH64_VECTOR_TYPE_MFLOAT("__MFloat8x16_t", "__MFloat8x16_t", MFloat8x16, MFloat8x16Ty, 16, 8, 1) diff --git a/clang/include/clang/Basic/AMDGPUTypes.def b/clang/include/clang/Basic/AMDGPUTypes.def index e47e544fdc82c1c7f0739d9d12db348f89c4eb9d..d3dff446f9edf01ce2c7c8056ca400280b5a774a 100644 --- a/clang/include/clang/Basic/AMDGPUTypes.def +++ b/clang/include/clang/Basic/AMDGPUTypes.def @@ -15,7 +15,15 @@ AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) #endif +#ifndef AMDGPU_NAMED_BARRIER_TYPE +#define AMDGPU_NAMED_BARRIER_TYPE(Name, Id, SingletonId, Width, Align, Scope) \ + AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) +#endif + AMDGPU_OPAQUE_PTR_TYPE("__amdgpu_buffer_rsrc_t", AMDGPUBufferRsrc, AMDGPUBufferRsrcTy, 128, 128, 8) +AMDGPU_NAMED_BARRIER_TYPE("__amdgpu_named_workgroup_barrier_t", AMDGPUNamedWorkgroupBarrier, AMDGPUNamedWorkgroupBarrierTy, 128, 32, 0) + #undef AMDGPU_TYPE #undef AMDGPU_OPAQUE_PTR_TYPE +#undef AMDGPU_NAMED_BARRIER_TYPE diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 3d0ee01870bd67696f99288b21a9a823e176132a..10bda5d9e2a71de9dbefc0a20f150e93cbd71e19 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -411,7 +411,6 @@ def SYCL : LangOpt<"SYCLIsDevice">; def COnly : LangOpt<"", "!LangOpts.CPlusPlus">; def CPlusPlus : LangOpt<"CPlusPlus">; def OpenCL : LangOpt<"OpenCL">; -def RenderScript : LangOpt<"RenderScript">; def ObjC : LangOpt<"ObjC">; def BlocksSupported : LangOpt<"Blocks">; def ObjCAutoRefCount : LangOpt<"ObjCAutoRefCount">; @@ -1629,14 +1628,6 @@ def OpenCLNoSVM : Attr { let ASTNode = 0; } -def RenderScriptKernel : Attr { - let Spellings = [GNU<"kernel">]; - let Subjects = SubjectList<[Function]>; - let Documentation = [RenderScriptKernelAttributeDocs]; - let LangOpts = [RenderScript]; - let SimpleHandler = 1; -} - def Deprecated : InheritableAttr { let Spellings = [GCC<"deprecated">, Declspec<"deprecated">, CXX11<"","deprecated", 201309>, diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index ee8126cadae232285f1ced20df7b40d63c9197b6..7a130c434e73cedf97338a028292d1b90fc3fa0c 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5831,21 +5831,6 @@ provided with the regular ``visibility`` attribute. }]; } -def RenderScriptKernelAttributeDocs : Documentation { - let Category = DocCatFunction; - let Content = [{ -``__attribute__((kernel))`` is used to mark a ``kernel`` function in -RenderScript. - -In RenderScript, ``kernel`` functions are used to express data-parallel -computations. The RenderScript runtime efficiently parallelizes ``kernel`` -functions to run on computational resources such as multi-core CPUs and GPUs. -See the RenderScript_ documentation for more information. - -.. _RenderScript: https://developer.android.com/guide/topics/renderscript/compute.html - }]; -} - def XRayDocs : Documentation { let Category = DocCatFunction; let Heading = "xray_always_instrument, xray_never_instrument, xray_log_args"; diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 90475a361bb8f86c00d2dba7cf812b1aaf2fd523..9bd67e0cefebc32b293b2603413f1dfee475d870 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4871,6 +4871,12 @@ def HLSLRadians : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLSplitDouble: LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_elementwise_splitdouble"]; + let Attributes = [NoThrow, Const]; + let Prototype = "void(...)"; +} + // Builtins for XRay. def XRayCustomEvent : Builtin { let Spellings = ["__xray_customevent"]; diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def index 4c6b22cca421cab8480469cf576eb9f301980426..4486eb73a11fa6a3b2ae4a67ce4f94a2d442992e 100644 --- a/clang/include/clang/Basic/BuiltinsX86.def +++ b/clang/include/clang/Basic/BuiltinsX86.def @@ -2179,6 +2179,10 @@ TARGET_BUILTIN(__builtin_ia32_vsm4key4256, "V8UiV8UiV8Ui", "nV:256:", "sm4") TARGET_BUILTIN(__builtin_ia32_vsm4rnds4128, "V4UiV4UiV4Ui", "nV:128:", "sm4") TARGET_BUILTIN(__builtin_ia32_vsm4rnds4256, "V8UiV8UiV8Ui", "nV:256:", "sm4") +// SM4_EVEX +TARGET_BUILTIN(__builtin_ia32_vsm4key4512, "V16UiV16UiV16Ui", "nV:512:", "avx10.2-512,sm4") +TARGET_BUILTIN(__builtin_ia32_vsm4rnds4512, "V16UiV16UiV16Ui", "nV:512:", "avx10.2-512,sm4") + // AVX10 MINMAX TARGET_BUILTIN(__builtin_ia32_vminmaxnepbf16128, "V8yV8yV8yIi", "nV:128:", "avx10.2-256") TARGET_BUILTIN(__builtin_ia32_vminmaxnepbf16256, "V16yV16yV16yIi", "nV:256:", "avx10.2-256") diff --git a/clang/include/clang/Basic/BuiltinsX86_64.def b/clang/include/clang/Basic/BuiltinsX86_64.def index 2c591edb2835cd790cc4c35c0460964caf08371a..e1e613560167ac5fae543f18e2a753a523dd1300 100644 --- a/clang/include/clang/Basic/BuiltinsX86_64.def +++ b/clang/include/clang/Basic/BuiltinsX86_64.def @@ -161,6 +161,20 @@ TARGET_BUILTIN(__builtin_ia32_aand64, "vv*SOi", "n", "raoint") TARGET_BUILTIN(__builtin_ia32_aor64, "vv*SOi", "n", "raoint") TARGET_BUILTIN(__builtin_ia32_axor64, "vv*SOi", "n", "raoint") +// MOVRS and AVX10.2 +TARGET_BUILTIN(__builtin_ia32_vmovrsb128, "V16cV16cC*", "nV:128:", "movrs,avx10.2-256") +TARGET_BUILTIN(__builtin_ia32_vmovrsb256, "V32cV32cC*", "nV:256:", "movrs,avx10.2-256") +TARGET_BUILTIN(__builtin_ia32_vmovrsb512, "V64cV64cC*", "nV:512:", "movrs,avx10.2-512") +TARGET_BUILTIN(__builtin_ia32_vmovrsd128, "V4iV4iC*", "nV:128:", "movrs,avx10.2-256") +TARGET_BUILTIN(__builtin_ia32_vmovrsd256, "V8iV8iC*", "nV:256:", "movrs,avx10.2-256") +TARGET_BUILTIN(__builtin_ia32_vmovrsd512, "V16iV16iC*", "nV:512:", "movrs,avx10.2-512") +TARGET_BUILTIN(__builtin_ia32_vmovrsq128, "V2OiV2OiC*", "nV:128:", "movrs,avx10.2-256") +TARGET_BUILTIN(__builtin_ia32_vmovrsq256, "V4OiV4OiC*", "nV:256:", "movrs,avx10.2-256") +TARGET_BUILTIN(__builtin_ia32_vmovrsq512, "V8OiV8OiC*", "nV:512:", "movrs,avx10.2-512") +TARGET_BUILTIN(__builtin_ia32_vmovrsw128, "V8sV8sC*", "nV:128:", "movrs,avx10.2-256") +TARGET_BUILTIN(__builtin_ia32_vmovrsw256, "V16sV16sC*", "nV:256:", "movrs,avx10.2-256") +TARGET_BUILTIN(__builtin_ia32_vmovrsw512, "V32sV32sC*", "nV:512:", "movrs,avx10.2-512") + #undef BUILTIN #undef TARGET_BUILTIN #undef TARGET_HEADER_BUILTIN diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index d7bad4f5ebf76ea02ca2ea496a4886736d217572..104ad81ce7d1f35a749de09ec52c73ed7bb70810 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -136,6 +136,8 @@ CODEGENOPT(XRayIgnoreLoops , 1, 0) ///< Emit the XRay function index section. CODEGENOPT(XRayFunctionIndex , 1, 1) +///< Set when -fxray-shared is enabled +CODEGENOPT(XRayShared , 1, 0) ///< Set the minimum number of instructions in a function to determine selective ///< XRay instrumentation. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 0633c275a1479914d9b38ab96c25cc06721117b3..0dc132206fe08ebc5a81e3634ac72980a0708100 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -795,6 +795,10 @@ def warn_cstruct_memaccess : Warning< "%1 call is a pointer to record %2 that is not trivial to " "%select{primitive-default-initialize|primitive-copy}3">, InGroup; +def warn_cxxstruct_memaccess : Warning< + "first argument in call to " + "%0 is a pointer to non-trivially copyable type %1">, + InGroup; def note_nontrivial_field : Note< "field is non-trivial to %select{copy|default-initialize}0">; def err_non_trivial_c_union_in_invalid_context : Error< @@ -10097,6 +10101,9 @@ def err_lifetimebound_no_object_param : Error< def err_lifetimebound_ctor_dtor : Error< "'lifetimebound' attribute cannot be applied to a " "%select{constructor|destructor}0">; +def err_lifetimebound_void_return_type : Error< + "'lifetimebound' attribute cannot be applied to a parameter of a function " + "that returns void">; // CHECK: returning address/reference of stack memory def warn_ret_stack_addr_ref : Warning< diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 746b706f1bee7d7cb1153ecc5e2639e2ec7f8115..d76402f904c93c9e36da9ecad451852c18035893 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -281,7 +281,6 @@ LANGOPT(OpenMPNoNestedParallelism , 1, 0, "Assume that no thread in a parallel LANGOPT(OpenMPOffloadMandatory , 1, 0, "Assert that offloading is mandatory and do not create a host fallback.") LANGOPT(OpenMPForceUSM , 1, 0, "Enable OpenMP unified shared memory mode via compiler.") LANGOPT(NoGPULib , 1, 0, "Indicate a build without the standard GPU libraries.") -LANGOPT(RenderScript , 1, 0, "RenderScript") LANGOPT(HLSL, 1, 0, "HLSL") ENUM_LANGOPT(HLSLVersion, HLSLLangStd, 16, HLSL_Unset, "HLSL Version") diff --git a/clang/include/clang/Basic/LangStandard.h b/clang/include/clang/Basic/LangStandard.h index 56a0d2c95e2b1917d48b830c851aa0c97990a631..49412232c9c5edd7587095cad886736f18735090 100644 --- a/clang/include/clang/Basic/LangStandard.h +++ b/clang/include/clang/Basic/LangStandard.h @@ -39,7 +39,6 @@ enum class Language : uint8_t { OpenCL, OpenCLCXX, CUDA, - RenderScript, HIP, HLSL, ///@} diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h index 9c5d33fbb562cc9b95daa8284814d3c137914e2a..dd384c1d76c5fde4c791d1f638005f28fabbc791 100644 --- a/clang/include/clang/Basic/Module.h +++ b/clang/include/clang/Basic/Module.h @@ -227,7 +227,7 @@ private: /// A mapping from the submodule name to the index into the /// \c SubModules vector at which that submodule resides. - llvm::StringMap SubModuleIndex; + mutable llvm::StringMap SubModuleIndex; /// The AST file if this is a top-level module which has a /// corresponding serialized AST file, or null otherwise. @@ -253,8 +253,6 @@ public: HK_PrivateTextual, HK_Excluded }; - static const int NumHeaderKinds = HK_Excluded + 1; - /// Information about a header directive as found in the module map /// file. struct Header { @@ -263,17 +261,36 @@ public: FileEntryRef Entry; }; - /// Information about a directory name as found in the module map - /// file. +private: + static const int NumHeaderKinds = HK_Excluded + 1; + // The begin index for a HeaderKind also acts the end index of HeaderKind - 1. + // The extra element at the end acts as the end index of the last HeaderKind. + unsigned HeaderKindBeginIndex[NumHeaderKinds + 1] = {}; + SmallVector HeadersStorage; + +public: + ArrayRef
getAllHeaders() const { return HeadersStorage; } + ArrayRef
getHeaders(HeaderKind HK) const { + assert(HK < NumHeaderKinds && "Invalid Module::HeaderKind"); + auto BeginIt = HeadersStorage.begin() + HeaderKindBeginIndex[HK]; + auto EndIt = HeadersStorage.begin() + HeaderKindBeginIndex[HK + 1]; + return {BeginIt, EndIt}; + } + void addHeader(HeaderKind HK, Header H) { + assert(HK < NumHeaderKinds && "Invalid Module::HeaderKind"); + auto EndIt = HeadersStorage.begin() + HeaderKindBeginIndex[HK + 1]; + HeadersStorage.insert(EndIt, std::move(H)); + for (unsigned HKI = HK + 1; HKI != NumHeaderKinds + 1; ++HKI) + ++HeaderKindBeginIndex[HKI]; + } + + /// Information about a directory name as found in the module map file. struct DirectoryName { std::string NameAsWritten; std::string PathRelativeToRootModuleDirectory; DirectoryEntryRef Entry; }; - /// The headers that are part of this module. - SmallVector Headers[5]; - /// Stored information about a header directive that was found in the /// module map file but has not been resolved to a file. struct UnresolvedHeaderDirective { @@ -595,7 +612,6 @@ public: void setParent(Module *M) { assert(!Parent); Parent = M; - Parent->SubModuleIndex[Name] = Parent->SubModules.size(); Parent->SubModules.push_back(this); } diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index e7469e1e989128ad881520c69118dd4bd6c429c2..25eda907d20a7bf30d0ef036d5f6776c00631cf8 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -262,9 +262,6 @@ protected: LLVM_PREFERRED_TYPE(bool) unsigned HasBuiltinMSVaList : 1; - LLVM_PREFERRED_TYPE(bool) - unsigned IsRenderScriptTarget : 1; - LLVM_PREFERRED_TYPE(bool) unsigned HasAArch64SVETypes : 1; @@ -1031,9 +1028,6 @@ public: /// available on this target. bool hasBuiltinMSVaList() const { return HasBuiltinMSVaList; } - /// Returns true for RenderScript. - bool isRenderScriptTarget() const { return IsRenderScriptTarget; } - /// Returns whether or not the AArch64 SVE built-in types are /// available on this target. bool hasAArch64SVETypes() const { return HasAArch64SVETypes; } @@ -1858,11 +1852,9 @@ protected: } virtual ArrayRef getGCCRegNames() const = 0; virtual ArrayRef getGCCRegAliases() const = 0; - virtual ArrayRef getGCCAddlRegNames() const { - return std::nullopt; - } + virtual ArrayRef getGCCAddlRegNames() const { return {}; } - private: +private: // Assert the values for the fractional and integral bits for each fixed point // type follow the restrictions given in clause 6.2.6.3 of N1169. void CheckFixedPointBits() const; diff --git a/clang/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h index d19f84d198876f5d1b1cdf6cde8817e8de2e32f7..9d785d878b61dcc8e7a866f6485a23a087b5c2ae 100644 --- a/clang/include/clang/CodeGen/CGFunctionInfo.h +++ b/clang/include/clang/CodeGen/CGFunctionInfo.h @@ -271,12 +271,8 @@ public: // in the unpadded type. unsigned unpaddedIndex = 0; for (auto eltType : coerceToType->elements()) { - if (isPaddingForCoerceAndExpand(eltType)) continue; - if (unpaddedStruct) { - assert(unpaddedStruct->getElementType(unpaddedIndex) == eltType); - } else { - assert(unpaddedIndex == 0 && unpaddedCoerceToType == eltType); - } + if (isPaddingForCoerceAndExpand(eltType)) + continue; unpaddedIndex++; } @@ -295,12 +291,8 @@ public: } static bool isPaddingForCoerceAndExpand(llvm::Type *eltType) { - if (eltType->isArrayTy()) { - assert(eltType->getArrayElementType()->isIntegerTy(8)); - return true; - } else { - return false; - } + return eltType->isArrayTy() && + eltType->getArrayElementType()->isIntegerTy(8); } Kind getKind() const { return TheKind; } diff --git a/clang/include/clang/Driver/Job.h b/clang/include/clang/Driver/Job.h index df9449463c53bd1a5f8f0b0d77889713d7e9bea5..561866197b7803a2ff077e633cc4af1c172eab15 100644 --- a/clang/include/clang/Driver/Job.h +++ b/clang/include/clang/Driver/Job.h @@ -172,8 +172,7 @@ public: Command(const Action &Source, const Tool &Creator, ResponseFileSupport ResponseSupport, const char *Executable, const llvm::opt::ArgStringList &Arguments, ArrayRef Inputs, - ArrayRef Outputs = std::nullopt, - const char *PrependArg = nullptr); + ArrayRef Outputs = {}, const char *PrependArg = nullptr); // FIXME: This really shouldn't be copyable, but is currently copied in some // error handling in Driver::generateCompilationDiagnostics. Command(const Command &) = default; @@ -245,8 +244,7 @@ public: CC1Command(const Action &Source, const Tool &Creator, ResponseFileSupport ResponseSupport, const char *Executable, const llvm::opt::ArgStringList &Arguments, - ArrayRef Inputs, - ArrayRef Outputs = std::nullopt, + ArrayRef Inputs, ArrayRef Outputs = {}, const char *PrependArg = nullptr); void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index d02bb9e28766a8115c2221dd46f4a771b349ee96..7e854eb088b7c95215f72ba605649208d2300fb1 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -627,7 +627,6 @@ defvar c23 = LangOpts<"C23">; defvar lang_std = LangOpts<"LangStd">; defvar open_cl = LangOpts<"OpenCL">; defvar cuda = LangOpts<"CUDA">; -defvar render_script = LangOpts<"RenderScript">; defvar hip = LangOpts<"HIP">; defvar gnu_mode = LangOpts<"GNUMode">; defvar asm_preprocessor = LangOpts<"AsmPreprocessor">; @@ -1787,6 +1786,12 @@ defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling", PosFlag, NegFlag>; +def fprofile_generate_cold_function_coverage : Flag<["-"], "fprofile-generate-cold-function-coverage">, + Group, Visibility<[ClangOption, CLOption]>, + HelpText<"Generate instrumented code to collect coverage info for cold functions into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">; +def fprofile_generate_cold_function_coverage_EQ : Joined<["-"], "fprofile-generate-cold-function-coverage=">, + Group, Visibility<[ClangOption, CLOption]>, MetaVarName<"">, + HelpText<"Generate instrumented code to collect coverage info for cold functions into /default.profraw (overridden by LLVM_PROFILE_FILE env var)">; def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">, Group, Visibility<[ClangOption, CLOption]>, HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">; @@ -2948,6 +2953,11 @@ def fxray_selected_function_group : HelpText<"When using -fxray-function-groups, select which group of functions to instrument. Valid range is 0 to fxray-function-groups - 1">, MarshallingInfoInt, "0">; +defm xray_shared : BoolFOption<"xray-shared", + CodeGenOpts<"XRayShared">, DefaultFalse, + PosFlag, + NegFlag>; defm fine_grained_bitfield_accesses : BoolOption<"f", "fine-grained-bitfield-accesses", CodeGenOpts<"FineGrainedBitfieldAccesses">, DefaultFalse, @@ -5117,6 +5127,8 @@ def msimd128 : Flag<["-"], "msimd128">, Group; def mno_simd128 : Flag<["-"], "mno-simd128">, Group; def mtail_call : Flag<["-"], "mtail-call">, Group; def mno_tail_call : Flag<["-"], "mno-tail-call">, Group; +def mwide_arithmetic : Flag<["-"], "mwide-arithmetic">, Group; +def mno_wide_arithmetic : Flag<["-"], "mno-wide-arithmetic">, Group; def mexec_model_EQ : Joined<["-"], "mexec-model=">, Group, Values<"command,reactor">, HelpText<"Execution model (WebAssembly only)">, @@ -5409,9 +5421,9 @@ def mfrecipe : Flag<["-"], "mfrecipe">, Group, def mno_frecipe : Flag<["-"], "mno-frecipe">, Group, HelpText<"Disable frecipe.{s/d} and frsqrte.{s/d}">; def mlam_bh : Flag<["-"], "mlam-bh">, Group, - HelpText<"Enable amswap_[db].{b/h} and amadd_[db].{b/h}">; + HelpText<"Enable amswap[_db].{b/h} and amadd[_db].{b/h}">; def mno_lam_bh : Flag<["-"], "mno-lam-bh">, Group, - HelpText<"Disable amswap_[db].{b/h} and amadd_[db].{b/h}">; + HelpText<"Disable amswap[_db].{b/h} and amadd[_db].{b/h}">; def mannotate_tablejump : Flag<["-"], "mannotate-tablejump">, Group, HelpText<"Enable annotate table jump instruction to correlate it with the jump table.">; def mno_annotate_tablejump : Flag<["-"], "mno-annotate-tablejump">, Group, @@ -5637,6 +5649,7 @@ def noprebind : Flag<["-"], "noprebind">; def noprofilelib : Flag<["-"], "noprofilelib">; def noseglinkedit : Flag<["-"], "noseglinkedit">; def nostartfiles : Flag<["-"], "nostartfiles">, Group; +def startfiles : Flag<["-"], "startfiles">, Group; def nostdinc : Flag<["-"], "nostdinc">, Visibility<[ClangOption, CLOption, DXCOption]>, Group, HelpText<"Disable both standard system #include directories and builtin #include directories">; @@ -5649,6 +5662,9 @@ def nostdincxx : Flag<["-"], "nostdinc++">, Visibility<[ClangOption, CC1Option]> def nostdlib : Flag<["-"], "nostdlib">, Visibility<[ClangOption, CLOption, FlangOption, DXCOption]>, Group; +def stdlib : Flag<["-"], "stdlib">, + Visibility<[ClangOption, CLOption, FlangOption, DXCOption]>, + Group; def nostdlibxx : Flag<["-"], "nostdlib++">; def object : Flag<["-"], "object">; def o : JoinedOrSeparate<["-"], "o">, @@ -6433,6 +6449,8 @@ def mmovdiri : Flag<["-"], "mmovdiri">, Group; def mno_movdiri : Flag<["-"], "mno-movdiri">, Group; def mmovdir64b : Flag<["-"], "mmovdir64b">, Group; def mno_movdir64b : Flag<["-"], "mno-movdir64b">, Group; +def mmovrs : Flag<["-"], "mmovrs">, Group; +def mno_movrs : Flag<["-"], "mno-movrs">, Group; def mmwaitx : Flag<["-"], "mmwaitx">, Group; def mno_mwaitx : Flag<["-"], "mno-mwaitx">, Group; def mpku : Flag<["-"], "mpku">, Group; @@ -8125,11 +8143,11 @@ def vtordisp_mode_EQ : Joined<["-"], "vtordisp-mode=">, def fnative_half_type: Flag<["-"], "fnative-half-type">, HelpText<"Use the native half type for __fp16 instead of promoting to float">, MarshallingInfoFlag>, - ImpliedByAnyOf<[open_cl.KeyPath, render_script.KeyPath]>; + ImpliedByAnyOf<[open_cl.KeyPath]>; def fnative_half_arguments_and_returns : Flag<["-"], "fnative-half-arguments-and-returns">, HelpText<"Use the native __fp16 type for arguments and returns (and skip ABI-specific lowering)">, MarshallingInfoFlag>, - ImpliedByAnyOf<[open_cl.KeyPath, render_script.KeyPath, hlsl.KeyPath, hip.KeyPath]>; + ImpliedByAnyOf<[open_cl.KeyPath, hlsl.KeyPath, hip.KeyPath]>; def fdefault_calling_conv_EQ : Joined<["-"], "fdefault-calling-conv=">, HelpText<"Set default calling convention">, Values<"cdecl,fastcall,stdcall,vectorcall,regcall,rtdcall">, diff --git a/clang/include/clang/Driver/Types.def b/clang/include/clang/Driver/Types.def index fd7db0e552a3136f68202cf87b3e970c6e43d735..ffc81e12b84b34101a4fade20214c882911dfd03 100644 --- a/clang/include/clang/Driver/Types.def +++ b/clang/include/clang/Driver/Types.def @@ -55,7 +55,6 @@ TYPE("c++", CXX, PP_CXX, "cpp", phases TYPE("objective-c++-cpp-output", PP_ObjCXX, INVALID, "mii", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("objc++-cpp-output", PP_ObjCXX_Alias, INVALID, "mii", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("objective-c++", ObjCXX, PP_ObjCXX, "mm", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link) -TYPE("renderscript", RenderScript, PP_C, "rs", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("hlsl", HLSL, PP_CXX, "hlsl", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble) // C family input files to precompile. diff --git a/clang/include/clang/Driver/XRayArgs.h b/clang/include/clang/Driver/XRayArgs.h index bdd3d979547eed5ea3ab27bb3c403aec1cd11bd8..1b5c4a4c42f12a793af2de8e9823816cfdf49129 100644 --- a/clang/include/clang/Driver/XRayArgs.h +++ b/clang/include/clang/Driver/XRayArgs.h @@ -27,6 +27,7 @@ class XRayArgs { XRayInstrSet InstrumentationBundle; llvm::opt::Arg *XRayInstrument = nullptr; bool XRayRT = true; + bool XRayShared = false; public: /// Parses the XRay arguments from an argument list. @@ -35,6 +36,7 @@ public: llvm::opt::ArgStringList &CmdArgs, types::ID InputType) const; bool needsXRayRt() const { return XRayInstrument && XRayRT; } + bool needsXRayDSORt() const { return XRayInstrument && XRayRT && XRayShared; } llvm::ArrayRef modeList() const { return Modes; } XRayInstrSet instrumentationBundle() const { return InstrumentationBundle; } }; diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index debba1c78228398cafdf5ae4cc66dc37f195e026..c9b72e65cb236dda7d9458b71741a58d84de351e 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -3207,6 +3207,13 @@ struct FormatStyle { /// \version 3.7 // bool KeepEmptyLinesAtTheStartOfBlocks; + /// Keep the form feed character if it's immediately preceded and followed by + /// a newline. Multiple form feeds and newlines within a whitespace range are + /// replaced with a single newline and form feed followed by the remaining + /// newlines. + /// \version 20 + bool KeepFormFeed; + /// Indentation logic for lambda bodies. enum LambdaBodyIndentationKind : int8_t { /// Align lambda body relative to the lambda signature. This is the default. @@ -5222,7 +5229,8 @@ struct FormatStyle { JavaImportGroups == R.JavaImportGroups && JavaScriptQuotes == R.JavaScriptQuotes && JavaScriptWrapImports == R.JavaScriptWrapImports && - KeepEmptyLines == R.KeepEmptyLines && Language == R.Language && + KeepEmptyLines == R.KeepEmptyLines && + KeepFormFeed == R.KeepFormFeed && Language == R.Language && LambdaBodyIndentation == R.LambdaBodyIndentation && LineEnding == R.LineEnding && MacroBlockBegin == R.MacroBlockBegin && MacroBlockEnd == R.MacroBlockEnd && Macros == R.Macros && @@ -5300,8 +5308,8 @@ struct FormatStyle { R.TableGenBreakingDAGArgOperators && TableGenBreakInsideDAGArg == R.TableGenBreakInsideDAGArg && TabWidth == R.TabWidth && TemplateNames == R.TemplateNames && - TabWidth == R.TabWidth && TypeNames == R.TypeNames && - TypenameMacros == R.TypenameMacros && UseTab == R.UseTab && + TypeNames == R.TypeNames && TypenameMacros == R.TypenameMacros && + UseTab == R.UseTab && VerilogBreakBetweenInstancePorts == R.VerilogBreakBetweenInstancePorts && WhitespaceSensitiveMacros == R.WhitespaceSensitiveMacros; diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h index 8cefae8587aa34cd96c0a23c36f5f5bb05d636ae..1f98c6ab328baa3a3da17ba4e252085ca2be1bf9 100644 --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -836,7 +836,7 @@ public: bool StorePreamblesInMemory = false, StringRef PreambleStoragePath = StringRef(), bool OnlyLocalDecls = false, CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, - ArrayRef RemappedFiles = std::nullopt, + ArrayRef RemappedFiles = {}, bool RemappedFilesKeepOriginalName = true, unsigned PrecompilePreambleAfterNParses = 0, TranslationUnitKind TUKind = TU_Complete, @@ -864,7 +864,7 @@ public: /// \returns True if a failure occurred that causes the ASTUnit not to /// contain any translation-unit information, false otherwise. bool Reparse(std::shared_ptr PCHContainerOps, - ArrayRef RemappedFiles = std::nullopt, + ArrayRef RemappedFiles = {}, IntrusiveRefCntPtr VFS = nullptr); /// Free data that will be re-generated on the next parse. diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index 75b567a347cb6cf5cbfa2b39cabb0f19eff2a254..53e9e0ec83ddb1fd2e64c83de710bab7f3a079df 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -546,6 +546,17 @@ public: std::pair findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework, bool IsExplicit); + /// Call \c ModuleMap::findOrCreateModule and throw away the information + /// whether the module was found or created. + Module *findOrCreateModuleFirst(StringRef Name, Module *Parent, + bool IsFramework, bool IsExplicit) { + return findOrCreateModule(Name, Parent, IsFramework, IsExplicit).first; + } + /// Create new submodule, assuming it does not exist. This function can only + /// be called when it is guaranteed that this submodule does not exist yet. + /// The parameters have same semantics as \c ModuleMap::findOrCreateModule. + Module *createModule(StringRef Name, Module *Parent, bool IsFramework, + bool IsExplicit); /// Create a global module fragment for a C++ module unit. /// diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 92749e4de44b577fbc67e41d25908a686a2a302f..38a527d2324ffe89069ad5c5f03043040df9b544 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -911,7 +911,7 @@ private: getActiveModuleMacros(Preprocessor &PP, const IdentifierInfo *II) const { if (auto *Info = getModuleInfo(PP, II)) return Info->ActiveModuleMacros; - return std::nullopt; + return {}; } MacroDirective::DefInfo findDirectiveAtLoc(SourceLocation Loc, @@ -935,7 +935,7 @@ private: ArrayRef getOverriddenMacros() const { if (auto *Info = State.dyn_cast()) return Info->OverriddenMacros; - return std::nullopt; + return {}; } void setOverriddenMacros(Preprocessor &PP, @@ -1444,7 +1444,7 @@ public: auto I = LeafModuleMacros.find(II); if (I != LeafModuleMacros.end()) return I->second; - return std::nullopt; + return {}; } /// Get the list of submodules that we're currently building. @@ -1490,7 +1490,7 @@ public: /// Mark the file as included. /// Returns true if this is the first time the file was included. bool markIncluded(FileEntryRef File) { - HeaderInfo.getFileInfo(File); + HeaderInfo.getFileInfo(File).IsLocallyIncluded = true; return IncludedFiles.insert(File).second; } diff --git a/clang/include/clang/Sema/CodeCompleteConsumer.h b/clang/include/clang/Sema/CodeCompleteConsumer.h index 0924dc27af82b512331dd3049f41319880c5cd48..2dd27593778c7cd735c089c5293de13e6e9cc749 100644 --- a/clang/include/clang/Sema/CodeCompleteConsumer.h +++ b/clang/include/clang/Sema/CodeCompleteConsumer.h @@ -375,12 +375,11 @@ private: public: /// Construct a new code-completion context of the given kind. CodeCompletionContext(Kind CCKind) - : CCKind(CCKind), IsUsingDeclaration(false), SelIdents(std::nullopt) {} + : CCKind(CCKind), IsUsingDeclaration(false), SelIdents() {} /// Construct a new code-completion context of the given kind. - CodeCompletionContext( - Kind CCKind, QualType T, - ArrayRef SelIdents = std::nullopt) + CodeCompletionContext(Kind CCKind, QualType T, + ArrayRef SelIdents = {}) : CCKind(CCKind), IsUsingDeclaration(false), SelIdents(SelIdents) { if (CCKind == CCC_DotMemberAccess || CCKind == CCC_ArrowMemberAccess || CCKind == CCC_ObjCPropertyAccess || CCKind == CCC_ObjCClassMessage || diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index c716a25bb673b8b36a743004d6901771f2a89454..58fa64c80a16f00d89b9477a9290ad6d29bde018 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -1206,9 +1206,8 @@ class Sema; /// Add a new candidate with NumConversions conversion sequence slots /// to the overload set. - OverloadCandidate & - addCandidate(unsigned NumConversions = 0, - ConversionSequenceList Conversions = std::nullopt) { + OverloadCandidate &addCandidate(unsigned NumConversions = 0, + ConversionSequenceList Conversions = {}) { assert((Conversions.empty() || Conversions.size() == NumConversions) && "preallocated conversion sequence has wrong length"); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 9e6b04bc3f8f7c527b08120f622d7f282ec8b1d5..93d98e1cbb9c8118ad879c9b429170f3030fb20c 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3478,10 +3478,12 @@ public: /// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'. NamedDecl *ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *D, LookupResult &Previous, bool &Redeclaration); - NamedDecl *ActOnVariableDeclarator( - Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, - LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, - bool &AddToScope, ArrayRef Bindings = std::nullopt); + NamedDecl *ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, + TypeSourceInfo *TInfo, + LookupResult &Previous, + MultiTemplateParamsArg TemplateParamLists, + bool &AddToScope, + ArrayRef Bindings = {}); /// Perform semantic checking on a newly-created variable /// declaration. @@ -5325,9 +5327,8 @@ public: bool SetDelegatingInitializer(CXXConstructorDecl *Constructor, CXXCtorInitializer *Initializer); - bool SetCtorInitializers( - CXXConstructorDecl *Constructor, bool AnyErrors, - ArrayRef Initializers = std::nullopt); + bool SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, + ArrayRef Initializers = {}); /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, /// mark all the non-trivial destructors of its members and bases as @@ -6623,9 +6624,9 @@ public: /// \param SkipLocalVariables If true, don't mark local variables as /// 'referenced'. /// \param StopAt Subexpressions that we shouldn't recurse into. - void MarkDeclarationsReferencedInExpr( - Expr *E, bool SkipLocalVariables = false, - ArrayRef StopAt = std::nullopt); + void MarkDeclarationsReferencedInExpr(Expr *E, + bool SkipLocalVariables = false, + ArrayRef StopAt = {}); /// Try to convert an expression \p E to type \p Ty. Returns the result of the /// conversion. @@ -6696,7 +6697,7 @@ public: DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, CorrectionCandidateCallback &CCC, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, - ArrayRef Args = std::nullopt, + ArrayRef Args = {}, DeclContext *LookupCtx = nullptr, TypoExpr **Out = nullptr); @@ -10124,15 +10125,17 @@ public: /// \param PartialOverloading true if we are performing "partial" overloading /// based on an incomplete set of function arguments. This feature is used by /// code completion. - void AddOverloadCandidate( - FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef Args, - OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, - bool PartialOverloading = false, bool AllowExplicit = true, - bool AllowExplicitConversion = false, - ADLCallKind IsADLCandidate = ADLCallKind::NotADL, - ConversionSequenceList EarlyConversions = std::nullopt, - OverloadCandidateParamOrder PO = {}, - bool AggregateCandidateDeduction = false); + void AddOverloadCandidate(FunctionDecl *Function, DeclAccessPair FoundDecl, + ArrayRef Args, + OverloadCandidateSet &CandidateSet, + bool SuppressUserConversions = false, + bool PartialOverloading = false, + bool AllowExplicit = true, + bool AllowExplicitConversion = false, + ADLCallKind IsADLCandidate = ADLCallKind::NotADL, + ConversionSequenceList EarlyConversions = {}, + OverloadCandidateParamOrder PO = {}, + bool AggregateCandidateDeduction = false); /// Add all of the function declarations in the given function set to /// the overload candidate set. @@ -10159,15 +10162,15 @@ public: /// both @c a1 and @c a2. If @p SuppressUserConversions, then don't /// allow user-defined conversions via constructors or conversion /// operators. - void - AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, QualType ObjectType, - Expr::Classification ObjectClassification, - ArrayRef Args, OverloadCandidateSet &CandidateSet, - bool SuppressUserConversions = false, - bool PartialOverloading = false, - ConversionSequenceList EarlyConversions = std::nullopt, - OverloadCandidateParamOrder PO = {}); + void AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, + ArrayRef Args, + OverloadCandidateSet &CandidateSet, + bool SuppressUserConversions = false, + bool PartialOverloading = false, + ConversionSequenceList EarlyConversions = {}, + OverloadCandidateParamOrder PO = {}); /// Add a C++ member function template as a candidate to the candidate /// set, using template argument deduction to produce an appropriate member @@ -12968,12 +12971,13 @@ public: bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, SourceRange InstantiationRange); - InstantiatingTemplate( - Sema &SemaRef, CodeSynthesisContext::SynthesisKind Kind, - SourceLocation PointOfInstantiation, SourceRange InstantiationRange, - Decl *Entity, NamedDecl *Template = nullptr, - ArrayRef TemplateArgs = std::nullopt, - sema::TemplateDeductionInfo *DeductionInfo = nullptr); + InstantiatingTemplate(Sema &SemaRef, + CodeSynthesisContext::SynthesisKind Kind, + SourceLocation PointOfInstantiation, + SourceRange InstantiationRange, Decl *Entity, + NamedDecl *Template = nullptr, + ArrayRef TemplateArgs = {}, + sema::TemplateDeductionInfo *DeductionInfo = nullptr); InstantiatingTemplate(const InstantiatingTemplate &) = delete; diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h index d994d1819b44237533d1b0a90040bdd09e56abda..41d05b2bfb078eb013055eaa2396447b7ad61ab2 100644 --- a/clang/include/clang/Sema/SemaInternal.h +++ b/clang/include/clang/Sema/SemaInternal.h @@ -58,7 +58,7 @@ inline InheritableAttr *getDLLAttr(Decl *D) { } /// Retrieve the depth and index of a template parameter. -inline std::pair getDepthAndIndex(NamedDecl *ND) { +inline std::pair getDepthAndIndex(const NamedDecl *ND) { if (const auto *TTP = dyn_cast(ND)) return std::make_pair(TTP->getDepth(), TTP->getIndex()); diff --git a/clang/include/clang/Sema/SemaObjC.h b/clang/include/clang/Sema/SemaObjC.h index 9367c680953f71f680562ef27f10a6505e8e7d98..1332eb4f4d4233babcc1310b4b3329842a20d63b 100644 --- a/clang/include/clang/Sema/SemaObjC.h +++ b/clang/include/clang/Sema/SemaObjC.h @@ -336,8 +336,8 @@ public: ObjCInterfaceDecl *ID); Decl *ActOnAtEnd(Scope *S, SourceRange AtEnd, - ArrayRef allMethods = std::nullopt, - ArrayRef allTUVars = std::nullopt); + ArrayRef allMethods = {}, + ArrayRef allTUVars = {}); struct ObjCArgInfo { IdentifierInfo *Name; diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index d6e56f85e2d54e4aea757f48b6509b6d25f9b9d7..a34551f6b5a19240b0b34e1ee4f5dd27a03c5ed6 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -274,7 +274,7 @@ public: "Parsed clause kind does not have a queue id expr list"); if (std::holds_alternative(Details)) - return ArrayRef{std::nullopt}; + return ArrayRef(); return std::get(Details).QueueIdExprs; } diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h index 6ef5062a261699e2b81b09ca713768b5bd9d2678..0b591a28537e213507f500782e0eedcf4f97debe 100644 --- a/clang/include/clang/Sema/SemaOpenMP.h +++ b/clang/include/clang/Sema/SemaOpenMP.h @@ -1270,21 +1270,21 @@ public: SourceLocation ModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, - ArrayRef UnresolvedReductions = std::nullopt); + ArrayRef UnresolvedReductions = {}); /// Called on well-formed 'task_reduction' clause. OMPClause *ActOnOpenMPTaskReductionClause( ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, - ArrayRef UnresolvedReductions = std::nullopt); + ArrayRef UnresolvedReductions = {}); /// Called on well-formed 'in_reduction' clause. OMPClause *ActOnOpenMPInReductionClause( ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, - ArrayRef UnresolvedReductions = std::nullopt); + ArrayRef UnresolvedReductions = {}); /// Called on well-formed 'linear' clause. OMPClause *ActOnOpenMPLinearClause( ArrayRef VarList, Expr *Step, SourceLocation StartLoc, @@ -1348,7 +1348,7 @@ public: OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef VarList, const OMPVarListLocTy &Locs, bool NoDiagnose = false, - ArrayRef UnresolvedMappers = std::nullopt); + ArrayRef UnresolvedMappers = {}); /// Called on well-formed 'num_teams' clause. OMPClause *ActOnOpenMPNumTeamsClause(ArrayRef VarList, SourceLocation StartLoc, @@ -1380,7 +1380,7 @@ public: CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, SourceLocation ColonLoc, ArrayRef VarList, const OMPVarListLocTy &Locs, - ArrayRef UnresolvedMappers = std::nullopt); + ArrayRef UnresolvedMappers = {}); /// Called on well-formed 'from' clause. OMPClause * ActOnOpenMPFromClause(ArrayRef MotionModifiers, @@ -1388,7 +1388,7 @@ public: CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, SourceLocation ColonLoc, ArrayRef VarList, const OMPVarListLocTy &Locs, - ArrayRef UnresolvedMappers = std::nullopt); + ArrayRef UnresolvedMappers = {}); /// Called on well-formed 'use_device_ptr' clause. OMPClause *ActOnOpenMPUseDevicePtrClause(ArrayRef VarList, const OMPVarListLocTy &Locs); diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index d368cfcee9d6b48d4e7986bb969775fd36300a78..859d3d16fb5ad54701ccf24f02d90300bd7d9b8c 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -44,7 +44,7 @@ namespace serialization { /// Version 4 of AST files also requires that the version control branch and /// revision match exactly, since there is no backward compatibility of /// AST files at this time. -const unsigned VERSION_MAJOR = 31; +const unsigned VERSION_MAJOR = 32; /// AST file minor version number supported by this version of /// Clang. @@ -54,7 +54,7 @@ const unsigned VERSION_MAJOR = 31; /// for the previous version could still support reading the new /// version by ignoring new kinds of subblocks), this number /// should be increased. -const unsigned VERSION_MINOR = 1; +const unsigned VERSION_MINOR = 0; /// An ID number that refers to an identifier in an AST file. /// @@ -1149,7 +1149,7 @@ enum PredefinedTypeIDs { /// /// Type IDs for non-predefined types will start at /// NUM_PREDEF_TYPE_IDs. -const unsigned NUM_PREDEF_TYPE_IDS = 511; +const unsigned NUM_PREDEF_TYPE_IDS = 513; // Ensure we do not overrun the predefined types we reserved // in the enum PredefinedTypeIDs above. diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index b476a40ebd2c8c308d1e31a48264aa9a267657f7..070c1c9a54f48c6a696f513f010b0181a6f37866 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -2335,6 +2335,8 @@ public: /// Translate a FileID from another module file's FileID space into ours. FileID TranslateFileID(ModuleFile &F, FileID FID) const { assert(FID.ID >= 0 && "Reading non-local FileID."); + if (FID.isInvalid()) + return FID; return FileID::get(F.SLocEntryBaseID + FID.ID - 1); } diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 349040c15eeb83e1598c55e9508a555785065d0b..9a6b35c1b9f774ef65cbadee89a151fc0d58b303 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -118,8 +118,6 @@ def Debug : Package<"debug">, Hidden; def CloneDetectionAlpha : Package<"clone">, ParentPackage; -def NonDeterminismAlpha : Package<"nondeterminism">, ParentPackage; - def Fuchsia : Package<"fuchsia">; def FuchsiaAlpha : Package<"fuchsia">, ParentPackage; @@ -1711,22 +1709,6 @@ def TaintedDivChecker: Checker<"TaintedDiv">, } // end "optin.taint" -//===----------------------------------------------------------------------===// -// NonDeterminism checkers. -//===----------------------------------------------------------------------===// - -let ParentPackage = NonDeterminismAlpha in { - -def PointerIterationChecker : Checker<"PointerIteration">, - HelpText<"Checks for non-determinism caused by iteration of unordered containers of pointers">, - Documentation; - -def PointerSortingChecker : Checker<"PointerSorting">, - HelpText<"Check for non-determinism caused by sorting of pointers">, - Documentation; - -} // end alpha.nondeterminism - //===----------------------------------------------------------------------===// // Fuchsia checkers. //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index ead96ce6891c39a261fc47fe73b0753611d5eaaa..8974342166fadda4d4d218a3a59d00c4478ec0b8 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -644,14 +644,14 @@ public: void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, - ArrayRef Ranges = std::nullopt, - ArrayRef Fixits = std::nullopt); + ArrayRef Ranges = {}, + ArrayRef Fixits = {}); void EmitBasicReport(const Decl *DeclWithIssue, CheckerNameRef CheckerName, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, - ArrayRef Ranges = std::nullopt, - ArrayRef Fixits = std::nullopt); + ArrayRef Ranges = {}, + ArrayRef Fixits = {}); private: llvm::StringMap> StrBugTypes; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index 549c864dc91ef2f74984122155f62c27152afe86..4552df2a2a31e66a933d1fd04f64347fa6995d75 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -690,6 +690,11 @@ protected: ValueList &Values, RegionAndSymbolInvalidationTraits *ETraits) const override; + /// Returns the decl refered to by the "dynamic type" of the current object + /// and if the class can be a sub-class or not. + /// If the Pointer is null, the flag has no meaning. + std::pair getDeclForDynamicType() const; + public: /// Returns the expression representing the implicit 'this' object. virtual const Expr *getCXXThisExpr() const { return nullptr; } diff --git a/clang/lib/ARCMigrate/Internals.h b/clang/lib/ARCMigrate/Internals.h index d790c7c02189b8dd5750c65d82df0bcadffa8498..de6ebdce1bea1635ca69d66422bd9b1d9ade73f2 100644 --- a/clang/lib/ARCMigrate/Internals.h +++ b/clang/lib/ARCMigrate/Internals.h @@ -74,7 +74,7 @@ public: bool clearDiagnostic(ArrayRef IDs, SourceRange range); bool clearAllDiagnostics(SourceRange range) { - return clearDiagnostic(std::nullopt, range); + return clearDiagnostic({}, range); } bool clearDiagnostic(unsigned ID1, unsigned ID2, SourceRange range) { unsigned IDs[] = { ID1, ID2 }; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index dfee55b0dbbc239ed358a5ff356c348d54bf4d5d..a3664695f0961e84da7826e675aac8b334c49182 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1052,7 +1052,7 @@ ASTContext::getModulesWithMergedDefinition(const NamedDecl *Def) { auto MergedIt = MergedDefModules.find(cast(Def->getCanonicalDecl())); if (MergedIt == MergedDefModules.end()) - return std::nullopt; + return {}; return MergedIt->second; } @@ -1111,7 +1111,7 @@ void ASTContext::addLazyModuleInitializers(Module *M, ArrayRef ASTContext::getModuleInitializers(Module *M) { auto It = ModuleInitializers.find(M); if (It == ModuleInitializers.end()) - return std::nullopt; + return {}; auto *Inits = It->second; Inits->resolve(*this); diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index b7a6c224c80f8e9c3f9ee68a3f7170e3da0f1d98..513d4512b45cff49ae1228c070152f59b6f51a1f 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -400,7 +400,7 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { } static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { - if (!Ptr.isBlockPointer()) + if (!Ptr.isStatic() || !Ptr.isBlockPointer()) return true; return CheckConstant(S, OpPC, Ptr.getDeclDesc()); } @@ -513,8 +513,8 @@ bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return false; } -bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - AccessKinds AK) { +static bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + AccessKinds AK) { assert(Ptr.isLive()); // FIXME: This check here might be kinda expensive. Maybe it would be better @@ -1451,6 +1451,11 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, << StorageType << AllocType; return false; } + + // Can't activate fields in a union, unless the direct base is the union. + if (Ptr.inUnion() && !Ptr.isActive() && !Ptr.getBase().getRecord()->isUnion()) + return CheckActive(S, OpPC, Ptr, AK_Construct); + return true; } diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 10e33c14f4b455b95192dbbdc8eb5f13aefe9490..b00d2a1768b6b716109fcf75ea0b782b60829743 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -1670,6 +1670,15 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC, S, OpPC, *AllocForm, DynamicAllocator::Form::Operator, BlockDesc, Source); } +static bool interp__builtin_arithmetic_fence(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *Func, + const CallExpr *Call) { + const Floating &Arg0 = S.Stk.peek(); + S.Stk.push(Arg0); + return true; +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call, uint32_t BuiltinID) { const InterpFrame *Frame = S.Current; @@ -2111,6 +2120,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return false; break; + case Builtin::BI__arithmetic_fence: + if (!interp__builtin_arithmetic_fence(S, OpPC, Frame, F, Call)) + return false; + break; + default: S.FFDiag(S.Current->getLocation(OpPC), diag::note_invalid_subexpr_in_const_expr) diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index 72e255dba13f6bad4c4be51c7edd41855cffbcd3..457fe93b278175796b32210ca9120af83fc45cb6 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -653,15 +653,6 @@ public: return *reinterpret_cast(asBlockPointer().Pointee->rawData() + Offset); } - /// Dereferences a primitive element. - template T &elem(unsigned I) const { - assert(I < getNumElems()); - assert(isBlockPointer()); - assert(asBlockPointer().Pointee); - return reinterpret_cast(asBlockPointer().Pointee->data() + - sizeof(InitMapPtr))[I]; - } - /// Whether this block can be read from at all. This is only true for /// block pointers that point to a valid location inside that block. bool isDereferencable() const { diff --git a/clang/lib/AST/Comment.cpp b/clang/lib/AST/Comment.cpp index cce8b12170f21fdd31fc0b4ba7aed828ebb0cb57..d022c5c845ae62be1752a6a159280f5a6759a8cc 100644 --- a/clang/lib/AST/Comment.cpp +++ b/clang/lib/AST/Comment.cpp @@ -210,7 +210,7 @@ void DeclInfo::fill() { IsInstanceMethod = false; IsClassMethod = false; IsVariadic = false; - ParamVars = std::nullopt; + ParamVars = {}; TemplateParameters = nullptr; if (!CommentDecl) { diff --git a/clang/lib/AST/CommentParser.cpp b/clang/lib/AST/CommentParser.cpp index d5e5bb27ceba3cab950097dd3597c057e7de8b35..61508fe886efc016001615b1c40ff52c1c13d8fd 100644 --- a/clang/lib/AST/CommentParser.cpp +++ b/clang/lib/AST/CommentParser.cpp @@ -499,7 +499,7 @@ BlockCommandComment *Parser::parseBlockCommand() { if (isTokBlockCommand()) { // Block command ahead. We can't nest block commands, so pretend that this // command has an empty argument. - ParagraphComment *Paragraph = S.actOnParagraphComment(std::nullopt); + ParagraphComment *Paragraph = S.actOnParagraphComment({}); if (PC) { S.actOnParamCommandFinish(PC, Paragraph); return PC; @@ -547,7 +547,7 @@ BlockCommandComment *Parser::parseBlockCommand() { ParagraphComment *Paragraph; if (EmptyParagraph) - Paragraph = S.actOnParagraphComment(std::nullopt); + Paragraph = S.actOnParagraphComment({}); else { BlockContentComment *Block = parseParagraphOrBlockCommand(); // Since we have checked for a block command, we should have parsed a diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index ba68ebbb197964fda62914bae2d5b6beb7613d1b..9800239c89248ae5b99c415942aed7ba7fff9367 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -5507,9 +5507,8 @@ IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IndirectFieldDecl *IndirectFieldDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { - return new (C, ID) - IndirectFieldDecl(C, nullptr, SourceLocation(), DeclarationName(), - QualType(), std::nullopt); + return new (C, ID) IndirectFieldDecl(C, nullptr, SourceLocation(), + DeclarationName(), QualType(), {}); } SourceRange EnumConstantDecl::getSourceRange() const { @@ -5749,7 +5748,7 @@ ImportDecl *ImportDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, ArrayRef ImportDecl::getIdentifierLocs() const { if (!isImportComplete()) - return std::nullopt; + return {}; const auto *StoredLocs = getTrailingObjects(); return llvm::ArrayRef(StoredLocs, diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 17ebee0d6b22fa2fe6171423809bcda690d9e077..db0ea62a2323eb08f21fdd691dacf18f569ad1c9 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -3293,8 +3293,7 @@ UsingPackDecl *UsingPackDecl::Create(ASTContext &C, DeclContext *DC, UsingPackDecl *UsingPackDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumExpansions) { size_t Extra = additionalSizeToAlloc(NumExpansions); - auto *Result = - new (C, ID, Extra) UsingPackDecl(nullptr, nullptr, std::nullopt); + auto *Result = new (C, ID, Extra) UsingPackDecl(nullptr, nullptr, {}); Result->NumExpansions = NumExpansions; auto *Trail = Result->getTrailingObjects(); for (unsigned I = 0; I != NumExpansions; ++I) @@ -3443,7 +3442,7 @@ DecompositionDecl *DecompositionDecl::CreateDeserialized(ASTContext &C, size_t Extra = additionalSizeToAlloc(NumBindings); auto *Result = new (C, ID, Extra) DecompositionDecl(C, nullptr, SourceLocation(), SourceLocation(), - QualType(), nullptr, StorageClass(), std::nullopt); + QualType(), nullptr, StorageClass(), {}); // Set up and clean out the bindings array. Result->NumBindings = NumBindings; auto *Trail = Result->getTrailingObjects(); diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 83062b0e68878d4e42d6b68d808e1e1eea852bc4..ae8a310769260ce314c87d43e1f6d49f29cdfe93 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -947,12 +947,12 @@ void ObjCMethodDecl::setMethodParams(ASTContext &C, assert((!SelLocs.empty() || isImplicit()) && "No selector locs for non-implicit method"); if (isImplicit()) - return setParamsAndSelLocs(C, Params, std::nullopt); + return setParamsAndSelLocs(C, Params, {}); setSelLocsKind(hasStandardSelectorLocs(getSelector(), SelLocs, Params, DeclEndLoc)); if (getSelLocsKind() != SelLoc_NonStandard) - return setParamsAndSelLocs(C, Params, std::nullopt); + return setParamsAndSelLocs(C, Params, {}); setParamsAndSelLocs(C, Params, SelLocs); } diff --git a/clang/lib/AST/DeclOpenMP.cpp b/clang/lib/AST/DeclOpenMP.cpp index 81ca48e60942d5a69c7d5a3f873459dae4a79afe..32c82f614d6f273432fabcee90ad4d83df23ba48 100644 --- a/clang/lib/AST/DeclOpenMP.cpp +++ b/clang/lib/AST/DeclOpenMP.cpp @@ -30,7 +30,7 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, SourceLocation L, ArrayRef VL) { auto *D = OMPDeclarativeDirective::createDirective( - C, DC, std::nullopt, VL.size(), L); + C, DC, {}, VL.size(), L); D->setVars(VL); return D; } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index d2d8907b884ec88386a8a602b54446fb96b08a40..4a506b7be4564298a58c13ee6f92a5f8f09172d7 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -794,8 +794,7 @@ NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, additionalSizeToAlloc, Expr *>( NumExpandedTypes, HasTypeConstraint ? 1 : 0)) NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(), - 0, 0, nullptr, QualType(), nullptr, - std::nullopt, std::nullopt); + 0, 0, nullptr, QualType(), nullptr, {}, {}); NTTP->NumExpandedTypes = NumExpandedTypes; return NTTP; } @@ -870,7 +869,7 @@ TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, auto *TTP = new (C, ID, additionalSizeToAlloc(NumExpansions)) TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0, nullptr, - false, nullptr, std::nullopt); + false, nullptr, {}); TTP->NumExpandedParams = NumExpansions; return TTP; } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 66db6263cb1bd2573972788dfd2754c74d10dcd9..bf2c1b92fa6b49b4e996ca241151a2088a0302b0 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4720,8 +4720,7 @@ DesignatedInitUpdateExpr::DesignatedInitUpdateExpr(const ASTContext &C, OK_Ordinary) { BaseAndUpdaterExprs[0] = baseExpr; - InitListExpr *ILE = - new (C) InitListExpr(C, lBraceLoc, std::nullopt, rBraceLoc); + InitListExpr *ILE = new (C) InitListExpr(C, lBraceLoc, {}, rBraceLoc); ILE->setType(baseExpr->getType()); BaseAndUpdaterExprs[1] = ILE; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 8e36cad2d2c6e7552caa4b7b24430b7c905b0083..d664c503655ba6b8e959814c52f11647aca941ab 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -11579,6 +11579,9 @@ bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr( LValue Subobject = This; Subobject.addArray(Info, ExprToVisit, CAT); auto Eval = [&](const Expr *Init, unsigned ArrayIndex) { + if (Init->isValueDependent()) + return EvaluateDependentExpr(Init, Info); + if (!EvaluateInPlace(Result.getArrayInitializedElt(ArrayIndex), Info, Subobject, Init) || !HandleLValueArrayAdjustment(Info, Init, Subobject, diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index 3931fcaa3529610ae5b0c63e1c17b919a8328834..dbc161347025c0df7d9bbc0abf4d97c334d62548 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -397,7 +397,7 @@ public: void mangleBits(llvm::APInt Number); void mangleTagTypeKind(TagTypeKind TK); void mangleArtificialTagType(TagTypeKind TK, StringRef UnqualifiedName, - ArrayRef NestedNames = std::nullopt); + ArrayRef NestedNames = {}); void mangleAddressSpaceType(QualType T, Qualifiers Quals, SourceRange Range); void mangleType(QualType T, SourceRange Range, QualifierMangleMode QMM = QMM_Mangle); diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp index 08264888e22b77284f2b1644207398f51cddb832..614f78f6eb379038c030ba04d81a6c637bdf6b3e 100644 --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -452,8 +452,7 @@ OMPReverseDirective::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AssociatedStmt, Stmt *TransformedStmt, Stmt *PreInits) { OMPReverseDirective *Dir = createDirective( - C, std::nullopt, AssociatedStmt, TransformedStmtOffset + 1, StartLoc, - EndLoc); + C, {}, AssociatedStmt, TransformedStmtOffset + 1, StartLoc, EndLoc); Dir->setTransformedStmt(TransformedStmt); Dir->setPreInits(PreInits); return Dir; @@ -555,7 +554,7 @@ OMPSectionDirective *OMPSectionDirective::Create(const ASTContext &C, Stmt *AssociatedStmt, bool HasCancel) { auto *Dir = - createDirective(C, std::nullopt, AssociatedStmt, + createDirective(C, {}, AssociatedStmt, /*NumChildren=*/0, StartLoc, EndLoc); Dir->setHasCancel(HasCancel); return Dir; @@ -605,7 +604,7 @@ OMPMasterDirective *OMPMasterDirective::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AssociatedStmt) { - return createDirective(C, std::nullopt, AssociatedStmt, + return createDirective(C, {}, AssociatedStmt, /*NumChildren=*/0, StartLoc, EndLoc); } diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp index 127e843d4ead21637f6a29c6dcd9811403df2ec6..c5f35b35ad357925597080b91e55157522e2bd91 100644 --- a/clang/lib/Analysis/BodyFarm.cpp +++ b/clang/lib/Analysis/BodyFarm.cpp @@ -542,7 +542,7 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { CallExpr *CE = CallExpr::Create( /*ASTContext=*/C, /*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Block), - /*Args=*/std::nullopt, + /*Args=*/{}, /*QualType=*/C.VoidTy, /*ExprValueType=*/VK_PRValue, /*SourceLocation=*/SourceLocation(), FPOptionsOverride()); @@ -610,7 +610,7 @@ static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) { ASTMaker M(C); DeclRefExpr *DR = M.makeDeclRefExpr(PV); ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); - CallExpr *CE = CallExpr::Create(C, ICE, std::nullopt, C.VoidTy, VK_PRValue, + CallExpr *CE = CallExpr::Create(C, ICE, {}, C.VoidTy, VK_PRValue, SourceLocation(), FPOptionsOverride()); return CE; } diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp index a36cb41a63dfb152527e01f163e47b2f662ba7c6..557df218837941b136e40782f233260a59c1f39b 100644 --- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp +++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp @@ -133,8 +133,7 @@ public: for (const auto &Child : RLoc->children()) JOS.attributeObject("f:" + Child.first->getNameAsString(), [&] { if (Child.second) - if (Value *Val = Env.getValue(*Child.second)) - dump(*Val); + dump(*Child.second); }); for (const auto &SyntheticField : RLoc->synthetic_fields()) diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp index b0bd8274405d02ecca4d3ee3f3b95e8a7db04e58..da5dda063344f9746d53d1e9ef90c5144b7bd113 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -338,6 +338,11 @@ auto isZeroParamConstMemberCall() { callee(cxxMethodDecl(parameterCountIs(0), isConst()))); } +auto isZeroParamConstMemberOperatorCall() { + return cxxOperatorCallExpr( + callee(cxxMethodDecl(parameterCountIs(0), isConst()))); +} + auto isNonConstMemberCall() { return cxxMemberCallExpr(callee(cxxMethodDecl(unless(isConst())))); } @@ -572,9 +577,10 @@ void handleConstMemberCall(const CallExpr *CE, return; } - // Cache if the const method returns a boolean type. + // Cache if the const method returns a boolean or pointer type. // We may decide to cache other return types in the future. - if (RecordLoc != nullptr && CE->getType()->isBooleanType()) { + if (RecordLoc != nullptr && + (CE->getType()->isBooleanType() || CE->getType()->isPointerType())) { Value *Val = State.Lattice.getOrCreateConstMethodReturnValue(*RecordLoc, CE, State.Env); if (Val == nullptr) @@ -597,14 +603,26 @@ void transferValue_ConstMemberCall(const CXXMemberCallExpr *MCE, MCE, dataflow::getImplicitObjectLocation(*MCE, State.Env), Result, State); } +void transferValue_ConstMemberOperatorCall( + const CXXOperatorCallExpr *OCE, const MatchFinder::MatchResult &Result, + LatticeTransferState &State) { + auto *RecordLoc = cast_or_null( + State.Env.getStorageLocation(*OCE->getArg(0))); + handleConstMemberCall(OCE, RecordLoc, Result, State); +} + void handleNonConstMemberCall(const CallExpr *CE, dataflow::RecordStorageLocation *RecordLoc, const MatchFinder::MatchResult &Result, LatticeTransferState &State) { - // When a non-const member function is called, reset some state. if (RecordLoc != nullptr) { + // When a non-const member function is called, clear all (non-const) + // optional fields of the receiver. Const-qualified fields can't be + // changed (at least, not without UB). for (const auto &[Field, FieldLoc] : RecordLoc->children()) { - if (isSupportedOptionalType(Field->getType())) { + QualType FieldType = Field->getType(); + if (!FieldType.isConstQualified() && + isSupportedOptionalType(Field->getType())) { auto *FieldRecordLoc = cast_or_null(FieldLoc); if (FieldRecordLoc) { setHasValue(*FieldRecordLoc, State.Env.makeAtomicBoolValue(), @@ -1016,6 +1034,8 @@ auto buildTransferMatchSwitch() { // const accessor calls .CaseOfCFGStmt(isZeroParamConstMemberCall(), transferValue_ConstMemberCall) + .CaseOfCFGStmt(isZeroParamConstMemberOperatorCall(), + transferValue_ConstMemberOperatorCall) // non-const member calls that may modify the state of an object. .CaseOfCFGStmt(isNonConstMemberCall(), transferValue_NonConstMemberCall) diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 8afd18b315d286d0e314f1053f20abf91bbfdad8..32b3886439495f838129e0033c897bd261610f59 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -30,6 +30,7 @@ #include "clang/Analysis/FlowSensitive/Transfer.h" #include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" #include "clang/Analysis/FlowSensitive/Value.h" +#include "clang/Support/Compiler.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" @@ -37,6 +38,20 @@ #define DEBUG_TYPE "clang-dataflow" +namespace clang { +namespace dataflow { +class NoopLattice; +} +} // namespace clang + +namespace llvm { +// This needs to be exported for ClangAnalysisFlowSensitiveTests so any_cast +// uses the correct address of Any::TypeId from the clang shared library instead +// of creating one in the test executable. when building with +// CLANG_LINK_CLANG_DYLIB +template struct CLANG_EXPORT_TEMPLATE Any::TypeId; +} // namespace llvm + namespace clang { namespace dataflow { diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index 5e0ec9ecc92ea4332eaffeb6793947bc721d732b..fad2f52e89ef149ad67aad2efe46f9e2b0631adf 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -3605,7 +3605,7 @@ public: auto It = VarGrpMap.find(Var); if (It == VarGrpMap.end()) - return std::nullopt; + return {}; return Groups[It->second]; } diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp index da3216ae03af2e62f5ce0ae6a8ab2d769a489701..94caf6a3897bc1cba2e06d483bc843ab3b0e7cbf 100644 --- a/clang/lib/Basic/LangOptions.cpp +++ b/clang/lib/Basic/LangOptions.cpp @@ -203,8 +203,6 @@ void LangOptions::setLangDefaults(LangOptions &Opts, Language Lang, Opts.setDefaultFPContractMode(LangOptions::FPM_Fast); } - Opts.RenderScript = Lang == Language::RenderScript; - // OpenCL, C++ and C23 have bool, true, false keywords. Opts.Bool = Opts.OpenCL || Opts.CPlusPlus || Opts.C23; diff --git a/clang/lib/Basic/LangStandards.cpp b/clang/lib/Basic/LangStandards.cpp index 214567a53efe95a8120eec151c32f6b3fe16552b..c49d095018b200286cbee78b8cb72d28d12e6de2 100644 --- a/clang/lib/Basic/LangStandards.cpp +++ b/clang/lib/Basic/LangStandards.cpp @@ -37,8 +37,6 @@ StringRef clang::languageToString(Language L) { return "OpenCLC++"; case Language::CUDA: return "CUDA"; - case Language::RenderScript: - return "RenderScript"; case Language::HIP: return "HIP"; case Language::HLSL: @@ -114,8 +112,6 @@ LangStandard::Kind clang::getDefaultLanguageStandard(clang::Language Lang, case Language::CUDA: case Language::HIP: return LangStandard::lang_gnucxx17; - case Language::RenderScript: - return LangStandard::lang_c99; case Language::HLSL: return LangStandard::lang_hlsl202x; } diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp index ad52fccff5dc7ff5340b8609e5d2b07ee0eb3793..330108d5b3e47f6047c9698f258022cda6bf8cfb 100644 --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -54,7 +54,6 @@ Module::Module(ModuleConstructorTag, StringRef Name, NoUndeclaredIncludes = Parent->NoUndeclaredIncludes; ModuleMapIsPrivate = Parent->ModuleMapIsPrivate; - Parent->SubModuleIndex[Name] = Parent->SubModules.size(); Parent->SubModules.push_back(this); } } @@ -351,11 +350,14 @@ void Module::markUnavailable(bool Unimportable) { } Module *Module::findSubmodule(StringRef Name) const { - llvm::StringMap::const_iterator Pos = SubModuleIndex.find(Name); - if (Pos == SubModuleIndex.end()) - return nullptr; + // Add new submodules into the index. + for (unsigned I = SubModuleIndex.size(), E = SubModules.size(); I != E; ++I) + SubModuleIndex[SubModules[I]->Name] = I; - return SubModules[Pos->getValue()]; + if (auto It = SubModuleIndex.find(Name); It != SubModuleIndex.end()) + return SubModules[It->second]; + + return nullptr; } Module *Module::getGlobalModuleFragment() const { @@ -528,7 +530,7 @@ void Module::print(raw_ostream &OS, unsigned Indent, bool Dump) const { for (auto &K : Kinds) { assert(&K == &Kinds[K.Kind] && "kinds in wrong order"); - for (auto &H : Headers[K.Kind]) { + for (auto &H : getHeaders(K.Kind)) { OS.indent(Indent + 2); OS << K.Prefix << "header \""; OS.write_escaped(H.NameAsWritten); diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 145ca545854da7daf50dc29160063706dba79748..86befb1cbc74fc8c48d63ded032d18b8210a1f78 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -154,7 +154,6 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) { SSERegParmMax = 0; HasAlignMac68kSupport = false; HasBuiltinMSVaList = false; - IsRenderScriptTarget = false; HasAArch64SVETypes = false; HasRISCVVTypes = false; AllowAMDGPUUnsafeFPAtomics = false; diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 4917ef015941be422a9a9ba275fbb718feb5e1fc..0021d33c45d7c9b47d2f372635edef5fe5041bf5 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -710,12 +710,6 @@ std::unique_ptr AllocateTarget(const llvm::Triple &Triple, case llvm::Triple::dxil: return std::make_unique(Triple, Opts); - case llvm::Triple::renderscript32: - return std::make_unique>(Triple, - Opts); - case llvm::Triple::renderscript64: - return std::make_unique>(Triple, - Opts); case llvm::Triple::ve: return std::make_unique>(Triple, Opts); diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 3dbba2b4d25bd6c96579323ef4cab5021892e051..a0f94d5d3154807f757a4985e33f5273c3696fe5 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -1723,19 +1723,3 @@ TargetInfo::BuiltinVaListKind DarwinAArch64TargetInfo::getBuiltinVaListKind() const { return TargetInfo::CharPtrBuiltinVaList; } - -// 64-bit RenderScript is aarch64 -RenderScript64TargetInfo::RenderScript64TargetInfo(const llvm::Triple &Triple, - const TargetOptions &Opts) - : AArch64leTargetInfo(llvm::Triple("aarch64", Triple.getVendorName(), - Triple.getOSName(), - Triple.getEnvironmentName()), - Opts) { - IsRenderScriptTarget = true; -} - -void RenderScript64TargetInfo::getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - Builder.defineMacro("__RENDERSCRIPT__"); - AArch64leTargetInfo::getTargetDefines(Opts, Builder); -} diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index 16a02e102e045d644d2b26e3ecd30663f6b7e317..ea3e4015d842653eca5b353186e181343d141ce7 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -319,17 +319,6 @@ public: MacroBuilder &Builder) const override; }; -// 64-bit RenderScript is aarch64 -class LLVM_LIBRARY_VISIBILITY RenderScript64TargetInfo - : public AArch64leTargetInfo { -public: - RenderScript64TargetInfo(const llvm::Triple &Triple, - const TargetOptions &Opts); - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override; -}; - } // namespace targets } // namespace clang diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h index 94d9ba93ed226f75cb868931b6107b6b6516b731..6edd3474d4edae3b4370aeb881c277ee95d1443b 100644 --- a/clang/lib/Basic/Targets/AMDGPU.h +++ b/clang/lib/Basic/Targets/AMDGPU.h @@ -122,7 +122,7 @@ public: ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override { - return std::nullopt; + return {}; } /// Accepted register names: (n, m is unsigned integer, n < m) diff --git a/clang/lib/Basic/Targets/ARC.h b/clang/lib/Basic/Targets/ARC.h index fcbfdd6eec5862ee5ca3c497a37fa3200ef1c8a8..7f3d0aa15ab81fb439e073211c7a4be1e6d0c453 100644 --- a/clang/lib/Basic/Targets/ARC.h +++ b/clang/lib/Basic/Targets/ARC.h @@ -40,9 +40,7 @@ public: void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - ArrayRef getTargetBuiltins() const override { - return std::nullopt; - } + ArrayRef getTargetBuiltins() const override { return {}; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; @@ -60,7 +58,7 @@ public: } ArrayRef getGCCRegAliases() const override { - return std::nullopt; + return {}; } bool validateAsmConstraint(const char *&Name, diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index c87300bf2d60e0407851c395ef294baae1d476a5..370444057b42981b19e2d6c305480aa211dd683b 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -1498,19 +1498,3 @@ void DarwinARMTargetInfo::getOSDefines(const LangOptions &Opts, MacroBuilder &Builder) const { getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); } - -RenderScript32TargetInfo::RenderScript32TargetInfo(const llvm::Triple &Triple, - const TargetOptions &Opts) - : ARMleTargetInfo(llvm::Triple("armv7", Triple.getVendorName(), - Triple.getOSName(), - Triple.getEnvironmentName()), - Opts) { - IsRenderScriptTarget = true; - LongWidth = LongAlign = 64; -} - -void RenderScript32TargetInfo::getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - Builder.defineMacro("__RENDERSCRIPT__"); - ARMleTargetInfo::getTargetDefines(Opts, Builder); -} diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h index df9855a52e61c0fd38520675f06e5cbac3dd9433..55ecb99d82d8fb1b99e70d5b0cba255813ec14da 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -310,17 +310,6 @@ public: DarwinARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); }; -// 32-bit RenderScript is armv7 with width and align of 'long' set to 8-bytes -class LLVM_LIBRARY_VISIBILITY RenderScript32TargetInfo - : public ARMleTargetInfo { -public: - RenderScript32TargetInfo(const llvm::Triple &Triple, - const TargetOptions &Opts); - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override; -}; - } // namespace targets } // namespace clang diff --git a/clang/lib/Basic/Targets/AVR.h b/clang/lib/Basic/Targets/AVR.h index 0a2f51747f8a7f65c17f12f617e018130ab9d2ca..df1f8d171efbaae2720b2303dc2407979151c0dd 100644 --- a/clang/lib/Basic/Targets/AVR.h +++ b/clang/lib/Basic/Targets/AVR.h @@ -63,9 +63,7 @@ public: void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - ArrayRef getTargetBuiltins() const override { - return std::nullopt; - } + ArrayRef getTargetBuiltins() const override { return {}; } bool allowsLargerPreferedTypeAlignment() const override { return false; } @@ -84,7 +82,7 @@ public: } ArrayRef getGCCRegAliases() const override { - return std::nullopt; + return {}; } ArrayRef getGCCAddlRegNames() const override { diff --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h index d19b37dd4df7a7d2cbf42b4321079a8d5ca9f8aa..27a4b5f31497024776cf9f6bd7193ac09b34e415 100644 --- a/clang/lib/Basic/Targets/BPF.h +++ b/clang/lib/Basic/Targets/BPF.h @@ -67,9 +67,7 @@ public: } bool isValidGCCRegisterName(StringRef Name) const override { return true; } - ArrayRef getGCCRegNames() const override { - return std::nullopt; - } + ArrayRef getGCCRegNames() const override { return {}; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { @@ -86,7 +84,7 @@ public: } ArrayRef getGCCRegAliases() const override { - return std::nullopt; + return {}; } bool allowDebugInfoForExternalRef() const override { return true; } diff --git a/clang/lib/Basic/Targets/DirectX.h b/clang/lib/Basic/Targets/DirectX.h index 19b61252409b099d542f5cd89cf83be577ec305b..ab22d1281a4df7992b13a40a50ad665ccbc81ae9 100644 --- a/clang/lib/Basic/Targets/DirectX.h +++ b/clang/lib/Basic/Targets/DirectX.h @@ -72,15 +72,11 @@ public: return Feature == "directx"; } - ArrayRef getTargetBuiltins() const override { - return std::nullopt; - } + ArrayRef getTargetBuiltins() const override { return {}; } std::string_view getClobbers() const override { return ""; } - ArrayRef getGCCRegNames() const override { - return std::nullopt; - } + ArrayRef getGCCRegNames() const override { return {}; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { @@ -88,7 +84,7 @@ public: } ArrayRef getGCCRegAliases() const override { - return std::nullopt; + return {}; } BuiltinVaListKind getBuiltinVaListKind() const override { diff --git a/clang/lib/Basic/Targets/Lanai.h b/clang/lib/Basic/Targets/Lanai.h index 144cbc7de98931c61937075c9073579474287871..f7e439c7c9e1cf3697005700f4c06b06409631a5 100644 --- a/clang/lib/Basic/Targets/Lanai.h +++ b/clang/lib/Basic/Targets/Lanai.h @@ -78,9 +78,7 @@ public: return TargetInfo::VoidPtrBuiltinVaList; } - ArrayRef getTargetBuiltins() const override { - return std::nullopt; - } + ArrayRef getTargetBuiltins() const override { return {}; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { diff --git a/clang/lib/Basic/Targets/M68k.cpp b/clang/lib/Basic/Targets/M68k.cpp index 8b8bf97d6f99a1b1745e4aee928025d7b0e39877..b5b29fd8675630bcdb09a6a040a92a31cbfb3141 100644 --- a/clang/lib/Basic/Targets/M68k.cpp +++ b/clang/lib/Basic/Targets/M68k.cpp @@ -117,7 +117,7 @@ void M68kTargetInfo::getTargetDefines(const LangOptions &Opts, ArrayRef M68kTargetInfo::getTargetBuiltins() const { // FIXME: Implement. - return std::nullopt; + return {}; } bool M68kTargetInfo::hasFeature(StringRef Feature) const { diff --git a/clang/lib/Basic/Targets/MSP430.h b/clang/lib/Basic/Targets/MSP430.h index 25639b8c1e0ad95a30f15af6ab2959fea62cb3d2..2266ada25c1dd64ad02360fc1a753e39d9f904d3 100644 --- a/clang/lib/Basic/Targets/MSP430.h +++ b/clang/lib/Basic/Targets/MSP430.h @@ -52,7 +52,7 @@ public: ArrayRef getTargetBuiltins() const override { // FIXME: Implement. - return std::nullopt; + return {}; } bool allowsLargerPreferedTypeAlignment() const override { return false; } diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h index 1ef20ce733917d86fffcfc060c2e0a00ae382ff0..165b28a60fb2a92e27ffef00dcc29b4f71e995be 100644 --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -93,7 +93,7 @@ public: ArrayRef getGCCRegAliases() const override { // No aliases. - return std::nullopt; + return {}; } bool validateAsmConstraint(const char *&Name, diff --git a/clang/lib/Basic/Targets/PNaCl.cpp b/clang/lib/Basic/Targets/PNaCl.cpp index 51b6452b0c2039db9557887c92913789bdeb3ae0..c4adfbefb9c73a9a30e4c37ee7db79b2b4bce6d1 100644 --- a/clang/lib/Basic/Targets/PNaCl.cpp +++ b/clang/lib/Basic/Targets/PNaCl.cpp @@ -16,12 +16,10 @@ using namespace clang; using namespace clang::targets; -ArrayRef PNaClTargetInfo::getGCCRegNames() const { - return std::nullopt; -} +ArrayRef PNaClTargetInfo::getGCCRegNames() const { return {}; } ArrayRef PNaClTargetInfo::getGCCRegAliases() const { - return std::nullopt; + return {}; } void PNaClTargetInfo::getArchDefines(const LangOptions &Opts, diff --git a/clang/lib/Basic/Targets/PNaCl.h b/clang/lib/Basic/Targets/PNaCl.h index 595c4d83b1d1c347e742c7839b5765661689062d..7e0e10aa362d87b286ee7c827df63523584d6c33 100644 --- a/clang/lib/Basic/Targets/PNaCl.h +++ b/clang/lib/Basic/Targets/PNaCl.h @@ -52,9 +52,7 @@ public: return Feature == "pnacl"; } - ArrayRef getTargetBuiltins() const override { - return std::nullopt; - } + ArrayRef getTargetBuiltins() const override { return {}; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::PNaClABIBuiltinVaList; diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h index bf72383f81587af82cb8de9dad704e2fdd99a11a..5e807f26ff4c1ec8057793ec001c270dbed741e1 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -143,6 +143,13 @@ public: return true; } + bool + checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const override { + if (ISAInfo->hasExtension("zicfiss")) + return true; + return TargetInfo::checkCFProtectionReturnSupported(Diags); + } + CFBranchLabelSchemeKind getDefaultCFBranchLabelScheme() const override { return CFBranchLabelSchemeKind::FuncSig; } diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h index cc79562de2871e51be526bd1e3a13aa3271b1471..30c7ac8d9c037f818d301da5732ba8b89416a445 100644 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -159,15 +159,11 @@ public: // memcpy as per section 3 of the SPIR spec. bool useFP16ConversionIntrinsics() const override { return false; } - ArrayRef getTargetBuiltins() const override { - return std::nullopt; - } + ArrayRef getTargetBuiltins() const override { return {}; } std::string_view getClobbers() const override { return ""; } - ArrayRef getGCCRegNames() const override { - return std::nullopt; - } + ArrayRef getGCCRegNames() const override { return {}; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { @@ -175,7 +171,7 @@ public: } ArrayRef getGCCRegAliases() const override { - return std::nullopt; + return {}; } BuiltinVaListKind getBuiltinVaListKind() const override { diff --git a/clang/lib/Basic/Targets/Sparc.h b/clang/lib/Basic/Targets/Sparc.h index ee0d3e2b4329eb6da365936195e7b4525e2c0b66..9c529a5bc5e7fa2ca16b9a6ae3ca018a20726bd6 100644 --- a/clang/lib/Basic/Targets/Sparc.h +++ b/clang/lib/Basic/Targets/Sparc.h @@ -50,7 +50,7 @@ public: ArrayRef getTargetBuiltins() const override { // FIXME: Implement! - return std::nullopt; + return {}; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h index f05ea473017bec4f0a51444efb29029000734bdb..ef9a07033a6e4fffd5fadb1e76f037cf4fd3d1c8 100644 --- a/clang/lib/Basic/Targets/SystemZ.h +++ b/clang/lib/Basic/Targets/SystemZ.h @@ -105,7 +105,7 @@ public: ArrayRef getGCCRegAliases() const override { // No aliases. - return std::nullopt; + return {}; } ArrayRef getGCCAddlRegNames() const override; diff --git a/clang/lib/Basic/Targets/TCE.h b/clang/lib/Basic/Targets/TCE.h index dcf684fe6dbc011f1a7e4634bc0bcdb74dc91bbe..d6280b02f07b251c3c7080ea05c47f74afb24094 100644 --- a/clang/lib/Basic/Targets/TCE.h +++ b/clang/lib/Basic/Targets/TCE.h @@ -95,9 +95,7 @@ public: bool hasFeature(StringRef Feature) const override { return Feature == "tce"; } - ArrayRef getTargetBuiltins() const override { - return std::nullopt; - } + ArrayRef getTargetBuiltins() const override { return {}; } std::string_view getClobbers() const override { return ""; } @@ -105,9 +103,7 @@ public: return TargetInfo::VoidPtrBuiltinVaList; } - ArrayRef getGCCRegNames() const override { - return std::nullopt; - } + ArrayRef getGCCRegNames() const override { return {}; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { @@ -115,7 +111,7 @@ public: } ArrayRef getGCCRegAliases() const override { - return std::nullopt; + return {}; } }; diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index 5ac9421663adea43d83cf1cee4735cf4326578f7..0b380bdf835ffbd00b677f76b34deadc41c9f3be 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -59,6 +59,7 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const { .Case("sign-ext", HasSignExt) .Case("simd128", SIMDLevel >= SIMD128) .Case("tail-call", HasTailCall) + .Case("wide-arithmetic", HasWideArithmetic) .Default(false); } @@ -102,6 +103,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__wasm_simd128__"); if (HasTailCall) Builder.defineMacro("__wasm_tail_call__"); + if (HasWideArithmetic) + Builder.defineMacro("__wasm_wide_arithmetic__"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); @@ -151,21 +154,22 @@ bool WebAssemblyTargetInfo::initFeatureMap( llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const { auto addGenericFeatures = [&]() { + Features["bulk-memory"] = true; Features["multivalue"] = true; Features["mutable-globals"] = true; + Features["nontrapping-fptoint"] = true; Features["reference-types"] = true; Features["sign-ext"] = true; }; auto addBleedingEdgeFeatures = [&]() { addGenericFeatures(); Features["atomics"] = true; - Features["bulk-memory"] = true; Features["exception-handling"] = true; Features["extended-const"] = true; Features["fp16"] = true; Features["multimemory"] = true; - Features["nontrapping-fptoint"] = true; Features["tail-call"] = true; + Features["wide-arithmetic"] = true; setSIMDLevel(Features, RelaxedSIMD, true); }; if (CPU == "generic") { @@ -293,6 +297,14 @@ bool WebAssemblyTargetInfo::handleTargetFeatures( HasTailCall = false; continue; } + if (Feature == "+wide-arithmetic") { + HasWideArithmetic = true; + continue; + } + if (Feature == "-wide-arithmetic") { + HasWideArithmetic = false; + continue; + } Diags.Report(diag::err_opt_not_valid_with_opt) << Feature << "-target-feature"; diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index 213ec42ca84bb77b3924d14c70fc6d31aa3b6715..6c2fe8049ff47ab362299ba814db1e8ef76f0547 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -65,6 +65,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { bool HasReferenceTypes = false; bool HasSignExt = false; bool HasTailCall = false; + bool HasWideArithmetic = false; std::string ABI; @@ -123,10 +124,10 @@ private: return VoidPtrBuiltinVaList; } - ArrayRef getGCCRegNames() const final { return std::nullopt; } + ArrayRef getGCCRegNames() const final { return {}; } ArrayRef getGCCRegAliases() const final { - return std::nullopt; + return {}; } bool validateAsmConstraint(const char *&Name, diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 5448bd841959f4de28a75ab5c2bfcfe0bfad4365..700c2f9a5dbd18d1624c8269bca2643fec33e32e 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -348,6 +348,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector &Features, HasSM4 = true; } else if (Feature == "+movbe") { HasMOVBE = true; + } else if (Feature == "+movrs") { + HasMOVRS = true; } else if (Feature == "+sgx") { HasSGX = true; } else if (Feature == "+cx8") { @@ -915,6 +917,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__MOVDIRI__"); if (HasMOVDIR64B) Builder.defineMacro("__MOVDIR64B__"); + if (HasMOVRS) + Builder.defineMacro("__MOVRS__"); if (HasPCONFIG) Builder.defineMacro("__PCONFIG__"); if (HasPTWRITE) @@ -1116,6 +1120,7 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const { .Case("lzcnt", true) .Case("mmx", true) .Case("movbe", true) + .Case("movrs", true) .Case("movdiri", true) .Case("movdir64b", true) .Case("mwaitx", true) @@ -1233,6 +1238,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("lzcnt", HasLZCNT) .Case("mmx", HasMMX) .Case("movbe", HasMOVBE) + .Case("movrs", HasMOVRS) .Case("movdiri", HasMOVDIRI) .Case("movdir64b", HasMOVDIR64B) .Case("mwaitx", HasMWAITX) @@ -1459,7 +1465,7 @@ bool X86TargetInfo::validateAsmConstraint( } case 'f': // Any x87 floating point stack register. // Constraint 'f' cannot be used for output operands. - if (Info.ConstraintStr[0] == '=') + if (Info.ConstraintStr[0] == '=' || Info.ConstraintStr[0] == '+') return false; Info.setAllowsRegister(); return true; diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index a99ae62984c7d5834e86545b207ac5e40816a9b6..e8aad3ec5a74b102c90dfeb9abf0099dfcae28f9 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -130,6 +130,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { bool HasCLFLUSHOPT = false; bool HasCLWB = false; bool HasMOVBE = false; + bool HasMOVRS = false; bool HasPREFETCHI = false; bool HasRDPID = false; bool HasRDPRU = false; @@ -210,7 +211,7 @@ public: ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override { - return std::nullopt; + return {}; } ArrayRef getGCCAddlRegNames() const override; diff --git a/clang/lib/Basic/Targets/XCore.h b/clang/lib/Basic/Targets/XCore.h index a58d3e8acf4791e38d90405ceda67a284b1c8db7..84fd59d1a71e498170c48aec0edfe79bab17a221 100644 --- a/clang/lib/Basic/Targets/XCore.h +++ b/clang/lib/Basic/Targets/XCore.h @@ -60,7 +60,7 @@ public: } ArrayRef getGCCRegAliases() const override { - return std::nullopt; + return {}; } bool validateAsmConstraint(const char *&Name, diff --git a/clang/lib/CodeGen/ABIInfoImpl.cpp b/clang/lib/CodeGen/ABIInfoImpl.cpp index be91b85e3a816f82f13eebcb393308b2bbbb8944..79300df15d0e29fce18210d9d5f5723b210f88f3 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.cpp +++ b/clang/lib/CodeGen/ABIInfoImpl.cpp @@ -80,16 +80,6 @@ RValue DefaultABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, Slot); } -ABIArgInfo CodeGen::coerceToIntArray(QualType Ty, ASTContext &Context, - llvm::LLVMContext &LLVMContext) { - // Alignment and Size are measured in bits. - const uint64_t Size = Context.getTypeSize(Ty); - const uint64_t Alignment = Context.getTypeAlign(Ty); - llvm::Type *IntType = llvm::Type::getIntNTy(LLVMContext, Alignment); - const uint64_t NumElements = (Size + Alignment - 1) / Alignment; - return ABIArgInfo::getDirect(llvm::ArrayType::get(IntType, NumElements)); -} - void CodeGen::AssignToArrayRange(CodeGen::CGBuilderTy &Builder, llvm::Value *Array, llvm::Value *Value, unsigned FirstIndex, unsigned LastIndex) { diff --git a/clang/lib/CodeGen/ABIInfoImpl.h b/clang/lib/CodeGen/ABIInfoImpl.h index 2a3ef6b8a6c961047775dcedccf1755686e239ee..d9d79c6a55ddb167cdc10e4e751e105225f35b4a 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.h +++ b/clang/lib/CodeGen/ABIInfoImpl.h @@ -33,23 +33,6 @@ public: AggValueSlot Slot) const override; }; -// Helper for coercing an aggregate argument or return value into an integer -// array of the same size (including padding) and alignment. This alternate -// coercion happens only for the RenderScript ABI and can be removed after -// runtimes that rely on it are no longer supported. -// -// RenderScript assumes that the size of the argument / return value in the IR -// is the same as the size of the corresponding qualified type. This helper -// coerces the aggregate type into an array of the same size (including -// padding). This coercion is used in lieu of expansion of struct members or -// other canonical coercions that return a coerced-type of larger size. -// -// Ty - The argument / return value type -// Context - The associated ASTContext -// LLVMContext - The associated LLVMContext -ABIArgInfo coerceToIntArray(QualType Ty, ASTContext &Context, - llvm::LLVMContext &LLVMContext); - void AssignToArrayRange(CodeGen::CGBuilderTy &Builder, llvm::Value *Array, llvm::Value *Value, unsigned FirstIndex, unsigned LastIndex); diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index e45a5010f4b3356139955bc871aa731254fc9672..ec6c77d3afdef7bc3f9201aea7cc5988d2c76bbd 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -17,6 +17,7 @@ #include "CGObjCRuntime.h" #include "CGOpenCLRuntime.h" #include "CGRecordLayout.h" +#include "CGValue.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" @@ -25,8 +26,10 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" #include "clang/AST/OSLog.h" #include "clang/AST/OperationKinds.h" +#include "clang/AST/Type.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" @@ -68,7 +71,7 @@ #include "llvm/TargetParser/X86TargetParser.h" #include #include -#include +#include using namespace clang; using namespace CodeGen; @@ -97,6 +100,76 @@ static void initializeAlloca(CodeGenFunction &CGF, AllocaInst *AI, Value *Size, I->addAnnotationMetadata("auto-init"); } +static Value *handleHlslSplitdouble(const CallExpr *E, CodeGenFunction *CGF) { + Value *Op0 = CGF->EmitScalarExpr(E->getArg(0)); + const auto *OutArg1 = dyn_cast(E->getArg(1)); + const auto *OutArg2 = dyn_cast(E->getArg(2)); + + CallArgList Args; + LValue Op1TmpLValue = + CGF->EmitHLSLOutArgExpr(OutArg1, Args, OutArg1->getType()); + LValue Op2TmpLValue = + CGF->EmitHLSLOutArgExpr(OutArg2, Args, OutArg2->getType()); + + if (CGF->getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) + Args.reverseWritebacks(); + + Value *LowBits = nullptr; + Value *HighBits = nullptr; + + if (CGF->CGM.getTarget().getTriple().isDXIL()) { + + llvm::Type *RetElementTy = CGF->Int32Ty; + if (auto *Op0VecTy = E->getArg(0)->getType()->getAs()) + RetElementTy = llvm::VectorType::get( + CGF->Int32Ty, ElementCount::getFixed(Op0VecTy->getNumElements())); + auto *RetTy = llvm::StructType::get(RetElementTy, RetElementTy); + + CallInst *CI = CGF->Builder.CreateIntrinsic( + RetTy, Intrinsic::dx_splitdouble, {Op0}, nullptr, "hlsl.splitdouble"); + + LowBits = CGF->Builder.CreateExtractValue(CI, 0); + HighBits = CGF->Builder.CreateExtractValue(CI, 1); + + } else { + // For Non DXIL targets we generate the instructions. + + if (!Op0->getType()->isVectorTy()) { + FixedVectorType *DestTy = FixedVectorType::get(CGF->Int32Ty, 2); + Value *Bitcast = CGF->Builder.CreateBitCast(Op0, DestTy); + + LowBits = CGF->Builder.CreateExtractElement(Bitcast, (uint64_t)0); + HighBits = CGF->Builder.CreateExtractElement(Bitcast, 1); + } else { + int NumElements = 1; + if (const auto *VecTy = + E->getArg(0)->getType()->getAs()) + NumElements = VecTy->getNumElements(); + + FixedVectorType *Uint32VecTy = + FixedVectorType::get(CGF->Int32Ty, NumElements * 2); + Value *Uint32Vec = CGF->Builder.CreateBitCast(Op0, Uint32VecTy); + if (NumElements == 1) { + LowBits = CGF->Builder.CreateExtractElement(Uint32Vec, (uint64_t)0); + HighBits = CGF->Builder.CreateExtractElement(Uint32Vec, 1); + } else { + SmallVector EvenMask, OddMask; + for (int I = 0, E = NumElements; I != E; ++I) { + EvenMask.push_back(I * 2); + OddMask.push_back(I * 2 + 1); + } + LowBits = CGF->Builder.CreateShuffleVector(Uint32Vec, EvenMask); + HighBits = CGF->Builder.CreateShuffleVector(Uint32Vec, OddMask); + } + } + } + CGF->Builder.CreateStore(LowBits, Op1TmpLValue.getAddress()); + auto *LastInst = + CGF->Builder.CreateStore(HighBits, Op2TmpLValue.getAddress()); + CGF->EmitWritebacks(Args); + return LastInst; +} + /// getBuiltinLibFunction - Given a builtin id for a function like /// "__builtin_fabsf", return a Function* for "fabsf". llvm::Constant *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD, @@ -2026,7 +2099,7 @@ Value *CodeGenFunction::EmitCheckedArgForBuiltin(const Expr *E, SanitizerHandler::InvalidBuiltin, {EmitCheckSourceLocation(E->getExprLoc()), llvm::ConstantInt::get(Builder.getInt8Ty(), Kind)}, - std::nullopt); + {}); return ArgValue; } @@ -18532,9 +18605,9 @@ Value *EmitAMDGPUWorkGroupSize(CodeGenFunction &CGF, unsigned Index) { APInt(16, CGF.getTarget().getMaxOpenCLWorkGroupSize() + 1)); LD->setMetadata(llvm::LLVMContext::MD_range, RNode); LD->setMetadata(llvm::LLVMContext::MD_noundef, - llvm::MDNode::get(CGF.getLLVMContext(), std::nullopt)); + llvm::MDNode::get(CGF.getLLVMContext(), {})); LD->setMetadata(llvm::LLVMContext::MD_invariant_load, - llvm::MDNode::get(CGF.getLLVMContext(), std::nullopt)); + llvm::MDNode::get(CGF.getLLVMContext(), {})); return LD; } @@ -18548,7 +18621,7 @@ Value *EmitAMDGPUGridSize(CodeGenFunction &CGF, unsigned Index) { auto *LD = CGF.Builder.CreateLoad( Address(GEP, CGF.Int32Ty, CharUnits::fromQuantity(4))); LD->setMetadata(llvm::LLVMContext::MD_invariant_load, - llvm::MDNode::get(CGF.getLLVMContext(), std::nullopt)); + llvm::MDNode::get(CGF.getLLVMContext(), {})); return LD; } } // namespace @@ -18961,6 +19034,14 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { CGM.getHLSLRuntime().getRadiansIntrinsic(), ArrayRef{Op0}, nullptr, "hlsl.radians"); } + case Builtin::BI__builtin_hlsl_elementwise_splitdouble: { + + assert((E->getArg(0)->getType()->hasFloatingRepresentation() && + E->getArg(1)->getType()->hasUnsignedIntegerRepresentation() && + E->getArg(2)->getType()->hasUnsignedIntegerRepresentation()) && + "asuint operands types mismatch"); + return handleHlslSplitdouble(E, this); + } } return nullptr; } @@ -19057,7 +19138,7 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, Args.push_back(llvm::PoisonValue::get(IntTy)); for (unsigned I = 0; I != E->getNumArgs(); ++I) { llvm::Value *V = EmitScalarOrConstFoldImmArg(ICEArguments, I, E); - if (I <= !InsertOld && Size < 32) { + if (I <= (InsertOld ? 0u : 1u) && Size < 32) { if (!DataTy->isIntegerTy()) V = Builder.CreateBitCast( V, llvm::IntegerType::get(Builder.getContext(), Size)); @@ -20494,8 +20575,8 @@ static NVPTXMmaInfo getNVPTXMmaInfo(unsigned BuiltinID) { #undef MMA_VARIANTS_B1_XOR } -static Value *MakeLdgLdu(unsigned IntrinsicID, CodeGenFunction &CGF, - const CallExpr *E) { +static Value *MakeLdu(unsigned IntrinsicID, CodeGenFunction &CGF, + const CallExpr *E) { Value *Ptr = CGF.EmitScalarExpr(E->getArg(0)); QualType ArgType = E->getArg(0)->getType(); clang::CharUnits Align = CGF.CGM.getNaturalPointeeTypeAlignment(ArgType); @@ -20505,6 +20586,21 @@ static Value *MakeLdgLdu(unsigned IntrinsicID, CodeGenFunction &CGF, {Ptr, ConstantInt::get(CGF.Builder.getInt32Ty(), Align.getQuantity())}); } +static Value *MakeLdg(CodeGenFunction &CGF, const CallExpr *E) { + Value *Ptr = CGF.EmitScalarExpr(E->getArg(0)); + QualType ArgType = E->getArg(0)->getType(); + clang::CharUnits AlignV = CGF.CGM.getNaturalPointeeTypeAlignment(ArgType); + llvm::Type *ElemTy = CGF.ConvertTypeForMem(ArgType->getPointeeType()); + + // Use addrspace(1) for NVPTX ADDRESS_SPACE_GLOBAL + auto *ASC = CGF.Builder.CreateAddrSpaceCast(Ptr, CGF.Builder.getPtrTy(1)); + auto *LD = CGF.Builder.CreateAlignedLoad(ElemTy, ASC, AlignV.getAsAlign()); + MDNode *MD = MDNode::get(CGF.Builder.getContext(), {}); + LD->setMetadata(LLVMContext::MD_invariant_load, MD); + + return LD; +} + static Value *MakeScopedAtomic(unsigned IntrinsicID, CodeGenFunction &CGF, const CallExpr *E) { Value *Ptr = CGF.EmitScalarExpr(E->getArg(0)); @@ -20538,9 +20634,11 @@ static Value *MakeHalfType(unsigned IntrinsicID, unsigned BuiltinID, return nullptr; } - if (IntrinsicID == Intrinsic::nvvm_ldg_global_f || - IntrinsicID == Intrinsic::nvvm_ldu_global_f) - return MakeLdgLdu(IntrinsicID, CGF, E); + if (BuiltinID == NVPTX::BI__nvvm_ldg_h || BuiltinID == NVPTX::BI__nvvm_ldg_h2) + return MakeLdg(CGF, E); + + if (IntrinsicID == Intrinsic::nvvm_ldu_global_f) + return MakeLdu(IntrinsicID, CGF, E); SmallVector Args; auto *F = CGF.CGM.getIntrinsic(IntrinsicID); @@ -20677,16 +20775,15 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, case NVPTX::BI__nvvm_ldg_ul2: case NVPTX::BI__nvvm_ldg_ull: case NVPTX::BI__nvvm_ldg_ull2: - // PTX Interoperability section 2.2: "For a vector with an even number of - // elements, its alignment is set to number of elements times the alignment - // of its member: n*alignof(t)." - return MakeLdgLdu(Intrinsic::nvvm_ldg_global_i, *this, E); case NVPTX::BI__nvvm_ldg_f: case NVPTX::BI__nvvm_ldg_f2: case NVPTX::BI__nvvm_ldg_f4: case NVPTX::BI__nvvm_ldg_d: case NVPTX::BI__nvvm_ldg_d2: - return MakeLdgLdu(Intrinsic::nvvm_ldg_global_f, *this, E); + // PTX Interoperability section 2.2: "For a vector with an even number of + // elements, its alignment is set to number of elements times the alignment + // of its member: n*alignof(t)." + return MakeLdg(*this, E); case NVPTX::BI__nvvm_ldu_c: case NVPTX::BI__nvvm_ldu_sc: @@ -20717,13 +20814,13 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, case NVPTX::BI__nvvm_ldu_ul2: case NVPTX::BI__nvvm_ldu_ull: case NVPTX::BI__nvvm_ldu_ull2: - return MakeLdgLdu(Intrinsic::nvvm_ldu_global_i, *this, E); + return MakeLdu(Intrinsic::nvvm_ldu_global_i, *this, E); case NVPTX::BI__nvvm_ldu_f: case NVPTX::BI__nvvm_ldu_f2: case NVPTX::BI__nvvm_ldu_f4: case NVPTX::BI__nvvm_ldu_d: case NVPTX::BI__nvvm_ldu_d2: - return MakeLdgLdu(Intrinsic::nvvm_ldu_global_f, *this, E); + return MakeLdu(Intrinsic::nvvm_ldu_global_f, *this, E); case NVPTX::BI__nvvm_atom_cta_add_gen_i: case NVPTX::BI__nvvm_atom_cta_add_gen_l: @@ -21197,14 +21294,11 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, return MakeHalfType(Intrinsic::nvvm_fmin_xorsign_abs_f16x2, BuiltinID, E, *this); case NVPTX::BI__nvvm_ldg_h: - return MakeHalfType(Intrinsic::nvvm_ldg_global_f, BuiltinID, E, *this); case NVPTX::BI__nvvm_ldg_h2: - return MakeHalfType(Intrinsic::nvvm_ldg_global_f, BuiltinID, E, *this); + return MakeHalfType(Intrinsic::not_intrinsic, BuiltinID, E, *this); case NVPTX::BI__nvvm_ldu_h: + case NVPTX::BI__nvvm_ldu_h2: return MakeHalfType(Intrinsic::nvvm_ldu_global_f, BuiltinID, E, *this); - case NVPTX::BI__nvvm_ldu_h2: { - return MakeHalfType(Intrinsic::nvvm_ldu_global_f, BuiltinID, E, *this); - } case NVPTX::BI__nvvm_cp_async_ca_shared_global_4: return MakeCpAsync(Intrinsic::nvvm_cp_async_ca_shared_global_4, Intrinsic::nvvm_cp_async_ca_shared_global_4_s, *this, E, diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 55d6748397ced2daca222f1af9c0780cc02b2bfa..3bc498d2e91f2d8af2f577c6275073bff7cefcbc 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -40,6 +40,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Type.h" +#include "llvm/Support/Path.h" #include "llvm/Transforms/Utils/Local.h" #include using namespace clang; @@ -118,8 +119,8 @@ CodeGenTypes::arrangeFreeFunctionType(CanQual FTNP) { // When translating an unprototyped function type, always use a // variadic type. return arrangeLLVMFunctionInfo(FTNP->getReturnType().getUnqualifiedType(), - FnInfoOpts::None, std::nullopt, - FTNP->getExtInfo(), {}, RequiredArgs(0)); + FnInfoOpts::None, {}, FTNP->getExtInfo(), {}, + RequiredArgs(0)); } static void addExtParameterInfosForCall( @@ -473,7 +474,7 @@ CodeGenTypes::arrangeFunctionDeclaration(const FunctionDecl *FD) { // non-variadic type. if (CanQual noProto = FTy.getAs()) { return arrangeLLVMFunctionInfo(noProto->getReturnType(), FnInfoOpts::None, - std::nullopt, noProto->getExtInfo(), {}, + {}, noProto->getExtInfo(), {}, RequiredArgs::All); } @@ -719,8 +720,8 @@ CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args, } const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() { - return arrangeLLVMFunctionInfo(getContext().VoidTy, FnInfoOpts::None, - std::nullopt, FunctionType::ExtInfo(), {}, + return arrangeLLVMFunctionInfo(getContext().VoidTy, FnInfoOpts::None, {}, + FunctionType::ExtInfo(), {}, RequiredArgs::All); } @@ -1410,6 +1411,30 @@ static Address emitAddressAtOffset(CodeGenFunction &CGF, Address addr, return addr; } +static std::pair +CoerceScalableToFixed(CodeGenFunction &CGF, llvm::FixedVectorType *ToTy, + llvm::ScalableVectorType *FromTy, llvm::Value *V, + StringRef Name = "") { + // If we are casting a scalable i1 predicate vector to a fixed i8 + // vector, first bitcast the source. + if (FromTy->getElementType()->isIntegerTy(1) && + FromTy->getElementCount().isKnownMultipleOf(8) && + ToTy->getElementType() == CGF.Builder.getInt8Ty()) { + FromTy = llvm::ScalableVectorType::get( + ToTy->getElementType(), + FromTy->getElementCount().getKnownMinValue() / 8); + V = CGF.Builder.CreateBitCast(V, FromTy); + } + if (FromTy->getElementType() == ToTy->getElementType()) { + llvm::Value *Zero = llvm::Constant::getNullValue(CGF.CGM.Int64Ty); + + V->setName(Name + ".coerce"); + V = CGF.Builder.CreateExtractVector(ToTy, V, Zero, "cast.fixed"); + return {V, true}; + } + return {V, false}; +} + namespace { /// Encapsulates information about the way function arguments from @@ -3196,26 +3221,14 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // a VLAT at the function boundary and the types match up, use // llvm.vector.extract to convert back to the original VLST. if (auto *VecTyTo = dyn_cast(ConvertType(Ty))) { - llvm::Value *Coerced = Fn->getArg(FirstIRArg); + llvm::Value *ArgVal = Fn->getArg(FirstIRArg); if (auto *VecTyFrom = - dyn_cast(Coerced->getType())) { - // If we are casting a scalable i1 predicate vector to a fixed i8 - // vector, bitcast the source and use a vector extract. - if (VecTyFrom->getElementType()->isIntegerTy(1) && - VecTyFrom->getElementCount().isKnownMultipleOf(8) && - VecTyTo->getElementType() == Builder.getInt8Ty()) { - VecTyFrom = llvm::ScalableVectorType::get( - VecTyTo->getElementType(), - VecTyFrom->getElementCount().getKnownMinValue() / 8); - Coerced = Builder.CreateBitCast(Coerced, VecTyFrom); - } - if (VecTyFrom->getElementType() == VecTyTo->getElementType()) { - llvm::Value *Zero = llvm::Constant::getNullValue(CGM.Int64Ty); - + dyn_cast(ArgVal->getType())) { + auto [Coerced, Extracted] = CoerceScalableToFixed( + *this, VecTyTo, VecTyFrom, ArgVal, Arg->getName()); + if (Extracted) { assert(NumIRArgs == 1); - Coerced->setName(Arg->getName() + ".coerce"); - ArgVals.push_back(ParamValue::forDirect(Builder.CreateExtractVector( - VecTyTo, Coerced, Zero, "cast.fixed"))); + ArgVals.push_back(ParamValue::forDirect(Coerced)); break; } } @@ -3340,16 +3353,33 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, ArgVals.push_back(ParamValue::forIndirect(alloca)); auto coercionType = ArgI.getCoerceAndExpandType(); + auto unpaddedCoercionType = ArgI.getUnpaddedCoerceAndExpandType(); + auto *unpaddedStruct = dyn_cast(unpaddedCoercionType); + alloca = alloca.withElementType(coercionType); unsigned argIndex = FirstIRArg; + unsigned unpaddedIndex = 0; for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) { llvm::Type *eltType = coercionType->getElementType(i); if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue; auto eltAddr = Builder.CreateStructGEP(alloca, i); - auto elt = Fn->getArg(argIndex++); + llvm::Value *elt = Fn->getArg(argIndex++); + + auto paramType = unpaddedStruct + ? unpaddedStruct->getElementType(unpaddedIndex++) + : unpaddedCoercionType; + + if (auto *VecTyTo = dyn_cast(eltType)) { + if (auto *VecTyFrom = dyn_cast(paramType)) { + bool Extracted; + std::tie(elt, Extracted) = CoerceScalableToFixed( + *this, VecTyTo, VecTyFrom, elt, elt->getName()); + assert(Extracted && "Unexpected scalable to fixed vector coercion"); + } + } Builder.CreateStore(elt, eltAddr); } assert(argIndex == FirstIRArg + NumIRArgs); @@ -3944,17 +3974,24 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, case ABIArgInfo::CoerceAndExpand: { auto coercionType = RetAI.getCoerceAndExpandType(); + auto unpaddedCoercionType = RetAI.getUnpaddedCoerceAndExpandType(); + auto *unpaddedStruct = dyn_cast(unpaddedCoercionType); // Load all of the coerced elements out into results. llvm::SmallVector results; Address addr = ReturnValue.withElementType(coercionType); + unsigned unpaddedIndex = 0; for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) { auto coercedEltType = coercionType->getElementType(i); if (ABIArgInfo::isPaddingForCoerceAndExpand(coercedEltType)) continue; auto eltAddr = Builder.CreateStructGEP(addr, i); - auto elt = Builder.CreateLoad(eltAddr); + llvm::Value *elt = CreateCoercedLoad( + eltAddr, + unpaddedStruct ? unpaddedStruct->getElementType(unpaddedIndex++) + : unpaddedCoercionType, + *this); results.push_back(elt); } @@ -4221,12 +4258,6 @@ static void emitWriteback(CodeGenFunction &CGF, CGF.EmitBlock(contBB); } -static void emitWritebacks(CodeGenFunction &CGF, - const CallArgList &args) { - for (const auto &I : args.writebacks()) - emitWriteback(CGF, I); -} - static void deactivateArgCleanupsBeforeCall(CodeGenFunction &CGF, const CallArgList &CallArgs) { ArrayRef Cleanups = @@ -4437,7 +4468,7 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType, EmitCheckSourceLocation(ArgLoc), EmitCheckSourceLocation(AttrLoc), llvm::ConstantInt::get(Int32Ty, ArgNo + 1), }; - EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, std::nullopt); + EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, {}); } void CodeGenFunction::EmitNonNullArgCheck(Address Addr, QualType ArgType, @@ -4695,6 +4726,11 @@ void CallArg::copyInto(CodeGenFunction &CGF, Address Addr) const { IsUsed = true; } +void CodeGenFunction::EmitWritebacks(const CallArgList &args) { + for (const auto &I : args.writebacks()) + emitWriteback(*this, I); +} + void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, QualType type) { DisableDebugLocationUpdates Dis(*this, E); @@ -4828,7 +4864,7 @@ CodeGenFunction::EmitNounwindRuntimeCall(llvm::FunctionCallee callee, /// runtime function. llvm::CallInst *CodeGenFunction::EmitRuntimeCall(llvm::FunctionCallee callee, const llvm::Twine &name) { - return EmitRuntimeCall(callee, std::nullopt, name); + return EmitRuntimeCall(callee, {}, name); } // Calls which may throw must have operand bundles indicating which funclet @@ -4895,7 +4931,7 @@ void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke( llvm::CallBase * CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::FunctionCallee callee, const Twine &name) { - return EmitRuntimeCallOrInvoke(callee, std::nullopt, name); + return EmitRuntimeCallOrInvoke(callee, {}, name); } /// Emits a call or invoke instruction to the given runtime function. @@ -5126,7 +5162,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, RawAddress SRetAlloca = RawAddress::invalid(); llvm::Value *UnusedReturnSizePtr = nullptr; if (RetAI.isIndirect() || RetAI.isInAlloca() || RetAI.isCoerceAndExpand()) { - if (IsVirtualFunctionPointerThunk && RetAI.isIndirect()) { + // For virtual function pointer thunks and musttail calls, we must always + // forward an incoming SRet pointer to the callee, because a local alloca + // would be de-allocated before the call. These cases both guarantee that + // there will be an incoming SRet argument of the correct type. + if ((IsVirtualFunctionPointerThunk || IsMustTail) && RetAI.isIndirect()) { SRetPtr = makeNaturalAddressForPointer(CurFn->arg_begin() + IRFunctionArgs.getSRetArgNo(), RetTy, CharUnits::fromQuantity(1)); @@ -5482,6 +5522,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, case ABIArgInfo::CoerceAndExpand: { auto coercionType = ArgInfo.getCoerceAndExpandType(); auto layout = CGM.getDataLayout().getStructLayout(coercionType); + auto unpaddedCoercionType = ArgInfo.getUnpaddedCoerceAndExpandType(); + auto *unpaddedStruct = dyn_cast(unpaddedCoercionType); llvm::Value *tempSize = nullptr; Address addr = Address::invalid(); @@ -5512,11 +5554,16 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, addr = addr.withElementType(coercionType); unsigned IRArgPos = FirstIRArg; + unsigned unpaddedIndex = 0; for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) { llvm::Type *eltType = coercionType->getElementType(i); if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue; Address eltAddr = Builder.CreateStructGEP(addr, i); - llvm::Value *elt = Builder.CreateLoad(eltAddr); + llvm::Value *elt = CreateCoercedLoad( + eltAddr, + unpaddedStruct ? unpaddedStruct->getElementType(unpaddedIndex++) + : unpaddedCoercionType, + *this); if (ArgHasMaybeUndefAttr) elt = Builder.CreateFreeze(elt); IRCallArgs[IRArgPos++] = elt; @@ -5907,7 +5954,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // Emit any call-associated writebacks immediately. Arguably this // should happen after any return-value munging. if (CallArgs.hasWritebacks()) - emitWritebacks(*this, CallArgs); + EmitWritebacks(CallArgs); // The stack cleanup for inalloca arguments has to run out of the normal // lexical order, so deactivate it and run it manually here. diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp index 5d253c92a38a81e097fe526de914ff73650c4f1a..d9c0dbe45d6cf907eba2b7e2018036e569abdc8d 100644 --- a/clang/lib/CodeGen/CGCleanup.cpp +++ b/clang/lib/CodeGen/CGCleanup.cpp @@ -1329,8 +1329,7 @@ static void EmitSehScope(CodeGenFunction &CGF, CGF.getBundlesForFunclet(SehCppScope.getCallee()); if (CGF.CurrentFuncletPad) BundleList.emplace_back("funclet", CGF.CurrentFuncletPad); - CGF.Builder.CreateInvoke(SehCppScope, Cont, InvokeDest, std::nullopt, - BundleList); + CGF.Builder.CreateInvoke(SehCppScope, Cont, InvokeDest, {}, BundleList); CGF.EmitBlock(Cont); } diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 06015a9e541ea24a03db0f19bb1419bf5c079b2d..ad64abe7cd40a39a2e3851c966444fbde89698f5 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -624,8 +624,6 @@ void CGDebugInfo::CreateCompileUnit() { } else if (LO.OpenCL && (!CGM.getCodeGenOpts().DebugStrictDwarf || CGM.getCodeGenOpts().DwarfVersion >= 5)) { LangTag = llvm::dwarf::DW_LANG_OpenCL; - } else if (LO.RenderScript) { - LangTag = llvm::dwarf::DW_LANG_GOOGLE_RenderScript; } else if (LO.C11 && !(CGO.DebugStrictDwarf && CGO.DwarfVersion < 5)) { LangTag = llvm::dwarf::DW_LANG_C11; } else if (LO.C99) { @@ -783,6 +781,13 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { #define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/AArch64SVEACLETypes.def" { + if (BT->getKind() == BuiltinType::MFloat8) { + Encoding = llvm::dwarf::DW_ATE_unsigned_char; + BTName = BT->getName(CGM.getLangOpts()); + // Bit size and offset of the type. + uint64_t Size = CGM.getContext().getTypeSize(BT); + return DBuilder.createBasicType(BTName, Size, Encoding); + } ASTContext::BuiltinVectorTypeInfo Info = // For svcount_t, only the lower 2 bytes are relevant. BT->getKind() == BuiltinType::SveCount @@ -909,6 +914,13 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { TheCU, TheCU->getFile(), 0); \ return SingletonId; \ } +#define AMDGPU_NAMED_BARRIER_TYPE(Name, Id, SingletonId, Width, Align, Scope) \ + case BuiltinType::Id: { \ + if (!SingletonId) \ + SingletonId = \ + DBuilder.createBasicType(Name, Width, llvm::dwarf::DW_ATE_unsigned); \ + return SingletonId; \ + } #include "clang/Basic/AMDGPUTypes.def" case BuiltinType::UChar: case BuiltinType::Char_U: @@ -2642,7 +2654,7 @@ void CGDebugInfo::addHeapAllocSiteMetadata(llvm::CallBase *CI, return; llvm::MDNode *node; if (AllocatedTy->isVoidType()) - node = llvm::MDNode::get(CGM.getLLVMContext(), std::nullopt); + node = llvm::MDNode::get(CGM.getLLVMContext(), {}); else node = getOrCreateType(AllocatedTy, getOrCreateFile(Loc)); @@ -4324,8 +4336,7 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D, !CGM.getCodeGenOpts().EmitCodeView)) // Create fake but valid subroutine type. Otherwise -verify would fail, and // subprogram DIE will miss DW_AT_decl_file and DW_AT_decl_line fields. - return DBuilder.createSubroutineType( - DBuilder.getOrCreateTypeArray(std::nullopt)); + return DBuilder.createSubroutineType(DBuilder.getOrCreateTypeArray({})); if (const auto *Method = dyn_cast(D)) return getOrCreateMethodType(Method, F); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 161dd7e4138a7621fbeed3c0444d58d4a21835b7..64fa1644cae832f6d1ebdd9ef8222632792071ba 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2053,7 +2053,7 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty)) { Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo); Load->setMetadata(llvm::LLVMContext::MD_noundef, - llvm::MDNode::get(getLLVMContext(), std::nullopt)); + llvm::MDNode::get(getLLVMContext(), {})); } return EmitFromMemory(Load, Ty); @@ -3390,9 +3390,9 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) { // Format the type name as if for a diagnostic, including quotes and // optionally an 'aka'. SmallString<32> Buffer; - CGM.getDiags().ConvertArgToString( - DiagnosticsEngine::ak_qualtype, (intptr_t)T.getAsOpaquePtr(), StringRef(), - StringRef(), std::nullopt, Buffer, std::nullopt); + CGM.getDiags().ConvertArgToString(DiagnosticsEngine::ak_qualtype, + (intptr_t)T.getAsOpaquePtr(), StringRef(), + StringRef(), {}, Buffer, {}); if (IsBitInt) { // The Structure is: 0 to end the string, 32 bit unsigned integer in target @@ -3899,7 +3899,7 @@ void CodeGenFunction::EmitUnreachable(SourceLocation Loc) { EmitCheck(std::make_pair(static_cast(Builder.getFalse()), SanitizerKind::Unreachable), SanitizerHandler::BuiltinUnreachable, - EmitCheckSourceLocation(Loc), std::nullopt); + EmitCheckSourceLocation(Loc), {}); } Builder.CreateUnreachable(); } @@ -5475,9 +5475,8 @@ LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) { return getOrCreateOpaqueLValueMapping(e); } -void CodeGenFunction::EmitHLSLOutArgExpr(const HLSLOutArgExpr *E, - CallArgList &Args, QualType Ty) { - +std::pair +CodeGenFunction::EmitHLSLOutArgLValues(const HLSLOutArgExpr *E, QualType Ty) { // Emitting the casted temporary through an opaque value. LValue BaseLV = EmitLValue(E->getArgLValue()); OpaqueValueMappingData::bind(*this, E->getOpaqueArgLValue(), BaseLV); @@ -5491,6 +5490,13 @@ void CodeGenFunction::EmitHLSLOutArgExpr(const HLSLOutArgExpr *E, TempLV); OpaqueValueMappingData::bind(*this, E->getCastedTemporary(), TempLV); + return std::make_pair(BaseLV, TempLV); +} + +LValue CodeGenFunction::EmitHLSLOutArgExpr(const HLSLOutArgExpr *E, + CallArgList &Args, QualType Ty) { + + auto [BaseLV, TempLV] = EmitHLSLOutArgLValues(E, Ty); llvm::Value *Addr = TempLV.getAddress().getBasePointer(); llvm::Type *ElTy = ConvertTypeForMem(TempLV.getType()); @@ -5503,6 +5509,7 @@ void CodeGenFunction::EmitHLSLOutArgExpr(const HLSLOutArgExpr *E, Args.addWriteback(BaseLV, TmpAddr, nullptr, E->getWritebackCast(), LifetimeSize); Args.add(RValue::get(TmpAddr, *this), Ty); + return TempLV; } LValue diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 2cce2936fe5aeefa5bcd82a2561dc993a3bb92d9..06558ce796f2e4947828e04db52165e043917f9d 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -404,6 +404,16 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, BasicBlock *BB = BasicBlock::Create(Ctx, "entry", EntryFn); IRBuilder<> B(BB); llvm::SmallVector Args; + + SmallVector OB; + if (CGM.shouldEmitConvergenceTokens()) { + assert(EntryFn->isConvergent()); + llvm::Value *I = B.CreateIntrinsic( + llvm::Intrinsic::experimental_convergence_entry, {}, {}); + llvm::Value *bundleArgs[] = {I}; + OB.emplace_back("convergencectrl", bundleArgs); + } + // FIXME: support struct parameters where semantics are on members. // See: https://github.com/llvm/llvm-project/issues/57874 unsigned SRetOffset = 0; @@ -419,7 +429,7 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, Args.push_back(emitInputSemantic(B, *PD, Param.getType())); } - CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args); + CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB); CI->setCallingConv(Fn->getCallingConv()); // FIXME: Handle codegen for return type semantics. // See: https://github.com/llvm/llvm-project/issues/57875 @@ -474,14 +484,22 @@ void CGHLSLRuntime::generateGlobalCtorDtorCalls() { for (auto &F : M.functions()) { if (!F.hasFnAttribute("hlsl.shader")) continue; - IRBuilder<> B(&F.getEntryBlock(), F.getEntryBlock().begin()); + auto *Token = getConvergenceToken(F.getEntryBlock()); + Instruction *IP = &*F.getEntryBlock().begin(); + SmallVector OB; + if (Token) { + llvm::Value *bundleArgs[] = {Token}; + OB.emplace_back("convergencectrl", bundleArgs); + IP = Token->getNextNode(); + } + IRBuilder<> B(IP); for (auto *Fn : CtorFns) - B.CreateCall(FunctionCallee(Fn)); + B.CreateCall(FunctionCallee(Fn), {}, OB); // Insert global dtors before the terminator of the last instruction B.SetInsertPoint(F.back().getTerminator()); for (auto *Fn : DtorFns) - B.CreateCall(FunctionCallee(Fn)); + B.CreateCall(FunctionCallee(Fn), {}, OB); } // No need to keep global ctors/dtors for non-lib profile after call to @@ -579,3 +597,18 @@ llvm::Function *CGHLSLRuntime::createResourceBindingInitFn() { Builder.CreateRetVoid(); return InitResBindingsFunc; } + +llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) { + if (!CGM.shouldEmitConvergenceTokens()) + return nullptr; + + auto E = BB.end(); + for (auto I = BB.begin(); I != E; ++I) { + auto *II = dyn_cast(&*I); + if (II && llvm::isConvergenceControlIntrinsic(II->getIntrinsicID())) { + return II; + } + } + llvm_unreachable("Convergence token should have been emitted."); + return nullptr; +} diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index ff7df41b5c62e711b474ea65d8bfbdf2043c6adb..cd533cad84e9fbe413a07ba96201e2790e9d0243 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -143,6 +143,7 @@ public: bool needsResourceBindingInitFn(); llvm::Function *createResourceBindingInitFn(); + llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB); private: void addBufferResourceAnnotation(llvm::GlobalVariable *GV, diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp index 9be9683b30941da3e4233631283d9f4e752f0231..e9ab2233308bee61ba839166a992a676c9177941 100644 --- a/clang/lib/CodeGen/CGLoopInfo.cpp +++ b/clang/lib/CodeGen/CGLoopInfo.cpp @@ -506,7 +506,7 @@ LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs, Attrs.CodeAlign == 0 && !StartLoc && !EndLoc && !Attrs.MustProgress) return; - TempLoopID = MDNode::getTemporary(Header->getContext(), std::nullopt); + TempLoopID = MDNode::getTemporary(Header->getContext(), {}); } void LoopInfo::finish() { diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index a73a71f2d26889cb8a12ea4a88839ff421ec3d89..28da353ff2d78d2b028f926913b554d5eb575ccb 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -140,7 +140,7 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E, llvm::Value *Ptr = EmitLoadOfScalar(LV, E->getBeginLoc()); cast(Ptr)->setMetadata( llvm::LLVMContext::MD_invariant_load, - llvm::MDNode::get(getLLVMContext(), std::nullopt)); + llvm::MDNode::get(getLLVMContext(), {})); return Builder.CreateBitCast(Ptr, ConvertType(E->getType())); } @@ -2319,7 +2319,7 @@ llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value, CGM.getObjCEntrypoints().objc_retainBlock); call->setMetadata("clang.arc.copy_on_escape", - llvm::MDNode::get(Builder.getContext(), std::nullopt)); + llvm::MDNode::get(Builder.getContext(), {})); } return result; @@ -2361,8 +2361,7 @@ static void emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) { // Call the marker asm if we made one, which we do only at -O0. if (marker) - CGF.Builder.CreateCall(marker, std::nullopt, - CGF.getBundlesForFunclet(marker)); + CGF.Builder.CreateCall(marker, {}, CGF.getBundlesForFunclet(marker)); } static llvm::Value *emitOptimizedARCReturnCall(llvm::Value *value, @@ -2449,7 +2448,7 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, if (precise == ARCImpreciseLifetime) { call->setMetadata("clang.imprecise_release", - llvm::MDNode::get(Builder.getContext(), std::nullopt)); + llvm::MDNode::get(Builder.getContext(), {})); } } @@ -2843,7 +2842,7 @@ void CodeGenFunction::EmitObjCRelease(llvm::Value *value, if (precise == ARCImpreciseLifetime) { call->setMetadata("clang.imprecise_release", - llvm::MDNode::get(Builder.getContext(), std::nullopt)); + llvm::MDNode::get(Builder.getContext(), {})); } } diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index 6280e9465ecba6635b43e10d33207fb7aad1eb4e..7a07284f8a8aa56af38ae650e68a0e8b82bfe472 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -69,7 +69,7 @@ public: FTy = llvm::FunctionType::get(RetTy, ArgTys, false); } else { - FTy = llvm::FunctionType::get(RetTy, std::nullopt, false); + FTy = llvm::FunctionType::get(RetTy, {}, false); } } diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 30f3911a8b03c2df83aaa1da255925842c39e380..1c16d273a5535713e0c1604d825464442e83285b 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -7191,7 +7191,7 @@ CGObjCNonFragileABIMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF, if (IsIvarOffsetKnownIdempotent(CGF, Ivar)) cast(IvarOffsetValue) ->setMetadata(llvm::LLVMContext::MD_invariant_load, - llvm::MDNode::get(VMContext, std::nullopt)); + llvm::MDNode::get(VMContext, {})); } // This could be 32bit int or 64bit integer depending on the architecture. @@ -7589,7 +7589,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF, llvm::LoadInst* LI = CGF.Builder.CreateLoad(Addr); LI->setMetadata(llvm::LLVMContext::MD_invariant_load, - llvm::MDNode::get(VMContext, std::nullopt)); + llvm::MDNode::get(VMContext, {})); return LI; } diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 631f82413b2578ffd702bac9ae9857092deb7d42..d449b8e46f9e856a8f552220f0df3d2f2f17266e 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -1192,6 +1192,7 @@ struct PushAndPopStackRAII { CodeGenFunction::JumpDest Dest = CGF.getOMPCancelDestination(OMPD_parallel); CGF.EmitBranchThroughCleanup(Dest); + return llvm::Error::success(); }; // TODO: Remove this once we emit parallel regions through the @@ -2331,8 +2332,11 @@ void CGOpenMPRuntime::emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc, auto *OMPRegionInfo = dyn_cast_or_null(CGF.CapturedStmtInfo); if (CGF.CGM.getLangOpts().OpenMPIRBuilder) { - CGF.Builder.restoreIP(OMPBuilder.createBarrier( - CGF.Builder, Kind, ForceSimpleCall, EmitChecks)); + llvm::OpenMPIRBuilder::InsertPointOrErrorTy AfterIP = + OMPBuilder.createBarrier(CGF.Builder, Kind, ForceSimpleCall, + EmitChecks); + assert(AfterIP && "unexpected error creating barrier"); + CGF.Builder.restoreIP(*AfterIP); return; } @@ -5078,7 +5082,7 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc, }; RegionCodeGenTy RCG(CodeGen); CommonActionTy Action( - nullptr, std::nullopt, + nullptr, {}, OMPBuilder.getOrCreateRuntimeFunction( CGM.getModule(), WithNowait ? OMPRTL___kmpc_end_reduce_nowait : OMPRTL___kmpc_end_reduce), @@ -5200,7 +5204,7 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc, ThreadId, // i32 Lock // kmp_critical_name *& }; - CommonActionTy Action(nullptr, std::nullopt, + CommonActionTy Action(nullptr, {}, OMPBuilder.getOrCreateRuntimeFunction( CGM.getModule(), OMPRTL___kmpc_end_reduce), EndArgs); @@ -5931,8 +5935,10 @@ void CGOpenMPRuntime::emitTargetOutlinedFunctionHelper( return CGF.GenerateOpenMPCapturedStmtFunction(CS, D.getBeginLoc()); }; - OMPBuilder.emitTargetRegionFunction(EntryInfo, GenerateOutlinedFunction, - IsOffloadEntry, OutlinedFn, OutlinedFnID); + llvm::Error Err = OMPBuilder.emitTargetRegionFunction( + EntryInfo, GenerateOutlinedFunction, IsOffloadEntry, OutlinedFn, + OutlinedFnID); + assert(!Err && "unexpected error creating target region"); if (!OutlinedFn) return; @@ -6822,7 +6828,7 @@ private: const ValueDecl *Mapper = nullptr, bool ForDeviceAddr = false, const ValueDecl *BaseDecl = nullptr, const Expr *MapExpr = nullptr, ArrayRef - OverlappedElements = std::nullopt, + OverlappedElements = {}, bool AreBothBasePtrAndPteeMapped = false) const { // The following summarizes what has to be generated for each map and the // types below. The generated information is expressed in this order: @@ -7696,7 +7702,7 @@ private: // for map(to: lambda): using user specified map type. return getMapTypeBits( I->getSecond()->getMapType(), I->getSecond()->getMapTypeModifiers(), - /*MotionModifiers=*/std::nullopt, I->getSecond()->isImplicit(), + /*MotionModifiers=*/{}, I->getSecond()->isImplicit(), /*AddPtrFlag=*/false, /*AddIsTargetParamFlag=*/false, /*isNonContiguous=*/false); @@ -7821,7 +7827,7 @@ private: for (const auto L : C->component_lists()) { const Expr *E = (C->getMapLoc().isValid()) ? *EI : nullptr; InfoGen(std::get<0>(L), Kind, std::get<1>(L), C->getMapType(), - C->getMapTypeModifiers(), std::nullopt, + C->getMapTypeModifiers(), {}, /*ReturnDevicePointer=*/false, C->isImplicit(), std::get<2>(L), E); ++EI; @@ -7837,7 +7843,7 @@ private: Kind = Present; const auto *EI = C->getVarRefs().begin(); for (const auto L : C->component_lists()) { - InfoGen(std::get<0>(L), Kind, std::get<1>(L), OMPC_MAP_to, std::nullopt, + InfoGen(std::get<0>(L), Kind, std::get<1>(L), OMPC_MAP_to, {}, C->getMotionModifiers(), /*ReturnDevicePointer=*/false, C->isImplicit(), std::get<2>(L), *EI); ++EI; @@ -7853,8 +7859,8 @@ private: Kind = Present; const auto *EI = C->getVarRefs().begin(); for (const auto L : C->component_lists()) { - InfoGen(std::get<0>(L), Kind, std::get<1>(L), OMPC_MAP_from, - std::nullopt, C->getMotionModifiers(), + InfoGen(std::get<0>(L), Kind, std::get<1>(L), OMPC_MAP_from, {}, + C->getMotionModifiers(), /*ReturnDevicePointer=*/false, C->isImplicit(), std::get<2>(L), *EI); ++EI; @@ -7906,9 +7912,9 @@ private: // processed. Nonetheless, generateInfoForComponentList must be // called to take the pointer into account for the calculation of // the range of the partial struct. - InfoGen(nullptr, Other, Components, OMPC_MAP_unknown, std::nullopt, - std::nullopt, /*ReturnDevicePointer=*/false, IsImplicit, - nullptr, nullptr, IsDevAddr); + InfoGen(nullptr, Other, Components, OMPC_MAP_unknown, {}, {}, + /*ReturnDevicePointer=*/false, IsImplicit, nullptr, nullptr, + IsDevAddr); DeferredInfo[nullptr].emplace_back(IE, VD, IsDevAddr); } else { llvm::Value *Ptr; @@ -8059,7 +8065,7 @@ private: CurInfo, StructBaseCurInfo, PartialStruct, /*IsFirstComponentList=*/false, L.IsImplicit, /*GenerateAllInfoForClauses*/ true, L.Mapper, L.ForDeviceAddr, VD, - L.VarRef, /*OverlappedElements*/ std::nullopt, + L.VarRef, /*OverlappedElements*/ {}, HasMapBasePtr && HasMapArraySec); // If this entry relates to a device pointer, set the relevant @@ -8695,7 +8701,7 @@ public: ArrayRef OverlappedComponents = Pair.getSecond(); generateInfoForComponentList( - MapType, MapModifiers, std::nullopt, Components, CombinedInfo, + MapType, MapModifiers, {}, Components, CombinedInfo, StructBaseCombinedInfo, PartialStruct, IsFirstComponentList, IsImplicit, /*GenerateAllInfoForClauses*/ false, Mapper, /*ForDeviceAddr=*/false, VD, VarRef, OverlappedComponents); @@ -8714,12 +8720,11 @@ public: auto It = OverlappedData.find(&L); if (It == OverlappedData.end()) generateInfoForComponentList( - MapType, MapModifiers, std::nullopt, Components, CombinedInfo, + MapType, MapModifiers, {}, Components, CombinedInfo, StructBaseCombinedInfo, PartialStruct, IsFirstComponentList, IsImplicit, /*GenerateAllInfoForClauses*/ false, Mapper, /*ForDeviceAddr=*/false, VD, VarRef, - /*OverlappedElements*/ std::nullopt, - HasMapBasePtr && HasMapArraySec); + /*OverlappedElements*/ {}, HasMapBasePtr && HasMapArraySec); IsFirstComponentList = false; } } @@ -9674,9 +9679,12 @@ static void emitTargetCallKernelLaunch( NumTargetItems, RTArgs, NumIterations, NumTeams, NumThreads, DynCGGroupMem, HasNoWait); - CGF.Builder.restoreIP(OMPRuntime->getOMPBuilder().emitKernelLaunch( - CGF.Builder, OutlinedFnID, EmitTargetCallFallbackCB, Args, DeviceID, - RTLoc, AllocaIP)); + llvm::OpenMPIRBuilder::InsertPointOrErrorTy AfterIP = + OMPRuntime->getOMPBuilder().emitKernelLaunch( + CGF.Builder, OutlinedFnID, EmitTargetCallFallbackCB, Args, DeviceID, + RTLoc, AllocaIP); + assert(AfterIP && "unexpected error creating kernel launch"); + CGF.Builder.restoreIP(*AfterIP); }; if (RequiresOuterTask) @@ -10353,9 +10361,12 @@ void CGOpenMPRuntime::emitTargetDataCalls( InsertPointTy CodeGenIP(CGF.Builder.GetInsertBlock(), CGF.Builder.GetInsertPoint()); llvm::OpenMPIRBuilder::LocationDescription OmpLoc(CodeGenIP); - CGF.Builder.restoreIP(OMPBuilder.createTargetData( - OmpLoc, AllocaIP, CodeGenIP, DeviceID, IfCondVal, Info, GenMapInfoCB, - /*MapperFunc=*/nullptr, BodyCB, DeviceAddrCB, CustomMapperCB, RTLoc)); + llvm::OpenMPIRBuilder::InsertPointOrErrorTy AfterIP = + OMPBuilder.createTargetData( + OmpLoc, AllocaIP, CodeGenIP, DeviceID, IfCondVal, Info, GenMapInfoCB, + /*MapperFunc=*/nullptr, BodyCB, DeviceAddrCB, CustomMapperCB, RTLoc); + assert(AfterIP && "unexpected error creating target data"); + CGF.Builder.restoreIP(*AfterIP); } void CGOpenMPRuntime::emitTargetDataStandAloneCall( diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h index 5030a84ba6c184f507ee85f9c03bbc34784bf7eb..9f52f24e4c0ba14130433ca9758ec53adeac1c45 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -353,7 +353,7 @@ protected: /// Emits \p Callee function call with arguments \p Args with location \p Loc. void emitCall(CodeGenFunction &CGF, SourceLocation Loc, llvm::FunctionCallee Callee, - ArrayRef Args = std::nullopt) const; + ArrayRef Args = {}) const; /// Emits address of the word in a memory where current thread id is /// stored. @@ -1544,7 +1544,7 @@ public: virtual void emitOutlinedFunctionCall(CodeGenFunction &CGF, SourceLocation Loc, llvm::FunctionCallee OutlinedFn, - ArrayRef Args = std::nullopt) const; + ArrayRef Args = {}) const; /// Emits OpenMP-specific function prolog. /// Required for device constructs. diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index 2e5ab6e7b9ac5cd9a1b334ba10b6bfcca1007949..598b946ad88dbbf41533aef4f9416eac749936b7 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -985,8 +985,8 @@ llvm::Function *CGOpenMPRuntimeGPU::emitTeamsOutlinedFunction( getDistributeLastprivateVars(CGM.getContext(), D, LastPrivatesReductions); if (!LastPrivatesReductions.empty()) { GlobalizedRD = ::buildRecordForGlobalizedVars( - CGM.getContext(), std::nullopt, LastPrivatesReductions, - MappedDeclsFields, WarpSize); + CGM.getContext(), {}, LastPrivatesReductions, MappedDeclsFields, + WarpSize); } } else if (!LastPrivatesReductions.empty()) { assert(!TeamAndReductions.first && @@ -1681,7 +1681,7 @@ void CGOpenMPRuntimeGPU::emitReduction( ++Cnt; } const RecordDecl *ReductionRec = ::buildRecordForGlobalizedVars( - CGM.getContext(), PrivatesReductions, std::nullopt, VarFieldMap, 1); + CGM.getContext(), PrivatesReductions, {}, VarFieldMap, 1); if (TeamsReduction) TeamsReductions.push_back(ReductionRec); @@ -1753,11 +1753,14 @@ void CGOpenMPRuntimeGPU::emitReduction( Idx++; } - CGF.Builder.restoreIP(OMPBuilder.createReductionsGPU( - OmpLoc, AllocaIP, CodeGenIP, ReductionInfos, false, TeamsReduction, - DistributeReduction, llvm::OpenMPIRBuilder::ReductionGenCBKind::Clang, - CGF.getTarget().getGridValue(), C.getLangOpts().OpenMPCUDAReductionBufNum, - RTLoc)); + llvm::OpenMPIRBuilder::InsertPointOrErrorTy AfterIP = + OMPBuilder.createReductionsGPU( + OmpLoc, AllocaIP, CodeGenIP, ReductionInfos, false, TeamsReduction, + DistributeReduction, llvm::OpenMPIRBuilder::ReductionGenCBKind::Clang, + CGF.getTarget().getGridValue(), + C.getLangOpts().OpenMPCUDAReductionBufNum, RTLoc); + assert(AfterIP && "unexpected error creating GPU reductions"); + CGF.Builder.restoreIP(*AfterIP); return; } @@ -2345,11 +2348,11 @@ llvm::Value *CGOpenMPRuntimeGPU::getGPUNumThreads(CodeGenFunction &CGF) { const char *LocSize = "__kmpc_get_hardware_num_threads_in_block"; llvm::Function *F = M->getFunction(LocSize); if (!F) { - F = llvm::Function::Create( - llvm::FunctionType::get(CGF.Int32Ty, std::nullopt, false), - llvm::GlobalVariable::ExternalLinkage, LocSize, &CGF.CGM.getModule()); + F = llvm::Function::Create(llvm::FunctionType::get(CGF.Int32Ty, {}, false), + llvm::GlobalVariable::ExternalLinkage, LocSize, + &CGF.CGM.getModule()); } - return Bld.CreateCall(F, std::nullopt, "nvptx_num_threads"); + return Bld.CreateCall(F, {}, "nvptx_num_threads"); } llvm::Value *CGOpenMPRuntimeGPU::getGPUThreadID(CodeGenFunction &CGF) { diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h index 4d586ec972f8d68cb422328c2b674bfd7fa48d54..b59f43a6915ddf0618a51643cc0805e4333abc3e 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h @@ -294,9 +294,10 @@ public: /// Emits call of the outlined function with the provided arguments, /// translating these arguments to correct target-specific arguments. - void emitOutlinedFunctionCall( - CodeGenFunction &CGF, SourceLocation Loc, llvm::FunctionCallee OutlinedFn, - ArrayRef Args = std::nullopt) const override; + void + emitOutlinedFunctionCall(CodeGenFunction &CGF, SourceLocation Loc, + llvm::FunctionCallee OutlinedFn, + ArrayRef Args = {}) const override; /// Emits OpenMP-specific function prolog. /// Required for device constructs. diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 1a4476232b8002b823c9abf4db370336e691d7bb..ca24b219484ef7bddbaa8c27a07ce6db876442c1 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -501,7 +501,7 @@ static llvm::Function *emitOutlinedFunctionPrologue( FunctionDecl *DebugFunctionDecl = nullptr; if (!FO.UIntPtrCastRequired) { FunctionProtoType::ExtProtoInfo EPI; - QualType FunctionTy = Ctx.getFunctionType(Ctx.VoidTy, std::nullopt, EPI); + QualType FunctionTy = Ctx.getFunctionType(Ctx.VoidTy, {}, EPI); DebugFunctionDecl = FunctionDecl::Create( Ctx, Ctx.getTranslationUnitDecl(), FO.S->getBeginLoc(), SourceLocation(), DeclarationName(), FunctionTy, @@ -1809,6 +1809,7 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { // thus calls destructors etc. auto FiniCB = [this](InsertPointTy IP) { OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP); + return llvm::Error::success(); }; // Privatization callback that performs appropriate action for @@ -1831,15 +1832,18 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { InsertPointTy CodeGenIP) { OMPBuilderCBHelpers::EmitOMPOutlinedRegionBody( *this, ParallelRegionBodyStmt, AllocaIP, CodeGenIP, "parallel"); + return llvm::Error::success(); }; CGCapturedStmtInfo CGSI(*CS, CR_OpenMP); CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(*this, &CGSI); llvm::OpenMPIRBuilder::InsertPointTy AllocaIP( AllocaInsertPt->getParent(), AllocaInsertPt->getIterator()); - Builder.restoreIP( + llvm::OpenMPIRBuilder::InsertPointOrErrorTy AfterIP = OMPBuilder.createParallel(Builder, AllocaIP, BodyGenCB, PrivCB, FiniCB, - IfCond, NumThreads, ProcBind, S.hasCancel())); + IfCond, NumThreads, ProcBind, S.hasCancel()); + assert(AfterIP && "unexpected error creating parallel"); + Builder.restoreIP(*AfterIP); return; } @@ -2128,9 +2132,13 @@ void CodeGenFunction::EmitOMPCanonicalLoop(const OMPCanonicalLoop *S) { RunCleanupsScope BodyScope(*this); EmitStmt(BodyStmt); + return llvm::Error::success(); }; - llvm::CanonicalLoopInfo *CL = + + llvm::Expected Result = OMPBuilder.createCanonicalLoop(Builder, BodyGen, DistVal); + assert(Result && "unexpected error creating canonical loop"); + llvm::CanonicalLoopInfo *CL = *Result; // Finish up the loop. Builder.restoreIP(CL->getAfterIP()); @@ -4025,11 +4033,13 @@ static void emitOMPForDirective(const OMPLoopDirective &S, CodeGenFunction &CGF, CGM.getOpenMPRuntime().getOMPBuilder(); llvm::OpenMPIRBuilder::InsertPointTy AllocaIP( CGF.AllocaInsertPt->getParent(), CGF.AllocaInsertPt->getIterator()); - OMPBuilder.applyWorkshareLoop( - CGF.Builder.getCurrentDebugLocation(), CLI, AllocaIP, NeedsBarrier, - SchedKind, ChunkSize, /*HasSimdModifier=*/false, - /*HasMonotonicModifier=*/false, /*HasNonmonotonicModifier=*/false, - /*HasOrderedClause=*/false); + llvm::OpenMPIRBuilder::InsertPointOrErrorTy AfterIP = + OMPBuilder.applyWorkshareLoop( + CGF.Builder.getCurrentDebugLocation(), CLI, AllocaIP, + NeedsBarrier, SchedKind, ChunkSize, /*HasSimdModifier=*/false, + /*HasMonotonicModifier=*/false, /*HasNonmonotonicModifier=*/false, + /*HasOrderedClause=*/false); + assert(AfterIP && "unexpected error creating workshare loop"); return; } @@ -4266,6 +4276,7 @@ void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) { auto FiniCB = [this](InsertPointTy IP) { OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP); + return llvm::Error::success(); }; const CapturedStmt *ICS = S.getInnermostCapturedStmt(); @@ -4278,6 +4289,7 @@ void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) { InsertPointTy CodeGenIP) { OMPBuilderCBHelpers::EmitOMPInlinedRegionBody( *this, SubStmt, AllocaIP, CodeGenIP, "section"); + return llvm::Error::success(); }; SectionCBVector.push_back(SectionCB); } @@ -4286,6 +4298,7 @@ void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) { InsertPointTy CodeGenIP) { OMPBuilderCBHelpers::EmitOMPInlinedRegionBody( *this, CapturedStmt, AllocaIP, CodeGenIP, "section"); + return llvm::Error::success(); }; SectionCBVector.push_back(SectionCB); } @@ -4307,9 +4320,12 @@ void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) { CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(*this, &CGSI); llvm::OpenMPIRBuilder::InsertPointTy AllocaIP( AllocaInsertPt->getParent(), AllocaInsertPt->getIterator()); - Builder.restoreIP(OMPBuilder.createSections( - Builder, AllocaIP, SectionCBVector, PrivCB, FiniCB, S.hasCancel(), - S.getSingleClause())); + llvm::OpenMPIRBuilder::InsertPointOrErrorTy AfterIP = + OMPBuilder.createSections(Builder, AllocaIP, SectionCBVector, PrivCB, + FiniCB, S.hasCancel(), + S.getSingleClause()); + assert(AfterIP && "unexpected error creating sections"); + Builder.restoreIP(*AfterIP); return; } { @@ -4335,17 +4351,22 @@ void CodeGenFunction::EmitOMPSectionDirective(const OMPSectionDirective &S) { const Stmt *SectionRegionBodyStmt = S.getAssociatedStmt(); auto FiniCB = [this](InsertPointTy IP) { OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP); + return llvm::Error::success(); }; auto BodyGenCB = [SectionRegionBodyStmt, this](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) { OMPBuilderCBHelpers::EmitOMPInlinedRegionBody( *this, SectionRegionBodyStmt, AllocaIP, CodeGenIP, "section"); + return llvm::Error::success(); }; LexicalScope Scope(*this, S.getSourceRange()); EmitStopPoint(&S); - Builder.restoreIP(OMPBuilder.createSection(Builder, BodyGenCB, FiniCB)); + llvm::OpenMPIRBuilder::InsertPointOrErrorTy AfterIP = + OMPBuilder.createSection(Builder, BodyGenCB, FiniCB); + assert(AfterIP && "unexpected error creating section"); + Builder.restoreIP(*AfterIP); return; } @@ -4416,17 +4437,22 @@ void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) { auto FiniCB = [this](InsertPointTy IP) { OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP); + return llvm::Error::success(); }; auto BodyGenCB = [MasterRegionBodyStmt, this](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) { OMPBuilderCBHelpers::EmitOMPInlinedRegionBody( *this, MasterRegionBodyStmt, AllocaIP, CodeGenIP, "master"); + return llvm::Error::success(); }; LexicalScope Scope(*this, S.getSourceRange()); EmitStopPoint(&S); - Builder.restoreIP(OMPBuilder.createMaster(Builder, BodyGenCB, FiniCB)); + llvm::OpenMPIRBuilder::InsertPointOrErrorTy AfterIP = + OMPBuilder.createMaster(Builder, BodyGenCB, FiniCB); + assert(AfterIP && "unexpected error creating master"); + Builder.restoreIP(*AfterIP); return; } @@ -4462,18 +4488,22 @@ void CodeGenFunction::EmitOMPMaskedDirective(const OMPMaskedDirective &S) { auto FiniCB = [this](InsertPointTy IP) { OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP); + return llvm::Error::success(); }; auto BodyGenCB = [MaskedRegionBodyStmt, this](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) { OMPBuilderCBHelpers::EmitOMPInlinedRegionBody( *this, MaskedRegionBodyStmt, AllocaIP, CodeGenIP, "masked"); + return llvm::Error::success(); }; LexicalScope Scope(*this, S.getSourceRange()); EmitStopPoint(&S); - Builder.restoreIP( - OMPBuilder.createMasked(Builder, BodyGenCB, FiniCB, FilterVal)); + llvm::OpenMPIRBuilder::InsertPointOrErrorTy AfterIP = + OMPBuilder.createMasked(Builder, BodyGenCB, FiniCB, FilterVal); + assert(AfterIP && "unexpected error creating masked"); + Builder.restoreIP(*AfterIP); return; } @@ -4502,19 +4532,23 @@ void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) { auto FiniCB = [this](InsertPointTy IP) { OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP); + return llvm::Error::success(); }; auto BodyGenCB = [CriticalRegionBodyStmt, this](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) { OMPBuilderCBHelpers::EmitOMPInlinedRegionBody( *this, CriticalRegionBodyStmt, AllocaIP, CodeGenIP, "critical"); + return llvm::Error::success(); }; LexicalScope Scope(*this, S.getSourceRange()); EmitStopPoint(&S); - Builder.restoreIP(OMPBuilder.createCritical( - Builder, BodyGenCB, FiniCB, S.getDirectiveName().getAsString(), - HintInst)); + llvm::OpenMPIRBuilder::InsertPointOrErrorTy AfterIP = + OMPBuilder.createCritical(Builder, BodyGenCB, FiniCB, + S.getDirectiveName().getAsString(), HintInst); + assert(AfterIP && "unexpected error creating critical"); + Builder.restoreIP(*AfterIP); return; } @@ -5488,11 +5522,15 @@ void CodeGenFunction::EmitOMPTaskgroupDirective( InsertPointTy CodeGenIP) { Builder.restoreIP(CodeGenIP); EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt()); + return llvm::Error::success(); }; CodeGenFunction::CGCapturedStmtInfo CapStmtInfo; if (!CapturedStmtInfo) CapturedStmtInfo = &CapStmtInfo; - Builder.restoreIP(OMPBuilder.createTaskgroup(Builder, AllocaIP, BodyGenCB)); + llvm::OpenMPIRBuilder::InsertPointOrErrorTy AfterIP = + OMPBuilder.createTaskgroup(Builder, AllocaIP, BodyGenCB); + assert(AfterIP && "unexpected error creating taskgroup"); + Builder.restoreIP(*AfterIP); return; } auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { @@ -5533,7 +5571,7 @@ void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &S) { if (const auto *FlushClause = S.getSingleClause()) return llvm::ArrayRef(FlushClause->varlist_begin(), FlushClause->varlist_end()); - return std::nullopt; + return {}; }(), S.getBeginLoc(), AO); } @@ -6065,6 +6103,7 @@ void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &S) { auto FiniCB = [this](InsertPointTy IP) { OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP); + return llvm::Error::success(); }; auto BodyGenCB = [&S, C, this](InsertPointTy AllocaIP, @@ -6088,11 +6127,14 @@ void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &S) { OMPBuilderCBHelpers::EmitOMPInlinedRegionBody( *this, CS->getCapturedStmt(), AllocaIP, CodeGenIP, "ordered"); } + return llvm::Error::success(); }; OMPLexicalScope Scope(*this, S, OMPD_unknown); - Builder.restoreIP( - OMPBuilder.createOrderedThreadsSimd(Builder, BodyGenCB, FiniCB, !C)); + llvm::OpenMPIRBuilder::InsertPointOrErrorTy AfterIP = + OMPBuilder.createOrderedThreadsSimd(Builder, BodyGenCB, FiniCB, !C); + assert(AfterIP && "unexpected error creating ordered"); + Builder.restoreIP(*AfterIP); } return; } @@ -6223,7 +6265,7 @@ static void emitOMPAtomicReadExpr(CodeGenFunction &CGF, llvm::AtomicOrdering AO, case llvm::AtomicOrdering::Acquire: case llvm::AtomicOrdering::AcquireRelease: case llvm::AtomicOrdering::SequentiallyConsistent: - CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc, + CGF.CGM.getOpenMPRuntime().emitFlush(CGF, {}, Loc, llvm::AtomicOrdering::Acquire); break; case llvm::AtomicOrdering::Monotonic: @@ -6252,7 +6294,7 @@ static void emitOMPAtomicWriteExpr(CodeGenFunction &CGF, case llvm::AtomicOrdering::Release: case llvm::AtomicOrdering::AcquireRelease: case llvm::AtomicOrdering::SequentiallyConsistent: - CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc, + CGF.CGM.getOpenMPRuntime().emitFlush(CGF, {}, Loc, llvm::AtomicOrdering::Release); break; case llvm::AtomicOrdering::Acquire: @@ -6442,7 +6484,7 @@ static void emitOMPAtomicUpdateExpr(CodeGenFunction &CGF, case llvm::AtomicOrdering::Release: case llvm::AtomicOrdering::AcquireRelease: case llvm::AtomicOrdering::SequentiallyConsistent: - CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc, + CGF.CGM.getOpenMPRuntime().emitFlush(CGF, {}, Loc, llvm::AtomicOrdering::Release); break; case llvm::AtomicOrdering::Acquire: @@ -6557,17 +6599,17 @@ static void emitOMPAtomicCaptureExpr(CodeGenFunction &CGF, // operation is also an acquire flush. switch (AO) { case llvm::AtomicOrdering::Release: - CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc, + CGF.CGM.getOpenMPRuntime().emitFlush(CGF, {}, Loc, llvm::AtomicOrdering::Release); break; case llvm::AtomicOrdering::Acquire: - CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc, + CGF.CGM.getOpenMPRuntime().emitFlush(CGF, {}, Loc, llvm::AtomicOrdering::Acquire); break; case llvm::AtomicOrdering::AcquireRelease: case llvm::AtomicOrdering::SequentiallyConsistent: CGF.CGM.getOpenMPRuntime().emitFlush( - CGF, std::nullopt, Loc, llvm::AtomicOrdering::AcquireRelease); + CGF, {}, Loc, llvm::AtomicOrdering::AcquireRelease); break; case llvm::AtomicOrdering::Monotonic: break; @@ -7368,8 +7410,10 @@ void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) { if (IfCond) IfCondition = EmitScalarExpr(IfCond, /*IgnoreResultAssign=*/true); - return Builder.restoreIP( - OMPBuilder.createCancel(Builder, IfCondition, S.getCancelRegion())); + llvm::OpenMPIRBuilder::InsertPointOrErrorTy AfterIP = + OMPBuilder.createCancel(Builder, IfCondition, S.getCancelRegion()); + assert(AfterIP && "unexpected error creating cancel"); + return Builder.restoreIP(*AfterIP); } } diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 465dc8c661af5c83332ad32cc4fcaa456eb2637a..6ead45793742d6c8de0b77ad77847028356ffc40 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -852,7 +852,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, if (Fe.Effect.kind() == FunctionEffect::Kind::NonBlocking) Fn->addFnAttr(llvm::Attribute::SanitizeRealtime); else if (Fe.Effect.kind() == FunctionEffect::Kind::Blocking) - Fn->addFnAttr(llvm::Attribute::SanitizeRealtimeUnsafe); + Fn->addFnAttr(llvm::Attribute::SanitizeRealtimeBlocking); } // Apply fuzzing attribute to the function. @@ -1595,7 +1595,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, llvm::Value *IsFalse = Builder.getFalse(); EmitCheck(std::make_pair(IsFalse, SanitizerKind::Return), SanitizerHandler::MissingReturn, - EmitCheckSourceLocation(FD->getLocation()), std::nullopt); + EmitCheckSourceLocation(FD->getLocation()), {}); } else if (ShouldEmitUnreachable) { if (CGM.getCodeGenOpts().OptimizationLevel == 0) EmitTrapCall(llvm::Intrinsic::trap); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index b9e28efde81c1a6165fbbec155a41deeec241678..f383741b73f18493a132c154ae7c14b0e9b024ad 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3524,7 +3524,7 @@ public: /// This function may clear the current insertion point; callers should use /// EnsureInsertPoint if they wish to subsequently generate code without first /// calling EmitBlock, EmitBranch, or EmitStmt. - void EmitStmt(const Stmt *S, ArrayRef Attrs = std::nullopt); + void EmitStmt(const Stmt *S, ArrayRef Attrs = {}); /// EmitSimpleStmt - Try to emit a "simple" statement which does not /// necessarily require an insertion point or debug information; typically @@ -3551,11 +3551,9 @@ public: void EmitIndirectGotoStmt(const IndirectGotoStmt &S); void EmitIfStmt(const IfStmt &S); - void EmitWhileStmt(const WhileStmt &S, - ArrayRef Attrs = std::nullopt); - void EmitDoStmt(const DoStmt &S, ArrayRef Attrs = std::nullopt); - void EmitForStmt(const ForStmt &S, - ArrayRef Attrs = std::nullopt); + void EmitWhileStmt(const WhileStmt &S, ArrayRef Attrs = {}); + void EmitDoStmt(const DoStmt &S, ArrayRef Attrs = {}); + void EmitForStmt(const ForStmt &S, ArrayRef Attrs = {}); void EmitReturnStmt(const ReturnStmt &S); void EmitDeclStmt(const DeclStmt &S); void EmitBreakStmt(const BreakStmt &S); @@ -3632,7 +3630,7 @@ public: llvm::Value *ParentFP); void EmitCXXForRangeStmt(const CXXForRangeStmt &S, - ArrayRef Attrs = std::nullopt); + ArrayRef Attrs = {}); /// Controls insertion of cancellation exit blocks in worksharing constructs. class OMPCancelStackRAII { @@ -4298,8 +4296,11 @@ public: LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E); LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e); LValue EmitHLSLArrayAssignLValue(const BinaryOperator *E); - void EmitHLSLOutArgExpr(const HLSLOutArgExpr *E, CallArgList &Args, - QualType Ty); + + std::pair EmitHLSLOutArgLValues(const HLSLOutArgExpr *E, + QualType Ty); + LValue EmitHLSLOutArgExpr(const HLSLOutArgExpr *E, CallArgList &Args, + QualType Ty); Address EmitExtVectorElementLValue(LValue V); @@ -5153,6 +5154,9 @@ public: SourceLocation ArgLoc, AbstractCallee AC, unsigned ParmNum); + /// EmitWriteback - Emit callbacks for function. + void EmitWritebacks(const CallArgList &Args); + /// EmitCallArg - Emit a single call argument. void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 1b77490e261c210ddbee88ffb3a1667a8795f429..8d5787769382f6858a53ff33aa12c3ef590e0219 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -753,8 +753,7 @@ public: llvm::MDNode *getNoObjCARCExceptionsMetadata() { if (!NoObjCARCExceptionsMetadata) - NoObjCARCExceptionsMetadata = - llvm::MDNode::get(getLLVMContext(), std::nullopt); + NoObjCARCExceptionsMetadata = llvm::MDNode::get(getLLVMContext(), {}); return NoObjCARCExceptionsMetadata; } @@ -1181,8 +1180,7 @@ public: llvm::Constant *getBuiltinLibFunction(const FunctionDecl *FD, unsigned BuiltinID); - llvm::Function *getIntrinsic(unsigned IID, - ArrayRef Tys = std::nullopt); + llvm::Function *getIntrinsic(unsigned IID, ArrayRef Tys = {}); /// Emit code for a single top level declaration. void EmitTopLevelDecl(Decl *D); diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index 624b3cf267e2db6a97bd15a8fb6c0dd96d0c8229..99de26192d96cdf15f94bffe1093fe32f77f7a59 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -564,6 +564,10 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { #define AMDGPU_OPAQUE_PTR_TYPE(Name, Id, SingletonId, Width, Align, AS) \ case BuiltinType::Id: \ return llvm::PointerType::get(getLLVMContext(), AS); +#define AMDGPU_NAMED_BARRIER_TYPE(Name, Id, SingletonId, Width, Align, Scope) \ + case BuiltinType::Id: \ + return llvm::TargetExtType::get(getLLVMContext(), "amdgcn.named.barrier", \ + {}, {Scope}); #include "clang/Basic/AMDGPUTypes.def" #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/HLSLIntangibleTypes.def" diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 0a63c50d44f4b742ddefc7fa88af4f03ab89bfe6..45518736a2ac38e25f887a4bab3e190ec40bb61c 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -649,7 +649,7 @@ struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder { if (MappingRegions.empty()) return; - CoverageMappingWriter Writer(FileIDMapping, std::nullopt, MappingRegions); + CoverageMappingWriter Writer(FileIDMapping, {}, MappingRegions); Writer.write(OS); } }; diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 89f9457523824a60371689bddc01699967bef449..9b3c2f1b2af67726b612dbc7ddd69dbf7cd3c5c7 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -1416,7 +1416,7 @@ void ItaniumCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) { llvm::FunctionCallee Fn = CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); if (isNoReturn) - CGF.EmitNoreturnRuntimeCallOrInvoke(Fn, std::nullopt); + CGF.EmitNoreturnRuntimeCallOrInvoke(Fn, {}); else CGF.EmitRuntimeCallOrInvoke(Fn); } diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp index ec617eec67192cc797bb95dbc6def2871ebd5362..9320c6ef06efab0acda3531acc3f7cd0a3a4e811 100644 --- a/clang/lib/CodeGen/Targets/AArch64.cpp +++ b/clang/lib/CodeGen/Targets/AArch64.cpp @@ -34,10 +34,17 @@ private: AArch64ABIKind getABIKind() const { return Kind; } bool isDarwinPCS() const { return Kind == AArch64ABIKind::DarwinPCS; } - ABIArgInfo classifyReturnType(QualType RetTy, bool IsVariadic) const; - ABIArgInfo classifyArgumentType(QualType RetTy, bool IsVariadic, - unsigned CallingConvention) const; - ABIArgInfo coerceIllegalVector(QualType Ty) const; + ABIArgInfo classifyReturnType(QualType RetTy, bool IsVariadicFn) const; + ABIArgInfo classifyArgumentType(QualType RetTy, bool IsVariadicFn, + bool IsNamedArg, unsigned CallingConvention, + unsigned &NSRN, unsigned &NPRN) const; + llvm::Type *convertFixedToScalableVectorType(const VectorType *VT) const; + ABIArgInfo coerceIllegalVector(QualType Ty, unsigned &NSRN, + unsigned &NPRN) const; + ABIArgInfo coerceAndExpandPureScalableAggregate( + QualType Ty, bool IsNamedArg, unsigned NVec, unsigned NPred, + const SmallVectorImpl &UnpaddedCoerceToSeq, unsigned &NSRN, + unsigned &NPRN) const; bool isHomogeneousAggregateBaseType(QualType Ty) const override; bool isHomogeneousAggregateSmallEnough(const Type *Ty, uint64_t Members) const override; @@ -45,14 +52,26 @@ private: bool isIllegalVectorType(QualType Ty) const; + bool passAsPureScalableType(QualType Ty, unsigned &NV, unsigned &NP, + SmallVectorImpl &CoerceToSeq) const; + + void flattenType(llvm::Type *Ty, + SmallVectorImpl &Flattened) const; + void computeInfo(CGFunctionInfo &FI) const override { if (!::classifyReturnType(getCXXABI(), FI, *this)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), FI.isVariadic()); - for (auto &it : FI.arguments()) - it.info = classifyArgumentType(it.type, FI.isVariadic(), - FI.getCallingConvention()); + unsigned ArgNo = 0; + unsigned NSRN = 0, NPRN = 0; + for (auto &it : FI.arguments()) { + const bool IsNamedArg = + !FI.isVariadic() || ArgNo < FI.getRequiredArgs().getNumRequiredArgs(); + ++ArgNo; + it.info = classifyArgumentType(it.type, FI.isVariadic(), IsNamedArg, + FI.getCallingConvention(), NSRN, NPRN); + } } RValue EmitDarwinVAArg(Address VAListAddr, QualType Ty, CodeGenFunction &CGF, @@ -201,65 +220,83 @@ void WindowsAArch64TargetCodeGenInfo::setTargetAttributes( } } -ABIArgInfo AArch64ABIInfo::coerceIllegalVector(QualType Ty) const { - assert(Ty->isVectorType() && "expected vector type!"); +llvm::Type * +AArch64ABIInfo::convertFixedToScalableVectorType(const VectorType *VT) const { + assert(VT->getElementType()->isBuiltinType() && "expected builtin type!"); - const auto *VT = Ty->castAs(); if (VT->getVectorKind() == VectorKind::SveFixedLengthPredicate) { - assert(VT->getElementType()->isBuiltinType() && "expected builtin type!"); assert(VT->getElementType()->castAs()->getKind() == BuiltinType::UChar && "unexpected builtin type for SVE predicate!"); - return ABIArgInfo::getDirect(llvm::ScalableVectorType::get( - llvm::Type::getInt1Ty(getVMContext()), 16)); + return llvm::ScalableVectorType::get(llvm::Type::getInt1Ty(getVMContext()), + 16); } if (VT->getVectorKind() == VectorKind::SveFixedLengthData) { - assert(VT->getElementType()->isBuiltinType() && "expected builtin type!"); - const auto *BT = VT->getElementType()->castAs(); - llvm::ScalableVectorType *ResType = nullptr; switch (BT->getKind()) { default: llvm_unreachable("unexpected builtin type for SVE vector!"); + case BuiltinType::SChar: case BuiltinType::UChar: - ResType = llvm::ScalableVectorType::get( + return llvm::ScalableVectorType::get( llvm::Type::getInt8Ty(getVMContext()), 16); - break; + case BuiltinType::Short: case BuiltinType::UShort: - ResType = llvm::ScalableVectorType::get( + return llvm::ScalableVectorType::get( llvm::Type::getInt16Ty(getVMContext()), 8); - break; + case BuiltinType::Int: case BuiltinType::UInt: - ResType = llvm::ScalableVectorType::get( + return llvm::ScalableVectorType::get( llvm::Type::getInt32Ty(getVMContext()), 4); - break; + case BuiltinType::Long: case BuiltinType::ULong: - ResType = llvm::ScalableVectorType::get( + return llvm::ScalableVectorType::get( llvm::Type::getInt64Ty(getVMContext()), 2); - break; + case BuiltinType::Half: - ResType = llvm::ScalableVectorType::get( + return llvm::ScalableVectorType::get( llvm::Type::getHalfTy(getVMContext()), 8); - break; + case BuiltinType::Float: - ResType = llvm::ScalableVectorType::get( + return llvm::ScalableVectorType::get( llvm::Type::getFloatTy(getVMContext()), 4); - break; + case BuiltinType::Double: - ResType = llvm::ScalableVectorType::get( + return llvm::ScalableVectorType::get( llvm::Type::getDoubleTy(getVMContext()), 2); - break; + case BuiltinType::BFloat16: - ResType = llvm::ScalableVectorType::get( + return llvm::ScalableVectorType::get( llvm::Type::getBFloatTy(getVMContext()), 8); - break; } - return ABIArgInfo::getDirect(ResType); + } + + llvm_unreachable("expected fixed-length SVE vector"); +} + +ABIArgInfo AArch64ABIInfo::coerceIllegalVector(QualType Ty, unsigned &NSRN, + unsigned &NPRN) const { + assert(Ty->isVectorType() && "expected vector type!"); + + const auto *VT = Ty->castAs(); + if (VT->getVectorKind() == VectorKind::SveFixedLengthPredicate) { + assert(VT->getElementType()->isBuiltinType() && "expected builtin type!"); + assert(VT->getElementType()->castAs()->getKind() == + BuiltinType::UChar && + "unexpected builtin type for SVE predicate!"); + NPRN = std::min(NPRN + 1, 4u); + return ABIArgInfo::getDirect(llvm::ScalableVectorType::get( + llvm::Type::getInt1Ty(getVMContext()), 16)); + } + + if (VT->getVectorKind() == VectorKind::SveFixedLengthData) { + NSRN = std::min(NSRN + 1, 8u); + return ABIArgInfo::getDirect(convertFixedToScalableVectorType(VT)); } uint64_t Size = getContext().getTypeSize(Ty); @@ -273,26 +310,54 @@ ABIArgInfo AArch64ABIInfo::coerceIllegalVector(QualType Ty) const { return ABIArgInfo::getDirect(ResType); } if (Size == 64) { + NSRN = std::min(NSRN + 1, 8u); auto *ResType = llvm::FixedVectorType::get(llvm::Type::getInt32Ty(getVMContext()), 2); return ABIArgInfo::getDirect(ResType); } if (Size == 128) { + NSRN = std::min(NSRN + 1, 8u); auto *ResType = llvm::FixedVectorType::get(llvm::Type::getInt32Ty(getVMContext()), 4); return ABIArgInfo::getDirect(ResType); } + return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } -ABIArgInfo -AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadic, - unsigned CallingConvention) const { +ABIArgInfo AArch64ABIInfo::coerceAndExpandPureScalableAggregate( + QualType Ty, bool IsNamedArg, unsigned NVec, unsigned NPred, + const SmallVectorImpl &UnpaddedCoerceToSeq, unsigned &NSRN, + unsigned &NPRN) const { + if (!IsNamedArg || NSRN + NVec > 8 || NPRN + NPred > 4) + return getNaturalAlignIndirect(Ty, /*ByVal=*/false); + NSRN += NVec; + NPRN += NPred; + + llvm::Type *UnpaddedCoerceToType = + UnpaddedCoerceToSeq.size() == 1 + ? UnpaddedCoerceToSeq[0] + : llvm::StructType::get(CGT.getLLVMContext(), UnpaddedCoerceToSeq, + true); + + SmallVector CoerceToSeq; + flattenType(CGT.ConvertType(Ty), CoerceToSeq); + auto *CoerceToType = + llvm::StructType::get(CGT.getLLVMContext(), CoerceToSeq, false); + + return ABIArgInfo::getCoerceAndExpand(CoerceToType, UnpaddedCoerceToType); +} + +ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadicFn, + bool IsNamedArg, + unsigned CallingConvention, + unsigned &NSRN, + unsigned &NPRN) const { Ty = useFirstFieldIfTransparentUnion(Ty); // Handle illegal vector types here. if (isIllegalVectorType(Ty)) - return coerceIllegalVector(Ty); + return coerceIllegalVector(Ty, NSRN, NPRN); if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. @@ -303,6 +368,36 @@ AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadic, if (EIT->getNumBits() > 128) return getNaturalAlignIndirect(Ty, false); + if (Ty->isVectorType()) + NSRN = std::min(NSRN + 1, 8u); + else if (const auto *BT = Ty->getAs()) { + if (BT->isFloatingPoint()) + NSRN = std::min(NSRN + 1, 8u); + else { + switch (BT->getKind()) { + case BuiltinType::MFloat8x8: + case BuiltinType::MFloat8x16: + NSRN = std::min(NSRN + 1, 8u); + break; + case BuiltinType::SveBool: + case BuiltinType::SveCount: + NPRN = std::min(NPRN + 1, 4u); + break; + case BuiltinType::SveBoolx2: + NPRN = std::min(NPRN + 2, 4u); + break; + case BuiltinType::SveBoolx4: + NPRN = std::min(NPRN + 4, 4u); + break; + default: + if (BT->isSVESizelessBuiltinType()) + NSRN = std::min( + NSRN + getContext().getBuiltinVectorTypeInfo(BT).NumVectors, + 8u); + } + } + } + return (isPromotableIntegerTypeForABI(Ty) && isDarwinPCS() ? ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty)) : ABIArgInfo::getDirect()); @@ -335,10 +430,11 @@ AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadic, uint64_t Members = 0; bool IsWin64 = Kind == AArch64ABIKind::Win64 || CallingConvention == llvm::CallingConv::Win64; - bool IsWinVariadic = IsWin64 && IsVariadic; + bool IsWinVariadic = IsWin64 && IsVariadicFn; // In variadic functions on Windows, all composite types are treated alike, // no special handling of HFAs/HVAs. if (!IsWinVariadic && isHomogeneousAggregate(Ty, Base, Members)) { + NSRN = std::min(NSRN + Members, uint64_t(8)); if (Kind != AArch64ABIKind::AAPCS) return ABIArgInfo::getDirect( llvm::ArrayType::get(CGT.ConvertType(QualType(Base, 0)), Members)); @@ -353,13 +449,19 @@ AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadic, nullptr, true, Align); } + // In AAPCS named arguments of a Pure Scalable Type are passed expanded in + // registers, or indirectly if there are not enough registers. + if (Kind == AArch64ABIKind::AAPCS) { + unsigned NVec = 0, NPred = 0; + SmallVector UnpaddedCoerceToSeq; + if (passAsPureScalableType(Ty, NVec, NPred, UnpaddedCoerceToSeq) && + (NVec + NPred) > 0) + return coerceAndExpandPureScalableAggregate( + Ty, IsNamedArg, NVec, NPred, UnpaddedCoerceToSeq, NSRN, NPRN); + } + // Aggregates <= 16 bytes are passed directly in registers or on the stack. if (Size <= 128) { - // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of - // same size and alignment. - if (getTarget().isRenderScriptTarget()) { - return coerceToIntArray(Ty, getContext(), getVMContext()); - } unsigned Alignment; if (Kind == AArch64ABIKind::AAPCS) { Alignment = getContext().getTypeUnadjustedAlign(Ty); @@ -383,14 +485,16 @@ AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadic, } ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy, - bool IsVariadic) const { + bool IsVariadicFn) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); if (const auto *VT = RetTy->getAs()) { if (VT->getVectorKind() == VectorKind::SveFixedLengthData || - VT->getVectorKind() == VectorKind::SveFixedLengthPredicate) - return coerceIllegalVector(RetTy); + VT->getVectorKind() == VectorKind::SveFixedLengthPredicate) { + unsigned NSRN = 0, NPRN = 0; + return coerceIllegalVector(RetTy, NSRN, NPRN); + } } // Large vector types should be returned via memory. @@ -419,18 +523,26 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy, uint64_t Members = 0; if (isHomogeneousAggregate(RetTy, Base, Members) && !(getTarget().getTriple().getArch() == llvm::Triple::aarch64_32 && - IsVariadic)) + IsVariadicFn)) // Homogeneous Floating-point Aggregates (HFAs) are returned directly. return ABIArgInfo::getDirect(); + // In AAPCS return values of a Pure Scalable type are treated as a single + // named argument and passed expanded in registers, or indirectly if there are + // not enough registers. + if (Kind == AArch64ABIKind::AAPCS) { + unsigned NSRN = 0, NPRN = 0; + unsigned NVec = 0, NPred = 0; + SmallVector UnpaddedCoerceToSeq; + if (passAsPureScalableType(RetTy, NVec, NPred, UnpaddedCoerceToSeq) && + (NVec + NPred) > 0) + return coerceAndExpandPureScalableAggregate( + RetTy, /* IsNamedArg */ true, NVec, NPred, UnpaddedCoerceToSeq, NSRN, + NPRN); + } + // Aggregates <= 16 bytes are returned directly in registers or on the stack. if (Size <= 128) { - // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of - // same size and alignment. - if (getTarget().isRenderScriptTarget()) { - return coerceToIntArray(RetTy, getContext(), getVMContext()); - } - if (Size <= 64 && getDataLayout().isLittleEndian()) { // Composite types are returned in lower bits of a 64-bit register for LE, // and in higher bits for BE. However, integer types are always returned @@ -508,9 +620,15 @@ bool AArch64ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { // but with the difference that any floating-point type is allowed, // including __fp16. if (const BuiltinType *BT = Ty->getAs()) { - if (BT->isFloatingPoint()) + if (BT->isFloatingPoint() || BT->getKind() == BuiltinType::MFloat8x16 || + BT->getKind() == BuiltinType::MFloat8x8) return true; } else if (const VectorType *VT = Ty->getAs()) { + if (auto Kind = VT->getVectorKind(); + Kind == VectorKind::SveFixedLengthData || + Kind == VectorKind::SveFixedLengthPredicate) + return false; + unsigned VecSize = getContext().getTypeSize(VT); if (VecSize == 64 || VecSize == 128) return true; @@ -533,11 +651,166 @@ bool AArch64ABIInfo::isZeroLengthBitfieldPermittedInHomogeneousAggregate() return true; } +// Check if a type needs to be passed in registers as a Pure Scalable Type (as +// defined by AAPCS64). Return the number of data vectors and the number of +// predicate vectors in the type, into `NVec` and `NPred`, respectively. Upon +// return `CoerceToSeq` contains an expanded sequence of LLVM IR types, one +// element for each non-composite member. For practical purposes, limit the +// length of `CoerceToSeq` to about 12 (the maximum that could possibly fit +// in registers) and return false, the effect of which will be to pass the +// argument under the rules for a large (> 128 bytes) composite. +bool AArch64ABIInfo::passAsPureScalableType( + QualType Ty, unsigned &NVec, unsigned &NPred, + SmallVectorImpl &CoerceToSeq) const { + if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) { + uint64_t NElt = AT->getZExtSize(); + if (NElt == 0) + return false; + + unsigned NV = 0, NP = 0; + SmallVector EltCoerceToSeq; + if (!passAsPureScalableType(AT->getElementType(), NV, NP, EltCoerceToSeq)) + return false; + + if (CoerceToSeq.size() + NElt * EltCoerceToSeq.size() > 12) + return false; + + for (uint64_t I = 0; I < NElt; ++I) + llvm::copy(EltCoerceToSeq, std::back_inserter(CoerceToSeq)); + + NVec += NElt * NV; + NPred += NElt * NP; + return true; + } + + if (const RecordType *RT = Ty->getAs()) { + // If the record cannot be passed in registers, then it's not a PST. + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); + RAA != CGCXXABI::RAA_Default) + return false; + + // Pure scalable types are never unions and never contain unions. + const RecordDecl *RD = RT->getDecl(); + if (RD->isUnion()) + return false; + + // If this is a C++ record, check the bases. + if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { + for (const auto &I : CXXRD->bases()) { + if (isEmptyRecord(getContext(), I.getType(), true)) + continue; + if (!passAsPureScalableType(I.getType(), NVec, NPred, CoerceToSeq)) + return false; + } + } + + // Check members. + for (const auto *FD : RD->fields()) { + QualType FT = FD->getType(); + if (isEmptyField(getContext(), FD, /* AllowArrays */ true)) + continue; + if (!passAsPureScalableType(FT, NVec, NPred, CoerceToSeq)) + return false; + } + + return true; + } + + const auto *VT = Ty->getAs(); + if (!VT) + return false; + + if (VT->getVectorKind() == VectorKind::SveFixedLengthPredicate) { + ++NPred; + if (CoerceToSeq.size() + 1 > 12) + return false; + CoerceToSeq.push_back(convertFixedToScalableVectorType(VT)); + return true; + } + + if (VT->getVectorKind() == VectorKind::SveFixedLengthData) { + ++NVec; + if (CoerceToSeq.size() + 1 > 12) + return false; + CoerceToSeq.push_back(convertFixedToScalableVectorType(VT)); + return true; + } + + if (!VT->isBuiltinType()) + return false; + + switch (cast(VT)->getKind()) { +#define SVE_VECTOR_TYPE(Name, MangledName, Id, SingletonId) \ + case BuiltinType::Id: \ + ++NVec; \ + break; +#define SVE_PREDICATE_TYPE(Name, MangledName, Id, SingletonId) \ + case BuiltinType::Id: \ + ++NPred; \ + break; +#define SVE_TYPE(Name, Id, SingletonId) +#include "clang/Basic/AArch64SVEACLETypes.def" + default: + return false; + } + + ASTContext::BuiltinVectorTypeInfo Info = + getContext().getBuiltinVectorTypeInfo(cast(Ty)); + assert(Info.NumVectors > 0 && Info.NumVectors <= 4 && + "Expected 1, 2, 3 or 4 vectors!"); + auto VTy = llvm::ScalableVectorType::get(CGT.ConvertType(Info.ElementType), + Info.EC.getKnownMinValue()); + + if (CoerceToSeq.size() + Info.NumVectors > 12) + return false; + std::fill_n(std::back_inserter(CoerceToSeq), Info.NumVectors, VTy); + + return true; +} + +// Expand an LLVM IR type into a sequence with a element for each non-struct, +// non-array member of the type, with the exception of the padding types, which +// are retained. +void AArch64ABIInfo::flattenType( + llvm::Type *Ty, SmallVectorImpl &Flattened) const { + + if (ABIArgInfo::isPaddingForCoerceAndExpand(Ty)) { + Flattened.push_back(Ty); + return; + } + + if (const auto *AT = dyn_cast(Ty)) { + uint64_t NElt = AT->getNumElements(); + if (NElt == 0) + return; + + SmallVector EltFlattened; + flattenType(AT->getElementType(), EltFlattened); + + for (uint64_t I = 0; I < NElt; ++I) + llvm::copy(EltFlattened, std::back_inserter(Flattened)); + return; + } + + if (const auto *ST = dyn_cast(Ty)) { + for (auto *ET : ST->elements()) + flattenType(ET, Flattened); + return; + } + + Flattened.push_back(Ty); +} + RValue AArch64ABIInfo::EmitAAPCSVAArg(Address VAListAddr, QualType Ty, CodeGenFunction &CGF, AArch64ABIKind Kind, AggValueSlot Slot) const { - ABIArgInfo AI = classifyArgumentType(Ty, /*IsVariadic=*/true, - CGF.CurFnInfo->getCallingConvention()); + // These numbers are not used for variadic arguments, hence it doesn't matter + // they don't retain their values across multiple calls to + // `classifyArgumentType` here. + unsigned NSRN = 0, NPRN = 0; + ABIArgInfo AI = + classifyArgumentType(Ty, /*IsVariadicFn=*/true, /* IsNamedArg */ false, + CGF.CurFnInfo->getCallingConvention(), NSRN, NPRN); // Empty records are ignored for parameter passing purposes. if (AI.isIgnore()) return Slot.asRValue(); diff --git a/clang/lib/CodeGen/Targets/ARM.cpp b/clang/lib/CodeGen/Targets/ARM.cpp index 49ac1a76e767aa0602e1b8eb61a6c94451223a41..2d858fa2f3c3a35113245cb8e5cffe4ea2494d33 100644 --- a/clang/lib/CodeGen/Targets/ARM.cpp +++ b/clang/lib/CodeGen/Targets/ARM.cpp @@ -420,12 +420,6 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic, /*Realign=*/TyAlign > ABIAlign); } - // On RenderScript, coerce Aggregates <= 64 bytes to an integer array of - // same size and alignment. - if (getTarget().isRenderScriptTarget()) { - return coerceToIntArray(Ty, getContext(), getVMContext()); - } - // Otherwise, pass by coercing to a structure of the appropriate size. llvm::Type* ElemTy; unsigned SizeRegs; @@ -609,11 +603,6 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, bool isVariadic, // are returned indirectly. uint64_t Size = getContext().getTypeSize(RetTy); if (Size <= 32) { - // On RenderScript, coerce Aggregates <= 4 bytes to an integer array of - // same size and alignment. - if (getTarget().isRenderScriptTarget()) { - return coerceToIntArray(RetTy, getContext(), getVMContext()); - } if (getDataLayout().isBigEndian()) // Return in 32 bit integer integer type (as if loaded by LDR, AAPCS 5.4) return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 81e2b2991e9c0bb6c79ed094642c595d66306ef8..1cd8e3cb5ee434875b9601a7cdd1705b4d485b1b 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -608,6 +608,11 @@ public: const auto *FD = dyn_cast_or_null(D); if (!FD) return; + auto *Fn = cast(GV); + + if (CGM.getCodeGenOpts().CFProtectionReturn) + Fn->addFnAttr("hw-shadow-stack"); + const auto *Attr = FD->getAttr(); if (!Attr) return; @@ -618,8 +623,6 @@ public: case RISCVInterruptAttr::machine: Kind = "machine"; break; } - auto *Fn = cast(GV); - Fn->addFnAttr("interrupt", Kind); } }; diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 3e7078f366abb8238ac4cecbeafab399b3598a21..b76c36d0e53b027384fbad15eec4e4c3eb4ed3a6 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -903,7 +903,9 @@ bool ToolChain::needsProfileRT(const ArgList &Args) { Args.hasArg(options::OPT_fprofile_instr_generate) || Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || Args.hasArg(options::OPT_fcreate_profile) || - Args.hasArg(options::OPT_forder_file_instrumentation); + Args.hasArg(options::OPT_forder_file_instrumentation) || + Args.hasArg(options::OPT_fprofile_generate_cold_function_coverage) || + Args.hasArg(options::OPT_fprofile_generate_cold_function_coverage_EQ); } bool ToolChain::needsGCovInstrumentation(const llvm::opt::ArgList &Args) { diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index 2c85d21ebd738c7ffd3535bf1a0d880a9425ce1e..a8061ffd9321f5803a586c533a6d02712bbe467c 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -648,6 +648,17 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString("-plugin-opt=-mattr=" + llvm::join(Features, ","))); } + if (Args.hasArg(options::OPT_stdlib)) + CmdArgs.append({"-lc", "-lm"}); + if (Args.hasArg(options::OPT_startfiles)) { + std::optional IncludePath = getToolChain().getStdlibPath(); + if (!IncludePath) + IncludePath = "/lib"; + SmallString<128> P(*IncludePath); + llvm::sys::path::append(P, "crt1.o"); + CmdArgs.push_back(Args.MakeArgString(P)); + } + CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); C.addCommand(std::make_unique( diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index f083e40df13144965b163cfb5f002df409bea118..1e2ac4e501bafd1a09e5813ea7ba29036df8005c 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -135,15 +135,21 @@ getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, return true; } -static bool -getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, - const ArgList &Args, - llvm::AArch64::ExtensionSet &Extensions) { +static bool getAArch64ArchFeaturesFromMcpu( + const Driver &D, StringRef Mcpu, const ArgList &Args, + llvm::AArch64::ExtensionSet &Extensions, std::vector &Features) { StringRef CPU; std::string McpuLowerCase = Mcpu.lower(); if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Extensions)) return false; + if (Mcpu == "native") { + llvm::StringMap HostFeatures = llvm::sys::getHostCPUFeatures(); + for (auto &[Feature, Enabled] : HostFeatures) { + Features.push_back(Args.MakeArgString((Enabled ? "+" : "-") + Feature)); + } + } + return true; } @@ -210,11 +216,11 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Extensions); else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) - success = - getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Extensions); + success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Extensions, + Features); else if (isCPUDeterminedByTriple(Triple)) success = getAArch64ArchFeaturesFromMcpu( - D, getAArch64TargetCPU(Args, Triple, A), Args, Extensions); + D, getAArch64TargetCPU(Args, Triple, A), Args, Extensions, Features); else // Default to 'A' profile if the architecture is not specified. success = getAArch64ArchFeaturesFromMarch(D, "armv8-a", Args, Extensions); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 6fc1387f6fe3c9be5f364f06dd9036d17b27dea0..f26a8e467f800741e1c10f76d7eba25e627b274e 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -632,6 +632,26 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, } } + if (auto *ColdFuncCoverageArg = Args.getLastArg( + options::OPT_fprofile_generate_cold_function_coverage, + options::OPT_fprofile_generate_cold_function_coverage_EQ)) { + SmallString<128> Path( + ColdFuncCoverageArg->getOption().matches( + options::OPT_fprofile_generate_cold_function_coverage_EQ) + ? ColdFuncCoverageArg->getValue() + : ""); + llvm::sys::path::append(Path, "default_%m.profraw"); + // FIXME: Idealy the file path should be passed through + // `-fprofile-instrument-path=`(InstrProfileOutput), however, this field is + // shared with other profile use path(see PGOOptions), we need to refactor + // PGOOptions to make it work. + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString( + Twine("--instrument-cold-function-only-path=") + Path)); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("--pgo-function-entry-coverage"); + } + Arg *PGOGenArg = nullptr; if (PGOGenerateArg) { assert(!CSPGOGenerateArg); @@ -2866,7 +2886,7 @@ static std::string ComplexArithmeticStr(LangOptions::ComplexRangeKind Range) { static void EmitComplexRangeDiag(const Driver &D, std::string str1, std::string str2) { - if ((str1.compare(str2) != 0) && !str2.empty() && !str1.empty()) { + if (str1 != str2 && !str2.empty() && !str1.empty()) { D.Diag(clang::diag::warn_drv_overriding_option) << str1 << str2; } } @@ -3024,8 +3044,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, EmitComplexRangeDiag(D, RenderComplexRangeOption(Range), "-fno-cx-limited-range"); } else { - if (GccRangeComplexOption.compare("-fcx-limited-range") != 0 && - GccRangeComplexOption.compare("-fno-cx-fortran-rules") != 0) + if (GccRangeComplexOption != "-fcx-limited-range" && + GccRangeComplexOption != "-fno-cx-fortran-rules") EmitComplexRangeDiag(D, GccRangeComplexOption, "-fno-cx-limited-range"); } @@ -3070,8 +3090,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, break; } if (!GccRangeComplexOption.empty()) { - if (GccRangeComplexOption.compare("-fcx-limited-range") != 0) { - if (GccRangeComplexOption.compare("-fcx-fortran-rules") != 0) { + if (GccRangeComplexOption != "-fcx-limited-range") { + if (GccRangeComplexOption != "-fcx-fortran-rules") { if (RangeVal != LangOptions::ComplexRangeKind::CX_Improved) EmitComplexRangeDiag(D, GccRangeComplexOption, ComplexArithmeticStr(RangeVal)); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 17ec3b27b992fe5c2247c7e81fce95b949059db2..5f9a2a05f660ae4d023ed2f6a6adcce964648236 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1626,10 +1626,14 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, } bool tools::addXRayRuntime(const ToolChain&TC, const ArgList &Args, ArgStringList &CmdArgs) { - if (Args.hasArg(options::OPT_shared)) - return false; - - if (TC.getXRayArgs().needsXRayRt()) { + if (Args.hasArg(options::OPT_shared)) { + if (TC.getXRayArgs().needsXRayDSORt()) { + CmdArgs.push_back("--whole-archive"); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray-dso")); + CmdArgs.push_back("--no-whole-archive"); + return true; + } + } else if (TC.getXRayArgs().needsXRayRt()) { CmdArgs.push_back("--whole-archive"); CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray")); for (const auto &Mode : TC.getXRayArgs().modeList()) diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 412b379304b1e6fbfb212d29407946d833d19688..ddd5ea248ca0ccab93484e804b551f309f9d9b7f 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -643,6 +643,17 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME); CmdArgs.push_back(Args.MakeArgString(Twine("-L") + DefaultLibPath)); + if (Args.hasArg(options::OPT_stdlib)) + CmdArgs.append({"-lc", "-lm"}); + if (Args.hasArg(options::OPT_startfiles)) { + std::optional IncludePath = getToolChain().getStdlibPath(); + if (!IncludePath) + IncludePath = "/lib"; + SmallString<128> P(*IncludePath); + llvm::sys::path::append(P, "crt1.o"); + CmdArgs.push_back(Args.MakeArgString(P)); + } + C.addCommand(std::make_unique( JA, *this, ResponseFileSupport{ResponseFileSupport::RF_Full, llvm::sys::WEM_UTF8, diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp index a50333223ff5c41cba4ec7dc7edd34979802a6ed..9daafbe703f68eb46649cd22568d5286f31ce332 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.cpp +++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -250,6 +250,20 @@ void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-pie"); if (!Relocatable) { + CmdArgs.push_back("--eh-frame-hdr"); + CmdArgs.push_back("--hash-style=sysv"); + + // Add a build-id by default to allow the PlayStation symbol server to + // index the symbols. `uuid` is the cheapest fool-proof method. + // (The non-determinism and alternative methods are noted in the downstream + // PlayStation docs). + CmdArgs.push_back("--build-id=uuid"); + + // All references are expected to be resolved at static link time for both + // executables and dynamic libraries. This has been the default linking + // behaviour for numerous PlayStation generations. + CmdArgs.push_back("--unresolved-symbols=report-all"); + // Lazy binding of PLTs is not supported on PlayStation. They are placed in // the RelRo segment. CmdArgs.push_back("-z"); @@ -416,8 +430,7 @@ toolchains::PS4PS5Base::PS4PS5Base(const Driver &D, const llvm::Triple &Triple, } void toolchains::PS4PS5Base::AddClangSystemIncludeArgs( - const ArgList &DriverArgs, - ArgStringList &CC1Args) const { + const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Driver &D = getDriver(); if (DriverArgs.hasArg(options::OPT_nostdinc)) diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp index 3de45b00b4d00fd102cedad20c921128ae806477..b14aac0f0ce015eb66c32f28b3cb149cef5e6400 100644 --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -201,7 +201,6 @@ bool types::isDerivedFromC(ID Id) { case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias: case TY_ObjCXX: - case TY_RenderScript: case TY_PP_CHeader: case TY_CHeader: case TY_CLHeader: @@ -328,7 +327,6 @@ types::ID types::lookupTypeForExtension(llvm::StringRef Ext) { .Case("ll", TY_LLVM_IR) .Case("mi", TY_PP_ObjC) .Case("mm", TY_ObjCXX) - .Case("rs", TY_RenderScript) .Case("adb", TY_Ada) .Case("ads", TY_Ada) .Case("asm", TY_PP_Asm) diff --git a/clang/lib/Driver/XRayArgs.cpp b/clang/lib/Driver/XRayArgs.cpp index 8c5134e2501358c268c8886d7d645f9cda6fcbc2..d0bb5d4887c184775affa3b3160c1836f1b3fb2b 100644 --- a/clang/lib/Driver/XRayArgs.cpp +++ b/clang/lib/Driver/XRayArgs.cpp @@ -63,6 +63,23 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { << XRayInstrument->getSpelling() << Triple.str(); } + if (Args.hasFlag(options::OPT_fxray_shared, options::OPT_fno_xray_shared, + false)) { + XRayShared = true; + + // DSO instrumentation is currently limited to x86_64 + if (Triple.getArch() != llvm::Triple::x86_64) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << "-fxray-shared" << Triple.str(); + } + + unsigned PICLvl = std::get<1>(tools::ParsePICArgs(TC, Args)); + if (!PICLvl) { + D.Diag(diag::err_opt_not_valid_without_opt) << "-fxray-shared" + << "-fPIC"; + } + } + // Both XRay and -fpatchable-function-entry use // TargetOpcode::PATCHABLE_FUNCTION_ENTER. if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) @@ -177,6 +194,10 @@ void XRayArgs::addArgs(const ToolChain &TC, const ArgList &Args, Args.addOptOutFlag(CmdArgs, options::OPT_fxray_function_index, options::OPT_fno_xray_function_index); + if (XRayShared) + Args.addOptInFlag(CmdArgs, options::OPT_fxray_shared, + options::OPT_fno_xray_shared); + if (const Arg *A = Args.getLastArg(options::OPT_fxray_instruction_threshold_EQ)) { int Value; diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp index 030509d37875950d22d5aa36aa5f243e345e2599..c730c062b6a1d566320b120e24090707c6cea7ea 100644 --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -213,7 +213,6 @@ StringRef getLanguageName(Language Lang) { case Language::OpenCL: case Language::OpenCLCXX: case Language::CUDA: - case Language::RenderScript: case Language::HIP: case Language::HLSL: diff --git a/clang/lib/Format/CMakeLists.txt b/clang/lib/Format/CMakeLists.txt index b787b11ac7b744c4cff98aa46f27db6fd65dc118..ff987cc608fb882b4cc7fd5b2436a76fd6078879 100644 --- a/clang/lib/Format/CMakeLists.txt +++ b/clang/lib/Format/CMakeLists.txt @@ -33,10 +33,10 @@ add_clang_library(clangFormat file(GLOB_RECURSE files *.cpp *.h - ../../include/clang/Format/*.h - ../../tools/clang-format/*.cpp - ../../unittests/Format/*.cpp - ../../unittests/Format/*.h + ${CLANG_SOURCE_DIR}/include/clang/Format/*.h + ${CLANG_SOURCE_DIR}/tools/clang-format/*.cpp + ${CLANG_SOURCE_DIR}/unittests/Format/*.cpp + ${CLANG_SOURCE_DIR}/unittests/Format/*.h ) set(check_format_depends) @@ -46,8 +46,8 @@ foreach (file IN LISTS files) COMMAND clang-format ${file} | diff -u ${file} - VERBATIM COMMENT "Checking format of ${file}..." - ) - list(APPEND check_format_depends "clang-format-check-format${i}") + ) + list(APPEND check_format_depends clang-format-check-format${i}) math(EXPR i ${i}+1) endforeach () diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index f85fe440f50a610da4e8df82896676d4682d7ca3..0cf4cdbeab31f34a1e0ea74fc5e9dce9f1114a91 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1052,6 +1052,7 @@ template <> struct MappingTraits { IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes); IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports); IO.mapOptional("KeepEmptyLines", Style.KeepEmptyLines); + IO.mapOptional("KeepFormFeed", Style.KeepFormFeed); IO.mapOptional("LambdaBodyIndentation", Style.LambdaBodyIndentation); IO.mapOptional("LineEnding", Style.LineEnding); IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin); @@ -1567,6 +1568,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { /*AtStartOfBlock=*/true, /*AtStartOfFile=*/true, }; + LLVMStyle.KeepFormFeed = false; LLVMStyle.LambdaBodyIndentation = FormatStyle::LBI_Signature; LLVMStyle.Language = Language; LLVMStyle.LineEnding = FormatStyle::LE_DeriveLF; @@ -1927,6 +1929,7 @@ FormatStyle getGNUStyle() { Style.ColumnLimit = 79; Style.Cpp11BracedListStyle = false; Style.FixNamespaceComments = false; + Style.KeepFormFeed = true; Style.SpaceBeforeParens = FormatStyle::SBPO_Always; return Style; } diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 7d342a7dcca01df7aa1dacf5c88ad7be561bf2e5..f6bb860a1fea31e5fe12ac6a30083d2aca579269 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -586,6 +586,9 @@ public: /// Might be function declaration open/closing paren. bool MightBeFunctionDeclParen = false; + /// Has "\n\f\n" or "\n\f\r\n" before TokenText. + bool HasFormFeedBefore = false; + /// Number of optional braces to be inserted after this token: /// -1: a single left brace /// 0: no braces diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 2cdf6cd286b280180d670a2ba107c8ae912f9f4d..7a264bddcdfe19dba1a1ced23de35134f4dd81a1 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -1186,6 +1186,14 @@ FormatToken *FormatTokenLexer::getNextToken() { Column = 0; break; case '\f': + if (Style.KeepFormFeed && !FormatTok->HasFormFeedBefore && + // The form feed is immediately preceded and followed by a newline. + i > 0 && Text[i - 1] == '\n' && + ((i + 1 < e && Text[i + 1] == '\n') || + (i + 2 < e && Text[i + 1] == '\r' && Text[i + 2] == '\n'))) { + FormatTok->HasFormFeedBefore = true; + } + [[fallthrough]]; case '\v': Column = 0; break; diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index b6b24672f6a39de01df18be3d988ad1c289efff9..b1e43f0313dbfe2e30b9adb0e69e501398a2f105 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -1674,7 +1674,7 @@ void WhitespaceManager::generateChanges() { C.PreviousEndOfTokenColumn, C.EscapedNewlineColumn); } else { - appendNewlineText(ReplacementText, C.NewlinesBefore); + appendNewlineText(ReplacementText, C); } // FIXME: This assert should hold if we computed the column correctly. // assert((int)C.StartOfTokenColumn >= C.Spaces); @@ -1706,15 +1706,18 @@ void WhitespaceManager::storeReplacement(SourceRange Range, StringRef Text) { } } -void WhitespaceManager::appendNewlineText(std::string &Text, - unsigned Newlines) { - if (UseCRLF) { - Text.reserve(Text.size() + 2 * Newlines); - for (unsigned i = 0; i < Newlines; ++i) - Text.append("\r\n"); - } else { - Text.append(Newlines, '\n'); - } +void WhitespaceManager::appendNewlineText(std::string &Text, const Change &C) { + if (C.NewlinesBefore <= 0) + return; + + StringRef Newline = UseCRLF ? "\r\n" : "\n"; + Text.append(Newline); + + if (C.Tok->HasFormFeedBefore) + Text.append("\f"); + + for (unsigned I = 1; I < C.NewlinesBefore; ++I) + Text.append(Newline); } void WhitespaceManager::appendEscapedNewlineText( diff --git a/clang/lib/Format/WhitespaceManager.h b/clang/lib/Format/WhitespaceManager.h index 7b91d8bf4db72b40fca30f9411fe829440a33411..5dd667fb4ba3bf6014f58f1850d36a4ee37e952c 100644 --- a/clang/lib/Format/WhitespaceManager.h +++ b/clang/lib/Format/WhitespaceManager.h @@ -349,7 +349,7 @@ private: /// Stores \p Text as the replacement for the whitespace in \p Range. void storeReplacement(SourceRange Range, StringRef Text); - void appendNewlineText(std::string &Text, unsigned Newlines); + void appendNewlineText(std::string &Text, const Change &C); void appendEscapedNewlineText(std::string &Text, unsigned Newlines, unsigned PreviousEndOfTokenColumn, unsigned EscapedNewlineColumn); diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index bffff0d27af3ab66139165a11747a89dd647eccc..4aec928f9eb0a5bb8ea697bc27586cdd5fcf3ae1 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -2699,8 +2699,6 @@ InputKind ASTUnit::getInputKind() const { Lang = Language::OpenCL; else if (LangOpts.CUDA) Lang = Language::CUDA; - else if (LangOpts.RenderScript) - Lang = Language::RenderScript; else if (LangOpts.CPlusPlus) Lang = LangOpts.ObjC ? Language::ObjCXX : Language::CXX; else diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index fda21746db1881d72b4825cfe83dc411e2f93db9..0299ef5ce000226df5b43245494c48f72a197aa3 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2846,9 +2846,6 @@ static void GenerateFrontendArgs(const FrontendOptions &Opts, case Language::ObjCXX: Lang = "objective-c++"; break; - case Language::RenderScript: - Lang = "renderscript"; - break; case Language::Asm: Lang = "assembler-with-cpp"; break; @@ -3071,7 +3068,6 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, .Case("c++", Language::CXX) .Case("objective-c", Language::ObjC) .Case("objective-c++", Language::ObjCXX) - .Case("renderscript", Language::RenderScript) .Case("hlsl", Language::HLSL) .Default(Language::Unknown); @@ -3499,7 +3495,6 @@ static bool IsInputCompatibleWithStandard(InputKind IK, case Language::C: case Language::ObjC: - case Language::RenderScript: return S.getLanguage() == Language::C; case Language::OpenCL: @@ -3551,8 +3546,6 @@ static StringRef GetInputKindName(InputKind IK) { return "C++ for OpenCL"; case Language::CUDA: return "CUDA"; - case Language::RenderScript: - return "RenderScript"; case Language::HIP: return "HIP"; diff --git a/clang/lib/Frontend/DiagnosticRenderer.cpp b/clang/lib/Frontend/DiagnosticRenderer.cpp index 017ce1c17d5c9a0808d4b7b9d3f5ecd042bf4f16..8b32af1337257935e243cd8fcb33b2ee451328fa 100644 --- a/clang/lib/Frontend/DiagnosticRenderer.cpp +++ b/clang/lib/Frontend/DiagnosticRenderer.cpp @@ -146,7 +146,7 @@ void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) { void DiagnosticRenderer::emitBasicNote(StringRef Message) { emitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagnosticsEngine::Note, - Message, std::nullopt, DiagOrStoredDiag()); + Message, {}, DiagOrStoredDiag()); } /// Prints an include stack when appropriate for a particular @@ -451,7 +451,7 @@ void DiagnosticRenderer::emitSingleMacroExpansion( Message << "expanded from macro '" << MacroName << "'"; emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(), - SpellingRanges, std::nullopt); + SpellingRanges, {}); } /// Check that the macro argument location of Loc starts with ArgumentLoc. diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 81eea9c4c4dc58e285bf4f3b05a76ef0b6540c6e..9a50e7453eb61a5247b8198960a75955a6c8c397 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -358,7 +358,7 @@ static std::error_code collectModuleHeaderIncludes( // Add includes for each of these headers. for (auto HK : {Module::HK_Normal, Module::HK_Private}) { - for (Module::Header &H : Module->Headers[HK]) { + for (const Module::Header &H : Module->getHeaders(HK)) { Module->addTopHeader(H.Entry); // Use the path as specified in the module map file. We'll look for this // file relative to the module build directory (the directory containing @@ -534,7 +534,6 @@ static Module *prepareToBuildModule(CompilerInstance &CI, } if (*OriginalModuleMap != CI.getSourceManager().getFileEntryRefForID( CI.getSourceManager().getMainFileID())) { - M->IsInferred = true; auto FileCharacter = M->IsSystem ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap; FileID OriginalModuleMapFID = CI.getSourceManager().getOrCreateFileID( diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 64f90c493c1055ddef06d4924c2d02cabee2ad3d..e943f143d4c15886d802e0a4d4d9897edf7a62bb 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -1108,7 +1108,6 @@ void PrintPreambleAction::ExecuteAction() { case Language::Unknown: case Language::Asm: case Language::LLVM_IR: - case Language::RenderScript: // We can't do anything with these. return; } diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp index 383d43560849164df16036082bc14cb36290e535..1005825441b3e66312bc53de0a9d181240663f65 100644 --- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -952,13 +952,15 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, continue; } else if (Tok.is(tok::annot_header_unit)) { // This is a header-name that has been (effectively) converted into a - // module-name. + // module-name, print them inside quote. // FIXME: The module name could contain non-identifier module name - // components. We don't have a good way to round-trip those. + // components and OS specific file paths components. We don't have a good + // way to round-trip those. Module *M = reinterpret_cast(Tok.getAnnotationValue()); std::string Name = M->getFullModuleName(); - Callbacks->OS->write(Name.data(), Name.size()); - Callbacks->HandleNewlinesInToken(Name.data(), Name.size()); + *Callbacks->OS << '"'; + Callbacks->OS->write_escaped(Name); + *Callbacks->OS << '"'; } else if (Tok.is(tok::annot_embed)) { // Manually explode the binary data out to a stream of comma-delimited // integer values. If the user passed -dE, that is handled by the diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt index 876731c1f62045575ad9cbb0a2fb28c94ae265d8..ee3ed71d139f20636842491cf30657e67a68ba48 100644 --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -221,6 +221,8 @@ set(x86_files mm3dnow.h mmintrin.h movdirintrin.h + movrs_avx10_2_512intrin.h + movrs_avx10_2intrin.h mwaitxintrin.h nmmintrin.h pconfigintrin.h @@ -241,6 +243,7 @@ set(x86_files shaintrin.h sm3intrin.h sm4intrin.h + sm4evexintrin.h smmintrin.h tbmintrin.h tmmintrin.h diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 30dce60b3ff7029d5c6c787150a535566e1405e1..8ade4b27f360fbcec54cd192d6f4d1e970d0e45b 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -438,6 +438,24 @@ template constexpr uint asuint(T F) { return __detail::bit_cast(F); } +//===----------------------------------------------------------------------===// +// asuint splitdouble builtins +//===----------------------------------------------------------------------===// + +/// \fn void asuint(double D, out uint lowbits, out int highbits) +/// \brief Split and interprets the lowbits and highbits of double D into uints. +/// \param D The input double. +/// \param lowbits The output lowbits of D. +/// \param highbits The output highbits of D. +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_splitdouble) +void asuint(double, out uint, out uint); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_splitdouble) +void asuint(double2, out uint2, out uint2); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_splitdouble) +void asuint(double3, out uint3, out uint3); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_splitdouble) +void asuint(double4, out uint4, out uint4); + //===----------------------------------------------------------------------===// // atan builtins //===----------------------------------------------------------------------===// diff --git a/clang/lib/Headers/immintrin.h b/clang/lib/Headers/immintrin.h index 3fbabffa98df2093dc46269b768df793620b868f..65ad72bc479f49a2f83cbecc6ad3eccd28f3b7c9 100644 --- a/clang/lib/Headers/immintrin.h +++ b/clang/lib/Headers/immintrin.h @@ -605,6 +605,16 @@ _storebe_i64(void * __P, long long __D) { #include #endif +#if !defined(__SCE__) || __has_feature(modules) || \ + (defined(__AVX10_2__) && defined(__MOVRS__)) +#include +#endif + +#if !defined(__SCE__) || __has_feature(modules) || \ + (defined(__AVX10_2_512__) && defined(__MOVRS__)) +#include +#endif + #if !defined(__SCE__) || __has_feature(modules) || defined(__PCONFIG__) #include #endif @@ -667,6 +677,11 @@ _storebe_i64(void * __P, long long __D) { #include #endif +#if !defined(__SCE__) || __has_feature(modules) || \ + (defined(__AVX10_2_512__) && defined(__SM4__)) +#include +#endif + #if !defined(__SCE__) || __has_feature(modules) || defined(__ENQCMD__) #include #endif diff --git a/clang/lib/Headers/movrs_avx10_2_512intrin.h b/clang/lib/Headers/movrs_avx10_2_512intrin.h new file mode 100644 index 0000000000000000000000000000000000000000..5cd907a5973494f355b49f4f9b817070db193877 --- /dev/null +++ b/clang/lib/Headers/movrs_avx10_2_512intrin.h @@ -0,0 +1,98 @@ +/*===----- movrs_avx10_2_512intrin.h - AVX10.2-512-MOVRS intrinsics --------=== + * + * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. + * See https://llvm.org/LICENSE.txt for license information. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + *===-----------------------------------------------------------------------=== + */ +#ifndef __IMMINTRIN_H +#error \ + "Never use directly; include instead." +#endif + +#ifndef __MOVRS_AVX10_2_512INTRIN_H +#define __MOVRS_AVX10_2_512INTRIN_H +#ifdef __x86_64__ + +/* Define the default attributes for the functions in this file. */ +#define __DEFAULT_FN_ATTRS512 \ + __attribute__((__always_inline__, __nodebug__, \ + __target__("movrs, avx10.2-512"), __min_vector_width__(512))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_loadrs_epi8(void const *__A) { + return (__m512i)__builtin_ia32_vmovrsb512((const __v64qi *)(__A)); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_loadrs_epi8(__m512i __W, __mmask64 __U, void const *__A) { + return (__m512i)__builtin_ia32_selectb_512( + (__mmask64)__U, (__v64qi)_mm512_loadrs_epi8(__A), (__v64qi)__W); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_loadrs_epi8(__mmask64 __U, void const *__A) { + return (__m512i)__builtin_ia32_selectb_512((__mmask64)__U, + (__v64qi)_mm512_loadrs_epi8(__A), + (__v64qi)_mm512_setzero_si512()); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_loadrs_epi32(void const *__A) { + return (__m512i)__builtin_ia32_vmovrsd512((const __v16si *)(__A)); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_loadrs_epi32(__m512i __W, __mmask16 __U, void const *__A) { + return (__m512i)__builtin_ia32_selectd_512( + (__mmask16)__U, (__v16si)_mm512_loadrs_epi32(__A), (__v16si)__W); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_loadrs_epi32(__mmask16 __U, void const *__A) { + return (__m512i)__builtin_ia32_selectd_512((__mmask16)__U, + (__v16si)_mm512_loadrs_epi32(__A), + (__v16si)_mm512_setzero_si512()); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_loadrs_epi64(void const *__A) { + return (__m512i)__builtin_ia32_vmovrsq512((const __v8di *)(__A)); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_loadrs_epi64(__m512i __W, __mmask8 __U, void const *__A) { + return (__m512i)__builtin_ia32_selectq_512( + (__mmask8)__U, (__v8di)_mm512_loadrs_epi64(__A), (__v8di)__W); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_loadrs_epi64(__mmask8 __U, void const *__A) { + return (__m512i)__builtin_ia32_selectq_512((__mmask8)__U, + (__v8di)_mm512_loadrs_epi64(__A), + (__v8di)_mm512_setzero_si512()); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_loadrs_epi16(void const *__A) { + return (__m512i)__builtin_ia32_vmovrsw512((const __v32hi *)(__A)); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_loadrs_epi16(__m512i __W, __mmask32 __U, void const *__A) { + return (__m512i)__builtin_ia32_selectw_512( + (__mmask32)__U, (__v32hi)_mm512_loadrs_epi16(__A), (__v32hi)__W); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_loadrs_epi16(__mmask32 __U, void const *__A) { + return (__m512i)__builtin_ia32_selectw_512((__mmask32)__U, + (__v32hi)_mm512_loadrs_epi16(__A), + (__v32hi)_mm512_setzero_si512()); +} + +#undef __DEFAULT_FN_ATTRS512 + +#endif /* __x86_64__ */ +#endif /* __MOVRS_AVX10_2_512INTRIN_H */ diff --git a/clang/lib/Headers/movrs_avx10_2intrin.h b/clang/lib/Headers/movrs_avx10_2intrin.h new file mode 100644 index 0000000000000000000000000000000000000000..27b625b6b43139d04f18362c0fcb7254a232e215 --- /dev/null +++ b/clang/lib/Headers/movrs_avx10_2intrin.h @@ -0,0 +1,174 @@ +/*===--------- movrs_avx10_2intrin.h - AVX10.2-MOVRS intrinsics ------------=== + * + * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. + * See https://llvm.org/LICENSE.txt for license information. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + *===-----------------------------------------------------------------------=== + */ +#ifndef __IMMINTRIN_H +#error \ + "Never use directly; include instead." +#endif + +#ifndef __MOVRS_AVX10_2INTRIN_H +#define __MOVRS_AVX10_2INTRIN_H +#ifdef __x86_64__ + +/* Define the default attributes for the functions in this file. */ +#define __DEFAULT_FN_ATTRS128 \ + __attribute__((__always_inline__, __nodebug__, \ + __target__("movrs,avx10.2-256"), __min_vector_width__(128))) +#define __DEFAULT_FN_ATTRS256 \ + __attribute__((__always_inline__, __nodebug__, \ + __target__("movrs,avx10.2-256"), __min_vector_width__(256))) + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_loadrs_epi8(void const *__A) { + return (__m128i)__builtin_ia32_vmovrsb128((const __v16qi *)(__A)); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_loadrs_epi8(__m128i __W, __mmask16 __U, void const *__A) { + return (__m128i)__builtin_ia32_selectb_128( + (__mmask16)__U, (__v16qi)_mm_loadrs_epi8(__A), (__v16qi)__W); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_loadrs_epi8(__mmask16 __U, void const *__A) { + return (__m128i)__builtin_ia32_selectb_128((__mmask16)__U, + (__v16qi)_mm_loadrs_epi8(__A), + (__v16qi)_mm_setzero_si128()); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_loadrs_epi8(void const *__A) { + return (__m256i)__builtin_ia32_vmovrsb256((const __v32qi *)(__A)); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_loadrs_epi8(__m256i __W, __mmask32 __U, void const *__A) { + return (__m256i)__builtin_ia32_selectb_256( + (__mmask32)__U, (__v32qi)_mm256_loadrs_epi8(__A), (__v32qi)__W); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_loadrs_epi8(__mmask32 __U, void const *__A) { + return (__m256i)__builtin_ia32_selectb_256((__mmask32)__U, + (__v32qi)_mm256_loadrs_epi8(__A), + (__v32qi)_mm256_setzero_si256()); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_loadrs_epi32(void const *__A) { + return (__m128i)__builtin_ia32_vmovrsd128((const __v4si *)(__A)); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_loadrs_epi32(__m128i __W, __mmask8 __U, void const *__A) { + return (__m128i)__builtin_ia32_selectd_128( + (__mmask8)__U, (__v4si)_mm_loadrs_epi32(__A), (__v4si)__W); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_loadrs_epi32(__mmask8 __U, void const *__A) { + return (__m128i)__builtin_ia32_selectd_128((__mmask8)__U, + (__v4si)_mm_loadrs_epi32(__A), + (__v4si)_mm_setzero_si128()); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_loadrs_epi32(void const *__A) { + return (__m256i)__builtin_ia32_vmovrsd256((const __v8si *)(__A)); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_loadrs_epi32(__m256i __W, __mmask8 __U, void const *__A) { + return (__m256i)__builtin_ia32_selectd_256( + (__mmask8)__U, (__v8si)_mm256_loadrs_epi32(__A), (__v8si)__W); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_loadrs_epi32(__mmask8 __U, void const *__A) { + return (__m256i)__builtin_ia32_selectd_256((__mmask8)__U, + (__v8si)_mm256_loadrs_epi32(__A), + (__v8si)_mm256_setzero_si256()); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_loadrs_epi64(void const *__A) { + return (__m128i)__builtin_ia32_vmovrsq128((const __v2di *)(__A)); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_loadrs_epi64(__m128i __W, __mmask8 __U, void const *__A) { + return (__m128i)__builtin_ia32_selectq_128( + (__mmask8)__U, (__v2di)_mm_loadrs_epi64(__A), (__v2di)__W); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_loadrs_epi64(__mmask8 __U, void const *__A) { + return (__m128i)__builtin_ia32_selectq_128((__mmask8)__U, + (__v2di)_mm_loadrs_epi64(__A), + (__v2di)_mm_setzero_si128()); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_loadrs_epi64(void const *__A) { + return (__m256i)__builtin_ia32_vmovrsq256((const __v4di *)(__A)); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_loadrs_epi64(__m256i __W, __mmask8 __U, void const *__A) { + return (__m256i)__builtin_ia32_selectq_256( + (__mmask8)__U, (__v4di)_mm256_loadrs_epi64(__A), (__v4di)__W); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_loadrs_epi64(__mmask8 __U, void const *__A) { + return (__m256i)__builtin_ia32_selectq_256((__mmask8)__U, + (__v4di)_mm256_loadrs_epi64(__A), + (__v4di)_mm256_setzero_si256()); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_loadrs_epi16(void const *__A) { + return (__m128i)__builtin_ia32_vmovrsw128((const __v8hi *)(__A)); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_loadrs_epi16(__m128i __W, __mmask8 __U, void const *__A) { + return (__m128i)__builtin_ia32_selectw_128( + (__mmask8)__U, (__v8hi)_mm_loadrs_epi16(__A), (__v8hi)__W); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_loadrs_epi16(__mmask8 __U, void const *__A) { + return (__m128i)__builtin_ia32_selectw_128((__mmask8)__U, + (__v8hi)_mm_loadrs_epi16(__A), + (__v8hi)_mm_setzero_si128()); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_loadrs_epi16(void const *__A) { + return (__m256i)__builtin_ia32_vmovrsw256((const __v16hi *)(__A)); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_loadrs_epi16(__m256i __W, __mmask16 __U, void const *__A) { + return (__m256i)__builtin_ia32_selectw_256( + (__mmask16)__U, (__v16hi)_mm256_loadrs_epi16(__A), (__v16hi)__W); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_loadrs_epi16(__mmask16 __U, void const *__A) { + return (__m256i)__builtin_ia32_selectw_256((__mmask16)__U, + (__v16hi)_mm256_loadrs_epi16(__A), + (__v16hi)_mm256_setzero_si256()); +} + +#undef __DEFAULT_FN_ATTRS128 +#undef __DEFAULT_FN_ATTRS256 + +#endif /* __x86_64__ */ +#endif /* __MOVRS_AVX10_2INTRIN_H */ diff --git a/clang/lib/Headers/sm4evexintrin.h b/clang/lib/Headers/sm4evexintrin.h new file mode 100644 index 0000000000000000000000000000000000000000..f6ae0037baea033ed94a0fa6ecf98c2a096c8944 --- /dev/null +++ b/clang/lib/Headers/sm4evexintrin.h @@ -0,0 +1,32 @@ +/*===--------------- sm4evexintrin.h - SM4 EVEX intrinsics -----------------=== + * + * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. + * See https://llvm.org/LICENSE.txt for license information. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + *===----------------------------------------------------------------------=== + */ +#ifndef __IMMINTRIN_H +#error "Never use directly; include instead." +#endif // __IMMINTRIN_H + +#ifndef __SM4EVEXINTRIN_H +#define __SM4EVEXINTRIN_H + +#define __DEFAULT_FN_ATTRS512 \ + __attribute__((__always_inline__, __nodebug__, \ + __target__("sm4,avx10.2-512"), __min_vector_width__(512))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_sm4key4_epi32(__m512i __A, __m512i __B) { + return (__m512i)__builtin_ia32_vsm4key4512((__v16su)__A, (__v16su)__B); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_sm4rnds4_epi32(__m512i __A, __m512i __B) { + return (__m512i)__builtin_ia32_vsm4rnds4512((__v16su)__A, (__v16su)__B); +} + +#undef __DEFAULT_FN_ATTRS512 + +#endif // __SM4EVEXINTRIN_H diff --git a/clang/lib/Index/IndexingContext.h b/clang/lib/Index/IndexingContext.h index 89363b529fe99a4f0f8428a1cffcbf8611175362..3020b33bea38575c78c0809979731ae2a5415489 100644 --- a/clang/lib/Index/IndexingContext.h +++ b/clang/lib/Index/IndexingContext.h @@ -68,17 +68,17 @@ public: static bool isTemplateImplicitInstantiation(const Decl *D); bool handleDecl(const Decl *D, SymbolRoleSet Roles = SymbolRoleSet(), - ArrayRef Relations = std::nullopt); + ArrayRef Relations = {}); bool handleDecl(const Decl *D, SourceLocation Loc, SymbolRoleSet Roles = SymbolRoleSet(), - ArrayRef Relations = std::nullopt, + ArrayRef Relations = {}, const DeclContext *DC = nullptr); bool handleReference(const NamedDecl *D, SourceLocation Loc, const NamedDecl *Parent, const DeclContext *DC, SymbolRoleSet Roles = SymbolRoleSet(), - ArrayRef Relations = std::nullopt, + ArrayRef Relations = {}, const Expr *RefE = nullptr); void handleMacroDefined(const IdentifierInfo &Name, SourceLocation Loc, @@ -94,8 +94,7 @@ public: bool indexDecl(const Decl *D); - void indexTagDecl(const TagDecl *D, - ArrayRef Relations = std::nullopt); + void indexTagDecl(const TagDecl *D, ArrayRef Relations = {}); void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent, const DeclContext *DC = nullptr, diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt index 2cc7c59b61d31828ef7c6263ca90b28bc874e8df..d5ffe78251d253865a2d4854eee9e65cfa13bc3c 100644 --- a/clang/lib/Interpreter/CMakeLists.txt +++ b/clang/lib/Interpreter/CMakeLists.txt @@ -14,6 +14,7 @@ set(LLVM_LINK_COMPONENTS if (EMSCRIPTEN AND "lld" IN_LIST LLVM_ENABLE_PROJECTS) set(WASM_SRC Wasm.cpp) + set(WASM_LINK lldWasm) endif() add_clang_library(clangInterpreter @@ -44,6 +45,7 @@ add_clang_library(clangInterpreter clangParse clangSema clangSerialization + ${WASM_LINK} ) if ((MINGW OR CYGWIN) AND BUILD_SHARED_LIBS) diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index 8826ab449df4930cf1b8deb0a57550adca73002e..052be1395161d4f05e3b740416a150250bcb7d3a 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -1582,7 +1582,6 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, } } - FileInfo.IsLocallyIncluded = true; IsFirstIncludeOfFile = PP.markIncluded(File); return true; } diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index fd6bc17ae9cdac4df5361cea73ec55b7682cfb89..dc9d2bfd5629c95351db7ddf93e9b0bd61640516 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -472,12 +472,12 @@ static bool violatesPrivateInclude(Module *RequestingModule, // as obtained from the lookup and as obtained from the module. // This check is not cheap, so enable it only for debugging. bool IsPrivate = false; - SmallVectorImpl *HeaderList[] = { - &Header.getModule()->Headers[Module::HK_Private], - &Header.getModule()->Headers[Module::HK_PrivateTextual]}; - for (auto *Hs : HeaderList) + ArrayRef HeaderList[] = { + Header.getModule()->getHeaders(Module::HK_Private), + Header.getModule()->getHeaders(Module::HK_PrivateTextual)}; + for (auto Hs : HeaderList) IsPrivate |= llvm::any_of( - *Hs, [&](const Module::Header &H) { return H.Entry == IncFileEnt; }); + Hs, [&](const Module::Header &H) { return H.Entry == IncFileEnt; }); assert(IsPrivate && "inconsistent headers and roles"); } #endif @@ -655,10 +655,9 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(FileEntryRef File) { SmallString<32> NameBuf; StringRef Name = sanitizeFilenameAsIdentifier( llvm::sys::path::stem(SkippedDir.getName()), NameBuf); - Result = findOrCreateModule(Name, Result, /*IsFramework=*/false, - Explicit).first; - InferredModuleAllowedBy[Result] = UmbrellaModuleMap; - Result->IsInferred = true; + Result = findOrCreateModuleFirst(Name, Result, /*IsFramework=*/false, + Explicit); + setInferredModuleAllowedBy(Result, UmbrellaModuleMap); // Associate the module and the directory. UmbrellaDirs[SkippedDir] = Result; @@ -673,10 +672,9 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(FileEntryRef File) { SmallString<32> NameBuf; StringRef Name = sanitizeFilenameAsIdentifier( llvm::sys::path::stem(File.getName()), NameBuf); - Result = findOrCreateModule(Name, Result, /*IsFramework=*/false, - Explicit).first; - InferredModuleAllowedBy[Result] = UmbrellaModuleMap; - Result->IsInferred = true; + Result = findOrCreateModuleFirst(Name, Result, /*IsFramework=*/false, + Explicit); + setInferredModuleAllowedBy(Result, UmbrellaModuleMap); Result->addTopHeader(File); // If inferred submodules export everything they import, add a @@ -707,7 +705,7 @@ ModuleMap::findAllModulesForHeader(FileEntryRef File) { if (findOrCreateModuleForHeaderInUmbrellaDir(File)) return Headers.find(File)->second; - return std::nullopt; + return {}; } ArrayRef @@ -716,7 +714,7 @@ ModuleMap::findResolvedModulesForHeader(FileEntryRef File) const { resolveHeaderDirectives(File); auto It = Headers.find(File); if (It == Headers.end()) - return std::nullopt; + return {}; return It->second; } @@ -868,6 +866,15 @@ std::pair ModuleMap::findOrCreateModule(StringRef Name, return std::make_pair(Sub, false); // Create a new module with this name. + Module *M = createModule(Name, Parent, IsFramework, IsExplicit); + return std::make_pair(M, true); +} + +Module *ModuleMap::createModule(StringRef Name, Module *Parent, + bool IsFramework, bool IsExplicit) { + assert(lookupModuleQualified(Name, Parent) == nullptr && + "Creating duplicate submodule"); + Module *Result = new (ModulesAlloc.Allocate()) Module(ModuleConstructorTag{}, Name, SourceLocation(), Parent, IsFramework, IsExplicit, NumCreatedModules++); @@ -877,7 +884,7 @@ std::pair ModuleMap::findOrCreateModule(StringRef Name, Modules[Name] = Result; ModuleScopeIDs[Result] = CurrentModuleScopeID; } - return std::make_pair(Result, true); + return Result; } Module *ModuleMap::createGlobalModuleFragmentForModuleUnit(SourceLocation Loc, @@ -1097,8 +1104,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, Module *Result = new (ModulesAlloc.Allocate()) Module(ModuleConstructorTag{}, ModuleName, SourceLocation(), Parent, /*IsFramework=*/true, /*IsExplicit=*/false, NumCreatedModules++); - InferredModuleAllowedBy[Result] = ModuleMapFID; - Result->IsInferred = true; + setInferredModuleAllowedBy(Result, ModuleMapFID); if (!Parent) { if (LangOpts.CurrentModule == ModuleName) SourceModule = Result; @@ -1296,27 +1302,28 @@ void ModuleMap::addHeader(Module *Mod, Module::Header Header, ModuleHeaderRole Role, bool Imported) { KnownHeader KH(Mod, Role); + FileEntryRef HeaderEntry = Header.Entry; + // Only add each header to the headers list once. // FIXME: Should we diagnose if a header is listed twice in the // same module definition? - auto &HeaderList = Headers[Header.Entry]; + auto &HeaderList = Headers[HeaderEntry]; if (llvm::is_contained(HeaderList, KH)) return; HeaderList.push_back(KH); - Mod->Headers[headerRoleToKind(Role)].push_back(Header); + Mod->addHeader(headerRoleToKind(Role), std::move(Header)); bool isCompilingModuleHeader = Mod->isForBuilding(LangOpts); if (!Imported || isCompilingModuleHeader) { // When we import HeaderFileInfo, the external source is expected to // set the isModuleHeader flag itself. - HeaderInfo.MarkFileModuleHeader(Header.Entry, Role, - isCompilingModuleHeader); + HeaderInfo.MarkFileModuleHeader(HeaderEntry, Role, isCompilingModuleHeader); } // Notify callbacks that we just added a new header. for (const auto &Cb : Callbacks) - Cb->moduleMapAddHeader(Header.Entry.getName()); + Cb->moduleMapAddHeader(HeaderEntry.getName()); } FileID ModuleMap::getContainingModuleMapFileID(const Module *Module) const { @@ -1345,7 +1352,7 @@ ModuleMap::getModuleMapFileForUniquing(const Module *M) const { } void ModuleMap::setInferredModuleAllowedBy(Module *M, FileID ModMapFID) { - assert(M->IsInferred && "module not inferred"); + M->IsInferred = true; InferredModuleAllowedBy[M] = ModMapFID; } @@ -2125,9 +2132,8 @@ void ModuleMapParser::parseModuleDecl() { ActiveModule = Map.createShadowedModule(ModuleName, Framework, ShadowingModule); } else { - ActiveModule = - Map.findOrCreateModule(ModuleName, ActiveModule, Framework, Explicit) - .first; + ActiveModule = Map.findOrCreateModuleFirst(ModuleName, ActiveModule, + Framework, Explicit); } ActiveModule->DefinitionLoc = ModuleNameLoc; diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index d48bb8a9a9cded0edc4fd2afdffe5eed64b53b82..3eef3dc9b0f344cfcdf86630e4df224b5f3869e1 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -286,8 +286,8 @@ void Preprocessor::dumpMacroInfo(const IdentifierInfo *II) { // Dump module macros. llvm::DenseSet Active; - for (auto *MM : - State ? State->getActiveModuleMacros(*this, II) : std::nullopt) + for (auto *MM : State ? State->getActiveModuleMacros(*this, II) + : ArrayRef()) Active.insert(MM); llvm::DenseSet Visited; llvm::SmallVector Worklist(Leaf); diff --git a/clang/lib/Lex/TokenConcatenation.cpp b/clang/lib/Lex/TokenConcatenation.cpp index 865879d1805336819d324c1ae03c5cdcf2adb377..05f4203bd722bb2e076218f291484038f792b2b4 100644 --- a/clang/lib/Lex/TokenConcatenation.cpp +++ b/clang/lib/Lex/TokenConcatenation.cpp @@ -160,6 +160,10 @@ static char GetFirstChar(const Preprocessor &PP, const Token &Tok) { bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok, const Token &PrevTok, const Token &Tok) const { + // No space is required between header unit name in quote and semi. + if (PrevTok.is(tok::annot_header_unit) && Tok.is(tok::semi)) + return false; + // Conservatively assume that every annotation token that has a printable // form requires whitespace. if (PrevTok.isAnnotation()) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index b47fdd1213c3ccf7e7198998adcaca81b8be56b3..b5f241739fa9d49983394cda9b9c43783fc52960 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2445,8 +2445,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // Recover as if it were an explicit specialization. TemplateParameterLists FakedParamLists; FakedParamLists.push_back(Actions.ActOnTemplateParameterList( - 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, - std::nullopt, LAngleLoc, nullptr)); + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, {}, + LAngleLoc, nullptr)); TheDecl = ParseFunctionDefinition( D, @@ -2787,8 +2787,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( // Recover as if it were an explicit specialization. TemplateParameterLists FakedParamLists; FakedParamLists.push_back(Actions.ActOnTemplateParameterList( - 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, - std::nullopt, LAngleLoc, nullptr)); + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, {}, + LAngleLoc, nullptr)); ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(), FakedParamLists, D); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index b28c2a9db91b0ffa0cbc2bea53dbeb90cbc73162..60aab1411a96c58dcb38034c320fba0a8045cdd8 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -2220,8 +2220,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // "template<>", so that we treat this construct as a class // template specialization. FakedParamLists.push_back(Actions.ActOnTemplateParameterList( - 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, - std::nullopt, LAngleLoc, nullptr)); + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, {}, + LAngleLoc, nullptr)); TemplateParams = &FakedParamLists; } } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 1398d3224fdf1137ba06dc30d13dcbdef32c89c2..62ec32b97b55cc49f068d3aa38dc54c496458ef9 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -3859,8 +3859,8 @@ ExprResult Parser::ParseBlockLiteralExpression() { /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, - /*DeclsInPrototype=*/std::nullopt, - CaretLoc, CaretLoc, ParamInfo), + /*DeclsInPrototype=*/{}, CaretLoc, + CaretLoc, ParamInfo), CaretLoc); MaybeParseGNUAttributes(ParamInfo); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index e96cddf88a1346e96bcecc26f7fe2f12cbba6abd..ce3624f366a2a19f18ba8fae898a5a3e4f6cf54f 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1579,9 +1579,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DynamicExceptionRanges.data(), DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, /*ExceptionSpecTokens*/ nullptr, - /*DeclsInPrototype=*/std::nullopt, LParenLoc, - FunLocalRangeEnd, D, TrailingReturnType, - TrailingReturnTypeLoc, &DS), + /*DeclsInPrototype=*/{}, LParenLoc, FunLocalRangeEnd, D, + TrailingReturnType, TrailingReturnTypeLoc, &DS), std::move(Attributes), DeclEndLoc); // We have called ActOnLambdaClosureQualifiers for parentheses-less cases diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp index dd59cb23236d74b3fae9dd7411d2451a172bf3b7..07f133408c38794d3141eb00f3e1dccfdbc9e466 100644 --- a/clang/lib/Parse/ParseInit.cpp +++ b/clang/lib/Parse/ParseInit.cpp @@ -487,7 +487,7 @@ ExprResult Parser::ParseBraceInitializer() { : diag::ext_c_empty_initializer); } // Match the '}'. - return Actions.ActOnInitList(LBraceLoc, std::nullopt, ConsumeBrace()); + return Actions.ActOnInitList(LBraceLoc, {}, ConsumeBrace()); } // Enter an appropriate expression evaluation context for an initializer list. diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index dad39d8dc736de1e38a8cae1a6327d7bc5990645..28ccd3061f8433a2b4fbd399abf205bb7b79d0db 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -3227,13 +3227,13 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, cutOffParsing(); if (SuperLoc.isValid()) Actions.CodeCompletion().CodeCompleteObjCSuperMessage( - getCurScope(), SuperLoc, std::nullopt, false); + getCurScope(), SuperLoc, {}, false); else if (ReceiverType) Actions.CodeCompletion().CodeCompleteObjCClassMessage( - getCurScope(), ReceiverType, std::nullopt, false); + getCurScope(), ReceiverType, {}, false); else Actions.CodeCompletion().CodeCompleteObjCInstanceMessage( - getCurScope(), ReceiverExpr, std::nullopt, false); + getCurScope(), ReceiverExpr, {}, false); return ExprError(); } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 257c688068873cb964f29c992762a962fc1092fb..0bb9446456e0e29a1b300a49634c5b500a51d4ee 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2580,7 +2580,7 @@ StmtResult Parser::ParseOpenMPExecutableDirective( DKind == OMPD_target_exit_data_spread) { Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope()); AssociatedStmt = (Sema::CompoundScopeRAII(Actions), - Actions.ActOnCompoundStmt(Loc, Loc, std::nullopt, + Actions.ActOnCompoundStmt(Loc, Loc, {}, /*isStmtExpr=*/false)); AssociatedStmt = Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 60d647da48f0533a9eaf1f236b0ec34a1dd565b3..7d727efb228731c6cd43968146ff62580b7bca6a 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -2558,8 +2558,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { // If the function body could not be parsed, make a bogus compoundstmt. if (FnBody.isInvalid()) { Sema::CompoundScopeRAII CompoundScope(Actions); - FnBody = - Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, std::nullopt, false); + FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, {}, false); } BodyScope.Exit(); @@ -2596,8 +2595,7 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { // compound statement as the body. if (FnBody.isInvalid()) { Sema::CompoundScopeRAII CompoundScope(Actions); - FnBody = - Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, std::nullopt, false); + FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, {}, false); } BodyScope.Exit(); diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp index aa0a2e223e708f03bd2a04457021f310dd8be7fc..357082fe329350d07332ffa6d0cc29f52f7252b9 100644 --- a/clang/lib/Sema/CheckExprLifetime.cpp +++ b/clang/lib/Sema/CheckExprLifetime.cpp @@ -472,7 +472,7 @@ shouldTrackFirstArgumentForConstructor(const CXXConstructExpr *Ctor) { } // Return true if this is an "normal" assignment operator. -// We assuments that a normal assingment operator always returns *this, that is, +// We assume that a normal assignment operator always returns *this, that is, // an lvalue reference that is the same type as the implicit object parameter // (or the LHS for a non-member operator$=). static bool isNormalAssignmentOperator(const FunctionDecl *FD) { diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index 5f51047b4d7b125244d11deb7cae541854d53bca..ce8564429b3802c2caa11547259a0b8c0a4e1239 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -512,6 +512,17 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer") .addSimpleTemplateParams(*SemaPtr, {"element_type"}) .Record; + onCompletion(Decl, [this](CXXRecordDecl *Decl) { + setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, + ResourceKind::TypedBuffer, /*IsROV=*/false, + /*RawBuffer=*/true) + .addArraySubscriptOperators() + .completeDefinition(); + }); + + Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWStructuredBuffer") + .addSimpleTemplateParams(*SemaPtr, {"element_type"}) + .Record; onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, ResourceKind::TypedBuffer, /*IsROV=*/false, diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 5e9886a109468f8d0c790d9ea5689ccc0d3b0f27..2b51765e80864acb677bf2407158d53ce0adb2ac 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2536,8 +2536,8 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, // with default arguments, etc. if (IsMemExpr && !E.isTypeDependent()) { Sema::TentativeAnalysisScope Trap(*this); - ExprResult R = BuildCallToMemberFunction(nullptr, &E, SourceLocation(), - std::nullopt, SourceLocation()); + ExprResult R = BuildCallToMemberFunction(nullptr, &E, SourceLocation(), {}, + SourceLocation()); if (R.isUsable()) { ZeroArgCallReturnTy = R.get()->getType(); return true; @@ -2689,7 +2689,7 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, // FIXME: Try this before emitting the fixit, and suppress diagnostics // while doing so. - E = BuildCallExpr(nullptr, E.get(), Range.getEnd(), std::nullopt, + E = BuildCallExpr(nullptr, E.get(), Range.getEnd(), {}, Range.getEnd().getLocWithOffset(1)); return true; } diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp index 798cabaa31a476e99f498b9b41cca8165ffed67a..076d3489fa94383b08c182a1f81801ab64518bb8 100644 --- a/clang/lib/Sema/SemaAvailability.cpp +++ b/clang/lib/Sema/SemaAvailability.cpp @@ -182,6 +182,12 @@ static bool ShouldDiagnoseAvailabilityInContext( return false; } + if (K == AR_Deprecated) { + if (const auto *VD = dyn_cast(OffendingDecl)) + if (VD->isLocalVarDeclOrParm() && VD->isDeprecated()) + return true; + } + // Checks if we should emit the availability diagnostic in the context of C. auto CheckContext = [&](const Decl *C) { if (K == AR_NotYetIntroduced) { diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 2bcb930acdcb575beed00fb3b9925ca612d2f53c..3308b898a5b68f44007bf5012c4450da83945d45 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -6300,7 +6300,7 @@ public: EmitFormatDiagnostic(Sema &S, bool inFunctionCall, const Expr *ArgumentExpr, const PartialDiagnostic &PDiag, SourceLocation StringLoc, bool IsStringLocation, Range StringRange, - ArrayRef Fixit = std::nullopt); + ArrayRef Fixit = {}); protected: bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, @@ -6327,7 +6327,7 @@ protected: template void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc, bool IsStringLocation, Range StringRange, - ArrayRef Fixit = std::nullopt); + ArrayRef Fixit = {}); }; } // namespace @@ -8899,18 +8899,36 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, << ArgIdx << FnName << PointeeTy << Call->getCallee()->getSourceRange()); else if (const auto *RT = PointeeTy->getAs()) { + + bool IsTriviallyCopyableCXXRecord = + RT->desugar().isTriviallyCopyableType(Context); + if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) && RT->getDecl()->isNonTrivialToPrimitiveDefaultInitialize()) { DiagRuntimeBehavior(Dest->getExprLoc(), Dest, PDiag(diag::warn_cstruct_memaccess) << ArgIdx << FnName << PointeeTy << 0); SearchNonTrivialToInitializeField::diag(PointeeTy, Dest, *this); + } else if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) && + !IsTriviallyCopyableCXXRecord && ArgIdx == 0) { + // FIXME: Limiting this warning to dest argument until we decide + // whether it's valid for source argument too. + DiagRuntimeBehavior(Dest->getExprLoc(), Dest, + PDiag(diag::warn_cxxstruct_memaccess) + << FnName << PointeeTy); } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) && RT->getDecl()->isNonTrivialToPrimitiveCopy()) { DiagRuntimeBehavior(Dest->getExprLoc(), Dest, PDiag(diag::warn_cstruct_memaccess) << ArgIdx << FnName << PointeeTy << 1); SearchNonTrivialToCopyField::diag(PointeeTy, Dest, *this); + } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) && + !IsTriviallyCopyableCXXRecord && ArgIdx == 0) { + // FIXME: Limiting this warning to dest argument until we decide + // whether it's valid for source argument too. + DiagRuntimeBehavior(Dest->getExprLoc(), Dest, + PDiag(diag::warn_cxxstruct_memaccess) + << FnName << PointeeTy); } else { continue; } @@ -9574,16 +9592,23 @@ static QualType GetExprType(const Expr *E) { return Ty; } -/// Pseudo-evaluate the given integer expression, estimating the -/// range of values it might take. +/// Attempts to estimate an approximate range for the given integer expression. +/// Returns a range if successful, otherwise it returns \c std::nullopt if a +/// reliable estimation cannot be determined. /// /// \param MaxWidth The width to which the value will be truncated. -/// \param Approximate If \c true, return a likely range for the result: in -/// particular, assume that arithmetic on narrower types doesn't leave -/// those types. If \c false, return a range including all possible -/// result values. -static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth, - bool InConstantContext, bool Approximate) { +/// \param InConstantContext If \c true, interpret the expression within a +/// constant context. +/// \param Approximate If \c true, provide a likely range of values by assuming +/// that arithmetic on narrower types remains within those types. +/// If \c false, return a range that includes all possible values +/// resulting from the expression. +/// \returns A range of values that the expression might take, or +/// std::nullopt if a reliable estimation cannot be determined. +static std::optional TryGetExprRange(ASTContext &C, const Expr *E, + unsigned MaxWidth, + bool InConstantContext, + bool Approximate) { E = E->IgnoreParens(); // Try a full evaluation first. @@ -9596,8 +9621,8 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth, // being of the new, wider type. if (const auto *CE = dyn_cast(E)) { if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue) - return GetExprRange(C, CE->getSubExpr(), MaxWidth, InConstantContext, - Approximate); + return TryGetExprRange(C, CE->getSubExpr(), MaxWidth, InConstantContext, + Approximate); IntRange OutputTypeRange = IntRange::forValueOfType(C, GetExprType(CE)); @@ -9608,40 +9633,52 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth, if (!isIntegerCast) return OutputTypeRange; - IntRange SubRange = GetExprRange(C, CE->getSubExpr(), - std::min(MaxWidth, OutputTypeRange.Width), - InConstantContext, Approximate); + std::optional SubRange = TryGetExprRange( + C, CE->getSubExpr(), std::min(MaxWidth, OutputTypeRange.Width), + InConstantContext, Approximate); + if (!SubRange) + return std::nullopt; // Bail out if the subexpr's range is as wide as the cast type. - if (SubRange.Width >= OutputTypeRange.Width) + if (SubRange->Width >= OutputTypeRange.Width) return OutputTypeRange; // Otherwise, we take the smaller width, and we're non-negative if // either the output type or the subexpr is. - return IntRange(SubRange.Width, - SubRange.NonNegative || OutputTypeRange.NonNegative); + return IntRange(SubRange->Width, + SubRange->NonNegative || OutputTypeRange.NonNegative); } if (const auto *CO = dyn_cast(E)) { // If we can fold the condition, just take that operand. bool CondResult; if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C)) - return GetExprRange(C, - CondResult ? CO->getTrueExpr() : CO->getFalseExpr(), - MaxWidth, InConstantContext, Approximate); + return TryGetExprRange( + C, CondResult ? CO->getTrueExpr() : CO->getFalseExpr(), MaxWidth, + InConstantContext, Approximate); // Otherwise, conservatively merge. - // GetExprRange requires an integer expression, but a throw expression + // TryGetExprRange requires an integer expression, but a throw expression // results in a void type. - Expr *E = CO->getTrueExpr(); - IntRange L = E->getType()->isVoidType() - ? IntRange{0, true} - : GetExprRange(C, E, MaxWidth, InConstantContext, Approximate); - E = CO->getFalseExpr(); - IntRange R = E->getType()->isVoidType() - ? IntRange{0, true} - : GetExprRange(C, E, MaxWidth, InConstantContext, Approximate); - return IntRange::join(L, R); + Expr *TrueExpr = CO->getTrueExpr(); + if (TrueExpr->getType()->isVoidType()) + return std::nullopt; + + std::optional L = + TryGetExprRange(C, TrueExpr, MaxWidth, InConstantContext, Approximate); + if (!L) + return std::nullopt; + + Expr *FalseExpr = CO->getFalseExpr(); + if (FalseExpr->getType()->isVoidType()) + return std::nullopt; + + std::optional R = + TryGetExprRange(C, FalseExpr, MaxWidth, InConstantContext, Approximate); + if (!R) + return std::nullopt; + + return IntRange::join(*L, *R); } if (const auto *BO = dyn_cast(E)) { @@ -9678,8 +9715,8 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth, // been coerced to the LHS type. case BO_Assign: // TODO: bitfields? - return GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext, - Approximate); + return TryGetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext, + Approximate); // Operations with opaque sources are black-listed. case BO_PtrMemD: @@ -9711,18 +9748,20 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth, // Right shift by a constant can narrow its left argument. case BO_Shr: case BO_ShrAssign: { - IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth, InConstantContext, - Approximate); + std::optional L = TryGetExprRange( + C, BO->getLHS(), MaxWidth, InConstantContext, Approximate); + if (!L) + return std::nullopt; // If the shift amount is a positive constant, drop the width by // that much. if (std::optional shift = BO->getRHS()->getIntegerConstantExpr(C)) { if (shift->isNonNegative()) { - if (shift->uge(L.Width)) - L.Width = (L.NonNegative ? 0 : 1); + if (shift->uge(L->Width)) + L->Width = (L->NonNegative ? 0 : 1); else - L.Width -= shift->getZExtValue(); + L->Width -= shift->getZExtValue(); } } @@ -9731,8 +9770,8 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth, // Comma acts as its right operand. case BO_Comma: - return GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext, - Approximate); + return TryGetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext, + Approximate); case BO_Add: if (!Approximate) @@ -9756,26 +9795,31 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth, case BO_Div: { // Don't 'pre-truncate' the operands. unsigned opWidth = C.getIntWidth(GetExprType(E)); - IntRange L = GetExprRange(C, BO->getLHS(), opWidth, InConstantContext, - Approximate); + std::optional L = TryGetExprRange( + C, BO->getLHS(), opWidth, InConstantContext, Approximate); + if (!L) + return std::nullopt; // If the divisor is constant, use that. if (std::optional divisor = BO->getRHS()->getIntegerConstantExpr(C)) { unsigned log2 = divisor->logBase2(); // floor(log_2(divisor)) - if (log2 >= L.Width) - L.Width = (L.NonNegative ? 0 : 1); + if (log2 >= L->Width) + L->Width = (L->NonNegative ? 0 : 1); else - L.Width = std::min(L.Width - log2, MaxWidth); + L->Width = std::min(L->Width - log2, MaxWidth); return L; } // Otherwise, just use the LHS's width. // FIXME: This is wrong if the LHS could be its minimal value and the RHS // could be -1. - IntRange R = GetExprRange(C, BO->getRHS(), opWidth, InConstantContext, - Approximate); - return IntRange(L.Width, L.NonNegative && R.NonNegative); + std::optional R = TryGetExprRange( + C, BO->getRHS(), opWidth, InConstantContext, Approximate); + if (!R) + return std::nullopt; + + return IntRange(L->Width, L->NonNegative && R->NonNegative); } case BO_Rem: @@ -9792,11 +9836,17 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth, // performed the computation. QualType T = GetExprType(E); unsigned opWidth = C.getIntWidth(T); - IntRange L = - GetExprRange(C, BO->getLHS(), opWidth, InConstantContext, Approximate); - IntRange R = - GetExprRange(C, BO->getRHS(), opWidth, InConstantContext, Approximate); - IntRange C = Combine(L, R); + std::optional L = TryGetExprRange(C, BO->getLHS(), opWidth, + InConstantContext, Approximate); + if (!L) + return std::nullopt; + + std::optional R = TryGetExprRange(C, BO->getRHS(), opWidth, + InConstantContext, Approximate); + if (!R) + return std::nullopt; + + IntRange C = Combine(*L, *R); C.NonNegative |= T->isUnsignedIntegerOrEnumerationType(); C.Width = std::min(C.Width, MaxWidth); return C; @@ -9814,26 +9864,30 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth, return IntRange::forValueOfType(C, GetExprType(E)); default: - return GetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext, - Approximate); + return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext, + Approximate); } } if (const auto *OVE = dyn_cast(E)) - return GetExprRange(C, OVE->getSourceExpr(), MaxWidth, InConstantContext, - Approximate); + return TryGetExprRange(C, OVE->getSourceExpr(), MaxWidth, InConstantContext, + Approximate); if (const auto *BitField = E->getSourceBitField()) return IntRange(BitField->getBitWidthValue(C), BitField->getType()->isUnsignedIntegerOrEnumerationType()); + if (GetExprType(E)->isVoidType()) + return std::nullopt; + return IntRange::forValueOfType(C, GetExprType(E)); } -static IntRange GetExprRange(ASTContext &C, const Expr *E, - bool InConstantContext, bool Approximate) { - return GetExprRange(C, E, C.getIntWidth(GetExprType(E)), InConstantContext, - Approximate); +static std::optional TryGetExprRange(ASTContext &C, const Expr *E, + bool InConstantContext, + bool Approximate) { + return TryGetExprRange(C, E, C.getIntWidth(GetExprType(E)), InConstantContext, + Approximate); } /// Checks whether the given value, which currently has the given @@ -10078,8 +10132,10 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, S.Context.hasSameUnqualifiedType(Constant->getType(), Other->getType())) return false; - IntRange OtherValueRange = GetExprRange( + std::optional OtherValueRange = TryGetExprRange( S.Context, Other, S.isConstantEvaluatedContext(), /*Approximate=*/false); + if (!OtherValueRange) + return false; QualType OtherT = Other->getType(); if (const auto *AT = OtherT->getAs()) @@ -10097,11 +10153,11 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, bool OtherIsBooleanDespiteType = !OtherT->isBooleanType() && Other->isKnownToHaveBooleanValue(); if (OtherIsBooleanDespiteType || IsObjCSignedCharBool) - OtherTypeRange = OtherValueRange = IntRange::forBoolType(); + OtherTypeRange = *OtherValueRange = IntRange::forBoolType(); // Check if all values in the range of possible values of this expression // lead to the same comparison outcome. - PromotedRange OtherPromotedValueRange(OtherValueRange, Value.getBitWidth(), + PromotedRange OtherPromotedValueRange(*OtherValueRange, Value.getBitWidth(), Value.isUnsigned()); auto Cmp = OtherPromotedValueRange.compare(Value); auto Result = PromotedRange::constantValue(E->getOpcode(), Cmp, RhsConstant); @@ -10125,7 +10181,7 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, // Don't warn if the non-constant operand actually always evaluates to the // same value. - if (!TautologicalTypeCompare && OtherValueRange.Width == 0) + if (!TautologicalTypeCompare && OtherValueRange->Width == 0) return false; // Suppress the diagnostic for an in-range comparison if the constant comes @@ -10164,7 +10220,7 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, if (!TautologicalTypeCompare) { S.Diag(E->getOperatorLoc(), diag::warn_tautological_compare_value_range) - << RhsConstant << OtherValueRange.Width << OtherValueRange.NonNegative + << RhsConstant << OtherValueRange->Width << OtherValueRange->NonNegative << E->getOpcodeStr() << OS.str() << *Result << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); return true; @@ -10294,9 +10350,11 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) { } // Otherwise, calculate the effective range of the signed operand. - IntRange signedRange = - GetExprRange(S.Context, signedOperand, S.isConstantEvaluatedContext(), - /*Approximate=*/true); + std::optional signedRange = + TryGetExprRange(S.Context, signedOperand, S.isConstantEvaluatedContext(), + /*Approximate=*/true); + if (!signedRange) + return; // Go ahead and analyze implicit conversions in the operands. Note // that we skip the implicit conversions on both sides. @@ -10304,7 +10362,7 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) { AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc()); // If the signed range is non-negative, -Wsign-compare won't fire. - if (signedRange.NonNegative) + if (signedRange->NonNegative) return; // For (in)equality comparisons, if the unsigned operand is a @@ -10313,15 +10371,17 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) { // change the result of the comparison. if (E->isEqualityOp()) { unsigned comparisonWidth = S.Context.getIntWidth(T); - IntRange unsignedRange = - GetExprRange(S.Context, unsignedOperand, S.isConstantEvaluatedContext(), - /*Approximate=*/true); + std::optional unsignedRange = TryGetExprRange( + S.Context, unsignedOperand, S.isConstantEvaluatedContext(), + /*Approximate=*/true); + if (!unsignedRange) + return; // We should never be unable to prove that the unsigned operand is // non-negative. - assert(unsignedRange.NonNegative && "unsigned range includes negative?"); + assert(unsignedRange->NonNegative && "unsigned range includes negative?"); - if (unsignedRange.Width < comparisonWidth) + if (unsignedRange->Width < comparisonWidth) return; } @@ -11128,10 +11188,12 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC, if (SourceBT && TargetBT && SourceBT->isIntegerType() && TargetBT->isFloatingType() && !IsListInit) { // Determine the number of precision bits in the source integer type. - IntRange SourceRange = - GetExprRange(Context, E, isConstantEvaluatedContext(), - /*Approximate=*/true); - unsigned int SourcePrecision = SourceRange.Width; + std::optional SourceRange = + TryGetExprRange(Context, E, isConstantEvaluatedContext(), + /*Approximate=*/true); + if (!SourceRange) + return; + unsigned int SourcePrecision = SourceRange->Width; // Determine the number of precision bits in the // target floating point type. @@ -11194,14 +11256,16 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC, E, Diag(CC, diag::warn_impcast_int_to_objc_signed_char_bool) << E->getType()); } + std::optional LikelySourceRange = TryGetExprRange( + Context, E, isConstantEvaluatedContext(), /*Approximate=*/true); + if (!LikelySourceRange) + return; IntRange SourceTypeRange = IntRange::forTargetOfCanonicalType(Context, Source); - IntRange LikelySourceRange = GetExprRange( - Context, E, isConstantEvaluatedContext(), /*Approximate=*/true); IntRange TargetRange = IntRange::forTargetOfCanonicalType(Context, Target); - if (LikelySourceRange.Width > TargetRange.Width) { + if (LikelySourceRange->Width > TargetRange.Width) { // If the source is a constant, use a default-on diagnostic. // TODO: this should happen for bitfield stores, too. Expr::EvalResult Result; @@ -11248,8 +11312,8 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC, } } - if (TargetRange.Width == LikelySourceRange.Width && - !TargetRange.NonNegative && LikelySourceRange.NonNegative && + if (TargetRange.Width == LikelySourceRange->Width && + !TargetRange.NonNegative && LikelySourceRange->NonNegative && Source->isSignedIntegerType()) { // Warn when doing a signed to signed conversion, warn if the positive // source value is exactly the width of the target type, which will @@ -11275,9 +11339,9 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC, } if ((!isa(Target) || !isa(Source)) && - ((TargetRange.NonNegative && !LikelySourceRange.NonNegative) || - (!TargetRange.NonNegative && LikelySourceRange.NonNegative && - LikelySourceRange.Width == TargetRange.Width))) { + ((TargetRange.NonNegative && !LikelySourceRange->NonNegative) || + (!TargetRange.NonNegative && LikelySourceRange->NonNegative && + LikelySourceRange->Width == TargetRange.Width))) { if (SourceMgr.isInSystemMacro(CC)) return; diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 3e31f3d82657a3e323758f8f3a2c06124672c3ff..16a76ff9b5c241998e4e0ae420d3904c0abc7c7a 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -4567,8 +4567,7 @@ void SemaCodeCompletion::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, 0) { ParsedType T = DS.getRepAsType(); if (!T.get().isNull() && T.get()->isObjCObjectOrInterfaceType()) - AddClassMessageCompletions(SemaRef, S, T, std::nullopt, false, false, - Results); + AddClassMessageCompletions(SemaRef, S, T, {}, false, false, Results); } // Note that we intentionally suppress macro results here, since we do not @@ -4931,7 +4930,7 @@ void SemaCodeCompletion::CodeCompletePostfixExpression(Scope *S, ExprResult E, if (E.isInvalid()) CodeCompleteExpression(S, PreferredType); else if (getLangOpts().ObjC) - CodeCompleteObjCInstanceMessage(S, E.get(), std::nullopt, false); + CodeCompleteObjCInstanceMessage(S, E.get(), {}, false); } /// The set of properties that have already been added, referenced by @@ -7747,8 +7746,8 @@ void SemaCodeCompletion::CodeCompleteObjCPropertyGetter(Scope *S) { Results.EnterNewScope(); VisitedSelectorSet Selectors; - AddObjCMethods(Class, true, MK_ZeroArgSelector, std::nullopt, - SemaRef.CurContext, Selectors, + AddObjCMethods(Class, true, MK_ZeroArgSelector, {}, SemaRef.CurContext, + Selectors, /*AllowSameLength=*/true, Results); Results.ExitScope(); HandleCodeCompleteResults(&SemaRef, CodeCompleter, @@ -7776,8 +7775,8 @@ void SemaCodeCompletion::CodeCompleteObjCPropertySetter(Scope *S) { Results.EnterNewScope(); VisitedSelectorSet Selectors; - AddObjCMethods(Class, true, MK_OneArgSelector, std::nullopt, - SemaRef.CurContext, Selectors, + AddObjCMethods(Class, true, MK_OneArgSelector, {}, SemaRef.CurContext, + Selectors, /*AllowSameLength=*/true, Results); Results.ExitScope(); @@ -8075,8 +8074,7 @@ void SemaCodeCompletion::CodeCompleteObjCMessageReceiver(Scope *S) { if (Iface->getSuperClass()) { Results.AddResult(Result("super")); - AddSuperSendCompletion(SemaRef, /*NeedSuperKeyword=*/true, std::nullopt, - Results); + AddSuperSendCompletion(SemaRef, /*NeedSuperKeyword=*/true, {}, Results); } if (getLangOpts().CPlusPlus11) diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 89a0beadc61f3db0d081cd194b7b5cf6b9eac90f..3724aaf804c90599e7d3ab177d56ab11a2b0a564 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -341,7 +341,7 @@ static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E, // EvaluateBinaryTypeTrait(BTT_IsConvertible, ...) which is at the moment // a private function in SemaExprCXX.cpp - ExprResult AddressExpr = buildMemberCall(S, E, Loc, "address", std::nullopt); + ExprResult AddressExpr = buildMemberCall(S, E, Loc, "address", {}); if (AddressExpr.isInvalid()) return nullptr; @@ -392,8 +392,8 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise, return Result.get(); }; - CallExpr *AwaitReady = cast_or_null( - BuildSubExpr(ACT::ACT_Ready, "await_ready", std::nullopt)); + CallExpr *AwaitReady = + cast_or_null(BuildSubExpr(ACT::ACT_Ready, "await_ready", {})); if (!AwaitReady) return Calls; if (!AwaitReady->getType()->isDependentType()) { @@ -454,7 +454,7 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise, } } - BuildSubExpr(ACT::ACT_Resume, "await_resume", std::nullopt); + BuildSubExpr(ACT::ACT_Resume, "await_resume", {}); // Make sure the awaiter object gets a chance to be cleaned up. S.Cleanup.setExprNeedsCleanups(true); @@ -722,8 +722,8 @@ bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc, SourceLocation Loc = Fn->getLocation(); // Build the initial suspend point auto buildSuspends = [&](StringRef Name) mutable -> StmtResult { - ExprResult Operand = buildPromiseCall(*this, ScopeInfo->CoroutinePromise, - Loc, Name, std::nullopt); + ExprResult Operand = + buildPromiseCall(*this, ScopeInfo->CoroutinePromise, Loc, Name, {}); if (Operand.isInvalid()) return StmtError(); ExprResult Suspend = @@ -1049,7 +1049,7 @@ StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E, PC = buildPromiseCall(*this, Promise, Loc, "return_value", E); } else { E = MakeFullDiscardedValueExpr(E).get(); - PC = buildPromiseCall(*this, Promise, Loc, "return_void", std::nullopt); + PC = buildPromiseCall(*this, Promise, Loc, "return_void", {}); } if (PC.isInvalid()) return StmtError(); @@ -1735,8 +1735,8 @@ bool CoroutineStmtBuilder::makeOnException() { if (!S.getLangOpts().CXXExceptions) return true; - ExprResult UnhandledException = buildPromiseCall( - S, Fn.CoroutinePromise, Loc, "unhandled_exception", std::nullopt); + ExprResult UnhandledException = + buildPromiseCall(S, Fn.CoroutinePromise, Loc, "unhandled_exception", {}); UnhandledException = S.ActOnFinishFullExpr(UnhandledException.get(), Loc, /*DiscardedValue*/ false); if (UnhandledException.isInvalid()) @@ -1759,8 +1759,8 @@ bool CoroutineStmtBuilder::makeReturnObject() { // [dcl.fct.def.coroutine]p7 // The expression promise.get_return_object() is used to initialize the // returned reference or prvalue result object of a call to a coroutine. - ExprResult ReturnObject = buildPromiseCall(S, Fn.CoroutinePromise, Loc, - "get_return_object", std::nullopt); + ExprResult ReturnObject = + buildPromiseCall(S, Fn.CoroutinePromise, Loc, "get_return_object", {}); if (ReturnObject.isInvalid()) return false; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index cb90263ae767298ffe2646210de78899361aee7a..e5ad59a2b52b9e3382f18d5f3e450e39b2de4d59 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6940,7 +6940,7 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { } } - // Check the attributes on the function type, if any. + // Check the attributes on the function type and function params, if any. if (const auto *FD = dyn_cast(&ND)) { // Don't declare this variable in the second operand of the for-statement; // GCC miscompiles that by ending its lifetime before evaluating the @@ -6970,6 +6970,18 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { } } } + + for (unsigned int I = 0; I < FD->getNumParams(); ++I) { + const ParmVarDecl *P = FD->getParamDecl(I); + + // The [[lifetimebound]] attribute can be applied to a function parameter + // only if the function returns a value. + if (auto *A = P->getAttr()) { + if (!isa(FD) && FD->getReturnType()->isVoidType()) { + S.Diag(A->getLocation(), diag::err_lifetimebound_void_return_type); + } + } + } } } @@ -14149,8 +14161,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { InitializationKind Kind = InitializationKind::CreateDefault(Var->getLocation()); - InitializationSequence InitSeq(*this, Entity, Kind, std::nullopt); - ExprResult Init = InitSeq.Perform(*this, Entity, Kind, std::nullopt); + InitializationSequence InitSeq(*this, Entity, Kind, {}); + ExprResult Init = InitSeq.Perform(*this, Entity, Kind, {}); if (Init.get()) { Var->setInit(MaybeCreateExprWithCleanups(Init.get())); @@ -16442,8 +16454,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, - /*DeclsInPrototype=*/std::nullopt, - Loc, Loc, D), + /*DeclsInPrototype=*/{}, Loc, Loc, + D), std::move(DS.getAttributes()), SourceLocation()); D.SetIdentifier(&II, Loc); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 7a9b653a96eb047cd74273ea941cc4f80b808bac..733b7eedeb965870906d21fea503f920311a1436 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1281,7 +1281,7 @@ static bool checkTupleLikeDecomposition(Sema &S, if (E.isInvalid()) return true; - E = S.BuildCallExpr(nullptr, E.get(), Loc, std::nullopt, Loc); + E = S.BuildCallExpr(nullptr, E.get(), Loc, {}, Loc); } else { // Otherwise, the initializer is get(e), where get is looked up // in the associated namespaces. @@ -4807,8 +4807,8 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, case IIK_Default: { InitializationKind InitKind = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, std::nullopt); - BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, std::nullopt); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, {}); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, {}); break; } @@ -4972,9 +4972,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationKind InitKind = InitializationKind::CreateDefault(Loc); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, std::nullopt); - ExprResult MemberInit = - InitSeq.Perform(SemaRef, InitEntity, InitKind, std::nullopt); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, {}); + ExprResult MemberInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, {}); MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit); if (MemberInit.isInvalid()) @@ -11002,7 +11001,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, EPI.Variadic = false; EPI.TypeQuals = Qualifiers(); EPI.RefQualifier = RQ_None; - return Context.getFunctionType(Context.VoidTy, std::nullopt, EPI); + return Context.getFunctionType(Context.VoidTy, {}, EPI); } static void extendLeft(SourceRange &R, SourceRange Before) { @@ -11182,8 +11181,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // of the errors above fired) and with the conversion type as the // return type. if (D.isInvalidType()) - R = Context.getFunctionType(ConvType, std::nullopt, - Proto->getExtProtoInfo()); + R = Context.getFunctionType(ConvType, {}, Proto->getExtProtoInfo()); // C++0x explicit conversion operators. if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus20) @@ -13877,7 +13875,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); - setupImplicitSpecialMemberType(DefaultCon, Context.VoidTy, std::nullopt); + setupImplicitSpecialMemberType(DefaultCon, Context.VoidTy, {}); if (getLangOpts().CUDA) CUDA().inferTargetForImplicitSpecialMember( @@ -14163,7 +14161,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { Destructor->setAccess(AS_public); Destructor->setDefaulted(); - setupImplicitSpecialMemberType(Destructor, Context.VoidTy, std::nullopt); + setupImplicitSpecialMemberType(Destructor, Context.VoidTy, {}); if (getLangOpts().CUDA) CUDA().inferTargetForImplicitSpecialMember( @@ -14322,8 +14320,7 @@ void Sema::AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor) { FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo(); EPI.ExceptionSpec.Type = EST_Unevaluated; EPI.ExceptionSpec.SourceDecl = Destructor; - Destructor->setType( - Context.getFunctionType(Context.VoidTy, std::nullopt, EPI)); + Destructor->setType(Context.getFunctionType(Context.VoidTy, {}, EPI)); // FIXME: If the destructor has a body that could throw, and the newly created // spec doesn't allow exceptions, we should emit a warning, because this @@ -15649,8 +15646,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, : CopyConstructor->getLocation(); Sema::CompoundScopeRAII CompoundScope(*this); CopyConstructor->setBody( - ActOnCompoundStmt(Loc, Loc, std::nullopt, /*isStmtExpr=*/false) - .getAs()); + ActOnCompoundStmt(Loc, Loc, {}, /*isStmtExpr=*/false).getAs()); CopyConstructor->markUsed(Context); } @@ -15781,8 +15777,7 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation, : MoveConstructor->getLocation(); Sema::CompoundScopeRAII CompoundScope(*this); MoveConstructor->setBody( - ActOnCompoundStmt(Loc, Loc, std::nullopt, /*isStmtExpr=*/false) - .getAs()); + ActOnCompoundStmt(Loc, Loc, {}, /*isStmtExpr=*/false).getAs()); MoveConstructor->markUsed(Context); } @@ -17238,8 +17233,7 @@ bool Sema::EvaluateStaticAssertMessageAsString(Expr *Message, CXXScopeSpec(), SourceLocation(), nullptr, LR, nullptr, nullptr); if (Res.isInvalid()) return ExprError(); - Res = BuildCallExpr(nullptr, Res.get(), Loc, std::nullopt, Loc, nullptr, - false, true); + Res = BuildCallExpr(nullptr, Res.get(), Loc, {}, Loc, nullptr, false, true); if (Res.isInvalid()) return ExprError(); if (Res.get()->isTypeDependent() || Res.get()->isValueDependent()) diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index d8cd09b8272930cd4caa8ff0204dc881ab99ee77..78acfeddb786391a1f405edba3b94635bbfe51e6 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -5511,10 +5511,9 @@ void SemaObjC::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { InitializationKind InitKind = InitializationKind::CreateDefault(ObjCImplementation->getLocation()); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, - std::nullopt); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, {}); ExprResult MemberInit = - InitSeq.Perform(SemaRef, InitEntity, InitKind, std::nullopt); + InitSeq.Perform(SemaRef, InitEntity, InitKind, {}); MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit); // Note, MemberInit could actually come back empty if no initialization // is required (e.g., because it would call a trivial default constructor) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index f6071fba3742663a78047b793e3dba5a38c3ae7b..709057c6fe620107319659b7d6cd4c981875d72b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1079,8 +1079,8 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, if (TrapFn.isInvalid()) return ExprError(); - ExprResult Call = BuildCallExpr(TUScope, TrapFn.get(), E->getBeginLoc(), - std::nullopt, E->getEndLoc()); + ExprResult Call = BuildCallExpr(TUScope, TrapFn.get(), E->getBeginLoc(), {}, + E->getEndLoc()); if (Call.isInvalid()) return ExprError(); @@ -2164,8 +2164,8 @@ Sema::ActOnStringLiteral(ArrayRef StringToks, Scope *UDLScope) { TemplateArgument Arg(Lit); TemplateArgumentLocInfo ArgInfo(Lit); ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); - return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt, - StringTokLocs.back(), &ExplicitArgs); + return BuildLiteralOperatorCall(R, OpNameInfo, {}, StringTokLocs.back(), + &ExplicitArgs); } case LOLR_StringTemplatePack: { @@ -2185,8 +2185,8 @@ Sema::ActOnStringLiteral(ArrayRef StringToks, Scope *UDLScope) { TemplateArgumentLocInfo ArgInfo; ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); } - return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt, - StringTokLocs.back(), &ExplicitArgs); + return BuildLiteralOperatorCall(R, OpNameInfo, {}, StringTokLocs.back(), + &ExplicitArgs); } case LOLR_Raw: case LOLR_ErrorNoDiagnostic: @@ -2801,7 +2801,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // a template name, but we happen to have always already looked up the name // before we get here if it must be a template name. if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr, - std::nullopt, nullptr, &TE)) { + {}, nullptr, &TE)) { if (TE && KeywordReplacement) { auto &State = getTypoExprState(TE); auto BestTC = State.Consumer->getNextCorrection(); @@ -3787,8 +3787,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { TemplateArgumentLocInfo ArgInfo; ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); } - return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt, TokLoc, - &ExplicitArgs); + return BuildLiteralOperatorCall(R, OpNameInfo, {}, TokLoc, &ExplicitArgs); } case LOLR_StringTemplatePack: llvm_unreachable("unexpected literal operator lookup result"); @@ -16296,7 +16295,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (isa(FTy)) { FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = Ext; - BlockTy = Context.getFunctionType(RetTy, std::nullopt, EPI); + BlockTy = Context.getFunctionType(RetTy, {}, EPI); // Otherwise, if we don't need to change anything about the function type, // preserve its sugar structure. @@ -16317,7 +16316,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, } else { FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn); - BlockTy = Context.getFunctionType(RetTy, std::nullopt, EPI); + BlockTy = Context.getFunctionType(RetTy, {}, EPI); } DiagnoseUnusedParameters(BD->parameters()); @@ -20195,7 +20194,8 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef Stmts, bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, const PartialDiagnostic &PD) { return DiagRuntimeBehavior( - Loc, Statement ? llvm::ArrayRef(Statement) : std::nullopt, PD); + Loc, Statement ? llvm::ArrayRef(Statement) : llvm::ArrayRef(), + PD); } bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc, diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 2f914ddc22a38b8948bf4c44ed73f86d5a3c13a6..35fbc4e7c30ebbaf3d687348a5e9e55c29ba0abe 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -305,7 +305,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(SemaObjC &S, SourceLocation Loc, ParmVarDecl::Create(S.SemaRef.Context, Method, SourceLocation(), SourceLocation(), &CX.Idents.get("value"), NumberType, /*TInfo=*/nullptr, SC_None, nullptr); - Method->setMethodParams(S.SemaRef.Context, value, std::nullopt); + Method->setMethodParams(S.SemaRef.Context, value, {}); } if (!validateBoxingMethod(S.SemaRef, Loc, S.NSNumberDecl, Sel, Method)) @@ -588,7 +588,7 @@ ExprResult SemaObjC::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { Context.getPointerType(ConstCharType), /*TInfo=*/nullptr, SC_None, nullptr); - M->setMethodParams(Context, value, std::nullopt); + M->setMethodParams(Context, value, {}); BoxingMethod = M; } @@ -713,7 +713,7 @@ ExprResult SemaObjC::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { SC_None, nullptr); Params.push_back(type); - M->setMethodParams(Context, Params, std::nullopt); + M->setMethodParams(Context, Params, {}); BoxingMethod = M; } @@ -843,7 +843,7 @@ ExprResult SemaObjC::BuildObjCArrayLiteral(SourceRange SR, /*TInfo=*/nullptr, SC_None, nullptr); Params.push_back(cnt); - Method->setMethodParams(Context, Params, std::nullopt); + Method->setMethodParams(Context, Params, {}); } if (!validateBoxingMethod(SemaRef, Loc, NSArrayDecl, Sel, Method)) @@ -1012,7 +1012,7 @@ ExprResult SemaObjC::BuildObjCDictionaryLiteral( /*TInfo=*/nullptr, SC_None, nullptr); Params.push_back(cnt); - Method->setMethodParams(Context, Params, std::nullopt); + Method->setMethodParams(Context, Params, {}); } if (!validateBoxingMethod(SemaRef, SR.getBegin(), NSDictionaryDecl, Sel, @@ -4388,7 +4388,7 @@ bool SemaObjC::CheckObjCBridgeRelatedConversions(SourceLocation Loc, ExprResult msg = BuildInstanceMessageImplicit( SrcExpr, SrcType, InstanceMethod->getLocation(), - InstanceMethod->getSelector(), InstanceMethod, std::nullopt); + InstanceMethod->getSelector(), InstanceMethod, {}); SrcExpr = msg.get(); } return true; diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 1f6c5b8d4561bcd5a8ef556c192d4ddd608f3809..a472538236e2d91dec1f7d478e8ed6c83640244f 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1698,18 +1698,27 @@ static bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) { return true; } -static bool CheckArgsTypesAreCorrect( +bool CheckArgTypeIsCorrect( + Sema *S, Expr *Arg, QualType ExpectedType, + llvm::function_ref Check) { + QualType PassedType = Arg->getType(); + if (Check(PassedType)) { + if (auto *VecTyA = PassedType->getAs()) + ExpectedType = S->Context.getVectorType( + ExpectedType, VecTyA->getNumElements(), VecTyA->getVectorKind()); + S->Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible) + << PassedType << ExpectedType << 1 << 0 << 0; + return true; + } + return false; +} + +bool CheckAllArgTypesAreCorrect( Sema *S, CallExpr *TheCall, QualType ExpectedType, llvm::function_ref Check) { for (unsigned i = 0; i < TheCall->getNumArgs(); ++i) { - QualType PassedType = TheCall->getArg(i)->getType(); - if (Check(PassedType)) { - if (auto *VecTyA = PassedType->getAs()) - ExpectedType = S->Context.getVectorType( - ExpectedType, VecTyA->getNumElements(), VecTyA->getVectorKind()); - S->Diag(TheCall->getArg(0)->getBeginLoc(), - diag::err_typecheck_convert_incompatible) - << PassedType << ExpectedType << 1 << 0 << 0; + Expr *Arg = TheCall->getArg(i); + if (CheckArgTypeIsCorrect(S, Arg, ExpectedType, Check)) { return true; } } @@ -1720,8 +1729,8 @@ static bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall) { auto checkAllFloatTypes = [](clang::QualType PassedType) -> bool { return !PassedType->hasFloatingRepresentation(); }; - return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, - checkAllFloatTypes); + return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.FloatTy, + checkAllFloatTypes); } static bool CheckFloatOrHalfRepresentations(Sema *S, CallExpr *TheCall) { @@ -1732,8 +1741,19 @@ static bool CheckFloatOrHalfRepresentations(Sema *S, CallExpr *TheCall) { : PassedType; return !BaseType->isHalfType() && !BaseType->isFloat32Type(); }; - return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, - checkFloatorHalf); + return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.FloatTy, + checkFloatorHalf); +} + +static bool CheckModifiableLValue(Sema *S, CallExpr *TheCall, + unsigned ArgIndex) { + auto *Arg = TheCall->getArg(ArgIndex); + SourceLocation OrigLoc = Arg->getExprLoc(); + if (Arg->IgnoreCasts()->isModifiableLvalue(S->Context, &OrigLoc) == + Expr::MLV_Valid) + return false; + S->Diag(OrigLoc, diag::error_hlsl_inout_lvalue) << Arg << 0; + return true; } static bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall) { @@ -1742,24 +1762,24 @@ static bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall) { return VecTy->getElementType()->isDoubleType(); return false; }; - return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, - checkDoubleVector); + return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.FloatTy, + checkDoubleVector); } static bool CheckFloatingOrIntRepresentation(Sema *S, CallExpr *TheCall) { auto checkAllSignedTypes = [](clang::QualType PassedType) -> bool { return !PassedType->hasIntegerRepresentation() && !PassedType->hasFloatingRepresentation(); }; - return CheckArgsTypesAreCorrect(S, TheCall, S->Context.IntTy, - checkAllSignedTypes); + return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.IntTy, + checkAllSignedTypes); } static bool CheckUnsignedIntRepresentation(Sema *S, CallExpr *TheCall) { auto checkAllUnsignedTypes = [](clang::QualType PassedType) -> bool { return !PassedType->hasUnsignedIntegerRepresentation(); }; - return CheckArgsTypesAreCorrect(S, TheCall, S->Context.UnsignedIntTy, - checkAllUnsignedTypes); + return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.UnsignedIntTy, + checkAllUnsignedTypes); } static void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, @@ -2074,6 +2094,22 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; break; } + case Builtin::BI__builtin_hlsl_elementwise_splitdouble: { + if (SemaRef.checkArgCount(TheCall, 3)) + return true; + + if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.DoubleTy, 0) || + CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.UnsignedIntTy, + 1) || + CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.UnsignedIntTy, + 2)) + return true; + + if (CheckModifiableLValue(&SemaRef, TheCall, 1) || + CheckModifiableLValue(&SemaRef, TheCall, 2)) + return true; + break; + } case Builtin::BI__builtin_elementwise_acos: case Builtin::BI__builtin_elementwise_asin: case Builtin::BI__builtin_elementwise_atan: diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index f560865681fa5a6850f1943688b169465b6f919c..573e90aced3eeac4890d5187a8634773dc8ec8e1 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -569,7 +569,7 @@ ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc, true); MultiExprArg SubInit; Expr *InitExpr; - InitListExpr DummyInitList(SemaRef.Context, Loc, std::nullopt, Loc); + InitListExpr DummyInitList(SemaRef.Context, Loc, {}, Loc); // C++ [dcl.init.aggr]p7: // If there are fewer initializer-clauses in the list than there are @@ -588,10 +588,9 @@ ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc, // // Only do this if we're initializing a class type, to avoid filling in // the initializer list where possible. - InitExpr = VerifyOnly - ? &DummyInitList - : new (SemaRef.Context) - InitListExpr(SemaRef.Context, Loc, std::nullopt, Loc); + InitExpr = VerifyOnly ? &DummyInitList + : new (SemaRef.Context) + InitListExpr(SemaRef.Context, Loc, {}, Loc); InitExpr->setType(SemaRef.Context.VoidTy); SubInit = InitExpr; Kind = InitializationKind::CreateCopy(Loc, Loc); @@ -3403,7 +3402,7 @@ InitListChecker::createInitListExpr(QualType CurrentObjectType, SourceRange InitRange, unsigned ExpectedNumInits) { InitListExpr *Result = new (SemaRef.Context) InitListExpr( - SemaRef.Context, InitRange.getBegin(), std::nullopt, InitRange.getEnd()); + SemaRef.Context, InitRange.getBegin(), {}, InitRange.getEnd()); QualType ResultType = CurrentObjectType; if (!ResultType->isArrayType()) @@ -5650,7 +5649,7 @@ static void TryDefaultInitialization(Sema &S, // constructor for T is called (and the initialization is ill-formed if // T has no accessible default constructor); if (DestType->isRecordType() && S.getLangOpts().CPlusPlus) { - TryConstructorInitialization(S, Entity, Kind, std::nullopt, DestType, + TryConstructorInitialization(S, Entity, Kind, {}, DestType, Entity.getType(), Sequence); return; } @@ -5687,11 +5686,13 @@ static void TryOrBuildParenListInitialization( const InitializationKind &SubKind, Expr *Arg, Expr **InitExpr = nullptr) { InitializationSequence IS = InitializationSequence( - S, SubEntity, SubKind, Arg ? MultiExprArg(Arg) : std::nullopt); + S, SubEntity, SubKind, + Arg ? MultiExprArg(Arg) : MutableArrayRef()); if (IS.Failed()) { if (!VerifyOnly) { - IS.Diagnose(S, SubEntity, SubKind, Arg ? ArrayRef(Arg) : std::nullopt); + IS.Diagnose(S, SubEntity, SubKind, + Arg ? ArrayRef(Arg) : ArrayRef()); } else { Sequence.SetFailed( InitializationSequence::FK_ParenthesizedListInitFailed); @@ -5702,7 +5703,7 @@ static void TryOrBuildParenListInitialization( if (!VerifyOnly) { ExprResult ER; ER = IS.Perform(S, SubEntity, SubKind, - Arg ? MultiExprArg(Arg) : std::nullopt); + Arg ? MultiExprArg(Arg) : MutableArrayRef()); if (ER.isInvalid()) return false; diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 7b9d5f4ff7eb341545fead5136f9714cf04fd828..e7afa0f4c81fc4965e8d003142d1065b5cbb244d 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -909,8 +909,8 @@ getDummyLambdaType(Sema &S, SourceLocation Loc = SourceLocation()) { QualType DefaultTypeForNoTrailingReturn = S.getLangOpts().CPlusPlus14 ? S.Context.getAutoDeductType() : S.Context.DependentTy; - QualType MethodTy = S.Context.getFunctionType(DefaultTypeForNoTrailingReturn, - std::nullopt, EPI); + QualType MethodTy = + S.Context.getFunctionType(DefaultTypeForNoTrailingReturn, {}, EPI); return S.Context.getTrivialTypeSourceInfo(MethodTy, Loc); } @@ -1681,8 +1681,7 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange, ConvExtInfo.TypeQuals = Qualifiers(); ConvExtInfo.TypeQuals.addConst(); ConvExtInfo.ExceptionSpec.Type = EST_BasicNoexcept; - QualType ConvTy = - S.Context.getFunctionType(PtrToFunctionTy, std::nullopt, ConvExtInfo); + QualType ConvTy = S.Context.getFunctionType(PtrToFunctionTy, {}, ConvExtInfo); SourceLocation Loc = IntroducerRange.getBegin(); DeclarationName ConversionName @@ -1864,8 +1863,7 @@ static void addBlockPointerConversion(Sema &S, /*IsVariadic=*/false, /*IsCXXMethod=*/true)); ConversionEPI.TypeQuals = Qualifiers(); ConversionEPI.TypeQuals.addConst(); - QualType ConvTy = - S.Context.getFunctionType(BlockPtrTy, std::nullopt, ConversionEPI); + QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, {}, ConversionEPI); SourceLocation Loc = IntroducerRange.getBegin(); DeclarationName Name diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index e5db11369221a4556eab2819515c542304d52f4e..8468e9a730c2d0e3bdd964150f2382a6aa749104 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1200,7 +1200,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_C); EPI.ExceptionSpec = EST_None; QualType ExpectedType = R.getSema().Context.getFunctionType( - R.getLookupName().getCXXNameType(), std::nullopt, EPI); + R.getLookupName().getCXXNameType(), {}, EPI); // Perform template argument deduction against the type that we would // expect the function to have. diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 031f2a6af87744f9a97cc896ff96e1964ee01227..5c4dc93ff16cdfdaf3ff113b03478b90570baf56 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -2552,7 +2552,7 @@ void SemaObjC::ProcessPropertyDecl(ObjCPropertyDecl *property) { /*TInfo=*/nullptr, SC_None, nullptr); - SetterMethod->setMethodParams(Context, Argument, std::nullopt); + SetterMethod->setMethodParams(Context, Argument, {}); AddPropertyAttrs(SemaRef, SetterMethod, property); diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index d33b0d0c1c30186e0f0f0f9b8ebd3e7416657bed..aadcd7183e713b2d16e80369bd363b00a241a11c 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -1986,8 +1986,7 @@ ExprResult SemaOpenACC::ActOnArraySectionExpr(Expr *Base, SourceLocation LBLoc, // Fill in a dummy 'length' so that when we instantiate this we don't // double-diagnose here. ExprResult Recovery = SemaRef.CreateRecoveryExpr( - ColonLoc, SourceLocation(), ArrayRef{std::nullopt}, - Context.IntTy); + ColonLoc, SourceLocation(), ArrayRef(), Context.IntTy); Length = Recovery.isUsable() ? Recovery.get() : nullptr; } diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 16f63f94d54812c130ca0266d3fb7382be5e1163..203e44a97de81ec63119635459206addfc0dca6b 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -16300,9 +16300,9 @@ OMPClause *SemaOpenMP::ActOnOpenMPSimpleClause( return Res; } -static std::string -getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last, - ArrayRef Exclude = std::nullopt) { +static std::string getListOfPossibleValues(OpenMPClauseKind K, unsigned First, + unsigned Last, + ArrayRef Exclude = {}) { SmallString<256> Buffer; llvm::raw_svector_ostream Out(Buffer); unsigned Skipped = Exclude.size(); @@ -21855,7 +21855,7 @@ static void checkMappableExpressionList( CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo MapperId, ArrayRef UnresolvedMappers, OpenMPMapClauseKind MapType = OMPC_MAP_unknown, - ArrayRef Modifiers = std::nullopt, + ArrayRef Modifiers = {}, bool IsMapTypeImplicit = false, bool NoDiagnose = false) { // We only expect mappable expressions in 'to', 'from', and 'map' clauses. assert((CKind == OMPC_map || CKind == OMPC_to || CKind == OMPC_from) && diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 7b86299561a3653592aca9f6512d15cea5736012..4aeceba128b29b7d5ef24c832dc029856986a925 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5502,7 +5502,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, } if (CT->getSize().ugt(e)) { // Need an init from empty {}, is there one? - InitListExpr EmptyList(S.Context, From->getEndLoc(), std::nullopt, + InitListExpr EmptyList(S.Context, From->getEndLoc(), {}, From->getEndLoc()); EmptyList.setType(S.Context.VoidTy); DfltElt = TryListConversion( @@ -7479,7 +7479,7 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, } else { AddMethodCandidate(cast(Decl), FoundDecl, ActingContext, ObjectType, ObjectClassification, Args, CandidateSet, - SuppressUserConversions, false, std::nullopt, PO); + SuppressUserConversions, false, {}, PO); } } @@ -8125,7 +8125,7 @@ void Sema::AddConversionCandidate( } if (EnableIfAttr *FailedAttr = - CheckEnableIf(Conversion, CandidateSet.getLocation(), std::nullopt)) { + CheckEnableIf(Conversion, CandidateSet.getLocation(), {})) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; Candidate.DeductionFailure.Data = FailedAttr; @@ -8306,7 +8306,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, } if (EnableIfAttr *FailedAttr = - CheckEnableIf(Conversion, CandidateSet.getLocation(), std::nullopt)) { + CheckEnableIf(Conversion, CandidateSet.getLocation(), {})) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; Candidate.DeductionFailure.Data = FailedAttr; @@ -8346,10 +8346,10 @@ void Sema::AddNonMemberOperatorCandidates( continue; AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet); if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) - AddOverloadCandidate( - FD, F.getPair(), {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, - false, false, true, false, ADLCallKind::NotADL, std::nullopt, - OverloadCandidateParamOrder::Reversed); + AddOverloadCandidate(FD, F.getPair(), + {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, + false, false, true, false, ADLCallKind::NotADL, {}, + OverloadCandidateParamOrder::Reversed); } } } @@ -10102,8 +10102,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, FD, FoundDecl, {Args[1], Args[0]}, CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, /*AllowExplicit=*/true, /*AllowExplicitConversion=*/false, - ADLCallKind::UsesADL, std::nullopt, - OverloadCandidateParamOrder::Reversed); + ADLCallKind::UsesADL, {}, OverloadCandidateParamOrder::Reversed); } } else { auto *FTD = cast(*I); @@ -15954,7 +15953,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context), - std::nullopt, CandidateSet, + {}, CandidateSet, /*SuppressUserConversion=*/false); } @@ -16149,8 +16148,7 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc, *CallExpr = ExprError(); return FRS_DiagnosticIssued; } - *CallExpr = - BuildCallExpr(S, MemberRef.get(), Loc, std::nullopt, Loc, nullptr); + *CallExpr = BuildCallExpr(S, MemberRef.get(), Loc, {}, Loc, nullptr); if (CallExpr->isInvalid()) { *CallExpr = ExprError(); return FRS_DiagnosticIssued; diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index 30ed47e6e56ec9ee550df0ecac3b50adc04d06ea..c9379d25f7805c4912241a77739bf14741f11785 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -746,11 +746,11 @@ ExprResult ObjCPropertyOpBuilder::buildGet() { assert(InstanceReceiver || RefExpr->isSuperReceiver()); msg = S.ObjC().BuildInstanceMessageImplicit( InstanceReceiver, receiverType, GenericLoc, Getter->getSelector(), - Getter, std::nullopt); + Getter, {}); } else { msg = S.ObjC().BuildClassMessageImplicit( receiverType, RefExpr->isSuperReceiver(), GenericLoc, - Getter->getSelector(), Getter, std::nullopt); + Getter->getSelector(), Getter, {}); } return msg; } @@ -1131,7 +1131,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { /*TInfo=*/nullptr, SC_None, nullptr); - AtIndexGetter->setMethodParams(S.Context, Argument, std::nullopt); + AtIndexGetter->setMethodParams(S.Context, Argument, {}); } if (!AtIndexGetter) { @@ -1243,7 +1243,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { SC_None, nullptr); Params.push_back(key); - AtIndexSetter->setMethodParams(S.Context, Params, std::nullopt); + AtIndexSetter->setMethodParams(S.Context, Params, {}); } if (!AtIndexSetter) { diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 9e235a46707cd4ddab463015e5078d1c350d2443..38ae6d8116c3bb04c4a6cd0e3ee965c3d5667b1d 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -390,7 +390,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) { // type of the left operand could be used for SFINAE, so technically it is // *used*. if (DiagID != diag::warn_unused_comma_left_operand || !isSFINAEContext()) - DiagIfReachable(Loc, S ? llvm::ArrayRef(S) : std::nullopt, + DiagIfReachable(Loc, S ? llvm::ArrayRef(S) : llvm::ArrayRef(), PDiag(DiagID) << R1 << R2); } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 62f13610b5285c2bf418b7cd7474785547286046..fcf05798d9c709c1f9062053dab4a1a17236d0bb 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2991,7 +2991,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( // Fabricate an empty template parameter list for the invented header. return TemplateParameterList::Create(Context, SourceLocation(), - SourceLocation(), std::nullopt, + SourceLocation(), {}, SourceLocation(), nullptr); } diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 3a87128a7db0fa23995ace8967083c8a3a81496f..698e0760d808fe684991b63f0caf60afcb6e69c4 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -1388,7 +1388,7 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, // additional function template derived as above from a hypothetical // constructor C(). if (!AddedAny) - Transform.buildSimpleDeductionGuide(std::nullopt); + Transform.buildSimpleDeductionGuide({}); // -- An additional function template derived as above from a hypothetical // constructor C(C), called the copy deduction candidate. diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 198442dd9821ec1915fce608f14a2475ee3ba699..6a55861fe5af3b1b729d64c0d3612887e5d8e318 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -732,8 +732,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( : InstantiatingTemplate( SemaRef, CodeSynthesisContext::RequirementInstantiation, PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, - /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt, &DeductionInfo) { -} + /*Template=*/nullptr, /*TemplateArgs=*/{}, &DeductionInfo) {} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -742,7 +741,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( : InstantiatingTemplate( SemaRef, CodeSynthesisContext::NestedRequirementConstraintsCheck, PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, - /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt) {} + /*Template=*/nullptr, /*TemplateArgs=*/{}) {} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, const RequiresExpr *RE, @@ -750,8 +749,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( : InstantiatingTemplate( SemaRef, CodeSynthesisContext::RequirementParameterInstantiation, PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, - /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt, &DeductionInfo) { -} + /*Template=*/nullptr, /*TemplateArgs=*/{}, &DeductionInfo) {} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index cf21b2a586572b354ff4558934d2c28d7887c409..e50a371e61f5af5c183f7610211f5fc1746d565f 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -803,7 +803,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, - /*DeclsInPrototype=*/std::nullopt, loc, loc, declarator)); + /*DeclsInPrototype=*/{}, loc, loc, declarator)); // For consistency, make sure the state still has us as processing // the decl spec. diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 3eed6da5543458e86b19b57670a7e193468a37f9..c6559d14270641fc3cda853f649e8e3c991f7c66 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3484,8 +3484,7 @@ public: ExprResult RebuildCXXScalarValueInitExpr(TypeSourceInfo *TSInfo, SourceLocation LParenLoc, SourceLocation RParenLoc) { - return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, std::nullopt, - RParenLoc, + return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, {}, RParenLoc, /*ListInitialization=*/false); } @@ -4304,13 +4303,13 @@ ExprResult TreeTransform::TransformInitializer(Expr *Init, // Revert value-initialization back to empty parens. if (CXXScalarValueInitExpr *VIE = dyn_cast(Init)) { SourceRange Parens = VIE->getSourceRange(); - return getDerived().RebuildParenListExpr(Parens.getBegin(), std::nullopt, + return getDerived().RebuildParenListExpr(Parens.getBegin(), {}, Parens.getEnd()); } // FIXME: We shouldn't build ImplicitValueInitExprs for direct-initialization. if (isa(Init)) - return getDerived().RebuildParenListExpr(SourceLocation(), std::nullopt, + return getDerived().RebuildParenListExpr(SourceLocation(), {}, SourceLocation()); // Revert initialization by constructor back to a parenthesized or braced list @@ -15661,7 +15660,7 @@ TreeTransform::TransformSizeOfPackExpr(SizeOfPackExpr *E) { return ExprError(); return getDerived().RebuildSizeOfPackExpr( E->getOperatorLoc(), Pack, E->getPackLoc(), E->getRParenLoc(), - std::nullopt, std::nullopt); + std::nullopt, {}); } // Try to compute the result without performing a partial substitution. @@ -15705,9 +15704,9 @@ TreeTransform::TransformSizeOfPackExpr(SizeOfPackExpr *E) { // Common case: we could determine the number of expansions without // substituting. if (Result) - return getDerived().RebuildSizeOfPackExpr( - E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(), - *Result, std::nullopt); + return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(), + E->getPackLoc(), + E->getRParenLoc(), *Result, {}); TemplateArgumentListInfo TransformedPackArgs(E->getPackLoc(), E->getPackLoc()); @@ -15738,7 +15737,7 @@ TreeTransform::TransformSizeOfPackExpr(SizeOfPackExpr *E) { return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(), - Args.size(), std::nullopt); + Args.size(), {}); } template @@ -15782,7 +15781,7 @@ TreeTransform::TransformPackIndexingExpr(PackIndexingExpr *E) { return ExprError(); return getDerived().RebuildPackIndexingExpr( E->getEllipsisLoc(), E->getRSquareLoc(), Pack.get(), IndexExpr.get(), - std::nullopt); + {}); } for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 18992a2bf4f552efd791902d31539ca0e5b686bc..3f9bb60d8fe818d72cd65e8ea22d7ca15a43b9b6 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -5756,6 +5756,14 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F, return Err; ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); + bool KnowsTopLevelModule = ModMap.findModule(F.ModuleName) != nullptr; + // If we don't know the top-level module, there's no point in doing qualified + // lookup of its submodules; it won't find anything anywhere within this tree. + // Let's skip that and avoid some string lookups. + auto CreateModule = !KnowsTopLevelModule + ? &ModuleMap::createModule + : &ModuleMap::findOrCreateModuleFirst; + bool First = true; Module *CurrentModule = nullptr; RecordData Record; @@ -5813,6 +5821,7 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F, SubmoduleID Parent = getGlobalSubmoduleID(F, Record[Idx++]); Module::ModuleKind Kind = (Module::ModuleKind)Record[Idx++]; SourceLocation DefinitionLoc = ReadSourceLocation(F, Record[Idx++]); + FileID InferredAllowedBy = ReadFileID(F, Record, Idx); bool IsFramework = Record[Idx++]; bool IsExplicit = Record[Idx++]; bool IsSystem = Record[Idx++]; @@ -5828,13 +5837,8 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F, if (Parent) ParentModule = getSubmodule(Parent); - // Retrieve this (sub)module from the module map, creating it if - // necessary. - CurrentModule = - ModMap.findOrCreateModule(Name, ParentModule, IsFramework, IsExplicit) - .first; - - // FIXME: Call ModMap.setInferredModuleAllowedBy() + CurrentModule = std::invoke(CreateModule, &ModMap, Name, ParentModule, + IsFramework, IsExplicit); SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS; if (GlobalIndex >= SubmodulesLoaded.size() || @@ -5866,6 +5870,8 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F, CurrentModule->DefinitionLoc = DefinitionLoc; CurrentModule->Signature = F.Signature; CurrentModule->IsFromModuleFile = true; + if (InferredAllowedBy.isValid()) + ModMap.setInferredModuleAllowedBy(CurrentModule, InferredAllowedBy); CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; CurrentModule->IsExternC = IsExternC; CurrentModule->InferSubmodules = InferSubmodules; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 6e88bd74dd9e5ffae8871e8ca9dbb9a06faa5f31..b66c1e8781465691ebe5e927e8008883f26545e7 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -2163,8 +2163,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) { continue; // We have no information on this being a header file. if (!HFI->isCompilingModuleHeader && HFI->isModuleHeader) continue; // Header file info is tracked by the owning module file. - if (!HFI->isCompilingModuleHeader && !PP->alreadyIncluded(*File)) - continue; // Non-modular header not included is not needed. + if (!HFI->isCompilingModuleHeader && !HFI->IsLocallyIncluded) + continue; // Header file info is tracked by the including module file. // Massage the file path into an appropriate form. StringRef Filename = File->getName(); @@ -2176,7 +2176,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) { SavedStrings.push_back(Filename.data()); } - bool Included = PP->alreadyIncluded(*File); + bool Included = HFI->IsLocallyIncluded || PP->alreadyIncluded(*File); HeaderFileInfoTrait::key_type Key = { Filename, File->getSize(), getTimestampForOutput(*File) @@ -2914,6 +2914,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 4)); // Kind Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Definition location + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // Inferred allowed by Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem @@ -3018,6 +3019,12 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { SourceLocationEncoding::RawLocEncoding DefinitionLoc = getRawSourceLocationEncoding(getAdjustedLocation(Mod->DefinitionLoc)); + ModuleMap &ModMap = PP->getHeaderSearchInfo().getModuleMap(); + FileID UnadjustedInferredFID; + if (Mod->IsInferred) + UnadjustedInferredFID = ModMap.getModuleMapFileIDForUniquing(Mod); + int InferredFID = getAdjustedFileID(UnadjustedInferredFID).getOpaqueValue(); + // Emit the definition of the block. { RecordData::value_type Record[] = {SUBMODULE_DEFINITION, @@ -3025,6 +3032,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { ParentID, (RecordData::value_type)Mod->Kind, DefinitionLoc, + (RecordData::value_type)InferredFID, Mod->IsFramework, Mod->IsExplicit, Mod->IsSystem, @@ -3070,9 +3078,9 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Module::HK_PrivateTextual}, {SUBMODULE_EXCLUDED_HEADER, ExcludedHeaderAbbrev, Module::HK_Excluded} }; - for (auto &HL : HeaderLists) { + for (const auto &HL : HeaderLists) { RecordData::value_type Record[] = {HL.RecordKind}; - for (auto &H : Mod->Headers[HL.HeaderKind]) + for (const auto &H : Mod->getHeaders(HL.HeaderKind)) Stream.EmitRecordWithBlob(HL.Abbrev, Record, H.NameAsWritten); } diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index f21cbd11b6ab8955c8ffc74ef5ce611395ee36cf..b5fe16bf6e787b410cd5da4ad1e46ace901e6241 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -207,7 +207,7 @@ namespace clang { return Common->PartialSpecializations; } ArrayRef getPartialSpecializations(FunctionTemplateDecl::Common *) { - return std::nullopt; + return {}; } template diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt index 6da3665ab9a4dfc05a86adea5781e4faa7f6cc78..62aa5ff7f002a9763efc5600501a98ed7e23da15 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -91,8 +91,6 @@ add_clang_library(clangStaticAnalyzerCheckers OSObjectCStyleCast.cpp PaddingChecker.cpp PointerArithChecker.cpp - PointerIterationChecker.cpp - PointerSortingChecker.cpp PointerSubChecker.cpp PthreadLockChecker.cpp PutenvStackArrayChecker.cpp diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerIterationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerIterationChecker.cpp deleted file mode 100644 index 895b2160b76a7b0ae8e32e903d0a0598ddcc1d7e..0000000000000000000000000000000000000000 --- a/clang/lib/StaticAnalyzer/Checkers/PointerIterationChecker.cpp +++ /dev/null @@ -1,101 +0,0 @@ -//== PointerIterationChecker.cpp ------------------------------- -*- C++ -*--=// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines PointerIterationChecker which checks for non-determinism -// caused due to iteration of unordered containers of pointer elements. -// -//===----------------------------------------------------------------------===// - -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" -#include "clang/StaticAnalyzer/Core/Checker.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" - -using namespace clang; -using namespace ento; -using namespace ast_matchers; - -namespace { - -// ID of a node at which the diagnostic would be emitted. -constexpr llvm::StringLiteral WarnAtNode = "iter"; - -class PointerIterationChecker : public Checker { -public: - void checkASTCodeBody(const Decl *D, - AnalysisManager &AM, - BugReporter &BR) const; -}; - -static void emitDiagnostics(const BoundNodes &Match, const Decl *D, - BugReporter &BR, AnalysisManager &AM, - const PointerIterationChecker *Checker) { - auto *ADC = AM.getAnalysisDeclContext(D); - - const auto *MarkedStmt = Match.getNodeAs(WarnAtNode); - assert(MarkedStmt); - - auto Range = MarkedStmt->getSourceRange(); - auto Location = PathDiagnosticLocation::createBegin(MarkedStmt, - BR.getSourceManager(), - ADC); - std::string Diagnostics; - llvm::raw_string_ostream OS(Diagnostics); - OS << "Iteration of pointer-like elements " - << "can result in non-deterministic ordering"; - - BR.EmitBasicReport(ADC->getDecl(), Checker, - "Iteration of pointer-like elements", "Non-determinism", - Diagnostics, Location, Range); -} - -// Assumption: Iteration of ordered containers of pointers is deterministic. - -// TODO: Currently, we only check for std::unordered_set. Other unordered -// containers like std::unordered_map also need to be handled. - -// TODO: Currently, we do not check what the for loop does with the iterated -// pointer values. Not all iterations may cause non-determinism. For example, -// counting or summing up the elements should not be non-deterministic. - -auto matchUnorderedIterWithPointers() -> decltype(decl()) { - - auto UnorderedContainerM = declRefExpr(to(varDecl(hasType( - recordDecl(hasName("std::unordered_set") - ))))); - - auto PointerTypeM = varDecl(hasType(hasCanonicalType(pointerType()))); - - auto PointerIterM = stmt(cxxForRangeStmt( - hasLoopVariable(PointerTypeM), - hasRangeInit(UnorderedContainerM) - )).bind(WarnAtNode); - - return decl(forEachDescendant(PointerIterM)); -} - -void PointerIterationChecker::checkASTCodeBody(const Decl *D, - AnalysisManager &AM, - BugReporter &BR) const { - auto MatcherM = matchUnorderedIterWithPointers(); - - auto Matches = match(MatcherM, *D, AM.getASTContext()); - for (const auto &Match : Matches) - emitDiagnostics(Match, D, BR, AM, this); -} - -} // end of anonymous namespace - -void ento::registerPointerIterationChecker(CheckerManager &Mgr) { - Mgr.registerChecker(); -} - -bool ento::shouldRegisterPointerIterationChecker(const CheckerManager &mgr) { - const LangOptions &LO = mgr.getLangOpts(); - return LO.CPlusPlus; -} diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp deleted file mode 100644 index 25d87f4acfc910c9216822c652b50402bc674d93..0000000000000000000000000000000000000000 --- a/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp +++ /dev/null @@ -1,115 +0,0 @@ -//== PointerSortingChecker.cpp --------------------------------- -*- C++ -*--=// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines PointerSortingChecker which checks for non-determinism -// caused due to sorting containers with pointer-like elements. -// -//===----------------------------------------------------------------------===// - -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" -#include "clang/StaticAnalyzer/Core/Checker.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" - -using namespace clang; -using namespace ento; -using namespace ast_matchers; - -namespace { - -// ID of a node at which the diagnostic would be emitted. -constexpr llvm::StringLiteral WarnAtNode = "sort"; - -class PointerSortingChecker : public Checker { -public: - void checkASTCodeBody(const Decl *D, - AnalysisManager &AM, - BugReporter &BR) const; -}; - -static void emitDiagnostics(const BoundNodes &Match, const Decl *D, - BugReporter &BR, AnalysisManager &AM, - const PointerSortingChecker *Checker) { - auto *ADC = AM.getAnalysisDeclContext(D); - - const auto *MarkedStmt = Match.getNodeAs(WarnAtNode); - assert(MarkedStmt); - - auto Range = MarkedStmt->getSourceRange(); - auto Location = PathDiagnosticLocation::createBegin(MarkedStmt, - BR.getSourceManager(), - ADC); - std::string Diagnostics; - llvm::raw_string_ostream OS(Diagnostics); - OS << "Sorting pointer-like elements " - << "can result in non-deterministic ordering"; - - BR.EmitBasicReport(ADC->getDecl(), Checker, - "Sorting of pointer-like elements", "Non-determinism", - OS.str(), Location, Range); -} - -decltype(auto) callsName(const char *FunctionName) { - return callee(functionDecl(hasName(FunctionName))); -} - -// FIXME: Currently we simply check if std::sort is used with pointer-like -// elements. This approach can have a big false positive rate. Using std::sort, -// std::unique and then erase is common technique for deduplicating a container -// (which in some cases might even be quicker than using, let's say std::set). -// In case a container contains arbitrary memory addresses (e.g. multiple -// things give different stuff but might give the same thing multiple times) -// which we don't want to do things with more than once, we might use -// sort-unique-erase and the sort call will emit a report. -auto matchSortWithPointers() -> decltype(decl()) { - // Match any of these function calls. - auto SortFuncM = anyOf( - callsName("std::is_sorted"), - callsName("std::nth_element"), - callsName("std::partial_sort"), - callsName("std::partition"), - callsName("std::sort"), - callsName("std::stable_partition"), - callsName("std::stable_sort") - ); - - // Match only if the container has pointer-type elements. - auto IteratesPointerEltsM = hasArgument(0, - hasType(cxxRecordDecl(has( - fieldDecl(hasType(hasCanonicalType( - pointsTo(hasCanonicalType(pointerType())) - ))) - )))); - - auto PointerSortM = traverse( - TK_AsIs, - stmt(callExpr(allOf(SortFuncM, IteratesPointerEltsM))).bind(WarnAtNode)); - - return decl(forEachDescendant(PointerSortM)); -} - -void PointerSortingChecker::checkASTCodeBody(const Decl *D, - AnalysisManager &AM, - BugReporter &BR) const { - auto MatcherM = matchSortWithPointers(); - - auto Matches = match(MatcherM, *D, AM.getASTContext()); - for (const auto &Match : Matches) - emitDiagnostics(Match, D, BR, AM, this); -} - -} // end of anonymous namespace - -void ento::registerPointerSortingChecker(CheckerManager &Mgr) { - Mgr.registerChecker(); -} - -bool ento::shouldRegisterPointerSortingChecker(const CheckerManager &mgr) { - const LangOptions &LO = mgr.getLangOpts(); - return LO.CPlusPlus; -} diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index b7b2f8a16f07b31cd1a13c3093408c9aa185ba7b..9d34dfd3cea636b1bed826c713c1c2fabad7144e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -17,6 +17,10 @@ namespace clang { +bool isSafePtr(clang::CXXRecordDecl *Decl) { + return isRefCounted(Decl) || isCheckedPtr(Decl); +} + bool tryToFindPtrOrigin( const Expr *E, bool StopAtFirstRefCountedObj, std::function callback) { @@ -31,7 +35,7 @@ bool tryToFindPtrOrigin( } if (auto *tempExpr = dyn_cast(E)) { if (auto *C = tempExpr->getConstructor()) { - if (auto *Class = C->getParent(); Class && isRefCounted(Class)) + if (auto *Class = C->getParent(); Class && isSafePtr(Class)) return callback(E, true); break; } @@ -56,7 +60,7 @@ bool tryToFindPtrOrigin( if (StopAtFirstRefCountedObj) { if (auto *ConversionFunc = dyn_cast_or_null(cast->getConversionFunction())) { - if (isCtorOfRefCounted(ConversionFunc)) + if (isCtorOfSafePtr(ConversionFunc)) return callback(E, true); } } @@ -68,7 +72,7 @@ bool tryToFindPtrOrigin( if (auto *call = dyn_cast(E)) { if (auto *memberCall = dyn_cast(call)) { if (auto *decl = memberCall->getMethodDecl()) { - std::optional IsGetterOfRefCt = isGetterOfRefCounted(decl); + std::optional IsGetterOfRefCt = isGetterOfSafePtr(decl); if (IsGetterOfRefCt && *IsGetterOfRefCt) { E = memberCall->getImplicitObjectArgument(); if (StopAtFirstRefCountedObj) { @@ -87,7 +91,7 @@ bool tryToFindPtrOrigin( } if (auto *callee = call->getDirectCallee()) { - if (isCtorOfRefCounted(callee)) { + if (isCtorOfRefCounted(callee) || isCtorOfCheckedPtr(callee)) { if (StopAtFirstRefCountedObj) return callback(E, true); @@ -95,7 +99,7 @@ bool tryToFindPtrOrigin( continue; } - if (isRefType(callee->getReturnType())) + if (isSafePtrType(callee->getReturnType())) return callback(E, true); if (isSingleton(callee)) @@ -114,7 +118,7 @@ bool tryToFindPtrOrigin( } if (auto *ObjCMsgExpr = dyn_cast(E)) { if (auto *Method = ObjCMsgExpr->getMethodDecl()) { - if (isRefType(Method->getReturnType())) + if (isSafePtrType(Method->getReturnType())) return callback(E, true); } } diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index e043806eadd6ac7dd69a952a658d702c5542d28b..2293dcf1d4bd6432261144c6a7a408f9b7b100c5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -135,7 +135,16 @@ bool isCtorOfRefCounted(const clang::FunctionDecl *F) { || FunctionName == "Identifier"; } -bool isRefType(const clang::QualType T) { +bool isCtorOfCheckedPtr(const clang::FunctionDecl *F) { + assert(F); + return isCheckedPtr(safeGetName(F)); +} + +bool isCtorOfSafePtr(const clang::FunctionDecl *F) { + return isCtorOfRefCounted(F) || isCtorOfCheckedPtr(F); +} + +bool isSafePtrType(const clang::QualType T) { QualType type = T; while (!type.isNull()) { if (auto *elaboratedT = type->getAs()) { @@ -145,7 +154,7 @@ bool isRefType(const clang::QualType T) { if (auto *specialT = type->getAs()) { if (auto *decl = specialT->getTemplateName().getAsTemplateDecl()) { auto name = decl->getNameAsString(); - return isRefType(name); + return isRefType(name) || isCheckedPtr(name); } return false; } @@ -177,6 +186,12 @@ std::optional isUncounted(const CXXRecordDecl* Class) return (*IsRefCountable); } +std::optional isUnchecked(const CXXRecordDecl *Class) { + if (isCheckedPtr(Class)) + return false; // Cheaper than below + return isCheckedPtrCapable(Class); +} + std::optional isUncountedPtr(const QualType T) { if (T->isPointerType() || T->isReferenceType()) { if (auto *CXXRD = T->getPointeeCXXRecordDecl()) @@ -185,8 +200,16 @@ std::optional isUncountedPtr(const QualType T) { return false; } -std::optional isGetterOfRefCounted(const CXXMethodDecl* M) -{ +std::optional isUnsafePtr(const QualType T) { + if (T->isPointerType() || T->isReferenceType()) { + if (auto *CXXRD = T->getPointeeCXXRecordDecl()) { + return isUncounted(CXXRD) || isUnchecked(CXXRD); + } + } + return false; +} + +std::optional isGetterOfSafePtr(const CXXMethodDecl *M) { assert(M); if (isa(M)) { @@ -194,6 +217,9 @@ std::optional isGetterOfRefCounted(const CXXMethodDecl* M) auto className = safeGetName(calleeMethodsClass); auto method = safeGetName(M); + if (isCheckedPtr(className) && (method == "get" || method == "ptr")) + return true; + if ((isRefType(className) && (method == "get" || method == "ptr")) || ((className == "String" || className == "AtomString" || className == "AtomStringImpl" || className == "UniqueString" || @@ -205,7 +231,12 @@ std::optional isGetterOfRefCounted(const CXXMethodDecl* M) // FIXME: Currently allowing any Ref -> whatever cast. if (isRefType(className)) { if (auto *maybeRefToRawOperator = dyn_cast(M)) - return isUncountedPtr(maybeRefToRawOperator->getConversionType()); + return isUnsafePtr(maybeRefToRawOperator->getConversionType()); + } + + if (isCheckedPtr(className)) { + if (auto *maybeRefToRawOperator = dyn_cast(M)) + return isUnsafePtr(maybeRefToRawOperator->getConversionType()); } } return false; @@ -414,7 +445,8 @@ public: Name == "isMainThreadOrGCThread" || Name == "isMainRunLoop" || Name == "isWebThread" || Name == "isUIThread" || Name == "mayBeGCThread" || Name == "compilerFenceForCrash" || - Name == "bitwise_cast" || Name.find("__builtin") == 0) + Name == "bitwise_cast" || Name.find("__builtin") == 0 || + Name == "__libcpp_verbose_abort") return true; return IsFunctionTrivial(Callee); @@ -447,7 +479,7 @@ public: if (!Callee) return false; - std::optional IsGetterOfRefCounted = isGetterOfRefCounted(Callee); + std::optional IsGetterOfRefCounted = isGetterOfSafePtr(Callee); if (IsGetterOfRefCounted && *IsGetterOfRefCounted) return true; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h index 8e6aadf63b6d67911d647e61f280d746b1c0ac98..4b41ca96e1df1d3b1331121bae42b94781b89774 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h @@ -63,18 +63,30 @@ std::optional isUncounted(const clang::CXXRecordDecl* Class); /// class, false if not, std::nullopt if inconclusive. std::optional isUncountedPtr(const clang::QualType T); -/// \returns true if Name is a RefPtr, Ref, or its variant, false if not. -bool isRefType(const std::string &Name); +/// \returns true if \p T is a RefPtr, Ref, CheckedPtr, CheckedRef, or its +/// variant, false if not. +bool isSafePtrType(const clang::QualType T); /// \returns true if \p F creates ref-countable object from uncounted parameter, /// false if not. bool isCtorOfRefCounted(const clang::FunctionDecl *F); -/// \returns true if \p T is RefPtr, Ref, or its variant, false if not. -bool isRefType(const clang::QualType T); +/// \returns true if \p F creates checked ptr object from uncounted parameter, +/// false if not. +bool isCtorOfCheckedPtr(const clang::FunctionDecl *F); + +/// \returns true if \p F creates ref-countable or checked ptr object from +/// uncounted parameter, false if not. +bool isCtorOfSafePtr(const clang::FunctionDecl *F); + +/// \returns true if \p Name is RefPtr, Ref, or its variant, false if not. +bool isRefType(const std::string &Name); + +/// \returns true if \p Name is CheckedRef or CheckedPtr, false if not. +bool isCheckedPtr(const std::string &Name); /// \returns true if \p M is getter of a ref-counted class, false if not. -std::optional isGetterOfRefCounted(const clang::CXXMethodDecl* Method); +std::optional isGetterOfSafePtr(const clang::CXXMethodDecl *Method); /// \returns true if \p F is a conversion between ref-countable or ref-counted /// pointer types. diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp index cea3503fa2c314d4ed7d63d65e75e71ccdacfb88..1a5a7309a54f16729775ae6a416518d5b42c951f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp @@ -96,6 +96,8 @@ public: auto name = safeGetName(MD); if (name == "ref" || name == "deref") return; + if (name == "incrementPtrCount" || name == "decrementPtrCount") + return; } auto *E = MemberCallExpr->getImplicitObjectArgument(); QualType ArgType = MemberCallExpr->getObjectType().getCanonicalType(); diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp index 81d21100de878db61083779c56f5fcba108d21f2..5cdf047738abcb2cfa9fc542a3b5bdadbccf0ac4 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp @@ -227,6 +227,7 @@ public: if (MaybeGuardianArgCXXRecord) { if (MaybeGuardian->isLocalVarDecl() && (isRefCounted(MaybeGuardianArgCXXRecord) || + isCheckedPtr(MaybeGuardianArgCXXRecord) || isRefcountedStringsHack(MaybeGuardian)) && isGuardedScopeEmbeddedInGuardianScope( V, MaybeGuardian)) diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 1efac6ac1c57f427456a9f0db13f748a8fc943bd..0fdef7487b981439ee4265998b15c3cc33c035a5 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -554,7 +554,7 @@ std::optional CallEvent::getReturnValueUnderConstruction() const { ArrayRef AnyFunctionCall::parameters() const { const FunctionDecl *D = getDecl(); if (!D) - return std::nullopt; + return {}; return D->parameters(); } @@ -711,18 +711,17 @@ void CXXInstanceCall::getExtraInvalidatedValues( if (const auto *D = cast_or_null(getDecl())) { if (!D->isConst()) return; - // Get the record decl for the class of 'This'. D->getParent() may return a - // base class decl, rather than the class of the instance which needs to be - // checked for mutable fields. - // TODO: We might as well look at the dynamic type of the object. - const Expr *Ex = getCXXThisExpr()->IgnoreParenBaseCasts(); - QualType T = Ex->getType(); - if (T->isPointerType()) // Arrow or implicit-this syntax? - T = T->getPointeeType(); - const CXXRecordDecl *ParentRecord = T->getAsCXXRecordDecl(); - assert(ParentRecord); + + // Get the record decl for the class of 'This'. D->getParent() may return + // a base class decl, rather than the class of the instance which needs to + // be checked for mutable fields. + const CXXRecordDecl *ParentRecord = getDeclForDynamicType().first; + if (!ParentRecord || !ParentRecord->hasDefinition()) + return; + if (ParentRecord->hasMutableFields()) return; + // Preserve CXXThis. const MemRegion *ThisRegion = ThisVal.getAsRegion(); if (!ThisRegion) @@ -748,6 +747,21 @@ SVal CXXInstanceCall::getCXXThisVal() const { return ThisVal; } +std::pair +CXXInstanceCall::getDeclForDynamicType() const { + const MemRegion *R = getCXXThisVal().getAsRegion(); + if (!R) + return {}; + + DynamicTypeInfo DynType = getDynamicTypeInfo(getState(), R); + if (!DynType.isValid()) + return {}; + + assert(!DynType.getType()->getPointeeType().isNull()); + return {DynType.getType()->getPointeeCXXRecordDecl(), + DynType.canBeASubClass()}; +} + RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { // Do we have a decl at all? const Decl *D = getDecl(); @@ -759,21 +773,7 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { if (!MD->isVirtual()) return AnyFunctionCall::getRuntimeDefinition(); - // Do we know the implicit 'this' object being called? - const MemRegion *R = getCXXThisVal().getAsRegion(); - if (!R) - return {}; - - // Do we know anything about the type of 'this'? - DynamicTypeInfo DynType = getDynamicTypeInfo(getState(), R); - if (!DynType.isValid()) - return {}; - - // Is the type a C++ class? (This is mostly a defensive check.) - QualType RegionType = DynType.getType()->getPointeeType(); - assert(!RegionType.isNull() && "DynamicTypeInfo should always be a pointer."); - - const CXXRecordDecl *RD = RegionType->getAsCXXRecordDecl(); + auto [RD, CanBeSubClass] = getDeclForDynamicType(); if (!RD || !RD->hasDefinition()) return {}; @@ -800,7 +800,7 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { // Does the decl that we found have an implementation? const FunctionDecl *Definition; if (!Result->hasBody(Definition)) { - if (!DynType.canBeASubClass()) + if (!CanBeSubClass) return AnyFunctionCall::getRuntimeDefinition(); return {}; } @@ -808,8 +808,9 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { // We found a definition. If we're not sure that this devirtualization is // actually what will happen at runtime, make sure to provide the region so // that ExprEngine can decide what to do with it. - if (DynType.canBeASubClass()) - return RuntimeDefinition(Definition, R->StripCasts()); + if (CanBeSubClass) + return RuntimeDefinition(Definition, + getCXXThisVal().getAsRegion()->StripCasts()); return RuntimeDefinition(Definition, /*DispatchRegion=*/nullptr); } @@ -884,7 +885,7 @@ const BlockDataRegion *BlockCall::getBlockRegion() const { ArrayRef BlockCall::parameters() const { const BlockDecl *D = getDecl(); if (!D) - return std::nullopt; + return {}; return D->parameters(); } @@ -981,7 +982,7 @@ RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const { ArrayRef ObjCMethodCall::parameters() const { const ObjCMethodDecl *D = getDecl(); if (!D) - return std::nullopt; + return {}; return D->parameters(); } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index c50db1e0e2f863e30e6736daa5adffbcbcf4c0fc..ccc3097e8d2f971cfe092c3c5deae2176634a79f 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -513,70 +513,25 @@ ProgramStateRef ExprEngine::updateObjectsUnderConstruction( static ProgramStateRef bindRequiredArrayElementToEnvironment(ProgramStateRef State, const ArrayInitLoopExpr *AILE, - const LocationContext *LCtx, SVal Idx) { - // The ctor in this case is guaranteed to be a copy ctor, otherwise we hit a - // compile time error. - // - // -ArrayInitLoopExpr <-- we're here - // |-OpaqueValueExpr - // | `-DeclRefExpr <-- match this - // `-CXXConstructExpr - // `-ImplicitCastExpr - // `-ArraySubscriptExpr - // |-ImplicitCastExpr - // | `-OpaqueValueExpr - // | `-DeclRefExpr - // `-ArrayInitIndexExpr - // - // The resulting expression might look like the one below in an implicit - // copy/move ctor. - // - // ArrayInitLoopExpr <-- we're here - // |-OpaqueValueExpr - // | `-MemberExpr <-- match this - // | (`-CXXStaticCastExpr) <-- move ctor only - // | `-DeclRefExpr - // `-CXXConstructExpr - // `-ArraySubscriptExpr - // |-ImplicitCastExpr - // | `-OpaqueValueExpr - // | `-MemberExpr - // | `-DeclRefExpr - // `-ArrayInitIndexExpr - // - // The resulting expression for a multidimensional array. - // ArrayInitLoopExpr <-- we're here - // |-OpaqueValueExpr - // | `-DeclRefExpr <-- match this - // `-ArrayInitLoopExpr - // |-OpaqueValueExpr - // | `-ArraySubscriptExpr - // | |-ImplicitCastExpr - // | | `-OpaqueValueExpr - // | | `-DeclRefExpr - // | `-ArrayInitIndexExpr - // `-CXXConstructExpr <-- extract this - // ` ... - - const auto *OVESrc = AILE->getCommonExpr()->getSourceExpr(); + const LocationContext *LCtx, NonLoc Idx) { + SValBuilder &SVB = State->getStateManager().getSValBuilder(); + MemRegionManager &MRMgr = SVB.getRegionManager(); + ASTContext &Ctx = SVB.getContext(); // HACK: There is no way we can put the index of the array element into the // CFG unless we unroll the loop, so we manually select and bind the required // parameter to the environment. - const auto *CE = + const Expr *SourceArray = AILE->getCommonExpr()->getSourceExpr(); + const auto *Ctor = cast(extractElementInitializerFromNestedAILE(AILE)); - SVal Base = UnknownVal(); - if (const auto *ME = dyn_cast(OVESrc)) - Base = State->getSVal(ME, LCtx); - else if (const auto *DRE = dyn_cast(OVESrc)) - Base = State->getLValue(cast(DRE->getDecl()), LCtx); - else - llvm_unreachable("ArrayInitLoopExpr contains unexpected source expression"); - - SVal NthElem = State->getLValue(CE->getType(), Idx, Base); + const auto *SourceArrayRegion = + cast(State->getSVal(SourceArray, LCtx).getAsRegion()); + const ElementRegion *ElementRegion = + MRMgr.getElementRegion(Ctor->getType(), Idx, SourceArrayRegion, Ctx); - return State->BindExpr(CE->getArg(0), LCtx, NthElem); + return State->BindExpr(Ctor->getArg(0), LCtx, + loc::MemRegionVal(ElementRegion)); } void ExprEngine::handleConstructor(const Expr *E, diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index 693791c3aee8b99f82ef4378c04ee12400b596a7..02d1358a2001ef47c5ac9682befea963780c351b 100644 --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -722,6 +722,13 @@ std::string MemRegion::getDescriptiveName(bool UseQuotes) const { SmallString<50> buf; llvm::raw_svector_ostream os(buf); + // Enclose subject with single quotes if needed. + auto QuoteIfNeeded = [UseQuotes](const Twine &Subject) -> std::string { + if (UseQuotes) + return ("'" + Subject + "'").str(); + return Subject.str(); + }; + // Obtain array indices to add them to the variable name. const ElementRegion *ER = nullptr; while ((ER = R->getAs())) { @@ -751,12 +758,20 @@ std::string MemRegion::getDescriptiveName(bool UseQuotes) const { } // Get variable name. - if (R && R->canPrintPrettyAsExpr()) { - R->printPrettyAsExpr(os); - if (UseQuotes) - return (llvm::Twine("'") + os.str() + ArrayIndices + "'").str(); - else - return (llvm::Twine(os.str()) + ArrayIndices).str(); + if (R) { + // MemRegion can be pretty printed. + if (R->canPrintPrettyAsExpr()) { + R->printPrettyAsExpr(os); + return QuoteIfNeeded(llvm::Twine(os.str()) + ArrayIndices); + } + + // FieldRegion may have ElementRegion as SuperRegion. + if (const auto *FR = R->getAs()) { + std::string Super = FR->getSuperRegion()->getDescriptiveName(false); + if (Super.empty()) + return ""; + return QuoteIfNeeded(Super + "." + FR->getDecl()->getName()); + } } return VariableName; @@ -1079,7 +1094,7 @@ const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D, T = getContext().VoidTy; if (!T->getAs()) { FunctionProtoType::ExtProtoInfo Ext; - T = getContext().getFunctionType(T, std::nullopt, Ext); + T = getContext().getFunctionType(T, {}, Ext); } T = getContext().getBlockPointerType(T); diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp index 77f9d07175c2c15d4e5059bad61dbb3961736d74..637416cd1fc621f845a289ac59be71340e3bf809 100644 --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -587,9 +587,7 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { ModuleMap &ModMapInfo = MDC.ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); - OptionalFileEntryRef ModuleMap = ModMapInfo.getModuleMapFileForUniquing(M); - - if (ModuleMap) { + if (auto ModuleMap = ModMapInfo.getModuleMapFileForUniquing(M)) { SmallString<128> Path = ModuleMap->getNameAsRequested(); ModMapInfo.canonicalizeModuleMapPath(Path); MD.ClangModuleMapFile = std::string(Path); @@ -601,15 +599,13 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { MDC.ScanInstance.getASTReader()->visitInputFileInfos( *MF, /*IncludeSystem=*/true, [&](const serialization::InputFileInfo &IFI, bool IsSystem) { - // __inferred_module.map is the result of the way in which an implicit - // module build handles inferred modules. It adds an overlay VFS with - // this file in the proper directory and relies on the rest of Clang to - // handle it like normal. With explicitly built modules we don't need - // to play VFS tricks, so replace it with the correct module map. - if (StringRef(IFI.Filename).ends_with("__inferred_module.map")) { - MDC.addFileDep(MD, ModuleMap->getName()); + // The __inferred_module.map file is an insignificant implementation + // detail of implicitly-built modules. The PCM will also report the + // actual on-disk module map file that allowed inferring the module, + // which is what we need for building the module explicitly + // Let's ignore this file. + if (StringRef(IFI.Filename).ends_with("__inferred_module.map")) return; - } MDC.addFileDep(MD, IFI.Filename); }); diff --git a/clang/test/AST/ByteCode/placement-new.cpp b/clang/test/AST/ByteCode/placement-new.cpp index 5673b5cba3f700b82382d31a4fcb868141532cee..56f54ff168f3e858b5797eefea78450581ca5422 100644 --- a/clang/test/AST/ByteCode/placement-new.cpp +++ b/clang/test/AST/ByteCode/placement-new.cpp @@ -14,7 +14,9 @@ namespace std { template constexpr void construct_at(void *p, Args &&...args) { new (p) T((Args&&)args...); // both-note {{in call to}} \ - // both-note {{placement new would change type of storage from 'int' to 'float'}} + // both-note {{placement new would change type of storage from 'int' to 'float'}} \ + // both-note {{construction of subobject of member 'x' of union with active member 'a' is not allowed in a constant expression}} + } } @@ -284,6 +286,18 @@ namespace ConstructAt { static_assert(bad_construct_at_type()); // both-error {{not an integral constant expression}} \ // both-note {{in call}} + constexpr bool bad_construct_at_subobject() { + struct X { int a, b; }; + union A { + int a; + X x; + }; + A a = {1}; + std::construct_at(&a.x.a, 1); // both-note {{in call}} + return true; + } + static_assert(bad_construct_at_subobject()); // both-error{{not an integral constant expression}} \ + // both-note {{in call}} } namespace UsedToCrash { diff --git a/clang/test/AST/HLSL/RWStructuredBuffer-AST.hlsl b/clang/test/AST/HLSL/RWStructuredBuffer-AST.hlsl new file mode 100644 index 0000000000000000000000000000000000000000..f95d74b30acded0ae3f168504cb460fdcab19fec --- /dev/null +++ b/clang/test/AST/HLSL/RWStructuredBuffer-AST.hlsl @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY %s | FileCheck -check-prefix=EMPTY %s +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump %s | FileCheck %s + + +// This test tests two different AST generations. The "EMPTY" test mode verifies +// the AST generated by forward declaration of the HLSL types which happens on +// initializing the HLSL external AST with an AST Context. + +// The non-empty mode has a use that requires the RWStructuredBuffer type be complete, +// which results in the AST being populated by the external AST source. That +// case covers the full implementation of the template declaration and the +// instantiated specialization. + +// EMPTY: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <> implicit RWStructuredBuffer +// EMPTY-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <> class depth 0 index 0 element_type +// EMPTY-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <> implicit class RWStructuredBuffer +// EMPTY-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <> Implicit final + +// There should be no more occurrances of RWStructuredBuffer +// EMPTY-NOT: {{[^[:alnum:]]}}RWStructuredBuffer + +#ifndef EMPTY + +RWStructuredBuffer Buffer; + +#endif + +// CHECK: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <> implicit RWStructuredBuffer +// CHECK-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <> class depth 0 index 0 element_type +// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <> implicit class RWStructuredBuffer definition + +// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <> Implicit final +// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <> implicit h '__hlsl_resource_t +// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] +// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]] +// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]] +// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <> Implicit TypedBuffer + +// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <> operator[] 'element_type &const (unsigned int) const' +// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <> Idx 'unsigned int' +// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <> +// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <> +// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <> 'const RWStructuredBuffer' lvalue implicit this +// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <> Implicit always_inline + +// CHECK-NEXT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <> operator[] 'element_type &(unsigned int)' +// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <> Idx 'unsigned int' +// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <> +// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <> +// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}} +// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <> 'RWStructuredBuffer' lvalue implicit this +// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <> Implicit always_inline + +// CHECK: ClassTemplateSpecializationDecl 0x{{[0-9A-Fa-f]+}} <> class RWStructuredBuffer definition + +// CHECK: TemplateArgument type 'int' +// CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'int' +// CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <> Implicit final +// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <> implicit h '__hlsl_resource_t +// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] +// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]] +// CHECK-SAME{LITERAL}: [[hlsl::contained_type(int)]] +// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <> Implicit TypedBuffer diff --git a/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl index 030fcfc31691dc244eb5ecaa73ba5abb8d6fa636..6c39be8ba519f90574d84ce1ae6e80452920b1a9 100644 --- a/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl +++ b/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl @@ -17,7 +17,7 @@ // EMPTY-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <> Implicit final // There should be no more occurrances of StructuredBuffer -// EMPTY-NOT: StructuredBuffer +// EMPTY-NOT: {{[^[:alnum:]]}}StructuredBuffer #ifndef EMPTY @@ -31,7 +31,7 @@ StructuredBuffer Buffer; // CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <> Implicit final // CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <> implicit h '__hlsl_resource_t -// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] +// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]] // CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]] // CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]] // CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <> Implicit TypedBuffer @@ -58,7 +58,7 @@ StructuredBuffer Buffer; // CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float' // CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <> Implicit final // CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <> implicit h '__hlsl_resource_t -// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] +// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]] // CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]] // CHECK-SAME{LITERAL}: [[hlsl::contained_type(float)]] // CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <> Implicit TypedBuffer diff --git a/clang/test/AST/arm-mfp8.cpp b/clang/test/AST/arm-mfp8.cpp new file mode 100644 index 0000000000000000000000000000000000000000..51bebba067eb9f60154be3be79f2df589b6d018c --- /dev/null +++ b/clang/test/AST/arm-mfp8.cpp @@ -0,0 +1,91 @@ +// RUN: %clang_cc1 -std=c++11 -triple aarch64-arm-none-eabi -target-feature -fp8 -ast-dump %s | \ +// RUN: FileCheck %s --strict-whitespace + +// REQUIRES: aarch64-registered-target || arm-registered-target + +/* Various contexts where type __mfp8 can appear. */ + +#include +/* Namespace */ +namespace { + __mfp8 f2n; + __mfp8 arr1n[10]; +} + +//CHECK: |-NamespaceDecl {{.*}} +//CHECK-NEXT: | |-VarDecl {{.*}} f2n '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | `-VarDecl {{.*}} arr1n '__mfp8[10]' + + + const __mfp8 func1n(const __mfp8 mfp8) { + // this should fail + __mfp8 f1n; + f1n = mfp8; + return f1n; + } +//CHECK: |-FunctionDecl {{.*}} func1n 'const __mfp8 (const __mfp8)' +//CHECK: | `-VarDecl {{.*}} f1n '__mfp8':'__MFloat8_t' +//CHECK-NEXT: |-BinaryOperator {{.*}} '__mfp8':'__MFloat8_t' lvalue '=' +//CHECK-NEXT: | |-DeclRefExpr {{.*}} '__mfp8':'__MFloat8_t' lvalue Var {{.*}} 'f1n' '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | `-DeclRefExpr {{.*}} 'const __mfp8':'const __MFloat8_t' lvalue ParmVar {{.*}} 'mfp8' 'const __mfp8':'const __MFloat8_t' +//CHECK-NEXT: `-ReturnStmt {{.*}} +//CHECK-NEXT: `-ImplicitCastExpr {{.*}} '__mfp8':'__MFloat8_t' +//CHECK-NEXT: `-DeclRefExpr {{.*}} '__mfp8':'__MFloat8_t' lvalue Var {{.*}} 'f1n' '__mfp8':'__MFloat8_t' + + +/* Class */ + +class C1 { + __mfp8 f1c; + static const __mfp8 f2c; + volatile __MFloat8_t f3c; +public: + C1(__mfp8 arg) : f1c(arg), f3c(arg) { } + __mfp8 func1c(__mfp8 arg ) { + return arg; + } + static __mfp8 func2c(__mfp8 arg) { + return arg; + } +}; + +//CHECK: | |-CXXRecordDecl {{.*}} referenced class C1 +//CHECK-NEXT: | |-FieldDecl {{.*}} f1c '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | |-VarDecl {{.*}} f2c 'const __mfp8':'const __MFloat8_t' static +//CHECK-NEXT: | |-FieldDecl {{.*}} f3c 'volatile __MFloat8_t' +//CHECK-NEXT: | |-AccessSpecDecl {{.*}} +//CHECK-NEXT: | |-CXXConstructorDecl {{.*}} C1 'void (__mfp8)' implicit-inline +//CHECK-NEXT: | | |-ParmVarDecl {{.*}} arg '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | | |-CXXCtorInitializer {{.*}} 'f1c' '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} '__mfp8':'__MFloat8_t' lvalue ParmVar {{.*}} 'arg' '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | | |-CXXCtorInitializer {{.*}} 'f3c' 'volatile __MFloat8_t' +//CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | | | `-DeclRefExpr {{.*}} '__mfp8':'__MFloat8_t' lvalue ParmVar {{.*}} 'arg' '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | | `-CompoundStmt {{.*}} +//CHECK-NEXT: | |-CXXMethodDecl {{.*}} func1c '__mfp8 (__mfp8)' implicit-inline +//CHECK-NEXT: | | |-ParmVarDecl {{.*}} arg '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | | `-CompoundStmt {{.*}} +//CHECK-NEXT: | | `-ReturnStmt {{.*}} +//CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | | `-DeclRefExpr {{.*}} '__mfp8':'__MFloat8_t' lvalue ParmVar {{.*}} 'arg' '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | `-CXXMethodDecl {{.*}} func2c '__mfp8 (__mfp8)' static implicit-inline +//CHECK-NEXT: | |-ParmVarDecl {{.*}} arg '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | `-CompoundStmt {{.*}} +//CHECK-NEXT: | `-ReturnStmt {{.*}} +//CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '__mfp8':'__MFloat8_t' +//CHECK-NEXT: | `-DeclRefExpr {{.*}} '__mfp8':'__MFloat8_t' lvalue ParmVar {{.*}} 'arg' '__mfp8':'__MFloat8_t' + +template struct S1 { + C mem1; +}; + +template <> struct S1<__mfp8> { + __mfp8 mem2; +}; + +//CHECK: |-TemplateArgument type '__MFloat8_t' +//CHECK-NEXT: | `-BuiltinType {{.*}} '__MFloat8_t' +//CHECK-NEXT: |-CXXRecordDecl {{.*}} implicit struct S1 +//CHECK-NEXT: `-FieldDecl {{.*}} mem2 '__mfp8':'__MFloat8_t' diff --git a/clang/test/AST/ast-dump-amdgpu-types.c b/clang/test/AST/ast-dump-amdgpu-types.c index e032d678f1a09e8a8d23285a2256a4cf3ff06a34..f01461cdba2374e896ca3952d76cbb20a9ae6fa8 100644 --- a/clang/test/AST/ast-dump-amdgpu-types.c +++ b/clang/test/AST/ast-dump-amdgpu-types.c @@ -1,10 +1,15 @@ // REQUIRES: amdgpu-registered-target // Test without serialization: -// RUN: %clang_cc1 -triple amdgcn -ast-dump -ast-dump-filter __amdgpu_buffer_rsrc_t %s | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn -ast-dump -ast-dump-filter __amdgpu_buffer_rsrc_t %s | FileCheck %s -check-prefix=BUFFER-RSRC +// RUN: %clang_cc1 -triple amdgcn -ast-dump -ast-dump-filter __amdgpu_named_workgroup_barrier %s | FileCheck %s -check-prefix=WORKGROUP-BARRIER // // Test with serialization: // RUN: %clang_cc1 -triple amdgcn -emit-pch -o %t %s -// RUN: %clang_cc1 -x c -triple amdgcn -include-pch %t -ast-dump-all -ast-dump-filter __amdgpu_buffer_rsrc_t /dev/null | sed -e "s/ //" -e "s/ imported//" | FileCheck %s +// RUN: %clang_cc1 -x c -triple amdgcn -include-pch %t -ast-dump-all -ast-dump-filter __amdgpu_buffer_rsrc_t /dev/null | sed -e "s/ //" -e "s/ imported//" | FileCheck %s -check-prefix=BUFFER-RSRC +// RUN: %clang_cc1 -x c -triple amdgcn -include-pch %t -ast-dump-all -ast-dump-filter __amdgpu_named_workgroup_barrier /dev/null | sed -e "s/ //" -e "s/ imported//" | FileCheck %s -check-prefix=WORKGROUP-BARRIER -// CHECK: TypedefDecl {{.*}} implicit __amdgpu_buffer_rsrc_t -// CHECK-NEXT: -BuiltinType {{.*}} '__amdgpu_buffer_rsrc_t' +// BUFFER-RSRC: TypedefDecl {{.*}} implicit __amdgpu_buffer_rsrc_t +// BUFFER-RSRC-NEXT: -BuiltinType {{.*}} '__amdgpu_buffer_rsrc_t' + +// WORKGROUP-BARRIER: TypedefDecl {{.*}} implicit __amdgpu_named_workgroup_barrier_t +// WORKGROUP-BARRIER-NEXT: -BuiltinType {{.*}} '__amdgpu_named_workgroup_barrier_t' diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp new file mode 100644 index 0000000000000000000000000000000000000000..49b6bfcd7cadfdcd4fcf2db305e046914ed167f2 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s + +#include "mock-types.h" + +RefCountableAndCheckable* makeObj(); +CheckedRef makeObjChecked(); +void someFunction(RefCountableAndCheckable*); + +namespace call_args_unchecked_uncounted { + +static void foo() { + someFunction(makeObj()); + // expected-warning@-1{{Call argument is uncounted and unsafe [alpha.webkit.UncountedCallArgsChecker]}} +} + +} // namespace call_args_checked + +namespace call_args_checked { + +static void foo() { + CheckedPtr ptr = makeObj(); + someFunction(ptr.get()); +} + +static void bar() { + someFunction(CheckedPtr { makeObj() }.get()); +} + +static void baz() { + someFunction(makeObjChecked().ptr()); +} + +} // namespace call_args_checked + +namespace call_args_default { + +void someFunction(RefCountableAndCheckable* = makeObj()); +// expected-warning@-1{{Call argument is uncounted and unsafe [alpha.webkit.UncountedCallArgsChecker]}} +void otherFunction(RefCountableAndCheckable* = makeObjChecked().ptr()); + +void foo() { + someFunction(); + otherFunction(); +} + +} diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h index 933b4c5e62a79cc043e51280b8d90fa64d9f03d9..8d8a90f0afae0e140f042984405f0a138aecf9c6 100644 --- a/clang/test/Analysis/Checkers/WebKit/mock-types.h +++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h @@ -114,8 +114,8 @@ private: public: CheckedRef() : t{} {}; - CheckedRef(T &t) : t(t) { t->incrementPtrCount(); } - CheckedRef(const CheckedRef& o) : t(o.t) { if (t) t->incrementPtrCount(); } + CheckedRef(T &t) : t(&t) { t.incrementPtrCount(); } + CheckedRef(const CheckedRef &o) : t(o.t) { if (t) t->incrementPtrCount(); } ~CheckedRef() { if (t) t->decrementPtrCount(); } T &get() { return *t; } T *ptr() { return t; } @@ -135,7 +135,7 @@ public: if (t) t->incrementPtrCount(); } - CheckedPtr(Ref&& o) + CheckedPtr(Ref &&o) : t(o.leakRef()) { } ~CheckedPtr() { @@ -156,4 +156,14 @@ public: void decrementPtrCount(); }; +class RefCountableAndCheckable { +public: + void incrementPtrCount() const; + void decrementPtrCount() const; + void ref() const; + void deref() const; + void method(); + int trivial() { return 0; } +}; + #endif diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp index b5f6b8535bf41812b36d01d9b788440316041e95..1c0df42cdda663c312d1ebf48132dc87da08cdba 100644 --- a/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp +++ b/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp @@ -290,6 +290,57 @@ void foo() { } // namespace local_assignment_to_global +namespace local_refcountable_checkable_object { + +RefCountableAndCheckable* provide_obj(); + +void local_raw_ptr() { + RefCountableAndCheckable* a = nullptr; + // expected-warning@-1{{Local variable 'a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} + a = provide_obj(); + a->method(); +} + +void local_checked_ptr() { + CheckedPtr a = nullptr; + a = provide_obj(); + a->method(); +} + +void local_var_with_guardian_checked_ptr() { + CheckedPtr a = provide_obj(); + { + auto* b = a.get(); + b->method(); + } +} + +void local_var_with_guardian_checked_ptr_with_assignment() { + CheckedPtr a = provide_obj(); + { + RefCountableAndCheckable* b = a.get(); + // expected-warning@-1{{Local variable 'b' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} + b = provide_obj(); + b->method(); + } +} + +void local_var_with_guardian_checked_ref() { + CheckedRef a = *provide_obj(); + { + RefCountableAndCheckable& b = a; + b.method(); + } +} + +void static_var() { + static RefCountableAndCheckable* a = nullptr; + // expected-warning@-1{{Static local variable 'a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}} + a = provide_obj(); +} + +} // namespace local_refcountable_checkable_object + namespace local_var_in_recursive_function { struct TreeNode { diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed28a64bba059c27ea6c58ecd8557dccc985c290 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg-std-array.cpp @@ -0,0 +1,39 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s +// expected-no-diagnostics + +#include "mock-types.h" + +void __libcpp_verbose_abort(const char *__format, ...); + +using size_t = __typeof(sizeof(int)); +namespace std{ +template +class array { + T elements[N]; + + public: + T& operator[](unsigned i) { + if (i >= N) { + __libcpp_verbose_abort("%s", "aborting"); + } + return elements[i]; + } +}; +} + +class ArrayClass { +public: + void ref() const; + void deref() const; + typedef std::array, 4> Matrix; + double e() { return matrix[3][0]; } + Matrix matrix; +}; + +class AnotherClass { + RefPtr matrix; + void test() { + double val = { matrix->e()}; + } +}; + diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp index 10da776f81575cea543ec824c412b6dce6a1f11b..e1dacdd9e25b6d304ad7b22cd1989247e2ef0e0e 100644 --- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp +++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp @@ -238,6 +238,8 @@ public: using BaseType::BaseType; }; +void __libcpp_verbose_abort(const char *__format, ...); + class RefCounted { public: void ref() const; @@ -361,6 +363,9 @@ public: void trivial62() { WTFReportBacktrace(); } SomeType trivial63() { return SomeType(0); } SomeType trivial64() { return SomeType(); } + void trivial65() { + __libcpp_verbose_abort("%s", "aborting"); + } static RefCounted& singleton() { static RefCounted s_RefCounted; @@ -544,6 +549,7 @@ public: getFieldTrivial().trivial62(); // no-warning getFieldTrivial().trivial63(); // no-warning getFieldTrivial().trivial64(); // no-warning + getFieldTrivial().trivial65(); // no-warning RefCounted::singleton().trivial18(); // no-warning RefCounted::singleton().someFunction(); // no-warning diff --git a/clang/test/Analysis/array-init-loop.cpp b/clang/test/Analysis/array-init-loop.cpp index 4ab4489fc882f3fa85ab25a96135d97bfc70fe9e..b28468b7f560b2c56acb3f46b9b98e0e154a9f18 100644 --- a/clang/test/Analysis/array-init-loop.cpp +++ b/clang/test/Analysis/array-init-loop.cpp @@ -330,3 +330,41 @@ void no_crash() { } } // namespace crash + +namespace array_subscript_initializer { +struct S { + int x; +}; + +void no_crash() { + S arr[][2] = {{1, 2}}; + + const auto [a, b] = arr[0]; // no-crash + + clang_analyzer_eval(a.x == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(b.x == 2); // expected-warning{{TRUE}} +} +} // namespace array_subscript_initializer + +namespace iterator_initializer { +struct S { + int x; +}; + +void no_crash() { + S arr[][2] = {{1, 2}, {3, 4}}; + + int i = 0; + for (const auto [a, b] : arr) { // no-crash + if (i == 0) { + clang_analyzer_eval(a.x == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(b.x == 2); // expected-warning{{TRUE}} + } else { + clang_analyzer_eval(a.x == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(b.x == 4); // expected-warning{{TRUE}} + } + + ++i; + } +} +} // namespace iterator_initializer diff --git a/clang/test/Analysis/const-method-call.cpp b/clang/test/Analysis/const-method-call.cpp index 8e1fd3b125f0e2cf8ae9a0f7d6b4bb214e26b384..7da7ca5554a23e91177df855bfdabf7ae90a5be8 100644 --- a/clang/test/Analysis/const-method-call.cpp +++ b/clang/test/Analysis/const-method-call.cpp @@ -271,3 +271,49 @@ void checkThatConstMethodCallDoesInvalidateObjectForCircularReferences() { // FIXME: Should be UNKNOWN. clang_analyzer_eval(t.x); // expected-warning{{TRUE}} } + +namespace gh77378 { +template class callable; + +template class callable { + struct CallableType { + bool operator()(); + }; + using MethodType = R (CallableType::*)(); + CallableType *object_{nullptr}; + MethodType method_; + +public: + callable() = default; + + template + constexpr callable(const T &obj) + : object_{reinterpret_cast(&const_cast(obj))}, + method_{reinterpret_cast( + static_cast(&T::operator()))} {} + + constexpr bool const_method() const { + return (object_->*(method_))(); + } + + callable call() const & { + static const auto L = [this]() { + while (true) { + // This should not crash when conservative eval calling the member function + // when it unwinds the call stack due to exhausting the budget or reaching + // the inlining limit. + if (this->const_method()) { + break; + } + } + return true; + }; + return L; + } +}; + +void entry() { + callable{}.call().const_method(); + // expected-warning@-1 {{Address of stack memory associated with temporary object of type 'callable' is still referred to by the static variable 'L' upon returning to the caller. This will be a dangling reference}} +} +} // namespace gh77378 diff --git a/clang/test/Analysis/ptr-iter.cpp b/clang/test/Analysis/ptr-iter.cpp deleted file mode 100644 index a94288cd1c8cccb96ed0513565d503ea4da1321a..0000000000000000000000000000000000000000 --- a/clang/test/Analysis/ptr-iter.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// RUN: %clang_analyze_cc1 %s -std=c++14 -analyzer-output=text -verify \ -// RUN: -analyzer-checker=core,alpha.nondeterminism.PointerIteration - -#include "Inputs/system-header-simulator-cxx.h" - -template -void f(T x); - -void PointerIteration() { - int a = 1, b = 2; - std::set OrderedIntSet = {a, b}; - std::set OrderedPtrSet = {&a, &b}; - std::unordered_set UnorderedIntSet = {a, b}; - std::unordered_set UnorderedPtrSet = {&a, &b}; - - for (auto i : OrderedIntSet) // no-warning - f(i); - - for (auto i : OrderedPtrSet) // no-warning - f(i); - - for (auto i : UnorderedIntSet) // no-warning - f(i); - - for (auto i : UnorderedPtrSet) // expected-warning {{Iteration of pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerIteration] -// expected-note@-1 {{Iteration of pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerIteration] - f(i); -} diff --git a/clang/test/Analysis/ptr-sort.cpp b/clang/test/Analysis/ptr-sort.cpp deleted file mode 100644 index d238b390bdc2357925b5a22e7a438c353f675d0f..0000000000000000000000000000000000000000 --- a/clang/test/Analysis/ptr-sort.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// RUN: %clang_analyze_cc1 %s -std=c++14 -analyzer-output=text -verify \ -// RUN: -analyzer-checker=core,alpha.nondeterminism.PointerSorting - -#include "Inputs/system-header-simulator-cxx.h" - -bool f(int x) { return true; } -bool g(int *x) { return true; } - -void PointerSorting() { - int a = 1, b = 2; - std::vector V1 = {a, b}; - std::vector V2 = {&a, &b}; - - std::is_sorted(V1.begin(), V1.end()); // no-warning - std::nth_element(V1.begin(), V1.begin() + 1, V1.end()); // no-warning - std::partial_sort(V1.begin(), V1.begin() + 1, V1.end()); // no-warning - std::sort(V1.begin(), V1.end()); // no-warning - std::stable_sort(V1.begin(), V1.end()); // no-warning - std::partition(V1.begin(), V1.end(), f); // no-warning - std::stable_partition(V1.begin(), V1.end(), g); // no-warning - - std::is_sorted(V2.begin(), V2.end()); // expected-warning {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] - // expected-note@-1 {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] - std::nth_element(V2.begin(), V2.begin() + 1, V2.end()); // expected-warning {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] - // expected-note@-1 {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] - std::partial_sort(V2.begin(), V2.begin() + 1, V2.end()); // expected-warning {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] - // expected-note@-1 {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] - std::sort(V2.begin(), V2.end()); // expected-warning {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] - // expected-note@-1 {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] - std::stable_sort(V2.begin(), V2.end()); // expected-warning {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] - // expected-note@-1 {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] - std::partition(V2.begin(), V2.end(), f); // expected-warning {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] - // expected-note@-1 {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] - std::stable_partition(V2.begin(), V2.end(), g); // expected-warning {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] - // expected-note@-1 {{Sorting pointer-like elements can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] -} diff --git a/clang/test/CXX/drs/cwg1884.cpp b/clang/test/CXX/drs/cwg1884.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c4f76baa3933fbea2ba4b3d077c1e35ba4e37a53 --- /dev/null +++ b/clang/test/CXX/drs/cwg1884.cpp @@ -0,0 +1,643 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file --leading-lines %s %t +// RUN: %clang_cc1 -std=c++20 -pedantic-errors -fexceptions -fcxx-exceptions %t/cwg1884_A.cppm -triple x86_64-unknown-unknown -emit-module-interface -o %t/cwg1884_A.pcm +// RUN: %clang_cc1 -std=c++20 -verify=since-cxx20 -pedantic-errors -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown %t/cwg1884.cpp -fmodule-file=cwg1884_A=%t/cwg1884_A.pcm +// RUN: %clang_cc1 -std=c++23 -pedantic-errors -fexceptions -fcxx-exceptions %t/cwg1884_A.cppm -triple x86_64-unknown-unknown -emit-module-interface -o %t/cwg1884_A.pcm +// RUN: %clang_cc1 -std=c++23 -verify=since-cxx20 -pedantic-errors -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown %t/cwg1884.cpp -fmodule-file=cwg1884_A=%t/cwg1884_A.pcm +// RUN: %clang_cc1 -std=c++2c -pedantic-errors -fexceptions -fcxx-exceptions %t/cwg1884_A.cppm -triple x86_64-unknown-unknown -emit-module-interface -o %t/cwg1884_A.pcm +// RUN: %clang_cc1 -std=c++2c -verify=since-cxx20 -pedantic-errors -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown %t/cwg1884.cpp -fmodule-file=cwg1884_A=%t/cwg1884_A.pcm + +// cwg1884: partial +// Cases b11, e11, g3, g4 are problematic, but we handle the other 101 cases fine. + +// _N4993_.[basic.link]/11: +// For any two declarations of an entity E: +// — If one declares E to be a variable or function, +// the other shall declare E as one of the same type. +// — If one declares E to be an enumerator, the other shall do so. +// — If one declares E to be a namespace, the other shall do so. +// — If one declares E to be a type, +// the other shall declare E to be a type of the same kind (9.2.9.5). +// — If one declares E to be a class template, +// the other shall do so with the same kind and an equivalent template-head (13.7.7.2). +// [Note 5 : The declarations can supply different default template arguments. — end note] +// — If one declares E to be a function template or a (partial specialization of a) variable template, +// the other shall declare E to be one with an equivalent template-head and type. +// — If one declares E to be an alias template, +// the other shall declare E to be one with an equivalent template-head and defining-type-id. +// — If one declares E to be a concept, the other shall do so. +// Types are compared after all adjustments of types (during which typedefs (9.2.4) are replaced by their definitions); +// declarations for an array object can specify array types that differ by the presence or absence of a major array bound (9.3.4.5). +// No diagnostic is required if neither declaration is reachable from the other. + +// The structure of the test is the following. First, module cwg1884_A +// provides all (significant) kinds of entities, each named 'a' through 'h', and copies of them. +// Then the .cpp file does MxN kind of testing, where it tests one kind of entity against every other kind. + +//--- cwg1884_A.cppm +export module cwg1884_A; + +export { +int a1; +int a2; +int a3; +int a4; +int a5; +int a6; +int a7; +int a8; +int a9; +int a10; +int a11; +void b1(); +void b2(); +void b3(); +void b4(); +void b5(); +void b6(); +void b7(); +void b8(); +void b9(); +void b10(); +void b11(); +enum E { + c1, + c2, + c3, + c4, + c5, + c6, + c7, + c8, + c9, + c10 +}; +namespace d1 {} +namespace d2 {} +namespace d3 {} +namespace d4 {} +namespace d5 {} +namespace d6 {} +namespace d7 {} +namespace d8 {} +namespace d9 {} +namespace d10 {} +struct e1; +struct e2; +struct e3; +struct e4; +struct e5; +struct e6; +struct e7; +struct e8; +struct e9; +struct e10; +struct e11; +struct e12; +struct e13; +template +class f1; +template +class f2; +template +class f3; +template +class f4; +template +class f5; +template +class f6; +template +class f7; +template +class f8; +template +class f9; +template +class f10; +template +class f11; +template +void g1(int); +template +void g2(int); +template +void g3(int); +template +void g4(int); +template +void g5(int); +template +void g6(int); +template +void g7(int); +template +void g8(int); +template +void g9(int); +template +void g10(int); +template +int h1; +template +int h2; +template +int h3; +template +int h4; +template +int h5; +template +int h6; +template +int h7; +template +int h8; +template +int h9; +template +int h10; +template +using i1 = int; +template +using i2 = int; +template +using i3 = int; +template +using i4 = int; +template +using i5 = int; +template +using i6 = int; +template +using i7 = int; +template +using i8 = int; +template +using i9 = int; +template +using i10 = int; +template +using i11 = int; +template +concept j1 = true; +template +concept j2 = true; +template +concept j3 = true; +template +concept j4 = true; +template +concept j5 = true; +template +concept j6 = true; +template +concept j7 = true; +template +concept j8 = true; +template +concept j9 = true; +template +concept j10 = true; +template +concept j11 = true; +} // export + + +//--- cwg1884.cpp +import cwg1884_A; + +// FIXME: we don't diagnose several cases we should be. They are marked with MISSING prefix. + +// Part A: matching against `int a;` +// --------------------------------- + +void a1(); +// since-cxx20-error@-1 {{redefinition of 'a1' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:42 {{previous definition is here}} +enum Ea { + a2 + // since-cxx20-error@-1 {{redefinition of 'a2'}} + // since-cxx20-note@cwg1884_A.cppm:43 {{previous definition is here}} +}; +namespace a3 {} +// since-cxx20-error@-1 {{redefinition of 'a3' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:44 {{previous definition is here}} +struct a4; +// @-1 OK, types and variables do not correspond +template +class a5; +// since-cxx20-error@-1 {{redefinition of 'a5' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:46 {{previous definition is here}} +template +void a6(int); +// since-cxx20-error@-1 {{redefinition of 'a6' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:47 {{previous definition is here}} +template +int a7; +// since-cxx20-error@-1 {{redefinition of 'a7' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:48 {{previous definition is here}} +template +int a8; +// since-cxx20-error@-1 {{redefinition of 'a8' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:49 {{previous definition is here}} +// since-cxx20-error@-3 {{expected ';' after top level declarator}} +template +using a9 = int; +// since-cxx20-error@-1 {{redefinition of 'a9' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:50 {{previous definition is here}} +template +concept a10 = true; +// since-cxx20-error@-1 {{redefinition of 'a10' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:51 {{previous definition is here}} +// For variables, type has to match as well. +long a11; +// since-cxx20-error@-1 {{redefinition of 'a11' with a different type: 'long' vs 'int'}} +// since-cxx20-note@cwg1884_A.cppm:52 {{previous definition is here}} + + +// Part B: matching against `void b();` +// ------------------------------------ + +int b1; +// since-cxx20-error@-1 {{redefinition of 'b1' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:53 {{previous definition is here}} +enum Eb { + b2 + // since-cxx20-error@-1 {{redefinition of 'b2'}} + // since-cxx20-note@cwg1884_A.cppm:54 {{previous definition is here}} +}; +namespace b3 {} // #cwg1884-namespace-b +// since-cxx20-error@-1 {{redefinition of 'b3' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:55 {{previous definition is here}} +struct b4; +// @-1 OK, types and functions do not correspond +template +class b5; +// since-cxx20-error@-1 {{redefinition of 'b5' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:57 {{previous definition is here}} +template +void b6(int); +// @-1 OK, a non-corresponding overload +template +int b7; +// since-cxx20-error@-1 {{redefinition of 'b7' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:59 {{previous definition is here}} +template +int b8; +// since-cxx20-error@-1 {{no variable template matches partial specialization}} +template +using b9 = int; +// since-cxx20-error@-1 {{redefinition of 'b9' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:61 {{previous definition is here}} +template +concept b10 = true; +// since-cxx20-error@-1 {{redefinition of 'b10' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:62 {{previous definition is here}} +// For functions, type has to match as well. +// FIXME: we should be loud and clear here about type mismatch, like we do in `a11` case. +int b11(); +// since-cxx20-error@-1 {{declaration of 'b11' in the global module follows declaration in module cwg1884_A}} +// since-cxx20-note@cwg1884_A.cppm:63 {{previous declaration is here}} + + +// Part C: matching against `enum E { c };` +// ---------------------------------------- + +int c1; +// since-cxx20-error@-1 {{redefinition of 'c1' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:65 {{previous definition is here}} +void c2(); +// since-cxx20-error@-1 {{redefinition of 'c2' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:66 {{previous definition is here}} +namespace c3 {} +// since-cxx20-error@-1 {{redefinition of 'c3' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:67 {{previous definition is here}} +struct c4; +// @-1 OK, types and enumerators do not correspond +template +class c5; +// since-cxx20-error@-1 {{redefinition of 'c5' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:69 {{previous definition is here}} +template +void c6(int); +// since-cxx20-error@-1 {{redefinition of 'c6' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:70 {{previous definition is here}} +template +int c7; +// since-cxx20-error@-1 {{redefinition of 'c7' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:71 {{previous definition is here}} +template +int c8; +// since-cxx20-error@-1 {{redefinition of 'c8' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:72 {{previous definition is here}} +// since-cxx20-error@-3 {{expected ';' after top level declarator}} +template +using c9 = int; +// since-cxx20-error@-1 {{redefinition of 'c9' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:73 {{previous definition is here}} +template +concept c10 = true; +// since-cxx20-error@-1 {{redefinition of 'c10' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:74 {{previous definition is here}} + + +// Part D: matching against `namespace d {};` +// ------------------------------------------ + +int d1; +// since-cxx20-error@-1 {{redefinition of 'd1' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:76 {{previous definition is here}} +void d2(); +// since-cxx20-error@-1 {{redefinition of 'd2' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:77 {{previous definition is here}} +enum Ed { + d3 + // since-cxx20-error@-1 {{redefinition of 'd3'}} + // since-cxx20-note@cwg1884_A.cppm:78 {{previous definition is here}} +}; +struct d4; +// since-cxx20-error@-1 {{redefinition of 'd4' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:79 {{previous definition is here}} +template +class d5; +// since-cxx20-error@-1 {{redefinition of 'd5' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:80 {{previous definition is here}} +template +void d6(int); +// since-cxx20-error@-1 {{redefinition of 'd6' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:81 {{previous definition is here}} +template +int d7; +// since-cxx20-error@-1 {{redefinition of 'd7' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:82 {{previous definition is here}} +template +int d8; +// since-cxx20-error@-1 {{redefinition of 'd8' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:83 {{previous definition is here}} +// since-cxx20-error@-3 {{expected ';' after top level declarator}} +template +using d9 = int; +// since-cxx20-error@-1 {{redefinition of 'd9' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:84 {{previous definition is here}} +template +concept d10 = true; +// since-cxx20-error@-1 {{redefinition of 'd10' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:85 {{previous definition is here}} + + +// Part E: matching against `struct e;` +// ------------------------------------ + +int e1; +// @-1 OK, types and variables do not correspond +void e2(); +// @-1 OK, types and functions do not correspond +enum Ee { + e3 + // @-1 OK, types and enumerators do not correspond +}; +namespace e4 {} +// since-cxx20-error@-1 {{redefinition of 'e4' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:89 {{previous definition is here}} +template +class e5; +// since-cxx20-error@-1 {{redefinition of 'e5' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:90 {{previous definition is here}} +template +void e6(int); +// @-1 OK, types and function templates do not correspond +template +int e7; +// since-cxx20-error@-1 {{redefinition of 'e7' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:92 {{previous definition is here}} +template +int e8; +// since-cxx20-error@-1 {{redefinition of 'e8' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:93 {{previous definition is here}} +// since-cxx20-error@-3 {{expected ';' after top level declarator}} +template +using e9 = int; +// since-cxx20-error@-1 {{redefinition of 'e9' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:94 {{previous definition is here}} +template +concept e10 = true; +// since-cxx20-error@-1 {{redefinition of 'e10' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:95 {{previous definition is here}} +// FIXME: the following forward declaration is well-formed. +// Agreement on 'struct' vs 'class' is not required per [dcl.type.elab]/7. +class e11; +// since-cxx20-error@-1 {{declaration of 'e11' in the global module follows declaration in module cwg1884_A}} +// since-cxx20-note@cwg1884_A.cppm:96 {{previous declaration is here}} +union e12; +// since-cxx20-error@-1 {{use of 'e12' with tag type that does not match previous declaration}} +// since-cxx20-note@cwg1884_A.cppm:97 {{previous use is here}} +// since-cxx20-error@-3 {{declaration of 'e12' in the global module follows declaration in module cwg1884_A}} +// since-cxx20-note@cwg1884_A.cppm:97 {{previous declaration is here}} +enum e13 {}; +// since-cxx20-error@-1 {{use of 'e13' with tag type that does not match previous declaration}} +// since-cxx20-note@cwg1884_A.cppm:98 {{previous use is here}} + + +// Part F: matching against `template class f;` +// ------------------------------------------------------- + +int f1; +// since-cxx20-error@-1 {{redefinition of 'f1' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:100 {{previous definition is here}} +void f2(); +// since-cxx20-error@-1 {{redefinition of 'f2' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:102 {{previous definition is here}} +enum Ef { + f3 + // since-cxx20-error@-1 {{redefinition of 'f3'}} + // since-cxx20-note@cwg1884_A.cppm:104 {{previous definition is here}} +}; +namespace f4 {} +// since-cxx20-error@-1 {{redefinition of 'f4' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:106 {{previous definition is here}} +struct f5; +// since-cxx20-error@-1 {{redefinition of 'f5' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:108 {{previous definition is here}} +template +void f6(int); +// since-cxx20-error@-1 {{redefinition of 'f6' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:110 {{previous definition is here}} +template +int f7; +// since-cxx20-error@-1 {{redefinition of 'f7' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:112 {{previous definition is here}} +template +int f8; +// since-cxx20-error@-1 {{no variable template matches partial specialization}} +template +using f9 = int; +// since-cxx20-error@-1 {{redefinition of 'f9' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:116 {{previous definition is here}} +template +concept f10 = true; +// since-cxx20-error@-1 {{redefinition of 'f10' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:118 {{previous definition is here}} + + +// Part G: matching against `template void g(int);` +// ----------------------------------------------------------- + +int g1; +// since-cxx20-error@-1 {{redefinition of 'g1' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:122 {{previous definition is here}} +void g2(); +// @-1 OK, a non-corresponding overload +enum Eg { + g3 + // MISSING-since-cxx20-error@-1 {{redefinition of 'g3'}} + // MISSING-since-cxx20-note@cwg1884_A.cppm:126 {{previous definition is here}} +}; +namespace g4 {} +// MISSING-since-cxx20-error@-1 {{redefinition of 'g4' as different kind of symbol}} +// MISSING-since-cxx20-note@cwg1884_A.cppm:128 {{previous definition is here}} +struct g5; +// @-1 OK, types and function templates do not correspond +template +class g6; +// since-cxx20-error@-1 {{redefinition of 'g6' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:132 {{previous definition is here}} +template +int g7; +// since-cxx20-error@-1 {{redefinition of 'g7' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:134 {{previous definition is here}} +template +int g8; +// since-cxx20-error@-1 {{no variable template matches specialization; did you mean to use 'g8' as function template instead?}} +template +using g9 = int; +// since-cxx20-error@-1 {{redefinition of 'g9' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:138 {{previous definition is here}} +template +concept g10 = true; +// since-cxx20-error@-1 {{redefinition of 'g10' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:140 {{previous definition is here}} + + +// Part H: matching against `template int h;` +// --------------------------------------------------------------- + +int h1; +// since-cxx20-error@-1 {{redefinition of 'h1' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:142 {{previous definition is here}} +void h2(); +// since-cxx20-error@-1 {{redefinition of 'h2' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:144 {{previous definition is here}} +enum Eh { + h3 + // since-cxx20-error@-1 {{redefinition of 'h3'}} + // since-cxx20-note@cwg1884_A.cppm:146 {{previous definition is here}} +}; +namespace h4 {} +// since-cxx20-error@-1 {{redefinition of 'h4' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:148 {{previous definition is here}} +struct h5; +// since-cxx20-error@-1 {{redefinition of 'h5' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:150 {{previous definition is here}} +template +class h6; +// since-cxx20-error@-1 {{redefinition of 'h6' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:152 {{previous definition is here}} +template +void h7(int); +// since-cxx20-error@-1 {{redefinition of 'h7' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:154 {{previous definition is here}} +template +int h8; +// @-1 OK, partial specialization +template +using h9 = int; +// since-cxx20-error@-1 {{redefinition of 'h9' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:158 {{previous definition is here}} +template +concept h10 = true; +// since-cxx20-error@-1 {{redefinition of 'h10' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:160 {{previous definition is here}} + + +// Part I: matching against `template using i = int;` +// ------------------------------------------------------------- + +int i1; +// since-cxx20-error@-1 {{redefinition of 'i1' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:162 {{previous definition is here}} +void i2(); +// since-cxx20-error@-1 {{redefinition of 'i2' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:164 {{previous definition is here}} +enum Ei { + i3 + // since-cxx20-error@-1 {{redefinition of 'i3'}} + // since-cxx20-note@cwg1884_A.cppm:166 {{previous definition is here}} +}; +namespace i4 {} +// since-cxx20-error@-1 {{redefinition of 'i4' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:168 {{previous definition is here}} +struct i5; +// since-cxx20-error@-1 {{redefinition of 'i5' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:170 {{previous definition is here}} +template +class i6; +// since-cxx20-error@-1 {{redefinition of 'i6' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:172 {{previous definition is here}} +template +void i7(int); +// since-cxx20-error@-1 {{redefinition of 'i7' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:174 {{previous definition is here}} +template +int i8; +// since-cxx20-error@-1 {{redefinition of 'i8' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:176 {{previous definition is here}} +template +int i9; +// since-cxx20-error@-1 {{no variable template matches partial specialization}} +template +concept i10 = true; +// since-cxx20-error@-1 {{redefinition of 'i10' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:180 {{previous definition is here}} + + +// Part J: matching against `template concept j = true;` +// ---------------------------------------------------------------- + +int j1; +// since-cxx20-error@-1 {{redefinition of 'j1' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:184 {{previous definition is here}} +void j2(); +// since-cxx20-error@-1 {{redefinition of 'j2' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:186 {{previous definition is here}} +enum Ej { + j3 + // since-cxx20-error@-1 {{redefinition of 'j3'}} + // since-cxx20-note@cwg1884_A.cppm:188 {{previous definition is here}} +}; +namespace j4 {} +// since-cxx20-error@-1 {{redefinition of 'j4' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:190 {{previous definition is here}} +struct j5; +// since-cxx20-error@-1 {{redefinition of 'j5' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:192 {{previous definition is here}} +template +class j6; +// since-cxx20-error@-1 {{redefinition of 'j6' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:194 {{previous definition is here}} +template +void j7(int); +// since-cxx20-error@-1 {{redefinition of 'j7' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:196 {{previous definition is here}} +template +int j8; +// since-cxx20-error@-1 {{redefinition of 'j8' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:198 {{previous definition is here}} +template +int j9; +// since-cxx20-error@-1 {{no variable template matches partial specialization}} +template +using j10 = int; +// since-cxx20-error@-1 {{redefinition of 'j10' as different kind of symbol}} +// since-cxx20-note@cwg1884_A.cppm:202 {{previous definition is here}} diff --git a/clang/test/CXX/drs/cwg18xx.cpp b/clang/test/CXX/drs/cwg18xx.cpp index 7f0fb8cf589d48c6fa99810abc321378ca163499..0fd2cd6b2d870c01339944798b98b1f4825eafda 100644 --- a/clang/test/CXX/drs/cwg18xx.cpp +++ b/clang/test/CXX/drs/cwg18xx.cpp @@ -547,6 +547,8 @@ namespace cwg1881 { // cwg1881: 7 static_assert(!__is_standard_layout(D), ""); } +// cwg1884 is in cwg1884.cpp + namespace cwg1890 { // cwg1890: no drafting 2018-06-04 // FIXME: current consensus for CWG2335 is that the examples are well-formed. namespace ex1 { @@ -640,3 +642,86 @@ namespace H { struct S s; } } + +namespace cwg1898 { // cwg1898: 2.7 +void e(int) {} // #cwg1898-e +void e(int) {} +// expected-error@-1 {{redefinition of 'e'}} +// expected-note@#cwg1898-e {{previous definition is here}} + +void e2(int) {} +void e2(long) {} // OK, different type + +void f(int) {} // #cwg1898-f +void f(const int) {} +// expected-error@-1 {{redefinition of 'f'}} +// expected-note@#cwg1898-f {{previous definition is here}} + +void g(int) {} // #cwg1898-g +void g(volatile int) {} +// since-cxx20-warning@-1 {{volatile-qualified parameter type 'volatile int' is deprecated}} +// expected-error@-2 {{redefinition of 'g'}} +// expected-note@#cwg1898-g {{previous definition is here}} + +void h(int *) {} // #cwg1898-h +void h(int[]) {} +// expected-error@-1 {{redefinition of 'h'}} +// expected-note@#cwg1898-h {{previous definition is here}} + +void h2(int *) {} // #cwg1898-h2 +void h2(int[2]) {} +// expected-error@-1 {{redefinition of 'h2'}} +// expected-note@#cwg1898-h2 {{previous definition is here}} + +void h3(int (*)[2]) {} // #cwg1898-h3 +void h3(int [3][2]) {} +// expected-error@-1 {{redefinition of 'h3'}} +// expected-note@#cwg1898-h3 {{previous definition is here}} + +void h4(int (*)[2]) {} +void h4(int [3][3]) {} // OK, differ in non-top-level extent of array + +void i(int *) {} +void i(const int *) {} // OK, pointee cv-qualification is not discarded + +void i2(int *) {} // #cwg1898-i2 +void i2(int * const) {} +// expected-error@-1 {{redefinition of 'i2'}} +// expected-note@#cwg1898-i2 {{previous definition is here}} + +void j(void(*)()) {} // #cwg1898-j +void j(void()) {} +// expected-error@-1 {{redefinition of 'j'}} +// expected-note@#cwg1898-j {{previous definition is here}} + +void j2(void(int)) {} // #cwg1898-j2 +void j2(void(const int)) {} +// expected-error@-1 {{redefinition of 'j2'}} +// expected-note@#cwg1898-j2 {{previous definition is here}} + +struct A { + void k(int) {} // #cwg1898-k + void k(int) {} + // expected-error@-1 {{class member cannot be redeclared}} + // expected-note@#cwg1898-k {{previous definition is here}} +}; + +struct B : A { + void k(int) {} // OK, shadows A::k +}; + +void l() {} +void l(...) {} + +#if __cplusplus >= 201103L +template +void m(T) {} +template +void m(Ts...) {} + +template +void m2(T, U) {} +template +void m2(Ts..., U) {} +#endif +} // namespace cwg1898 diff --git a/clang/test/CXX/drs/cwg279.cpp b/clang/test/CXX/drs/cwg279.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c63486cc0dd5ef0cdcbc7b451ddb9025ed25c6d --- /dev/null +++ b/clang/test/CXX/drs/cwg279.cpp @@ -0,0 +1,53 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file --leading-lines %s %t +// RUN: %clang_cc1 -std=c++20 -pedantic-errors -fexceptions -fcxx-exceptions %t/cwg279_A.cppm -triple x86_64-unknown-unknown -emit-module-interface -o %t/cwg279_A.pcm +// RUN: %clang_cc1 -std=c++20 -verify=since-cxx20 -pedantic-errors -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown %t/cwg279.cpp -fmodule-file=cwg279_A=%t/cwg279_A.pcm +// RUN: %clang_cc1 -std=c++23 -pedantic-errors -fexceptions -fcxx-exceptions %t/cwg279_A.cppm -triple x86_64-unknown-unknown -emit-module-interface -o %t/cwg279_A.pcm +// RUN: %clang_cc1 -std=c++23 -verify=since-cxx20 -pedantic-errors -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown %t/cwg279.cpp -fmodule-file=cwg279_A=%t/cwg279_A.pcm +// RUN: %clang_cc1 -std=c++2c -pedantic-errors -fexceptions -fcxx-exceptions %t/cwg279_A.cppm -triple x86_64-unknown-unknown -emit-module-interface -o %t/cwg279_A.pcm +// RUN: %clang_cc1 -std=c++2c -verify=since-cxx20 -pedantic-errors -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown %t/cwg279.cpp -fmodule-file=cwg279_A=%t/cwg279_A.pcm + +// cwg279: no + +//--- cwg279_A.cppm +export module cwg279_A; + +export { +struct S; // #cwg279-S +extern S *q; // #cwg279-q + +struct S2 {}; // #cwg279-S2 +extern S2 *q2; // #cwg279-q2 + +struct S3 {}; // #cwg279-S3 +extern S3 *q3; // #cwg279-q3 +} // export + +//--- cwg279.cpp +import cwg279_A; + +// FIXME: We should use markers instead. They are less fragile, +// but -verify doesn't support them across modules yet. +// FIXME: This is well-formed. Previous "definition" is actually just a declaration. +typedef struct {} S; +// since-cxx20-error@-1 {{typedef redefinition with different types ('struct S' vs 'S')}} +// since-cxx20-note@cwg279_A.cppm:17 {{previous definition is here}} +extern S *q; +// since-cxx20-error@-1 {{declaration of 'q' in the global module follows declaration in module cwg279_A}} +// since-cxx20-note@cwg279_A.cppm:18 {{previous declaration is here}} + +typedef struct {} S2; +// since-cxx20-error@-1 {{typedef redefinition with different types ('struct S2' vs 'S2')}} +// since-cxx20-note@cwg279_A.cppm:20 {{previous definition is here}} +extern S2 *q2; +// since-cxx20-error@-1 {{declaration of 'q2' in the global module follows declaration in module cwg279_A}} +// since-cxx20-note@cwg279_A.cppm:21 {{previous declaration is here}} + +// FIXME: This is well-formed, because [basic.def.odr]/15 is satisfied. +struct S3 {}; +// since-cxx20-error@-1 {{redefinition of 'S3'}} +// since-cxx20-note@cwg279_A.cppm:23 {{previous definition is here}} +extern S3 *q3; +// since-cxx20-error@-1 {{declaration of 'q3' in the global module follows declaration in module cwg279_A}} +// since-cxx20-note@cwg279_A.cppm:24 {{previous declaration is here}} diff --git a/clang/test/CXX/drs/cwg2xx.cpp b/clang/test/CXX/drs/cwg2xx.cpp index 926cb19596026b4f7be9f2aa270e2a30acaf6544..ec37b420880e28ab1b7ba53609525e63bb010562 100644 --- a/clang/test/CXX/drs/cwg2xx.cpp +++ b/clang/test/CXX/drs/cwg2xx.cpp @@ -1032,6 +1032,8 @@ namespace cwg277 { // cwg277: 3.1 static_assert(__enable_constant_folding(!intp()), ""); } +// cwg279 is in cwg279.cpp + namespace cwg280 { // cwg280: 2.9 typedef void f0(); typedef void f1(int); diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp index f20054c3701b1ce26b851321c8d85b5dfe4ef6bf..10c8d86ed16a0dbcf9ccd4ea9ced4b2f9db7a07e 100644 --- a/clang/test/CXX/drs/cwg3xx.cpp +++ b/clang/test/CXX/drs/cwg3xx.cpp @@ -637,6 +637,8 @@ namespace cwg337 { // cwg337: yes struct B { virtual ~B() = 0; }; } +// cwg338: dup 1884 + namespace cwg339 { // cwg339: 2.8 template struct A { static const int value = I; }; diff --git a/clang/test/ClangScanDeps/link-libraries.c b/clang/test/ClangScanDeps/link-libraries.c index c09691d2356efccdba56e91e3a5671343bc40ee7..bc0b0c546ea032d44df5a8f410f1a4822b2f86d1 100644 --- a/clang/test/ClangScanDeps/link-libraries.c +++ b/clang/test/ClangScanDeps/link-libraries.c @@ -39,14 +39,13 @@ module transitive { // CHECK-NEXT: "modules": [ // CHECK-NEXT: { // CHECK-NEXT: "clang-module-deps": [], -// CHECK-NEXT: "clang-modulemap-file": "{{.*}}/__inferred_module.map", +// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/Inputs/frameworks/module.modulemap", // CHECK-NEXT: "command-line": [ // CHECK: ], // CHECK-NEXT: "context-hash": "{{.*}}", // CHECK-NEXT: "file-deps": [ -// CHECK-NEXT: "{{.*}}/Framework.h" -// CHECK-NEXT: "{{.*}}/__inferred_module.map" -// CHECK-NEXT: "{{.*}}/module.modulemap" +// CHECK-NEXT: "[[PREFIX]]/Inputs/frameworks/Framework.framework/Headers/Framework.h" +// CHECK-NEXT: "[[PREFIX]]/Inputs/frameworks/module.modulemap" // CHECK-NEXT: ], // CHECK-NEXT: "link-libraries": [ // CHECK-NEXT: { diff --git a/clang/test/ClangScanDeps/print-timing.c b/clang/test/ClangScanDeps/print-timing.c index f27df1ebf732a9c25fa7e07230a152614c9facfa..fa2a433b9553708b30701cce1a352c555ff2c441 100644 --- a/clang/test/ClangScanDeps/print-timing.c +++ b/clang/test/ClangScanDeps/print-timing.c @@ -3,7 +3,8 @@ // RUN: clang-scan-deps -compilation-database %t/cdb.json -print-timing > %t/result.json 2>%t/errs // RUN: cat %t/errs | FileCheck %s -// CHECK: clang-scan-deps timing: {{[0-9]+}}.{{[0-9][0-9]}}s wall, {{[0-9]+}}.{{[0-9][0-9]}}s process +// CHECK: wall time [s] process time [s] instruction count +// CHECK-NEXT: {{[0-9]+}}.{{([0-9]{4})}} {{[0-9]+}}.{{([0-9]{4})}} {{[0-9]+}} //--- cdb.json [] diff --git a/clang/test/CodeGen/RISCV/attr-hw-shadow-stack.c b/clang/test/CodeGen/RISCV/attr-hw-shadow-stack.c new file mode 100644 index 0000000000000000000000000000000000000000..cabff7e598eb02a65a03de12f768b5726b552d68 --- /dev/null +++ b/clang/test/CodeGen/RISCV/attr-hw-shadow-stack.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple riscv64 -target-feature +experimental-zicfiss -emit-llvm -o - %s -fcf-protection=return | FileCheck %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +experimental-zicfiss -emit-llvm -o - %s | FileCheck -check-prefix=NOSHADOWSTACK %s +// RUN: %clang_cc1 -triple riscv32 -target-feature +experimental-zicfiss -emit-llvm -o - %s -fcf-protection=return | FileCheck %s +// RUN: %clang_cc1 -triple riscv32 -target-feature +experimental-zicfiss -emit-llvm -o - %s | FileCheck -check-prefix=NOSHADOWSTACK %s + +int foo(int *a) { return *a; } + +// CHECK: attributes {{.*}}"hw-shadow-stack"{{.*}} +// NOSHADOWSTACK-NOT: attributes {{.*}}"hw-shadow-stack"{{.*}} diff --git a/clang/test/CodeGen/X86/avx-cmp-builtins.c b/clang/test/CodeGen/X86/avx-cmp-builtins.c index c4e3c7ccd54988dcff8217fa32a4c4f4a11ce4a6..2e4a383a6b3fca19d038ff36a4822901485b433e 100644 --- a/clang/test/CodeGen/X86/avx-cmp-builtins.c +++ b/clang/test/CodeGen/X86/avx-cmp-builtins.c @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -flax-vector-conversions=none -ffreestanding %s -O3 -triple=x86_64-apple-darwin -target-feature +avx -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -flax-vector-conversions=none -ffreestanding %s -O3 -triple=i386-apple-darwin -target-feature +avx -emit-llvm -o - | FileCheck %s -// FIXME: The shufflevector instructions in test_cmpgt_sd are relying on O3 here. +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-- -target-feature +avx -disable-O0-optnone -emit-llvm -o - | opt -S -passes=mem2reg | FileCheck %s +// RUN: %clang_cc1 -flax-vector-conversions=none -ffreestanding %s -triple=i386-- -target-feature +avx -disable-O0-optnone -emit-llvm -o - | opt -S -passes=mem2reg | FileCheck %s #include @@ -9,62 +9,124 @@ // Test LLVM IR codegen of cmpXY instructions // +// CHECK-LABEL: define dso_local <2 x double> @test_cmp_sd( +// CHECK-SAME: <2 x double> noundef [[A:%.*]], <2 x double> noundef [[B:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> [[A]], <2 x double> [[B]], i8 13) +// CHECK-NEXT: ret <2 x double> [[TMP0]] +// __m128d test_cmp_sd(__m128d a, __m128d b) { // Expects that the third argument in LLVM IR is immediate expression - // CHECK: @llvm.x86.sse2.cmp.sd({{.*}}, i8 13) return _mm_cmp_sd(a, b, _CMP_GE_OS); } +// CHECK-LABEL: define dso_local <4 x float> @test_cmp_ss( +// CHECK-SAME: <4 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call <4 x float> @llvm.x86.sse.cmp.ss(<4 x float> [[A]], <4 x float> [[B]], i8 13) +// CHECK-NEXT: ret <4 x float> [[TMP0]] +// __m128 test_cmp_ss(__m128 a, __m128 b) { // Expects that the third argument in LLVM IR is immediate expression - // CHECK: @llvm.x86.sse.cmp.ss({{.*}}, i8 13) return _mm_cmp_ss(a, b, _CMP_GE_OS); } +// CHECK-LABEL: define dso_local <4 x float> @test_cmpgt_ss( +// CHECK-SAME: <4 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call <4 x float> @llvm.x86.sse.cmp.ss(<4 x float> [[B]], <4 x float> [[A]], i8 1) +// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <4 x float> [[A]], <4 x float> [[TMP0]], <4 x i32> +// CHECK-NEXT: ret <4 x float> [[SHUFFLE_I]] +// __m128 test_cmpgt_ss(__m128 a, __m128 b) { - // CHECK: @llvm.x86.sse.cmp.ss({{.*}}, i8 1) - // CHECK: shufflevector <{{.*}}, <4 x i32> return _mm_cmpgt_ss(a, b); } +// CHECK-LABEL: define dso_local <4 x float> @test_cmpge_ss( +// CHECK-SAME: <4 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call <4 x float> @llvm.x86.sse.cmp.ss(<4 x float> [[B]], <4 x float> [[A]], i8 2) +// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <4 x float> [[A]], <4 x float> [[TMP0]], <4 x i32> +// CHECK-NEXT: ret <4 x float> [[SHUFFLE_I]] +// __m128 test_cmpge_ss(__m128 a, __m128 b) { - // CHECK: @llvm.x86.sse.cmp.ss({{.*}}, i8 2) - // CHECK: shufflevector <{{.*}}, <4 x i32> return _mm_cmpge_ss(a, b); } +// CHECK-LABEL: define dso_local <4 x float> @test_cmpngt_ss( +// CHECK-SAME: <4 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call <4 x float> @llvm.x86.sse.cmp.ss(<4 x float> [[B]], <4 x float> [[A]], i8 5) +// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <4 x float> [[A]], <4 x float> [[TMP0]], <4 x i32> +// CHECK-NEXT: ret <4 x float> [[SHUFFLE_I]] +// __m128 test_cmpngt_ss(__m128 a, __m128 b) { - // CHECK: @llvm.x86.sse.cmp.ss({{.*}}, i8 5) - // CHECK: shufflevector <{{.*}}, <4 x i32> return _mm_cmpngt_ss(a, b); } +// CHECK-LABEL: define dso_local <4 x float> @test_cmpnge_ss( +// CHECK-SAME: <4 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call <4 x float> @llvm.x86.sse.cmp.ss(<4 x float> [[B]], <4 x float> [[A]], i8 6) +// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <4 x float> [[A]], <4 x float> [[TMP0]], <4 x i32> +// CHECK-NEXT: ret <4 x float> [[SHUFFLE_I]] +// __m128 test_cmpnge_ss(__m128 a, __m128 b) { - // CHECK: @llvm.x86.sse.cmp.ss({{.*}}, i8 6) - // CHECK: shufflevector <{{.*}}, <4 x i32> return _mm_cmpnge_ss(a, b); } +// CHECK-LABEL: define dso_local <2 x double> @test_cmpgt_sd( +// CHECK-SAME: <2 x double> noundef [[A:%.*]], <2 x double> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> [[B]], <2 x double> [[A]], i8 1) +// CHECK-NEXT: [[VECEXT_I:%.*]] = extractelement <2 x double> [[TMP0]], i32 0 +// CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <2 x double> poison, double [[VECEXT_I]], i32 0 +// CHECK-NEXT: [[VECEXT1_I:%.*]] = extractelement <2 x double> [[A]], i32 1 +// CHECK-NEXT: [[VECINIT2_I:%.*]] = insertelement <2 x double> [[VECINIT_I]], double [[VECEXT1_I]], i32 1 +// CHECK-NEXT: ret <2 x double> [[VECINIT2_I]] +// __m128d test_cmpgt_sd(__m128d a, __m128d b) { - // CHECK: @llvm.x86.sse2.cmp.sd({{.*}}, i8 1) - // CHECK: shufflevector <{{.*}}, <2 x i32> return _mm_cmpgt_sd(a, b); } +// CHECK-LABEL: define dso_local <2 x double> @test_cmpge_sd( +// CHECK-SAME: <2 x double> noundef [[A:%.*]], <2 x double> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> [[B]], <2 x double> [[A]], i8 2) +// CHECK-NEXT: [[VECEXT_I:%.*]] = extractelement <2 x double> [[TMP0]], i32 0 +// CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <2 x double> poison, double [[VECEXT_I]], i32 0 +// CHECK-NEXT: [[VECEXT1_I:%.*]] = extractelement <2 x double> [[A]], i32 1 +// CHECK-NEXT: [[VECINIT2_I:%.*]] = insertelement <2 x double> [[VECINIT_I]], double [[VECEXT1_I]], i32 1 +// CHECK-NEXT: ret <2 x double> [[VECINIT2_I]] +// __m128d test_cmpge_sd(__m128d a, __m128d b) { - // CHECK: @llvm.x86.sse2.cmp.sd({{.*}}, i8 2) - // CHECK: shufflevector <{{.*}}, <2 x i32> return _mm_cmpge_sd(a, b); } +// CHECK-LABEL: define dso_local <2 x double> @test_cmpngt_sd( +// CHECK-SAME: <2 x double> noundef [[A:%.*]], <2 x double> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> [[B]], <2 x double> [[A]], i8 5) +// CHECK-NEXT: [[VECEXT_I:%.*]] = extractelement <2 x double> [[TMP0]], i32 0 +// CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <2 x double> poison, double [[VECEXT_I]], i32 0 +// CHECK-NEXT: [[VECEXT1_I:%.*]] = extractelement <2 x double> [[A]], i32 1 +// CHECK-NEXT: [[VECINIT2_I:%.*]] = insertelement <2 x double> [[VECINIT_I]], double [[VECEXT1_I]], i32 1 +// CHECK-NEXT: ret <2 x double> [[VECINIT2_I]] +// __m128d test_cmpngt_sd(__m128d a, __m128d b) { - // CHECK: @llvm.x86.sse2.cmp.sd({{.*}}, i8 5) - // CHECK: shufflevector <{{.*}}, <2 x i32> return _mm_cmpngt_sd(a, b); } +// CHECK-LABEL: define dso_local <2 x double> @test_cmpnge_sd( +// CHECK-SAME: <2 x double> noundef [[A:%.*]], <2 x double> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = call <2 x double> @llvm.x86.sse2.cmp.sd(<2 x double> [[B]], <2 x double> [[A]], i8 6) +// CHECK-NEXT: [[VECEXT_I:%.*]] = extractelement <2 x double> [[TMP0]], i32 0 +// CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <2 x double> poison, double [[VECEXT_I]], i32 0 +// CHECK-NEXT: [[VECEXT1_I:%.*]] = extractelement <2 x double> [[A]], i32 1 +// CHECK-NEXT: [[VECINIT2_I:%.*]] = insertelement <2 x double> [[VECINIT_I]], double [[VECEXT1_I]], i32 1 +// CHECK-NEXT: ret <2 x double> [[VECINIT2_I]] +// __m128d test_cmpnge_sd(__m128d a, __m128d b) { - // CHECK: @llvm.x86.sse2.cmp.sd({{.*}}, i8 6) - // CHECK: shufflevector <{{.*}}, <2 x i32> return _mm_cmpnge_sd(a, b); } diff --git a/clang/test/CodeGen/X86/avx-shuffle-builtins.c b/clang/test/CodeGen/X86/avx-shuffle-builtins.c index d184d28f3e07aa9b383a6e66972bddc9d42698cc..1c05fa436983ed74ccadca14d615e4d5bd80ee4f 100644 --- a/clang/test/CodeGen/X86/avx-shuffle-builtins.c +++ b/clang/test/CodeGen/X86/avx-shuffle-builtins.c @@ -1,7 +1,7 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 // REQUIRES: x86-registered-target -// RUN: %clang_cc1 -ffreestanding %s -O3 -triple=x86_64-apple-darwin -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,X64 -// RUN: %clang_cc1 -ffreestanding %s -O3 -triple=i386-apple-darwin -target-feature +avx -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,X86 -// FIXME: This is testing optimized generation of shuffle instructions and should be fixed. +// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-- -target-feature +avx -disable-O0-optnone -emit-llvm -o - | opt -S -passes=mem2reg | FileCheck %s +// RUN: %clang_cc1 -ffreestanding %s -triple=i386-- -target-feature +avx -disable-O0-optnone -emit-llvm -o - | opt -S -passes=mem2reg | FileCheck %s #include @@ -10,201 +10,341 @@ // Test LLVM IR codegen of shuffle instructions, checking if the masks are correct // +// CHECK-LABEL: define dso_local <8 x float> @x( +// CHECK-SAME: <8 x float> noundef [[A:%.*]], <8 x float> noundef [[B:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SHUFP:%.*]] = shufflevector <8 x float> [[A]], <8 x float> [[B]], <8 x i32> +// CHECK-NEXT: ret <8 x float> [[SHUFP]] +// __m256 x(__m256 a, __m256 b) { - // CHECK-LABEL: x - // CHECK: shufflevector{{.*}} return _mm256_shuffle_ps(a, b, 203); } +// CHECK-LABEL: define dso_local <2 x double> @test_mm_permute_pd( +// CHECK-SAME: <2 x double> noundef [[A:%.*]]) #[[ATTR1:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PERMIL:%.*]] = shufflevector <2 x double> [[A]], <2 x double> poison, <2 x i32> +// CHECK-NEXT: ret <2 x double> [[PERMIL]] +// __m128d test_mm_permute_pd(__m128d a) { - // CHECK-LABEL: test_mm_permute_pd - // CHECK: shufflevector{{.*}} return _mm_permute_pd(a, 1); } +// CHECK-LABEL: define dso_local <4 x double> @test_mm256_permute_pd( +// CHECK-SAME: <4 x double> noundef [[A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PERMIL:%.*]] = shufflevector <4 x double> [[A]], <4 x double> poison, <4 x i32> +// CHECK-NEXT: ret <4 x double> [[PERMIL]] +// __m256d test_mm256_permute_pd(__m256d a) { - // CHECK-LABEL: test_mm256_permute_pd - // CHECK: shufflevector{{.*}} return _mm256_permute_pd(a, 5); } +// CHECK-LABEL: define dso_local <4 x float> @test_mm_permute_ps( +// CHECK-SAME: <4 x float> noundef [[A:%.*]]) #[[ATTR1]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PERMIL:%.*]] = shufflevector <4 x float> [[A]], <4 x float> poison, <4 x i32> +// CHECK-NEXT: ret <4 x float> [[PERMIL]] +// __m128 test_mm_permute_ps(__m128 a) { - // CHECK-LABEL: test_mm_permute_ps - // CHECK: shufflevector{{.*}} return _mm_permute_ps(a, 0x1b); } -// Test case for PR12401 +// CHECK-LABEL: define dso_local <4 x float> @test_mm_permute_ps2( +// CHECK-SAME: <4 x float> noundef [[A:%.*]]) #[[ATTR1]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PERMIL:%.*]] = shufflevector <4 x float> [[A]], <4 x float> poison, <4 x i32> +// CHECK-NEXT: ret <4 x float> [[PERMIL]] +// __m128 test_mm_permute_ps2(__m128 a) { - // CHECK-LABEL: test_mm_permute_ps2 - // CHECK: shufflevector{{.*}} return _mm_permute_ps(a, 0xe6); } +// CHECK-LABEL: define dso_local <8 x float> @test_mm256_permute_ps( +// CHECK-SAME: <8 x float> noundef [[A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PERMIL:%.*]] = shufflevector <8 x float> [[A]], <8 x float> poison, <8 x i32> +// CHECK-NEXT: ret <8 x float> [[PERMIL]] +// __m256 test_mm256_permute_ps(__m256 a) { - // CHECK-LABEL: test_mm256_permute_ps - // CHECK: shufflevector{{.*}} return _mm256_permute_ps(a, 0x1b); } +// CHECK-LABEL: define dso_local <4 x double> @test_mm256_permute2f128_pd( +// CHECK-SAME: <4 x double> noundef [[A:%.*]], <4 x double> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[VPERM:%.*]] = shufflevector <4 x double> [[A]], <4 x double> [[B]], <4 x i32> +// CHECK-NEXT: ret <4 x double> [[VPERM]] +// __m256d test_mm256_permute2f128_pd(__m256d a, __m256d b) { - // CHECK-LABEL: test_mm256_permute2f128_pd - // CHECK: shufflevector{{.*}} return _mm256_permute2f128_pd(a, b, 0x31); } +// CHECK-LABEL: define dso_local <8 x float> @test_mm256_permute2f128_ps( +// CHECK-SAME: <8 x float> noundef [[A:%.*]], <8 x float> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[VPERM:%.*]] = shufflevector <8 x float> [[B]], <8 x float> [[A]], <8 x i32> +// CHECK-NEXT: ret <8 x float> [[VPERM]] +// __m256 test_mm256_permute2f128_ps(__m256 a, __m256 b) { - // CHECK-LABEL: test_mm256_permute2f128_ps - // CHECK: shufflevector{{.*}} return _mm256_permute2f128_ps(a, b, 0x13); } +// CHECK-LABEL: define dso_local <4 x i64> @test_mm256_permute2f128_si256( +// CHECK-SAME: <4 x i64> noundef [[A:%.*]], <4 x i64> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i64> [[A]] to <8 x i32> +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <4 x i64> [[B]] to <8 x i32> +// CHECK-NEXT: [[VPERM:%.*]] = shufflevector <8 x i32> [[TMP0]], <8 x i32> [[TMP1]], <8 x i32> +// CHECK-NEXT: [[TMP2:%.*]] = bitcast <8 x i32> [[VPERM]] to <4 x i64> +// CHECK-NEXT: ret <4 x i64> [[TMP2]] +// __m256i test_mm256_permute2f128_si256(__m256i a, __m256i b) { - // CHECK-LABEL: test_mm256_permute2f128_si256 - // CHECK: shufflevector{{.*}} return _mm256_permute2f128_si256(a, b, 0x20); } -__m128 -test_mm_broadcast_ss(float const *__a) { - // CHECK-LABEL: test_mm_broadcast_ss - // CHECK: insertelement <4 x float> {{.*}}, i64 0 - // CHECK: shufflevector <4 x float> {{.*}}, <4 x float> poison, <4 x i32> zeroinitializer +// CHECK-LABEL: define dso_local <4 x float> @test_mm_broadcast_ss( +// CHECK-SAME: ptr noundef [[__A:%.*]]) #[[ATTR1]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[__A]], align 1 +// CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <4 x float> poison, float [[TMP0]], i32 0 +// CHECK-NEXT: [[VECINIT2_I:%.*]] = insertelement <4 x float> [[VECINIT_I]], float [[TMP0]], i32 1 +// CHECK-NEXT: [[VECINIT3_I:%.*]] = insertelement <4 x float> [[VECINIT2_I]], float [[TMP0]], i32 2 +// CHECK-NEXT: [[VECINIT4_I:%.*]] = insertelement <4 x float> [[VECINIT3_I]], float [[TMP0]], i32 3 +// CHECK-NEXT: ret <4 x float> [[VECINIT4_I]] +// +__m128 test_mm_broadcast_ss(float const *__a) { return _mm_broadcast_ss(__a); } -__m256d -test_mm256_broadcast_sd(double const *__a) { - // CHECK-LABEL: test_mm256_broadcast_sd - // CHECK: insertelement <4 x double> {{.*}}, i64 0 - // CHECK: shufflevector <4 x double> {{.*}}, <4 x double> poison, <4 x i32> zeroinitializer +// CHECK-LABEL: define dso_local <4 x double> @test_mm256_broadcast_sd( +// CHECK-SAME: ptr noundef [[__A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[__A]], align 1 +// CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <4 x double> poison, double [[TMP0]], i32 0 +// CHECK-NEXT: [[VECINIT2_I:%.*]] = insertelement <4 x double> [[VECINIT_I]], double [[TMP0]], i32 1 +// CHECK-NEXT: [[VECINIT3_I:%.*]] = insertelement <4 x double> [[VECINIT2_I]], double [[TMP0]], i32 2 +// CHECK-NEXT: [[VECINIT4_I:%.*]] = insertelement <4 x double> [[VECINIT3_I]], double [[TMP0]], i32 3 +// CHECK-NEXT: ret <4 x double> [[VECINIT4_I]] +// +__m256d test_mm256_broadcast_sd(double const *__a) { return _mm256_broadcast_sd(__a); } -__m256 -test_mm256_broadcast_ss(float const *__a) { - // CHECK-LABEL: test_mm256_broadcast_ss - // CHECK: insertelement <8 x float> {{.*}}, i64 0 - // CHECK: shufflevector <8 x float> {{.*}}, <8 x float> poison, <8 x i32> zeroinitializer +// CHECK-LABEL: define dso_local <8 x float> @test_mm256_broadcast_ss( +// CHECK-SAME: ptr noundef [[__A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[__A]], align 1 +// CHECK-NEXT: [[VECINIT_I:%.*]] = insertelement <8 x float> poison, float [[TMP0]], i32 0 +// CHECK-NEXT: [[VECINIT2_I:%.*]] = insertelement <8 x float> [[VECINIT_I]], float [[TMP0]], i32 1 +// CHECK-NEXT: [[VECINIT3_I:%.*]] = insertelement <8 x float> [[VECINIT2_I]], float [[TMP0]], i32 2 +// CHECK-NEXT: [[VECINIT4_I:%.*]] = insertelement <8 x float> [[VECINIT3_I]], float [[TMP0]], i32 3 +// CHECK-NEXT: [[VECINIT5_I:%.*]] = insertelement <8 x float> [[VECINIT4_I]], float [[TMP0]], i32 4 +// CHECK-NEXT: [[VECINIT6_I:%.*]] = insertelement <8 x float> [[VECINIT5_I]], float [[TMP0]], i32 5 +// CHECK-NEXT: [[VECINIT7_I:%.*]] = insertelement <8 x float> [[VECINIT6_I]], float [[TMP0]], i32 6 +// CHECK-NEXT: [[VECINIT8_I:%.*]] = insertelement <8 x float> [[VECINIT7_I]], float [[TMP0]], i32 7 +// CHECK-NEXT: ret <8 x float> [[VECINIT8_I]] +// +__m256 test_mm256_broadcast_ss(float const *__a) { return _mm256_broadcast_ss(__a); } // Make sure we have the correct mask for each insertf128 case. +// CHECK-LABEL: define dso_local <8 x float> @test_mm256_insertf128_ps_0( +// CHECK-SAME: <8 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[WIDEN:%.*]] = shufflevector <4 x float> [[B]], <4 x float> poison, <8 x i32> +// CHECK-NEXT: [[INSERT:%.*]] = shufflevector <8 x float> [[A]], <8 x float> [[WIDEN]], <8 x i32> +// CHECK-NEXT: ret <8 x float> [[INSERT]] +// __m256 test_mm256_insertf128_ps_0(__m256 a, __m128 b) { - // CHECK-LABEL: test_mm256_insertf128_ps_0 - // CHECK: shufflevector{{.*}} return _mm256_insertf128_ps(a, b, 0); } +// CHECK-LABEL: define dso_local <4 x double> @test_mm256_insertf128_pd_0( +// CHECK-SAME: <4 x double> noundef [[A:%.*]], <2 x double> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[WIDEN:%.*]] = shufflevector <2 x double> [[B]], <2 x double> poison, <4 x i32> +// CHECK-NEXT: [[INSERT:%.*]] = shufflevector <4 x double> [[A]], <4 x double> [[WIDEN]], <4 x i32> +// CHECK-NEXT: ret <4 x double> [[INSERT]] +// __m256d test_mm256_insertf128_pd_0(__m256d a, __m128d b) { - // CHECK-LABEL: test_mm256_insertf128_pd_0 - // CHECK: shufflevector{{.*}} return _mm256_insertf128_pd(a, b, 0); } +// CHECK-LABEL: define dso_local <4 x i64> @test_mm256_insertf128_si256_0( +// CHECK-SAME: <4 x i64> noundef [[A:%.*]], <2 x i64> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i64> [[A]] to <8 x i32> +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[B]] to <4 x i32> +// CHECK-NEXT: [[WIDEN:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> poison, <8 x i32> +// CHECK-NEXT: [[INSERT:%.*]] = shufflevector <8 x i32> [[TMP0]], <8 x i32> [[WIDEN]], <8 x i32> +// CHECK-NEXT: [[TMP2:%.*]] = bitcast <8 x i32> [[INSERT]] to <4 x i64> +// CHECK-NEXT: ret <4 x i64> [[TMP2]] +// __m256i test_mm256_insertf128_si256_0(__m256i a, __m128i b) { - // CHECK-LABEL: test_mm256_insertf128_si256_0 - // X64: shufflevector{{.*}} - // X86: shufflevector{{.*}} return _mm256_insertf128_si256(a, b, 0); } +// CHECK-LABEL: define dso_local <8 x float> @test_mm256_insertf128_ps_1( +// CHECK-SAME: <8 x float> noundef [[A:%.*]], <4 x float> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[WIDEN:%.*]] = shufflevector <4 x float> [[B]], <4 x float> poison, <8 x i32> +// CHECK-NEXT: [[INSERT:%.*]] = shufflevector <8 x float> [[A]], <8 x float> [[WIDEN]], <8 x i32> +// CHECK-NEXT: ret <8 x float> [[INSERT]] +// __m256 test_mm256_insertf128_ps_1(__m256 a, __m128 b) { - // CHECK-LABEL: test_mm256_insertf128_ps_1 - // CHECK: shufflevector{{.*}} return _mm256_insertf128_ps(a, b, 1); } +// CHECK-LABEL: define dso_local <4 x double> @test_mm256_insertf128_pd_1( +// CHECK-SAME: <4 x double> noundef [[A:%.*]], <2 x double> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[WIDEN:%.*]] = shufflevector <2 x double> [[B]], <2 x double> poison, <4 x i32> +// CHECK-NEXT: [[INSERT:%.*]] = shufflevector <4 x double> [[A]], <4 x double> [[WIDEN]], <4 x i32> +// CHECK-NEXT: ret <4 x double> [[INSERT]] +// __m256d test_mm256_insertf128_pd_1(__m256d a, __m128d b) { - // CHECK-LABEL: test_mm256_insertf128_pd_1 - // CHECK: shufflevector{{.*}} return _mm256_insertf128_pd(a, b, 1); } +// CHECK-LABEL: define dso_local <4 x i64> @test_mm256_insertf128_si256_1( +// CHECK-SAME: <4 x i64> noundef [[A:%.*]], <2 x i64> noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i64> [[A]] to <8 x i32> +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> [[B]] to <4 x i32> +// CHECK-NEXT: [[WIDEN:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> poison, <8 x i32> +// CHECK-NEXT: [[INSERT:%.*]] = shufflevector <8 x i32> [[TMP0]], <8 x i32> [[WIDEN]], <8 x i32> +// CHECK-NEXT: [[TMP2:%.*]] = bitcast <8 x i32> [[INSERT]] to <4 x i64> +// CHECK-NEXT: ret <4 x i64> [[TMP2]] +// __m256i test_mm256_insertf128_si256_1(__m256i a, __m128i b) { - // CHECK-LABEL: test_mm256_insertf128_si256_1 - // X64: shufflevector{{.*}} - // X86: shufflevector{{.*}} return _mm256_insertf128_si256(a, b, 1); } // Make sure we have the correct mask for each extractf128 case. +// CHECK-LABEL: define dso_local <4 x float> @test_mm256_extractf128_ps_0( +// CHECK-SAME: <8 x float> noundef [[A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[EXTRACT:%.*]] = shufflevector <8 x float> [[A]], <8 x float> poison, <4 x i32> +// CHECK-NEXT: ret <4 x float> [[EXTRACT]] +// __m128 test_mm256_extractf128_ps_0(__m256 a) { - // X64-LABEL: test_mm256_extractf128_ps_0 - // X64: shufflevector{{.*}} - // - // X86-LABEL: test_mm256_extractf128_ps_0 - // X86: shufflevector{{.*}} return _mm256_extractf128_ps(a, 0); } +// CHECK-LABEL: define dso_local <2 x double> @test_mm256_extractf128_pd_0( +// CHECK-SAME: <4 x double> noundef [[A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[EXTRACT:%.*]] = shufflevector <4 x double> [[A]], <4 x double> poison, <2 x i32> +// CHECK-NEXT: ret <2 x double> [[EXTRACT]] +// __m128d test_mm256_extractf128_pd_0(__m256d a) { - // CHECK-LABEL: test_mm256_extractf128_pd_0 - // CHECK: shufflevector{{.*}} return _mm256_extractf128_pd(a, 0); } +// CHECK-LABEL: define dso_local <2 x i64> @test_mm256_extractf128_si256_0( +// CHECK-SAME: <4 x i64> noundef [[A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i64> [[A]] to <8 x i32> +// CHECK-NEXT: [[EXTRACT:%.*]] = shufflevector <8 x i32> [[TMP0]], <8 x i32> poison, <4 x i32> +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <4 x i32> [[EXTRACT]] to <2 x i64> +// CHECK-NEXT: ret <2 x i64> [[TMP1]] +// __m128i test_mm256_extractf128_si256_0(__m256i a) { - // CHECK-LABEL: test_mm256_extractf128_si256_0 - // CHECK: shufflevector{{.*}} return _mm256_extractf128_si256(a, 0); } +// CHECK-LABEL: define dso_local <4 x float> @test_mm256_extractf128_ps_1( +// CHECK-SAME: <8 x float> noundef [[A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[EXTRACT:%.*]] = shufflevector <8 x float> [[A]], <8 x float> poison, <4 x i32> +// CHECK-NEXT: ret <4 x float> [[EXTRACT]] +// __m128 test_mm256_extractf128_ps_1(__m256 a) { - // X64-LABEL: test_mm256_extractf128_ps_1 - // X64: shufflevector{{.*}} - // - // X86-LABEL: test_mm256_extractf128_ps_1 - // X86: shufflevector{{.*}} return _mm256_extractf128_ps(a, 1); } +// CHECK-LABEL: define dso_local <2 x double> @test_mm256_extractf128_pd_1( +// CHECK-SAME: <4 x double> noundef [[A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[EXTRACT:%.*]] = shufflevector <4 x double> [[A]], <4 x double> poison, <2 x i32> +// CHECK-NEXT: ret <2 x double> [[EXTRACT]] +// __m128d test_mm256_extractf128_pd_1(__m256d a) { - // CHECK-LABEL: test_mm256_extractf128_pd_1 - // CHECK: shufflevector{{.*}} return _mm256_extractf128_pd(a, 1); } +// CHECK-LABEL: define dso_local <2 x i64> @test_mm256_extractf128_si256_1( +// CHECK-SAME: <4 x i64> noundef [[A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = bitcast <4 x i64> [[A]] to <8 x i32> +// CHECK-NEXT: [[EXTRACT:%.*]] = shufflevector <8 x i32> [[TMP0]], <8 x i32> poison, <4 x i32> +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <4 x i32> [[EXTRACT]] to <2 x i64> +// CHECK-NEXT: ret <2 x i64> [[TMP1]] +// __m128i test_mm256_extractf128_si256_1(__m256i a) { - // CHECK-LABEL: test_mm256_extractf128_si256_1 - // CHECK: shufflevector{{.*}} return _mm256_extractf128_si256(a, 1); } +// CHECK-LABEL: define dso_local <8 x float> @test_mm256_set_m128( +// CHECK-SAME: <4 x float> noundef [[HI:%.*]], <4 x float> noundef [[LO:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <4 x float> [[LO]], <4 x float> [[HI]], <8 x i32> +// CHECK-NEXT: ret <8 x float> [[SHUFFLE_I]] +// __m256 test_mm256_set_m128(__m128 hi, __m128 lo) { - // CHECK-LABEL: test_mm256_set_m128 - // CHECK: shufflevector{{.*}} return _mm256_set_m128(hi, lo); } +// CHECK-LABEL: define dso_local <4 x double> @test_mm256_set_m128d( +// CHECK-SAME: <2 x double> noundef [[HI:%.*]], <2 x double> noundef [[LO:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <2 x double> [[LO]], <2 x double> [[HI]], <4 x i32> +// CHECK-NEXT: ret <4 x double> [[SHUFFLE_I]] +// __m256d test_mm256_set_m128d(__m128d hi, __m128d lo) { - // CHECK-LABEL: test_mm256_set_m128d - // CHECK: shufflevector{{.*}} return _mm256_set_m128d(hi, lo); } +// CHECK-LABEL: define dso_local <4 x i64> @test_mm256_set_m128i( +// CHECK-SAME: <2 x i64> noundef [[HI:%.*]], <2 x i64> noundef [[LO:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SHUFFLE_I:%.*]] = shufflevector <2 x i64> [[LO]], <2 x i64> [[HI]], <4 x i32> +// CHECK-NEXT: ret <4 x i64> [[SHUFFLE_I]] +// __m256i test_mm256_set_m128i(__m128i hi, __m128i lo) { - // CHECK-LABEL: test_mm256_set_m128i - // CHECK: shufflevector{{.*}} return _mm256_set_m128i(hi, lo); } +// CHECK-LABEL: define dso_local <8 x float> @test_mm256_setr_m128( +// CHECK-SAME: <4 x float> noundef [[HI:%.*]], <4 x float> noundef [[LO:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SHUFFLE_I_I:%.*]] = shufflevector <4 x float> [[LO]], <4 x float> [[HI]], <8 x i32> +// CHECK-NEXT: ret <8 x float> [[SHUFFLE_I_I]] +// __m256 test_mm256_setr_m128(__m128 hi, __m128 lo) { - // CHECK-LABEL: test_mm256_setr_m128 - // CHECK: shufflevector{{.*}} return _mm256_setr_m128(lo, hi); } +// CHECK-LABEL: define dso_local <4 x double> @test_mm256_setr_m128d( +// CHECK-SAME: <2 x double> noundef [[HI:%.*]], <2 x double> noundef [[LO:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SHUFFLE_I_I:%.*]] = shufflevector <2 x double> [[LO]], <2 x double> [[HI]], <4 x i32> +// CHECK-NEXT: ret <4 x double> [[SHUFFLE_I_I]] +// __m256d test_mm256_setr_m128d(__m128d hi, __m128d lo) { - // CHECK-LABEL: test_mm256_setr_m128d - // CHECK: shufflevector{{.*}} return _mm256_setr_m128d(lo, hi); } +// CHECK-LABEL: define dso_local <4 x i64> @test_mm256_setr_m128i( +// CHECK-SAME: <2 x i64> noundef [[HI:%.*]], <2 x i64> noundef [[LO:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SHUFFLE_I_I:%.*]] = shufflevector <2 x i64> [[LO]], <2 x i64> [[HI]], <4 x i32> +// CHECK-NEXT: ret <4 x i64> [[SHUFFLE_I_I]] +// __m256i test_mm256_setr_m128i(__m128i hi, __m128i lo) { - // CHECK-LABEL: test_mm256_setr_m128i - // CHECK: shufflevector{{.*}} return _mm256_setr_m128i(lo, hi); } diff --git a/clang/test/CodeGen/X86/builtin_test_helpers.h b/clang/test/CodeGen/X86/builtin_test_helpers.h new file mode 100644 index 0000000000000000000000000000000000000000..043b6ecbc69f18fc1d82ae6302927f4c55fea718 --- /dev/null +++ b/clang/test/CodeGen/X86/builtin_test_helpers.h @@ -0,0 +1,25 @@ +/* Helper methods for builtin intrinsic tests */ + +#include + +#if defined(__cplusplus) && (__cplusplus >= 201103L) + +constexpr bool match_m128(__m128 v, float x, float y, float z, float w) { + return v[0] == x && v[1] == y && v[2] == z && v[3] == w; +} + +constexpr bool match_m128d(__m128d v, double x, double y) { + return v[0] == x && v[1] == y; +} + +constexpr bool match_m128i(__m128i v, unsigned long long x, unsigned long long y) { + return v[0] == x && v[1] == y; +} + +#define TEST_CONSTEXPR(...) static_assert(__VA_ARGS__) + +#else + +#define TEST_CONSTEXPR(...) + +#endif \ No newline at end of file diff --git a/clang/test/CodeGen/X86/movrs-avx10.2-512-builtins-error-32.c b/clang/test/CodeGen/X86/movrs-avx10.2-512-builtins-error-32.c new file mode 100644 index 0000000000000000000000000000000000000000..a4d887f0be41646af318b98674c4ff7b0fc80980 --- /dev/null +++ b/clang/test/CodeGen/X86/movrs-avx10.2-512-builtins-error-32.c @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -ffreestanding %s -Wno-implicit-function-declaration -triple=i386-- -target-feature +movrs -target-feature +avx10.2-512 -verify + +#include +__m512i test_mm512_loadrs_epi8(const __m512i * __A) { + return _mm512_loadrs_epi8(__A); // expected-error {{returning 'int' from a function with incompatible result type '__m512i' (vector of 8 'long long' values)}} +} + +__m512i test_mm512_mask_loadrs_epi8(__m512i __A, __mmask64 __B, const __m512i * __C) { + return _mm512_mask_loadrs_epi8(__A, __B, __C); // expected-error {{returning 'int' from a function with incompatible result type '__m512i' (vector of 8 'long long' values)}} +} + +__m512i test_mm512_maskz_loadrs_epi8(__mmask64 __A, const __m512i * __B) { + return _mm512_maskz_loadrs_epi8(__A, __B); // expected-error {{returning 'int' from a function with incompatible result type '__m512i' (vector of 8 'long long' values)}} +} + +__m512i test_mm512_loadrs_epi32(const __m512i * __A) { + return _mm512_loadrs_epi32(__A); // expected-error {{returning 'int' from a function with incompatible result type '__m512i' (vector of 8 'long long' values)}} +} + +__m512i test_mm512_mask_loadrs_epi32(__m512i __A, __mmask16 __B, const __m512i * __C) { + return _mm512_mask_loadrs_epi32(__A, __B, __C); // expected-error {{returning 'int' from a function with incompatible result type '__m512i' (vector of 8 'long long' values)}} +} + +__m512i test_mm512_maskz_loadrs_epi32(__mmask16 __A, const __m512i * __B) { + return _mm512_maskz_loadrs_epi32(__A, __B); // expected-error {{returning 'int' from a function with incompatible result type '__m512i' (vector of 8 'long long' values)}} +} + +__m512i test_mm512_loadrs_epi64(const __m512i * __A) { + return _mm512_loadrs_epi64(__A); // expected-error {{returning 'int' from a function with incompatible result type '__m512i' (vector of 8 'long long' values)}} +} + +__m512i test_mm512_mask_loadrs_epi64(__m512i __A, __mmask8 __B, const __m512i * __C) { + return _mm512_mask_loadrs_epi64(__A, __B, __C); // expected-error {{returning 'int' from a function with incompatible result type '__m512i' (vector of 8 'long long' values)}} +} + +__m512i test_mm512_maskz_loadrs_epi64(__mmask8 __A, const __m512i * __B) { + return _mm512_maskz_loadrs_epi64(__A, __B); // expected-error {{returning 'int' from a function with incompatible result type '__m512i' (vector of 8 'long long' values)}} +} + +__m512i test_mm512_loadrs_epi16(const __m512i * __A) { + return _mm512_loadrs_epi16(__A); // expected-error {{returning 'int' from a function with incompatible result type '__m512i' (vector of 8 'long long' values)}} +} + +__m512i test_mm512_mask_loadrs_epi16(__m512i __A, __mmask32 __B, const __m512i * __C) { + return _mm512_mask_loadrs_epi16(__A, __B, __C); // expected-error {{returning 'int' from a function with incompatible result type '__m512i' (vector of 8 'long long' values)}} +} + +__m512i test_mm512_maskz_loadrs_epi16(__mmask32 __A, const __m512i * __B) { + return _mm512_maskz_loadrs_epi16(__A, __B); // expected-error {{returning 'int' from a function with incompatible result type '__m512i' (vector of 8 'long long' values)}} +} diff --git a/clang/test/CodeGen/X86/movrs-avx10.2-512-builtins.c b/clang/test/CodeGen/X86/movrs-avx10.2-512-builtins.c new file mode 100644 index 0000000000000000000000000000000000000000..997d6dbc53a8b035f5279c3f00da4e820487656f --- /dev/null +++ b/clang/test/CodeGen/X86/movrs-avx10.2-512-builtins.c @@ -0,0 +1,87 @@ +// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-- -target-feature +movrs -target-feature +avx10.2-512 -emit-llvm -o - -Wall -Werror | FileCheck %s + +#include + +__m512i test_mm512_loadrs_epi8(const __m512i * __A) { + // CHECK-LABEL: @test_mm512_loadrs_epi8( + // CHECK: call <64 x i8> @llvm.x86.avx10.vmovrsb512( + return _mm512_loadrs_epi8(__A); +} + +__m512i test_mm512_mask_loadrs_epi8(__m512i __A, __mmask64 __B, const __m512i * __C) { + // CHECK-LABEL: @test_mm512_mask_loadrs_epi8( + // CHECK: call <64 x i8> @llvm.x86.avx10.vmovrsb512( + // CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}} + return _mm512_mask_loadrs_epi8(__A, __B, __C); +} + +__m512i test_mm512_maskz_loadrs_epi8(__mmask64 __A, const __m512i * __B) { + // CHECK-LABEL: @test_mm512_maskz_loadrs_epi8( + // CHECK: call <64 x i8> @llvm.x86.avx10.vmovrsb512( + // CHECK: store <8 x i64> zeroinitializer + // CHECK: select <64 x i1> %{{.*}}, <64 x i8> %{{.*}}, <64 x i8> %{{.*}} + return _mm512_maskz_loadrs_epi8(__A, __B); +} + +__m512i test_mm512_loadrs_epi32(const __m512i * __A) { + // CHECK-LABEL: @test_mm512_loadrs_epi32( + // CHECK: call <16 x i32> @llvm.x86.avx10.vmovrsd512( + return _mm512_loadrs_epi32(__A); +} + +__m512i test_mm512_mask_loadrs_epi32(__m512i __A, __mmask16 __B, const __m512i * __C) { + // CHECK-LABEL: @test_mm512_mask_loadrs_epi32( + // CHECK: call <16 x i32> @llvm.x86.avx10.vmovrsd512( + // CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}} + return _mm512_mask_loadrs_epi32(__A, __B, __C); +} + +__m512i test_mm512_maskz_loadrs_epi32(__mmask16 __A, const __m512i * __B) { + // CHECK-LABEL: @test_mm512_maskz_loadrs_epi32( + // CHECK: call <16 x i32> @llvm.x86.avx10.vmovrsd512( + // CHECK: store <8 x i64> zeroinitializer + // CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}} + return _mm512_maskz_loadrs_epi32(__A, __B); +} + +__m512i test_mm512_loadrs_epi64(const __m512i * __A) { + // CHECK-LABEL: @test_mm512_loadrs_epi64( + // CHECK: call <8 x i64> @llvm.x86.avx10.vmovrsq512( + return _mm512_loadrs_epi64(__A); +} + +__m512i test_mm512_mask_loadrs_epi64(__m512i __A, __mmask8 __B, const __m512i * __C) { + // CHECK-LABEL: @test_mm512_mask_loadrs_epi64( + // CHECK: call <8 x i64> @llvm.x86.avx10.vmovrsq512( + // CHECK: select <8 x i1> %{{.*}}, <8 x i64> %{{.*}}, <8 x i64> %{{.*}} + return _mm512_mask_loadrs_epi64(__A, __B, __C); +} + +__m512i test_mm512_maskz_loadrs_epi64(__mmask8 __A, const __m512i * __B) { + // CHECK-LABEL: @test_mm512_maskz_loadrs_epi64( + // CHECK: call <8 x i64> @llvm.x86.avx10.vmovrsq512( + // CHECK: store <8 x i64> zeroinitializer + // CHECK: select <8 x i1> %{{.*}}, <8 x i64> %{{.*}}, <8 x i64> %{{.*}} + return _mm512_maskz_loadrs_epi64(__A, __B); +} + +__m512i test_mm512_loadrs_epi16(const __m512i * __A) { + // CHECK-LABEL: @test_mm512_loadrs_epi16( + // CHECK: call <32 x i16> @llvm.x86.avx10.vmovrsw512( + return _mm512_loadrs_epi16(__A); +} + +__m512i test_mm512_mask_loadrs_epi16(__m512i __A, __mmask32 __B, const __m512i * __C) { + // CHECK-LABEL: @test_mm512_mask_loadrs_epi16( + // CHECK: call <32 x i16> @llvm.x86.avx10.vmovrsw512( + // CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}} + return _mm512_mask_loadrs_epi16(__A, __B, __C); +} + +__m512i test_mm512_maskz_loadrs_epi16(__mmask32 __A, const __m512i * __B) { + // CHECK-LABEL: @test_mm512_maskz_loadrs_epi16( + // CHECK: call <32 x i16> @llvm.x86.avx10.vmovrsw512( + // CHECK: store <8 x i64> zeroinitializer + // CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}} + return _mm512_maskz_loadrs_epi16(__A, __B); +} diff --git a/clang/test/CodeGen/X86/movrs-avx10.2-builtins-error-32.c b/clang/test/CodeGen/X86/movrs-avx10.2-builtins-error-32.c new file mode 100644 index 0000000000000000000000000000000000000000..2a7204e39b8300ea47b24b638bab0a431c6ebd23 --- /dev/null +++ b/clang/test/CodeGen/X86/movrs-avx10.2-builtins-error-32.c @@ -0,0 +1,98 @@ +// RUN: %clang_cc1 -ffreestanding %s -Wno-implicit-function-declaration -triple=i386-unknown-unknown -target-feature +movrs -target-feature +avx10.2-256 -verify + +#include +__m128i test_mm_loadrs_epi8(const __m128i * __A) { + return _mm_loadrs_epi8(__A); // expected-error {{returning 'int' from a function with incompatible result type '__m128i' (vector of 2 'long long' values)}} +} + +__m128i test_mm_mask_loadrs_epi8(__m128i __A, __mmask16 __B, const __m128i * __C) { + return _mm_mask_loadrs_epi8(__A, __B, __C); // expected-error {{returning 'int' from a function with incompatible result type '__m128i' (vector of 2 'long long' values)}} +} + +__m128i test_mm_maskz_loadrs_epi8(__mmask16 __A, const __m128i * __B) { + return _mm_maskz_loadrs_epi8(__A, __B); // expected-error {{returning 'int' from a function with incompatible result type '__m128i' (vector of 2 'long long' values)}} +} + +__m256i test_mm256_loadrs_epi8(const __m256i * __A) { + return _mm256_loadrs_epi8(__A); // expected-error {{returning 'int' from a function with incompatible result type '__m256i' (vector of 4 'long long' values)}} +} + +__m256i test_mm256_mask_loadrs_epi8(__m256i __A, __mmask32 __B, const __m256i * __C) { + return _mm256_mask_loadrs_epi8(__A, __B, __C); // expected-error {{returning 'int' from a function with incompatible result type '__m256i' (vector of 4 'long long' values)}} +} + +__m256i test_mm256_maskz_loadrs_epi8(__mmask32 __A, const __m256i * __B) { + return _mm256_maskz_loadrs_epi8(__A, __B); // expected-error {{returning 'int' from a function with incompatible result type '__m256i' (vector of 4 'long long' values)}} +} + +__m128i test_mm_loadrs_epi32(const __m128i * __A) { + return _mm_loadrs_epi32(__A); // expected-error {{returning 'int' from a function with incompatible result type '__m128i' (vector of 2 'long long' values)}} +} + +__m128i test_mm_mask_loadrs_epi32(__m128i __A, __mmask8 __B, const __m128i * __C) { + return _mm_mask_loadrs_epi32(__A, __B, __C); // expected-error {{returning 'int' from a function with incompatible result type '__m128i' (vector of 2 'long long' values)}} +} + +__m128i test_mm_maskz_loadrs_epi32(__mmask8 __A, const __m128i * __B) { + return _mm_maskz_loadrs_epi32(__A, __B); // expected-error {{returning 'int' from a function with incompatible result type '__m128i' (vector of 2 'long long' values)}} +} + +__m256i test_mm256_loadrs_epi32(const __m256i * __A) { + return _mm256_loadrs_epi32(__A); // expected-error {{returning 'int' from a function with incompatible result type '__m256i' (vector of 4 'long long' values)}} +} + +__m256i test_mm256_mask_loadrs_epi32(__m256i __A, __mmask8 __B, const __m256i * __C) { + return _mm256_mask_loadrs_epi32(__A, __B, __C); // expected-error {{returning 'int' from a function with incompatible result type '__m256i' (vector of 4 'long long' values)}} +} + +__m256i test_mm256_maskz_loadrs_epi32(__mmask8 __A, const __m256i * __B) { + return _mm256_maskz_loadrs_epi32(__A, __B); // expected-error {{returning 'int' from a function with incompatible result type '__m256i' (vector of 4 'long long' values)}} +} + +__m128i test_mm_loadrs_epi64(const __m128i * __A) { + return _mm_loadrs_epi64(__A); // expected-error {{returning 'int' from a function with incompatible result type '__m128i' (vector of 2 'long long' values)}} +} + +__m128i test_mm_mask_loadrs_epi64(__m128i __A, __mmask8 __B, const __m128i * __C) { + return _mm_mask_loadrs_epi64(__A, __B, __C); // expected-error {{returning 'int' from a function with incompatible result type '__m128i' (vector of 2 'long long' values)}} +} + +__m128i test_mm_maskz_loadrs_epi64(__mmask8 __A, const __m128i * __B) { + return _mm_maskz_loadrs_epi64(__A, __B); // expected-error {{returning 'int' from a function with incompatible result type '__m128i' (vector of 2 'long long' values)}} +} + +__m256i test_mm256_loadrs_epi64(const __m256i * __A) { + return _mm256_loadrs_epi64(__A); // expected-error {{returning 'int' from a function with incompatible result type '__m256i' (vector of 4 'long long' values)}} +} + +__m256i test_mm256_mask_loadrs_epi64(__m256i __A, __mmask8 __B, const __m256i * __C) { + return _mm256_mask_loadrs_epi64(__A, __B, __C); // expected-error {{returning 'int' from a function with incompatible result type '__m256i' (vector of 4 'long long' values)}} +} + +__m256i test_mm256_maskz_loadrs_epi64(__mmask8 __A, const __m256i * __B) { + return _mm256_maskz_loadrs_epi64(__A, __B); // expected-error {{returning 'int' from a function with incompatible result type '__m256i' (vector of 4 'long long' values)}} +} + +__m128i test_mm_loadrs_epi16(const __m128i * __A) { + return _mm_loadrs_epi16(__A); // expected-error {{returning 'int' from a function with incompatible result type '__m128i' (vector of 2 'long long' values)}} +} + +__m128i test_mm_mask_loadrs_epi16(__m128i __A, __mmask8 __B, const __m128i * __C) { + return _mm_mask_loadrs_epi16(__A, __B, __C); // expected-error {{returning 'int' from a function with incompatible result type '__m128i' (vector of 2 'long long' values)}} +} + +__m128i test_mm_maskz_loadrs_epi16(__mmask8 __A, const __m128i * __B) { + return _mm_maskz_loadrs_epi16(__A, __B); // expected-error {{returning 'int' from a function with incompatible result type '__m128i' (vector of 2 'long long' values)}} +} + +__m256i test_mm256_loadrs_epi16(const __m256i * __A) { + return _mm256_loadrs_epi16(__A); // expected-error {{returning 'int' from a function with incompatible result type '__m256i' (vector of 4 'long long' values)}} +} + +__m256i test_mm256_mask_loadrs_epi16(__m256i __A, __mmask16 __B, const __m256i * __C) { + return _mm256_mask_loadrs_epi16(__A, __B, __C); // expected-error {{returning 'int' from a function with incompatible result type '__m256i' (vector of 4 'long long' values)}} +} + +__m256i test_mm256_maskz_loadrs_epi16(__mmask16 __A, const __m256i * __B) { + return _mm256_maskz_loadrs_epi16(__A, __B); // expected-error {{returning 'int' from a function with incompatible result type '__m256i' (vector of 4 'long long' values)}} +} diff --git a/clang/test/CodeGen/X86/movrs-avx10.2-builtins.c b/clang/test/CodeGen/X86/movrs-avx10.2-builtins.c new file mode 100644 index 0000000000000000000000000000000000000000..2011b2a8624738064648680a891a7cc251f37673 --- /dev/null +++ b/clang/test/CodeGen/X86/movrs-avx10.2-builtins.c @@ -0,0 +1,171 @@ +// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-- -target-feature +movrs -target-feature +avx10.2-256 -emit-llvm -o - -Wall -Werror | FileCheck %s + +#include + +__m128i test_mm_loadrs_epi8(const __m128i * __A) { + // CHECK-LABEL: @test_mm_loadrs_epi8( + // CHECK: call <16 x i8> @llvm.x86.avx10.vmovrsb128( + return _mm_loadrs_epi8(__A); +} + +__m128i test_mm_mask_loadrs_epi8(__m128i __A, __mmask16 __B, const __m128i * __C) { + // CHECK-LABEL: @test_mm_mask_loadrs_epi8( + // CHECK: call <16 x i8> @llvm.x86.avx10.vmovrsb128( + // CHECK: select <16 x i1> %{{.*}}, <16 x i8> %{{.*}}, <16 x i8> %{{.*}} + return _mm_mask_loadrs_epi8(__A, __B, __C); +} + +__m128i test_mm_maskz_loadrs_epi8(__mmask16 __A, const __m128i * __B) { + // CHECK-LABEL: @test_mm_maskz_loadrs_epi8( + // CHECK: call <16 x i8> @llvm.x86.avx10.vmovrsb128( + // CHECK: store <2 x i64> zeroinitializer + // CHECK: select <16 x i1> %{{.*}}, <16 x i8> %{{.*}}, <16 x i8> %{{.*}} + return _mm_maskz_loadrs_epi8(__A, __B); +} + +__m256i test_mm256_loadrs_epi8(const __m256i * __A) { + // CHECK-LABEL: @test_mm256_loadrs_epi8( + // CHECK: call <32 x i8> @llvm.x86.avx10.vmovrsb256( + return _mm256_loadrs_epi8(__A); +} + +__m256i test_mm256_mask_loadrs_epi8(__m256i __A, __mmask32 __B, const __m256i * __C) { + // CHECK-LABEL: @test_mm256_mask_loadrs_epi8( + // CHECK: call <32 x i8> @llvm.x86.avx10.vmovrsb256( + // CHECK: select <32 x i1> %{{.*}}, <32 x i8> %{{.*}}, <32 x i8> %{{.*}} + return _mm256_mask_loadrs_epi8(__A, __B, __C); +} + +__m256i test_mm256_maskz_loadrs_epi8(__mmask32 __A, const __m256i * __B) { + // CHECK-LABEL: @test_mm256_maskz_loadrs_epi8( + // CHECK: call <32 x i8> @llvm.x86.avx10.vmovrsb256( + // CHECK: store <4 x i64> zeroinitializer + // CHECK: select <32 x i1> %{{.*}}, <32 x i8> %{{.*}}, <32 x i8> %{{.*}} + return _mm256_maskz_loadrs_epi8(__A, __B); +} + +__m128i test_mm_loadrs_epi32(const __m128i * __A) { + // CHECK-LABEL: @test_mm_loadrs_epi32( + // CHECK: call <4 x i32> @llvm.x86.avx10.vmovrsd128( + return _mm_loadrs_epi32(__A); +} + +__m128i test_mm_mask_loadrs_epi32(__m128i __A, __mmask8 __B, const __m128i * __C) { + // CHECK-LABEL: @test_mm_mask_loadrs_epi32( + // CHECK: call <4 x i32> @llvm.x86.avx10.vmovrsd128( + // CHECK: select <4 x i1> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> %{{.*}} + return _mm_mask_loadrs_epi32(__A, __B, __C); +} + +__m128i test_mm_maskz_loadrs_epi32(__mmask8 __A, const __m128i * __B) { + // CHECK-LABEL: @test_mm_maskz_loadrs_epi32( + // CHECK: call <4 x i32> @llvm.x86.avx10.vmovrsd128( + // CHECK: store <2 x i64> zeroinitializer + // CHECK: select <4 x i1> %{{.*}}, <4 x i32> %{{.*}}, <4 x i32> %{{.*}} + return _mm_maskz_loadrs_epi32(__A, __B); +} + +__m256i test_mm256_loadrs_epi32(const __m256i * __A) { + // CHECK-LABEL: @test_mm256_loadrs_epi32( + // CHECK: call <8 x i32> @llvm.x86.avx10.vmovrsd256( + return _mm256_loadrs_epi32(__A); +} + +__m256i test_mm256_mask_loadrs_epi32(__m256i __A, __mmask8 __B, const __m256i * __C) { + // CHECK-LABEL: @test_mm256_mask_loadrs_epi32( + // CHECK: call <8 x i32> @llvm.x86.avx10.vmovrsd256( + // CHECK: select <8 x i1> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> %{{.*}} + return _mm256_mask_loadrs_epi32(__A, __B, __C); +} + +__m256i test_mm256_maskz_loadrs_epi32(__mmask8 __A, const __m256i * __B) { + // CHECK-LABEL: @test_mm256_maskz_loadrs_epi32( + // CHECK: call <8 x i32> @llvm.x86.avx10.vmovrsd256( + // CHECK: store <4 x i64> zeroinitializer + // CHECK: select <8 x i1> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> %{{.*}} + return _mm256_maskz_loadrs_epi32(__A, __B); +} + +__m128i test_mm_loadrs_epi64(const __m128i * __A) { + // CHECK-LABEL: @test_mm_loadrs_epi64( + // CHECK: call <2 x i64> @llvm.x86.avx10.vmovrsq128( + return _mm_loadrs_epi64(__A); +} + +__m128i test_mm_mask_loadrs_epi64(__m128i __A, __mmask8 __B, const __m128i * __C) { + // CHECK-LABEL: @test_mm_mask_loadrs_epi64( + // CHECK: call <2 x i64> @llvm.x86.avx10.vmovrsq128( + // CHECK: select <2 x i1> %{{.*}}, <2 x i64> %{{.*}}, <2 x i64> %{{.*}} + return _mm_mask_loadrs_epi64(__A, __B, __C); +} + +__m128i test_mm_maskz_loadrs_epi64(__mmask8 __A, const __m128i * __B) { + // CHECK-LABEL: @test_mm_maskz_loadrs_epi64( + // CHECK: call <2 x i64> @llvm.x86.avx10.vmovrsq128( + // CHECK: store <2 x i64> zeroinitializer + // CHECK: select <2 x i1> %{{.*}}, <2 x i64> %{{.*}}, <2 x i64> %{{.*}} + return _mm_maskz_loadrs_epi64(__A, __B); +} + +__m256i test_mm256_loadrs_epi64(const __m256i * __A) { + // CHECK-LABEL: @test_mm256_loadrs_epi64( + // CHECK: call <4 x i64> @llvm.x86.avx10.vmovrsq256( + return _mm256_loadrs_epi64(__A); +} + +__m256i test_mm256_mask_loadrs_epi64(__m256i __A, __mmask8 __B, const __m256i * __C) { + // CHECK-LABEL: @test_mm256_mask_loadrs_epi64( + // CHECK: call <4 x i64> @llvm.x86.avx10.vmovrsq256( + // CHECK: select <4 x i1> %{{.*}}, <4 x i64> %{{.*}}, <4 x i64> %{{.*}} + return _mm256_mask_loadrs_epi64(__A, __B, __C); +} + +__m256i test_mm256_maskz_loadrs_epi64(__mmask8 __A, const __m256i * __B) { + // CHECK-LABEL: @test_mm256_maskz_loadrs_epi64( + // CHECK: call <4 x i64> @llvm.x86.avx10.vmovrsq256( + // CHECK: store <4 x i64> zeroinitializer + // CHECK: select <4 x i1> %{{.*}}, <4 x i64> %{{.*}}, <4 x i64> %{{.*}} + return _mm256_maskz_loadrs_epi64(__A, __B); +} + +__m128i test_mm_loadrs_epi16(const __m128i * __A) { + // CHECK-LABEL: @test_mm_loadrs_epi16( + // CHECK: call <8 x i16> @llvm.x86.avx10.vmovrsw128( + return _mm_loadrs_epi16(__A); +} + +__m128i test_mm_mask_loadrs_epi16(__m128i __A, __mmask8 __B, const __m128i * __C) { + // CHECK-LABEL: @test_mm_mask_loadrs_epi16( + // CHECK: call <8 x i16> @llvm.x86.avx10.vmovrsw128( + // CHECK: select <8 x i1> %{{.*}}, <8 x i16> %{{.*}}, <8 x i16> %{{.*}} + return _mm_mask_loadrs_epi16(__A, __B, __C); +} + +__m128i test_mm_maskz_loadrs_epi16(__mmask8 __A, const __m128i * __B) { + // CHECK-LABEL: @test_mm_maskz_loadrs_epi16( + // CHECK: call <8 x i16> @llvm.x86.avx10.vmovrsw128( + // CHECK: store <2 x i64> zeroinitializer + // CHECK: select <8 x i1> %{{.*}}, <8 x i16> %{{.*}}, <8 x i16> %{{.*}} + return _mm_maskz_loadrs_epi16(__A, __B); +} + +__m256i test_mm256_loadrs_epi16(const __m256i * __A) { + // CHECK-LABEL: @test_mm256_loadrs_epi16( + // CHECK: call <16 x i16> @llvm.x86.avx10.vmovrsw256( + return _mm256_loadrs_epi16(__A); +} + +__m256i test_mm256_mask_loadrs_epi16(__m256i __A, __mmask16 __B, const __m256i * __C) { + // CHECK-LABEL: @test_mm256_mask_loadrs_epi16( + // CHECK: call <16 x i16> @llvm.x86.avx10.vmovrsw256( + // CHECK: select <16 x i1> %{{.*}}, <16 x i16> %{{.*}}, <16 x i16> %{{.*}} + return _mm256_mask_loadrs_epi16(__A, __B, __C); +} + +__m256i test_mm256_maskz_loadrs_epi16(__mmask16 __A, const __m256i * __B) { + // CHECK-LABEL: @test_mm256_maskz_loadrs_epi16( + // CHECK: call <16 x i16> @llvm.x86.avx10.vmovrsw256( + // CHECK: store <4 x i64> zeroinitializer + // CHECK: select <16 x i1> %{{.*}}, <16 x i16> %{{.*}}, <16 x i16> %{{.*}} + return _mm256_maskz_loadrs_epi16(__A, __B); +} diff --git a/clang/test/CodeGen/X86/sm4-evex-builtins.c b/clang/test/CodeGen/X86/sm4-evex-builtins.c new file mode 100644 index 0000000000000000000000000000000000000000..0e54bd008d4fb0e641f48b3a6a34d789a8f71c59 --- /dev/null +++ b/clang/test/CodeGen/X86/sm4-evex-builtins.c @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-- -target-feature +sm4 \ +// RUN: -target-feature +avx10.2-512 -emit-llvm -o - -Wall -Werror | FileCheck %s +// RUN: %clang_cc1 %s -ffreestanding -triple=i386-- -target-feature +sm4 \ +// RUN: -target-feature +avx10.2-512 -emit-llvm -o - -Wall -Werror | FileCheck %s + +#include +#include + +__m512i test_mm512_sm4key4_epi32(__m512i __A, __m512i __B) { + // CHECK-LABEL: @test_mm512_sm4key4_epi32( + // CHECK: call <16 x i32> @llvm.x86.vsm4key4512(<16 x i32> %{{.*}}, <16 x i32> %{{.*}}) + return _mm512_sm4key4_epi32(__A, __B); +} + +__m512i test_mm512_sm4rnds4_epi32(__m512i __A, __m512i __B) { + // CHECK-LABEL: @test_mm512_sm4rnds4_epi32( + // CHECK: call <16 x i32> @llvm.x86.vsm4rnds4512(<16 x i32> %{{.*}}, <16 x i32> %{{.*}}) + return _mm512_sm4rnds4_epi32(__A, __B); +} diff --git a/clang/test/CodeGen/X86/sse-builtins.c b/clang/test/CodeGen/X86/sse-builtins.c index 391e049a6ae3ef0af43aab7454397b1a3fc8ea3d..f779ab07a266408014ccb4e6d56684209578e503 100644 --- a/clang/test/CodeGen/X86/sse-builtins.c +++ b/clang/test/CodeGen/X86/sse-builtins.c @@ -5,6 +5,7 @@ #include +#include "builtin_test_helpers.h" // NOTE: This should match the tests in llvm/test/CodeGen/X86/sse-intrinsics-fast-isel.ll @@ -13,6 +14,7 @@ __m128 test_mm_add_ps(__m128 A, __m128 B) { // CHECK: fadd <4 x float> return _mm_add_ps(A, B); } +TEST_CONSTEXPR(match_m128(_mm_add_ps((__m128){+1.0f, +0.0f, +2.0f, +4.0f}, (__m128){+8.0f, +4.0f, +2.0f, +1.0f}), +9.0f, +4.0f, +4.0f, +5.0f)); __m128 test_mm_add_ss(__m128 A, __m128 B) { // CHECK-LABEL: test_mm_add_ss @@ -22,12 +24,14 @@ __m128 test_mm_add_ss(__m128 A, __m128 B) { // CHECK: insertelement <4 x float> %{{.*}}, float %{{.*}}, i32 0 return _mm_add_ss(A, B); } +TEST_CONSTEXPR(match_m128(_mm_add_ss((__m128){+1.0f, +0.0f, +2.0f, +4.0f}, (__m128){+8.0f, +4.0f, +2.0f, +1.0f}), +9.0f, +0.0f, +2.0f, +4.0f)); __m128 test_mm_and_ps(__m128 A, __m128 B) { // CHECK-LABEL: test_mm_and_ps // CHECK: and <4 x i32> return _mm_and_ps(A, B); } +TEST_CONSTEXPR(match_m128(_mm_and_ps((__m128){-4.0f, -5.0f, +6.0f, +7.0f}, (__m128){+0.0f, -0.0f, -0.0f, +7.0f}), -0.0f, -0.0f, +0.0f, +7.0f)); __m128 test_mm_andnot_ps(__m128 A, __m128 B) { // CHECK-LABEL: test_mm_andnot_ps @@ -35,6 +39,7 @@ __m128 test_mm_andnot_ps(__m128 A, __m128 B) { // CHECK: and <4 x i32> return _mm_andnot_ps(A, B); } +TEST_CONSTEXPR(match_m128(_mm_andnot_ps((__m128){-4.0f, -5.0f, +6.0f, +7.0f}, (__m128){+0.0f, -0.0f, -0.0f, +7.0f}), +0.0f, +0.0f, +0.0f, +0.0f)); __m128 test_mm_cmp_ps_eq_oq(__m128 a, __m128 b) { // CHECK-LABEL: test_mm_cmp_ps_eq_oq @@ -322,6 +327,15 @@ __m128 test_mm_cvtsi32_ss(__m128 A, int B) { // CHECK: insertelement <4 x float> %{{.*}}, float %{{.*}}, i32 0 return _mm_cvtsi32_ss(A, B); } +TEST_CONSTEXPR(match_m128(_mm_cvtsi32_ss((__m128){+1.0f, +0.0f, +2.0f, +4.0f}, 42), +42.0f, +0.0f, +2.0f, +4.0f)); + +__m128 test_mm_cvt_si2ss(__m128 A, int B) { + // CHECK-LABEL: test_mm_cvt_si2ss + // CHECK: sitofp i32 %{{.*}} to float + // CHECK: insertelement <4 x float> %{{.*}}, float %{{.*}}, i32 0 + return _mm_cvt_si2ss(A, B); +} +TEST_CONSTEXPR(match_m128(_mm_cvt_si2ss((__m128){+4.0f, +2.0f, +0.0f, +4.0f}, -99), -99.0f, +2.0f, +0.0f, +4.0f)); #ifdef __x86_64__ __m128 test_mm_cvtsi64_ss(__m128 A, long long B) { @@ -330,6 +344,7 @@ __m128 test_mm_cvtsi64_ss(__m128 A, long long B) { // CHECK: insertelement <4 x float> %{{.*}}, float %{{.*}}, i32 0 return _mm_cvtsi64_ss(A, B); } +TEST_CONSTEXPR(match_m128(_mm_cvtsi64_ss((__m128){+1.0f, +0.0f, +2.0f, +4.0f}, 555), +555.0f, +0.0f, +2.0f, +4.0f)); #endif float test_mm_cvtss_f32(__m128 A) { @@ -337,6 +352,7 @@ float test_mm_cvtss_f32(__m128 A) { // CHECK: extractelement <4 x float> %{{.*}}, i32 0 return _mm_cvtss_f32(A); } +TEST_CONSTEXPR(_mm_cvtss_f32((__m128){+8.0f, +4.0f, +2.0f, +1.0f}) == +8.0f); int test_mm_cvtss_si32(__m128 A) { // CHECK-LABEL: test_mm_cvtss_si32 @@ -377,6 +393,7 @@ __m128 test_mm_div_ps(__m128 A, __m128 B) { // CHECK: fdiv <4 x float> return _mm_div_ps(A, B); } +TEST_CONSTEXPR(match_m128(_mm_div_ps((__m128){+1.0f, +0.0f, +2.0f, +4.0f}, (__m128){+8.0f, +4.0f, +2.0f, +1.0f}), +0.125f, +0.0f, +1.0f, +4.0f)); __m128 test_mm_div_ss(__m128 A, __m128 B) { // CHECK-LABEL: test_mm_div_ss @@ -386,6 +403,7 @@ __m128 test_mm_div_ss(__m128 A, __m128 B) { // CHECK: insertelement <4 x float> %{{.*}}, float %{{.*}}, i32 0 return _mm_div_ss(A, B); } +TEST_CONSTEXPR(match_m128(_mm_div_ss((__m128){+1.0f, +5.0f, +2.0f, +4.0f}, (__m128){+8.0f, +4.0f, +2.0f, +1.0f}), +0.125f, +5.0f, +2.0f, +4.0f)); unsigned int test_MM_GET_EXCEPTION_MASK(void) { // CHECK-LABEL: test_MM_GET_EXCEPTION_MASK @@ -517,18 +535,21 @@ __m128 test_mm_move_ss(__m128 A, __m128 B) { // CHECK: insertelement <4 x float> %{{.*}}, float %{{.*}}, i32 0 return _mm_move_ss(A, B); } +TEST_CONSTEXPR(match_m128(_mm_move_ss((__m128){+1.0f, +0.0f, +2.0f, +4.0f}, (__m128){+8.0f, +4.0f, +2.0f, +1.0f}), +8.0f, +0.0f, +2.0f, +4.0f)); __m128 test_mm_movehl_ps(__m128 A, __m128 B) { // CHECK-LABEL: test_mm_movehl_ps // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x i32> return _mm_movehl_ps(A, B); } +TEST_CONSTEXPR(match_m128(_mm_movehl_ps((__m128){+1.0f, +0.0f, +2.0f, +4.0f}, (__m128){+8.0f, +4.0f, +2.0f, +1.0f}), +2.0f, +1.0f, +2.0f, +4.0f)); __m128 test_mm_movelh_ps(__m128 A, __m128 B) { // CHECK-LABEL: test_mm_movelh_ps // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x i32> return _mm_movelh_ps(A, B); } +TEST_CONSTEXPR(match_m128(_mm_movelh_ps((__m128){+1.0f, +0.0f, +2.0f, +4.0f}, (__m128){+8.0f, +4.0f, +2.0f, +1.0f}), +1.0f, +0.0f, +8.0f, +4.0f)); int test_mm_movemask_ps(__m128 A) { // CHECK-LABEL: test_mm_movemask_ps @@ -541,6 +562,7 @@ __m128 test_mm_mul_ps(__m128 A, __m128 B) { // CHECK: fmul <4 x float> return _mm_mul_ps(A, B); } +TEST_CONSTEXPR(match_m128(_mm_mul_ps((__m128){+1.0f, +0.0f, +2.0f, +4.0f}, (__m128){+8.0f, +4.0f, +2.0f, +1.0f}), +8.0f, +0.0f, +4.0f, +4.0f)); __m128 test_mm_mul_ss(__m128 A, __m128 B) { // CHECK-LABEL: test_mm_mul_ss @@ -550,12 +572,14 @@ __m128 test_mm_mul_ss(__m128 A, __m128 B) { // CHECK: insertelement <4 x float> %{{.*}}, float %{{.*}}, i32 0 return _mm_mul_ss(A, B); } +TEST_CONSTEXPR(match_m128(_mm_mul_ps((__m128){+1.0f, +0.0f, +2.0f, +4.0f}, (__m128){+8.0f, +4.0f, +2.0f, +1.0f}), +8.0f, +0.0f, +4.0f, +4.0f)); __m128 test_mm_or_ps(__m128 A, __m128 B) { // CHECK-LABEL: test_mm_or_ps // CHECK: or <4 x i32> return _mm_or_ps(A, B); } +TEST_CONSTEXPR(match_m128(_mm_or_ps((__m128){-4.0f, -5.0f, +6.0f, +7.0f}, (__m128){+0.0f, -0.0f, -0.0f, +7.0f}), -4.0f, -5.0f, -6.0f, +7.0f)); void test_mm_prefetch(char const* p) { // CHECK-LABEL: test_mm_prefetch @@ -628,6 +652,7 @@ __m128 test_mm_set_ps(float A, float B, float C, float D) { // CHECK: insertelement <4 x float> {{.*}}, float {{.*}}, i32 3 return _mm_set_ps(A, B, C, D); } +TEST_CONSTEXPR(match_m128(_mm_set_ps(+0.0f, +1.0f, +2.0f, +3.0f), +3.0f, +2.0f, +1.0f, +.0f)); __m128 test_mm_set_ps1(float A) { // CHECK-LABEL: test_mm_set_ps1 @@ -637,6 +662,7 @@ __m128 test_mm_set_ps1(float A) { // CHECK: insertelement <4 x float> {{.*}}, float {{.*}}, i32 3 return _mm_set_ps1(A); } +TEST_CONSTEXPR(match_m128(_mm_set_ps1(-2.0f), -2.0f, -2.0f, -2.0f, -2.0f)); void test_MM_SET_ROUNDING_MODE(unsigned int A) { // CHECK-LABEL: test_MM_SET_ROUNDING_MODE @@ -657,6 +683,7 @@ __m128 test_mm_set_ss(float A) { // CHECK: insertelement <4 x float> {{.*}}, float 0.000000e+00, i32 3 return _mm_set_ss(A); } +TEST_CONSTEXPR(match_m128(_mm_set_ss(1.0f), +1.0f, +0.0f, +0.0f, +0.0f)); __m128 test_mm_set1_ps(float A) { // CHECK-LABEL: test_mm_set1_ps @@ -666,6 +693,7 @@ __m128 test_mm_set1_ps(float A) { // CHECK: insertelement <4 x float> {{.*}}, float {{.*}}, i32 3 return _mm_set1_ps(A); } +TEST_CONSTEXPR(match_m128(_mm_set1_ps(2.0f), +2.0f, +2.0f, +2.0f, +2.0f)); void test_mm_setcsr(unsigned int A) { // CHECK-LABEL: test_mm_setcsr @@ -682,12 +710,14 @@ __m128 test_mm_setr_ps(float A, float B, float C, float D) { // CHECK: insertelement <4 x float> {{.*}}, float {{.*}}, i32 3 return _mm_setr_ps(A, B, C, D); } +TEST_CONSTEXPR(match_m128(_mm_setr_ps(+0.0f, +1.0f, +2.0f, +3.0f), +0.0f, +1.0f, +2.0f, +3.0f)); __m128 test_mm_setzero_ps(void) { // CHECK-LABEL: test_mm_setzero_ps // CHECK: store <4 x float> zeroinitializer return _mm_setzero_ps(); } +TEST_CONSTEXPR(match_m128(_mm_setzero_ps(), +0.0f, +0.0f, +0.0f, +0.0f)); void test_mm_sfence(void) { // CHECK-LABEL: test_mm_sfence @@ -787,6 +817,7 @@ __m128 test_mm_sub_ps(__m128 A, __m128 B) { // CHECK: fsub <4 x float> return _mm_sub_ps(A, B); } +TEST_CONSTEXPR(match_m128(_mm_sub_ps((__m128){+1.0f, +0.0f, +2.0f, +4.0f}, (__m128){+8.0f, +4.0f, +2.0f, +1.0f}), -7.0f, -4.0f, +0.0f, +3.0f)); __m128 test_mm_sub_ss(__m128 A, __m128 B) { // CHECK-LABEL: test_mm_sub_ss @@ -796,6 +827,7 @@ __m128 test_mm_sub_ss(__m128 A, __m128 B) { // CHECK: insertelement <4 x float> %{{.*}}, float %{{.*}}, i32 0 return _mm_sub_ss(A, B); } +TEST_CONSTEXPR(match_m128(_mm_sub_ss((__m128){+1.0f, +0.0f, +2.0f, +4.0f}, (__m128){+8.0f, +4.0f, +2.0f, +1.0f}), -7.0f, +0.0f, +2.0f, +4.0f)); void test_MM_TRANSPOSE4_PS(__m128 *A, __m128 *B, __m128 *C, __m128 *D) { // CHECK-LABEL: test_MM_TRANSPOSE4_PS @@ -857,107 +889,18 @@ __m128 test_mm_unpackhi_ps(__m128 A, __m128 B) { // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x i32> return _mm_unpackhi_ps(A, B); } +TEST_CONSTEXPR(match_m128(_mm_unpackhi_ps((__m128){+1.0f, +0.0f, +2.0f, +4.0f}, (__m128){+8.0f, +4.0f, +2.0f, +1.0f}), +2.0f, +2.0f, +4.0f, +1.0f)); __m128 test_mm_unpacklo_ps(__m128 A, __m128 B) { // CHECK-LABEL: test_mm_unpacklo_ps // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x i32> return _mm_unpacklo_ps(A, B); } +TEST_CONSTEXPR(match_m128(_mm_unpacklo_ps((__m128){+1.0f, +0.0f, +2.0f, +4.0f}, (__m128){+8.0f, +4.0f, +2.0f, +1.0f}), +1.0f, +8.0f, +0.0f, +4.0f)); __m128 test_mm_xor_ps(__m128 A, __m128 B) { // CHECK-LABEL: test_mm_xor_ps // CHECK: xor <4 x i32> return _mm_xor_ps(A, B); } - -// Test constexpr handling. -#if defined(__cplusplus) && (__cplusplus >= 201103L) - -void test_constexpr() { - constexpr __m128 k1 {+1.0f,+0.0f,+2.0f,+4.0f}; - constexpr __m128 k2 {+8.0f,+4.0f,+2.0f,+1.0f}; - constexpr __m128 k3 {-4.0f,-5.0f,+6.0f,+7.0f}; - constexpr __m128 k4 {+0.0f,-0.0f,-0.0f,+0.0f}; - - constexpr __m128 v_mm_set_ss = _mm_set_ss(1.0f); - static_assert(v_mm_set_ss[0] == +1.0f && v_mm_set_ss[1] == +0.0f && v_mm_set_ss[2] == +0.0f && v_mm_set_ss[3] == +0.0f); - - constexpr __m128 v_mm_set1_ps = _mm_set1_ps(2.0f); - static_assert(v_mm_set1_ps[0] == +2.0f && v_mm_set1_ps[1] == +2.0f && v_mm_set1_ps[2] == +2.0f && v_mm_set1_ps[3] == +2.0f); - - constexpr __m128 v_mm_set_ps1 = _mm_set_ps1(-2.0f); - static_assert(v_mm_set_ps1[0] == -2.0f && v_mm_set_ps1[1] == -2.0f && v_mm_set_ps1[2] == -2.0f && v_mm_set_ps1[3] == -2.0f); - - constexpr __m128 v_mm_set_ps = _mm_set_ps(+0.0f, +1.0f, +2.0f, +3.0f); - static_assert(v_mm_set_ps[0] == +3.0f && v_mm_set_ps[1] == +2.0f && v_mm_set_ps[2] == +1.0f && v_mm_set_ps[3] == +0.0f); - - constexpr __m128 v_mm_setr_ps = _mm_setr_ps(+0.0f, +1.0f, +2.0f, +3.0f); - static_assert(v_mm_setr_ps[0] == +0.0f && v_mm_setr_ps[1] == +1.0f && v_mm_setr_ps[2] == +2.0f && v_mm_setr_ps[3] == +3.0f); - - constexpr __m128 v_mm_setzero_ps = _mm_setzero_ps(); - static_assert(v_mm_setzero_ps[0] == +0.0f && v_mm_setzero_ps[1] == +0.0f && v_mm_setzero_ps[2] == +0.0f && v_mm_setzero_ps[3] == +0.0f); - - constexpr __m128 v_mm_add_ss = _mm_add_ss(k1, k2); - static_assert(v_mm_add_ss[0] == +9.0f && v_mm_add_ss[1] == +0.0f && v_mm_add_ss[2] == +2.0f && v_mm_add_ss[3] == +4.0f); - - constexpr __m128 v_mm_add_ps = _mm_add_ps(k1, k2); - static_assert(v_mm_add_ps[0] == +9.0f && v_mm_add_ps[1] == +4.0f && v_mm_add_ps[2] == +4.0f && v_mm_add_ps[3] == +5.0f); - - constexpr __m128 v_mm_sub_ss = _mm_sub_ss(k1, k2); - static_assert(v_mm_sub_ss[0] == -7.0f && v_mm_sub_ss[1] == +0.0f && v_mm_sub_ss[2] == +2.0f && v_mm_sub_ss[3] == +4.0f); - - constexpr __m128 v_mm_sub_ps = _mm_sub_ps(k1, k2); - static_assert(v_mm_sub_ps[0] == -7.0f && v_mm_sub_ps[1] == -4.0f && v_mm_sub_ps[2] == +0.0f && v_mm_sub_ps[3] == +3.0f); - - constexpr __m128 v_mm_mul_ss = _mm_mul_ss(k1, k2); - static_assert(v_mm_mul_ss[0] == +8.0f && v_mm_mul_ss[1] == +0.0f && v_mm_mul_ss[2] == +2.0f && v_mm_mul_ss[3] == +4.0f); - - constexpr __m128 v_mm_mul_ps = _mm_mul_ps(k1, k2); - static_assert(v_mm_mul_ps[0] == +8.0f && v_mm_mul_ps[1] == +0.0f && v_mm_mul_ps[2] == +4.0f && v_mm_mul_ps[3] == +4.0f); - - constexpr __m128 v_mm_div_ss = _mm_div_ss(k1, k2); - static_assert(v_mm_div_ss[0] == +0.125f && v_mm_div_ss[1] == +0.0f && v_mm_div_ss[2] == +2.0f && v_mm_div_ss[3] == +4.0f); - - constexpr __m128 v_mm_div_ps = _mm_div_ps(k1, k2); - static_assert(v_mm_div_ps[0] == +0.125f && v_mm_div_ps[1] == +0.0f && v_mm_div_ps[2] == +1.0f && v_mm_div_ps[3] == +4.0f); - - constexpr __m128 v_mm_and_ps = _mm_and_ps(k3, k4); - static_assert(v_mm_and_ps[0] == +0.0f && v_mm_and_ps[1] == +0.0f && v_mm_and_ps[2] == +0.0f && v_mm_and_ps[3] == +0.0f); - - constexpr __m128 v_mm_andnot_ps = _mm_andnot_ps(k3, k4); - static_assert(v_mm_andnot_ps[0] == +0.0f && v_mm_andnot_ps[1] == +0.0f && v_mm_andnot_ps[2] == +0.0f && v_mm_andnot_ps[3] == +0.0f); - - constexpr __m128 v_mm_or_ps = _mm_or_ps(k3, k4); - static_assert(v_mm_or_ps[0] == -4.0f && v_mm_or_ps[1] == -5.0f && v_mm_or_ps[2] == -6.0f && v_mm_or_ps[3] == +7.0f); - - constexpr __m128 v_mm_xor_ps = _mm_xor_ps(k3, k4); - static_assert(v_mm_xor_ps[0] == -4.0f && v_mm_xor_ps[1] == +5.0f && v_mm_xor_ps[2] == -6.0f && v_mm_xor_ps[3] == +7.0f); - - constexpr __m128 v_mm_unpackhi_ps = _mm_unpackhi_ps(k1, k2); - static_assert(v_mm_unpackhi_ps[0] == +2.0f && v_mm_unpackhi_ps[1] == +2.0f && v_mm_unpackhi_ps[2] == +4.0f && v_mm_unpackhi_ps[3] == +1.0f); - - constexpr __m128 v_mm_unpacklo_ps = _mm_unpacklo_ps(k1, k2); - static_assert(v_mm_unpacklo_ps[0] == +1.0f && v_mm_unpacklo_ps[1] == +8.0f && v_mm_unpacklo_ps[2] == +0.0f && v_mm_unpacklo_ps[3] == +4.0f); - - constexpr __m128 v_mm_move_ss = _mm_move_ss(k1, k2); - static_assert(v_mm_move_ss[0] == +8.0f && v_mm_move_ss[1] == +0.0f && v_mm_move_ss[2] == +2.0f && v_mm_move_ss[3] == +4.0f); - - constexpr __m128 v_mm_movehl_ps = _mm_movehl_ps(k1, k2); - static_assert(v_mm_movehl_ps[0] == +2.0f && v_mm_movehl_ps[1] == +1.0f && v_mm_movehl_ps[2] == +2.0f && v_mm_movehl_ps[3] == +4.0f); - - constexpr __m128 v_mm_movelh_ps = _mm_movelh_ps(k1, k2); - static_assert(v_mm_movelh_ps[0] == +1.0f && v_mm_movelh_ps[1] == +0.0f && v_mm_movelh_ps[2] == +8.0f && v_mm_movelh_ps[3] == +4.0f); - - constexpr __m128 v_mm_cvtsi32_ss = _mm_cvtsi32_ss(k1, 42); - static_assert(v_mm_cvtsi32_ss[0] == 42.0f && v_mm_cvtsi32_ss[1] == +0.0f && v_mm_cvtsi32_ss[2] == +2.0f && v_mm_cvtsi32_ss[3] == +4.0f); - - constexpr __m128 v_mm_cvt_si2ss = _mm_cvt_si2ss(k2, -99); - static_assert(v_mm_cvt_si2ss[0] == -99.0f && v_mm_cvt_si2ss[1] == +4.0f && v_mm_cvt_si2ss[2] == +2.0f && v_mm_cvt_si2ss[3] == +1.0f); - - constexpr __m128 v_mm_cvtsi64_ss = _mm_cvtsi64_ss(k3, 555); - static_assert(v_mm_cvtsi64_ss[0] == 555.0f && v_mm_cvtsi64_ss[1] == -5.0f && v_mm_cvtsi64_ss[2] == +6.0f && v_mm_cvtsi64_ss[3] == +7.0f); - - static_assert(_mm_cvtss_f32(k2) == +8.0f); -} - -#endif \ No newline at end of file +TEST_CONSTEXPR(match_m128(_mm_xor_ps((__m128){-4.0f, -5.0f, +6.0f, +7.0f}, (__m128){+0.0f, -0.0f, -0.0f, +7.0f}), -4.0f, +5.0f, -6.0f, +0.0f)); diff --git a/clang/test/CodeGen/X86/sse.c b/clang/test/CodeGen/X86/sse.c index a75b8dc77e86e148267c3f706087f50d0cfc66e5..017bdd7846fa3966ff0c2ca8db22dda805693719 100644 --- a/clang/test/CodeGen/X86/sse.c +++ b/clang/test/CodeGen/X86/sse.c @@ -1,42 +1,72 @@ -// RUN: %clang_cc1 -ffreestanding -O3 -triple x86_64-apple-macosx10.8.0 -target-feature +sse4.1 -emit-llvm %s -o - | FileCheck %s -// FIXME: This test currently depends on optimization - it should be rewritten to avoid it. +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 -ffreestanding -triple x86_64-- -target-feature +sse4.1 -disable-O0-optnone -emit-llvm %s -o - | opt -S -passes=mem2reg | FileCheck %s #include // Byte-shifts look reversed due to xmm register layout +// CHECK-LABEL: define dso_local <2 x i64> @test_mm_slli_si128( +// CHECK-SAME: <2 x i64> noundef [[A:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[CAST:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8> +// CHECK-NEXT: [[PSLLDQ:%.*]] = shufflevector <16 x i8> zeroinitializer, <16 x i8> [[CAST]], <16 x i32> +// CHECK-NEXT: [[CAST1:%.*]] = bitcast <16 x i8> [[PSLLDQ]] to <2 x i64> +// CHECK-NEXT: ret <2 x i64> [[CAST1]] +// __m128i test_mm_slli_si128(__m128i a) { - // CHECK-LABEL: @test_mm_slli_si128 - // CHECK: shufflevector <16 x i8> <{{.*}}, i8 0, i8 0, i8 0, i8 0, i8 0>, <16 x i8> {{.*}}, <16 x i32> return _mm_slli_si128(a, 5); } +// CHECK-LABEL: define dso_local <2 x i64> @test_mm_slli_si128_0( +// CHECK-SAME: <2 x i64> noundef [[A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[CAST:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8> +// CHECK-NEXT: [[PSLLDQ:%.*]] = shufflevector <16 x i8> zeroinitializer, <16 x i8> [[CAST]], <16 x i32> +// CHECK-NEXT: [[CAST1:%.*]] = bitcast <16 x i8> [[PSLLDQ]] to <2 x i64> +// CHECK-NEXT: ret <2 x i64> [[CAST1]] +// __m128i test_mm_slli_si128_0(__m128i a) { - // CHECK-LABEL: @test_mm_slli_si128_0 - // CHECK-NOT: shufflevector return _mm_slli_si128(a, 0); } +// CHECK-LABEL: define dso_local <2 x i64> @test_mm_slli_si128_16( +// CHECK-SAME: <2 x i64> noundef [[A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret <2 x i64> zeroinitializer +// __m128i test_mm_slli_si128_16(__m128i a) { - // CHECK-LABEL: @test_mm_slli_si128_16 - // CHECK-NOT: shufflevector return _mm_slli_si128(a, 16); } +// CHECK-LABEL: define dso_local <2 x i64> @test_mm_srli_si128( +// CHECK-SAME: <2 x i64> noundef [[A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[CAST:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8> +// CHECK-NEXT: [[PSRLDQ:%.*]] = shufflevector <16 x i8> [[CAST]], <16 x i8> zeroinitializer, <16 x i32> +// CHECK-NEXT: [[CAST1:%.*]] = bitcast <16 x i8> [[PSRLDQ]] to <2 x i64> +// CHECK-NEXT: ret <2 x i64> [[CAST1]] +// __m128i test_mm_srli_si128(__m128i a) { - // CHECK-LABEL: @test_mm_srli_si128 - // CHECK: shufflevector <16 x i8> {{.*}}, <16 x i8> , <16 x i32> return _mm_srli_si128(a, 5); } +// CHECK-LABEL: define dso_local <2 x i64> @test_mm_srli_si128_0( +// CHECK-SAME: <2 x i64> noundef [[A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[CAST:%.*]] = bitcast <2 x i64> [[A]] to <16 x i8> +// CHECK-NEXT: [[PSRLDQ:%.*]] = shufflevector <16 x i8> [[CAST]], <16 x i8> zeroinitializer, <16 x i32> +// CHECK-NEXT: [[CAST1:%.*]] = bitcast <16 x i8> [[PSRLDQ]] to <2 x i64> +// CHECK-NEXT: ret <2 x i64> [[CAST1]] +// __m128i test_mm_srli_si128_0(__m128i a) { - // CHECK-LABEL: @test_mm_srli_si128_0 - // CHECK-NOT: shufflevector return _mm_srli_si128(a, 0); } +// CHECK-LABEL: define dso_local <2 x i64> @test_mm_srli_si128_16( +// CHECK-SAME: <2 x i64> noundef [[A:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret <2 x i64> zeroinitializer +// __m128i test_mm_srli_si128_16(__m128i a) { - // CHECK-LABEL: @test_mm_srli_si128_16 - // CHECK-NOT: shufflevector return _mm_srli_si128(a, 16); } diff --git a/clang/test/CodeGen/X86/sse2-builtins.c b/clang/test/CodeGen/X86/sse2-builtins.c index 0603ca5f78b6a12882b9d0de4305bb9cdd0e4ddc..4287d3d4b5ec4eb283cabd6a3fa7d633d35b7b2a 100644 --- a/clang/test/CodeGen/X86/sse2-builtins.c +++ b/clang/test/CodeGen/X86/sse2-builtins.c @@ -11,6 +11,7 @@ #include +#include "builtin_test_helpers.h" // NOTE: This should match the tests in llvm/test/CodeGen/X86/sse2-intrinsics-fast-isel.ll @@ -43,6 +44,7 @@ __m128d test_mm_add_pd(__m128d A, __m128d B) { // CHECK: fadd <2 x double> return _mm_add_pd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_add_pd((__m128d){+1.0, -3.0}, (__m128d){+5.0, -5.0}), +6.0, -8.0)); __m128d test_mm_add_sd(__m128d A, __m128d B) { // CHECK-LABEL: test_mm_add_sd @@ -52,6 +54,7 @@ __m128d test_mm_add_sd(__m128d A, __m128d B) { // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 0 return _mm_add_sd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_add_sd((__m128d){+1.0, -3.0}, (__m128d){+5.0, -5.0}), +6.0, -3.0)); __m128i test_mm_adds_epi8(__m128i A, __m128i B) { // CHECK-LABEL: test_mm_adds_epi8 @@ -84,6 +87,7 @@ __m128d test_mm_and_pd(__m128d A, __m128d B) { // CHECK: and <2 x i64> return _mm_and_pd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_and_pd((__m128d){+1.0, -3.0}, (__m128d){+0.0, -0.0}), +0.0, -0.0)); __m128i test_mm_and_si128(__m128i A, __m128i B) { // CHECK-LABEL: test_mm_and_si128 @@ -97,6 +101,7 @@ __m128d test_mm_andnot_pd(__m128d A, __m128d B) { // CHECK: and <2 x i64> return _mm_andnot_pd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_andnot_pd((__m128d){+1.0, -3.0}, (__m128d){+0.0, -0.0}), +0.0, -0.0)); __m128i test_mm_andnot_si128(__m128i A, __m128i B) { // CHECK-LABEL: test_mm_andnot_si128 @@ -133,11 +138,13 @@ __m128 test_mm_castpd_ps(__m128d A) { // CHECK-LABEL: test_mm_castpd_ps return _mm_castpd_ps(A); } +TEST_CONSTEXPR(match_m128(_mm_castpd_ps((__m128d){-1.0, +2.0}), +0.0f, -1.875f, +0.0f, +2.0f)); __m128i test_mm_castpd_si128(__m128d A) { // CHECK-LABEL: test_mm_castpd_si128 return _mm_castpd_si128(A); } +TEST_CONSTEXPR(match_m128i(_mm_castpd_si128((__m128d){-1.0, +2.0}), 0xBFF0000000000000ULL, 0x4000000000000000ULL)); __m128d test_mm_castps_pd(__m128 A) { // CHECK-LABEL: test_mm_castps_pd @@ -499,12 +506,14 @@ __m128d test_mm_cvtepi32_pd(__m128i A) { // CHECK: sitofp <2 x i32> %{{.*}} to <2 x double> return _mm_cvtepi32_pd(A); } +TEST_CONSTEXPR(match_m128d(_mm_cvtepi32_pd((__m128i)(__v4si){-9, +8, -6, 0}), -9.0, +8.0)); __m128 test_mm_cvtepi32_ps(__m128i A) { // CHECK-LABEL: test_mm_cvtepi32_ps // CHECK: sitofp <4 x i32> %{{.*}} to <4 x float> return _mm_cvtepi32_ps(A); } +TEST_CONSTEXPR(match_m128(_mm_cvtepi32_ps((__m128i)(__v4si){-3, +2, -1, 0}), -3.0f, +2.0f, -1.0f, +0.0f)); __m128i test_mm_cvtpd_epi32(__m128d A) { // CHECK-LABEL: test_mm_cvtpd_epi32 @@ -530,12 +539,14 @@ __m128d test_mm_cvtps_pd(__m128 A) { // CHECK: fpext <2 x float> %{{.*}} to <2 x double> return _mm_cvtps_pd(A); } +TEST_CONSTEXPR(match_m128d(_mm_cvtps_pd((__m128){-1.0f, +2.0f, -3.0f, +4.0f}), -1.0, +2.0)); double test_mm_cvtsd_f64(__m128d A) { // CHECK-LABEL: test_mm_cvtsd_f64 // CHECK: extractelement <2 x double> %{{.*}}, i32 0 return _mm_cvtsd_f64(A); } +TEST_CONSTEXPR(_mm_cvtsd_f64((__m128d){-4.0, +8.0}) == -4.0); int test_mm_cvtsd_si32(__m128d A) { // CHECK-LABEL: test_mm_cvtsd_si32 @@ -575,6 +586,7 @@ __m128d test_mm_cvtsi32_sd(__m128d A, int B) { // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 0 return _mm_cvtsi32_sd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_cvtsi32_sd((__m128d){-99.0, +42.0}, 55), +55.0, +42.0)); __m128i test_mm_cvtsi32_si128(int A) { // CHECK-LABEL: test_mm_cvtsi32_si128 @@ -608,6 +620,7 @@ __m128d test_mm_cvtss_sd(__m128d A, __m128 B) { // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 0 return _mm_cvtss_sd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_cvtss_sd((__m128d){+32.0, +8.0}, (__m128){-1.0f, +2.0f, -3.0f, +4.0f}), -1.0, +8.0)); __m128i test_mm_cvttpd_epi32(__m128d A) { // CHECK-LABEL: test_mm_cvttpd_epi32 @@ -640,6 +653,7 @@ __m128d test_mm_div_pd(__m128d A, __m128d B) { // CHECK: fdiv <2 x double> return _mm_div_pd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_div_pd((__m128d){+2.0, +8.0}, (__m128d){-4.0, +2.0}), -0.5, +4.0)); __m128d test_mm_div_sd(__m128d A, __m128d B) { // CHECK-LABEL: test_mm_div_sd @@ -649,6 +663,7 @@ __m128d test_mm_div_sd(__m128d A, __m128d B) { // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 0 return _mm_div_sd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_div_sd((__m128d){+2.0, +8.0}, (__m128d){-4.0, +2.0}), -0.5, +8.0)); // Lowering to pextrw requires optimization. int test_mm_extract_epi16(__m128i A) { @@ -873,6 +888,7 @@ __m128d test_mm_move_sd(__m128d A, __m128d B) { // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 0 return _mm_move_sd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_move_sd((__m128d){+2.0, +8.0}, (__m128d){-4.0, +2.0}), -4.0, +8.0)); int test_mm_movemask_epi8(__m128i A) { // CHECK-LABEL: test_mm_movemask_epi8 @@ -899,6 +915,7 @@ __m128d test_mm_mul_pd(__m128d A, __m128d B) { // CHECK: fmul <2 x double> %{{.*}}, %{{.*}} return _mm_mul_pd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_mul_pd((__m128d){+1.0, -3.0}, (__m128d){+5.0, -5.0}), +5.0, +15.0)); __m128d test_mm_mul_sd(__m128d A, __m128d B) { // CHECK-LABEL: test_mm_mul_sd @@ -908,6 +925,7 @@ __m128d test_mm_mul_sd(__m128d A, __m128d B) { // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 0 return _mm_mul_sd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_mul_sd((__m128d){+1.0, -3.0}, (__m128d){+5.0, -5.0}), +5.0, -3.0)); __m128i test_mm_mulhi_epi16(__m128i A, __m128i B) { // CHECK-LABEL: test_mm_mulhi_epi16 @@ -932,6 +950,7 @@ __m128d test_mm_or_pd(__m128d A, __m128d B) { // CHECK: or <2 x i64> %{{.*}}, %{{.*}} return _mm_or_pd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_or_pd((__m128d){+1.0, -3.0}, (__m128d){-0.0, +0.0}), -1.0, -3.0)); __m128i test_mm_or_si128(__m128i A, __m128i B) { // CHECK-LABEL: test_mm_or_si128 @@ -1036,6 +1055,7 @@ __m128d test_mm_set_pd(double A, double B) { // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 1 return _mm_set_pd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_set_pd(-9.0, +3.0), +3.0, -9.0)); __m128d test_mm_set_pd1(double A) { // CHECK-LABEL: test_mm_set_pd1 @@ -1043,6 +1063,7 @@ __m128d test_mm_set_pd1(double A) { // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 1 return _mm_set_pd1(A); } +TEST_CONSTEXPR(match_m128d(_mm_set_pd1(+5.0), +5.0, +5.0)); __m128d test_mm_set_sd(double A) { // CHECK-LABEL: test_mm_set_sd @@ -1050,6 +1071,7 @@ __m128d test_mm_set_sd(double A) { // CHECK: insertelement <2 x double> %{{.*}}, double 0.000000e+00, i32 1 return _mm_set_sd(A); } +TEST_CONSTEXPR(match_m128d(_mm_set_sd(+1.0), +1.0, +0.0)); __m128i test_mm_set1_epi8(char A) { // CHECK-LABEL: test_mm_set1_epi8 @@ -1114,6 +1136,7 @@ __m128d test_mm_set1_pd(double A) { // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 1 return _mm_set1_pd(A); } +TEST_CONSTEXPR(match_m128d(_mm_set1_pd(-42.0), -42.0, -42.0)); __m128i test_mm_setr_epi8(char A, char B, char C, char D, char E, char F, char G, char H, @@ -1175,18 +1198,21 @@ __m128d test_mm_setr_pd(double A, double B) { // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 1 return _mm_setr_pd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_setr_pd(-9.0, +3.0), -9.0, +3.0)); __m128d test_mm_setzero_pd(void) { // CHECK-LABEL: test_mm_setzero_pd // CHECK: store <2 x double> zeroinitializer return _mm_setzero_pd(); } +TEST_CONSTEXPR(match_m128d(_mm_setzero_pd(), +0.0, +0.0)); __m128i test_mm_setzero_si128(void) { // CHECK-LABEL: test_mm_setzero_si128 // CHECK: store <2 x i64> zeroinitializer return _mm_setzero_si128(); } +TEST_CONSTEXPR(match_m128i(_mm_setzero_si128(), 0, 0)); __m128i test_mm_shuffle_epi32(__m128i A) { // CHECK-LABEL: test_mm_shuffle_epi32 @@ -1620,6 +1646,7 @@ __m128d test_mm_sub_pd(__m128d A, __m128d B) { // CHECK: fsub <2 x double> return _mm_sub_pd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_sub_pd((__m128d){+1.0, -3.0}, (__m128d){+5.0, -5.0}), -4.0, +2.0)); __m128d test_mm_sub_sd(__m128d A, __m128d B) { // CHECK-LABEL: test_mm_sub_sd @@ -1629,6 +1656,7 @@ __m128d test_mm_sub_sd(__m128d A, __m128d B) { // CHECK: insertelement <2 x double> %{{.*}}, double %{{.*}}, i32 0 return _mm_sub_sd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_sub_sd((__m128d){+1.0, -3.0}, (__m128d){+5.0, -5.0}), -4.0, -3.0)); __m128i test_mm_subs_epi8(__m128i A, __m128i B) { // CHECK-LABEL: test_mm_subs_epi8 @@ -1736,6 +1764,7 @@ __m128d test_mm_unpackhi_pd(__m128d A, __m128d B) { // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> return _mm_unpackhi_pd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_unpackhi_pd((__m128d){+2.0, +8.0}, (__m128d){-4.0, -2.0}), +8.0, -2.0)); __m128i test_mm_unpacklo_epi8(__m128i A, __m128i B) { // CHECK-LABEL: test_mm_unpacklo_epi8 @@ -1766,123 +1795,17 @@ __m128d test_mm_unpacklo_pd(__m128d A, __m128d B) { // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> return _mm_unpacklo_pd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_unpacklo_pd((__m128d){+2.0, +8.0}, (__m128d){-4.0, -2.0}), +2.0, -4.0)); __m128d test_mm_xor_pd(__m128d A, __m128d B) { // CHECK-LABEL: test_mm_xor_pd // CHECK: xor <2 x i64> %{{.*}}, %{{.*}} return _mm_xor_pd(A, B); } +TEST_CONSTEXPR(match_m128d(_mm_xor_pd((__m128d){+1.0, -3.0}, (__m128d){+0.0, -0.0}), +1.0, +3.0)); __m128i test_mm_xor_si128(__m128i A, __m128i B) { // CHECK-LABEL: test_mm_xor_si128 // CHECK: xor <2 x i64> %{{.*}}, %{{.*}} return _mm_xor_si128(A, B); } - -// Test constexpr handling. -#if defined(__cplusplus) && (__cplusplus >= 201103L) - -void test_constexpr() { - constexpr __m128d kd1 {+2.0,-1.0}; - constexpr __m128d kd2 {-4.0,-2.0}; - constexpr __m128d kd3 {-0.0,+0.0}; - - constexpr __m128 kf1 {-1.0f,+2.0f,-3.0f,+4.0f}; - - constexpr __m64 km1 {0x00000080FFFFFFF0ULL}; // -16,+128 - constexpr __m128i ki1 {0x00000010FFFFFFF8ULL, 0x00000001FFFFFFFFULL}; // -8,+16,-1,1 - - constexpr __m128d v_mm_set_sd = _mm_set_sd(1.0); - static_assert(v_mm_set_sd[0] == +1.0 && v_mm_set_sd[1] == +0.0); - - constexpr __m128d v_mm_set1_pd = _mm_set1_pd(2.0); - static_assert(v_mm_set1_pd[0] == +2.0 && v_mm_set1_pd[1] == +2.0); - - constexpr __m128d v_mm_set_pd1 = _mm_set_pd1(-2.0); - static_assert(v_mm_set_pd1[0] == -2.0 && v_mm_set_pd1[1] == -2.0); - - constexpr __m128d v_mm_set_pd = _mm_set_pd(+2.0, +3.0); - static_assert(v_mm_set_pd[0] == +3.0 && v_mm_set_pd[1] == +2.0); - - constexpr __m128d v_mm_setr_pd = _mm_setr_pd(+2.0, +3.0); - static_assert(v_mm_setr_pd[0] == +2.0 && v_mm_setr_pd[1] == +3.0); - - constexpr __m128d v_mm_setzero_pd = _mm_setzero_pd(); - static_assert(v_mm_setzero_pd[0] == +0.0 && v_mm_setzero_pd[1] == +0.0); - - constexpr __m128i v_mm_setzero_si128 = _mm_setzero_si128(); - static_assert(v_mm_setzero_si128[0] == 0x0000000000000000ULL && v_mm_setzero_si128[1] == 0x0000000000000000ULL); - - constexpr __m128d v_mm_add_sd = _mm_add_sd(kd1, kd2); - static_assert(v_mm_add_sd[0] == -2.0 && v_mm_add_sd[1] == -1.0); - - constexpr __m128d v_mm_add_pd = _mm_add_pd(kd1, kd2); - static_assert(v_mm_add_pd[0] == -2.0 && v_mm_add_pd[1] == -3.0); - - constexpr __m128d v_mm_sub_sd = _mm_sub_sd(kd1, kd2); - static_assert(v_mm_sub_sd[0] == +6.0 && v_mm_sub_sd[1] == -1.0); - - constexpr __m128d v_mm_sub_pd = _mm_sub_pd(kd1, kd2); - static_assert(v_mm_sub_pd[0] == +6.0 && v_mm_sub_pd[1] == +1.0); - - constexpr __m128d v_mm_mul_sd = _mm_mul_sd(kd1, kd2); - static_assert(v_mm_mul_sd[0] == -8.0 && v_mm_mul_sd[1] == -1.0); - - constexpr __m128d v_mm_mul_pd = _mm_mul_pd(kd1, kd2); - static_assert(v_mm_mul_pd[0] == -8.0 && v_mm_mul_pd[1] == +2.0); - - constexpr __m128d v_mm_div_sd = _mm_div_sd(kd1, kd2); - static_assert(v_mm_div_sd[0] == -0.5 && v_mm_div_sd[1] == -1.0); - - constexpr __m128d v_mm_div_pd = _mm_div_pd(kd1, kd2); - static_assert(v_mm_div_pd[0] == -0.5 && v_mm_div_pd[1] == +0.5); - - constexpr __m128d v_mm_and_pd = _mm_and_pd(kd1, kd3); - static_assert(v_mm_and_pd[0] == +0.0 && v_mm_and_pd[1] == +0.0); - - constexpr __m128d v_mm_andnot_pd = _mm_andnot_pd(kd1, kd3); - static_assert(v_mm_andnot_pd[0] == -0.0 && v_mm_andnot_pd[1] == +0.0); - - constexpr __m128d v_mm_or_pd = _mm_or_pd(kd1, kd3); - static_assert(v_mm_or_pd[0] == -2.0 && v_mm_or_pd[1] == -1.0); - - constexpr __m128d v_mm_xor_pd = _mm_xor_pd(kd2, kd3); - static_assert(v_mm_xor_pd[0] == +4.0 && v_mm_xor_pd[1] == -2.0); - - constexpr __m128d v_mm_cvtps_pd = _mm_cvtps_pd(kf1); - static_assert(v_mm_cvtps_pd[0] == -1.0 && v_mm_cvtps_pd[1] == +2.0); - - constexpr __m128d v_mm_cvtepi32_pd = _mm_cvtepi32_pd(ki1); - static_assert(v_mm_cvtepi32_pd[0] == -8.0 && v_mm_cvtepi32_pd[1] == +16.0); - - constexpr __m128 v_mm_cvtepi32_ps = _mm_cvtepi32_ps(ki1); - static_assert(v_mm_cvtepi32_ps[0] == -8.0f && v_mm_cvtepi32_ps[1] == +16.0f && v_mm_cvtepi32_ps[2] == -1.0f && v_mm_cvtepi32_ps[3] == +1.0f); - - constexpr __m128d v_mm_cvtsi32_sd = _mm_cvtsi32_sd(kd1, 8); - static_assert(v_mm_cvtsi32_sd[0] == +8.0 && v_mm_cvtsi32_sd[1] == -1.0); - - constexpr __m128d v_mm_cvtss_sd = _mm_cvtss_sd(kd2, kf1); - static_assert(v_mm_cvtss_sd[0] == -1.0 && v_mm_cvtss_sd[1] == -2.0); - - constexpr __m128d v_mm_cvtpi32_pd = _mm_cvtpi32_pd(km1); - static_assert(v_mm_cvtpi32_pd[0] == -16.0 && v_mm_cvtpi32_pd[1] == 128.0); - - static_assert(_mm_cvtsd_f64(kd2) == -4.0); - - constexpr __m128d v_mm_move_sd = _mm_move_sd(kd1, kd2); - static_assert(v_mm_move_sd[0] == -4.0 && v_mm_move_sd[1] == -1.0); - - constexpr __m128d v_mm_unpackhi_pd = _mm_unpackhi_pd(kd1, kd2); - static_assert(v_mm_unpackhi_pd[0] == -1.0f && v_mm_unpackhi_pd[1] == -2.0f); - - constexpr __m128d v_mm_unpacklo_pd = _mm_unpacklo_pd(kd1, kd2); - static_assert(v_mm_unpacklo_pd[0] == +2.0f && v_mm_unpacklo_pd[1] == -4.0f); - - constexpr __m128 v_mm_castpd_ps = _mm_castpd_ps(kd3); - static_assert(v_mm_castpd_ps[0] == -0.0f && v_mm_castpd_ps[1] == +0.0f && v_mm_castpd_ps[2] == +0.0f && v_mm_castpd_ps[3] == +0.0f); - - constexpr __m128i v_mm_castpd_si128 = _mm_castpd_si128(kd3); - static_assert(v_mm_castpd_si128[0] == 0x8000000000000000ULL && v_mm_castpd_si128[1] == 0x0000000000000000ULL); -} - -#endif diff --git a/clang/test/CodeGen/X86/sse3-builtins.c b/clang/test/CodeGen/X86/sse3-builtins.c index 18c062f4c14a7db45077819f0c118a9698ec56cd..d47c19b882cd1efb4894659249b2368f04cb4695 100644 --- a/clang/test/CodeGen/X86/sse3-builtins.c +++ b/clang/test/CodeGen/X86/sse3-builtins.c @@ -5,6 +5,7 @@ #include +#include "builtin_test_helpers.h" // NOTE: This should match the tests in llvm/test/CodeGen/X86/sse3-intrinsics-fast-isel.ll @@ -63,34 +64,18 @@ __m128d test_mm_movedup_pd(__m128d A) { // CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> zeroinitializer return _mm_movedup_pd(A); } +TEST_CONSTEXPR(match_m128d(_mm_movedup_pd((__m128d){+7.0, -7.0}), +7.0, +7.0)); __m128 test_mm_movehdup_ps(__m128 A) { // CHECK-LABEL: test_mm_movehdup_ps // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x i32> return _mm_movehdup_ps(A); } +TEST_CONSTEXPR(match_m128(_mm_movehdup_ps((__m128){+1.0f,-1.0f,+2.0f,+4.0f}), -1.0f, -1.0f, +4.0f, +4.0f)); __m128 test_mm_moveldup_ps(__m128 A) { // CHECK-LABEL: test_mm_moveldup_ps // CHECK: shufflevector <4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x i32> return _mm_moveldup_ps(A); } - -// Test constexpr handling. -#if defined(__cplusplus) && (__cplusplus >= 201103L) - -void test_constexpr() { - constexpr __m128d kd1 {+7.0,-7.0}; - constexpr __m128 kf1 {+1.0f,-1.0f,+2.0f,+4.0f}; - - constexpr __m128d v_mm_movedup_pd = _mm_movedup_pd(kd1); - static_assert(v_mm_movedup_pd[0] == +7.0 && v_mm_movedup_pd[1] == +7.0); - - constexpr __m128 v_mm_movehdup_ps = _mm_movehdup_ps(kf1); - static_assert(v_mm_movehdup_ps[0] == -1.0f && v_mm_movehdup_ps[1] == -1.0f && v_mm_movehdup_ps[2] == +4.0f && v_mm_movehdup_ps[3] == +4.0f); - - constexpr __m128 v_mm_moveldup_ps = _mm_moveldup_ps(kf1); - static_assert(v_mm_moveldup_ps[0] == +1.0f && v_mm_moveldup_ps[1] == +1.0f && v_mm_moveldup_ps[2] == +2.0f && v_mm_moveldup_ps[3] == +2.0f); -} - -#endif +TEST_CONSTEXPR(match_m128(_mm_moveldup_ps((__m128){+1.0f,-1.0f,+2.0f,+4.0f}), +1.0f, +1.0f, +2.0f, +2.0f)); diff --git a/clang/test/CodeGen/aarch64-debug-types.c b/clang/test/CodeGen/aarch64-debug-types.c new file mode 100644 index 0000000000000000000000000000000000000000..f1ab74c5c31bdb1ca9e6d96d0ca31cad6562b7ce --- /dev/null +++ b/clang/test/CodeGen/aarch64-debug-types.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon -target-feature +fp8 \ +// RUN: -emit-llvm -o - %s -debug-info-kind=limited 2>&1 | FileCheck %s + +// REQUIRES: aarch64-registered-target + +#include + +void test_locals(void) { + // CHECK-DAG: !DIDerivedType(tag: DW_TAG_typedef, name: "__MFloat8_t", {{.*}}, baseType: ![[ELTTYU8:[0-9]+]] + // CHECK-DAG: ![[ELTTYU8]] = !DIBasicType(name: "__MFloat8_t", size: 8, encoding: DW_ATE_unsigned_char) + __MFloat8_t mfp8; +} diff --git a/clang/test/CodeGen/aarch64-fpm-helpers.c b/clang/test/CodeGen/aarch64-fpm-helpers.c new file mode 100644 index 0000000000000000000000000000000000000000..4bced01d5c71fa987c9128d6880fee2389878e02 --- /dev/null +++ b/clang/test/CodeGen/aarch64-fpm-helpers.c @@ -0,0 +1,165 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 + +// RUN: %clang_cc1 -O2 -triple aarch64 -emit-llvm -x c -DUSE_NEON_H %s -o - | FileCheck %s +// RUN: %clang_cc1 -O2 -triple aarch64 -emit-llvm -x c -DUSE_SVE_H %s -o - | FileCheck %s +// RUN: %clang_cc1 -O2 -triple aarch64 -emit-llvm -x c -DUSE_SME_H %s -o - | FileCheck %s +// RUN: %clang_cc1 -O2 -triple aarch64 -emit-llvm -x c++ -DUSE_NEON_H %s -o - | FileCheck %s +// RUN: %clang_cc1 -O2 -triple aarch64 -emit-llvm -x c++ -DUSE_SVE_H %s -o - | FileCheck %s +// RUN: %clang_cc1 -O2 -triple aarch64 -emit-llvm -x c++ -DUSE_SME_H %s -o - | FileCheck %s + +// REQUIRES: aarch64-registered-target + +#ifdef USE_NEON_H +#include "arm_neon.h" +#endif + +#ifdef USE_SVE_H +#include "arm_sve.h" +#endif + +#ifdef USE_SME_H +#include "arm_sme.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define INIT_ZERO 0 +#define INIT_ONES 0xffffffffffffffffU + +// CHECK-LABEL: define dso_local noundef i64 @test_init( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 0 +// +fpm_t test_init() { return __arm_fpm_init(); } + +// CHECK-LABEL: define dso_local noundef i64 @test_src1_1( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 -8 +// +fpm_t test_src1_1() { + return __arm_set_fpm_src1_format(INIT_ONES, __ARM_FPM_E5M2); +} + +// CHECK-LABEL: define dso_local noundef i64 @test_src1_2( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 1 +// +fpm_t test_src1_2() { + return __arm_set_fpm_src1_format(INIT_ZERO, __ARM_FPM_E4M3); +} + +// CHECK-LABEL: define dso_local noundef i64 @test_src2_1( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 -57 +// +fpm_t test_src2_1() { + return __arm_set_fpm_src2_format(INIT_ONES, __ARM_FPM_E5M2); +} + +// CHECK-LABEL: define dso_local noundef i64 @test_src2_2( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 8 +// +fpm_t test_src2_2() { + return __arm_set_fpm_src2_format(INIT_ZERO, __ARM_FPM_E4M3); +} + +// CHECK-LABEL: define dso_local noundef i64 @test_dst1_1( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 -449 +// +fpm_t test_dst1_1() { + return __arm_set_fpm_dst_format(INIT_ONES, __ARM_FPM_E5M2); +} + +// CHECK-LABEL: define dso_local noundef i64 @test_dst2_2( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 64 +// +fpm_t test_dst2_2() { + return __arm_set_fpm_dst_format(INIT_ZERO, __ARM_FPM_E4M3); +} + +// CHECK-LABEL: define dso_local noundef i64 @test_of_mul_1( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 -16385 +// +fpm_t test_of_mul_1() { + return __arm_set_fpm_overflow_mul(INIT_ONES, __ARM_FPM_INFNAN); +} + +// CHECK-LABEL: define dso_local noundef i64 @test_of_mul_2( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 16384 +// +fpm_t test_of_mul_2() { + return __arm_set_fpm_overflow_mul(INIT_ZERO, __ARM_FPM_SATURATE); +} + +// CHECK-LABEL: define dso_local noundef i64 @test_of_cvt_1( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 -32769 +// +fpm_t test_of_cvt_1() { + return __arm_set_fpm_overflow_cvt(INIT_ONES, __ARM_FPM_INFNAN); +} + +// CHECK-LABEL: define dso_local noundef i64 @test_of_cvt_2( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 32768 +// +fpm_t test_of_cvt_2() { + return __arm_set_fpm_overflow_cvt(INIT_ZERO, __ARM_FPM_SATURATE); +} + +// CHECK-LABEL: define dso_local noundef i64 @test_lscale( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 8323072 +// +fpm_t test_lscale() { return __arm_set_fpm_lscale(INIT_ZERO, 127); } + +// CHECK-LABEL: define dso_local noundef i64 @test_lscale2( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 270582939648 +// +fpm_t test_lscale2() { return __arm_set_fpm_lscale2(INIT_ZERO, 63); } + +// CHECK-LABEL: define dso_local noundef range(i64 0, 4294967296) i64 @test_nscale_1( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 2147483648 +// +fpm_t test_nscale_1() { return __arm_set_fpm_nscale(INIT_ZERO, -128); } + +// CHECK-LABEL: define dso_local noundef range(i64 0, 4294967296) i64 @test_nscale_2( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 2130706432 +// +fpm_t test_nscale_2() { return __arm_set_fpm_nscale(INIT_ZERO, 127); } + +// CHECK-LABEL: define dso_local noundef range(i64 0, 4294967296) i64 @test_nscale_3( +// CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret i64 4278190080 +// +fpm_t test_nscale_3() { return __arm_set_fpm_nscale(INIT_ZERO, -1); } + +#ifdef __cplusplus +} +#endif diff --git a/clang/test/CodeGen/aarch64-pure-scalable-args-empty-union.c b/clang/test/CodeGen/aarch64-pure-scalable-args-empty-union.c new file mode 100644 index 0000000000000000000000000000000000000000..546910068c78a221093cd03f770b06cd86dfadc0 --- /dev/null +++ b/clang/test/CodeGen/aarch64-pure-scalable-args-empty-union.c @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -O3 -triple aarch64 -target-feature +sve -mvscale-min=1 -mvscale-max=1 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK-C +// RUN: %clang_cc1 -x c++ -O3 -triple aarch64 -target-feature +sve -mvscale-min=1 -mvscale-max=1 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK-CXX + +typedef __SVFloat32_t fvec32 __attribute__((arm_sve_vector_bits(128))); + +// PST containing an empty union: when compiled as C pass it in registers, +// when compiled as C++ - in memory. +typedef struct { + fvec32 x[4]; + union {} u; +} S0; + +#ifdef __cplusplus +extern "C" +#endif +void use0(S0); + +void f0(S0 *p) { + use0(*p); +} +// CHECK-C: declare void @use0(, , , ) +// CHECK-CXX: declare void @use0(ptr noundef) + +#ifdef __cplusplus + +// PST containing an empty union with `[[no_unique_address]]`` - pass in registers. +typedef struct { + fvec32 x[4]; + [[no_unique_address]] + union {} u; +} S1; + +extern "C" void use1(S1); +void f1(S1 *p) { + use1(*p); +} +// CHECK-CXX: declare void @use1(, , , ) + +#endif // __cplusplus diff --git a/clang/test/CodeGen/aarch64-pure-scalable-args.c b/clang/test/CodeGen/aarch64-pure-scalable-args.c new file mode 100644 index 0000000000000000000000000000000000000000..851159ada767495586c467aebd0a06d25761827b --- /dev/null +++ b/clang/test/CodeGen/aarch64-pure-scalable-args.c @@ -0,0 +1,461 @@ +// RUN: %clang_cc1 -O3 -triple aarch64 -target-feature +sve -target-feature +sve2p1 -mvscale-min=1 -mvscale-max=1 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-AAPCS +// RUN: %clang_cc1 -O3 -triple arm64-apple-ios7.0 -target-abi darwinpcs -target-feature +sve -target-feature +sve2p1 -mvscale-min=1 -mvscale-max=1 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DARWIN +// RUN: %clang_cc1 -O3 -triple aarch64-linux-gnu -target-feature +sve -target-feature +sve2p1 -mvscale-min=1 -mvscale-max=1 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-AAPCS + +// REQUIRES: aarch64-registered-target + +#include +#include +#include + +typedef svfloat32_t fvec32 __attribute__((arm_sve_vector_bits(128))); +typedef svfloat64_t fvec64 __attribute__((arm_sve_vector_bits(128))); +typedef svbool_t bvec __attribute__((arm_sve_vector_bits(128))); +typedef svmfloat8_t mfvec8 __attribute__((arm_sve_vector_bits(128))); + +typedef struct { + float f[4]; +} HFA; + +typedef struct { + mfloat8x16_t f[4]; +} HVA; + +// Pure Scalable Type, needs 4 Z-regs, 2 P-regs +typedef struct { + bvec a; + fvec64 x; + fvec32 y[2]; + mfvec8 z; + bvec b; +} PST; + +// Pure Scalable Type, 1 Z-reg +typedef struct { + fvec32 x; +} SmallPST; + +// Big PST, does not fit in registers. +typedef struct { + struct { + bvec a; + fvec32 x[4]; + } u[2]; + fvec64 v; +} BigPST; + +// A small aggregate type +typedef struct { + char data[16]; +} SmallAgg; + +// CHECK: %struct.PST = type { <2 x i8>, <2 x double>, [2 x <4 x float>], <16 x i8>, <2 x i8> } + +// Test argument passing of Pure Scalable Types by examining the generated +// LLVM IR function declarations. A PST argument in C/C++ should map to: +// a) an `ptr` argument, if passed indirectly through memory +// b) a series of scalable vector arguments, if passed via registers + +// Simple argument passing, PST expanded into registers. +// a -> p0 +// b -> p1 +// x -> q0 +// y[0] -> q1 +// y[1] -> q2 +// z -> q3 +void test_argpass_simple(PST *p) { + void argpass_simple_callee(PST); + argpass_simple_callee(*p); +} +// CHECK-AAPCS: define dso_local void @test_argpass_simple(ptr nocapture noundef readonly %p) +// CHECK-AAPCS-NEXT: entry: +// CHECK-AAPCS-NEXT: %0 = load <2 x i8>, ptr %p, align 16 +// CHECK-AAPCS-NEXT: %cast.scalable = tail call @llvm.vector.insert.nxv2i8.v2i8( undef, <2 x i8> %0, i64 0) +// CHECK-AAPCS-NEXT: %1 = bitcast %cast.scalable to +// CHECK-AAPCS-NEXT: %2 = getelementptr inbounds nuw i8, ptr %p, i64 16 +// CHECK-AAPCS-NEXT: %3 = load <2 x double>, ptr %2, align 16 +// CHECK-AAPCS-NEXT: %cast.scalable1 = tail call @llvm.vector.insert.nxv2f64.v2f64( undef, <2 x double> %3, i64 0) +// CHECK-AAPCS-NEXT: %4 = getelementptr inbounds nuw i8, ptr %p, i64 32 +// CHECK-AAPCS-NEXT: %5 = load <4 x float>, ptr %4, align 16 +// CHECK-AAPCS-NEXT: %cast.scalable2 = tail call @llvm.vector.insert.nxv4f32.v4f32( undef, <4 x float> %5, i64 0) +// CHECK-AAPCS-NEXT: %6 = getelementptr inbounds nuw i8, ptr %p, i64 48 +// CHECK-AAPCS-NEXT: %7 = load <4 x float>, ptr %6, align 16 +// CHECK-AAPCS-NEXT: %cast.scalable3 = tail call @llvm.vector.insert.nxv4f32.v4f32( undef, <4 x float> %7, i64 0) +// CHECK-AAPCS-NEXT: %8 = getelementptr inbounds nuw i8, ptr %p, i64 64 +// CHECK-AAPCS-NEXT: %9 = load <16 x i8>, ptr %8, align 16 +// CHECK-AAPCS-NEXT: %cast.scalable4 = tail call @llvm.vector.insert.nxv16i8.v16i8( undef, <16 x i8> %9, i64 0) +// CHECK-AAPCS-NEXT: %10 = getelementptr inbounds nuw i8, ptr %p, i64 80 +// CHECK-AAPCS-NEXT: %11 = load <2 x i8>, ptr %10, align 16 +// CHECK-AAPCS-NEXT: %cast.scalable5 = tail call @llvm.vector.insert.nxv2i8.v2i8( undef, <2 x i8> %11, i64 0) +// CHECK-AAPCS-NEXT: %12 = bitcast %cast.scalable5 to +// CHECK-AAPCS-NEXT: tail call void @argpass_simple_callee( %1, %cast.scalable1, %cast.scalable2, %cast.scalable3, %cast.scalable4, %12) +// CHECK-AAPCS-NEXT: ret void + +// CHECK-AAPCS: declare void @argpass_simple_callee(, , , , , ) +// CHECK-DARWIN: declare void @argpass_simple_callee(ptr noundef) + +// Boundary case of using the last available Z-reg, PST expanded. +// 0.0 -> d0-d3 +// a -> p0 +// b -> p1 +// x -> q4 +// y[0] -> q5 +// y[1] -> q6 +// z -> q7 +void test_argpass_last_z(PST *p) { + void argpass_last_z_callee(double, double, double, double, PST); + argpass_last_z_callee(.0, .0, .0, .0, *p); +} +// CHECK-AAPCS: declare void @argpass_last_z_callee(double noundef, double noundef, double noundef, double noundef, , , , , , ) +// CHECK-DARWIN: declare void @argpass_last_z_callee(double noundef, double noundef, double noundef, double noundef, ptr noundef) + + +// Like the above, but using a tuple type to occupy some registers. +// x -> z0.d-z3.d +// a -> p0 +// b -> p1 +// x -> q4 +// y[0] -> q5 +// y[1] -> q6 +// z -> q7 +void test_argpass_last_z_tuple(PST *p, svfloat64x4_t x) { + void argpass_last_z_tuple_callee(svfloat64x4_t, PST); + argpass_last_z_tuple_callee(x, *p); +} +// CHECK-AAPCS: declare void @argpass_last_z_tuple_callee(, , , , , , , , , ) +// CHECK-DARWIN: declare void @argpass_last_z_tuple_callee(, , , , ptr noundef) + + +// Boundary case of using the last available P-reg, PST expanded. +// false -> p0-p1 +// a -> p2 +// b -> p3 +// x -> q0 +// y[0] -> q1 +// y[1] -> q2 +// z -> q3 +void test_argpass_last_p(PST *p) { + void argpass_last_p_callee(svbool_t, svcount_t, PST); + argpass_last_p_callee(svpfalse(), svpfalse_c(), *p); +} +// CHECK-AAPCS: declare void @argpass_last_p_callee(, target("aarch64.svcount"), , , , , , ) +// CHECK-DARWIN: declare void @argpass_last_p_callee(, target("aarch64.svcount"), ptr noundef) + + +// Not enough Z-regs, push PST to memory and pass a pointer, Z-regs and +// P-regs still available for other arguments +// u -> z0 +// v -> q1 +// w -> q2 +// 0.0 -> d3-d4 +// 1 -> w0 +// *p -> memory, address -> x1 +// 2 -> w2 +// 3.0 -> d5 +// true -> p0 +void test_argpass_no_z(PST *p, double dummy, svmfloat8_t u, int8x16_t v, mfloat8x16_t w) { + void argpass_no_z_callee(svmfloat8_t, int8x16_t, mfloat8x16_t, double, double, int, PST, int, double, svbool_t); + argpass_no_z_callee(u, v, w, .0, .0, 1, *p, 2, 3.0, svptrue_b64()); +} +// CHECK: declare void @argpass_no_z_callee(, <16 x i8> noundef, <16 x i8>, double noundef, double noundef, i32 noundef, ptr noundef, i32 noundef, double noundef, ) + + +// Like the above, using a tuple to occupy some registers. +// x -> z0.d-z3.d +// 0.0 -> d4 +// 1 -> w0 +// *p -> memory, address -> x1 +// 2 -> w2 +// 3.0 -> d5 +// true -> p0 +void test_argpass_no_z_tuple_f64(PST *p, float dummy, svfloat64x4_t x) { + void argpass_no_z_tuple_f64_callee(svfloat64x4_t, double, int, PST, int, + double, svbool_t); + argpass_no_z_tuple_f64_callee(x, .0, 1, *p, 2, 3.0, svptrue_b64()); +} +// CHECK: declare void @argpass_no_z_tuple_f64_callee(, , , , double noundef, i32 noundef, ptr noundef, i32 noundef, double noundef, ) + + +// Likewise, using a different tuple. +// x -> z0.d-z3.d +// 0.0 -> d4 +// 1 -> w0 +// *p -> memory, address -> x1 +// 2 -> w2 +// 3.0 -> d5 +// true -> p0 +void test_argpass_no_z_tuple_mfp8(PST *p, float dummy, svmfloat8x4_t x) { + void argpass_no_z_tuple_mfp8_callee(svmfloat8x4_t, double, int, PST, int, + double, svbool_t); + argpass_no_z_tuple_mfp8_callee(x, .0, 1, *p, 2, 3.0, svptrue_b64()); +} +// CHECK: declare void @argpass_no_z_tuple_mfp8_callee(, , , , double noundef, i32 noundef, ptr noundef, i32 noundef, double noundef, ) + + +// Not enough Z-regs (consumed by a HFA), PST passed indirectly +// 0.0 -> d0 +// *h -> s1-s4 +// 1 -> w0 +// *p -> memory, address -> x1 +// p -> x1 +// 2 -> w2 +// true -> p0 +void test_argpass_no_z_hfa(HFA *h, PST *p) { + void argpass_no_z_hfa_callee(double, HFA, int, PST, int, svbool_t); + argpass_no_z_hfa_callee(.0, *h, 1, *p, 2, svptrue_b64()); +} +// CHECK-AAPCS: declare void @argpass_no_z_hfa_callee(double noundef, [4 x float] alignstack(8), i32 noundef, ptr noundef, i32 noundef, ) +// CHECK-DARWIN: declare void @argpass_no_z_hfa_callee(double noundef, [4 x float], i32 noundef, ptr noundef, i32 noundef, ) + +// Not enough Z-regs (consumed by a HVA), PST passed indirectly +// 0.0 -> d0 +// *h -> s1-s4 +// 1 -> w0 +// *p -> memory, address -> x1 +// p -> x1 +// 2 -> w2 +// true -> p0 +void test_argpass_no_z_hva(HVA *h, PST *p) { + void argpass_no_z_hva_callee(double, HVA, int, PST, int, svbool_t); + argpass_no_z_hva_callee(.0, *h, 1, *p, 2, svptrue_b64()); +} +// CHECK-AAPCS: declare void @argpass_no_z_hva_callee(double noundef, [4 x <16 x i8>] alignstack(16), i32 noundef, ptr noundef, i32 noundef, ) +// CHECK-DARWIN: declare void @argpass_no_z_hva_callee(double noundef, [4 x <16 x i8>], i32 noundef, ptr noundef, i32 noundef, ) + +// Not enough P-regs, PST passed indirectly, Z-regs and P-regs still available. +// true -> p0-p2 +// 1 -> w0 +// *p -> memory, address -> x1 +// 2 -> w2 +// 3.0 -> d0 +// true -> p3 +void test_argpass_no_p(PST *p) { + void argpass_no_p_callee(svbool_t, svbool_t, svbool_t, int, PST, int, double, svbool_t); + argpass_no_p_callee(svptrue_b8(), svptrue_b16(), svptrue_b32(), 1, *p, 2, 3.0, svptrue_b64()); +} +// CHECK: declare void @argpass_no_p_callee(, , , i32 noundef, ptr noundef, i32 noundef, double noundef, ) + + +// Like above, using a tuple to occupy some registers. +// P-regs still available. +// v -> p0-p1 +// u -> p2 +// 1 -> w0 +// *p -> memory, address -> x1 +// 2 -> w2 +// 3.0 -> d0 +// true -> p3 +void test_argpass_no_p_tuple(PST *p, svbool_t u, svboolx2_t v) { + void argpass_no_p_tuple_callee(svboolx2_t, svbool_t, int, PST, int, double, + svbool_t); + argpass_no_p_tuple_callee(v, u, 1, *p, 2, 3.0, svptrue_b64()); +} +// CHECK: declare void @argpass_no_p_tuple_callee(, , , i32 noundef, ptr noundef, i32 noundef, double noundef, ) + + +// HFAs go back-to-back to memory, afterwards Z-regs not available, PST passed indirectly. +// 0.0 -> d0-d3 +// *h -> memory +// *p -> memory, address -> x0 +// *h -> memory +// false -> p0 +void test_after_hfa(HFA *h, PST *p) { + void after_hfa_callee(double, double, double, double, double, HFA, PST, HFA, svbool_t); + after_hfa_callee(.0, .0, .0, .0, .0, *h, *p, *h, svpfalse()); +} +// CHECK-AAPCS: declare void @after_hfa_callee(double noundef, double noundef, double noundef, double noundef, double noundef, [4 x float] alignstack(8), ptr noundef, [4 x float] alignstack(8), ) +// CHECK-DARWIN: declare void @after_hfa_callee(double noundef, double noundef, double noundef, double noundef, double noundef, [4 x float], ptr noundef, [4 x float], ) + +// Small PST, not enough registers, passed indirectly, unlike other small +// aggregates. +// *s -> x0-x1 +// 0.0 -> d0-d7 +// *p -> memory, address -> x2 +// 1.0 -> memory +// 2.0 -> memory (next to the above) +void test_small_pst(SmallPST *p, SmallAgg *s) { + void small_pst_callee(SmallAgg, double, double, double, double, double, double, double, double, double, SmallPST, double); + small_pst_callee(*s, .0, .0, .0, .0, .0, .0, .0, .0, 1.0, *p, 2.0); +} +// CHECK-AAPCS: declare void @small_pst_callee([2 x i64], double noundef, double noundef, double noundef, double noundef, double noundef, double noundef, double noundef, double noundef, double noundef, ptr noundef, double noundef) +// CHECK-DARWIN: declare void @small_pst_callee([2 x i64], double noundef, double noundef, double noundef, double noundef, double noundef, double noundef, double noundef, double noundef, double noundef, i128, double noundef) + + +// Simple return, PST expanded to registers +// p->a -> p0 +// p->x -> q0 +// p->y[0] -> q1 +// p->y[1] -> q2 +// p->z -> q3 +// p->b -> p1 +PST test_return(PST *p) { + return *p; +} +// CHECK-AAPCS: define dso_local <{ , , , , , }> @test_return(ptr +// CHECK-DARWIN: define void @test_return(ptr dead_on_unwind noalias nocapture writable writeonly sret(%struct.PST) align 16 %agg.result, ptr nocapture noundef readonly %p) + +// Corner case of 1-element aggregate +// p->x -> q0 +SmallPST test_return_small_pst(SmallPST *p) { + return *p; +} +// CHECK-AAPCS: define dso_local @test_return_small_pst(ptr +// CHECK-DARWIN: define i128 @test_return_small_pst(ptr nocapture noundef readonly %p) + + +// Big PST, returned indirectly +// *p -> *x8 +BigPST test_return_big_pst(BigPST *p) { + return *p; +} +// CHECK-AAPCS: define dso_local void @test_return_big_pst(ptr dead_on_unwind noalias nocapture writable writeonly sret(%struct.BigPST) align 16 %agg.result, ptr nocapture noundef readonly %p) +// CHECK-DARWIN: define void @test_return_big_pst(ptr dead_on_unwind noalias nocapture writable writeonly sret(%struct.BigPST) align 16 %agg.result, ptr nocapture noundef readonly %p) + +// Variadic arguments are unnamed, PST passed indirectly. +// (Passing SVE types to a variadic function currently unsupported by +// the AArch64 backend) +// p->a -> p0 +// p->x -> q0 +// p->y[0] -> q1 +// p->y[1] -> q2 +// p->z -> q3 +// p->b -> p1 +// *q -> memory, address -> x1 +void test_pass_variadic(PST *p, PST *q) { + void pass_variadic_callee(PST, ...); + pass_variadic_callee(*p, *q); +} +// CHECK-AAPCS: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 16 dereferenceable(96) %byval-temp, ptr noundef nonnull align 16 dereferenceable(96) %q, i64 96, i1 false) +// CHECK-AAPCS: call void (, , , , , , ...) @pass_variadic_callee( %1, %cast.scalable1, %cast.scalable2, %cast.scalable3, %cast.scalable4, %12, ptr noundef nonnull %byval-temp) + +// CHECK-DARWIN: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 16 dereferenceable(96) %byval-temp, ptr noundef nonnull align 16 dereferenceable(96) %p, i64 96, i1 false) +// CHECK-DARWIN: call void @llvm.lifetime.start.p0(i64 96, ptr nonnull %byval-temp1) +// CHECK-DARWIN: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 16 dereferenceable(96) %byval-temp1, ptr noundef nonnull align 16 dereferenceable(96) %q, i64 96, i1 false) +// CHECK-DARWIN: call void (ptr, ...) @pass_variadic_callee(ptr noundef nonnull %byval-temp, ptr noundef nonnull %byval-temp1) + + +// Test passing a small PST, still passed indirectly, despite being <= 128 bits +void test_small_pst_variadic(SmallPST *p) { + void small_pst_variadic_callee(int, ...); + small_pst_variadic_callee(0, *p); +} +// CHECK-AAPCS: call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 16 dereferenceable(16) %byval-temp, ptr noundef nonnull align 16 dereferenceable(16) %p, i64 16, i1 false) +// CHECK-AAPCS: call void (i32, ...) @small_pst_variadic_callee(i32 noundef 0, ptr noundef nonnull %byval-temp) + +// CHECK-DARWIN: %0 = load i128, ptr %p, align 16 +// CHECK-DARWIN: tail call void (i32, ...) @small_pst_variadic_callee(i32 noundef 0, i128 %0) + +// Test handling of a PST argument when passed in registers, from the callee side. +void test_argpass_callee_side(PST v) { + void use(PST *p); + use(&v); +} +// CHECK-AAPCS: define dso_local void @test_argpass_callee_side( %0, %.coerce1, %.coerce3, %.coerce5, %.coerce7, %1) +// CHECK-AAPCS-NEXT: entry: +// CHECK-AAPCS-NEXT: %v = alloca %struct.PST, align 16 +// CHECK-AAPCS-NEXT: %.coerce = bitcast %0 to +// CHECK-AAPCS-NEXT: %cast.fixed = tail call <2 x i8> @llvm.vector.extract.v2i8.nxv2i8( %.coerce, i64 0) +// CHECK-AAPCS-NEXT: store <2 x i8> %cast.fixed, ptr %v, align 16 +// CHECK-AAPCS-NEXT: %2 = getelementptr inbounds nuw i8, ptr %v, i64 16 +// CHECK-AAPCS-NEXT: %cast.fixed2 = tail call <2 x double> @llvm.vector.extract.v2f64.nxv2f64( %.coerce1, i64 0) +// CHECK-AAPCS-NEXT: store <2 x double> %cast.fixed2, ptr %2, align 16 +// CHECK-AAPCS-NEXT: %3 = getelementptr inbounds nuw i8, ptr %v, i64 32 +// CHECK-AAPCS-NEXT: %cast.fixed4 = tail call <4 x float> @llvm.vector.extract.v4f32.nxv4f32( %.coerce3, i64 0) +// CHECK-AAPCS-NEXT: store <4 x float> %cast.fixed4, ptr %3, align 16 +// CHECK-AAPCS-NEXT: %4 = getelementptr inbounds nuw i8, ptr %v, i64 48 +// CHECK-AAPCS-NEXT: %cast.fixed6 = tail call <4 x float> @llvm.vector.extract.v4f32.nxv4f32( %.coerce5, i64 0) +// CHECK-AAPCS-NEXT: store <4 x float> %cast.fixed6, ptr %4, align 16 +// CHECK-AAPCS-NEXT: %5 = getelementptr inbounds nuw i8, ptr %v, i64 64 +// CHECK-AAPCS-NEXT: %cast.fixed8 = tail call <16 x i8> @llvm.vector.extract.v16i8.nxv16i8( %.coerce7, i64 0) +// CHECK-AAPCS-NEXT: store <16 x i8> %cast.fixed8, ptr %5, align 16 +// CHECK-AAPCS-NEXT: %6 = getelementptr inbounds nuw i8, ptr %v, i64 80 +// CHECK-AAPCS-NEXT: %.coerce9 = bitcast %1 to +// CHECK-AAPCS-NEXT: %cast.fixed10 = tail call <2 x i8> @llvm.vector.extract.v2i8.nxv2i8( %.coerce9, i64 0) +// CHECK-AAPCS-NEXT: store <2 x i8> %cast.fixed10, ptr %6, align 16 +// CHECK-AAPCS-NEXT: call void @use(ptr noundef nonnull %v) +// CHECK-AAPCS-NEXT: ret void +// CHECK-AAPCS-NEXT: } + +// Test va_arg operation +#ifdef __cplusplus + extern "C" +#endif +void test_va_arg(int n, ...) { + va_list ap; + va_start(ap, n); + PST v = va_arg(ap, PST); + va_end(ap); + + void use1(bvec, fvec32); + use1(v.a, v.y[1]); +} +// CHECK-AAPCS: define dso_local void @test_va_arg(i32 noundef %n, ...) +// CHECK-AAPCS-NEXT: entry: +// CHECK-AAPCS-NEXT: %ap = alloca %struct.__va_list, align 8 +// CHECK-AAPCS-NEXT: call void @llvm.lifetime.start.p0(i64 32, ptr nonnull %ap) +// CHECK-AAPCS-NEXT: call void @llvm.va_start.p0(ptr nonnull %ap) +// CHECK-AAPCS-NEXT: %gr_offs_p = getelementptr inbounds nuw i8, ptr %ap, i64 24 +// CHECK-AAPCS-NEXT: %gr_offs = load i32, ptr %gr_offs_p, align 8 +// CHECK-AAPCS-NEXT: %0 = icmp sgt i32 %gr_offs, -1 +// CHECK-AAPCS-NEXT: br i1 %0, label %vaarg.on_stack, label %vaarg.maybe_reg +// CHECK-AAPCS-EMPTY: +// CHECK-AAPCS-NEXT: vaarg.maybe_reg: ; preds = %entry + +// Increment by 8, size of the pointer to the argument value, not size of the argument value itself. + +// CHECK-AAPCS-NEXT: %new_reg_offs = add nsw i32 %gr_offs, 8 +// CHECK-AAPCS-NEXT: store i32 %new_reg_offs, ptr %gr_offs_p, align 8 +// CHECK-AAPCS-NEXT: %inreg = icmp ult i32 %gr_offs, -7 +// CHECK-AAPCS-NEXT: br i1 %inreg, label %vaarg.in_reg, label %vaarg.on_stack +// CHECK-AAPCS-EMPTY: +// CHECK-AAPCS-NEXT: vaarg.in_reg: ; preds = %vaarg.maybe_reg +// CHECK-AAPCS-NEXT: %reg_top_p = getelementptr inbounds nuw i8, ptr %ap, i64 8 +// CHECK-AAPCS-NEXT: %reg_top = load ptr, ptr %reg_top_p, align 8 +// CHECK-AAPCS-NEXT: %1 = sext i32 %gr_offs to i64 +// CHECK-AAPCS-NEXT: %2 = getelementptr inbounds i8, ptr %reg_top, i64 %1 +// CHECK-AAPCS-NEXT: br label %vaarg.end +// CHECK-AAPCS-EMPTY: +// CHECK-AAPCS-NEXT: vaarg.on_stack: ; preds = %vaarg.maybe_reg, %entry +// CHECK-AAPCS-NEXT: %stack = load ptr, ptr %ap, align 8 +// CHECK-AAPCS-NEXT: %new_stack = getelementptr inbounds i8, ptr %stack, i64 8 +// CHECK-AAPCS-NEXT: store ptr %new_stack, ptr %ap, align 8 +// CHECK-AAPCS-NEXT: br label %vaarg.end +// CHECK-AAPCS-EMPTY: +// CHECK-AAPCS-NEXT: vaarg.end: ; preds = %vaarg.on_stack, %vaarg.in_reg +// CHECK-AAPCS-NEXT: %vaargs.addr = phi ptr [ %2, %vaarg.in_reg ], [ %stack, %vaarg.on_stack ] + +// Extra indirection, for a composite passed indirectly. +// CHECK-AAPCS-NEXT: %vaarg.addr = load ptr, ptr %vaargs.addr, align 8 + +// CHECK-AAPCS-NEXT: %v.sroa.0.0.copyload = load <2 x i8>, ptr %vaarg.addr, align 16 +// CHECK-AAPCS-NEXT: %v.sroa.43.0.vaarg.addr.sroa_idx = getelementptr inbounds i8, ptr %vaarg.addr, i64 48 +// CHECK-AAPCS-NEXT: %v.sroa.43.0.copyload = load <4 x float>, ptr %v.sroa.43.0.vaarg.addr.sroa_idx, align 16 +// CHECK-AAPCS-NEXT: call void @llvm.va_end.p0(ptr nonnull %ap) +// CHECK-AAPCS-NEXT: %cast.scalable = call @llvm.vector.insert.nxv2i8.v2i8( undef, <2 x i8> %v.sroa.0.0.copyload, i64 0) +// CHECK-AAPCS-NEXT: %3 = bitcast %cast.scalable to +// CHECK-AAPCS-NEXT: %cast.scalable2 = call @llvm.vector.insert.nxv4f32.v4f32( undef, <4 x float> %v.sroa.43.0.copyload, i64 0) +// CHECK-AAPCS-NEXT: call void @use1( noundef %3, noundef %cast.scalable2) +// CHECK-AAPCS-NEXT: call void @llvm.lifetime.end.p0(i64 32, ptr nonnull %ap) +// CHECK-AAPCS-NEXT: ret void +// CHECK-AAPCS-NEXT: } + +// CHECK-DARWIN: define void @test_va_arg(i32 noundef %n, ...) +// CHECK-DARWIN-NEXT: entry: +// CHECK-DARWIN-NEXT: %ap = alloca ptr, align 8 +// CHECK-DARWIN-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr nonnull %ap) +// CHECK-DARWIN-NEXT: call void @llvm.va_start.p0(ptr nonnull %ap) +// CHECK-DARWIN-NEXT: %argp.cur = load ptr, ptr %ap, align 8 +// CHECK-DARWIN-NEXT: %argp.next = getelementptr inbounds i8, ptr %argp.cur, i64 8 +// CHECK-DARWIN-NEXT: store ptr %argp.next, ptr %ap, align 8 +// CHECK-DARWIN-NEXT: %0 = load ptr, ptr %argp.cur, align 8 +// CHECK-DARWIN-NEXT: %v.sroa.0.0.copyload = load <2 x i8>, ptr %0, align 16 +// CHECK-DARWIN-NEXT: %v.sroa.43.0..sroa_idx = getelementptr inbounds i8, ptr %0, i64 48 +// CHECK-DARWIN-NEXT: %v.sroa.43.0.copyload = load <4 x float>, ptr %v.sroa.43.0..sroa_idx, align 16 +// CHECK-DARWIN-NEXT: call void @llvm.va_end.p0(ptr nonnull %ap) +// CHECK-DARWIN-NEXT: %cast.scalable = call @llvm.vector.insert.nxv2i8.v2i8( undef, <2 x i8> %v.sroa.0.0.copyload, i64 0) +// CHECK-DARWIN-NEXT: %1 = bitcast %cast.scalable to +// CHECK-DARWIN-NEXT: %cast.scalable2 = call @llvm.vector.insert.nxv4f32.v4f32( undef, <4 x float> %v.sroa.43.0.copyload, i64 0) +// CHECK-DARWIN-NEXT: call void @use1( noundef %1, noundef %cast.scalable2) +// CHECK-DARWIN-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr nonnull %ap) +// CHECK-DARWIN-NEXT: ret void +// CHECK-DARWIN-NEXT: } diff --git a/clang/test/CodeGen/amdgpu-barrier-type-debug-info.c b/clang/test/CodeGen/amdgpu-barrier-type-debug-info.c new file mode 100644 index 0000000000000000000000000000000000000000..f595f1b222c4f657879efea08cd3f162335ecfa9 --- /dev/null +++ b/clang/test/CodeGen/amdgpu-barrier-type-debug-info.c @@ -0,0 +1,8 @@ +// REQUIRES: amdgpu-registered-target +// RUN: %clang_cc1 -triple amdgcn -emit-llvm -o - %s -debug-info-kind=limited 2>&1 | FileCheck %s + +// CHECK: name: "__amdgpu_named_workgroup_barrier_t",{{.*}}baseType: ![[BT:[0-9]+]] +// CHECK: [[BT]] = !DIBasicType(name: "__amdgpu_named_workgroup_barrier_t", size: 128, encoding: DW_ATE_unsigned) +void test_locals(void) { + __amdgpu_named_workgroup_barrier_t k0; +} diff --git a/clang/test/CodeGen/arm-mfp8.c b/clang/test/CodeGen/arm-mfp8.c index 35ec24c8a7880db7fb2c7a2975f5ec118e29f50f..8c817fd5be1c9bedc9a9e995e2c1d9c06b60c333 100644 --- a/clang/test/CodeGen/arm-mfp8.c +++ b/clang/test/CodeGen/arm-mfp8.c @@ -47,5 +47,39 @@ mfloat8x8_t test_ret_mfloat8x8_t(mfloat8x8_t v) { return v; } +// CHECK-C-LABEL: define dso_local <1 x i8> @func1n( +// CHECK-C-SAME: <1 x i8> [[MFP8:%.*]]) #[[ATTR0]] { +// CHECK-C-NEXT: [[ENTRY:.*:]] +// CHECK-C-NEXT: [[MFP8_ADDR:%.*]] = alloca <1 x i8>, align 1 +// CHECK-C-NEXT: [[F1N:%.*]] = alloca [10 x <1 x i8>], align 1 +// CHECK-C-NEXT: store <1 x i8> [[MFP8]], ptr [[MFP8_ADDR]], align 1 +// CHECK-C-NEXT: [[TMP0:%.*]] = load <1 x i8>, ptr [[MFP8_ADDR]], align 1 +// CHECK-C-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x <1 x i8>], ptr [[F1N]], i64 0, i64 2 +// CHECK-C-NEXT: store <1 x i8> [[TMP0]], ptr [[ARRAYIDX]], align 1 +// CHECK-C-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [10 x <1 x i8>], ptr [[F1N]], i64 0, i64 2 +// CHECK-C-NEXT: [[TMP1:%.*]] = load <1 x i8>, ptr [[ARRAYIDX1]], align 1 +// CHECK-C-NEXT: ret <1 x i8> [[TMP1]] +// +// CHECK-CXX-LABEL: define dso_local <1 x i8> @_Z6func1nu11__MFloat8_t( +// CHECK-CXX-SAME: <1 x i8> [[MFP8:%.*]]) #[[ATTR0]] { +// CHECK-CXX-NEXT: [[ENTRY:.*:]] +// CHECK-CXX-NEXT: [[MFP8_ADDR:%.*]] = alloca <1 x i8>, align 1 +// CHECK-CXX-NEXT: [[F1N:%.*]] = alloca [10 x <1 x i8>], align 1 +// CHECK-CXX-NEXT: store <1 x i8> [[MFP8]], ptr [[MFP8_ADDR]], align 1 +// CHECK-CXX-NEXT: [[TMP0:%.*]] = load <1 x i8>, ptr [[MFP8_ADDR]], align 1 +// CHECK-CXX-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x <1 x i8>], ptr [[F1N]], i64 0, i64 2 +// CHECK-CXX-NEXT: store <1 x i8> [[TMP0]], ptr [[ARRAYIDX]], align 1 +// CHECK-CXX-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds [10 x <1 x i8>], ptr [[F1N]], i64 0, i64 2 +// CHECK-CXX-NEXT: [[TMP1:%.*]] = load <1 x i8>, ptr [[ARRAYIDX1]], align 1 +// CHECK-CXX-NEXT: ret <1 x i8> [[TMP1]] +// +__mfp8 func1n(__mfp8 mfp8) { + __mfp8 f1n[10]; + f1n[2] = mfp8; + return f1n[2]; +} + + + //// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: // CHECK: {{.*}} diff --git a/clang/test/CodeGen/builtins-nvptx-native-half-type-native.c b/clang/test/CodeGen/builtins-nvptx-native-half-type-native.c index b594fc876d4b9eb7443445153b11be2c946780b9..035c4c6066be2470176223bc8af7859a175248e6 100644 --- a/clang/test/CodeGen/builtins-nvptx-native-half-type-native.c +++ b/clang/test/CodeGen/builtins-nvptx-native-half-type-native.c @@ -52,8 +52,8 @@ typedef __fp16 __fp16v2 __attribute__((ext_vector_type(2))); // CHECK: call <2 x half> @llvm.nvvm.fmax.ftz.xorsign.abs.f16x2(<2 x half> {{.*}}, <2 x half> {{.*}}) // CHECK: call <2 x half> @llvm.nvvm.fmax.nan.xorsign.abs.f16x2(<2 x half> {{.*}}, <2 x half> {{.*}}) // CHECK: call <2 x half> @llvm.nvvm.fmax.ftz.nan.xorsign.abs.f16x2(<2 x half> {{.*}}, <2 x half> {{.*}}) -// CHECK: call half @llvm.nvvm.ldg.global.f.f16.p0(ptr {{.*}}, i32 2) -// CHECK: call <2 x half> @llvm.nvvm.ldg.global.f.v2f16.p0(ptr {{.*}}, i32 4) +// CHECK: load half, ptr addrspace(1) {{.*}}, align 2, !invariant.load +// CHECK: load <2 x half>, ptr addrspace(1) {{.*}}, align 4, !invariant.load // CHECK: call half @llvm.nvvm.ldu.global.f.f16.p0(ptr {{.*}}, i32 2) // CHECK: call <2 x half> @llvm.nvvm.ldu.global.f.v2f16.p0(ptr {{.*}}, i32 4) __device__ void nvvm_native_half_types(void *a, void*b, void*c, __fp16* out) { diff --git a/clang/test/CodeGen/builtins-nvptx-native-half-type.c b/clang/test/CodeGen/builtins-nvptx-native-half-type.c index 4aeae953bc1622c245f1b25cf67b30d0f41da39c..511497702ff7f9e1ce7ba76235f68c2ad12caefd 100644 --- a/clang/test/CodeGen/builtins-nvptx-native-half-type.c +++ b/clang/test/CodeGen/builtins-nvptx-native-half-type.c @@ -177,9 +177,9 @@ typedef __fp16 __fp16v2 __attribute__((ext_vector_type(2))); // CHECK-LABEL: nvvm_ldg_native_half_types __device__ void nvvm_ldg_native_half_types(const void *p) { - // CHECK: call half @llvm.nvvm.ldg.global.f.f16.p0 + // CHECK: load half, ptr addrspace(1) {{.*}}, align 2, !invariant.load __nvvm_ldg_h((const __fp16 *)p); - // CHECK: call <2 x half> @llvm.nvvm.ldg.global.f.v2f16.p0 + // CHECK: load <2 x half>, ptr addrspace(1) {{.*}}, align 4, !invariant.load __nvvm_ldg_h2((const __fp16v2 *)p); } diff --git a/clang/test/CodeGen/builtins-nvptx.c b/clang/test/CodeGen/builtins-nvptx.c index 0d0e3ecdb90c9e48cf05a30b2103e02456d5a57d..3406cbdde2bf8803f6597b219e6f75f4a139db1d 100644 --- a/clang/test/CodeGen/builtins-nvptx.c +++ b/clang/test/CodeGen/builtins-nvptx.c @@ -598,33 +598,33 @@ __device__ void nvvm_atom(float *fp, float f, double *dfp, double df, // CHECK-LABEL: nvvm_ldg __device__ void nvvm_ldg(const void *p) { - // CHECK: call i8 @llvm.nvvm.ldg.global.i.i8.p0(ptr {{%[0-9]+}}, i32 1) - // CHECK: call i8 @llvm.nvvm.ldg.global.i.i8.p0(ptr {{%[0-9]+}}, i32 1) - // CHECK: call i8 @llvm.nvvm.ldg.global.i.i8.p0(ptr {{%[0-9]+}}, i32 1) + // CHECK: load i8, ptr addrspace(1) {{%[0-9]+}}, align 1, !invariant.load + // CHECK: load i8, ptr addrspace(1) {{%[0-9]+}}, align 1, !invariant.load + // CHECK: load i8, ptr addrspace(1) {{%[0-9]+}}, align 1, !invariant.load __nvvm_ldg_c((const char *)p); __nvvm_ldg_uc((const unsigned char *)p); __nvvm_ldg_sc((const signed char *)p); - // CHECK: call i16 @llvm.nvvm.ldg.global.i.i16.p0(ptr {{%[0-9]+}}, i32 2) - // CHECK: call i16 @llvm.nvvm.ldg.global.i.i16.p0(ptr {{%[0-9]+}}, i32 2) + // CHECK: load i16, ptr addrspace(1) {{%[0-9]+}}, align 2, !invariant.load + // CHECK: load i16, ptr addrspace(1) {{%[0-9]+}}, align 2, !invariant.load __nvvm_ldg_s((const short *)p); __nvvm_ldg_us((const unsigned short *)p); - // CHECK: call i32 @llvm.nvvm.ldg.global.i.i32.p0(ptr {{%[0-9]+}}, i32 4) - // CHECK: call i32 @llvm.nvvm.ldg.global.i.i32.p0(ptr {{%[0-9]+}}, i32 4) + // CHECK: load i32, ptr addrspace(1) {{%[0-9]+}}, align 4, !invariant.load + // CHECK: load i32, ptr addrspace(1) {{%[0-9]+}}, align 4, !invariant.load __nvvm_ldg_i((const int *)p); __nvvm_ldg_ui((const unsigned int *)p); - // LP32: call i32 @llvm.nvvm.ldg.global.i.i32.p0(ptr {{%[0-9]+}}, i32 4) - // LP32: call i32 @llvm.nvvm.ldg.global.i.i32.p0(ptr {{%[0-9]+}}, i32 4) - // LP64: call i64 @llvm.nvvm.ldg.global.i.i64.p0(ptr {{%[0-9]+}}, i32 8) - // LP64: call i64 @llvm.nvvm.ldg.global.i.i64.p0(ptr {{%[0-9]+}}, i32 8) + // LP32: load i32, ptr addrspace(1) {{%[0-9]+}}, align 4, !invariant.load + // LP32: load i32, ptr addrspace(1) {{%[0-9]+}}, align 4, !invariant.load + // LP64: load i64, ptr addrspace(1) {{%[0-9]+}}, align 8, !invariant.load + // LP64: load i64, ptr addrspace(1) {{%[0-9]+}}, align 8, !invariant.load __nvvm_ldg_l((const long *)p); __nvvm_ldg_ul((const unsigned long *)p); - // CHECK: call float @llvm.nvvm.ldg.global.f.f32.p0(ptr {{%[0-9]+}}, i32 4) + // CHECK: load float, ptr addrspace(1) {{%[0-9]+}}, align 4, !invariant.load __nvvm_ldg_f((const float *)p); - // CHECK: call double @llvm.nvvm.ldg.global.f.f64.p0(ptr {{%[0-9]+}}, i32 8) + // CHECK: load double, ptr addrspace(1) {{%[0-9]+}}, align 8, !invariant.load __nvvm_ldg_d((const double *)p); // In practice, the pointers we pass to __ldg will be aligned as appropriate @@ -636,9 +636,9 @@ __device__ void nvvm_ldg(const void *p) { // elements, its alignment is set to number of elements times the alignment of // its member: n*alignof(t)." - // CHECK: call <2 x i8> @llvm.nvvm.ldg.global.i.v2i8.p0(ptr {{%[0-9]+}}, i32 2) - // CHECK: call <2 x i8> @llvm.nvvm.ldg.global.i.v2i8.p0(ptr {{%[0-9]+}}, i32 2) - // CHECK: call <2 x i8> @llvm.nvvm.ldg.global.i.v2i8.p0(ptr {{%[0-9]+}}, i32 2) + // CHECK: load <2 x i8>, ptr addrspace(1) {{%[0-9]+}}, align 2, !invariant.load + // CHECK: load <2 x i8>, ptr addrspace(1) {{%[0-9]+}}, align 2, !invariant.load + // CHECK: load <2 x i8>, ptr addrspace(1) {{%[0-9]+}}, align 2, !invariant.load typedef char char2 __attribute__((ext_vector_type(2))); typedef unsigned char uchar2 __attribute__((ext_vector_type(2))); typedef signed char schar2 __attribute__((ext_vector_type(2))); @@ -646,9 +646,9 @@ __device__ void nvvm_ldg(const void *p) { __nvvm_ldg_uc2((const uchar2 *)p); __nvvm_ldg_sc2((const schar2 *)p); - // CHECK: call <4 x i8> @llvm.nvvm.ldg.global.i.v4i8.p0(ptr {{%[0-9]+}}, i32 4) - // CHECK: call <4 x i8> @llvm.nvvm.ldg.global.i.v4i8.p0(ptr {{%[0-9]+}}, i32 4) - // CHECK: call <4 x i8> @llvm.nvvm.ldg.global.i.v4i8.p0(ptr {{%[0-9]+}}, i32 4) + // CHECK: load <4 x i8>, ptr addrspace(1) {{%[0-9]+}}, align 4, !invariant.load + // CHECK: load <4 x i8>, ptr addrspace(1) {{%[0-9]+}}, align 4, !invariant.load + // CHECK: load <4 x i8>, ptr addrspace(1) {{%[0-9]+}}, align 4, !invariant.load typedef char char4 __attribute__((ext_vector_type(4))); typedef unsigned char uchar4 __attribute__((ext_vector_type(4))); typedef signed char schar4 __attribute__((ext_vector_type(4))); @@ -656,59 +656,59 @@ __device__ void nvvm_ldg(const void *p) { __nvvm_ldg_uc4((const uchar4 *)p); __nvvm_ldg_sc4((const schar4 *)p); - // CHECK: call <2 x i16> @llvm.nvvm.ldg.global.i.v2i16.p0(ptr {{%[0-9]+}}, i32 4) - // CHECK: call <2 x i16> @llvm.nvvm.ldg.global.i.v2i16.p0(ptr {{%[0-9]+}}, i32 4) + // CHECK: load <2 x i16>, ptr addrspace(1) {{%[0-9]+}}, align 4, !invariant.load + // CHECK: load <2 x i16>, ptr addrspace(1) {{%[0-9]+}}, align 4, !invariant.load typedef short short2 __attribute__((ext_vector_type(2))); typedef unsigned short ushort2 __attribute__((ext_vector_type(2))); __nvvm_ldg_s2((const short2 *)p); __nvvm_ldg_us2((const ushort2 *)p); - // CHECK: call <4 x i16> @llvm.nvvm.ldg.global.i.v4i16.p0(ptr {{%[0-9]+}}, i32 8) - // CHECK: call <4 x i16> @llvm.nvvm.ldg.global.i.v4i16.p0(ptr {{%[0-9]+}}, i32 8) + // CHECK: load <4 x i16>, ptr addrspace(1) {{%[0-9]+}}, align 8, !invariant.load + // CHECK: load <4 x i16>, ptr addrspace(1) {{%[0-9]+}}, align 8, !invariant.load typedef short short4 __attribute__((ext_vector_type(4))); typedef unsigned short ushort4 __attribute__((ext_vector_type(4))); __nvvm_ldg_s4((const short4 *)p); __nvvm_ldg_us4((const ushort4 *)p); - // CHECK: call <2 x i32> @llvm.nvvm.ldg.global.i.v2i32.p0(ptr {{%[0-9]+}}, i32 8) - // CHECK: call <2 x i32> @llvm.nvvm.ldg.global.i.v2i32.p0(ptr {{%[0-9]+}}, i32 8) + // CHECK: load <2 x i32>, ptr addrspace(1) {{%[0-9]+}}, align 8, !invariant.load + // CHECK: load <2 x i32>, ptr addrspace(1) {{%[0-9]+}}, align 8, !invariant.load typedef int int2 __attribute__((ext_vector_type(2))); typedef unsigned int uint2 __attribute__((ext_vector_type(2))); __nvvm_ldg_i2((const int2 *)p); __nvvm_ldg_ui2((const uint2 *)p); - // CHECK: call <4 x i32> @llvm.nvvm.ldg.global.i.v4i32.p0(ptr {{%[0-9]+}}, i32 16) - // CHECK: call <4 x i32> @llvm.nvvm.ldg.global.i.v4i32.p0(ptr {{%[0-9]+}}, i32 16) + // CHECK: load <4 x i32>, ptr addrspace(1) {{%[0-9]+}}, align 16, !invariant.load + // CHECK: load <4 x i32>, ptr addrspace(1) {{%[0-9]+}}, align 16, !invariant.load typedef int int4 __attribute__((ext_vector_type(4))); typedef unsigned int uint4 __attribute__((ext_vector_type(4))); __nvvm_ldg_i4((const int4 *)p); __nvvm_ldg_ui4((const uint4 *)p); - // LP32: call <2 x i32> @llvm.nvvm.ldg.global.i.v2i32.p0(ptr {{%[0-9]+}}, i32 8) - // LP32: call <2 x i32> @llvm.nvvm.ldg.global.i.v2i32.p0(ptr {{%[0-9]+}}, i32 8) - // LP64: call <2 x i64> @llvm.nvvm.ldg.global.i.v2i64.p0(ptr {{%[0-9]+}}, i32 16) - // LP64: call <2 x i64> @llvm.nvvm.ldg.global.i.v2i64.p0(ptr {{%[0-9]+}}, i32 16) + // LP32: load <2 x i32>, ptr addrspace(1) {{%[0-9]+}}, align 8, !invariant.load + // LP32: load <2 x i32>, ptr addrspace(1) {{%[0-9]+}}, align 8, !invariant.load + // LP64: load <2 x i64>, ptr addrspace(1) {{%[0-9]+}}, align 16, !invariant.load + // LP64: load <2 x i64>, ptr addrspace(1) {{%[0-9]+}}, align 16, !invariant.load typedef long long2 __attribute__((ext_vector_type(2))); typedef unsigned long ulong2 __attribute__((ext_vector_type(2))); __nvvm_ldg_l2((const long2 *)p); __nvvm_ldg_ul2((const ulong2 *)p); - // CHECK: call <2 x i64> @llvm.nvvm.ldg.global.i.v2i64.p0(ptr {{%[0-9]+}}, i32 16) - // CHECK: call <2 x i64> @llvm.nvvm.ldg.global.i.v2i64.p0(ptr {{%[0-9]+}}, i32 16) + // CHECK: load <2 x i64>, ptr addrspace(1) {{%[0-9]+}}, align 16, !invariant.load + // CHECK: load <2 x i64>, ptr addrspace(1) {{%[0-9]+}}, align 16, !invariant.load typedef long long longlong2 __attribute__((ext_vector_type(2))); typedef unsigned long long ulonglong2 __attribute__((ext_vector_type(2))); __nvvm_ldg_ll2((const longlong2 *)p); __nvvm_ldg_ull2((const ulonglong2 *)p); - // CHECK: call <2 x float> @llvm.nvvm.ldg.global.f.v2f32.p0(ptr {{%[0-9]+}}, i32 8) + // CHECK: load <2 x float>, ptr addrspace(1) {{%[0-9]+}}, align 8, !invariant.load typedef float float2 __attribute__((ext_vector_type(2))); __nvvm_ldg_f2((const float2 *)p); - // CHECK: call <4 x float> @llvm.nvvm.ldg.global.f.v4f32.p0(ptr {{%[0-9]+}}, i32 16) + // CHECK: load <4 x float>, ptr addrspace(1) {{%[0-9]+}}, align 16, !invariant.load typedef float float4 __attribute__((ext_vector_type(4))); __nvvm_ldg_f4((const float4 *)p); - // CHECK: call <2 x double> @llvm.nvvm.ldg.global.f.v2f64.p0(ptr {{%[0-9]+}}, i32 16) + // CHECK: load <2 x double>, ptr addrspace(1) {{%[0-9]+}}, align 16, !invariant.load typedef double double2 __attribute__((ext_vector_type(2))); __nvvm_ldg_d2((const double2 *)p); } diff --git a/clang/test/CodeGen/debug-info-renderscript-tag.rs b/clang/test/CodeGen/debug-info-renderscript-tag.rs deleted file mode 100644 index ded650d9660b8b419afe295938a6c17f538ec181..0000000000000000000000000000000000000000 --- a/clang/test/CodeGen/debug-info-renderscript-tag.rs +++ /dev/null @@ -1,3 +0,0 @@ -// RUN: %clang -emit-llvm -S -g %s -o - | FileCheck %s - -// CHECK: !DICompileUnit(language: DW_LANG_GOOGLE_RenderScript{{.*}}) diff --git a/clang/test/CodeGen/fp16-ops.c b/clang/test/CodeGen/fp16-ops.c index bfa2a2f7f6c8267a6049ede3979d4ce72f3d4787..4c206690a7518e8a36d58e41a4fbcfc7c4394194 100644 --- a/clang/test/CodeGen/fp16-ops.c +++ b/clang/test/CodeGen/fp16-ops.c @@ -6,8 +6,6 @@ // RUN: | FileCheck %s --check-prefix=NATIVE-HALF // RUN: %clang_cc1 -emit-llvm -o - -triple aarch64 -fnative-half-type %s \ // RUN: | FileCheck %s --check-prefix=NATIVE-HALF -// RUN: %clang_cc1 -emit-llvm -o - -x renderscript %s \ -// RUN: | FileCheck %s --check-prefix=NATIVE-HALF typedef unsigned cond_t; typedef __fp16 float16_t; diff --git a/clang/test/CodeGen/musttail-sret.cpp b/clang/test/CodeGen/musttail-sret.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca67c218cd67f67e6bc85ddf096e941e0c224fe4 --- /dev/null +++ b/clang/test/CodeGen/musttail-sret.cpp @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -triple=arm %s -emit-llvm -O3 -o - | FileCheck %s --check-prefix=CHECK-ARM +// RUN: %clang_cc1 -triple=arm64 %s -emit-llvm -O3 -o - | FileCheck %s --check-prefix=CHECK-ARM64 +// RUN: %clang_cc1 -triple=i686 %s -emit-llvm -O3 -o - | FileCheck %s --check-prefix=CHECK-X86 +// RUN: %clang_cc1 -triple=x86_64 %s -emit-llvm -O3 -o - | FileCheck %s --check-prefix=CHECK-X64 + +// Sret tests +struct Big { + int a, b, c, d, e, f, g, h; +}; + +struct Big F1(signed short P0); + +struct Big F2(signed short P0) { + signed short P1 = 20391; + [[clang::musttail]] return F1(P1); +} + +// CHECK-NOT: alloca +// CHECK-ARM: musttail call arm_aapcscc void @_Z2F1s(ptr dead_on_unwind writable sret(%struct.Big) align 4 %agg.result, i16 noundef signext 20391) +// CHECK-ARM64: musttail call void @_Z2F1s(ptr dead_on_unwind writable sret(%struct.Big) align 4 %agg.result, i16 noundef 20391) +// CHECK-X86: musttail call void @_Z2F1s(ptr dead_on_unwind writable sret(%struct.Big) align 4 %agg.result, i16 noundef signext 20391) +// CHECK-X64: musttail call void @_Z2F1s(ptr dead_on_unwind writable sret(%struct.Big) align 4 %agg.result, i16 noundef signext 20391) + +struct ReallyBig { + int a[100]; +}; + +// Indirect sret tests +// Function pointer for testing indirect musttail call. +struct FunctionPointers { + ReallyBig (*F3)(int, int, int, int, float, double); + ReallyBig (*F4)(int, int, int, char, float, double); +}; + +struct ReallyBig F3(int P0, int P1, int P2, int P3, float P4, double P5); +struct ReallyBig F4(int P0, int P1, int P2, char P3, float P4, double P5); + +static struct FunctionPointers FP = {F3, F4}; + +struct ReallyBig F5 (int P0, int P1, int P2, int P3, float P4, double P5) { + [[clang::musttail]] return FP.F3(P0, P1, P2, P3, P4, P5); +} + +// CHECK-NOT: alloca +// CHECK-ARM: musttail call arm_aapcscc void @_Z2F3iiiifd(ptr dead_on_unwind writable sret(%struct.ReallyBig) align 4 %agg.result, i32 noundef %P0, i32 noundef %P1, i32 noundef %P2, i32 noundef %P3, float noundef %P4, double noundef %P5) +// CHECK-ARM64: musttail call void @_Z2F3iiiifd(ptr dead_on_unwind writable sret(%struct.ReallyBig) align 4 %agg.result, i32 noundef %P0, i32 noundef %P1, i32 noundef %P2, i32 noundef %P3, float noundef %P4, double noundef %P5) +// CHECK-X86: musttail call void @_Z2F3iiiifd(ptr dead_on_unwind writable sret(%struct.ReallyBig) align 4 %agg.result, i32 noundef %P0, i32 noundef %P1, i32 noundef %P2, i32 noundef %P3, float noundef %P4, double noundef %P5) +// CHECK-X64: musttail call void @_Z2F3iiiifd(ptr dead_on_unwind writable sret(%struct.ReallyBig) align 4 %agg.result, i32 noundef %P0, i32 noundef %P1, i32 noundef %P2, i32 noundef %P3, float noundef %P4, double noundef %P5) + +struct ReallyBig F6 (int P0, int P1, int P2, char P3, float P4, double P5) { + [[clang::musttail]] return FP.F4(P0, P1, P2, P3, P4, P5); +} + +// Complex and BitInt. Special cases for sret. +// CHECK-NOT: alloca +// CHECK-ARM: musttail call arm_aapcscc void @_Z2F4iiicfd(ptr dead_on_unwind writable sret(%struct.ReallyBig) align 4 %agg.result, i32 noundef %P0, i32 noundef %P1, i32 noundef %P2, i8 noundef signext %P3, float noundef %P4, double noundef %P5) +// CHECK-ARM64: musttail call void @_Z2F4iiicfd(ptr dead_on_unwind writable sret(%struct.ReallyBig) align 4 %agg.result, i32 noundef %P0, i32 noundef %P1, i32 noundef %P2, i8 noundef %P3, float noundef %P4, double noundef %P5) +// CHECK-X86: musttail call void @_Z2F4iiicfd(ptr dead_on_unwind writable sret(%struct.ReallyBig) align 4 %agg.result, i32 noundef %P0, i32 noundef %P1, i32 noundef %P2, i8 noundef signext %P3, float noundef %P4, double noundef %P5) +// CHECK-X64: musttail call void @_Z2F4iiicfd(ptr dead_on_unwind writable sret(%struct.ReallyBig) align 4 %agg.result, i32 noundef %P0, i32 noundef %P1, i32 noundef %P2, i8 noundef signext %P3, float noundef %P4, double noundef %P5) + +double _Complex F7(signed short P0); + +double _Complex F8(signed short P0) { + signed short P1 = 20391; + [[clang::musttail]] return F7(P1); +} + +// CHECK-NOT: alloca +// CHECK-ARM: musttail call arm_aapcscc void @_Z2F7s(ptr dead_on_unwind writable sret({ double, double }) align 8 %agg.result, i16 noundef signext 20391) +// CHECK-ARM64: musttail call noundef { double, double } @_Z2F7s(i16 noundef 20391) +// CHECK-X86: musttail call void @_Z2F7s(ptr dead_on_unwind writable sret({ double, double }) align 4 %agg.result, i16 noundef signext 20391) +// CHECK-X64: musttail call noundef { double, double } @_Z2F7s(i16 noundef signext 20391) + +signed _BitInt(100) F9(float P0, float P1, double P2, char P3); + +signed _BitInt(100) F10(float P0, float P1, double P2, char P3) { + [[clang::musttail]] return F9(P0, P1, P2, P3); +} + +// CHECK-NOT: alloca +// CHECK-ARM: musttail call arm_aapcscc void @_Z2F9ffdc(ptr dead_on_unwind writable sret(i128) align 8 %agg.result, float noundef %P0, float noundef %P1, double noundef %P2, i8 noundef signext %P3) +// CHECK-ARM64: musttail call noundef i100 @_Z2F9ffdc(float noundef %P0, float noundef %P1, double noundef %P2, i8 noundef %P3) +// CHECK-X86: musttail call void @_Z2F9ffdc(ptr dead_on_unwind writable sret(i128) align 4 %agg.result, float noundef %P0, float noundef %P1, double noundef %P2, i8 noundef signext %P3) +// CHECK-X64: musttail call noundef { i64, i64 } @_Z2F9ffdc(float noundef %P0, float noundef %P1, double noundef %P2, i8 noundef signext %P3) \ No newline at end of file diff --git a/clang/test/CodeGen/pgo-cold-function-coverage.c b/clang/test/CodeGen/pgo-cold-function-coverage.c new file mode 100644 index 0000000000000000000000000000000000000000..fd1e1e7e14cda567ac5663eb7f08b06d65eed7b7 --- /dev/null +++ b/clang/test/CodeGen/pgo-cold-function-coverage.c @@ -0,0 +1,19 @@ +// Test -fprofile-generate-cold-function-coverage + +// RUN: rm -rf %t && split-file %s %t +// RUN: %clang -O2 -fprofile-generate-cold-function-coverage=/xxx/yyy/ -fprofile-sample-accurate -fprofile-sample-use=%t/pgo-cold-func.prof -S -emit-llvm -o - %t/pgo-cold-func.c | FileCheck %s + +// CHECK: @__llvm_profile_filename = {{.*}} c"/xxx/yyy/default_%m.profraw\00" + +// CHECK: store i8 0, ptr @__profc_bar, align 1 +// CHECK-NOT: @__profc_foo + +//--- pgo-cold-func.prof +foo:1:1 + 1: 1 + +//--- pgo-cold-func.c +int bar(int x) { return x;} +int foo(int x) { + return x; +} diff --git a/clang/test/CodeGen/renderscript.c b/clang/test/CodeGen/renderscript.c deleted file mode 100644 index 1629665c1ffb8746ead76e28267df186be890acb..0000000000000000000000000000000000000000 --- a/clang/test/CodeGen/renderscript.c +++ /dev/null @@ -1,140 +0,0 @@ -// RUN: %clang_cc1 %s -triple=renderscript32-none-linux-gnueabi -emit-llvm -o - -Werror | FileCheck %s -check-prefix=CHECK-RS32 -// RUN: %clang_cc1 %s -triple=renderscript64-none-linux-android -emit-llvm -o - -Werror | FileCheck %s -check-prefix=CHECK-RS64 -// RUN: %clang_cc1 %s -triple=armv7-none-linux-gnueabi -emit-llvm -o - -Werror | FileCheck %s -check-prefix=CHECK-ARM - -// Ensure that the bitcode has the correct triple -// CHECK-RS32: target triple = "armv7-none-linux-gnueabi" -// CHECK-RS64: target triple = "aarch64-none-linux-android" -// CHECK-ARM: target triple = "armv7-none-linux-gnueabi" - -// Ensure that long data type has 8-byte size and alignment in RenderScript -#ifdef __RENDERSCRIPT__ -#define LONG_WIDTH_AND_ALIGN 8 -#else -#define LONG_WIDTH_AND_ALIGN 4 -#endif - -_Static_assert(sizeof(long) == LONG_WIDTH_AND_ALIGN, "sizeof long is wrong"); -_Static_assert(_Alignof(long) == LONG_WIDTH_AND_ALIGN, "sizeof long is wrong"); - -// CHECK-RS32: i64 @test_long(i64 noundef %v) -// CHECK-RS64: i64 @test_long(i64 noundef %v) -// CHECK-ARM: i32 @test_long(i32 noundef %v) -long test_long(long v) { - return v + 1; -} - -// ============================================================================= -// Test coercion of aggregate argument or return value into integer arrays -// ============================================================================= - -// ============================================================================= -// aggregate parameter <= 4 bytes: coerced to [a x iNN] for both 32-bit and -// 64-bit RenderScript -// ============================================================================== - -typedef struct {char c1, c2, c3; } sChar3; -typedef struct {short s; char c;} sShortChar; - -// CHECK-RS32: void @argChar3([3 x i8] %s.coerce) -// CHECK-RS64: void @argChar3([3 x i8] %s.coerce) -void argChar3(sChar3 s) {} - -// CHECK-RS32: void @argShortChar([2 x i16] %s.coerce) -// CHECK-RS64: void @argShortChar([2 x i16] %s.coerce) -void argShortChar(sShortChar s) {} - -// ============================================================================= -// aggregate return value <= 4 bytes: coerced to [a x iNN] for both 32-bit and -// 64-bit RenderScript -// ============================================================================= - -// CHECK-RS32: [3 x i8] @retChar3() -// CHECK-RS64: [3 x i8] @retChar3() -sChar3 retChar3(void) { sChar3 r; return r; } - -// CHECK-RS32: [2 x i16] @retShortChar() -// CHECK-RS64: [2 x i16] @retShortChar() -sShortChar retShortChar(void) { sShortChar r; return r; } - -// ============================================================================= -// aggregate parameter <= 16 bytes: coerced to [a x iNN] for both 32-bit and -// 64-bit RenderScript -// ============================================================================= - -typedef struct {short s1; char c; short s2; } sShortCharShort; -typedef struct {int i; short s; char c; } sIntShortChar; -typedef struct {long l; int i; } sLongInt; - -// CHECK-RS32: void @argShortCharShort([3 x i16] %s.coerce) -// CHECK-RS64: void @argShortCharShort([3 x i16] %s.coerce) -void argShortCharShort(sShortCharShort s) {} - -// CHECK-RS32: void @argIntShortChar([2 x i32] %s.coerce) -// CHECK-RS64: void @argIntShortChar([2 x i32] %s.coerce) -void argIntShortChar(sIntShortChar s) {} - -// CHECK-RS32: void @argLongInt([2 x i64] %s.coerce) -// CHECK-RS64: void @argLongInt([2 x i64] %s.coerce) -void argLongInt(sLongInt s) {} - -// ============================================================================= -// aggregate return value <= 16 bytes: returned on stack for 32-bit RenderScript -// and coerced to [a x iNN] for 64-bit RenderScript -// ============================================================================= - -// CHECK-RS32: void @retShortCharShort(ptr dead_on_unwind noalias writable sret(%struct.sShortCharShort) align 2 %agg.result) -// CHECK-RS64: [3 x i16] @retShortCharShort() -sShortCharShort retShortCharShort(void) { sShortCharShort r; return r; } - -// CHECK-RS32: void @retIntShortChar(ptr dead_on_unwind noalias writable sret(%struct.sIntShortChar) align 4 %agg.result) -// CHECK-RS64: [2 x i32] @retIntShortChar() -sIntShortChar retIntShortChar(void) { sIntShortChar r; return r; } - -// CHECK-RS32: void @retLongInt(ptr dead_on_unwind noalias writable sret(%struct.sLongInt) align 8 %agg.result) -// CHECK-RS64: [2 x i64] @retLongInt() -sLongInt retLongInt(void) { sLongInt r; return r; } - -// ============================================================================= -// aggregate parameter <= 64 bytes: coerced to [a x iNN] for 32-bit RenderScript -// and passed on the stack for 64-bit RenderScript -// ============================================================================= - -typedef struct {int i1, i2, i3, i4, i5; } sInt5; -typedef struct {long l1, l2; char c; } sLong2Char; - -// CHECK-RS32: void @argInt5([5 x i32] %s.coerce) -// CHECK-RS64: void @argInt5(ptr noundef %s) -void argInt5(sInt5 s) {} - -// CHECK-RS32: void @argLong2Char([3 x i64] %s.coerce) -// CHECK-RS64: void @argLong2Char(ptr noundef %s) -void argLong2Char(sLong2Char s) {} - -// ============================================================================= -// aggregate return value <= 64 bytes: returned on stack for both 32-bit and -// 64-bit RenderScript -// ============================================================================= - -// CHECK-RS32: void @retInt5(ptr dead_on_unwind noalias writable sret(%struct.sInt5) align 4 %agg.result) -// CHECK-RS64: void @retInt5(ptr dead_on_unwind noalias writable sret(%struct.sInt5) align 4 %agg.result) -sInt5 retInt5(void) { sInt5 r; return r;} - -// CHECK-RS32: void @retLong2Char(ptr dead_on_unwind noalias writable sret(%struct.sLong2Char) align 8 %agg.result) -// CHECK-RS64: void @retLong2Char(ptr dead_on_unwind noalias writable sret(%struct.sLong2Char) align 8 %agg.result) -sLong2Char retLong2Char(void) { sLong2Char r; return r;} - -// ============================================================================= -// aggregate parameters and return values > 64 bytes: passed and returned on the -// stack for both 32-bit and 64-bit RenderScript -// ============================================================================= - -typedef struct {long l1, l2, l3, l4, l5, l6, l7, l8, l9; } sLong9; - -// CHECK-RS32: void @argLong9(ptr noundef byval(%struct.sLong9) align 8 %s) -// CHECK-RS64: void @argLong9(ptr noundef %s) -void argLong9(sLong9 s) {} - -// CHECK-RS32: void @retLong9(ptr dead_on_unwind noalias writable sret(%struct.sLong9) align 8 %agg.result) -// CHECK-RS64: void @retLong9(ptr dead_on_unwind noalias writable sret(%struct.sLong9) align 8 %agg.result) -sLong9 retLong9(void) { sLong9 r; return r; } diff --git a/clang/test/CodeGen/rtsan_attribute_inserted.c b/clang/test/CodeGen/rtsan_attribute_inserted.c index b21ecb6b6b06a902ba0a1c871401177da0500ca3..cebfe43c81234cf95a1ce3da834e28174ef15080 100644 --- a/clang/test/CodeGen/rtsan_attribute_inserted.c +++ b/clang/test/CodeGen/rtsan_attribute_inserted.c @@ -8,4 +8,4 @@ float process(float *a) [[clang::nonblocking]] { return *a; } int spinlock(int *a) [[clang::blocking]] { return *a; } // CHECK: @spinlock{{.*}} #1 { // CHECK: attributes #1 = { -// CHECK-SAME: {{.*sanitize_realtime_unsafe .*}} +// CHECK-SAME: {{.*sanitize_realtime_blocking .*}} diff --git a/clang/test/CodeGen/rtsan_no_attribute_sanitizer_disabled.c b/clang/test/CodeGen/rtsan_no_attribute_sanitizer_disabled.c index 0f43007c5e4c1614adf4c24a415e24555d1c7dcc..86305080c94acee50f931608fb03a7fa8a21a79d 100644 --- a/clang/test/CodeGen/rtsan_no_attribute_sanitizer_disabled.c +++ b/clang/test/CodeGen/rtsan_no_attribute_sanitizer_disabled.c @@ -5,4 +5,4 @@ int spinlock(int *a) [[clang::blocking]] { return *a; } // Without the -fsanitize=realtime flag, we shouldn't attach the attributes. // CHECK-NOT: {{.*sanitize_realtime .*}} -// CHECK-NOT: {{.*sanitize_realtime_unsafe .*}} +// CHECK-NOT: {{.*sanitize_realtime_blocking .*}} diff --git a/clang/test/CodeGen/target-builtin-noerror.c b/clang/test/CodeGen/target-builtin-noerror.c index 2a05074d7c2b68d3037d088c1cc675c0b4552508..1e53621bc6b5ae45ab7129ac90b127bed10b5279 100644 --- a/clang/test/CodeGen/target-builtin-noerror.c +++ b/clang/test/CodeGen/target-builtin-noerror.c @@ -145,6 +145,7 @@ void verifyfeaturestrings(void) { (void)__builtin_cpu_supports("avx10.1-512"); (void)__builtin_cpu_supports("avx10.2-256"); (void)__builtin_cpu_supports("avx10.2-512"); + (void)__builtin_cpu_supports("movrs"); } void verifycpustrings(void) { diff --git a/clang/test/CodeGenCUDA/offloading-entries.cu b/clang/test/CodeGenCUDA/offloading-entries.cu index ec21f018607ff012ebe082553c0658f337208126..259e3324e8ac94fea5922127a0dc27b027120551 100644 --- a/clang/test/CodeGenCUDA/offloading-entries.cu +++ b/clang/test/CodeGenCUDA/offloading-entries.cu @@ -15,48 +15,48 @@ #include "Inputs/cuda.h" //. -// CUDA: @.offloading.entry_name = internal unnamed_addr constant [8 x i8] c"_Z3foov\00" +// CUDA: @.offloading.entry_name = internal unnamed_addr constant [8 x i8] c"_Z3foov\00", section ".llvm.rodata.offloading", align 1 // CUDA: @.offloading.entry._Z3foov = weak constant %struct.__tgt_offload_entry { ptr @_Z18__device_stub__foov, ptr @.offloading.entry_name, i64 0, i32 0, i32 0 }, section "cuda_offloading_entries", align 1 -// CUDA: @.offloading.entry_name.1 = internal unnamed_addr constant [11 x i8] c"_Z6kernelv\00" +// CUDA: @.offloading.entry_name.1 = internal unnamed_addr constant [11 x i8] c"_Z6kernelv\00", section ".llvm.rodata.offloading", align 1 // CUDA: @.offloading.entry._Z6kernelv = weak constant %struct.__tgt_offload_entry { ptr @_Z21__device_stub__kernelv, ptr @.offloading.entry_name.1, i64 0, i32 0, i32 0 }, section "cuda_offloading_entries", align 1 -// CUDA: @.offloading.entry_name.2 = internal unnamed_addr constant [4 x i8] c"var\00" +// CUDA: @.offloading.entry_name.2 = internal unnamed_addr constant [4 x i8] c"var\00", section ".llvm.rodata.offloading", align 1 // CUDA: @.offloading.entry.var = weak constant %struct.__tgt_offload_entry { ptr @var, ptr @.offloading.entry_name.2, i64 4, i32 0, i32 0 }, section "cuda_offloading_entries", align 1 -// CUDA: @.offloading.entry_name.3 = internal unnamed_addr constant [5 x i8] c"surf\00" +// CUDA: @.offloading.entry_name.3 = internal unnamed_addr constant [5 x i8] c"surf\00", section ".llvm.rodata.offloading", align 1 // CUDA: @.offloading.entry.surf = weak constant %struct.__tgt_offload_entry { ptr @surf, ptr @.offloading.entry_name.3, i64 4, i32 2, i32 1 }, section "cuda_offloading_entries", align 1 -// CUDA: @.offloading.entry_name.4 = internal unnamed_addr constant [4 x i8] c"tex\00" +// CUDA: @.offloading.entry_name.4 = internal unnamed_addr constant [4 x i8] c"tex\00", section ".llvm.rodata.offloading", align 1 // CUDA: @.offloading.entry.tex = weak constant %struct.__tgt_offload_entry { ptr @tex, ptr @.offloading.entry_name.4, i64 4, i32 3, i32 1 }, section "cuda_offloading_entries", align 1 //. -// HIP: @.offloading.entry_name = internal unnamed_addr constant [8 x i8] c"_Z3foov\00" +// HIP: @.offloading.entry_name = internal unnamed_addr constant [8 x i8] c"_Z3foov\00", section ".llvm.rodata.offloading", align 1 // HIP: @.offloading.entry._Z3foov = weak constant %struct.__tgt_offload_entry { ptr @_Z3foov, ptr @.offloading.entry_name, i64 0, i32 0, i32 0 }, section "hip_offloading_entries", align 1 -// HIP: @.offloading.entry_name.1 = internal unnamed_addr constant [11 x i8] c"_Z6kernelv\00" +// HIP: @.offloading.entry_name.1 = internal unnamed_addr constant [11 x i8] c"_Z6kernelv\00", section ".llvm.rodata.offloading", align 1 // HIP: @.offloading.entry._Z6kernelv = weak constant %struct.__tgt_offload_entry { ptr @_Z6kernelv, ptr @.offloading.entry_name.1, i64 0, i32 0, i32 0 }, section "hip_offloading_entries", align 1 -// HIP: @.offloading.entry_name.2 = internal unnamed_addr constant [4 x i8] c"var\00" +// HIP: @.offloading.entry_name.2 = internal unnamed_addr constant [4 x i8] c"var\00", section ".llvm.rodata.offloading", align 1 // HIP: @.offloading.entry.var = weak constant %struct.__tgt_offload_entry { ptr @var, ptr @.offloading.entry_name.2, i64 4, i32 0, i32 0 }, section "hip_offloading_entries", align 1 -// HIP: @.offloading.entry_name.3 = internal unnamed_addr constant [5 x i8] c"surf\00" +// HIP: @.offloading.entry_name.3 = internal unnamed_addr constant [5 x i8] c"surf\00", section ".llvm.rodata.offloading", align 1 // HIP: @.offloading.entry.surf = weak constant %struct.__tgt_offload_entry { ptr @surf, ptr @.offloading.entry_name.3, i64 4, i32 2, i32 1 }, section "hip_offloading_entries", align 1 -// HIP: @.offloading.entry_name.4 = internal unnamed_addr constant [4 x i8] c"tex\00" +// HIP: @.offloading.entry_name.4 = internal unnamed_addr constant [4 x i8] c"tex\00", section ".llvm.rodata.offloading", align 1 // HIP: @.offloading.entry.tex = weak constant %struct.__tgt_offload_entry { ptr @tex, ptr @.offloading.entry_name.4, i64 4, i32 3, i32 1 }, section "hip_offloading_entries", align 1 //. -// CUDA-COFF: @.offloading.entry_name = internal unnamed_addr constant [8 x i8] c"_Z3foov\00" +// CUDA-COFF: @.offloading.entry_name = internal unnamed_addr constant [8 x i8] c"_Z3foov\00", section ".llvm.rodata.offloading", align 1 // CUDA-COFF: @.offloading.entry._Z3foov = weak constant %struct.__tgt_offload_entry { ptr @_Z18__device_stub__foov, ptr @.offloading.entry_name, i64 0, i32 0, i32 0 }, section "cuda_offloading_entries$OE", align 1 -// CUDA-COFF: @.offloading.entry_name.1 = internal unnamed_addr constant [11 x i8] c"_Z6kernelv\00" +// CUDA-COFF: @.offloading.entry_name.1 = internal unnamed_addr constant [11 x i8] c"_Z6kernelv\00", section ".llvm.rodata.offloading", align 1 // CUDA-COFF: @.offloading.entry._Z6kernelv = weak constant %struct.__tgt_offload_entry { ptr @_Z21__device_stub__kernelv, ptr @.offloading.entry_name.1, i64 0, i32 0, i32 0 }, section "cuda_offloading_entries$OE", align 1 -// CUDA-COFF: @.offloading.entry_name.2 = internal unnamed_addr constant [4 x i8] c"var\00" +// CUDA-COFF: @.offloading.entry_name.2 = internal unnamed_addr constant [4 x i8] c"var\00", section ".llvm.rodata.offloading", align 1 // CUDA-COFF: @.offloading.entry.var = weak constant %struct.__tgt_offload_entry { ptr @var, ptr @.offloading.entry_name.2, i64 4, i32 0, i32 0 }, section "cuda_offloading_entries$OE", align 1 -// CUDA-COFF: @.offloading.entry_name.3 = internal unnamed_addr constant [5 x i8] c"surf\00" +// CUDA-COFF: @.offloading.entry_name.3 = internal unnamed_addr constant [5 x i8] c"surf\00", section ".llvm.rodata.offloading", align 1 // CUDA-COFF: @.offloading.entry.surf = weak constant %struct.__tgt_offload_entry { ptr @surf, ptr @.offloading.entry_name.3, i64 4, i32 2, i32 1 }, section "cuda_offloading_entries$OE", align 1 -// CUDA-COFF: @.offloading.entry_name.4 = internal unnamed_addr constant [4 x i8] c"tex\00" +// CUDA-COFF: @.offloading.entry_name.4 = internal unnamed_addr constant [4 x i8] c"tex\00", section ".llvm.rodata.offloading", align 1 // CUDA-COFF: @.offloading.entry.tex = weak constant %struct.__tgt_offload_entry { ptr @tex, ptr @.offloading.entry_name.4, i64 4, i32 3, i32 1 }, section "cuda_offloading_entries$OE", align 1 //. -// HIP-COFF: @.offloading.entry_name = internal unnamed_addr constant [8 x i8] c"_Z3foov\00" +// HIP-COFF: @.offloading.entry_name = internal unnamed_addr constant [8 x i8] c"_Z3foov\00", section ".llvm.rodata.offloading", align 1 // HIP-COFF: @.offloading.entry._Z3foov = weak constant %struct.__tgt_offload_entry { ptr @_Z3foov, ptr @.offloading.entry_name, i64 0, i32 0, i32 0 }, section "hip_offloading_entries$OE", align 1 -// HIP-COFF: @.offloading.entry_name.1 = internal unnamed_addr constant [11 x i8] c"_Z6kernelv\00" +// HIP-COFF: @.offloading.entry_name.1 = internal unnamed_addr constant [11 x i8] c"_Z6kernelv\00", section ".llvm.rodata.offloading", align 1 // HIP-COFF: @.offloading.entry._Z6kernelv = weak constant %struct.__tgt_offload_entry { ptr @_Z6kernelv, ptr @.offloading.entry_name.1, i64 0, i32 0, i32 0 }, section "hip_offloading_entries$OE", align 1 -// HIP-COFF: @.offloading.entry_name.2 = internal unnamed_addr constant [4 x i8] c"var\00" +// HIP-COFF: @.offloading.entry_name.2 = internal unnamed_addr constant [4 x i8] c"var\00", section ".llvm.rodata.offloading", align 1 // HIP-COFF: @.offloading.entry.var = weak constant %struct.__tgt_offload_entry { ptr @var, ptr @.offloading.entry_name.2, i64 4, i32 0, i32 0 }, section "hip_offloading_entries$OE", align 1 -// HIP-COFF: @.offloading.entry_name.3 = internal unnamed_addr constant [5 x i8] c"surf\00" +// HIP-COFF: @.offloading.entry_name.3 = internal unnamed_addr constant [5 x i8] c"surf\00", section ".llvm.rodata.offloading", align 1 // HIP-COFF: @.offloading.entry.surf = weak constant %struct.__tgt_offload_entry { ptr @surf, ptr @.offloading.entry_name.3, i64 4, i32 2, i32 1 }, section "hip_offloading_entries$OE", align 1 -// HIP-COFF: @.offloading.entry_name.4 = internal unnamed_addr constant [4 x i8] c"tex\00" +// HIP-COFF: @.offloading.entry_name.4 = internal unnamed_addr constant [4 x i8] c"tex\00", section ".llvm.rodata.offloading", align 1 // HIP-COFF: @.offloading.entry.tex = weak constant %struct.__tgt_offload_entry { ptr @tex, ptr @.offloading.entry_name.4, i64 4, i32 3, i32 1 }, section "hip_offloading_entries$OE", align 1 //. // CUDA-LABEL: @_Z18__device_stub__foov( @@ -137,3 +137,28 @@ template struct __attribute__((device_builtin_texture_type)) texture : public textureReference {}; texture tex; +//. +// CUDA: [[META0:![0-9]+]] = !{ptr @.offloading.entry_name} +// CUDA: [[META1:![0-9]+]] = !{ptr @.offloading.entry_name.1} +// CUDA: [[META2:![0-9]+]] = !{ptr @.offloading.entry_name.2} +// CUDA: [[META3:![0-9]+]] = !{ptr @.offloading.entry_name.3} +// CUDA: [[META4:![0-9]+]] = !{ptr @.offloading.entry_name.4} +//. +// HIP: [[META0:![0-9]+]] = !{ptr @.offloading.entry_name} +// HIP: [[META1:![0-9]+]] = !{ptr @.offloading.entry_name.1} +// HIP: [[META2:![0-9]+]] = !{ptr @.offloading.entry_name.2} +// HIP: [[META3:![0-9]+]] = !{ptr @.offloading.entry_name.3} +// HIP: [[META4:![0-9]+]] = !{ptr @.offloading.entry_name.4} +//. +// CUDA-COFF: [[META0:![0-9]+]] = !{ptr @.offloading.entry_name} +// CUDA-COFF: [[META1:![0-9]+]] = !{ptr @.offloading.entry_name.1} +// CUDA-COFF: [[META2:![0-9]+]] = !{ptr @.offloading.entry_name.2} +// CUDA-COFF: [[META3:![0-9]+]] = !{ptr @.offloading.entry_name.3} +// CUDA-COFF: [[META4:![0-9]+]] = !{ptr @.offloading.entry_name.4} +//. +// HIP-COFF: [[META0:![0-9]+]] = !{ptr @.offloading.entry_name} +// HIP-COFF: [[META1:![0-9]+]] = !{ptr @.offloading.entry_name.1} +// HIP-COFF: [[META2:![0-9]+]] = !{ptr @.offloading.entry_name.2} +// HIP-COFF: [[META3:![0-9]+]] = !{ptr @.offloading.entry_name.3} +// HIP-COFF: [[META4:![0-9]+]] = !{ptr @.offloading.entry_name.4} +//. diff --git a/clang/test/CodeGenCXX/amdgpu-barrier-typeinfo.cpp b/clang/test/CodeGenCXX/amdgpu-barrier-typeinfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a47f217dcd3db673d888b9adbc0d22d8cfac1587 --- /dev/null +++ b/clang/test/CodeGenCXX/amdgpu-barrier-typeinfo.cpp @@ -0,0 +1,10 @@ +// REQUIRES: amdgpu-registered-target +// RUN: %clang_cc1 -triple amdgcn %s -emit-llvm -o - | FileCheck %s + +namespace std { class type_info; }; + +auto &b0 = typeid(__amdgpu_named_workgroup_barrier_t); + +// CHECK-DAG: @_ZTSu34__amdgpu_named_workgroup_barrier_t = {{.*}} c"u34__amdgpu_named_workgroup_barrier_t\00" +// CHECK-DAG: @_ZTIu34__amdgpu_named_workgroup_barrier_t = {{.*}} @_ZTVN10__cxxabiv123__fundamental_type_infoE, {{.*}} @_ZTSu34__amdgpu_named_workgroup_barrier_t + diff --git a/clang/test/CodeGenHIP/amdgpu-barrier-type.hip b/clang/test/CodeGenHIP/amdgpu-barrier-type.hip new file mode 100644 index 0000000000000000000000000000000000000000..229e8b3c737c6aabf0bf8f27921f57dd0bc1a750 --- /dev/null +++ b/clang/test/CodeGenHIP/amdgpu-barrier-type.hip @@ -0,0 +1,42 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature + // REQUIRES: amdgpu-registered-target + // RUN: %clang_cc1 -triple amdgcn-unknown-unknown -target-cpu verde -emit-llvm -o - %s | FileCheck %s + +#define __shared__ __attribute__((shared)) + +__shared__ __amdgpu_named_workgroup_barrier_t bar; +__shared__ __amdgpu_named_workgroup_barrier_t arr[2]; +__shared__ struct { + __amdgpu_named_workgroup_barrier_t x; + __amdgpu_named_workgroup_barrier_t y; +} str; + +__amdgpu_named_workgroup_barrier_t *getBar(); +void useBar(__amdgpu_named_workgroup_barrier_t *); + +// CHECK-LABEL: define {{[^@]+}}@_Z7testSemPu34__amdgpu_named_workgroup_barrier_t +// CHECK-SAME: (ptr noundef [[P:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[RETVAL:%.*]] = alloca ptr, align 8, addrspace(5) +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 8, addrspace(5) +// CHECK-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// CHECK-NEXT: [[P_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[P_ADDR]] to ptr +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR_ASCAST]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR_ASCAST]], align 8 +// CHECK-NEXT: call void @_Z6useBarPu34__amdgpu_named_workgroup_barrier_t(ptr noundef [[TMP0]]) #[[ATTR2:[0-9]+]] +// CHECK-NEXT: call void @_Z6useBarPu34__amdgpu_named_workgroup_barrier_t(ptr noundef addrspacecast (ptr addrspace(1) @bar to ptr)) #[[ATTR2]] +// CHECK-NEXT: call void @_Z6useBarPu34__amdgpu_named_workgroup_barrier_t(ptr noundef getelementptr inbounds ([2 x target("amdgcn.named.barrier", 0)], ptr addrspacecast (ptr addrspace(1) @arr to ptr), i64 0, i64 1)) #[[ATTR2]] +// CHECK-NEXT: call void @_Z6useBarPu34__amdgpu_named_workgroup_barrier_t(ptr noundef getelementptr inbounds nuw ([[STRUCT_ANON:%.*]], ptr addrspacecast (ptr addrspace(1) @str to ptr), i32 0, i32 1)) #[[ATTR2]] +// CHECK-NEXT: [[CALL:%.*]] = call noundef ptr @_Z6getBarv() #[[ATTR2]] +// CHECK-NEXT: call void @_Z6useBarPu34__amdgpu_named_workgroup_barrier_t(ptr noundef [[CALL]]) #[[ATTR2]] +// CHECK-NEXT: [[CALL1:%.*]] = call noundef ptr @_Z6getBarv() #[[ATTR2]] +// CHECK-NEXT: ret ptr [[CALL1]] +// +__amdgpu_named_workgroup_barrier_t *testSem(__amdgpu_named_workgroup_barrier_t *p) { + useBar(p); + useBar(&bar); + useBar(&arr[1]); + useBar(&str.y); + useBar(getBar()); + return getBar(); +} diff --git a/clang/test/CodeGenHLSL/builtins/RWStructuredBuffer-elementtype.hlsl b/clang/test/CodeGenHLSL/builtins/RWStructuredBuffer-elementtype.hlsl new file mode 100644 index 0000000000000000000000000000000000000000..727f416cde57fd6aa2d9e37be865770ad642982a --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/RWStructuredBuffer-elementtype.hlsl @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s + +// NOTE: The number in type name and whether the struct is packed or not will mostly +// likely change once subscript operators are properly implemented (llvm/llvm-project#95956) +// and theinterim field of the contained type is removed. + +// CHECK: %"class.hlsl::RWStructuredBuffer" = type <{ target("dx.RawBuffer", i16, 1, 0) +// CHECK: %"class.hlsl::RWStructuredBuffer.0" = type <{ target("dx.RawBuffer", i16, 1, 0) +// CHECK: %"class.hlsl::RWStructuredBuffer.2" = type { target("dx.RawBuffer", i32, 1, 0) +// CHECK: %"class.hlsl::RWStructuredBuffer.3" = type { target("dx.RawBuffer", i32, 1, 0) +// CHECK: %"class.hlsl::RWStructuredBuffer.4" = type { target("dx.RawBuffer", i64, 1, 0) +// CHECK: %"class.hlsl::RWStructuredBuffer.5" = type { target("dx.RawBuffer", i64, 1, 0) +// CHECK: %"class.hlsl::RWStructuredBuffer.6" = type <{ target("dx.RawBuffer", half, 1, 0) +// CHECK: %"class.hlsl::RWStructuredBuffer.8" = type { target("dx.RawBuffer", float, 1, 0) +// CHECK: %"class.hlsl::RWStructuredBuffer.9" = type { target("dx.RawBuffer", double, 1, 0) +// CHECK: %"class.hlsl::RWStructuredBuffer.10" = type { target("dx.RawBuffer", <4 x i16>, 1, 0) +// CHECK: %"class.hlsl::RWStructuredBuffer.11" = type { target("dx.RawBuffer", <3 x i32>, 1, 0) +// CHECK: %"class.hlsl::RWStructuredBuffer.12" = type { target("dx.RawBuffer", <2 x half>, 1, 0) +// CHECK: %"class.hlsl::RWStructuredBuffer.13" = type { target("dx.RawBuffer", <3 x float>, 1, 0) + +RWStructuredBuffer BufI16; +RWStructuredBuffer BufU16; +RWStructuredBuffer BufI32; +RWStructuredBuffer BufU32; +RWStructuredBuffer BufI64; +RWStructuredBuffer BufU64; +RWStructuredBuffer BufF16; +RWStructuredBuffer BufF32; +RWStructuredBuffer BufF64; +RWStructuredBuffer< vector > BufI16x4; +RWStructuredBuffer< vector > BufU32x3; +RWStructuredBuffer BufF16x2; +RWStructuredBuffer BufF32x3; +// TODO: RWStructuredBuffer BufSNormF16; +// TODO: RWStructuredBuffer BufUNormF16; +// TODO: RWStructuredBuffer BufSNormF32; +// TODO: RWStructuredBuffer BufUNormF32; +// TODO: RWStructuredBuffer BufSNormF64; +// TODO: RWStructuredBuffer BufUNormF64; + +[numthreads(1,1,1)] +void main(int GI : SV_GroupIndex) { + BufI16[GI] = 0; + BufU16[GI] = 0; + BufI32[GI] = 0; + BufU32[GI] = 0; + BufI64[GI] = 0; + BufU64[GI] = 0; + BufF16[GI] = 0; + BufF32[GI] = 0; + BufF64[GI] = 0; + BufI16x4[GI] = 0; + BufU32x3[GI] = 0; + BufF16x2[GI] = 0; + BufF32x3[GI] = 0; +} + +// CHECK: !{{[0-9]+}} = !{ptr @BufI16, i32 10, i32 2, +// CHECK: !{{[0-9]+}} = !{ptr @BufU16, i32 10, i32 3, +// CHECK: !{{[0-9]+}} = !{ptr @BufI32, i32 10, i32 4, +// CHECK: !{{[0-9]+}} = !{ptr @BufU32, i32 10, i32 5, +// CHECK: !{{[0-9]+}} = !{ptr @BufI64, i32 10, i32 6, +// CHECK: !{{[0-9]+}} = !{ptr @BufU64, i32 10, i32 7, +// CHECK: !{{[0-9]+}} = !{ptr @BufF16, i32 10, i32 8, +// CHECK: !{{[0-9]+}} = !{ptr @BufF32, i32 10, i32 9, +// CHECK: !{{[0-9]+}} = !{ptr @BufF64, i32 10, i32 10, +// CHECK: !{{[0-9]+}} = !{ptr @BufI16x4, i32 10, i32 2, +// CHECK: !{{[0-9]+}} = !{ptr @BufU32x3, i32 10, i32 5, +// CHECK: !{{[0-9]+}} = !{ptr @BufF16x2, i32 10, i32 8, +// CHECK: !{{[0-9]+}} = !{ptr @BufF32x3, i32 10, i32 9, diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffer-annotations.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffer-annotations.hlsl index 4d3d4908c396e6d7a3fd1dbe70bfe00299b0ff00..a88ea774f33201595148ab0f79b20cb20b14432f 100644 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffer-annotations.hlsl +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffer-annotations.hlsl @@ -3,17 +3,17 @@ StructuredBuffer Buffer1; StructuredBuffer > BufferArray[4]; -StructuredBuffer Buffer2 : register(u3); -StructuredBuffer > BufferArray2[4] : register(u4); +StructuredBuffer Buffer2 : register(t3); +StructuredBuffer > BufferArray2[4] : register(t4); -StructuredBuffer Buffer3 : register(u3, space1); -StructuredBuffer > BufferArray3[4] : register(u4, space1); +StructuredBuffer Buffer3 : register(t3, space1); +StructuredBuffer > BufferArray3[4] : register(t4, space1); [numthreads(1,1,1)] void main() { } -// CHECK: !hlsl.uavs = !{![[Single:[0-9]+]], ![[Array:[0-9]+]], ![[SingleAllocated:[0-9]+]], ![[ArrayAllocated:[0-9]+]], ![[SingleSpace:[0-9]+]], ![[ArraySpace:[0-9]+]]} +// CHECK: !hlsl.srvs = !{![[Single:[0-9]+]], ![[Array:[0-9]+]], ![[SingleAllocated:[0-9]+]], ![[ArrayAllocated:[0-9]+]], ![[SingleSpace:[0-9]+]], ![[ArraySpace:[0-9]+]]} // CHECK-DAG: ![[Single]] = !{ptr @Buffer1, i32 10, i32 9, i1 false, i32 -1, i32 0} // CHECK-DAG: ![[Array]] = !{ptr @BufferArray, i32 10, i32 9, i1 false, i32 -1, i32 0} // CHECK-DAG: ![[SingleAllocated]] = !{ptr @Buffer2, i32 10, i32 9, i1 false, i32 3, i32 0} diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffer-constructor.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffer-constructor.hlsl deleted file mode 100644 index 4dbca9bc0a4d9360bf47192cc528208a1610717b..0000000000000000000000000000000000000000 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffer-constructor.hlsl +++ /dev/null @@ -1,24 +0,0 @@ -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -// RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV - -// NOTE: SPIRV codegen for resource types is not yet implemented - -StructuredBuffer Buf : register(u10); - -// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0), float } -// CHECK: @Buf = global %"class.hlsl::StructuredBuffer" zeroinitializer, align 4 - -// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(8) %this) -// CHECK-NEXT: entry: - -// CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffer_constructor.hlsl() -// CHECK-NEXT: entry: -// CHECK-NEXT: call void @__cxx_global_var_init() -// CHECK-NEXT: call void @_init_resource_bindings() - -// CHECK: define internal void @_init_resource_bindings() { -// CHECK-NEXT: entry: -// CHECK-DXIL-NEXT: %Buf_h = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 10, i32 1, i32 0, i1 false) -// CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf_h, ptr @Buf, align 4 -// CHECK-SPIRV-NEXT: %Buf_h = call target("dx.RawBuffer", float, 1, 0) @llvm.spv.handle.fromBinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 10, i32 1, i32 0, i1 false) -// CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf_h, ptr @Buf", align 4 diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffer-elementtype.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffer-elementtype.hlsl index a99c7f98a1afb67975cb4f1d92bc51025daf8b5b..4c30119498ff1a2616f81c8c6816235bf9e8d23d 100644 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffer-elementtype.hlsl +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffer-elementtype.hlsl @@ -4,19 +4,19 @@ // likely change once subscript operators are properly implemented (llvm/llvm-project#95956) // and theinterim field of the contained type is removed. -// CHECK: %"class.hlsl::StructuredBuffer" = type <{ target("dx.RawBuffer", i16, 1, 0) -// CHECK: %"class.hlsl::StructuredBuffer.0" = type <{ target("dx.RawBuffer", i16, 1, 0) -// CHECK: %"class.hlsl::StructuredBuffer.2" = type { target("dx.RawBuffer", i32, 1, 0) -// CHECK: %"class.hlsl::StructuredBuffer.3" = type { target("dx.RawBuffer", i32, 1, 0) -// CHECK: %"class.hlsl::StructuredBuffer.4" = type { target("dx.RawBuffer", i64, 1, 0) -// CHECK: %"class.hlsl::StructuredBuffer.5" = type { target("dx.RawBuffer", i64, 1, 0) -// CHECK: %"class.hlsl::StructuredBuffer.6" = type <{ target("dx.RawBuffer", half, 1, 0) -// CHECK: %"class.hlsl::StructuredBuffer.8" = type { target("dx.RawBuffer", float, 1, 0) -// CHECK: %"class.hlsl::StructuredBuffer.9" = type { target("dx.RawBuffer", double, 1, 0) -// CHECK: %"class.hlsl::StructuredBuffer.10" = type { target("dx.RawBuffer", <4 x i16>, 1, 0) -// CHECK: %"class.hlsl::StructuredBuffer.11" = type { target("dx.RawBuffer", <3 x i32>, 1, 0) -// CHECK: %"class.hlsl::StructuredBuffer.12" = type { target("dx.RawBuffer", <2 x half>, 1, 0) -// CHECK: %"class.hlsl::StructuredBuffer.13" = type { target("dx.RawBuffer", <3 x float>, 1, 0) +// CHECK: %"class.hlsl::StructuredBuffer" = type <{ target("dx.RawBuffer", i16, 0, 0) +// CHECK: %"class.hlsl::StructuredBuffer.0" = type <{ target("dx.RawBuffer", i16, 0, 0) +// CHECK: %"class.hlsl::StructuredBuffer.2" = type { target("dx.RawBuffer", i32, 0, 0) +// CHECK: %"class.hlsl::StructuredBuffer.3" = type { target("dx.RawBuffer", i32, 0, 0) +// CHECK: %"class.hlsl::StructuredBuffer.4" = type { target("dx.RawBuffer", i64, 0, 0) +// CHECK: %"class.hlsl::StructuredBuffer.5" = type { target("dx.RawBuffer", i64, 0, 0) +// CHECK: %"class.hlsl::StructuredBuffer.6" = type <{ target("dx.RawBuffer", half, 0, 0) +// CHECK: %"class.hlsl::StructuredBuffer.8" = type { target("dx.RawBuffer", float, 0, 0) +// CHECK: %"class.hlsl::StructuredBuffer.9" = type { target("dx.RawBuffer", double, 0, 0) +// CHECK: %"class.hlsl::StructuredBuffer.10" = type { target("dx.RawBuffer", <4 x i16>, 0, 0) +// CHECK: %"class.hlsl::StructuredBuffer.11" = type { target("dx.RawBuffer", <3 x i32>, 0, 0) +// CHECK: %"class.hlsl::StructuredBuffer.12" = type { target("dx.RawBuffer", <2 x half>, 0, 0) +// CHECK: %"class.hlsl::StructuredBuffer.13" = type { target("dx.RawBuffer", <3 x float>, 0, 0) StructuredBuffer BufI16; StructuredBuffer BufU16; @@ -31,28 +31,28 @@ StructuredBuffer< vector > BufI16x4; StructuredBuffer< vector > BufU32x3; StructuredBuffer BufF16x2; StructuredBuffer BufF32x3; -// TODO: StructuredBuffer BufSNormF16; -> 11 -// TODO: StructuredBuffer BufUNormF16; -> 12 -// TODO: StructuredBuffer BufSNormF32; -> 13 -// TODO: StructuredBuffer BufUNormF32; -> 14 -// TODO: StructuredBuffer BufSNormF64; -> 15 -// TODO: StructuredBuffer BufUNormF64; -> 16 +// TODO: StructuredBuffer BufSNormF16; +// TODO: StructuredBuffer BufUNormF16; +// TODO: StructuredBuffer BufSNormF32; +// TODO: StructuredBuffer BufUNormF32; +// TODO: StructuredBuffer BufSNormF64; +// TODO: StructuredBuffer BufUNormF64; [numthreads(1,1,1)] void main(int GI : SV_GroupIndex) { - BufI16[GI] = 0; - BufU16[GI] = 0; - BufI32[GI] = 0; - BufU32[GI] = 0; - BufI64[GI] = 0; - BufU64[GI] = 0; - BufF16[GI] = 0; - BufF32[GI] = 0; - BufF64[GI] = 0; - BufI16x4[GI] = 0; - BufU32x3[GI] = 0; - BufF16x2[GI] = 0; - BufF32x3[GI] = 0; + int16_t v1 = BufI16[GI]; + uint16_t v2 = BufU16[GI]; + int v3 = BufI32[GI]; + uint v4 = BufU32[GI]; + int64_t v5 = BufI64[GI]; + uint64_t v6 = BufU64[GI]; + half v7 = BufF16[GI]; + float v8 = BufF32[GI]; + double v9 = BufF64[GI]; + vector v10 = BufI16x4[GI]; + vector v11 = BufU32x3[GI]; + half2 v12 = BufF16x2[GI]; + float3 v13 = BufF32x3[GI]; } // CHECK: !{{[0-9]+}} = !{ptr @BufI16, i32 10, i32 2, diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl new file mode 100644 index 0000000000000000000000000000000000000000..4f2f8d079074da5a04a7513689d98e9dd56b68d2 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL +// RUN-DISABLED: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV + +// NOTE: SPIRV codegen for resource types is not yet implemented + +StructuredBuffer Buf : register(t10); +RWStructuredBuffer Buf2 : register(u5, space1); + +// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", float, 0, 0), float } +// CHECK: %"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0), float } + +// CHECK: @Buf = global %"class.hlsl::StructuredBuffer" zeroinitializer, align 4 +// CHECK: @Buf2 = global %"class.hlsl::RWStructuredBuffer" zeroinitializer, align 4 + +// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(8) %this) +// CHECK-NEXT: entry: +// CHECK: define linkonce_odr void @_ZN4hlsl18RWStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(8) %this) +// CHECK-NEXT: entry: + +// CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl() +// CHECK: entry: +// CHECK: call void @_init_resource_bindings() + +// CHECK: define internal void @_init_resource_bindings() { +// CHECK-NEXT: entry: +// CHECK-DXIL-NEXT: %Buf_h = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false) +// CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 0, 0) %Buf_h, ptr @Buf, align 4 +// CHECK-DXIL-NEXT: %Buf2_h = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.handle.fromBinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 5, i32 1, i32 0, i1 false) +// CHECK-DXIL-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf2_h, ptr @Buf2, align 4 +// CHECK-SPIRV-NEXT: %Buf_h = call target("dx.RawBuffer", float, 0, 0) @llvm.spv.handle.fromBinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false) +// CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 0, 0) %Buf_h, ptr @Buf", align 4 +// CHECK-SPIRV-NEXT: %Buf2_h = call target("dx.RawBuffer", float, 1, 0) @llvm.spv.handle.fromBinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 5, i32 1, i32 0, i1 false) +// CHECK-SPIRV-NEXT: store target("dx.RawBuffer", float, 1, 0) %Buf2_h, ptr @Buf2", align 4 diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffer-subscript.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-subscripts.hlsl similarity index 91% rename from clang/test/CodeGenHLSL/builtins/StructuredBuffer-subscript.hlsl rename to clang/test/CodeGenHLSL/builtins/StructuredBuffers-subscripts.hlsl index 155749ec4f94a9cb800dc11e6505dbc8fffa9206..b73b743c9b3f15317deadb5dda3c8fbc3f2b57d0 100644 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffer-subscript.hlsl +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-subscripts.hlsl @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -emit-llvm -o - -O0 %s | FileCheck %s StructuredBuffer In; -StructuredBuffer Out; +RWStructuredBuffer Out; [numthreads(1,1,1)] void main(unsigned GI : SV_GroupIndex) { diff --git a/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl b/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl index 6751cf2703ce0e493c5370f29d54a9ab2c2c9a12..c206874a4ca94ac1c49399dc0875e3ee341f4181 100644 --- a/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl +++ b/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl @@ -3,7 +3,7 @@ using handle_float_t = __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float)]]; // CHECK: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", <4 x float>, 1, 0, 0) -// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", %struct.MyStruct = type { <4 x float>, <2 x i32>, [8 x i8] }, 1, 0) +// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", %struct.MyStruct = type { <4 x float>, <2 x i32>, [8 x i8] }, 0, 0) // CHECK: define void @_Z2faU9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %a) // CHECK: call void @_Z4foo1U9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %0) diff --git a/clang/test/CodeGenHLSL/builtins/splitdouble.hlsl b/clang/test/CodeGenHLSL/builtins/splitdouble.hlsl new file mode 100644 index 0000000000000000000000000000000000000000..a883c9d5cc3555e1cbb4a36f3765aa29e9117c2d --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/splitdouble.hlsl @@ -0,0 +1,91 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s -fnative-half-type -emit-llvm -O1 -o - | FileCheck %s +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-vulkan-library %s -fnative-half-type -emit-llvm -O0 -o - | FileCheck %s --check-prefix=SPIRV + + + +// CHECK: define {{.*}} i32 {{.*}}test_scalar{{.*}}(double {{.*}} [[VALD:%.*]]) +// CHECK: [[VALRET:%.*]] = {{.*}} call { i32, i32 } @llvm.dx.splitdouble.i32(double [[VALD]]) +// CHECK-NEXT: extractvalue { i32, i32 } [[VALRET]], 0 +// CHECK-NEXT: extractvalue { i32, i32 } [[VALRET]], 1 +// +// SPIRV: define spir_func {{.*}} i32 {{.*}}test_scalar{{.*}}(double {{.*}} [[VALD:%.*]]) +// SPIRV-NOT: @llvm.dx.splitdouble.i32 +// SPIRV: [[LOAD:%.*]] = load double, ptr [[VALD]].addr, align 8 +// SPIRV-NEXT: [[CAST:%.*]] = bitcast double [[LOAD]] to <2 x i32> +// SPIRV-NEXT: extractelement <2 x i32> [[CAST]], i64 0 +// SPIRV-NEXT: extractelement <2 x i32> [[CAST]], i64 1 +uint test_scalar(double D) { + uint A, B; + asuint(D, A, B); + return A + B; +} + +// CHECK: define {{.*}} <1 x i32> {{.*}}test_double1{{.*}}(<1 x double> {{.*}} [[VALD:%.*]]) +// CHECK: [[TRUNC:%.*]] = extractelement <1 x double> %D, i64 0 +// CHECK-NEXT: [[VALRET:%.*]] = {{.*}} call { i32, i32 } @llvm.dx.splitdouble.i32(double [[TRUNC]]) +// CHECK-NEXT: extractvalue { i32, i32 } [[VALRET]], 0 +// CHECK-NEXT: extractvalue { i32, i32 } [[VALRET]], 1 +// +// SPIRV: define spir_func {{.*}} <1 x i32> {{.*}}test_double1{{.*}}(<1 x double> {{.*}} [[VALD:%.*]]) +// SPIRV-NOT: @llvm.dx.splitdouble.i32 +// SPIRV: [[LOAD:%.*]] = load <1 x double>, ptr [[VALD]].addr, align 8 +// SPIRV-NEXT: [[TRUNC:%.*]] = extractelement <1 x double> [[LOAD]], i64 0 +// SPIRV-NEXT: [[CAST:%.*]] = bitcast double [[TRUNC]] to <2 x i32> +// SPIRV-NEXT: extractelement <2 x i32> [[CAST]], i64 0 +// SPIRV-NEXT: extractelement <2 x i32> [[CAST]], i64 1 +uint1 test_double1(double1 D) { + uint A, B; + asuint(D, A, B); + return A + B; +} + +// CHECK: define {{.*}} <2 x i32> {{.*}}test_vector2{{.*}}(<2 x double> {{.*}} [[VALD:%.*]]) +// CHECK: [[VALRET:%.*]] = {{.*}} call { <2 x i32>, <2 x i32> } @llvm.dx.splitdouble.v2i32(<2 x double> [[VALD]]) +// CHECK-NEXT: extractvalue { <2 x i32>, <2 x i32> } [[VALRET]], 0 +// CHECK-NEXT: extractvalue { <2 x i32>, <2 x i32> } [[VALRET]], 1 +// +// SPIRV: define spir_func {{.*}} <2 x i32> {{.*}}test_vector2{{.*}}(<2 x double> {{.*}} [[VALD:%.*]]) +// SPIRV-NOT: @llvm.dx.splitdouble.i32 +// SPIRV: [[LOAD:%.*]] = load <2 x double>, ptr [[VALD]].addr, align 16 +// SPIRV-NEXT: [[CAST1:%.*]] = bitcast <2 x double> [[LOAD]] to <4 x i32> +// SPIRV-NEXT: [[SHUF1:%.*]] = shufflevector <4 x i32> [[CAST1]], <4 x i32> poison, <2 x i32> +// SPIRV-NEXT: [[SHUF2:%.*]] = shufflevector <4 x i32> [[CAST1]], <4 x i32> poison, <2 x i32> +uint2 test_vector2(double2 D) { + uint2 A, B; + asuint(D, A, B); + return A + B; +} + +// CHECK: define {{.*}} <3 x i32> {{.*}}test_vector3{{.*}}(<3 x double> {{.*}} [[VALD:%.*]]) +// CHECK: [[VALRET:%.*]] = {{.*}} call { <3 x i32>, <3 x i32> } @llvm.dx.splitdouble.v3i32(<3 x double> [[VALD]]) +// CHECK-NEXT: extractvalue { <3 x i32>, <3 x i32> } [[VALRET]], 0 +// CHECK-NEXT: extractvalue { <3 x i32>, <3 x i32> } [[VALRET]], 1 +// +// SPIRV: define spir_func {{.*}} <3 x i32> {{.*}}test_vector3{{.*}}(<3 x double> {{.*}} [[VALD:%.*]]) +// SPIRV-NOT: @llvm.dx.splitdouble.i32 +// SPIRV: [[LOAD:%.*]] = load <3 x double>, ptr [[VALD]].addr, align 32 +// SPIRV-NEXT: [[CAST1:%.*]] = bitcast <3 x double> [[LOAD]] to <6 x i32> +// SPIRV-NEXT: [[SHUF1:%.*]] = shufflevector <6 x i32> [[CAST1]], <6 x i32> poison, <3 x i32> +// SPIRV-NEXT: [[SHUF2:%.*]] = shufflevector <6 x i32> [[CAST1]], <6 x i32> poison, <3 x i32> +uint3 test_vector3(double3 D) { + uint3 A, B; + asuint(D, A, B); + return A + B; +} + +// CHECK: define {{.*}} <4 x i32> {{.*}}test_vector4{{.*}}(<4 x double> {{.*}} [[VALD:%.*]]) +// CHECK: [[VALRET:%.*]] = {{.*}} call { <4 x i32>, <4 x i32> } @llvm.dx.splitdouble.v4i32(<4 x double> [[VALD]]) +// CHECK-NEXT: extractvalue { <4 x i32>, <4 x i32> } [[VALRET]], 0 +// CHECK-NEXT: extractvalue { <4 x i32>, <4 x i32> } [[VALRET]], 1 +// +// SPIRV: define spir_func {{.*}} <4 x i32> {{.*}}test_vector4{{.*}}(<4 x double> {{.*}} [[VALD:%.*]]) +// SPIRV-NOT: @llvm.dx.splitdouble.i32 +// SPIRV: [[LOAD:%.*]] = load <4 x double>, ptr [[VALD]].addr, align 32 +// SPIRV-NEXT: [[CAST1:%.*]] = bitcast <4 x double> [[LOAD]] to <8 x i32> +// SPIRV-NEXT: [[SHUF1:%.*]] = shufflevector <8 x i32> [[CAST1]], <8 x i32> poison, <4 x i32> +// SPIRV-NEXT: [[SHUF2:%.*]] = shufflevector <8 x i32> [[CAST1]], <8 x i32> poison, <4 x i32> +uint4 test_vector4(double4 D) { + uint4 A, B; + asuint(D, A, B); + return A + B; +} diff --git a/clang/test/CodeGenHLSL/convergence/entry.point.hlsl b/clang/test/CodeGenHLSL/convergence/entry.point.hlsl new file mode 100644 index 0000000000000000000000000000000000000000..337a9ad5026c16155b158f9e83f8393e724fce1d --- /dev/null +++ b/clang/test/CodeGenHLSL/convergence/entry.point.hlsl @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple spirv-pc-vulkan-compute -finclude-default-header -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s + +// CHECK-LABEL: define void @main() +// CHECK-NEXT: entry: +// CHECK-NEXT: [[token:%[0-9]+]] = call token @llvm.experimental.convergence.entry() +// CHECK-NEXT: call spir_func void @_Z4mainv() [ "convergencectrl"(token [[token]]) ] + +[numthreads(1,1,1)] +void main() { +} + diff --git a/clang/test/CodeGenOpenCLCXX/local_addrspace_init.clcpp b/clang/test/CodeGenOpenCLCXX/local_addrspace_init.clcpp index bb9acf09d120be1ec55355b20b6cf887caad56b4..0a6462e4262413be6703236dec2adb8fcc7a9cca 100644 --- a/clang/test/CodeGenOpenCLCXX/local_addrspace_init.clcpp +++ b/clang/test/CodeGenOpenCLCXX/local_addrspace_init.clcpp @@ -14,7 +14,7 @@ kernel void test() { // address space variables. User defined initialization could // make sense, but would it mean that all work items need to // execute it? Potentially disallowing any initialization would - // make things easier and assingments can be used to set specific + // make things easier and assignments can be used to set specific // values. This rules should make it consistent with OpenCL C. //__local C c(); } diff --git a/clang/test/Driver/Inputs/cpunative/cortex-a57 b/clang/test/Driver/Inputs/cpunative/cortex-a57 new file mode 100644 index 0000000000000000000000000000000000000000..e1903012ab79ccda38c861ce11b9f32c1a8892aa --- /dev/null +++ b/clang/test/Driver/Inputs/cpunative/cortex-a57 @@ -0,0 +1,8 @@ +processor : 0 +BogoMIPS : 200.00 +Features : fp asimd evtstrm crc32 cpuid +CPU implementer : 0x41 +CPU architecture: 8 +CPU variant : 0x1 +CPU part : 0xd07 +CPU revision : 1 diff --git a/clang/test/Driver/Inputs/cpunative/cortex-a72 b/clang/test/Driver/Inputs/cpunative/cortex-a72 new file mode 100644 index 0000000000000000000000000000000000000000..7aed4a6fa732369477adbbbb0f0c1271df6651ba --- /dev/null +++ b/clang/test/Driver/Inputs/cpunative/cortex-a72 @@ -0,0 +1,8 @@ +processor : 0 +BogoMIPS : 250.00 +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid asimdrdm +CPU implementer : 0x41 +CPU architecture: 8 +CPU variant : 0x0 +CPU part : 0xd08 +CPU revision : 2 diff --git a/clang/test/Driver/Inputs/cpunative/cortex-a76 b/clang/test/Driver/Inputs/cpunative/cortex-a76 new file mode 100644 index 0000000000000000000000000000000000000000..21822cfcec60b0e6e7316f69875c9d6d88d28242 --- /dev/null +++ b/clang/test/Driver/Inputs/cpunative/cortex-a76 @@ -0,0 +1,8 @@ +processor : 0 +BogoMIPS : 500.00 +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics cpuid asimdrdm ssbs jscvt fcma +CPU implementer : 0x41 +CPU architecture: 8 +CPU variant : 0x1 +CPU part : 0xd0b +CPU revision : 2 diff --git a/clang/test/Driver/Inputs/cpunative/neoverse-n1 b/clang/test/Driver/Inputs/cpunative/neoverse-n1 new file mode 100644 index 0000000000000000000000000000000000000000..571e8840b09f08a82665ab1e1997fc7afde117cf --- /dev/null +++ b/clang/test/Driver/Inputs/cpunative/neoverse-n1 @@ -0,0 +1,8 @@ +processor : 0 +BogoMIPS : 50.00 +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs +CPU implementer : 0x41 +CPU architecture: 8 +CPU variant : 0x3 +CPU part : 0xd0c +CPU revision : 1 diff --git a/clang/test/Driver/Inputs/cpunative/neoverse-v2 b/clang/test/Driver/Inputs/cpunative/neoverse-v2 new file mode 100644 index 0000000000000000000000000000000000000000..c3c8433415d7a08c60057c01a91bafceba4923e7 --- /dev/null +++ b/clang/test/Driver/Inputs/cpunative/neoverse-v2 @@ -0,0 +1,8 @@ +processor : 0 +BogoMIPS : 2000.00 +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm ssbs sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh bti +CPU implementer : 0x41 +CPU architecture: 8 +CPU variant : 0x0 +CPU part : 0xd4f +CPU revision : 0 diff --git a/clang/test/Driver/XRay/xray-shared.cpp b/clang/test/Driver/XRay/xray-shared.cpp new file mode 100644 index 0000000000000000000000000000000000000000..215854e1fc7cefecca5ed5bcccc38bde03bed46c --- /dev/null +++ b/clang/test/Driver/XRay/xray-shared.cpp @@ -0,0 +1,17 @@ +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fPIC -fxray-instrument -fxray-shared -c %s -o /dev/null 2>&1 | FileCheck %s +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fpic -fxray-instrument -fxray-shared -c %s -o /dev/null 2>&1 | FileCheck %s +// RUN: %clang -### --target=x86_64-unknown-linux-gnu -fxray-instrument -fxray-shared -c %s -o /dev/null 2>&1 | FileCheck %s +// RUN: not %clang -### --target=x86_64-unknown-linux-gnu -fno-PIC -fxray-instrument -fxray-shared -c %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR-PIC +// RUN: not %clang -### --target=x86_64-unknown-linux-gnu -fno-pic -fxray-instrument -fxray-shared -c %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR-PIC + +// On 64 bit darwin, PIC is always enabled +// RUN: %clang -### --target=x86_64-apple-darwin -fxray-instrument -fxray-shared -c %s -o /dev/null 2>&1 | FileCheck %s + +// Check unsupported targets +// RUN: not %clang -### --target=aarch64-pc-freebsd -fPIC -fxray-instrument -fxray-shared -c %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR-TARGET +// RUN: not %clang -### --target=arm64-apple-macos -fPIC -fxray-instrument -fxray-shared -c %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR-TARGET + +// CHECK: "-cc1" {{.*}}"-fxray-instrument" {{.*}}"-fxray-shared" +// ERR-TARGET: error: unsupported option '-fxray-shared' for target +// ERR-PIC: error: option '-fxray-shared' cannot be specified without '-fPIC' + diff --git a/clang/test/Driver/aarch64-mcpu-native.c b/clang/test/Driver/aarch64-mcpu-native.c new file mode 100644 index 0000000000000000000000000000000000000000..f1d0ba76ad79c49afe834644308562478d6dce53 --- /dev/null +++ b/clang/test/Driver/aarch64-mcpu-native.c @@ -0,0 +1,138 @@ +// REQUIRES: aarch64-registered-target +// RUN: export LLVM_CPUINFO=%S/Inputs/cpunative/neoverse-v2 +// RUN: %clang --target=aarch64 --print-enabled-extensions -mcpu=native | FileCheck --strict-whitespace --check-prefix=CHECK-FEAT-NV2 --implicit-check-not=FEAT_ %s + +// CHECK-FEAT-NV2: Extensions enabled for the given AArch64 target +// CHECK-FEAT-NV2-EMPTY: +// CHECK-FEAT-NV2: Architecture Feature(s) Description +// CHECK-FEAT-NV2: FEAT_AES, FEAT_PMULL Enable AES support +// CHECK-FEAT-NV2: FEAT_AMUv1 Enable Armv8.4-A Activity Monitors extension +// CHECK-FEAT-NV2: FEAT_AdvSIMD Enable Advanced SIMD instructions +// CHECK-FEAT-NV2: FEAT_BF16 Enable BFloat16 Extension +// CHECK-FEAT-NV2: FEAT_BTI Enable Branch Target Identification +// CHECK-FEAT-NV2: FEAT_CCIDX Enable Armv8.3-A Extend of the CCSIDR number of sets +// CHECK-FEAT-NV2: FEAT_CRC32 Enable Armv8.0-A CRC-32 checksum instructions +// CHECK-FEAT-NV2: FEAT_CSV2_2 Enable architectural speculation restriction +// CHECK-FEAT-NV2: FEAT_DIT Enable Armv8.4-A Data Independent Timing instructions +// CHECK-FEAT-NV2: FEAT_DPB Enable Armv8.2-A data Cache Clean to Point of Persistence +// CHECK-FEAT-NV2: FEAT_DPB2 Enable Armv8.5-A Cache Clean to Point of Deep Persistence +// CHECK-FEAT-NV2: FEAT_DotProd Enable dot product support +// CHECK-FEAT-NV2: FEAT_ETE Enable Embedded Trace Extension +// CHECK-FEAT-NV2: FEAT_FCMA Enable Armv8.3-A Floating-point complex number support +// CHECK-FEAT-NV2: FEAT_FHM Enable FP16 FML instructions +// CHECK-FEAT-NV2: FEAT_FP Enable Armv8.0-A Floating Point Extensions +// CHECK-FEAT-NV2: FEAT_FP16 Enable half-precision floating-point data processing +// CHECK-FEAT-NV2: FEAT_FRINTTS Enable FRInt[32|64][Z|X] instructions that round a floating-point number to an integer (in FP format) forcing it to fit into a 32- or 64-bit int +// CHECK-FEAT-NV2: FEAT_FlagM Enable Armv8.4-A Flag Manipulation instructions +// CHECK-FEAT-NV2: FEAT_FlagM2 Enable alternative NZCV format for floating point comparisons +// CHECK-FEAT-NV2: FEAT_I8MM Enable Matrix Multiply Int8 Extension +// CHECK-FEAT-NV2: FEAT_JSCVT Enable Armv8.3-A JavaScript FP conversion instructions +// CHECK-FEAT-NV2: FEAT_LOR Enable Armv8.1-A Limited Ordering Regions extension +// CHECK-FEAT-NV2: FEAT_LRCPC Enable support for RCPC extension +// CHECK-FEAT-NV2: FEAT_LRCPC2 Enable Armv8.4-A RCPC instructions with Immediate Offsets +// CHECK-FEAT-NV2: FEAT_LSE Enable Armv8.1-A Large System Extension (LSE) atomic instructions +// CHECK-FEAT-NV2: FEAT_LSE2 Enable Armv8.4-A Large System Extension 2 (LSE2) atomicity rules +// CHECK-FEAT-NV2: FEAT_MPAM Enable Armv8.4-A Memory system Partitioning and Monitoring extension +// CHECK-FEAT-NV2: FEAT_MTE, FEAT_MTE2 Enable Memory Tagging Extension +// CHECK-FEAT-NV2: FEAT_NV, FEAT_NV2 Enable Armv8.4-A Nested Virtualization Enchancement +// CHECK-FEAT-NV2: FEAT_PAN Enable Armv8.1-A Privileged Access-Never extension +// CHECK-FEAT-NV2: FEAT_PAN2 Enable Armv8.2-A PAN s1e1R and s1e1W Variants +// CHECK-FEAT-NV2: FEAT_PAuth Enable Armv8.3-A Pointer Authentication extension +// CHECK-FEAT-NV2: FEAT_PMUv3 Enable Armv8.0-A PMUv3 Performance Monitors extension +// CHECK-FEAT-NV2: FEAT_RAS, FEAT_RASv1p1 Enable Armv8.0-A Reliability, Availability and Serviceability Extensions +// CHECK-FEAT-NV2: FEAT_RDM Enable Armv8.1-A Rounding Double Multiply Add/Subtract instructions +// CHECK-FEAT-NV2: FEAT_RNG Enable Random Number generation instructions +// CHECK-FEAT-NV2: FEAT_SB Enable Armv8.5-A Speculation Barrier +// CHECK-FEAT-NV2: FEAT_SEL2 Enable Armv8.4-A Secure Exception Level 2 extension +// CHECK-FEAT-NV2: FEAT_SHA1, FEAT_SHA256 Enable SHA1 and SHA256 support +// CHECK-FEAT-NV2: FEAT_SPE Enable Statistical Profiling extension +// CHECK-FEAT-NV2: FEAT_SPECRES Enable Armv8.5-A execution and data prediction invalidation instructions +// CHECK-FEAT-NV2: FEAT_SSBS, FEAT_SSBS2 Enable Speculative Store Bypass Safe bit +// CHECK-FEAT-NV2: FEAT_SVE Enable Scalable Vector Extension (SVE) instructions +// CHECK-FEAT-NV2: FEAT_SVE2 Enable Scalable Vector Extension 2 (SVE2) instructions +// CHECK-FEAT-NV2: FEAT_SVE_BitPerm Enable bit permutation SVE2 instructions +// CHECK-FEAT-NV2: FEAT_TLBIOS, FEAT_TLBIRANGE Enable Armv8.4-A TLB Range and Maintenance instructions +// CHECK-FEAT-NV2: FEAT_TRBE Enable Trace Buffer Extension +// CHECK-FEAT-NV2: FEAT_TRF Enable Armv8.4-A Trace extension +// CHECK-FEAT-NV2: FEAT_UAO Enable Armv8.2-A UAO PState +// CHECK-FEAT-NV2: FEAT_VHE Enable Armv8.1-A Virtual Host extension + +// RUN: export LLVM_CPUINFO=%S/Inputs/cpunative/neoverse-n1 +// RUN: %clang --target=aarch64 --print-enabled-extensions -mcpu=native | FileCheck --strict-whitespace --check-prefix=CHECK-FEAT-NN1 --implicit-check-not=FEAT_ %s + +// CHECK-FEAT-NN1: Extensions enabled for the given AArch64 target +// CHECK-FEAT-NN1-EMPTY: +// CHECK-FEAT-NN1: Architecture Feature(s) Description +// CHECK-FEAT-NN1: FEAT_AES, FEAT_PMULL Enable AES support +// CHECK-FEAT-NN1: FEAT_AdvSIMD Enable Advanced SIMD instructions +// CHECK-FEAT-NN1: FEAT_CRC32 Enable Armv8.0-A CRC-32 checksum instructions +// CHECK-FEAT-NN1: FEAT_DPB Enable Armv8.2-A data Cache Clean to Point of Persistence +// CHECK-FEAT-NN1: FEAT_DotProd Enable dot product support +// CHECK-FEAT-NN1: FEAT_FP Enable Armv8.0-A Floating Point Extensions +// CHECK-FEAT-NN1: FEAT_FP16 Enable half-precision floating-point data processing +// CHECK-FEAT-NN1: FEAT_LOR Enable Armv8.1-A Limited Ordering Regions extension +// CHECK-FEAT-NN1: FEAT_LRCPC Enable support for RCPC extension +// CHECK-FEAT-NN1: FEAT_LSE Enable Armv8.1-A Large System Extension (LSE) atomic instructions +// CHECK-FEAT-NN1: FEAT_PAN Enable Armv8.1-A Privileged Access-Never extension +// CHECK-FEAT-NN1: FEAT_PAN2 Enable Armv8.2-A PAN s1e1R and s1e1W Variants +// CHECK-FEAT-NN1: FEAT_PMUv3 Enable Armv8.0-A PMUv3 Performance Monitors extension +// CHECK-FEAT-NN1: FEAT_RAS, FEAT_RASv1p1 Enable Armv8.0-A Reliability, Availability and Serviceability Extensions +// CHECK-FEAT-NN1: FEAT_RDM Enable Armv8.1-A Rounding Double Multiply Add/Subtract instructions +// CHECK-FEAT-NN1: FEAT_SHA1, FEAT_SHA256 Enable SHA1 and SHA256 support +// CHECK-FEAT-NN1: FEAT_SPE Enable Statistical Profiling extension +// CHECK-FEAT-NN1: FEAT_SSBS, FEAT_SSBS2 Enable Speculative Store Bypass Safe bit +// CHECK-FEAT-NN1: FEAT_UAO Enable Armv8.2-A UAO PState +// CHECK-FEAT-NN1: FEAT_VHE Enable Armv8.1-A Virtual Host extension + + +// RUN: export LLVM_CPUINFO=%S/Inputs/cpunative/cortex-a57 +// RUN: %clang --target=aarch64 --print-enabled-extensions -mcpu=native | FileCheck --strict-whitespace --check-prefix=CHECK-FEAT-CA57 --implicit-check-not=FEAT_ %s + +// CHECK-FEAT-CA57: Extensions enabled for the given AArch64 target +// CHECK-FEAT-CA57-EMPTY: +// CHECK-FEAT-CA57: Architecture Feature(s) Description +// CHECK-FEAT-CA57: FEAT_AES, FEAT_PMULL Enable AES support +// CHECK-FEAT-CA57: FEAT_AdvSIMD Enable Advanced SIMD instructions +// CHECK-FEAT-CA57: FEAT_CRC32 Enable Armv8.0-A CRC-32 checksum instructions +// CHECK-FEAT-CA57: FEAT_FP Enable Armv8.0-A Floating Point Extensions +// CHECK-FEAT-CA57: FEAT_PMUv3 Enable Armv8.0-A PMUv3 Performance Monitors extension +// CHECK-FEAT-CA57: FEAT_SHA1, FEAT_SHA256 Enable SHA1 and SHA256 support + +// RUN: export LLVM_CPUINFO=%S/Inputs/cpunative/cortex-a72 +// RUN: %clang --target=aarch64 --print-enabled-extensions -mcpu=native | FileCheck --strict-whitespace --check-prefix=CHECK-FEAT-CA72 --implicit-check-not=FEAT_ %s + +// CHECK-FEAT-CA72: Extensions enabled for the given AArch64 target +// CHECK-EMPTY: +// CHECK-FEAT-CA72: Architecture Feature(s) Description +// CHECK-FEAT-CA72: FEAT_AES, FEAT_PMULL Enable AES support +// CHECK-FEAT-CA72: FEAT_AdvSIMD Enable Advanced SIMD instructions +// CHECK-FEAT-CA72: FEAT_CRC32 Enable Armv8.0-A CRC-32 checksum instructions +// CHECK-FEAT-CA72: FEAT_FP Enable Armv8.0-A Floating Point Extensions +// CHECK-FEAT-CA72: FEAT_PMUv3 Enable Armv8.0-A PMUv3 Performance Monitors extension +// CHECK-FEAT-CA72: FEAT_SHA1, FEAT_SHA256 Enable SHA1 and SHA256 support + +// RUN: export LLVM_CPUINFO=%S/Inputs/cpunative/cortex-a76 +// RUN: %clang --target=aarch64 --print-enabled-extensions -mcpu=native | FileCheck --strict-whitespace --check-prefix=CHECK-FEAT-CA76 --implicit-check-not=FEAT_ %s + +// CHECK-FEAT-CA76: Extensions enabled for the given AArch64 target +// CHECK-FEAT-CA76-EMPTY: +// CHECK-FEAT-CA76: Architecture Feature(s) Description +// CHECK-FEAT-CA76: FEAT_AES, FEAT_PMULL Enable AES support +// CHECK-FEAT-CA76: FEAT_AdvSIMD Enable Advanced SIMD instructions +// CHECK-FEAT-CA76: FEAT_CRC32 Enable Armv8.0-A CRC-32 checksum instructions +// CHECK-FEAT-CA76: FEAT_DPB Enable Armv8.2-A data Cache Clean to Point of Persistence +// CHECK-FEAT-CA76: FEAT_DotProd Enable dot product support +// CHECK-FEAT-CA76: FEAT_FP Enable Armv8.0-A Floating Point Extensions +// CHECK-FEAT-CA76: FEAT_FP16 Enable half-precision floating-point data processing +// CHECK-FEAT-CA76: FEAT_LOR Enable Armv8.1-A Limited Ordering Regions extension +// CHECK-FEAT-CA76: FEAT_LRCPC Enable support for RCPC extension +// CHECK-FEAT-CA76: FEAT_LSE Enable Armv8.1-A Large System Extension (LSE) atomic instructions +// CHECK-FEAT-CA76: FEAT_PAN Enable Armv8.1-A Privileged Access-Never extension +// CHECK-FEAT-CA76: FEAT_PAN2 Enable Armv8.2-A PAN s1e1R and s1e1W Variants +// CHECK-FEAT-CA76: FEAT_PMUv3 Enable Armv8.0-A PMUv3 Performance Monitors extension +// CHECK-FEAT-CA76: FEAT_RAS, FEAT_RASv1p1 Enable Armv8.0-A Reliability, Availability and Serviceability Extensions +// CHECK-FEAT-CA76: FEAT_RDM Enable Armv8.1-A Rounding Double Multiply Add/Subtract instructions +// CHECK-FEAT-CA76: FEAT_SHA1, FEAT_SHA256 Enable SHA1 and SHA256 support +// CHECK-FEAT-CA76: FEAT_SSBS, FEAT_SSBS2 Enable Speculative Store Bypass Safe bit +// CHECK-FEAT-CA76: FEAT_UAO Enable Armv8.2-A UAO PState +// CHECK-FEAT-CA76: FEAT_VHE Enable Armv8.1-A Virtual Host extension diff --git a/clang/test/Driver/aarch64-v96a.c b/clang/test/Driver/aarch64-v96a.c index 343e347c928cabc567ce2e381c23fe9027fe59e2..de7890140ebd3a03f35062145a6d69063c9315f9 100644 --- a/clang/test/Driver/aarch64-v96a.c +++ b/clang/test/Driver/aarch64-v96a.c @@ -65,4 +65,8 @@ // RUN: %clang -target aarch64 -march=armv9.6a+pcdphint -### -c %s 2>&1 | FileCheck -check-prefix=V96A-PCDPHINT %s // RUN: %clang -target aarch64 -march=armv9.6-a+pcdphint -### -c %s 2>&1 | FileCheck -check-prefix=V96A-PCDPHINT %s // V96A-PCDPHINT: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.6a"{{.*}} "-target-feature" "+pcdphint" + +// RUN: %clang -target aarch64 -march=armv9.6a+pops -### -c %s 2>&1 | FileCheck -check-prefix=V96A-POPS %s +// RUN: %clang -target aarch64 -march=armv9.6-a+pops -### -c %s 2>&1 | FileCheck -check-prefix=V96A-POPS %s +// V96A-POPS: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.6a"{{.*}} "-target-feature" "+pops" // diff --git a/clang/test/Driver/amdgpu-toolchain.c b/clang/test/Driver/amdgpu-toolchain.c index b60d31bae627009772d32756d9b752c78a9d3465..c1c5aa8e90e68681efb1b1fd73d81b493b79e21a 100644 --- a/clang/test/Driver/amdgpu-toolchain.c +++ b/clang/test/Driver/amdgpu-toolchain.c @@ -32,3 +32,7 @@ // RUN: %clang -### --target=amdgcn-amd-amdhsa -mcpu=gfx906 -nogpulib \ // RUN: -r %s 2>&1 | FileCheck -check-prefixes=RELO %s // RELO-NOT: -shared + +// RUN: %clang -target amdgcn-amd-amdhsa -march=gfx90a -stdlib -startfiles \ +// RUN: -nogpulib -nogpuinc -### %s 2>&1 | FileCheck -check-prefix=STARTUP %s +// STARTUP: ld.lld{{.*}}"-lc" "-lm" "{{.*}}crt1.o" diff --git a/clang/test/Driver/cuda-cross-compiling.c b/clang/test/Driver/cuda-cross-compiling.c index 126e9e9fc83d577a7d63789f86af7e67481491f5..baf370483003155108852415af76831307d632ec 100644 --- a/clang/test/Driver/cuda-cross-compiling.c +++ b/clang/test/Driver/cuda-cross-compiling.c @@ -105,3 +105,11 @@ // RUN: | FileCheck -check-prefix=FEATURE %s // FEATURE: clang-nvlink-wrapper{{.*}}"--plugin-opt=-mattr=+ptx63" + +// +// Test including the libc startup files and libc +// +// RUN: %clang -target nvptx64-nvidia-cuda -march=sm_61 -stdlib -startfiles \ +// RUN: -nogpulib -nogpuinc -### %s 2>&1 | FileCheck -check-prefix=STARTUP %s + +// STARTUP: clang-nvlink-wrapper{{.*}}"-lc" "-lm" "{{.*}}crt1.o" diff --git a/clang/test/Driver/fprofile-generate-cold-function-coverage.c b/clang/test/Driver/fprofile-generate-cold-function-coverage.c new file mode 100644 index 0000000000000000000000000000000000000000..9b2f46423f34b1d45a166615346c71d8409a8c52 --- /dev/null +++ b/clang/test/Driver/fprofile-generate-cold-function-coverage.c @@ -0,0 +1,8 @@ +// RUN: %clang -### -c -fprofile-generate-cold-function-coverage %s 2>&1 | FileCheck %s +// CHECK: "--instrument-cold-function-only-path=default_%m.profraw" +// CHECK: "--pgo-function-entry-coverage" +// CHECK-NOT: "-fprofile-instrument" +// CHECK-NOT: "-fprofile-instrument-path= + +// RUN: %clang -### -c -fprofile-generate-cold-function-coverage=dir %s 2>&1 | FileCheck %s --check-prefix=CHECK-EQ +// CHECK-EQ: "--instrument-cold-function-only-path=dir{{/|\\\\}}default_%m.profraw" diff --git a/clang/test/Driver/linker-wrapper.c b/clang/test/Driver/linker-wrapper.c index 068ea2d7d3c663c2397c69d1838b5257edd4305d..470af4d5d70cac743e5c4555af19b858afdf6fbb 100644 --- a/clang/test/Driver/linker-wrapper.c +++ b/clang/test/Driver/linker-wrapper.c @@ -250,3 +250,7 @@ __attribute__((visibility("protected"), used)) int x; // MLLVM-SAME: -Xlinker -mllvm=-pass-remarks=foo,bar // OFFLOAD-OPT-NOT: -Xlinker -mllvm=-pass-remarks=foo,bar // OFFLOAD-OPT-SAME: {{$}} + +// Error handling when --linker-path is not provided for clang-linker-wrapper +// RUN: not clang-linker-wrapper 2>&1 | FileCheck --check-prefix=LINKER-PATH-NOT-PROVIDED %s +// LINKER-PATH-NOT-PROVIDED: linker path missing, must pass 'linker-path' diff --git a/clang/test/Driver/print-supported-extensions-aarch64.c b/clang/test/Driver/print-supported-extensions-aarch64.c index 7ff4f17beff75ed8ed342ae04976fbb252e507e1..03eacf99736f9e1de5c5f3ea06cb9f221f68873f 100644 --- a/clang/test/Driver/print-supported-extensions-aarch64.c +++ b/clang/test/Driver/print-supported-extensions-aarch64.c @@ -50,6 +50,7 @@ // CHECK-NEXT: pauth-lr FEAT_PAuth_LR Enable Armv9.5-A PAC enhancements // CHECK-NEXT: pcdphint FEAT_PCDPHINT Enable Armv9.6-A Producer Consumer Data Placement hints // CHECK-NEXT: pmuv3 FEAT_PMUv3 Enable Armv8.0-A PMUv3 Performance Monitors extension +// CHECK-NEXT: pops FEAT_PoPS Enable Armv9.6-A Point Of Physical Storage (PoPS) DC instructions // CHECK-NEXT: predres FEAT_SPECRES Enable Armv8.5-A execution and data prediction invalidation instructions // CHECK-NEXT: rng FEAT_RNG Enable Random Number generation instructions // CHECK-NEXT: ras FEAT_RAS, FEAT_RASv1p1 Enable Armv8.0-A Reliability, Availability and Serviceability Extensions diff --git a/clang/test/Driver/print-supported-extensions-riscv.c b/clang/test/Driver/print-supported-extensions-riscv.c index 3e26149bced2eaa508ea439f12ba4a5872516902..712fb857af3e991a4bd471395fc28e82ac5f7ede 100644 --- a/clang/test/Driver/print-supported-extensions-riscv.c +++ b/clang/test/Driver/print-supported-extensions-riscv.c @@ -111,6 +111,7 @@ // CHECK-NEXT: zvl8192b 1.0 'Zvl' (Minimum Vector Length) 8192 // CHECK-NEXT: zhinx 1.0 'Zhinx' (Half Float in Integer) // CHECK-NEXT: zhinxmin 1.0 'Zhinxmin' (Half Float in Integer Minimal) +// CHECK-NEXT: sha 1.0 'Sha' (Augmented Hypervisor) // CHECK-NEXT: shcounterenw 1.0 'Shcounterenw' (Support writeable hcounteren enable bit for any hpmcounter that is not read-only zero) // CHECK-NEXT: shgatpa 1.0 'Sgatpa' (SvNNx4 mode supported for all modes supported by satp, as well as Bare) // CHECK-NEXT: shtvala 1.0 'Shtvala' (htval provides all needed values) @@ -121,6 +122,9 @@ // CHECK-NEXT: smcdeleg 1.0 'Smcdeleg' (Counter Delegation Machine Level) // CHECK-NEXT: smcsrind 1.0 'Smcsrind' (Indirect CSR Access Machine Level) // CHECK-NEXT: smepmp 1.0 'Smepmp' (Enhanced Physical Memory Protection) +// CHECK-NEXT: smmpm 1.0 'Smmpm' (Machine-level Pointer Masking for M-mode) +// CHECK-NEXT: smnpm 1.0 'Smnpm' (Machine-level Pointer Masking for next lower privilege mode) +// CHECK-NEXT: smrnmi 1.0 'Smrnmi' (Resumable Non-Maskable Interrupts) // CHECK-NEXT: smstateen 1.0 'Smstateen' (Machine-mode view of the state-enable extension) // CHECK-NEXT: ssaia 1.0 'Ssaia' (Advanced Interrupt Architecture Supervisor Level) // CHECK-NEXT: ssccfg 1.0 'Ssccfg' (Counter Configuration Supervisor Level) @@ -128,6 +132,8 @@ // CHECK-NEXT: sscofpmf 1.0 'Sscofpmf' (Count Overflow and Mode-Based Filtering) // CHECK-NEXT: sscounterenw 1.0 'Sscounterenw' (Support writeable scounteren enable bit for any hpmcounter that is not read-only zero) // CHECK-NEXT: sscsrind 1.0 'Sscsrind' (Indirect CSR Access Supervisor Level) +// CHECK-NEXT: ssnpm 1.0 'Ssnpm' (Supervisor-level Pointer Masking for next lower privilege mode) +// CHECK-NEXT: sspm 1.0 'Sspm' (Indicates Supervisor-mode Pointer Masking) // CHECK-NEXT: ssqosid 1.0 'Ssqosid' (Quality-of-Service (QoS) Identifiers) // CHECK-NEXT: ssstateen 1.0 'Ssstateen' (Supervisor-mode view of the state-enable extension) // CHECK-NEXT: ssstrict 1.0 'Ssstrict' (No non-conforming extensions are present) @@ -135,12 +141,14 @@ // CHECK-NEXT: sstvala 1.0 'Sstvala' (stval provides all needed values) // CHECK-NEXT: sstvecd 1.0 'Sstvecd' (stvec supports Direct mode) // CHECK-NEXT: ssu64xl 1.0 'Ssu64xl' (UXLEN=64 supported) +// CHECK-NEXT: supm 1.0 'Supm' (Indicates User-mode Pointer Masking) // CHECK-NEXT: svade 1.0 'Svade' (Raise exceptions on improper A/D bits) // CHECK-NEXT: svadu 1.0 'Svadu' (Hardware A/D updates) // CHECK-NEXT: svbare 1.0 'Svbare' $(satp mode Bare supported) // CHECK-NEXT: svinval 1.0 'Svinval' (Fine-Grained Address-Translation Cache Invalidation) // CHECK-NEXT: svnapot 1.0 'Svnapot' (NAPOT Translation Contiguity) // CHECK-NEXT: svpbmt 1.0 'Svpbmt' (Page-Based Memory Types) +// CHECK-NEXT: svvptc 1.0 'svvptc' (Obviating Memory-Management Instructions after Marking PTEs Valid) // CHECK-NEXT: xcvalu 1.0 'XCValu' (CORE-V ALU Operations) // CHECK-NEXT: xcvbi 1.0 'XCVbi' (CORE-V Immediate Branching) // CHECK-NEXT: xcvbitmanip 1.0 'XCVbitmanip' (CORE-V Bit Manipulation) @@ -177,26 +185,21 @@ // CHECK-NEXT: zvbc32e 0.7 'Zvbc32e' (Vector Carryless Multiplication with 32-bits elements) // CHECK-NEXT: zvkgs 0.7 'Zvkgs' (Vector-Scalar GCM instructions for Cryptography) // CHECK-NEXT: smctr 1.0 'Smctr' (Control Transfer Records Machine Level) -// CHECK-NEXT: smmpm 1.0 'Smmpm' (Machine-level Pointer Masking for M-mode) -// CHECK-NEXT: smnpm 1.0 'Smnpm' (Machine-level Pointer Masking for next lower privilege mode) // CHECK-NEXT: ssctr 1.0 'Ssctr' (Control Transfer Records Supervisor Level) -// CHECK-NEXT: ssnpm 1.0 'Ssnpm' (Supervisor-level Pointer Masking for next lower privilege mode) -// CHECK-NEXT: sspm 1.0 'Sspm' (Indicates Supervisor-mode Pointer Masking) -// CHECK-NEXT: supm 1.0 'Supm' (Indicates User-mode Pointer Masking) // CHECK-EMPTY: // CHECK-NEXT: Supported Profiles // CHECK-NEXT: rva20s64 // CHECK-NEXT: rva20u64 // CHECK-NEXT: rva22s64 // CHECK-NEXT: rva22u64 -// CHECK-NEXT: rvi20u32 -// CHECK-NEXT: rvi20u64 -// CHECK-EMPTY: -// CHECK-NEXT: Experimental Profiles // CHECK-NEXT: rva23s64 // CHECK-NEXT: rva23u64 // CHECK-NEXT: rvb23s64 // CHECK-NEXT: rvb23u64 +// CHECK-NEXT: rvi20u32 +// CHECK-NEXT: rvi20u64 +// CHECK-EMPTY: +// CHECK-NEXT: Experimental Profiles // CHECK-NEXT: rvm23u32 // CHECK-EMPTY: // CHECK-NEXT: Use -march to specify the target's extension. diff --git a/clang/test/Driver/ps5-linker.c b/clang/test/Driver/ps5-linker.c index d18309a650726d8718d1272ec9e4a7dd0ce5c03a..2080f4dc91a7fb986494769857652f5205a3043a 100644 --- a/clang/test/Driver/ps5-linker.c +++ b/clang/test/Driver/ps5-linker.c @@ -14,21 +14,32 @@ // CHECK-NO-PIE-NOT: "-pie" // CHECK-SHARED: "--shared" -// Test the driver passes PlayStation-specific -z options to the linker. - -// RUN: %clang --target=x86_64-sie-ps5 %s -### 2>&1 | FileCheck --check-prefixes=CHECK-Z %s - -// CHECK-Z: {{ld(\.exe)?}}" -// CHECK-Z-SAME: "-z" "now" -// CHECK-Z-SAME: "-z" "start-stop-visibility=hidden" -// CHECK-Z-SAME: "-z" "dead-reloc-in-nonalloc=.debug_*=0xffffffffffffffff" -// CHECK-Z-SAME: "-z" "dead-reloc-in-nonalloc=.debug_ranges=0xfffffffffffffffe" -// CHECK-Z-SAME: "-z" "dead-reloc-in-nonalloc=.debug_loc=0xfffffffffffffffe" - -// RUN: %clang --target=x86_64-sie-ps5 -r %s -### 2>&1 | FileCheck --check-prefixes=CHECK-NO-Z %s - -// CHECK-NO-Z: {{ld(\.exe)?}}" -// CHECK-NO-Z-NOT: "-z" +// Test the driver passes PlayStation-specific options to the linker that are +// appropriate for the type of output. Many options don't apply for relocatable +// output (-r). + +// RUN: %clang --target=x86_64-sie-ps5 %s -### 2>&1 | FileCheck --check-prefixes=CHECK-EXE %s +// RUN: %clang --target=x86_64-sie-ps5 %s -shared -### 2>&1 | FileCheck --check-prefixes=CHECK-EXE %s +// RUN: %clang --target=x86_64-sie-ps5 %s -static -### 2>&1 | FileCheck --check-prefixes=CHECK-EXE %s +// RUN: %clang --target=x86_64-sie-ps5 %s -r -### 2>&1 | FileCheck --check-prefixes=CHECK-NO-EXE %s + +// CHECK-EXE: {{ld(\.exe)?}}" +// CHECK-EXE-SAME: "--eh-frame-hdr" +// CHECK-EXE-SAME: "--hash-style=sysv" +// CHECK-EXE-SAME: "--build-id=uuid" +// CHECK-EXE-SAME: "--unresolved-symbols=report-all" +// CHECK-EXE-SAME: "-z" "now" +// CHECK-EXE-SAME: "-z" "start-stop-visibility=hidden" +// CHECK-EXE-SAME: "-z" "dead-reloc-in-nonalloc=.debug_*=0xffffffffffffffff" +// CHECK-EXE-SAME: "-z" "dead-reloc-in-nonalloc=.debug_ranges=0xfffffffffffffffe" +// CHECK-EXE-SAME: "-z" "dead-reloc-in-nonalloc=.debug_loc=0xfffffffffffffffe" + +// CHECK-NO-EXE: {{ld(\.exe)?}}" +// CHECK-NO-EXE-NOT: "--eh-frame-hdr" +// CHECK-NO-EXE-NOT: "--hash-style +// CHECK-NO-EXE-NOT: "--build-id +// CHECK-NO-EXE-NOT: "--unresolved-symbols +// CHECK-NO-EXE-NOT: "-z" // Test that -static is forwarded to the linker diff --git a/clang/test/Driver/renderscript.rs b/clang/test/Driver/renderscript.rs deleted file mode 100644 index 84f5dc4de777a2e339f9132bd76e3efd11c3ecdf..0000000000000000000000000000000000000000 --- a/clang/test/Driver/renderscript.rs +++ /dev/null @@ -1,3 +0,0 @@ -// RUN: %clang -### 2>&1 %s | FileCheck %s - -// CHECK: "-x" "renderscript" diff --git a/clang/test/Driver/riscv-profiles.c b/clang/test/Driver/riscv-profiles.c index 55aa5b398cee98d2ae7c17595b1470e46ef8ed3a..2b4d19422874cfb38f09d906aba3974703f3d3b7 100644 --- a/clang/test/Driver/riscv-profiles.c +++ b/clang/test/Driver/riscv-profiles.c @@ -111,7 +111,7 @@ // RVA22S64: "-target-feature" "+svinval" // RVA22S64: "-target-feature" "+svpbmt" -// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rva23u64 -menable-experimental-extensions \ +// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rva23u64 \ // RUN: | FileCheck -check-prefix=RVA23U64 %s // RVA23U64: "-target-feature" "+m" // RVA23U64: "-target-feature" "+a" @@ -148,7 +148,7 @@ // RVA23U64: "-target-feature" "+zvfhmin" // RVA23U64: "-target-feature" "+zvkt" -// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rva23s64 -menable-experimental-extensions \ +// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rva23s64 \ // RUN: | FileCheck -check-prefix=RVA23S64 %s // RVA23S64: "-target-feature" "+m" // RVA23S64: "-target-feature" "+a" @@ -195,7 +195,7 @@ // RVA23S64: "-target-feature" "+ssccptr" // RVA23S64: "-target-feature" "+sscofpmf" // RVA23S64: "-target-feature" "+sscounterenw" -// RVA23S64: "-target-feature" "+experimental-ssnpm" +// RVA23S64: "-target-feature" "+ssnpm" // RVA23S64: "-target-feature" "+ssstateen" // RVA23S64: "-target-feature" "+sstc" // RVA23S64: "-target-feature" "+sstvala" @@ -207,7 +207,7 @@ // RVA23S64: "-target-feature" "+svnapot" // RVA23S64: "-target-feature" "+svpbmt" -// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rvb23u64 -menable-experimental-extensions \ +// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rvb23u64 \ // RUN: | FileCheck -check-prefix=RVB23U64 %s // RVB23U64: "-target-feature" "+m" // RVB23U64: "-target-feature" "+a" @@ -239,7 +239,7 @@ // RVB23U64: "-target-feature" "+zbs" // RVB23U64: "-target-feature" "+zkt" -// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rvb23s64 -menable-experimental-extensions \ +// RUN: %clang --target=riscv64 -### -c %s 2>&1 -march=rvb23s64 \ // RUN: | FileCheck -check-prefix=RVB23S64 %s // RVB23S64: "-target-feature" "+m" // RVB23S64: "-target-feature" "+a" @@ -323,6 +323,6 @@ // RUN: not %clang --target=riscv64 -### -c %s 2>&1 -march=rva22u64zfa | FileCheck -check-prefix=INVALID-ADDITIONAL %s // INVALID-ADDITIONAL: error: invalid arch name 'rva22u64zfa', additional extensions must be after separator '_' -// RUN: not %clang --target=riscv64 -### -c %s 2>&1 -march=rva23u64 | FileCheck -check-prefix=EXPERIMENTAL-NOFLAG %s -// EXPERIMENTAL-NOFLAG: error: invalid arch name 'rva23u64' -// EXPERIMENTAL-NOFLAG: requires '-menable-experimental-extensions' for profile 'rva23u64' +// RUN: not %clang --target=riscv32 -### -c %s 2>&1 -march=rvm23u32 | FileCheck -check-prefix=EXPERIMENTAL-NOFLAG %s +// EXPERIMENTAL-NOFLAG: error: invalid arch name 'rvm23u32' +// EXPERIMENTAL-NOFLAG: requires '-menable-experimental-extensions' for profile 'rvm23u32' diff --git a/clang/test/Driver/unknown-std.c b/clang/test/Driver/unknown-std.c index 8f9047b2230adb5dd982def60dfbfb991780b74e..332d587ddd4a17ae8da236d7a737bc6b991be427 100644 --- a/clang/test/Driver/unknown-std.c +++ b/clang/test/Driver/unknown-std.c @@ -4,7 +4,6 @@ // RUN: not %clang %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s // RUN: not %clang -x objective-c %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s -// RUN: not %clang -x renderscript %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s // CHECK: error: invalid value 'foobar' in '-std=foobar' // CHECK-NEXT: note: use 'c89', 'c90', or 'iso9899:1990' for 'ISO C 1990' standard diff --git a/clang/test/Driver/wasm-features.c b/clang/test/Driver/wasm-features.c index 57f0fc4ef36b6b2cef3b00b9e4954eeb4ca082b8..746bd7b8dfcba43308bd78704f61848e40e3af79 100644 --- a/clang/test/Driver/wasm-features.c +++ b/clang/test/Driver/wasm-features.c @@ -94,3 +94,9 @@ // TAIL-CALL: "-target-feature" "+tail-call" // NO-TAIL-CALL: "-target-feature" "-tail-call" + +// RUN: %clang --target=wasm32-unknown-unknown -### %s -mwide-arithmetic 2>&1 | FileCheck %s -check-prefix=WIDE-ARITH +// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-wide-arithmetic 2>&1 | FileCheck %s -check-prefix=NO-WIDE-ARITH + +// WIDE-ARITH: "-target-feature" "+wide-arithmetic" +// NO-WIDE-ARITH: "-target-feature" "-wide-arithmetic" diff --git a/clang/test/Driver/x86-target-features.c b/clang/test/Driver/x86-target-features.c index ddfbb29a48f8d534cf0dab9ba3581593785a7290..02370ef60b7febb919cdfca0f8e03f9d4f01c077 100644 --- a/clang/test/Driver/x86-target-features.c +++ b/clang/test/Driver/x86-target-features.c @@ -404,6 +404,11 @@ // USERMSR: "-target-feature" "+usermsr" // NO-USERMSR: "-target-feature" "-usermsr" +// RUN: %clang --target=i386 -mmovrs %s -### -o %t.o 2>&1 | FileCheck -check-prefix=MOVRS %s +// RUN: %clang --target=i386 -mno-movrs %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-MOVRS %s +// MOVRS: "-target-feature" "+movrs" +// NO-MOVRS: "-target-feature" "-movrs" + // RUN: %clang --target=i386 -march=i386 -mcrc32 %s -### 2>&1 | FileCheck -check-prefix=CRC32 %s // RUN: %clang --target=i386 -march=i386 -mno-crc32 %s -### 2>&1 | FileCheck -check-prefix=NO-CRC32 %s // CRC32: "-target-feature" "+crc32" diff --git a/clang/test/Format/clang-format-ignore.cpp b/clang/test/Format/clang-format-ignore.cpp index fb49fa9dd52c650676e32c65507ad341442f6a04..67d68aebde5d0499378677ac81d210228b927096 100644 --- a/clang/test/Format/clang-format-ignore.cpp +++ b/clang/test/Format/clang-format-ignore.cpp @@ -46,5 +46,15 @@ // CHECK5-NEXT: {{Formatting \[4/5] .*foo\.c}} // CHECK5-NOT: foo.js +// RUN: echo "foo.*" > .clang-format-ignore +// RUN: echo "int i ;" > foo.c +// RUN: clang-format -assume-filename=foo.c < foo.c \ +// RUN: | FileCheck %s -check-prefix=CHECK6 -allow-empty +// CHECK6-NOT: int + +// RUN: clang-format -assume-filename=bar.c < foo.c \ +// RUN: | FileCheck %s -check-prefix=CHECK7 -match-full-lines +// CHECK7: int i; + // RUN: cd .. // RUN: rm -r %t.dir diff --git a/clang/test/Format/error-unfound-files.cpp b/clang/test/Format/error-unfound-files.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1cc57ed064fb429aededc05bdf1e7e8d4ee0e391 --- /dev/null +++ b/clang/test/Format/error-unfound-files.cpp @@ -0,0 +1,5 @@ +// RUN: rm -f a.c b.c + +// RUN: not clang-format a.c b.c 2>&1 | FileCheck %s +// CHECK: a.c: +// CHECK-NEXT: b.c: diff --git a/clang/test/Headers/header_unit_preprocessed_output.cpp b/clang/test/Headers/header_unit_preprocessed_output.cpp new file mode 100644 index 0000000000000000000000000000000000000000..12b4ab6159f34685318193a2306029b31b57fa21 --- /dev/null +++ b/clang/test/Headers/header_unit_preprocessed_output.cpp @@ -0,0 +1,20 @@ +// RUN: rm -fR %t +// RUN: split-file %s %t +// RUN: cd %t +// RUN: %clang_cc1 -verify -std=c++20 -emit-header-unit -xc++-user-header bz0.h +// RUN: %clang_cc1 -verify -std=c++20 -fmodule-file=bz0.pcm -xc++-user-header bz1.h -E -o bz1.output.h +// RUN: FileCheck %s < bz1.output.h +// RUN: %clang_cc1 -std=c++20 -fmodule-file=bz0.pcm -emit-header-unit -xc++-user-header bz1.output.h + +//--- bz0.h +// expected-no-diagnostics +#pragma once + +void foo(); + +//--- bz1.h +// expected-no-diagnostics +import "bz0.h"; + +// CHECK: # 1 ".{{/|\\\\?}}bz1.h" +// CHECK: import ".{{/|\\\\?}}bz0.h"; diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 914f94c08a9fd98b67282dfcfe87ccc2d0648f85..e28b0775410c0a51b9f0a7d4c03a2652c1ec5cf5 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -173,7 +173,6 @@ // CHECK-NEXT: RandomizeLayout (SubjectMatchRule_record) // CHECK-NEXT: ReadOnlyPlacement (SubjectMatchRule_record) // CHECK-NEXT: ReleaseHandle (SubjectMatchRule_variable_is_parameter) -// CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function) // CHECK-NEXT: ReqdWorkGroupSize (SubjectMatchRule_function) // CHECK-NEXT: Restrict (SubjectMatchRule_function) // CHECK-NEXT: ReturnTypestate (SubjectMatchRule_function, SubjectMatchRule_variable_is_parameter) diff --git a/clang/test/Modules/cxx20-include-translation.cpp b/clang/test/Modules/cxx20-include-translation.cpp index 7bf3184325829ec8986aeae6755265c38e5f9d6f..a607e7c0373f814cef379a6467c5abfc1f93444c 100644 --- a/clang/test/Modules/cxx20-include-translation.cpp +++ b/clang/test/Modules/cxx20-include-translation.cpp @@ -105,6 +105,6 @@ export void charlie() { } // CHECK: #pragma clang module import ".{{/|\\\\?}}h1.h" -// CHECK: import .{{/|\\\\?}}h2.h -// CHECK: import .{{/|\\\\?}}h3.h +// CHECK: import ".{{/|\\\\?}}h2.h" +// CHECK: import ".{{/|\\\\?}}h3.h" // CHECK-NOT: #pragma clang module import ".{{/|\\\\?}}h4.h" diff --git a/clang/test/Modules/no-external-type-id.cppm b/clang/test/Modules/no-external-type-id.cppm index b8b987403812f23bde7322807ea4ac0c8ae5d364..d067e574e72e37bca28714fd63419514926aa1fb 100644 --- a/clang/test/Modules/no-external-type-id.cppm +++ b/clang/test/Modules/no-external-type-id.cppm @@ -23,7 +23,7 @@ export module b; import a; export int b(); -// CHECK: &1 \ // RUN: -target wasm32-unknown-unknown -mcpu=generic \ @@ -162,8 +163,10 @@ // RUN: -target wasm64-unknown-unknown -mcpu=generic \ // RUN: | FileCheck %s -check-prefix=GENERIC-INCLUDE // +// GENERIC-INCLUDE-DAG: #define __wasm_bulk_memory__ 1{{$}} // GENERIC-INCLUDE-DAG: #define __wasm_multivalue__ 1{{$}} // GENERIC-INCLUDE-DAG: #define __wasm_mutable_globals__ 1{{$}} +// GENERIC-INCLUDE-DAG: #define __wasm_nontrapping_fptoint__ 1{{$}} // GENERIC-INCLUDE-DAG: #define __wasm_reference_types__ 1{{$}} // GENERIC-INCLUDE-DAG: #define __wasm_sign_ext__ 1{{$}} // @@ -175,15 +178,14 @@ // RUN: | FileCheck %s -check-prefix=GENERIC // // GENERIC-NOT: #define __wasm_atomics__ 1{{$}} -// GENERIC-NOT: #define __wasm_bulk_memory__ 1{{$}} // GENERIC-NOT: #define __wasm_exception_handling__ 1{{$}} // GENERIC-NOT: #define __wasm_extended_const__ 1{{$}} // GENERIC-NOT: #define __wasm__fp16__ 1{{$}} // GENERIC-NOT: #define __wasm_multimemory__ 1{{$}} -// GENERIC-NOT: #define __wasm_nontrapping_fptoint__ 1{{$}} // GENERIC-NOT: #define __wasm_relaxed_simd__ 1{{$}} // GENERIC-NOT: #define __wasm_simd128__ 1{{$}} // GENERIC-NOT: #define __wasm_tail_call__ 1{{$}} +// GENERIC-NOT: #define __wasm_wide_arithmetic__ 1{{$}} // RUN: %clang -E -dM %s -o - 2>&1 \ // RUN: -target wasm32-unknown-unknown -mcpu=bleeding-edge \ @@ -206,6 +208,7 @@ // BLEEDING-EDGE-INCLUDE-DAG: #define __wasm_sign_ext__ 1{{$}} // BLEEDING-EDGE-INCLUDE-DAG: #define __wasm_simd128__ 1{{$}} // BLEEDING-EDGE-INCLUDE-DAG: #define __wasm_tail_call__ 1{{$}} +// BLEEDING-EDGE-INCLUDE-DAG: #define __wasm_wide_arithmetic__ 1{{$}} // RUN: %clang -E -dM %s -o - 2>&1 \ // RUN: -target wasm32-unknown-unknown -mcpu=bleeding-edge -mno-simd128 \ @@ -215,3 +218,12 @@ // RUN: | FileCheck %s -check-prefix=BLEEDING-EDGE-NO-SIMD128 // // BLEEDING-EDGE-NO-SIMD128-NOT: #define __wasm_simd128__ 1{{$}} + +// RUN: %clang -E -dM %s -o - 2>&1 \ +// RUN: -target wasm32-unknown-unknown -mwide-arithmetic \ +// RUN: | FileCheck %s -check-prefix=WIDE-ARITHMETIC +// RUN: %clang -E -dM %s -o - 2>&1 \ +// RUN: -target wasm64-unknown-unknown -mwide-arithmetic \ +// RUN: | FileCheck %s -check-prefix=WIDE-ARITHMETIC +// +// WIDE-ARITHMETIC: #define __wasm_wide_arithmetic__ 1{{$}} diff --git a/clang/test/Preprocessor/x86_target_features.c b/clang/test/Preprocessor/x86_target_features.c index 8b4e6bdc09226a7528237635c7cc735115fc1ca3..2d1d2e57bdc7728de5ac46a8715cf4808b540c36 100644 --- a/clang/test/Preprocessor/x86_target_features.c +++ b/clang/test/Preprocessor/x86_target_features.c @@ -740,6 +740,12 @@ // RUN: %clang -target i686-unknown-linux-gnu -march=atom -mno-usermsr -x c -E -dM -o - %s | FileCheck -check-prefix=NO-USERMSR %s // NO-USERMSR-NOT: #define __USERMSR__ 1 +// RUN: %clang -target i686-unknown-linux-gnu -march=atom -mmovrs -x c -E -dM -o - %s | FileCheck -check-prefix=MOVRS %s +// MOVRS: #define __MOVRS__ 1 + +// RUN: %clang -target i686-unknown-linux-gnu -march=atom -mno-movrs -x c -E -dM -o - %s | FileCheck -check-prefix=NO-MOVRS %s +// NO-MOVRS-NOT: #define __MOVRS__ 1 + // RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mcrc32 -x c -E -dM -o - %s | FileCheck -check-prefix=CRC32 %s // CRC32: #define __CRC32__ 1 diff --git a/clang/test/Sema/arithmetic-fence-builtin.c b/clang/test/Sema/arithmetic-fence-builtin.c index a1941970edb53c0c6f4bf3a8cb27c74065a9e611..55867ffb5e012cd1b102190bdc7c26e487d91d81 100644 --- a/clang/test/Sema/arithmetic-fence-builtin.c +++ b/clang/test/Sema/arithmetic-fence-builtin.c @@ -1,8 +1,13 @@ // RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o - -verify -x c++ %s +// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o - -verify -x c++ %s -fexperimental-new-constant-interpreter // RUN: %clang_cc1 -triple ppc64le -DPPC -emit-llvm -o - -verify -x c++ %s +// RUN: %clang_cc1 -triple ppc64le -DPPC -emit-llvm -o - -verify -x c++ %s -fexperimental-new-constant-interpreter // RUN: not %clang_cc1 -triple ppc64le -DPPC -emit-llvm -o - -x c++ %s \ // RUN: -fprotect-parens 2>&1 | FileCheck -check-prefix=PPC %s +// RUN: not %clang_cc1 -triple ppc64le -DPPC -emit-llvm -o - -x c++ %s -fexperimental-new-constant-interpreter \ +// RUN: -fprotect-parens 2>&1 | FileCheck -check-prefix=PPC %s // RUN: %clang_cc1 -triple spir64 -emit-llvm -o - -verify -x c++ %s +// RUN: %clang_cc1 -triple spir64 -emit-llvm -o - -verify -x c++ %s -fexperimental-new-constant-interpreter #ifndef PPC int v; template T addT(T a, T b) { diff --git a/clang/test/Sema/arm-mfp8.c b/clang/test/Sema/arm-mfp8.c new file mode 100644 index 0000000000000000000000000000000000000000..e917078f50ed7e5296e6eae34e4bf67e1bd24348 --- /dev/null +++ b/clang/test/Sema/arm-mfp8.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64-arm-none-eabi -target-feature -fp8 %s + +// REQUIRES: aarch64-registered-target +#include +__mfp8 test_cast_from_float(unsigned in) { + return (__mfp8)in; // expected-error {{used type '__mfp8' (aka '__MFloat8_t') where arithmetic or pointer type is required}} +} + +unsigned test_cast_to_int(__mfp8 in) { + return (unsigned)in; // expected-error {{operand of type '__mfp8' (aka '__MFloat8_t') where arithmetic or pointer type is required}} +} diff --git a/clang/test/Sema/arm-mfp8.cpp b/clang/test/Sema/arm-mfp8.cpp index f270168faceb328383608ab9235d56cf8d164856..e882c382522c22355bac7eda668d5f63f6b01994 100644 --- a/clang/test/Sema/arm-mfp8.cpp +++ b/clang/test/Sema/arm-mfp8.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify=sve,neon -triple aarch64-arm-none-eabi \ +// RUN: %clang_cc1 -fsyntax-only -verify=sve,neon,scalar -triple aarch64-arm-none-eabi \ // RUN: -target-feature -fp8 -target-feature +sve -target-feature +neon %s // REQUIRES: aarch64-registered-target @@ -29,3 +29,35 @@ void test_vector(mfloat8x8_t a, mfloat8x16_t b, uint8x8_t c) { c * b; // neon-error {{cannot convert between vector and non-scalar values ('uint8x8_t' (vector of 8 'uint8_t' values) and 'mfloat8x16_t' (aka '__MFloat8x16_t'))}} c / b; // neon-error {{cannot convert between vector and non-scalar values ('uint8x8_t' (vector of 8 'uint8_t' values) and 'mfloat8x16_t' (aka '__MFloat8x16_t'))}} } +__mfp8 test_static_cast_from_char(char in) { + return static_cast<__mfp8>(in); // scalar-error {{static_cast from 'char' to '__mfp8' (aka '__MFloat8_t') is not allowed}} +} + +char test_static_cast_to_char(__mfp8 in) { + return static_cast(in); // scalar-error {{static_cast from '__mfp8' (aka '__MFloat8_t') to 'char' is not allowed}} +} +void test(bool b) { + __mfp8 mfp8; + + mfp8 + mfp8; // scalar-error {{invalid operands to binary expression ('__mfp8' (aka '__MFloat8_t') and '__mfp8')}} + mfp8 - mfp8; // scalar-error {{invalid operands to binary expression ('__mfp8' (aka '__MFloat8_t') and '__mfp8')}} + mfp8 * mfp8; // scalar-error {{invalid operands to binary expression ('__mfp8' (aka '__MFloat8_t') and '__mfp8')}} + mfp8 / mfp8; // scalar-error {{invalid operands to binary expression ('__mfp8' (aka '__MFloat8_t') and '__mfp8')}} + ++mfp8; // scalar-error {{cannot increment value of type '__mfp8' (aka '__MFloat8_t')}} + --mfp8; // scalar-error {{cannot decrement value of type '__mfp8' (aka '__MFloat8_t')}} + + char u8; + + mfp8 + u8; // scalar-error {{invalid operands to binary expression ('__mfp8' (aka '__MFloat8_t') and 'char')}} + u8 + mfp8; // scalar-error {{invalid operands to binary expression ('char' and '__mfp8' (aka '__MFloat8_t'))}} + mfp8 - u8; // scalar-error {{invalid operands to binary expression ('__mfp8' (aka '__MFloat8_t') and 'char')}} + u8 - mfp8; // scalar-error {{invalid operands to binary expression ('char' and '__mfp8' (aka '__MFloat8_t'))}} + mfp8 * u8; // scalar-error {{invalid operands to binary expression ('__mfp8' (aka '__MFloat8_t') and 'char')}} + u8 * mfp8; // scalar-error {{invalid operands to binary expression ('char' and '__mfp8' (aka '__MFloat8_t'))}} + mfp8 / u8; // scalar-error {{invalid operands to binary expression ('__mfp8' (aka '__MFloat8_t') and 'char')}} + u8 / mfp8; // scalar-error {{invalid operands to binary expression ('char' and '__mfp8' (aka '__MFloat8_t'))}} + mfp8 = u8; // scalar-error {{assigning to '__mfp8' (aka '__MFloat8_t') from incompatible type 'char'}} + u8 = mfp8; // scalar-error {{assigning to 'char' from incompatible type '__mfp8' (aka '__MFloat8_t')}} + mfp8 + (b ? u8 : mfp8); // scalar-error {{incompatible operand types ('char' and '__mfp8' (aka '__MFloat8_t'))}} +} + diff --git a/clang/test/Sema/asm.c b/clang/test/Sema/asm.c index 6cd95c71604d44356e8aa08af95feb9f30415b9c..28ef3ec6ce09c2a6bee95b7b3654f13e9ccc35a7 100644 --- a/clang/test/Sema/asm.c +++ b/clang/test/Sema/asm.c @@ -204,6 +204,12 @@ double f_output_constraint(void) { return result; } +double f_output_constraint_2(void) { + double result; + __asm("foo1": "+f" (result)); // expected-error {{invalid output constraint '+f' in asm}} + return result; +} + void fn1(void) { int l; __asm__("" diff --git a/clang/test/Sema/renderscript.rs b/clang/test/Sema/renderscript.rs deleted file mode 100644 index 8fa0d4389e7f1f8c490d19c0929fd1e262bb7846..0000000000000000000000000000000000000000 --- a/clang/test/Sema/renderscript.rs +++ /dev/null @@ -1,25 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -x renderscript -D__RENDERSCRIPT__ %s -// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -verify -x c %s -// REQUIRES: x86-registered-target - -#ifndef __RENDERSCRIPT__ -// expected-warning@+2 {{'kernel' attribute ignored}} -#endif -void __attribute__((kernel)) kernel(void) {} - -#ifndef __RENDERSCRIPT__ -// expected-warning@+4 {{'kernel' attribute ignored}} -#else -// expected-warning@+2 {{'kernel' attribute only applies to functions}} -#endif -int __attribute__((kernel)) global; - -#ifndef __RENDERSCRIPT__ -// expected-error@+2 {{function return value cannot have __fp16 type; did you forget * ?}} -#endif -__fp16 fp16_return(void); - -#ifndef __RENDERSCRIPT__ -// expected-error@+2 {{parameters cannot have __fp16 type; did you forget * ?}} -#endif -void fp16_arg(__fp16 p); diff --git a/clang/test/SemaCXX/amdgpu-barrier.cpp b/clang/test/SemaCXX/amdgpu-barrier.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a171433727dda41ef4adbc4ea491a9507aac9d68 --- /dev/null +++ b/clang/test/SemaCXX/amdgpu-barrier.cpp @@ -0,0 +1,17 @@ +// REQUIRES: amdgpu-registered-target +// RUN: %clang_cc1 -fsyntax-only -verify -std=gnu++11 -triple amdgcn -Wno-unused-value %s + +void foo() { + int n = 100; + __amdgpu_named_workgroup_barrier_t v = 0; // expected-error {{cannot initialize a variable of type '__amdgpu_named_workgroup_barrier_t' with an rvalue of type 'int'}} + static_cast<__amdgpu_named_workgroup_barrier_t>(n); // expected-error {{static_cast from 'int' to '__amdgpu_named_workgroup_barrier_t' is not allowed}} + dynamic_cast<__amdgpu_named_workgroup_barrier_t>(n); // expected-error {{invalid target type '__amdgpu_named_workgroup_barrier_t' for dynamic_cast; target type must be a reference or pointer type to a defined class}} + reinterpret_cast<__amdgpu_named_workgroup_barrier_t>(n); // expected-error {{reinterpret_cast from 'int' to '__amdgpu_named_workgroup_barrier_t' is not allowed}} + int c(v); // expected-error {{cannot initialize a variable of type 'int' with an lvalue of type '__amdgpu_named_workgroup_barrier_t'}} + __amdgpu_named_workgroup_barrier_t k; + int *ip = (int *)k; // expected-error {{cannot cast from type '__amdgpu_named_workgroup_barrier_t' to pointer type 'int *'}} + void *vp = (void *)k; // expected-error {{cannot cast from type '__amdgpu_named_workgroup_barrier_t' to pointer type 'void *'}} +} + +static_assert(sizeof(__amdgpu_named_workgroup_barrier_t) == 16, "wrong size"); +static_assert(alignof(__amdgpu_named_workgroup_barrier_t) == 4, "wrong alignment"); diff --git a/clang/test/SemaCXX/attr-lifetimebound.cpp b/clang/test/SemaCXX/attr-lifetimebound.cpp index 1c5c79777c71c8d2e402ae2e3fb695ea9735a1e3..804d61fb62ca402ab5d9624df336094699b9246b 100644 --- a/clang/test/SemaCXX/attr-lifetimebound.cpp +++ b/clang/test/SemaCXX/attr-lifetimebound.cpp @@ -1,8 +1,7 @@ // RUN: %clang_cc1 -std=c++23 -verify %s namespace usage_invalid { - // FIXME: Should we diagnose a void return type? - void voidreturn(int ¶m [[clang::lifetimebound]]); + void void_return(int ¶m [[clang::lifetimebound]]); // expected-error {{'lifetimebound' attribute cannot be applied to a parameter of a function that returns void}} int *not_class_member() [[clang::lifetimebound]]; // expected-error {{non-member function has no implicit object parameter}} struct A { @@ -12,6 +11,8 @@ namespace usage_invalid { int *explicit_object(this A&) [[clang::lifetimebound]]; // expected-error {{explicit object member function has no implicit object parameter}} int not_function [[clang::lifetimebound]]; // expected-error {{only applies to parameters and implicit object parameters}} int [[clang::lifetimebound]] also_not_function; // expected-error {{cannot be applied to types}} + // FIXME: Should diagnose a void return type. + void void_return_member() [[clang::lifetimebound]]; }; int *attr_with_param(int ¶m [[clang::lifetimebound(42)]]); // expected-error {{takes no arguments}} } @@ -31,6 +32,13 @@ namespace usage_ok { return *(int*)param; } + template R dependent_void(const T& t [[clang::lifetimebound]]); + void dependent_void_instantiation() { + dependent_void(1); // OK: Returns void. + int x = dependent_void(1); // expected-warning {{temporary whose address is used as value of local variable 'x' will be destroyed at the end of the full-expression}} + dependent_void(1); // OK: Returns an unused value. + } + struct A { A(); A(int); diff --git a/clang/test/SemaCXX/conditional-expr.cpp b/clang/test/SemaCXX/conditional-expr.cpp index 01effaa189322bce39b24e42c3771ea96e66ba9b..8f17555fd806ff8aace49cf18b29df71d0a6fe4e 100644 --- a/clang/test/SemaCXX/conditional-expr.cpp +++ b/clang/test/SemaCXX/conditional-expr.cpp @@ -429,3 +429,10 @@ void g() { long e = a = b ? throw 0 : throw 1; } } // namespace PR46484 + +namespace GH111854 { +void f() { + (true ? throw 0 : 0) <= 0; // expected-warning {{relational comparison result unused}} + (false ? 0 : throw 0) <= 0; // expected-warning {{relational comparison result unused}} +} +} diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index e2ea984b37cd049f623d3c1867e2596f980ec0c5..0c349333d89d44f47e7da5c54b2d4a511b7422ea 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -2564,3 +2564,13 @@ GH50055::E2 GlobalInitNotCE2 = GH50055::testDefaultArgForParam(); // ok, not a c constexpr GH50055::E2 GlobalInitCE = (GH50055::E2)-1; // expected-error@-1 {{constexpr variable 'GlobalInitCE' must be initialized by a constant expression}} // expected-note@-2 {{integer value -1 is outside the valid range of values [0, 7] for the enumeration type 'E2'}} + +namespace GH112140 { +struct S { + constexpr S(const int &a = ) { } // expected-error {{expected expression}} +}; + +void foo() { + constexpr S s[2] = { }; // expected-error {{constexpr variable 's' must be initialized by a constant expression}} +} +} diff --git a/clang/test/SemaCXX/constexpr-string.cpp b/clang/test/SemaCXX/constexpr-string.cpp index c456740ef7551f70c930ce64f5782ac351232896..5448365489a514d102cdf69720503f052b183887 100644 --- a/clang/test/SemaCXX/constexpr-string.cpp +++ b/clang/test/SemaCXX/constexpr-string.cpp @@ -670,6 +670,8 @@ namespace MemcpyEtc { constexpr bool test_address_of_incomplete_struct_type() { // expected-error {{never produces a constant}} struct Incomplete; extern Incomplete x, y; + // expected-warning@+2 {{first argument in call to '__builtin_memcpy' is a pointer to non-trivially copyable type 'Incomplete'}} + // expected-note@+1 {{explicitly cast the pointer to silence this warning}} __builtin_memcpy(&x, &x, 4); // expected-note@-1 2{{cannot constant evaluate 'memcpy' between objects of incomplete type 'Incomplete'}} return true; diff --git a/clang/test/SemaCXX/deprecated.cpp b/clang/test/SemaCXX/deprecated.cpp index a93331023f7e21d833814824fd57963a6fe71514..667f4d7d3edb03a4df734bdd88e1398d30154310 100644 --- a/clang/test/SemaCXX/deprecated.cpp +++ b/clang/test/SemaCXX/deprecated.cpp @@ -260,5 +260,25 @@ namespace ArrayComp { bool b7 = arr1 == +f(); } +namespace GH90073 { +[[deprecated]] int f1() { // expected-note {{'f1' has been explicitly marked deprecated here}} + [[deprecated]] int a; // expected-note {{'a' has been explicitly marked deprecated here}} \ + // expected-note {{'a' has been explicitly marked deprecated here}} + a = 0; // expected-warning {{'a' is deprecated}} + return a; // expected-warning {{'a' is deprecated}} +} + +[[deprecated]] void f2([[deprecated]] int x) { // expected-note {{'f2' has been explicitly marked deprecated here}} \ + // expected-note {{'x' has been explicitly marked deprecated here}} + x = 4; // expected-warning {{'x' is deprecated}} +} + +int main() { + f1(); // expected-warning {{'f1' is deprecated}} + f2(1); // expected-warning {{'f2' is deprecated}} + return 0; +} +} + # 1 "/usr/include/system-header.h" 1 3 void system_header_function(void) throw(); diff --git a/clang/test/SemaCXX/warn-memaccess.cpp b/clang/test/SemaCXX/warn-memaccess.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b4b7f6a6905b23e92e50eeb888fcd67bbc271b39 --- /dev/null +++ b/clang/test/SemaCXX/warn-memaccess.cpp @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wnontrivial-memaccess %s + +extern "C" void *bzero(void *, unsigned); +extern "C" void *memset(void *, int, unsigned); +extern "C" void *memmove(void *s1, const void *s2, unsigned n); +extern "C" void *memcpy(void *s1, const void *s2, unsigned n); + +class TriviallyCopyable {}; +class NonTriviallyCopyable { NonTriviallyCopyable(const NonTriviallyCopyable&);}; + +void test_bzero(TriviallyCopyable* tc, + NonTriviallyCopyable *ntc) { + // OK + bzero(tc, sizeof(*tc)); + + // expected-warning@+2{{first argument in call to 'bzero' is a pointer to non-trivially copyable type 'NonTriviallyCopyable'}} + // expected-note@+1{{explicitly cast the pointer to silence this warning}} + bzero(ntc, sizeof(*ntc)); + + // OK + bzero((void*)ntc, sizeof(*ntc)); +} + +void test_memset(TriviallyCopyable* tc, + NonTriviallyCopyable *ntc) { + // OK + memset(tc, 0, sizeof(*tc)); + + // expected-warning@+2{{first argument in call to 'memset' is a pointer to non-trivially copyable type 'NonTriviallyCopyable'}} + // expected-note@+1{{explicitly cast the pointer to silence this warning}} + memset(ntc, 0, sizeof(*ntc)); + + // OK + memset((void*)ntc, 0, sizeof(*ntc)); +} + + +void test_memcpy(TriviallyCopyable* tc0, TriviallyCopyable* tc1, + NonTriviallyCopyable *ntc0, NonTriviallyCopyable *ntc1) { + // OK + memcpy(tc0, tc1, sizeof(*tc0)); + + // expected-warning@+2{{first argument in call to 'memcpy' is a pointer to non-trivially copyable type 'NonTriviallyCopyable'}} + // expected-note@+1{{explicitly cast the pointer to silence this warning}} + memcpy(ntc0, ntc1, sizeof(*ntc0)); + + // ~ OK + memcpy((void*)ntc0, ntc1, sizeof(*ntc0)); + + // OK + memcpy((void*)ntc0, (void*)ntc1, sizeof(*ntc0)); +} + +void test_memmove(TriviallyCopyable* tc0, TriviallyCopyable* tc1, + NonTriviallyCopyable *ntc0, NonTriviallyCopyable *ntc1) { + // OK + memmove(tc0, tc1, sizeof(*tc0)); + + // expected-warning@+2{{first argument in call to 'memmove' is a pointer to non-trivially copyable type 'NonTriviallyCopyable'}} + // expected-note@+1{{explicitly cast the pointer to silence this warning}} + memmove(ntc0, ntc1, sizeof(*ntc0)); + + // ~ OK + memmove((void*)ntc0, ntc1, sizeof(*ntc0)); + + // OK + memmove((void*)ntc0, (void*)ntc1, sizeof(*ntc0)); +} diff --git a/clang/test/SemaHIP/amdgpu-barrier.hip b/clang/test/SemaHIP/amdgpu-barrier.hip new file mode 100644 index 0000000000000000000000000000000000000000..ccd99b1e2c1f2614f8cb44f75b63f57b11d2de95 --- /dev/null +++ b/clang/test/SemaHIP/amdgpu-barrier.hip @@ -0,0 +1,20 @@ +// REQUIRES: amdgpu-registered-target +// RUN: %clang_cc1 -fsyntax-only -verify -triple amdgcn -Wno-unused-value %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64 -aux-triple amdgcn -Wno-unused-value %s + +#define __device__ __attribute__((device)) + +__device__ void foo() { + int n = 100; + __amdgpu_named_workgroup_barrier_t v = 0; // expected-error {{cannot initialize a variable of type '__amdgpu_named_workgroup_barrier_t' with an rvalue of type 'int'}} + static_cast<__amdgpu_named_workgroup_barrier_t>(n); // expected-error {{static_cast from 'int' to '__amdgpu_named_workgroup_barrier_t' is not allowed}} + dynamic_cast<__amdgpu_named_workgroup_barrier_t>(n); // expected-error {{invalid target type '__amdgpu_named_workgroup_barrier_t' for dynamic_cast; target type must be a reference or pointer type to a defined class}} + reinterpret_cast<__amdgpu_named_workgroup_barrier_t>(n); // expected-error {{reinterpret_cast from 'int' to '__amdgpu_named_workgroup_barrier_t' is not allowed}} + int c(v); // expected-error {{cannot initialize a variable of type 'int' with an lvalue of type '__amdgpu_named_workgroup_barrier_t'}} + __amdgpu_named_workgroup_barrier_t k; + int *ip = (int *)k; // expected-error {{cannot cast from type '__amdgpu_named_workgroup_barrier_t' to pointer type 'int *'}} + void *vp = (void *)k; // expected-error {{cannot cast from type '__amdgpu_named_workgroup_barrier_t' to pointer type 'void *'}} +} + +static_assert(sizeof(__amdgpu_named_workgroup_barrier_t) == 16, "wrong size"); +static_assert(alignof(__amdgpu_named_workgroup_barrier_t) == 4, "wrong alignment"); diff --git a/clang/test/SemaHLSL/BuiltIns/asuint-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/asuint-errors.hlsl index 8c56fdddb1c24c55386d6ff2cd6f1cf71f6772a0..4adb0555c35be6071fbf7449e0389959110d6862 100644 --- a/clang/test/SemaHLSL/BuiltIns/asuint-errors.hlsl +++ b/clang/test/SemaHLSL/BuiltIns/asuint-errors.hlsl @@ -6,6 +6,10 @@ uint4 test_asuint_too_many_arg(float p0, float p1) { // expected-error@-1 {{no matching function for call to 'asuint'}} // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires single argument 'V', but 2 arguments were provided}} // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires single argument 'F', but 2 arguments were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 3 arguments, but 2 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 3 arguments, but 2 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 3 arguments, but 2 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 3 arguments, but 2 were provided}} } uint test_asuint_double(double p1) { @@ -23,3 +27,29 @@ uint test_asuint_half(half p1) { // expected-note@hlsl/hlsl_detail.h:* {{candidate template ignored: could not match 'vector' against 'half'}} // expected-note@hlsl/hlsl_detail.h:* {{candidate template ignored: substitution failure [with U = uint, T = half]: no type named 'Type'}} } + +void test_asuint_first_arg_const(double D) { + const uint A = 0; + uint B; + asuint(D, A, B); + // expected-error@hlsl/hlsl_intrinsics.h:* {{read-only variable is not assignable}} +} + +void test_asuint_second_arg_const(double D) { + const uint A = 0; + uint B; + asuint(D, B, A); + // expected-error@hlsl/hlsl_intrinsics.h:* {{read-only variable is not assignable}} +} + +void test_asuint_imidiate_value(double D) { + uint B; + asuint(D, B, 1); + // expected-error@-1 {{cannot bind non-lvalue argument 1 to out paramemter}} +} + +void test_asuint_expr(double D) { + uint B; + asuint(D, B, B + 1); + // expected-error@-1 {{cannot bind non-lvalue argument B + 1 to out paramemter}} +} diff --git a/clang/test/SemaHLSL/BuiltIns/splitdouble-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/splitdouble-errors.hlsl new file mode 100644 index 0000000000000000000000000000000000000000..18d2b692b335b9b1d8e5fc3c1c817928c71dc266 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/splitdouble-errors.hlsl @@ -0,0 +1,76 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -verify + +void test_no_second_arg(double D) { + __builtin_hlsl_elementwise_splitdouble(D); + // expected-error@-1 {{too few arguments to function call, expected 3, have 1}} +} + +void test_no_third_arg(double D) { + uint A; + __builtin_hlsl_elementwise_splitdouble(D, A); + // expected-error@-1 {{too few arguments to function call, expected 3, have 2}} +} + +void test_too_many_arg(double D) { + uint A, B, C; + __builtin_hlsl_elementwise_splitdouble(D, A, B, C); + // expected-error@-1 {{too many arguments to function call, expected 3, have 4}} +} + +void test_first_arg_type_mismatch(bool3 D) { + uint3 A, B; + __builtin_hlsl_elementwise_splitdouble(D, A, B); + // expected-error@-1 {{invalid operand of type 'bool3' (aka 'vector') where 'double' or a vector of such type is required}} +} + +void test_second_arg_type_mismatch(double D) { + bool A; + uint B; + __builtin_hlsl_elementwise_splitdouble(D, A, B); + // expected-error@-1 {{invalid operand of type 'bool' where 'unsigned int' or a vector of such type is required}} +} + +void test_third_arg_type_mismatch(double D) { + bool A; + uint B; + __builtin_hlsl_elementwise_splitdouble(D, B, A); + // expected-error@-1 {{invalid operand of type 'bool' where 'unsigned int' or a vector of such type is required}} +} + +void test_const_second_arg(double D) { + const uint A = 1; + uint B; + __builtin_hlsl_elementwise_splitdouble(D, A, B); + // expected-error@-1 {{cannot bind non-lvalue argument A to out paramemter}} +} + +void test_const_third_arg(double D) { + uint A; + const uint B = 1; + __builtin_hlsl_elementwise_splitdouble(D, A, B); + // expected-error@-1 {{cannot bind non-lvalue argument B to out paramemter}} +} + +void test_number_second_arg(double D) { + uint B; + __builtin_hlsl_elementwise_splitdouble(D, (uint)1, B); + // expected-error@-1 {{cannot bind non-lvalue argument (uint)1 to out paramemter}} +} + +void test_number_third_arg(double D) { + uint B; + __builtin_hlsl_elementwise_splitdouble(D, B, (uint)1); + // expected-error@-1 {{cannot bind non-lvalue argument (uint)1 to out paramemter}} +} + +void test_expr_second_arg(double D) { + uint B; + __builtin_hlsl_elementwise_splitdouble(D, B+1, B); + // expected-error@-1 {{cannot bind non-lvalue argument B + 1 to out paramemter}} +} + +void test_expr_third_arg(double D) { + uint B; + __builtin_hlsl_elementwise_splitdouble(D, B, B+1); + // expected-error@-1 {{cannot bind non-lvalue argument B + 1 to out paramemter}} +} diff --git a/clang/test/SemaOpenCL/amdgpu-barrier.cl b/clang/test/SemaOpenCL/amdgpu-barrier.cl new file mode 100644 index 0000000000000000000000000000000000000000..150c311c7c593032085252cd843921aea02d36de --- /dev/null +++ b/clang/test/SemaOpenCL/amdgpu-barrier.cl @@ -0,0 +1,12 @@ +// REQUIRES: amdgpu-registered-target +// RUN: %clang_cc1 -verify -cl-std=CL1.2 -triple amdgcn-amd-amdhsa -Wno-unused-value %s +// RUN: %clang_cc1 -verify -cl-std=CL2.0 -triple amdgcn-amd-amdhsa -Wno-unused-value %s + +void foo() { + int n = 100; + __amdgpu_named_workgroup_barrier_t v = 0; // expected-error {{initializing '__private __amdgpu_named_workgroup_barrier_t' with an expression of incompatible type 'int'}} + int c = v; // expected-error {{initializing '__private int' with an expression of incompatible type '__private __amdgpu_named_workgroup_barrier_t'}} + __amdgpu_named_workgroup_barrier_t k; + int *ip = (int *)k; // expected-error {{operand of type '__amdgpu_named_workgroup_barrier_t' where arithmetic or pointer type is required}} + void *vp = (void *)k; // expected-error {{operand of type '__amdgpu_named_workgroup_barrier_t' where arithmetic or pointer type is required}} + } diff --git a/clang/test/SemaOpenMP/amdgpu-barrier.cpp b/clang/test/SemaOpenMP/amdgpu-barrier.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70aaefd080885e6a2af788053e0cb86b0c01c582 --- /dev/null +++ b/clang/test/SemaOpenMP/amdgpu-barrier.cpp @@ -0,0 +1,17 @@ +// REQUIRES: amdgpu-registered-target +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -triple amdgcn-amd-amdhsa -fopenmp-is-target-device -Wno-unused-value %s + +void foo() { +#pragma omp target + { + int n = 100; + __amdgpu_named_workgroup_barrier_t v = 0; // expected-error {{cannot initialize a variable of type '__amdgpu_named_workgroup_barrier_t' with an rvalue of type 'int'}} + static_cast<__amdgpu_named_workgroup_barrier_t>(n); // expected-error {{static_cast from 'int' to '__amdgpu_named_workgroup_barrier_t' is not allowed}} + dynamic_cast<__amdgpu_named_workgroup_barrier_t>(n); // expected-error {{invalid target type '__amdgpu_named_workgroup_barrier_t' for dynamic_cast; target type must be a reference or pointer type to a defined class}} + reinterpret_cast<__amdgpu_named_workgroup_barrier_t>(n); // expected-error {{reinterpret_cast from 'int' to '__amdgpu_named_workgroup_barrier_t' is not allowed}} + int c(v); // expected-error {{cannot initialize a variable of type 'int' with an lvalue of type '__amdgpu_named_workgroup_barrier_t'}} + __amdgpu_named_workgroup_barrier_t k; + int *ip = (int *)k; // expected-error {{cannot cast from type '__amdgpu_named_workgroup_barrier_t' to pointer type 'int *'}} + void *vp = (void *)k; // expected-error {{cannot cast from type '__amdgpu_named_workgroup_barrier_t' to pointer type 'void *'}} + } + } diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index 108db7204aa68aa4d009d0e1558546c3e7d2ac03..cc735e48725921c43f92bb92126eb5a2d1e8f040 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -410,7 +410,7 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { const bool IsSTDIN = FileName == "-"; if (!OutputXML && Inplace && IsSTDIN) { errs() << "error: cannot use -i when reading from stdin.\n"; - return false; + return true; } // On Windows, overwriting a file with an open file mapping doesn't work, // so read the whole file into memory when formatting in-place. @@ -419,7 +419,7 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { ? MemoryBuffer::getFileAsStream(FileName) : MemoryBuffer::getFileOrSTDIN(FileName, /*IsText=*/true); if (std::error_code EC = CodeOrErr.getError()) { - errs() << EC.message() << "\n"; + errs() << FileName << ": " << EC.message() << "\n"; return true; } std::unique_ptr Code = std::move(CodeOrErr.get()); @@ -510,7 +510,7 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); Replaces = Replaces.merge(FormatChanges); if (DryRun) { - return Replaces.size() > (IsJson ? 1 : 0) && + return Replaces.size() > (IsJson ? 1u : 0u) && emitReplacementWarnings(Replaces, AssumedFileName, Code); } if (OutputXML) { @@ -707,8 +707,11 @@ int main(int argc, const char **argv) { errs() << "Clang-formatting " << LineNo << " files\n"; } - if (FileNames.empty()) + if (FileNames.empty()) { + if (isIgnored(AssumeFileName)) + return 0; return clang::format::format("-", FailOnIncompleteFormat); + } if (FileNames.size() > 1 && (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) { diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp index af8dc71a38fb0883c74609049435bd2c9144e1ff..1653904d1afe384146f3c0a9eec195243218ebc5 100644 --- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp +++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp @@ -370,6 +370,8 @@ Error runLinker(ArrayRef Files, const ArgList &Args) { // Render the linker arguments and add the newly created image. We add it // after the output file to ensure it is linked with the correct libraries. StringRef LinkerPath = Args.getLastArgValue(OPT_linker_path_EQ); + if (LinkerPath.empty()) + return createStringError("linker path missing, must pass 'linker-path'"); ArgStringList NewLinkerArgs; for (const opt::Arg *Arg : Args) { // Do not forward arguments only intended for the linker wrapper. diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp index 7d36cee7a22b39119ecee5f0a42115780672474c..f474b1346b1be108bd5a4711c935a22e06e40032 100644 --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -1080,10 +1080,15 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { << NumExistsCalls << " exists() calls\n" << NumIsLocalCalls << " isLocal() calls\n"; - if (PrintTiming) - llvm::errs() << llvm::format( - "clang-scan-deps timing: %0.2fs wall, %0.2fs process\n", - T.getTotalTime().getWallTime(), T.getTotalTime().getProcessTime()); + if (PrintTiming) { + llvm::errs() << "wall time [s]\t" + << "process time [s]\t" + << "instruction count\n"; + const llvm::TimeRecord &R = T.getTotalTime(); + llvm::errs() << llvm::format("%0.4f", R.getWallTime()) << "\t" + << llvm::format("%0.4f", R.getProcessTime()) << "\t" + << llvm::format("%llu", R.getInstructionsExecuted()) << "\n"; + } if (RoundTripArgs) if (FD && FD->roundTripCommands(llvm::errs())) diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index d61d430b537ba32b81aeb07fe707ea0b1eb1daab..98afabfdceff3cc6451fc4c243275e2292f71286 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -4296,8 +4296,7 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, LibclangInvocationReporter InvocationReporter( *CXXIdx, LibclangInvocationReporter::OperationKind::ParseOperation, - options, llvm::ArrayRef(*Args), /*InvocationArgs=*/std::nullopt, - unsaved_files); + options, llvm::ArrayRef(*Args), /*InvocationArgs=*/{}, unsaved_files); std::unique_ptr Unit = ASTUnit::LoadFromCommandLine( Args->data(), Args->data() + Args->size(), CXXIdx->getPCHContainerOperations(), Diags, diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp index 0209703395bc1140f5f5ed822c54466b4e43310d..de16f6be8eedbc910f3d5d26db0b8031c6724856 100644 --- a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp @@ -1282,28 +1282,35 @@ static raw_ostream &operator<<(raw_ostream &OS, class UncheckedOptionalAccessTest : public ::testing::TestWithParam { protected: - void ExpectDiagnosticsFor(std::string SourceCode) { - ExpectDiagnosticsFor(SourceCode, ast_matchers::hasName("target")); + void ExpectDiagnosticsFor(std::string SourceCode, + bool IgnoreSmartPointerDereference = true) { + ExpectDiagnosticsFor(SourceCode, ast_matchers::hasName("target"), + IgnoreSmartPointerDereference); } - void ExpectDiagnosticsForLambda(std::string SourceCode) { + void ExpectDiagnosticsForLambda(std::string SourceCode, + bool IgnoreSmartPointerDereference = true) { ExpectDiagnosticsFor( - SourceCode, ast_matchers::hasDeclContext( - ast_matchers::cxxRecordDecl(ast_matchers::isLambda()))); + SourceCode, + ast_matchers::hasDeclContext( + ast_matchers::cxxRecordDecl(ast_matchers::isLambda())), + IgnoreSmartPointerDereference); } template - void ExpectDiagnosticsFor(std::string SourceCode, - FuncDeclMatcher FuncMatcher) { + void ExpectDiagnosticsFor(std::string SourceCode, FuncDeclMatcher FuncMatcher, + bool IgnoreSmartPointerDereference = true) { // Run in C++17 and C++20 mode to cover differences in the AST between modes // (e.g. C++20 can contain `CXXRewrittenBinaryOperator`). for (const char *CxxMode : {"-std=c++17", "-std=c++20"}) - ExpectDiagnosticsFor(SourceCode, FuncMatcher, CxxMode); + ExpectDiagnosticsFor(SourceCode, FuncMatcher, CxxMode, + IgnoreSmartPointerDereference); } template void ExpectDiagnosticsFor(std::string SourceCode, FuncDeclMatcher FuncMatcher, - const char *CxxMode) { + const char *CxxMode, + bool IgnoreSmartPointerDereference) { ReplaceAllOccurrences(SourceCode, "$ns", GetParam().NamespaceName); ReplaceAllOccurrences(SourceCode, "$optional", GetParam().TypeName); @@ -1328,8 +1335,7 @@ protected: template T Make(); )"); - UncheckedOptionalAccessModelOptions Options{ - /*IgnoreSmartPointerDereference=*/true}; + UncheckedOptionalAccessModelOptions Options{IgnoreSmartPointerDereference}; std::vector Diagnostics; llvm::Error Error = checkDataflow( AnalysisInputs( @@ -1371,9 +1377,9 @@ protected: new DiagnosticOptions()); TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(), DiagOpts.get()); - TD.emitDiagnostic( - FullSourceLoc(Loc, SrcMgr), DiagnosticsEngine::Error, - "unexpected diagnostic", std::nullopt, std::nullopt); + TD.emitDiagnostic(FullSourceLoc(Loc, SrcMgr), + DiagnosticsEngine::Error, + "unexpected diagnostic", {}, {}); } } @@ -2167,7 +2173,7 @@ TEST_P(UncheckedOptionalAccessTest, OptionalReturnedFromFuntionCall) { )"); } -TEST_P(UncheckedOptionalAccessTest, OptionalFieldModified) { +TEST_P(UncheckedOptionalAccessTest, NonConstMethodMayClearOptionalField) { ExpectDiagnosticsFor( R"( #include "unchecked_optional_access_test.h" @@ -2187,6 +2193,27 @@ TEST_P(UncheckedOptionalAccessTest, OptionalFieldModified) { )"); } +TEST_P(UncheckedOptionalAccessTest, + NonConstMethodMayNotClearConstOptionalField) { + ExpectDiagnosticsFor( + R"( + #include "unchecked_optional_access_test.h" + + struct Foo { + const $ns::$optional opt; + void clear(); + }; + + void target(Foo& foo) { + if (foo.opt) { + foo.opt.value(); + foo.clear(); + foo.opt.value(); + } + } + )"); +} + TEST_P(UncheckedOptionalAccessTest, StdSwap) { ExpectDiagnosticsFor( R"( @@ -3700,6 +3727,50 @@ TEST_P(UncheckedOptionalAccessTest, ConstByValueAccessorWithModInBetween) { )cc"); } +TEST_P(UncheckedOptionalAccessTest, ConstPointerAccessor) { + ExpectDiagnosticsFor(R"cc( + #include "unchecked_optional_access_test.h" + + struct A { + $ns::$optional x; + }; + + struct MyUniquePtr { + A* operator->() const; + }; + + void target(MyUniquePtr p) { + if (p->x) { + *p->x; + } + } + )cc", + /*IgnoreSmartPointerDereference=*/false); +} + +TEST_P(UncheckedOptionalAccessTest, ConstPointerAccessorWithModInBetween) { + ExpectDiagnosticsFor(R"cc( + #include "unchecked_optional_access_test.h" + + struct A { + $ns::$optional x; + }; + + struct MyUniquePtr { + A* operator->() const; + void reset(A*); + }; + + void target(MyUniquePtr p) { + if (p->x) { + p.reset(nullptr); + *p->x; // [[unsafe]] + } + } + )cc", + /*IgnoreSmartPointerDereference=*/false); +} + TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessor) { ExpectDiagnosticsFor(R"cc( #include "unchecked_optional_access_test.h" diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index 9e8529050ed83d661470af2239b1c1bb20dfc9f2..7fc7492271668b4ec85dd90fb5c4dfc175c43b3d 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -165,24 +165,25 @@ TEST(ConfigParseTest, ParsesConfigurationBools) { CHECK_PARSE_BOOL(BreakBeforeTernaryOperators); CHECK_PARSE_BOOL(BreakStringLiterals); CHECK_PARSE_BOOL(CompactNamespaces); + CHECK_PARSE_BOOL(Cpp11BracedListStyle); CHECK_PARSE_BOOL(DerivePointerAlignment); CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding"); CHECK_PARSE_BOOL(DisableFormat); CHECK_PARSE_BOOL(IndentAccessModifiers); - CHECK_PARSE_BOOL(IndentCaseLabels); CHECK_PARSE_BOOL(IndentCaseBlocks); + CHECK_PARSE_BOOL(IndentCaseLabels); CHECK_PARSE_BOOL(IndentGotoLabels); - CHECK_PARSE_BOOL_FIELD(IndentRequiresClause, "IndentRequires"); CHECK_PARSE_BOOL(IndentRequiresClause); + CHECK_PARSE_BOOL_FIELD(IndentRequiresClause, "IndentRequires"); CHECK_PARSE_BOOL(IndentWrappedFunctionNames); CHECK_PARSE_BOOL(InsertBraces); CHECK_PARSE_BOOL(InsertNewlineAtEOF); CHECK_PARSE_BOOL_FIELD(KeepEmptyLines.AtEndOfFile, "KeepEmptyLinesAtEOF"); CHECK_PARSE_BOOL_FIELD(KeepEmptyLines.AtStartOfBlock, "KeepEmptyLinesAtTheStartOfBlocks"); + CHECK_PARSE_BOOL(KeepFormFeed); CHECK_PARSE_BOOL(ObjCSpaceAfterProperty); CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList); - CHECK_PARSE_BOOL(Cpp11BracedListStyle); CHECK_PARSE_BOOL(RemoveBracesLLVM); CHECK_PARSE_BOOL(RemoveEmptyLinesInUnwrappedLines); CHECK_PARSE_BOOL(RemoveSemicolon); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 8f4c92148adae4accd5b14c0eddd090ad8907817..cdb68b74ca79ffb30c41bcbb5d93ed263bf8a4fc 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -28135,7 +28135,7 @@ TEST_F(FormatTest, BreakBinaryOperations) { Style); } -TEST_F(FormatTest, RemovesEmptyLinesInUnwrappedLines) { +TEST_F(FormatTest, RemoveEmptyLinesInUnwrappedLines) { auto Style = getLLVMStyle(); Style.RemoveEmptyLinesInUnwrappedLines = true; @@ -28212,6 +28212,65 @@ TEST_F(FormatTest, RemovesEmptyLinesInUnwrappedLines) { Style); } +TEST_F(FormatTest, KeepFormFeed) { + auto Style = getLLVMStyle(); + Style.KeepFormFeed = true; + + constexpr StringRef NoFormFeed{"int i;\n" + "\n" + "void f();"}; + verifyFormat(NoFormFeed, + "int i;\n" + " \f\n" + "void f();", + Style); + verifyFormat(NoFormFeed, + "int i;\n" + "\n" + "\fvoid f();", + Style); + verifyFormat(NoFormFeed, + "\fint i;\n" + "\n" + "void f();", + Style); + verifyFormat(NoFormFeed, + "int i;\n" + "\n" + "void f();\f", + Style); + + constexpr StringRef FormFeed{"int i;\n" + "\f\n" + "void f();"}; + verifyNoChange(FormFeed, Style); + + Style.LineEnding = FormatStyle::LE_LF; + verifyFormat(FormFeed, + "int i;\r\n" + "\f\r\n" + "void f();", + Style); + + constexpr StringRef FormFeedBeforeEmptyLine{"int i;\n" + "\f\n" + "\n" + "void f();"}; + Style.MaxEmptyLinesToKeep = 2; + verifyFormat(FormFeedBeforeEmptyLine, + "int i;\n" + "\n" + "\f\n" + "void f();", + Style); + verifyFormat(FormFeedBeforeEmptyLine, + "int i;\n" + "\f\n" + "\f\n" + "void f();", + Style); +} + } // namespace } // namespace test } // namespace format diff --git a/clang/unittests/Frontend/ASTUnitTest.cpp b/clang/unittests/Frontend/ASTUnitTest.cpp index 19b5d9bb41466a3e780a49b36d19bfd87e341dc0..bd5d5d009818079d2106dadbaee3a1e41e745d4e 100644 --- a/clang/unittests/Frontend/ASTUnitTest.cpp +++ b/clang/unittests/Frontend/ASTUnitTest.cpp @@ -168,9 +168,9 @@ TEST_F(ASTUnitTest, LoadFromCommandLineEarlyError) { std::unique_ptr AST = ASTUnit::LoadFromCommandLine( &Args[0], &Args[4], PCHContainerOps, Diags, "", false, "", false, - CaptureDiagsKind::All, std::nullopt, true, 0, TU_Complete, false, false, - false, SkipFunctionBodiesScope::None, false, true, false, false, - std::nullopt, &ErrUnit, nullptr); + CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false, + SkipFunctionBodiesScope::None, false, true, false, false, std::nullopt, + &ErrUnit, nullptr); ASSERT_EQ(AST, nullptr); ASSERT_NE(ErrUnit, nullptr); @@ -195,9 +195,9 @@ TEST_F(ASTUnitTest, LoadFromCommandLineWorkingDirectory) { std::unique_ptr AST = ASTUnit::LoadFromCommandLine( &Args[0], &Args[4], PCHContainerOps, Diags, "", false, "", false, - CaptureDiagsKind::All, std::nullopt, true, 0, TU_Complete, false, false, - false, SkipFunctionBodiesScope::None, false, true, false, false, - std::nullopt, &ErrUnit, nullptr); + CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false, + SkipFunctionBodiesScope::None, false, true, false, false, std::nullopt, + &ErrUnit, nullptr); ASSERT_NE(AST, nullptr); ASSERT_FALSE(Diags->hasErrorOccurred()); diff --git a/clang/unittests/StaticAnalyzer/MemRegionDescriptiveNameTest.cpp b/clang/unittests/StaticAnalyzer/MemRegionDescriptiveNameTest.cpp index b13e7123ee524d1250ad69cfaa22ae866ab1d16a..0f6e49bf42f4acc28998a5b2f887ae078f1dcd8b 100644 --- a/clang/unittests/StaticAnalyzer/MemRegionDescriptiveNameTest.cpp +++ b/clang/unittests/StaticAnalyzer/MemRegionDescriptiveNameTest.cpp @@ -12,7 +12,6 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "gtest/gtest.h" -#include using namespace clang; using namespace ento; @@ -143,4 +142,32 @@ void top() { EXPECT_EQ(Output, "DescriptiveNameChecker: array[x]\n"); } +TEST(MemRegionDescriptiveNameTest, FieldRegWithSuperElementReg) { + StringRef Code = R"cpp( +void reportDescriptiveName(int *p); +struct val_struct { int val; }; +extern struct val_struct val_struct_array[3]; +void top() { + reportDescriptiveName(&val_struct_array[0].val); +})cpp"; + + std::string Output; + ASSERT_TRUE(runChecker(Code, Output)); + EXPECT_EQ(Output, "DescriptiveNameChecker: val_struct_array[0].val\n"); +} + +TEST(MemRegionDescriptiveNameTest, FieldRegWithSuperMultidimElementReg) { + StringRef Code = R"cpp( +void reportDescriptiveName(int *p); +struct val_struct { int val; }; +extern struct val_struct val_struct_array[3][4]; +void top() { + reportDescriptiveName(&val_struct_array[1][2].val); +})cpp"; + + std::string Output; + ASSERT_TRUE(runChecker(Code, Output)); + EXPECT_EQ(Output, "DescriptiveNameChecker: val_struct_array[1][2].val\n"); +} + } // namespace diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 4890d249c6d8f78e6c5d5897a4fbcd9cde8f2f4b..3031d81b3df7312f96bb0c0cf61ff9d8ee57af25 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -49,40 +49,38 @@ using namespace llvm; namespace { class FlattenedSpelling { - std::string V, N, NS; + StringRef V, N, NS; bool K = false; const Record &OriginalSpelling; public: - FlattenedSpelling(const std::string &Variety, const std::string &Name, - const std::string &Namespace, bool KnownToGCC, - const Record &OriginalSpelling) + FlattenedSpelling(StringRef Variety, StringRef Name, StringRef Namespace, + bool KnownToGCC, const Record &OriginalSpelling) : V(Variety), N(Name), NS(Namespace), K(KnownToGCC), OriginalSpelling(OriginalSpelling) {} explicit FlattenedSpelling(const Record &Spelling) - : V(std::string(Spelling.getValueAsString("Variety"))), - N(std::string(Spelling.getValueAsString("Name"))), - OriginalSpelling(Spelling) { + : V(Spelling.getValueAsString("Variety")), + N(Spelling.getValueAsString("Name")), OriginalSpelling(Spelling) { assert(V != "GCC" && V != "Clang" && "Given a GCC spelling, which means this hasn't been flattened!"); if (V == "CXX11" || V == "C23" || V == "Pragma") - NS = std::string(Spelling.getValueAsString("Namespace")); + NS = Spelling.getValueAsString("Namespace"); } - const std::string &variety() const { return V; } - const std::string &name() const { return N; } - const std::string &nameSpace() const { return NS; } + StringRef variety() const { return V; } + StringRef name() const { return N; } + StringRef nameSpace() const { return NS; } bool knownToGCC() const { return K; } const Record &getSpellingRecord() const { return OriginalSpelling; } }; struct FlattenedSpellingInfo { - FlattenedSpellingInfo(std::string Syntax, std::string Scope, - std::string TargetTest, uint32_t ArgMask) + FlattenedSpellingInfo(StringRef Syntax, StringRef Scope, + const std::string &TargetTest, uint32_t ArgMask) : Syntax(Syntax), Scope(Scope), TargetTest(TargetTest), ArgMask(ArgMask) { } - std::string Syntax; - std::string Scope; + StringRef Syntax; + StringRef Scope; std::string TargetTest; uint32_t ArgMask; }; @@ -105,17 +103,18 @@ GetFlattenedSpellings(const Record &Attr) { StringRef Variety = Spelling->getValueAsString("Variety"); StringRef Name = Spelling->getValueAsString("Name"); if (Variety == "GCC") { - Ret.emplace_back("GNU", std::string(Name), "", true, *Spelling); - Ret.emplace_back("CXX11", std::string(Name), "gnu", true, *Spelling); + Ret.emplace_back("GNU", Name, "", true, *Spelling); + Ret.emplace_back("CXX11", Name, "gnu", true, *Spelling); if (Spelling->getValueAsBit("AllowInC")) - Ret.emplace_back("C23", std::string(Name), "gnu", true, *Spelling); + Ret.emplace_back("C23", Name, "gnu", true, *Spelling); } else if (Variety == "Clang") { - Ret.emplace_back("GNU", std::string(Name), "", false, *Spelling); - Ret.emplace_back("CXX11", std::string(Name), "clang", false, *Spelling); + Ret.emplace_back("GNU", Name, "", false, *Spelling); + Ret.emplace_back("CXX11", Name, "clang", false, *Spelling); if (Spelling->getValueAsBit("AllowInC")) - Ret.emplace_back("C23", std::string(Name), "clang", false, *Spelling); - } else + Ret.emplace_back("C23", Name, "clang", false, *Spelling); + } else { Ret.push_back(FlattenedSpelling(*Spelling)); + } } return Ret; @@ -123,9 +122,7 @@ GetFlattenedSpellings(const Record &Attr) { static std::string ReadPCHRecord(StringRef type) { return StringSwitch(type) - .EndsWith("Decl *", "Record.readDeclAs<" + - std::string(type.data(), 0, type.size() - 1) + - ">()") + .EndsWith("Decl *", "Record.readDeclAs<" + type.drop_back().str() + ">()") .Case("TypeSourceInfo *", "Record.readTypeSourceInfo()") .Case("Expr *", "Record.readExpr()") .Case("IdentifierInfo *", "Record.readIdentifier()") @@ -146,18 +143,16 @@ static StringRef getStorageType(StringRef type) { static std::string WritePCHRecord(StringRef type, StringRef name) { return "Record." + StringSwitch(type) - .EndsWith("Decl *", "AddDeclRef(" + std::string(name) + ");\n") + .EndsWith("Decl *", "AddDeclRef(" + name.str() + ");\n") .Case("TypeSourceInfo *", - "AddTypeSourceInfo(" + std::string(name) + ");\n") - .Case("Expr *", "AddStmt(" + std::string(name) + ");\n") + "AddTypeSourceInfo(" + name.str() + ");\n") + .Case("Expr *", "AddStmt(" + name.str() + ");\n") .Case("IdentifierInfo *", - "AddIdentifierRef(" + std::string(name) + ");\n") - .Case("StringRef", "AddString(" + std::string(name) + ");\n") - .Case("ParamIdx", - "push_back(" + std::string(name) + ".serialize());\n") - .Case("OMPTraitInfo *", - "writeOMPTraitInfo(" + std::string(name) + ");\n") - .Default("push_back(" + std::string(name) + ");\n"); + "AddIdentifierRef(" + name.str() + ");\n") + .Case("StringRef", "AddString(" + name.str() + ");\n") + .Case("ParamIdx", "push_back(" + name.str() + ".serialize());\n") + .Case("OMPTraitInfo *", "writeOMPTraitInfo(" + name.str() + ");\n") + .Default("push_back(" + name.str() + ");\n"); } // Normalize attribute name by removing leading and trailing @@ -198,7 +193,7 @@ static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records, std::string AN; if (Attr->isSubClassOf("TargetSpecificAttr") && !Attr->isValueUnset("ParseKind")) { - AN = std::string(Attr->getValueAsString("ParseKind")); + AN = Attr->getValueAsString("ParseKind").str(); // If this attribute has already been handled, it does not need to be // handled again. @@ -226,7 +221,7 @@ namespace { public: Argument(StringRef Arg, StringRef Attr) - : lowerName(std::string(Arg)), upperName(lowerName), attrName(Attr), + : lowerName(Arg.str()), upperName(lowerName), attrName(Attr), isOpt(false), Fake(false) { if (!lowerName.empty()) { lowerName[0] = std::tolower(lowerName[0]); @@ -332,8 +327,7 @@ namespace { void writePCHWrite(raw_ostream &OS) const override { OS << " " - << WritePCHRecord(type, - "SA->get" + std::string(getUpperName()) + "()"); + << WritePCHRecord(type, "SA->get" + getUpperName().str() + "()"); } std::string getIsOmitted() const override { @@ -699,12 +693,12 @@ namespace { VariadicArgument(const Record &Arg, StringRef Attr, std::string T) : Argument(Arg, Attr), Type(std::move(T)), ArgName(getLowerName().str() + "_"), ArgSizeName(ArgName + "Size"), - RangeName(std::string(getLowerName())) {} + RangeName(getLowerName().str()) {} VariadicArgument(StringRef Arg, StringRef Attr, std::string T) : Argument(Arg, Attr), Type(std::move(T)), ArgName(getLowerName().str() + "_"), ArgSizeName(ArgName + "Size"), - RangeName(std::string(getLowerName())) {} + RangeName(getLowerName().str()) {} const std::string &getType() const { return Type; } const std::string &getArgName() const { return ArgName; } @@ -793,8 +787,8 @@ namespace { // If we can't store the values in the current type (if it's something // like StringRef), store them in a different type and convert the // container afterwards. - std::string StorageType = std::string(getStorageType(getType())); - std::string StorageName = std::string(getLowerName()); + std::string StorageType = getStorageType(getType()).str(); + std::string StorageName = getLowerName().str(); if (StorageType != getType()) { StorageName += "Storage"; OS << " SmallVector<" << StorageType << ", 4> " @@ -1082,8 +1076,7 @@ namespace { public: VariadicEnumArgument(const Record &Arg, StringRef Attr) - : VariadicArgument(Arg, Attr, - std::string(Arg.getValueAsString("Type"))), + : VariadicArgument(Arg, Attr, Arg.getValueAsString("Type").str()), values(Arg.getValueAsListOfStrings("Values")), enums(Arg.getValueAsListOfStrings("Enums")), uniques(uniqueEnumsInOrder(enums)), @@ -1438,7 +1431,7 @@ namespace { void writePCHWrite(raw_ostream &OS) const override { OS << " " << WritePCHRecord(getType(), - "SA->get" + std::string(getUpperName()) + "Loc()"); + "SA->get" + getUpperName().str() + "Loc()"); } }; @@ -1554,7 +1547,7 @@ static void writeAvailabilityValue(raw_ostream &OS) { << " OS << \""; } -static void writeDeprecatedAttrValue(raw_ostream &OS, std::string &Variety) { +static void writeDeprecatedAttrValue(raw_ostream &OS, StringRef Variety) { OS << "\\\"\" << getMessage() << \"\\\"\";\n"; // Only GNU deprecated has an optional fixit argument at the second position. if (Variety == "GNU") @@ -1577,9 +1570,12 @@ static void writeGetSpellingFunction(const Record &R, raw_ostream &OS) { " llvm_unreachable(\"Unknown attribute spelling!\");\n" " return \"(No spelling)\";\n"; - for (unsigned I = 0; I < Spellings.size(); ++I) - OS << " case " << I << ":\n" - " return \"" << Spellings[I].name() << "\";\n"; + for (const auto &[Idx, S] : enumerate(Spellings)) { + // clang-format off + OS << " case " << Idx << ":\n" + " return \"" << S.name() << "\";\n"; + // clang-format on + } // End of the switch statement. OS << " }\n"; // End of the getSpelling function. @@ -1607,14 +1603,14 @@ writePrettyPrintFunction(const Record &R, << " llvm_unreachable(\"Unknown attribute spelling!\");\n" << " break;\n"; - for (unsigned I = 0; I < Spellings.size(); ++ I) { + for (const auto &[Idx, S] : enumerate(Spellings)) { SmallString<16> Prefix; SmallString<8> Suffix; // The actual spelling of the name and namespace (if applicable) // of an attribute without considering prefix and suffix. SmallString<64> Spelling; - std::string Name = Spellings[I].name(); - std::string Variety = Spellings[I].variety(); + StringRef Name = S.name(); + StringRef Variety = S.variety(); if (Variety == "GNU") { Prefix = "__attribute__(("; @@ -1622,7 +1618,7 @@ writePrettyPrintFunction(const Record &R, } else if (Variety == "CXX11" || Variety == "C23") { Prefix = "[["; Suffix = "]]"; - std::string Namespace = Spellings[I].nameSpace(); + StringRef Namespace = S.nameSpace(); if (!Namespace.empty()) { Spelling += Namespace; Spelling += "::"; @@ -1639,7 +1635,7 @@ writePrettyPrintFunction(const Record &R, } else if (Variety == "Pragma") { Prefix = "#pragma "; Suffix = "\n"; - std::string Namespace = Spellings[I].nameSpace(); + StringRef Namespace = S.nameSpace(); if (!Namespace.empty()) { Spelling += Namespace; Spelling += " "; @@ -1653,7 +1649,7 @@ writePrettyPrintFunction(const Record &R, Spelling += Name; - OS << " case " << I << " : {\n" + OS << " case " << Idx << " : {\n" << " OS << \"" << Prefix << Spelling << "\";\n"; if (Variety == "Pragma") { @@ -1724,24 +1720,17 @@ writePrettyPrintFunction(const Record &R, } /// Return the index of a spelling in a spelling list. -static unsigned -getSpellingListIndex(const std::vector &SpellingList, - const FlattenedSpelling &Spelling) { +static unsigned getSpellingListIndex(ArrayRef SpellingList, + const FlattenedSpelling &Spelling) { assert(!SpellingList.empty() && "Spelling list is empty!"); - for (unsigned Index = 0; Index < SpellingList.size(); ++Index) { - const FlattenedSpelling &S = SpellingList[Index]; - if (S.variety() != Spelling.variety()) - continue; - if (S.nameSpace() != Spelling.nameSpace()) - continue; - if (S.name() != Spelling.name()) - continue; - - return Index; + for (const auto &[Index, S] : enumerate(SpellingList)) { + if (S.variety() == Spelling.variety() && + S.nameSpace() == Spelling.nameSpace() && S.name() == Spelling.name()) + return Index; } - llvm_unreachable("Unknown spelling!"); + PrintFatalError("Unknown spelling: " + Spelling.name()); } static void writeAttrAccessorDefinition(const Record &R, raw_ostream &OS) { @@ -1771,11 +1760,10 @@ static void writeAttrAccessorDefinition(const Record &R, raw_ostream &OS) { static bool SpellingNamesAreCommon(const std::vector& Spellings) { assert(!Spellings.empty() && "An empty list of spellings was provided"); - std::string FirstName = - std::string(NormalizeNameForSpellingComparison(Spellings.front().name())); + StringRef FirstName = + NormalizeNameForSpellingComparison(Spellings.front().name()); for (const auto &Spelling : drop_begin(Spellings)) { - std::string Name = - std::string(NormalizeNameForSpellingComparison(Spelling.name())); + StringRef Name = NormalizeNameForSpellingComparison(Spelling.name()); if (Name != FirstName) return false; } @@ -1802,15 +1790,15 @@ CreateSemanticSpellings(const std::vector &Spellings, "AttributeCommonInfo"); for (auto I = Spellings.begin(), E = Spellings.end(); I != E; ++I, ++Idx) { const FlattenedSpelling &S = *I; - const std::string &Variety = S.variety(); - const std::string &Spelling = S.name(); - const std::string &Namespace = S.nameSpace(); + StringRef Variety = S.variety(); + StringRef Spelling = S.name(); + StringRef Namespace = S.nameSpace(); std::string EnumName; - EnumName += (Variety + "_"); + EnumName += Variety; + EnumName += "_"; if (!Namespace.empty()) - EnumName += (NormalizeNameForSpellingComparison(Namespace).str() + - "_"); + EnumName += NormalizeNameForSpellingComparison(Namespace).str() + "_"; EnumName += NormalizeNameForSpellingComparison(Spelling); // Even if the name is not unique, this spelling index corresponds to a @@ -1837,7 +1825,7 @@ CreateSemanticSpellings(const std::vector &Spellings, return Ret; } -void WriteSemanticSpellingSwitch(const std::string &VarName, +void WriteSemanticSpellingSwitch(StringRef VarName, const SemanticSpellingMap &Map, raw_ostream &OS) { OS << " switch (" << VarName << ") {\n default: " @@ -1990,7 +1978,7 @@ struct AttributeSubjectMatchRule { } std::string getSpelling() const { - std::string Result = std::string(MetaSubject->getValueAsString("Name")); + std::string Result = MetaSubject->getValueAsString("Name").str(); if (isSubRule()) { Result += '('; if (isNegatedSubRule()) @@ -2378,30 +2366,22 @@ void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) { } template static void forEachSpelling(const Record &Attr, Fn &&F) { - std::vector Spellings = GetFlattenedSpellings(Attr); - for (const FlattenedSpelling &S : Spellings) { + for (const FlattenedSpelling &S : GetFlattenedSpellings(Attr)) { F(S); } } -std::map> NameToAttrsMap; +std::map> NameToAttrsMap; /// Build a map from the attribute name to the Attrs that use that name. If more /// than one Attr use a name, the arguments could be different so a more complex /// check is needed in the generated switch. void generateNameToAttrsMap(const RecordKeeper &Records) { for (const auto *A : Records.getAllDerivedDefinitions("Attr")) { - std::vector Spellings = GetFlattenedSpellings(*A); - for (const auto &S : Spellings) { - auto It = NameToAttrsMap.find(S.name()); - if (It != NameToAttrsMap.end()) { - if (none_of(It->second, [&](const Record *R) { return R == A; })) - It->second.emplace_back(A); - } else { - std::vector V; - V.emplace_back(A); - NameToAttrsMap.insert(std::make_pair(S.name(), V)); - } + for (const FlattenedSpelling &S : GetFlattenedSpellings(*A)) { + auto [It, Inserted] = NameToAttrsMap.try_emplace(S.name()); + if (Inserted || !is_contained(It->second, A)) + It->second.emplace_back(A); } } } @@ -2410,7 +2390,7 @@ void generateNameToAttrsMap(const RecordKeeper &Records) { /// attribute has the same name. Store the info in a map that can be processed /// after all attributes are seen. static void generateFlattenedSpellingInfo(const Record &Attr, - std::map &Map, + std::map &Map, uint32_t ArgMask = 0) { std::string TargetTest; if (Attr.isSubClassOf("TargetSpecificAttr") && @@ -2421,24 +2401,17 @@ static void generateFlattenedSpellingInfo(const Record &Attr, } forEachSpelling(Attr, [&](const FlattenedSpelling &S) { - auto It = Map.find(S.name()); - if (It != Map.end()) { - It->second.emplace_back(S.variety(), S.nameSpace(), TargetTest, ArgMask); - } else { - FSIVecTy V; - V.emplace_back(S.variety(), S.nameSpace(), TargetTest, ArgMask); - Map.insert(std::make_pair(S.name(), V)); - } + Map[S.name()].emplace_back(S.variety(), S.nameSpace(), TargetTest, ArgMask); }); } -static bool nameAppliesToOneAttribute(std::string Name) { +static bool nameAppliesToOneAttribute(StringRef Name) { auto It = NameToAttrsMap.find(Name); assert(It != NameToAttrsMap.end()); return It->second.size() == 1; } -static bool emitIfSimpleValue(std::string Name, uint32_t ArgMask, +static bool emitIfSimpleValue(StringRef Name, uint32_t ArgMask, raw_ostream &OS) { if (nameAppliesToOneAttribute(Name)) { OS << ".Case(\"" << Name << "\", "; @@ -2463,15 +2436,13 @@ static void emitSingleCondition(const FlattenedSpellingInfo &FSI, OS << ")"; } -static void emitStringSwitchCases(std::map &Map, +static void emitStringSwitchCases(std::map &Map, raw_ostream &OS) { - for (const auto &P : Map) { - if (emitIfSimpleValue(P.first, P.second[0].ArgMask, OS)) + for (const auto &[Name, Vec] : Map) { + if (emitIfSimpleValue(Name, Vec[0].ArgMask, OS)) continue; // Not simple, build expressions for each case. - StringRef Name = P.first; - const FSIVecTy &Vec = P.second; OS << ".Case(\"" << Name << "\", "; for (unsigned I = 0, E = Vec.size(); I < E; ++I) { emitSingleCondition(Vec[I], OS); @@ -2498,7 +2469,7 @@ static bool isTypeArgument(const Record *Arg) { static void emitClangAttrTypeArgList(const RecordKeeper &Records, raw_ostream &OS) { OS << "#if defined(CLANG_ATTR_TYPE_ARG_LIST)\n"; - std::map FSIMap; + std::map FSIMap; for (const auto *Attr : Records.getAllDerivedDefinitions("Attr")) { // Determine whether the first argument is a type. std::vector Args = Attr->getValueAsListOfDefs("Args"); @@ -2518,7 +2489,7 @@ static void emitClangAttrTypeArgList(const RecordKeeper &Records, static void emitClangAttrArgContextList(const RecordKeeper &Records, raw_ostream &OS) { OS << "#if defined(CLANG_ATTR_ARG_CONTEXT_LIST)\n"; - std::map FSIMap; + std::map FSIMap; ParsedAttrMap Attrs = getParsedAttrList(Records); for (const auto &I : Attrs) { const Record &Attr = *I.second; @@ -2576,7 +2547,7 @@ static bool isVariadicStringLiteralArgument(const Record *Arg) { static void emitClangAttrVariadicIdentifierArgList(const RecordKeeper &Records, raw_ostream &OS) { OS << "#if defined(CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST)\n"; - std::map FSIMap; + std::map FSIMap; for (const auto *A : Records.getAllDerivedDefinitions("Attr")) { // Determine whether the first argument is a variadic identifier. std::vector Args = A->getValueAsListOfDefs("Args"); @@ -2609,7 +2580,7 @@ emitClangAttrUnevaluatedStringLiteralList(const RecordKeeper &Records, return Bits; }; - std::map FSIMap; + std::map FSIMap; for (const auto *Attr : Records.getAllDerivedDefinitions("Attr")) { // Determine whether there are any string arguments. uint32_t ArgMask = MakeMask(Attr->getValueAsListOfDefs("Args")); @@ -2625,7 +2596,7 @@ emitClangAttrUnevaluatedStringLiteralList(const RecordKeeper &Records, static void emitClangAttrIdentifierArgList(const RecordKeeper &Records, raw_ostream &OS) { OS << "#if defined(CLANG_ATTR_IDENTIFIER_ARG_LIST)\n"; - std::map FSIMap; + std::map FSIMap; for (const auto *Attr : Records.getAllDerivedDefinitions("Attr")) { // Determine whether the first argument is an identifier. std::vector Args = Attr->getValueAsListOfDefs("Args"); @@ -2641,7 +2612,7 @@ static void emitClangAttrIdentifierArgList(const RecordKeeper &Records, static void emitClangAttrStrictIdentifierArgList(const RecordKeeper &Records, raw_ostream &OS) { OS << "#if defined(CLANG_ATTR_STRICT_IDENTIFIER_ARG_LIST)\n"; - std::map FSIMap; + std::map FSIMap; for (const auto *Attr : Records.getAllDerivedDefinitions("Attr")) { if (!Attr->getValueAsBit("StrictEnumParameters")) continue; @@ -2665,7 +2636,7 @@ static bool keywordThisIsaIdentifierInArgument(const Record *Arg) { static void emitClangAttrThisIsaIdentifierArgList(const RecordKeeper &Records, raw_ostream &OS) { OS << "#if defined(CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST)\n"; - std::map FSIMap; + std::map FSIMap; for (const auto *A : Records.getAllDerivedDefinitions("Attr")) { // Determine whether the first argument is a variadic identifier. std::vector Args = A->getValueAsListOfDefs("Args"); @@ -2681,7 +2652,7 @@ static void emitClangAttrAcceptsExprPack(const RecordKeeper &Records, raw_ostream &OS) { OS << "#if defined(CLANG_ATTR_ACCEPTS_EXPR_PACK)\n"; ParsedAttrMap Attrs = getParsedAttrList(Records); - std::map FSIMap; + std::map FSIMap; for (const auto &I : Attrs) { const Record &Attr = *I.second; @@ -2750,7 +2721,7 @@ static void emitAttributes(const RecordKeeper &Records, raw_ostream &OS, for (const auto &[R, _] : reverse(Supers)) { if (R->getName() != "TargetSpecificAttr" && R->getName() != "DeclOrTypeAttr" && SuperName.empty()) - SuperName = std::string(R->getName()); + SuperName = R->getName().str(); if (R->getName() == "InheritableAttr") Inheritable = true; } @@ -3678,9 +3649,8 @@ static bool GenerateTargetSpecificAttrChecks(const Record *R, } static void GenerateHasAttrSpellingStringSwitch( - const std::vector> &Attrs, - raw_ostream &OS, const std::string &Variety, - const std::string &Scope = "") { + ArrayRef> Attrs, + raw_ostream &OS, StringRef Variety, StringRef Scope = "") { for (const auto &[Attr, Spelling] : Attrs) { // C++11-style attributes have specific version information associated with // them. If the attribute has no scope, the version information must not @@ -3783,18 +3753,15 @@ void EmitClangAttrHasAttrImpl(const RecordKeeper &Records, raw_ostream &OS) { // Separate all of the attributes out into four group: generic, C++11, GNU, // and declspecs. Then generate a big switch statement for each of them. - std::vector> Declspec, Microsoft, - GNU, Pragma, HLSLAnnotation; - std::map>> - CXX, C23; + using PairTy = std::pair; + std::vector Declspec, Microsoft, GNU, Pragma, HLSLAnnotation; + std::map> CXX, C23; // Walk over the list of all attributes, and split them out based on the // spelling variety. for (auto *R : Records.getAllDerivedDefinitions("Attr")) { - std::vector Spellings = GetFlattenedSpellings(*R); - for (const auto &SI : Spellings) { - const std::string &Variety = SI.variety(); + for (const FlattenedSpelling &SI : GetFlattenedSpellings(*R)) { + StringRef Variety = SI.variety(); if (Variety == "GNU") GNU.emplace_back(R, SI); else if (Variety == "Declspec") @@ -3829,22 +3796,16 @@ void EmitClangAttrHasAttrImpl(const RecordKeeper &Records, raw_ostream &OS) { OS << "case AttributeCommonInfo::Syntax::AS_HLSLAnnotation:\n"; OS << " return llvm::StringSwitch(Name)\n"; GenerateHasAttrSpellingStringSwitch(HLSLAnnotation, OS, "HLSLAnnotation"); - auto fn = [&OS](const char *Spelling, - const std::map< - std::string, - std::vector>> - &List) { + auto fn = [&OS](StringRef Spelling, + const std::map> &Map) { OS << "case AttributeCommonInfo::Syntax::AS_" << Spelling << ": {\n"; // C++11-style attributes are further split out based on the Scope. - for (auto I = List.cbegin(), E = List.cend(); I != E; ++I) { - if (I != List.cbegin()) - OS << " else "; - if (I->first.empty()) - OS << "if (ScopeName == \"\") {\n"; - else - OS << "if (ScopeName == \"" << I->first << "\") {\n"; + ListSeparator LS(" else "); + for (const auto &[Scope, List] : Map) { + OS << LS; + OS << "if (ScopeName == \"" << Scope << "\") {\n"; OS << " return llvm::StringSwitch(Name)\n"; - GenerateHasAttrSpellingStringSwitch(I->second, OS, Spelling, I->first); + GenerateHasAttrSpellingStringSwitch(List, OS, Spelling, Scope); OS << "}"; } OS << "\n} break;\n"; @@ -4086,9 +4047,9 @@ static void emitArgInfo(const Record &R, raw_ostream &OS) { } static std::string GetDiagnosticSpelling(const Record &R) { - std::string Ret = std::string(R.getValueAsString("DiagSpelling")); + StringRef Ret = R.getValueAsString("DiagSpelling"); if (!Ret.empty()) - return Ret; + return Ret.str(); // If we couldn't find the DiagSpelling in this object, we can check to see // if the object is one that has a base, and if it is, loop up to the Base @@ -4121,7 +4082,7 @@ static std::string CalculateDiagnostic(const Record &S) { SmallVector Frags; SplitString(V, Frags, ","); for (auto Str : Frags) { - DiagList.push_back(std::string(Str.trim())); + DiagList.push_back(Str.trim().str()); } } } @@ -4152,7 +4113,7 @@ static std::string CalculateDiagnostic(const Record &S) { } static std::string GetSubjectWithSuffix(const Record *R) { - const std::string &B = std::string(R->getName()); + const std::string B = R->getName().str(); if (B == "DeclBase") return "Decl"; return B + "Decl"; @@ -4424,7 +4385,7 @@ static void GenerateMutualExclusionsChecks(const Record &Attr, MergeStmtOS << " auto Iter = llvm::find_if(C, [](const Attr *Check) " << "{ return isa<"; interleave( - StmtAttrs, [&](const std::string &Name) { MergeStmtOS << Name; }, + StmtAttrs, [&](StringRef Name) { MergeStmtOS << Name; }, [&] { MergeStmtOS << ", "; }); MergeStmtOS << ">(Check); });\n"; MergeStmtOS << " if (Iter != C.end()) {\n"; @@ -4719,10 +4680,10 @@ void EmitClangAttrParsedAttrImpl(const RecordKeeper &Records, raw_ostream &OS) { OS << "static constexpr ParsedAttrInfo::Spelling " << I->first << "Spellings[] = {\n"; for (const auto &S : Spellings) { - const std::string &RawSpelling = S.name(); + StringRef RawSpelling = S.name(); std::string Spelling; if (!S.nameSpace().empty()) - Spelling += S.nameSpace() + "::"; + Spelling += S.nameSpace().str() + "::"; if (S.variety() == "GNU") Spelling += NormalizeGNUAttrSpelling(RawSpelling); else @@ -4841,7 +4802,7 @@ void EmitClangAttrParsedAttrKinds(const RecordKeeper &Records, std::vector GNU, Declspec, Microsoft, CXX11, Keywords, Pragma, C23, HLSLAnnotation; - std::set Seen; + std::set Seen; for (const auto *A : Records.getAllDerivedDefinitions("Attr")) { const Record &Attr = *A; @@ -4861,38 +4822,41 @@ void EmitClangAttrParsedAttrKinds(const RecordKeeper &Records, std::string AttrName; if (Attr.isSubClassOf("TargetSpecificAttr") && !Attr.isValueUnset("ParseKind")) { - AttrName = std::string(Attr.getValueAsString("ParseKind")); - if (!Seen.insert(AttrName).second) + StringRef ParseKind = Attr.getValueAsString("ParseKind"); + if (!Seen.insert(ParseKind).second) continue; - } else - AttrName = NormalizeAttrName(StringRef(Attr.getName())).str(); + AttrName = ParseKind.str(); + } else { + AttrName = NormalizeAttrName(Attr.getName()).str(); + } std::vector Spellings = GetFlattenedSpellings(Attr); for (const auto &S : Spellings) { - const std::string &RawSpelling = S.name(); + StringRef RawSpelling = S.name(); std::vector *Matches = nullptr; std::string Spelling; - const std::string &Variety = S.variety(); + StringRef Variety = S.variety(); if (Variety == "CXX11") { Matches = &CXX11; if (!S.nameSpace().empty()) - Spelling += S.nameSpace() + "::"; + Spelling += S.nameSpace().str() + "::"; } else if (Variety == "C23") { Matches = &C23; if (!S.nameSpace().empty()) - Spelling += S.nameSpace() + "::"; - } else if (Variety == "GNU") + Spelling += S.nameSpace().str() + "::"; + } else if (Variety == "GNU") { Matches = &GNU; - else if (Variety == "Declspec") + } else if (Variety == "Declspec") { Matches = &Declspec; - else if (Variety == "Microsoft") + } else if (Variety == "Microsoft") { Matches = &Microsoft; - else if (Variety == "Keyword") + } else if (Variety == "Keyword") { Matches = &Keywords; - else if (Variety == "Pragma") + } else if (Variety == "Pragma") { Matches = &Pragma; - else if (Variety == "HLSLAnnotation") + } else if (Variety == "HLSLAnnotation") { Matches = &HLSLAnnotation; + } assert(Matches && "Unsupported spelling variety found"); @@ -5073,14 +5037,16 @@ public: .Case("Pragma", SpellingKind::Pragma) .Case("HLSLAnnotation", SpellingKind::HLSLAnnotation); std::string Name; - if (!Spelling.nameSpace().empty()) { + StringRef NameSpace = Spelling.nameSpace(); + if (!NameSpace.empty()) { + Name = NameSpace; switch (Kind) { case SpellingKind::CXX11: case SpellingKind::C23: - Name = Spelling.nameSpace() + "::"; + Name += "::"; break; case SpellingKind::Pragma: - Name = Spelling.nameSpace() + " "; + Name = " "; break; default: PrintFatalError(Attr.getLoc(), "Unexpected namespace in spelling"); @@ -5134,7 +5100,7 @@ GetAttributeHeadingAndSpellings(const Record &Documentation, "documented"); // Determine the heading to be used for this attribute. - std::string Heading = std::string(Documentation.getValueAsString("Heading")); + std::string Heading = Documentation.getValueAsString("Heading").str(); if (Heading.empty()) { // If there's only one spelling, we can simply use that. if (Spellings.size() == 1) @@ -5144,7 +5110,7 @@ GetAttributeHeadingAndSpellings(const Record &Documentation, for (auto I = Spellings.begin(), E = Spellings.end(); I != E; ++I) { std::string Spelling = - std::string(NormalizeNameForSpellingComparison(I->name())); + NormalizeNameForSpellingComparison(I->name()).str(); Uniques.insert(Spelling); } // If the semantic map has only one spelling, that is sufficient for our diff --git a/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp index 1a2503dcf660cfbf2c381c62357b14b11dbd2114..45a97425ef920aa2d8482ebd1a0f24b9a68a1636 100644 --- a/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp +++ b/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp @@ -63,7 +63,7 @@ void clang::EmitClangCommentCommandInfo(const RecordKeeper &Records, std::vector Matches; for (size_t i = 0, e = Tags.size(); i != e; ++i) { const Record &Tag = *Tags[i]; - std::string Name = std::string(Tag.getValueAsString("Name")); + std::string Name = Tag.getValueAsString("Name").str(); std::string Return; raw_string_ostream(Return) << "return &Commands[" << i << "];"; Matches.emplace_back(std::move(Name), std::move(Return)); diff --git a/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp b/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp index bd75b3f6b652a16a112813e9bd958c8b153bede1..2d615760814e01b25ee19bf18881f90be9b8f34a 100644 --- a/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp +++ b/clang/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp @@ -51,7 +51,7 @@ void clang::EmitClangCommentHTMLNamedCharacterReferences( std::vector NameToUTF8; SmallString<32> CLiteral; for (const Record *Tag : Records.getAllDerivedDefinitions("NCR")) { - std::string Spelling = std::string(Tag->getValueAsString("Spelling")); + std::string Spelling = Tag->getValueAsString("Spelling").str(); uint64_t CodePoint = Tag->getValueAsInt("CodePoint"); CLiteral.clear(); CLiteral.append("return "); diff --git a/clang/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp b/clang/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp index a457315bc62c5c7e118288682c6bed7458d68701..7d65cfe0d3f5292c5754eaf919dc1eb945a6d52f 100644 --- a/clang/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp +++ b/clang/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp @@ -24,7 +24,7 @@ void clang::EmitClangCommentHTMLTags(const RecordKeeper &Records, ArrayRef Tags = Records.getAllDerivedDefinitions("Tag"); std::vector Matches; for (const Record *Tag : Tags) { - Matches.emplace_back(std::string(Tag->getValueAsString("Spelling")), + Matches.emplace_back(Tag->getValueAsString("Spelling").str(), "return true;"); } @@ -42,7 +42,7 @@ void clang::EmitClangCommentHTMLTagsProperties(const RecordKeeper &Records, std::vector MatchesEndTagOptional; std::vector MatchesEndTagForbidden; for (const Record *Tag : Tags) { - std::string Spelling = std::string(Tag->getValueAsString("Spelling")); + std::string Spelling = Tag->getValueAsString("Spelling").str(); StringMatcher::StringPair Match(Spelling, "return true;"); if (Tag->getValueAsBit("EndTagOptional")) MatchesEndTagOptional.push_back(Match); diff --git a/clang/utils/TableGen/NeonEmitter.cpp b/clang/utils/TableGen/NeonEmitter.cpp index 59c023ca33606393546add4459425e08ae23470e..c6d82646b40de2467f56256d2846842a716287b3 100644 --- a/clang/utils/TableGen/NeonEmitter.cpp +++ b/clang/utils/TableGen/NeonEmitter.cpp @@ -1685,7 +1685,7 @@ Intrinsic::DagEmitter::emitDagShuffle(const DagInit *DI) { std::make_unique(Arg1.first.getElementSizeInBits())); ST.addExpander("MaskExpand", std::make_unique(Arg1.first.getNumElements())); - ST.evaluate(DI->getArg(2), Elts, std::nullopt); + ST.evaluate(DI->getArg(2), Elts, {}); std::string S = "__builtin_shufflevector(" + Arg1.second + ", " + Arg2.second; for (auto &E : Elts) { @@ -2588,11 +2588,66 @@ void NeonEmitter::runVectorTypes(raw_ostream &OS) { OS << "typedef __fp16 float16_t;\n"; OS << "#if defined(__aarch64__) || defined(__arm64ec__)\n"; + OS << "typedef __MFloat8_t __mfp8;\n"; OS << "typedef __MFloat8x8_t mfloat8x8_t;\n"; OS << "typedef __MFloat8x16_t mfloat8x16_t;\n"; OS << "typedef double float64_t;\n"; OS << "#endif\n\n"; + OS << R"( +typedef uint64_t fpm_t; + +enum __ARM_FPM_FORMAT { __ARM_FPM_E5M2, __ARM_FPM_E4M3 }; + +enum __ARM_FPM_OVERFLOW { __ARM_FPM_INFNAN, __ARM_FPM_SATURATE }; + +static __inline__ fpm_t __attribute__((__always_inline__, __nodebug__)) +__arm_fpm_init(void) { + return 0; +} + +static __inline__ fpm_t __attribute__((__always_inline__, __nodebug__)) +__arm_set_fpm_src1_format(fpm_t __fpm, enum __ARM_FPM_FORMAT __format) { + return (__fpm & ~7ull) | (fpm_t)__format; +} + +static __inline__ fpm_t __attribute__((__always_inline__, __nodebug__)) +__arm_set_fpm_src2_format(fpm_t __fpm, enum __ARM_FPM_FORMAT __format) { + return (__fpm & ~0x38ull) | ((fpm_t)__format << 3u); +} + +static __inline__ fpm_t __attribute__((__always_inline__, __nodebug__)) +__arm_set_fpm_dst_format(fpm_t __fpm, enum __ARM_FPM_FORMAT __format) { + return (__fpm & ~0x1c0ull) | ((fpm_t)__format << 6u); +} + +static __inline__ fpm_t __attribute__((__always_inline__, __nodebug__)) +__arm_set_fpm_overflow_mul(fpm_t __fpm, enum __ARM_FPM_OVERFLOW __behaviour) { + return (__fpm & ~0x4000ull) | ((fpm_t)__behaviour << 14u); +} + +static __inline__ fpm_t __attribute__((__always_inline__, __nodebug__)) +__arm_set_fpm_overflow_cvt(fpm_t __fpm, enum __ARM_FPM_OVERFLOW __behaviour) { + return (__fpm & ~0x8000ull) | ((fpm_t)__behaviour << 15u); +} + +static __inline__ fpm_t __attribute__((__always_inline__, __nodebug__)) +__arm_set_fpm_lscale(fpm_t __fpm, uint64_t __scale) { + return (__fpm & ~0x7f0000ull) | (__scale << 16u); +} + +static __inline__ fpm_t __attribute__((__always_inline__, __nodebug__)) +__arm_set_fpm_nscale(fpm_t __fpm, int64_t __scale) { + return (__fpm & ~0xff000000ull) | (((fpm_t)__scale & 0xffu) << 24u); +} + +static __inline__ fpm_t __attribute__((__always_inline__, __nodebug__)) +__arm_set_fpm_lscale2(fpm_t __fpm, uint64_t __scale) { + return (uint32_t)__fpm | (__scale << 32u); +} + +)"; + emitNeonTypeDefs("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQd", OS); emitNeonTypeDefs("bQb", OS); diff --git a/clang/www/analyzer/faq.html b/clang/www/analyzer/faq.html index 156d383db2f2343d26d8190b1348eff9f614dba7..b447968087fe9cfbb9e109f3d8e478d5789aa250 100644 --- a/clang/www/analyzer/faq.html +++ b/clang/www/analyzer/faq.html @@ -3,12 +3,11 @@ FAQ and How to Deal with Common False Positives + + - @@ -18,242 +17,11 @@

FAQ and How to Deal with Common False Positives

+

This page is deprecated and will be removed in release 21.0

+

Its content was migrated to the regular LLVM documentation.

+ -
    -
  1. How do I tell the analyzer that I do not want the bug being -reported here since my custom error handler will safely end the execution before -the bug is reached?
  2. -
  3. The analyzer reports a null dereference, but I know that the -pointer is never null. How can I tell the analyzer that a pointer can never be -null?
  4. -
  5. How do I tell the static analyzer that I don't care about a specific dead store?
  6. -
  7. How do I tell the static analyzer that I don't care about a specific unused instance variable in Objective C?
  8. -
  9. How do I tell the static analyzer that I don't care about a specific unlocalized string?
  10. -
  11. How do I tell the analyzer that my instance variable does not need to be released in -dealloc under Manual Retain/Release?
  12. -
  13. How do I decide whether a method's return type should be _Nullable or _Nonnull?
  14. -
  15. How do I tell the analyzer that I am intentionally violating nullability?
  16. -
  17. The analyzer assumes that a loop body is never entered. How can I tell it that the loop body will be entered at least once?
  18. -
  19. How can I suppress a specific analyzer warning?
  20. -
  21. How can I selectively exclude code the analyzer examines?
  22. -
- - -

Q: How do I tell the analyzer that I do not want the bug being -reported here since my custom error handler will safely end the execution before -the bug is reached?

- -example custom assert - -

You can tell the analyzer that this path is unreachable by teaching it about your custom assertion handlers. For example, you can modify the code segment as following.

- -
-void customAssert() __attribute__((analyzer_noreturn));
-int foo(int *b) {
-  if (!b)
-    customAssert();
-  return *b;
-}
- - -

Q: The analyzer reports a null dereference, but I know that the -pointer is never null. How can I tell the analyzer that a pointer can never be -null?

- -example null pointer - -

The reason the analyzer often thinks that a pointer can be null is because the preceding code checked compared it against null. So if you are absolutely sure that it cannot be null, remove the preceding check and, preferably, add an assertion as well. For example, in the code segment above, it will be sufficient to remove the if (!b) check.

- -
-void usePointer(int *b);
-int foo(int *b) {
-  usePointer(b);
-  return *b;
-}
- -

Q: How do I tell the static analyzer that I don't care about a specific dead store?

- -

When the analyzer sees that a value stored into a variable is never used, it's going to produce a message similar to this one: -

Value stored to 'x' is never read
-You can use the (void)x; idiom to acknowledge that there is a dead store in your code but you do not want it to be reported in the future.

- -

Q: How do I tell the static analyzer that I don't care about a specific unused instance variable in Objective C?

- -

When the analyzer sees that a value stored into a variable is never used, it is going to produce a message similar to this one: -

Instance variable 'commonName' in class 'HappyBird' is never used by the methods in its @implementation
-You can add __attribute__((unused)) to the instance variable declaration to suppress the warning.

- -

Q: How do I tell the static analyzer that I don't care about a specific unlocalized string?

- -

When the analyzer sees that an unlocalized string is passed to a method that will present that string to the user, it is going to produce a message similar to this one: -

User-facing text should use localized string macro
- -If your project deliberately uses unlocalized user-facing strings (for example, in a debugging UI that is never shown to users), you can suppress the analyzer warnings (and document your intent) with a function that just returns its input but is annotated to return a localized string: -
-__attribute__((annotate("returns_localized_nsstring")))
-static inline NSString *LocalizationNotNeeded(NSString *s) {
-  return s;
-}
-
- -You can then call this function when creating your debugging UI: -
-[field setStringValue:LocalizationNotNeeded(@"Debug")];
-
- -Some projects may also find it useful to use NSLocalizedString but add "DNL" or "Do Not Localize" to the string contents as a convention: -
-UILabel *testLabel = [[UILabel alloc] init];
-NSString *s = NSLocalizedString(@"Hello <Do Not Localize>", @"For debug purposes");
-[testLabel setText:s];
-
-

- -

Q: How do I tell the analyzer that my instance variable does not need to be released in -dealloc under Manual Retain/Release?

- -

If your class only uses an instance variable for part of its lifetime, it may -maintain an invariant guaranteeing that the instance variable is always released -before -dealloc. In this case, you can silence a warning about a missing release -by either adding assert(_ivar == nil) or an explicit release -[_ivar release] (which will be a no-op when the variable is nil) in --dealloc.

- -

Q: How do I decide whether a method's return type should be _Nullable or _Nonnull?

- -

Depending on the implementation of the method, this puts you in one of five situations: -

    -
  1. You actually never return nil.
  2. -
  3. You do return nil sometimes, and callers are supposed to handle that. This -includes cases where your method is documented to return nil given certain -inputs.
  4. -
  5. You return nil based on some external condition (such as an out-of-memory -error), but the client can't do anything about it either.
  6. -
  7. You return nil only when the caller passes input documented to be invalid. -That means it's the client's fault.
  8. -
  9. You return nil in some totally undocumented case.
  10. -
-

- -

In (1) you should annotate the method as returning a _Nonnull -object.

-

In (2) the method should be marked _Nullable.

-

In (3) you should probably annotate the method _Nonnull. Why? -Because no callers will actually check for nil, given that they can't do -anything about the situation and don't know what went wrong. At this point -things have gone so poorly that there's basically no way to recover.

-

The least happy case is (4) because the resulting program will almost -certainly either crash or just silently do the wrong thing. -If this is a new method or you control the callers, you can use -NSParameterAssert() (or the equivalent) to check the precondition and -remove the nil return. But if you don't control the callers and they rely on -this behavior, you should return mark the method _Nonnull and return -nil cast to _Nonnull anyway. -(Note that (4) doesn't apply in cases where the caller can't know they passed -bad parameters. For example, -+[NSData dataWithContentsOfFile:options:error:] will fail if the file -doesn't exist, but there's no way to check for that in advance. This means -you're really in (2).)

-

If you're in (5), document it, then figure out if you're now in (2), (3), or -(4). :-)

- -

Q: How do I tell the analyzer that I am intentionally violating nullability?

- -

In some cases, it may make sense for methods to intentionally violate -nullability. For example, your method may — for reasons of backward -compatibility — chose to return nil and log an error message in a method -with a non-null return type when the client violated a documented precondition -rather than check the precondition with NSAssert(). In these cases, you -can suppress the analyzer warning with a cast: -

-    return (id _Nonnull)nil;
-
-Note that this cast does not affect code generation. -

- -

Q: The analyzer assumes that a loop body is never entered. How can I tell it that the loop body will be entered at least once?

- -example use assert - -

In the contrived example above, the analyzer has detected that the body of -the loop is never entered for the case where length <= 0. In this -particular example, you may know that the loop will always be entered because -the input parameter length will be greater than zero in all calls to this -function. You can teach the analyzer facts about your code as well as document -it by using assertions. By adding assert(length > 0) in the beginning -of the function, you tell the analyzer that your code is never expecting a zero -or a negative value, so it won't need to test the correctness of those paths. -

- -
-int foo(int length) {
-  int x = 0;
-  assert(length > 0);
-  for (int i = 0; i < length; i++)
-    x += 1;
-  return length/x;
-}
-
- -

Q: How can I suppress a specific analyzer warning?

- -

When you encounter an analyzer bug/false positive, check if it's one of the -issues discussed above or if the analyzer -annotations can -resolve the issue by helping the static analyzer understand the code better. -Second, please report it to help us improve -user experience.

- -

Sometimes there's really no "good" way to eliminate the issue. In such cases -you can "silence" it directly by annotating the problematic line of code with -the help of Clang attribute 'suppress': - -

-int foo() {
-  int *x = nullptr;
-  ...
-  [[clang::suppress]] {
-    // all warnings in this scope are suppressed
-    int y = *x;
-  }
-
-  // null pointer dereference warning suppressed on the next line
-  [[clang::suppress]]
-  return *x
-}
-
-int bar(bool coin_flip) {
-  // suppress all memory leak warnings about this allocation
-  [[clang::suppress]]
-  int *result = (int *)malloc(sizeof(int));
-
-  if (coin_flip)
-    return 0;      // including this leak path
-
-  return *result;  // as well as this leak path
-}
-
- - -

You can also consider using __clang_analyzer__ macro -described below.

- -

Q: How can I selectively exclude code the analyzer examines?

- -

When the static analyzer is using clang to parse source files, it implicitly -defines the preprocessor macro __clang_analyzer__. One can use this -macro to selectively exclude code the analyzer examines. Here is an example: - -

-#ifndef __clang_analyzer__
-// Code not to be analyzed
-#endif
-
- -This usage is discouraged because it makes the code dead to the analyzer from -now on. Instead, we prefer that users file bugs against the analyzer when it flags -false positives. -

- -
- + + diff --git a/clang/www/analyzer/index.html b/clang/www/analyzer/index.html index ea0ed4967ec7cced58a8fa7f5953f67562146804..736ac4aa0f656222fa827a1f4f49e5c618b1af8a 100644 --- a/clang/www/analyzer/index.html +++ b/clang/www/analyzer/index.html @@ -72,45 +72,9 @@

The Clang Static Analyzer is a source code analysis tool that finds bugs in C, C++, and Objective-C programs.

-

Currently it can be run either from the command - line or if you use macOS then within Xcode. When -invoked from the command line, it is intended to be run in tandem with a build -of a codebase.

- -

The analyzer is 100% open source and is part of the Clang project. Like the rest of Clang, the -analyzer is implemented as a C++ library that can be used by other tools and -applications.

- -

Download

- -
- - - - - - -
-
-

Mac OS X

- -
-
- - - - - - -
+

The analyzer is 100% open source and is part of the Clang +project. Like the rest of Clang, the analyzer is implemented as a C++ library +that can be used by other tools and applications.

@@ -121,10 +85,27 @@ applications.

-

Other Platforms

-

For other platforms, please follow the instructions for building the analyzer from - source code.

+ +

To get started with the Clang Static Analyzer, visit the + LLVM + releases page for download and installation instructions. The official + releases include both the analyzer and scan-build, + a command-line tool for running the analyzer on your codebase.

+ +

If you're installing Clang from a different source, such as + a Linux package repository, then scan-build may be packaged + separately as an individual package, or as part of + a "clang tools" package.

+ +

If your IDE is using Clang, it may natively integrate the static analyzer. + On macOS, the easiest way to use the static analyzer is to invoke it + directly + from Xcode.

+ +

Additionally, if you're using clang-tidy, + you can naturally make the static analyzer run alongside clang-tidy + by enabling the clang-analyzer + checks.

diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 82ba9b370ba5953805a570bb266519ee1168bbd5..186f7cc0ace5465b37876f9c5cae4e3123a9667b 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -1721,7 +1721,7 @@ of class templates 279 CD6 Correspondence of "names for linkage purposes" - Unknown + No 280 @@ -2075,7 +2075,7 @@ of class templates 338 CD6 Enumerator name with linkage used as class name in other translation unit - Unknown + Duplicate of 1884 339 @@ -11131,7 +11131,7 @@ and POD class 1884 CD6 Unclear requirements for same-named external-linkage entities - Unknown + Partial 1885 @@ -11219,7 +11219,7 @@ and POD class 1898 CD6 Use of “equivalent” in overload resolution - Unknown + Clang 2.7 1899 diff --git a/clang/www/index.html b/clang/www/index.html index 95bbfa86172ba40fd07a09c450d1080127f24bce..465a6a6d29dc7654b73075d712b6cf05b24468ad 100755 --- a/clang/www/index.html +++ b/clang/www/index.html @@ -16,8 +16,8 @@

The Clang project provides a language front-end and tooling infrastructure - for languages in the C language family (C, C++, Objective C/C++, OpenCL, - CUDA, and RenderScript) for the LLVM + for languages in the C language family (C, C++, Objective C/C++, OpenCL, and + CUDA) for the LLVM project. Both a GCC-compatible compiler driver (clang) and an MSVC-compatible compiler driver (clang-cl.exe) are provided. You can get and build the source today.

diff --git a/cmake/Modules/HandleCompilerRT.cmake b/cmake/Modules/HandleCompilerRT.cmake index 0a7c56bc6309343f487024a72eb8cadd1fc6ec32..9398d99afdd013a115064242c401197bdda99fbd 100644 --- a/cmake/Modules/HandleCompilerRT.cmake +++ b/cmake/Modules/HandleCompilerRT.cmake @@ -5,7 +5,7 @@ # COMPILER_RT_LIBRARY-- to NOTFOUND function(cache_compiler_rt_library err_flag name target library_file) if(err_flag OR NOT EXISTS "${library_file}") - message(STATUS "Failed to find compiler-rt ${name} library for ${target}") + message(WARNING "Failed to find compiler-rt ${name} library for ${target}") set(COMPILER_RT_LIBRARY_${name}_${target} "NOTFOUND" CACHE INTERNAL "compiler-rt ${name} library for ${target}") else() diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt index f6072aa40fad0d56e427d947f38afc20d7e945a4..20054c6e85a407c7315b9fda075f2973d250a831 100644 --- a/compiler-rt/CMakeLists.txt +++ b/compiler-rt/CMakeLists.txt @@ -44,6 +44,22 @@ include(CompilerRTUtils) include(CMakeDependentOption) include(GetDarwinLinkerVersion) +include(CheckCXXCompilerFlag) + +# Check if we can compile with --no-default-config, or if that omits a config +# file that is essential for the toolchain to work properly. +# +# Using CMAKE_REQUIRED_FLAGS to make sure the flag is used both for compilation +# and for linking. +# +# Doing this test early on, to see if the flag works on the toolchain +# out of the box. Later on, we end up adding -nostdlib and similar flags +# to all test compiles, which easily can give false positives on this test. +set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") +set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} --no-default-config") +check_cxx_compiler_flag("" COMPILER_RT_HAS_NO_DEFAULT_CONFIG_FLAG) +set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}") + option(COMPILER_RT_BUILD_BUILTINS "Build builtins" ON) mark_as_advanced(COMPILER_RT_BUILD_BUILTINS) option(COMPILER_RT_DISABLE_AARCH64_FMV "Disable AArch64 Function Multi Versioning support" OFF) diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake index d00d39518104bf5de3252e11dc327260b87db3f8..fb4dfa7bd09dfea35db244809c0fac3e4c17cca2 100644 --- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake +++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake @@ -104,6 +104,7 @@ else() set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} powerpc64le ${HEXAGON} ${LOONGARCH64}) endif() +set(ALL_XRAY_DSO_SUPPORTED_ARCH ${X86_64}) set(ALL_SHADOWCALLSTACK_SUPPORTED_ARCH ${ARM64}) if (UNIX) diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake index a494e0532a50bca78e0cdd817b2ffe30a97ec64f..431f544e8ad6a714fa712927c834d5e52d487bc4 100644 --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -668,6 +668,9 @@ if(APPLE) list_intersect(XRAY_SUPPORTED_ARCH ALL_XRAY_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH) + list_intersect(XRAY_DSO_SUPPORTED_ARCH + ALL_XRAY_DSO_SUPPORTED_ARCH + SANITIZER_COMMON_SUPPORTED_ARCH) list_intersect(SHADOWCALLSTACK_SUPPORTED_ARCH ALL_SHADOWCALLSTACK_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH) @@ -702,6 +705,7 @@ else() filter_available_targets(CFI_SUPPORTED_ARCH ${ALL_CFI_SUPPORTED_ARCH}) filter_available_targets(SCUDO_STANDALONE_SUPPORTED_ARCH ${ALL_SCUDO_STANDALONE_SUPPORTED_ARCH}) filter_available_targets(XRAY_SUPPORTED_ARCH ${ALL_XRAY_SUPPORTED_ARCH}) + filter_available_targets(XRAY_DSO_SUPPORTED_ARCH ${ALL_XRAY_DSO_SUPPORTED_ARCH}) filter_available_targets(SHADOWCALLSTACK_SUPPORTED_ARCH ${ALL_SHADOWCALLSTACK_SUPPORTED_ARCH}) filter_available_targets(GWP_ASAN_SUPPORTED_ARCH ${ALL_GWP_ASAN_SUPPORTED_ARCH}) diff --git a/compiler-rt/include/fuzzer/FuzzedDataProvider.h b/compiler-rt/include/fuzzer/FuzzedDataProvider.h index 5903ed837917ca9a1ffe6630e6b96771ae319e62..e57b95b6304a9a058c155e1c632b2dfbfc34220a 100644 --- a/compiler-rt/include/fuzzer/FuzzedDataProvider.h +++ b/compiler-rt/include/fuzzer/FuzzedDataProvider.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/compiler-rt/include/xray/xray_interface.h b/compiler-rt/include/xray/xray_interface.h index 727431c04e4f736d593c6ad2b304af4ebf5fa9c5..675ea0cbc48c83d234a171d0b06128136b2cce0d 100644 --- a/compiler-rt/include/xray/xray_interface.h +++ b/compiler-rt/include/xray/xray_interface.h @@ -93,31 +93,78 @@ enum XRayPatchingStatus { FAILED = 3, }; -/// This tells XRay to patch the instrumentation points. See XRayPatchingStatus -/// for possible result values. +/// This tells XRay to patch the instrumentation points in all currently loaded +/// objects. See XRayPatchingStatus for possible result values. extern XRayPatchingStatus __xray_patch(); +/// This tells XRay to patch the instrumentation points in the given object. +/// See XRayPatchingStatus for possible result values. +extern XRayPatchingStatus __xray_patch_object(int32_t ObjId); + /// Reverses the effect of __xray_patch(). See XRayPatchingStatus for possible /// result values. extern XRayPatchingStatus __xray_unpatch(); -/// This patches a specific function id. See XRayPatchingStatus for possible +/// Reverses the effect of __xray_patch_object. See XRayPatchingStatus for +/// possible result values. +extern XRayPatchingStatus __xray_unpatch_object(int32_t ObjId); + +/// This unpacks the given (packed) function id and patches +/// the corresponding function. See XRayPatchingStatus for possible /// result values. extern XRayPatchingStatus __xray_patch_function(int32_t FuncId); -/// This unpatches a specific function id. See XRayPatchingStatus for possible +/// This patches a specific function in the given object. See XRayPatchingStatus +/// for possible result values. +extern XRayPatchingStatus __xray_patch_function_in_object(int32_t FuncId, + int32_t ObjId); + +/// This unpacks the given (packed) function id and unpatches +/// the corresponding function. See XRayPatchingStatus for possible /// result values. extern XRayPatchingStatus __xray_unpatch_function(int32_t FuncId); -/// This function returns the address of the function provided a valid function -/// id. We return 0 if we encounter any error, even if 0 may be a valid function -/// address. +/// This unpatches a specific function in the given object. +/// See XRayPatchingStatus for possible result values. +extern XRayPatchingStatus __xray_unpatch_function_in_object(int32_t FuncId, + int32_t ObjId); + +/// This function unpacks the given (packed) function id and returns the address +/// of the corresponding function. We return 0 if we encounter any error, even +/// if 0 may be a valid function address. extern uintptr_t __xray_function_address(int32_t FuncId); -/// This function returns the maximum valid function id. Returns 0 if we -/// encounter errors (when there are no instrumented functions, etc.). +/// This function returns the address of the function in the given object +/// provided valid function and object ids. We return 0 if we encounter any +/// error, even if 0 may be a valid function address. +extern uintptr_t __xray_function_address_in_object(int32_t FuncId, + int32_t ObjId); + +/// This function returns the maximum valid function id for the main executable +/// (object id = 0). Returns 0 if we encounter errors (when there are no +/// instrumented functions, etc.). extern size_t __xray_max_function_id(); +/// This function returns the maximum valid function id for the given object. +/// Returns 0 if we encounter errors (when there are no instrumented functions, +/// etc.). +extern size_t __xray_max_function_id_in_object(int32_t ObjId); + +/// This function returns the number of previously registered objects +/// (executable + loaded DSOs). Returns 0 if XRay has not been initialized. +extern size_t __xray_num_objects(); + +/// Unpacks the function id from the given packed id. +extern int32_t __xray_unpack_function_id(int32_t PackedId); + +/// Unpacks the object id from the given packed id. +extern int32_t __xray_unpack_object_id(int32_t PackedId); + +/// Creates and returns a packed id from the given function and object ids. +/// If the ids do not fit within the reserved number of bits for each part, the +/// high bits are truncated. +extern int32_t __xray_pack_id(int32_t FuncId, int32_t ObjId); + /// Initialize the required XRay data structures. This is useful in cases where /// users want to control precisely when the XRay instrumentation data /// structures are initialized, for example when the XRay library is built with diff --git a/compiler-rt/lib/asan/scripts/asan_symbolize.py b/compiler-rt/lib/asan/scripts/asan_symbolize.py index b08769614aeb18f102989bf9af8e55c5f02b2f06..058a1614b55e6a7d42ca79035585203ec9aa8f82 100755 --- a/compiler-rt/lib/asan/scripts/asan_symbolize.py +++ b/compiler-rt/lib/asan/scripts/asan_symbolize.py @@ -316,7 +316,7 @@ class DarwinSymbolizer(Symbolizer): # * For C functions atos omits parentheses and argument types. # * For C++ functions the function name (i.e., `foo` above) may contain # templates which may contain parentheses. - match = re.match("^(.*) \(in (.*)\) \((.*:\d*)\)$", atos_line) + match = re.match(r"^(.*) \(in (.*)\) \((.*:\d*)\)$", atos_line) logging.debug("atos_line: %s", atos_line) if match: function_name = match.group(1) @@ -541,7 +541,7 @@ class SymbolizationLoop(object): # names in the regex because it could be an # Objective-C or C++ demangled name. stack_trace_line_format = ( - "^( *#([0-9]+) *)(0x[0-9a-f]+) *(?:in *.+)? *\((.*)\+(0x[0-9a-f]+)\)" + r"^( *#([0-9]+) *)(0x[0-9a-f]+) *(?:in *.+)? *\((.*)\+(0x[0-9a-f]+)\)" ) match = re.match(stack_trace_line_format, line) if not match: diff --git a/compiler-rt/lib/builtins/cpu_model/x86.c b/compiler-rt/lib/builtins/cpu_model/x86.c index 7fa4b9e2b66082c0cb71d13830dbac37ef95382a..bfa478c4427a5bf420a15fa2afc8a2545ee12e00 100644 --- a/compiler-rt/lib/builtins/cpu_model/x86.c +++ b/compiler-rt/lib/builtins/cpu_model/x86.c @@ -229,6 +229,7 @@ enum ProcessorFeatures { FEATURE_AVX10_1_512, FEATURE_AVX10_2_256, FEATURE_AVX10_2_512, + FEATURE_MOVRS, CPU_FEATURE_MAX }; @@ -972,6 +973,8 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, setFeature(FEATURE_HRESET); if (HasLeaf7Subleaf1 && ((EAX >> 23) & 1) && HasAVXSave) setFeature(FEATURE_AVXIFMA); + if (HasLeaf7Subleaf1 && ((EAX >> 31) & 1)) + setFeature(FEATURE_MOVRS); if (HasLeaf7Subleaf1 && ((EDX >> 4) & 1) && HasAVXSave) setFeature(FEATURE_AVXVNNIINT8); diff --git a/compiler-rt/lib/hwasan/hwasan_platform_interceptors.h b/compiler-rt/lib/hwasan/hwasan_platform_interceptors.h index e8011014c2331d7ce9de7832daa1a5a84a2de04e..d92b51052194275d41bcfdbb25a2a78a43cf7561 100644 --- a/compiler-rt/lib/hwasan/hwasan_platform_interceptors.h +++ b/compiler-rt/lib/hwasan/hwasan_platform_interceptors.h @@ -200,9 +200,6 @@ #undef SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID #define SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID 0 -#undef SANITIZER_INTERCEPT_TIMER_CREATE -#define SANITIZER_INTERCEPT_TIMER_CREATE 0 - #undef SANITIZER_INTERCEPT_GETITIMER #define SANITIZER_INTERCEPT_GETITIMER 0 diff --git a/compiler-rt/lib/hwasan/scripts/hwasan_symbolize b/compiler-rt/lib/hwasan/scripts/hwasan_symbolize index d1b2857ccd8156f06a73364559e9bced490bd4ae..efca6b82809b970b645c0862f5909d51a5710f6f 100755 --- a/compiler-rt/lib/hwasan/scripts/hwasan_symbolize +++ b/compiler-rt/lib/hwasan/scripts/hwasan_symbolize @@ -316,7 +316,7 @@ class Symbolizer: self.__last_access_tag = int(match.group(2), 16) def process_tag_dump_line(self, line, ignore_tags=False): - m = re.match(r'.*?(0x[0-9a-f]+):' + '([ ]*[\[ ][0-9a-f][0-9a-f]\]?)' * 16, line) + m = re.match(r'.*?(0x[0-9a-f]+):' + r'([ ]*[\[ ][0-9a-f][0-9a-f]\]?)' * 16, line) if m is None: return False addr = m.group(1) diff --git a/compiler-rt/lib/msan/tests/msan_test.cpp b/compiler-rt/lib/msan/tests/msan_test.cpp index ad265acf4c1e39a703c32f730c67b283efc29664..41b99fabe84f4789d3ae179ed3f3bb4aefb812c5 100644 --- a/compiler-rt/lib/msan/tests/msan_test.cpp +++ b/compiler-rt/lib/msan/tests/msan_test.cpp @@ -4881,27 +4881,4 @@ TEST(MemorySanitizer, throw_catch) { // pass } } - -#if defined(__linux__) -TEST(MemorySanitizer, timer_create) { - timer_t timer; - EXPECT_POISONED(timer); - int res = timer_create(CLOCK_REALTIME, nullptr, &timer); - ASSERT_EQ(0, res); - EXPECT_NOT_POISONED(timer); - - // Make sure the timer is usable. - struct itimerspec cur_value {}; - cur_value.it_value.tv_sec = 1; - EXPECT_EQ(0, timer_settime(timer, 0, &cur_value, nullptr)); - - timer_t timer2; - EXPECT_POISONED(timer2); - // Use an invalid clock_id to make timer_create fail. - res = timer_create(INT_MAX, nullptr, &timer2); - ASSERT_EQ(-1, res); - EXPECT_POISONED(timer2); - timer_delete(timer); -} -#endif } // namespace diff --git a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp index 63b0ca28a1f409c3a81554769c65da6ee6542124..890d6c11c407623b239ebbc923be98d1bd13e8e4 100644 --- a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp +++ b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp @@ -8,12 +8,14 @@ // //===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_platform.h" +#if SANITIZER_POSIX + #include "rtsan/rtsan_interceptors.h" #include "interception/interception.h" #include "sanitizer_common/sanitizer_allocator_dlsym.h" #include "sanitizer_common/sanitizer_allocator_internal.h" -#include "sanitizer_common/sanitizer_platform.h" #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "interception/interception.h" @@ -608,3 +610,5 @@ void __rtsan::InitializeInterceptors() { INTERCEPT_FUNCTION(recvfrom); INTERCEPT_FUNCTION(shutdown); } + +#endif // SANITIZER_POSIX diff --git a/compiler-rt/lib/rtsan/tests/rtsan_test_functional.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_functional.cpp index 9e455f0326a549eb789a38bd7f902de254c83f1a..ed9ee4ded7b05988a92bc342f67c6eedda1ce55f 100644 --- a/compiler-rt/lib/rtsan/tests/rtsan_test_functional.cpp +++ b/compiler-rt/lib/rtsan/tests/rtsan_test_functional.cpp @@ -204,11 +204,11 @@ TEST(TestRtsan, ThrowingAnExceptionDiesWhenRealtime) { TEST(TestRtsan, DoesNotDieIfTurnedOff) { std::mutex mutex; - auto RealtimeUnsafeFunc = [&]() { + auto RealtimeBlockingFunc = [&]() { __rtsan_disable(); mutex.lock(); mutex.unlock(); __rtsan_enable(); }; - RealtimeInvoke(RealtimeUnsafeFunc); + RealtimeInvoke(RealtimeBlockingFunc); } diff --git a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp index f7a281f13e2ff659b8aad33e1b3947e84afea2b5..6233c3e91800e10e06b0f04e9a71b46c88b9bb91 100644 --- a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp +++ b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp @@ -8,9 +8,11 @@ // //===----------------------------------------------------------------------===// +#include "sanitizer_common/sanitizer_platform.h" +#if SANITIZER_POSIX + #include "gtest/gtest.h" -#include "sanitizer_common/sanitizer_platform.h" #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "rtsan_test_utilities.h" @@ -704,3 +706,5 @@ TEST(TestRtsanInterceptors, ShutdownOnASocketDiesWhenRealtime) { ExpectRealtimeDeath(Func, "shutdown"); ExpectNonRealtimeSurvival(Func); } + +#endif // SANITIZER_POSIX diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cpp index 1d5058c81acbcd31f0f19ac71ec08fc96594b44e..9d899371c2dd90feeed3038c7ffbd7e19cb472bd 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cpp @@ -59,7 +59,7 @@ static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache, static void *RawInternalRealloc(void *ptr, uptr size, InternalAllocatorCache *cache) { - uptr alignment = 8; + constexpr usize alignment = Max(8, sizeof(void *)); if (cache == 0) { SpinMutexLock l(&internal_allocator_cache_mu); return internal_allocator()->Reallocate(&internal_allocator_cache, ptr, @@ -137,7 +137,8 @@ void InternalAllocatorUnlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { } // LowLevelAllocator -constexpr uptr kLowLevelAllocatorDefaultAlignment = 8; +constexpr usize kLowLevelAllocatorDefaultAlignment = + Max(8, sizeof(void *)); constexpr uptr kMinNumPagesRounded = 16; constexpr uptr kMinRoundedSize = 65536; static uptr low_level_alloc_min_alignment = kLowLevelAllocatorDefaultAlignment; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 211f9f70d7e4c6c54ac4b8778f97c61bdee55b98..b8627f8557afe29c10a37211fbc7f7cf6fc8221b 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -2289,24 +2289,6 @@ INTERCEPTOR(int, pthread_getcpuclockid, uptr thread, #define INIT_CLOCK_GETCPUCLOCKID #endif -#if SANITIZER_INTERCEPT_TIMER_CREATE -INTERCEPTOR(int, timer_create, __sanitizer_clockid_t clockid, void *sevp, - __sanitizer_timer_t *timer) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, timer_create, clockid, sevp, timer); - int res = REAL(timer_create)(clockid, sevp, timer); - if (!res && timer) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, timer, sizeof *timer); - } - return res; -} - -# define INIT_TIMER_CREATE \ - COMMON_INTERCEPT_FUNCTION_GLIBC_VER_MIN(timer_create, "GLIBC_2.3.3"); -#else -# define INIT_TIMER_CREATE -#endif - #if SANITIZER_INTERCEPT_GETITIMER INTERCEPTOR(int, getitimer, int which, void *curr_value) { void *ctx; @@ -10284,7 +10266,6 @@ static void InitializeCommonInterceptors() { INIT_SETPWENT; INIT_CLOCK_GETTIME; INIT_CLOCK_GETCPUCLOCKID; - INIT_TIMER_CREATE; INIT_GETITIMER; INIT_TIME; INIT_GLOB; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 36fafdc642642bf758afc2879f36ea7d977116d9..6959a6d52d604e01b82b561733057e598e1f4c2e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -237,9 +237,6 @@ (SI_FREEBSD || SI_NETBSD || SI_LINUX || SI_SOLARIS) #define SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID \ (SI_LINUX || SI_FREEBSD || SI_NETBSD) -// TODO: This should be SI_POSIX, adding Linux first until I have time -// to verify all timer_t typedefs on other platforms. -#define SANITIZER_INTERCEPT_TIMER_CREATE SI_LINUX #define SANITIZER_INTERCEPT_GETITIMER SI_POSIX #define SANITIZER_INTERCEPT_TIME SI_POSIX #define SANITIZER_INTERCEPT_GLOB (SI_GLIBC || SI_SOLARIS) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h index b4ccf7b3d7bef4877ec82debbfd62ed0d4dffb0d..e8c81aa8e281637b74f7fff5660e8d07b0089412 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -1517,10 +1517,6 @@ extern const int si_SEGV_ACCERR; #define SIGACTION_SYMNAME sigaction -# if SANITIZER_LINUX -typedef void *__sanitizer_timer_t; -# endif - #endif // SANITIZER_LINUX || SANITIZER_APPLE #endif diff --git a/compiler-rt/lib/xray/CMakeLists.txt b/compiler-rt/lib/xray/CMakeLists.txt index cf7b5062aae32d32ea876d5d0019aa19ece89b41..f38c07420c9abf366717723f52d2a2ced5a7eac5 100644 --- a/compiler-rt/lib/xray/CMakeLists.txt +++ b/compiler-rt/lib/xray/CMakeLists.txt @@ -10,6 +10,10 @@ set(XRAY_SOURCES xray_utils.cpp ) +set(XRAY_DSO_SOURCES + xray_dso_init.cpp + ) + # Implementation files for all XRay modes. set(XRAY_FDR_MODE_SOURCES xray_fdr_flags.cpp @@ -33,6 +37,11 @@ set(x86_64_SOURCES xray_trampoline_x86_64.S ) +set(x86_64_DSO_SOURCES + xray_trampoline_x86_64.S + ) + + set(arm_SOURCES xray_arm.cpp xray_trampoline_arm.S @@ -128,10 +137,12 @@ set(XRAY_IMPL_HEADERS # consumption by tests. set(XRAY_ALL_SOURCE_FILES ${XRAY_SOURCES} + ${XRAY_DSO_SOURCES} ${XRAY_FDR_MODE_SOURCES} ${XRAY_BASIC_MODE_SOURCES} ${XRAY_PROFILING_MODE_SOURCES} ${x86_64_SOURCES} + ${x86_64_DSO_SOURCES} ${arm_SOURCES} ${armhf_SOURCES} ${hexagon_SOURCES} @@ -162,6 +173,9 @@ set(XRAY_CFLAGS ${COMPILER_RT_CXX_CFLAGS}) set(XRAY_COMMON_DEFINITIONS SANITIZER_COMMON_NO_REDEFINE_BUILTINS XRAY_HAS_EXCEPTIONS=1) +# DSO trampolines need to be compiled with GOT addressing +set(XRAY_COMMON_DEFINITIONS_DSO ${XRAY_COMMON_DEFINITIONS} XRAY_PIC) + # Too many existing bugs, needs cleanup. append_list_if(COMPILER_RT_HAS_WNO_FORMAT -Wno-format XRAY_CFLAGS) @@ -201,7 +215,16 @@ if (APPLE) CFLAGS ${XRAY_CFLAGS} DEFS ${XRAY_COMMON_DEFINITIONS} DEPS ${XRAY_DEPS}) + add_compiler_rt_object_libraries(RTXrayDSO + OS ${XRAY_SUPPORTED_OS} + ARCHS ${XRAY_DSO_SUPPORTED_ARCH} + SOURCES ${XRAY_DSO_SOURCES} + ADDITIONAL_HEADERS ${XRAY_IMPL_HEADERS} + CFLAGS ${XRAY_CFLAGS} + DEFS ${XRAY_COMMON_DEFINITIONS_DSO} + DEPS ${XRAY_DEPS}) set(XRAY_RTXRAY_ARCH_LIBS "") + set(XRAY_DSO_RTXRAY_ARCH_LIBS "") foreach(arch ${XRAY_SUPPORTED_ARCH}) if(NOT ${arch} IN_LIST XRAY_SOURCE_ARCHS) continue() @@ -215,6 +238,17 @@ if (APPLE) DEFS ${XRAY_COMMON_DEFINITIONS} DEPS ${XRAY_DEPS}) list(APPEND XRAY_RTXRAY_ARCH_LIBS RTXray_${arch}) + if (${arch} IN_LIST XRAY_DSO_SUPPORTED_ARCH) + add_compiler_rt_object_libraries(RTXrayDSO_${arch} + OS ${XRAY_SUPPORTED_OS} + ARCHS ${XRAY_DSO_SUPPORTED_ARCH} + SOURCES ${${arch}_DSO_SOURCES} + ADDITIONAL_HEADERS ${XRAY_IMPL_HEADERS} + CFLAGS ${XRAY_CFLAGS} + DEFS ${XRAY_COMMON_DEFINITIONS_DSO} + DEPS ${XRAY_DEPS}) + list(APPEND XRAY_DSO_RTXRAY_ARCH_LIBS RTXrayDSO_${arch}) + endif() endforeach() add_compiler_rt_object_libraries(RTXrayFDR OS ${XRAY_SUPPORTED_OS} @@ -252,6 +286,17 @@ if (APPLE) LINK_FLAGS ${XRAY_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} LINK_LIBS ${XRAY_LINK_LIBS} PARENT_TARGET xray) + add_compiler_rt_runtime(clang_rt.xray-dso + STATIC + OS ${XRAY_SUPPORTED_OS} + ARCHS ${XRAY_DSO_SUPPORTED_ARCH} + OBJECT_LIBS RTXrayDSO ${XRAY_DSO_RTXRAY_ARCH_LIBS} + CFLAGS ${XRAY_CFLAGS} + DEFS ${XRAY_COMMON_DEFINITIONS} + LINK_FLAGS ${XRAY_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} + LINK_LIBS ${XRAY_LINK_LIBS} + PARENT_TARGET xray) + add_compiler_rt_runtime(clang_rt.xray-fdr STATIC OS ${XRAY_SUPPORTED_OS} @@ -346,16 +391,37 @@ else() # not Apple DEFS ${XRAY_COMMON_DEFINITIONS} OBJECT_LIBS RTXrayBASIC PARENT_TARGET xray) - # Profiler Mode runtime - add_compiler_rt_runtime(clang_rt.xray-profiling - STATIC - ARCHS ${arch} - CFLAGS ${XRAY_CFLAGS} - LINK_FLAGS ${XRAY_LINK_FLAGS} - LINK_LIBS ${XRAY_LINK_LIBS} - DEFS ${XRAY_COMMON_DEFINITIONS} - OBJECT_LIBS RTXrayPROFILING - PARENT_TARGET xray) + # Profiler Mode runtime + add_compiler_rt_runtime(clang_rt.xray-profiling + STATIC + ARCHS ${arch} + CFLAGS ${XRAY_CFLAGS} + LINK_FLAGS ${XRAY_LINK_FLAGS} + LINK_LIBS ${XRAY_LINK_LIBS} + DEFS ${XRAY_COMMON_DEFINITIONS} + OBJECT_LIBS RTXrayPROFILING + PARENT_TARGET xray) + + if (${arch} IN_LIST XRAY_DSO_SUPPORTED_ARCH) + # TODO: Only implemented for X86 at the moment + add_compiler_rt_object_libraries(RTXrayDSO + ARCHS ${arch} + SOURCES ${XRAY_DSO_SOURCES} ${${arch}_DSO_SOURCES} + ADDITIONAL_HEADERS ${XRAY_IMPL_HEADERS} + CFLAGS ${XRAY_CFLAGS} + DEFS ${XRAY_COMMON_DEFINITIONS_DSO} + DEPS ${XRAY_DEPS}) + # DSO runtime archive + add_compiler_rt_runtime(clang_rt.xray-dso + STATIC + ARCHS ${arch} + CFLAGS ${XRAY_CFLAGS} + LINK_FLAGS ${XRAY_LINK_FLAGS} + LINK_LIBS ${XRAY_LINK_LIBS} + DEFS ${XRAY_COMMON_DEFINITIONS} + OBJECT_LIBS RTXrayDSO + PARENT_TARGET xray) + endif() endforeach() endif() # not Apple diff --git a/compiler-rt/lib/xray/xray_AArch64.cpp b/compiler-rt/lib/xray/xray_AArch64.cpp index c1d77758946edf3275a743dd8b394347ac84481b..2b151162ce4b9bd9c941de5def1dac71c67089fc 100644 --- a/compiler-rt/lib/xray/xray_AArch64.cpp +++ b/compiler-rt/lib/xray/xray_AArch64.cpp @@ -89,18 +89,23 @@ inline static bool patchSled(const bool Enable, const uint32_t FuncId, bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, - void (*Trampoline)()) XRAY_NEVER_INSTRUMENT { + const XRayTrampolines &Trampolines, + bool LogArgs) XRAY_NEVER_INSTRUMENT { + auto Trampoline = + LogArgs ? Trampolines.LogArgsTrampoline : Trampolines.EntryTrampoline; return patchSled(Enable, FuncId, Sled, Trampoline); } -bool patchFunctionExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { - return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); +bool patchFunctionExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, Trampolines.ExitTrampoline); } -bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { - return patchSled(Enable, FuncId, Sled, __xray_FunctionTailExit); +bool patchFunctionTailExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, Trampolines.TailExitTrampoline); } // AArch64AsmPrinter::LowerPATCHABLE_EVENT_CALL generates this code sequence: diff --git a/compiler-rt/lib/xray/xray_arm.cpp b/compiler-rt/lib/xray/xray_arm.cpp index e1818555906c35174f4b0ed51fe3816b8cef7066..e318bb7070e802c1533176e68fdf3a414df17935 100644 --- a/compiler-rt/lib/xray/xray_arm.cpp +++ b/compiler-rt/lib/xray/xray_arm.cpp @@ -128,18 +128,23 @@ inline static bool patchSled(const bool Enable, const uint32_t FuncId, bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, - void (*Trampoline)()) XRAY_NEVER_INSTRUMENT { + const XRayTrampolines &Trampolines, + bool LogArgs) XRAY_NEVER_INSTRUMENT { + auto Trampoline = + LogArgs ? Trampolines.LogArgsTrampoline : Trampolines.EntryTrampoline; return patchSled(Enable, FuncId, Sled, Trampoline); } -bool patchFunctionExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { - return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); +bool patchFunctionExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, Trampolines.ExitTrampoline); } -bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { - return patchSled(Enable, FuncId, Sled, __xray_FunctionTailExit); +bool patchFunctionTailExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, Trampolines.TailExitTrampoline); } bool patchCustomEvent(const bool Enable, const uint32_t FuncId, diff --git a/compiler-rt/lib/xray/xray_dso_init.cpp b/compiler-rt/lib/xray/xray_dso_init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eb754db54c64fa37b67f5819fc901048dabc4608 --- /dev/null +++ b/compiler-rt/lib/xray/xray_dso_init.cpp @@ -0,0 +1,62 @@ +//===-- xray_init.cpp -------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// XRay initialisation logic for DSOs. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_atomic.h" +#include "xray_defs.h" +#include "xray_flags.h" +#include "xray_interface_internal.h" + +using namespace __sanitizer; + +extern "C" { +extern const XRaySledEntry __start_xray_instr_map[] __attribute__((weak)) +__attribute__((visibility("hidden"))); +extern const XRaySledEntry __stop_xray_instr_map[] __attribute__((weak)) +__attribute__((visibility("hidden"))); +extern const XRayFunctionSledIndex __start_xray_fn_idx[] __attribute__((weak)) +__attribute__((visibility("hidden"))); +extern const XRayFunctionSledIndex __stop_xray_fn_idx[] __attribute__((weak)) +__attribute__((visibility("hidden"))); + +#if SANITIZER_APPLE +// HACK: This is a temporary workaround to make XRay build on +// Darwin, but it will probably not work at runtime. +extern const XRaySledEntry __start_xray_instr_map[] = {}; +extern const XRaySledEntry __stop_xray_instr_map[] = {}; +extern const XRayFunctionSledIndex __start_xray_fn_idx[] = {}; +extern const XRayFunctionSledIndex __stop_xray_fn_idx[] = {}; +#endif +} + +// Handler functions to call in the patched entry/exit sled. +extern atomic_uintptr_t XRayPatchedFunction; +extern atomic_uintptr_t XRayArgLogger; +extern atomic_uintptr_t XRayPatchedCustomEvent; +extern atomic_uintptr_t XRayPatchedTypedEvent; + +static int __xray_object_id{-1}; + +// Note: .preinit_array initialization does not work for DSOs +__attribute__((constructor(0))) static void +__xray_init_dso() XRAY_NEVER_INSTRUMENT { + // Register sleds in main XRay runtime. + __xray_object_id = + __xray_register_dso(__start_xray_instr_map, __stop_xray_instr_map, + __start_xray_fn_idx, __stop_xray_fn_idx, {}); +} + +__attribute__((destructor(0))) static void +__xray_finalize_dso() XRAY_NEVER_INSTRUMENT { + // Inform the main runtime that this DSO is no longer used. + __xray_deregister_dso(__xray_object_id); +} diff --git a/compiler-rt/lib/xray/xray_hexagon.cpp b/compiler-rt/lib/xray/xray_hexagon.cpp index 7f127b2b499cd21ec822c943c8d24560201e681d..1c07bb04690368310b39c0200fda578eef1f5c83 100644 --- a/compiler-rt/lib/xray/xray_hexagon.cpp +++ b/compiler-rt/lib/xray/xray_hexagon.cpp @@ -135,18 +135,23 @@ inline static bool patchSled(const bool Enable, const uint32_t FuncId, bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, - void (*Trampoline)()) XRAY_NEVER_INSTRUMENT { + const XRayTrampolines &Trampolines, + bool LogArgs) XRAY_NEVER_INSTRUMENT { + auto Trampoline = + LogArgs ? Trampolines.LogArgsTrampoline : Trampolines.EntryTrampoline; return patchSled(Enable, FuncId, Sled, Trampoline); } -bool patchFunctionExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { - return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); +bool patchFunctionExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, Trampolines.ExitTrampoline); } -bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { - return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); +bool patchFunctionTailExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, Trampolines.TailExitTrampoline); } bool patchCustomEvent(const bool Enable, const uint32_t FuncId, diff --git a/compiler-rt/lib/xray/xray_init.cpp b/compiler-rt/lib/xray/xray_init.cpp index f22a31b95686d0e762661ac6f11a52cf6218a0cc..020bfe52b532074616065178fdb1b3a25d30bb43 100644 --- a/compiler-rt/lib/xray/xray_init.cpp +++ b/compiler-rt/lib/xray/xray_init.cpp @@ -16,6 +16,8 @@ #include #include "sanitizer_common/sanitizer_common.h" +#include "xray/xray_interface.h" +#include "xray_allocator.h" #include "xray_defs.h" #include "xray_flags.h" #include "xray_interface_internal.h" @@ -28,7 +30,7 @@ extern const XRayFunctionSledIndex __start_xray_fn_idx[] __attribute__((weak)); extern const XRayFunctionSledIndex __stop_xray_fn_idx[] __attribute__((weak)); #if SANITIZER_APPLE -// HACK: This is a temporary workaround to make XRay build on +// HACK: This is a temporary workaround to make XRay build on // Darwin, but it will probably not work at runtime. const XRaySledEntry __start_xray_instr_map[] = {}; extern const XRaySledEntry __stop_xray_instr_map[] = {}; @@ -43,14 +45,16 @@ using namespace __xray; // the weak symbols defined above (__start_xray_inst_map and // __stop_xray_instr_map) to initialise the instrumentation map that XRay uses // for runtime patching/unpatching of instrumentation points. -// -// FIXME: Support DSO instrumentation maps too. The current solution only works -// for statically linked executables. atomic_uint8_t XRayInitialized{0}; // This should always be updated before XRayInitialized is updated. SpinMutex XRayInstrMapMutex; -XRaySledMap XRayInstrMap; + +// Contains maps for the main executable as well as DSOs. +XRaySledMap *XRayInstrMaps; + +// Number of binary objects registered. +atomic_uint32_t XRayNumObjects{0}; // Global flag to determine whether the flags have been initialized. atomic_uint8_t XRayFlagsInitialized{0}; @@ -58,6 +62,63 @@ atomic_uint8_t XRayFlagsInitialized{0}; // A mutex to allow only one thread to initialize the XRay data structures. SpinMutex XRayInitMutex; +// Registers XRay sleds and trampolines coming from the main executable or one +// of the linked DSOs. +// Returns the object ID if registration is successful, -1 otherwise. +int32_t +__xray_register_sleds(const XRaySledEntry *SledsBegin, + const XRaySledEntry *SledsEnd, + const XRayFunctionSledIndex *FnIndexBegin, + const XRayFunctionSledIndex *FnIndexEnd, bool FromDSO, + XRayTrampolines Trampolines) XRAY_NEVER_INSTRUMENT { + if (!SledsBegin || !SledsEnd) { + Report("Invalid XRay sleds.\n"); + return -1; + } + XRaySledMap SledMap; + SledMap.FromDSO = FromDSO; + SledMap.Loaded = true; + SledMap.Trampolines = Trampolines; + SledMap.Sleds = SledsBegin; + SledMap.Entries = SledsEnd - SledsBegin; + if (FnIndexBegin != nullptr) { + SledMap.SledsIndex = FnIndexBegin; + SledMap.Functions = FnIndexEnd - FnIndexBegin; + } else { + size_t CountFunctions = 0; + uint64_t LastFnAddr = 0; + + for (std::size_t I = 0; I < SledMap.Entries; I++) { + const auto &Sled = SledMap.Sleds[I]; + const auto Function = Sled.function(); + if (Function != LastFnAddr) { + CountFunctions++; + LastFnAddr = Function; + } + } + SledMap.SledsIndex = nullptr; + SledMap.Functions = CountFunctions; + } + if (SledMap.Functions >= XRayMaxFunctions) { + Report("Too many functions! Maximum is %ld\n", XRayMaxFunctions); + return -1; + } + + if (Verbosity()) + Report("Registering %d new functions!\n", SledMap.Functions); + + { + SpinMutexLock Guard(&XRayInstrMapMutex); + auto Idx = atomic_fetch_add(&XRayNumObjects, 1, memory_order_acq_rel); + if (Idx >= XRayMaxObjects) { + Report("Too many objects registered! Maximum is %ld\n", XRayMaxObjects); + return -1; + } + XRayInstrMaps[Idx] = std::move(SledMap); + return Idx; + } +} + // __xray_init() will do the actual loading of the current process' memory map // and then proceed to look for the .xray_instr_map section/segment. void __xray_init() XRAY_NEVER_INSTRUMENT { @@ -80,29 +141,21 @@ void __xray_init() XRAY_NEVER_INSTRUMENT { return; } - { - SpinMutexLock Guard(&XRayInstrMapMutex); - XRayInstrMap.Sleds = __start_xray_instr_map; - XRayInstrMap.Entries = __stop_xray_instr_map - __start_xray_instr_map; - if (__start_xray_fn_idx != nullptr) { - XRayInstrMap.SledsIndex = __start_xray_fn_idx; - XRayInstrMap.Functions = __stop_xray_fn_idx - __start_xray_fn_idx; - } else { - size_t CountFunctions = 0; - uint64_t LastFnAddr = 0; - - for (std::size_t I = 0; I < XRayInstrMap.Entries; I++) { - const auto &Sled = XRayInstrMap.Sleds[I]; - const auto Function = Sled.function(); - if (Function != LastFnAddr) { - CountFunctions++; - LastFnAddr = Function; - } - } + atomic_store(&XRayNumObjects, 0, memory_order_release); - XRayInstrMap.Functions = CountFunctions; - } + // Pre-allocation takes up approx. 5kB for XRayMaxObjects=64. + XRayInstrMaps = allocateBuffer(XRayMaxObjects); + + int MainBinaryId = + __xray_register_sleds(__start_xray_instr_map, __stop_xray_instr_map, + __start_xray_fn_idx, __stop_xray_fn_idx, false, {}); + + // The executable should always get ID 0. + if (MainBinaryId != 0) { + Report("Registering XRay sleds failed.\n"); + return; } + atomic_store(&XRayInitialized, true, memory_order_release); #ifndef XRAY_NO_PREINIT @@ -111,6 +164,84 @@ void __xray_init() XRAY_NEVER_INSTRUMENT { #endif } +// Registers XRay sleds and trampolines of an instrumented DSO. +// Returns the object ID if registration is successful, -1 otherwise. +// +// Default visibility is hidden, so we have to explicitly make it visible to +// DSO. +SANITIZER_INTERFACE_ATTRIBUTE int32_t __xray_register_dso( + const XRaySledEntry *SledsBegin, const XRaySledEntry *SledsEnd, + const XRayFunctionSledIndex *FnIndexBegin, + const XRayFunctionSledIndex *FnIndexEnd, + XRayTrampolines Trampolines) XRAY_NEVER_INSTRUMENT { + // Make sure XRay has been initialized in the main executable. + __xray_init(); + + if (__xray_num_objects() == 0) { + if (Verbosity()) + Report("No XRay instrumentation map in main executable. Not initializing " + "XRay for DSO.\n"); + return -1; + } + + // Register sleds in global map. + int ObjId = __xray_register_sleds(SledsBegin, SledsEnd, FnIndexBegin, + FnIndexEnd, true, Trampolines); + +#ifndef XRAY_NO_PREINIT + if (ObjId >= 0 && flags()->patch_premain) + __xray_patch_object(ObjId); +#endif + + return ObjId; +} + +// Deregisters a DSO from the main XRay runtime. +// Called from the DSO-local runtime when the library is unloaded (e.g. if +// dlclose is called). +// Returns true if the object ID is valid and the DSO was successfully +// deregistered. +SANITIZER_INTERFACE_ATTRIBUTE bool +__xray_deregister_dso(int32_t ObjId) XRAY_NEVER_INSTRUMENT { + + if (!atomic_load(&XRayInitialized, memory_order_acquire)) { + if (Verbosity()) + Report("XRay has not been initialized. Cannot deregister DSO.\n"); + return false; + } + + if (ObjId <= 0 || static_cast(ObjId) >= __xray_num_objects()) { + if (Verbosity()) + Report("Can't deregister object with ID %d: ID is invalid.\n", ObjId); + return false; + } + + { + SpinMutexLock Guard(&XRayInstrMapMutex); + auto &Entry = XRayInstrMaps[ObjId]; + if (!Entry.FromDSO) { + if (Verbosity()) + Report("Can't deregister object with ID %d: object does not correspond " + "to a shared library.\n", + ObjId); + return false; + } + if (!Entry.Loaded) { + if (Verbosity()) + Report("Can't deregister object with ID %d: object is not loaded.\n", + ObjId); + return true; + } + // Mark DSO as unloaded. No need to unpatch. + Entry.Loaded = false; + } + + if (Verbosity()) + Report("Deregistered object with ID %d.\n", ObjId); + + return true; +} + // FIXME: Make check-xray tests work on FreeBSD without // SANITIZER_CAN_USE_PREINIT_ARRAY. // See sanitizer_internal_defs.h where the macro is defined. diff --git a/compiler-rt/lib/xray/xray_interface.cpp b/compiler-rt/lib/xray/xray_interface.cpp index 5839043fcb93a8825185b0a4fe4fad3fac8c6c6b..b6f0e6762f1681eb7db51cbc68cc0bc243dcbe2c 100644 --- a/compiler-rt/lib/xray/xray_interface.cpp +++ b/compiler-rt/lib/xray/xray_interface.cpp @@ -36,7 +36,8 @@ extern __sanitizer::SpinMutex XRayInstrMapMutex; extern __sanitizer::atomic_uint8_t XRayInitialized; -extern __xray::XRaySledMap XRayInstrMap; +extern __xray::XRaySledMap *XRayInstrMaps; +extern __sanitizer::atomic_uint32_t XRayNumObjects; namespace __xray { @@ -61,16 +62,16 @@ static const int16_t cSledLength = 20; #endif /* CPU architecture */ // This is the function to call when we encounter the entry or exit sleds. -atomic_uintptr_t XRayPatchedFunction{0}; +atomic_uintptr_t XRayPatchedFunction SANITIZER_INTERFACE_ATTRIBUTE{0}; // This is the function to call from the arg1-enabled sleds/trampolines. -atomic_uintptr_t XRayArgLogger{0}; +atomic_uintptr_t XRayArgLogger SANITIZER_INTERFACE_ATTRIBUTE{0}; // This is the function to call when we encounter a custom event log call. -atomic_uintptr_t XRayPatchedCustomEvent{0}; +atomic_uintptr_t XRayPatchedCustomEvent SANITIZER_INTERFACE_ATTRIBUTE{0}; // This is the function to call when we encounter a typed event log call. -atomic_uintptr_t XRayPatchedTypedEvent{0}; +atomic_uintptr_t XRayPatchedTypedEvent SANITIZER_INTERFACE_ATTRIBUTE{0}; // This is the global status to determine whether we are currently // patching/unpatching. @@ -150,21 +151,32 @@ public: namespace { -bool patchSled(const XRaySledEntry &Sled, bool Enable, - int32_t FuncId) XRAY_NEVER_INSTRUMENT { +bool isObjectLoaded(int32_t ObjId) { + SpinMutexLock Guard(&XRayInstrMapMutex); + if (ObjId < 0 || static_cast(ObjId) >= + atomic_load(&XRayNumObjects, memory_order_acquire)) { + return false; + } + return XRayInstrMaps[ObjId].Loaded; +} + +bool patchSled(const XRaySledEntry &Sled, bool Enable, int32_t FuncId, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { bool Success = false; switch (Sled.Kind) { case XRayEntryType::ENTRY: - Success = patchFunctionEntry(Enable, FuncId, Sled, __xray_FunctionEntry); + Success = patchFunctionEntry(Enable, FuncId, Sled, Trampolines, + /*LogArgs=*/false); break; case XRayEntryType::EXIT: - Success = patchFunctionExit(Enable, FuncId, Sled); + Success = patchFunctionExit(Enable, FuncId, Sled, Trampolines); break; case XRayEntryType::TAIL: - Success = patchFunctionTailExit(Enable, FuncId, Sled); + Success = patchFunctionTailExit(Enable, FuncId, Sled, Trampolines); break; case XRayEntryType::LOG_ARGS_ENTRY: - Success = patchFunctionEntry(Enable, FuncId, Sled, __xray_ArgLoggerEntry); + Success = patchFunctionEntry(Enable, FuncId, Sled, Trampolines, + /*LogArgs=*/true); break; case XRayEntryType::CUSTOM_EVENT: Success = patchCustomEvent(Enable, FuncId, Sled); @@ -205,10 +217,9 @@ findFunctionSleds(int32_t FuncId, return Index; } -XRayPatchingStatus patchFunction(int32_t FuncId, +XRayPatchingStatus patchFunction(int32_t FuncId, int32_t ObjId, bool Enable) XRAY_NEVER_INSTRUMENT { - if (!atomic_load(&XRayInitialized, - memory_order_acquire)) + if (!atomic_load(&XRayInitialized, memory_order_acquire)) return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized. uint8_t NotPatching = false; @@ -220,13 +231,24 @@ XRayPatchingStatus patchFunction(int32_t FuncId, XRaySledMap InstrMap; { SpinMutexLock Guard(&XRayInstrMapMutex); - InstrMap = XRayInstrMap; + if (ObjId < 0 || static_cast(ObjId) >= + atomic_load(&XRayNumObjects, memory_order_acquire)) { + Report("Unable to patch function: invalid sled map index: %d", ObjId); + return XRayPatchingStatus::FAILED; + } + InstrMap = XRayInstrMaps[ObjId]; } // If we don't have an index, we can't patch individual functions. if (InstrMap.Functions == 0) return XRayPatchingStatus::NOT_INITIALIZED; + // Check if the corresponding DSO has been unloaded. + if (!InstrMap.Loaded) { + Report("Invalid function id provided: %d\n", FuncId); + return XRayPatchingStatus::NOT_INITIALIZED; + } + // FuncId must be a positive number, less than the number of functions // instrumented. if (FuncId <= 0 || static_cast(FuncId) > InstrMap.Functions) { @@ -234,6 +256,8 @@ XRayPatchingStatus patchFunction(int32_t FuncId, return XRayPatchingStatus::FAILED; } + auto PackedId = __xray::MakePackedId(FuncId, ObjId); + // Now we patch ths sleds for this specific function. XRayFunctionSledIndex SledRange; if (InstrMap.SledsIndex) { @@ -242,13 +266,13 @@ XRayPatchingStatus patchFunction(int32_t FuncId, } else { SledRange = findFunctionSleds(FuncId, InstrMap); } + auto *f = SledRange.Begin; bool SucceedOnce = false; for (size_t i = 0; i != SledRange.Size; ++i) - SucceedOnce |= patchSled(f[i], Enable, FuncId); + SucceedOnce |= patchSled(f[i], Enable, PackedId, InstrMap.Trampolines); - atomic_store(&XRayPatching, false, - memory_order_release); + atomic_store(&XRayPatching, false, memory_order_release); if (!SucceedOnce) { Report("Failed patching any sled for function '%d'.", FuncId); @@ -261,32 +285,31 @@ XRayPatchingStatus patchFunction(int32_t FuncId, // controlPatching implements the common internals of the patching/unpatching // implementation. |Enable| defines whether we're enabling or disabling the // runtime XRay instrumentation. -XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT { - if (!atomic_load(&XRayInitialized, - memory_order_acquire)) - return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized. - - uint8_t NotPatching = false; - if (!atomic_compare_exchange_strong( - &XRayPatching, &NotPatching, true, memory_order_acq_rel)) - return XRayPatchingStatus::ONGOING; // Already patching. - - uint8_t PatchingSuccess = false; - auto XRayPatchingStatusResetter = - at_scope_exit([&PatchingSuccess] { - if (!PatchingSuccess) - atomic_store(&XRayPatching, false, - memory_order_release); - }); - +// This function should only be called after ensuring that XRay is initialized +// and no other thread is currently patching. +XRayPatchingStatus controlPatchingObjectUnchecked(bool Enable, int32_t ObjId) { XRaySledMap InstrMap; { SpinMutexLock Guard(&XRayInstrMapMutex); - InstrMap = XRayInstrMap; + if (ObjId < 0 || static_cast(ObjId) >= + atomic_load(&XRayNumObjects, memory_order_acquire)) { + Report("Unable to patch functions: invalid sled map index: %d\n", ObjId); + return XRayPatchingStatus::FAILED; + } + InstrMap = XRayInstrMaps[ObjId]; } if (InstrMap.Entries == 0) return XRayPatchingStatus::NOT_INITIALIZED; + if (Verbosity()) + Report("Patching object %d with %d functions.\n", ObjId, InstrMap.Entries); + + // Check if the corresponding DSO has been unloaded. + if (!InstrMap.Loaded) { + Report("Object is not loaded at index: %d\n", ObjId); + return XRayPatchingStatus::FAILED; + } + uint32_t FuncId = 1; uint64_t CurFun = 0; @@ -336,20 +359,94 @@ XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT { ++FuncId; CurFun = F; } - patchSled(Sled, Enable, FuncId); + auto PackedId = __xray::MakePackedId(FuncId, ObjId); + patchSled(Sled, Enable, PackedId, InstrMap.Trampolines); } - atomic_store(&XRayPatching, false, - memory_order_release); - PatchingSuccess = true; + atomic_store(&XRayPatching, false, memory_order_release); return XRayPatchingStatus::SUCCESS; } -XRayPatchingStatus mprotectAndPatchFunction(int32_t FuncId, +// Controls patching for all registered objects. +// Returns: SUCCESS, if patching succeeds for all objects. +// NOT_INITIALIZED, if one or more objects returned NOT_INITIALIZED +// but none failed. +// FAILED, if patching of one or more objects failed. +XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT { + if (!atomic_load(&XRayInitialized, memory_order_acquire)) + return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized. + + uint8_t NotPatching = false; + if (!atomic_compare_exchange_strong(&XRayPatching, &NotPatching, true, + memory_order_acq_rel)) + return XRayPatchingStatus::ONGOING; // Already patching. + + auto XRayPatchingStatusResetter = at_scope_exit( + [] { atomic_store(&XRayPatching, false, memory_order_release); }); + + unsigned NumObjects = __xray_num_objects(); + + XRayPatchingStatus CombinedStatus{NOT_INITIALIZED}; + for (unsigned I = 0; I < NumObjects; ++I) { + if (!isObjectLoaded(I)) + continue; + auto LastStatus = controlPatchingObjectUnchecked(Enable, I); + switch (LastStatus) { + case SUCCESS: + if (CombinedStatus == NOT_INITIALIZED) + CombinedStatus = SUCCESS; + break; + case FAILED: + // Report failure, but try to patch the remaining objects + CombinedStatus = FAILED; + break; + case NOT_INITIALIZED: + // XRay has been initialized but there are no sleds available for this + // object. Try to patch remaining objects. + if (CombinedStatus != FAILED) + CombinedStatus = NOT_INITIALIZED; + break; + case ONGOING: + UNREACHABLE("Status ONGOING should not appear at this point"); + } + } + return CombinedStatus; +} + +// Controls patching for one object. +XRayPatchingStatus controlPatching(bool Enable, + int32_t ObjId) XRAY_NEVER_INSTRUMENT { + + if (!atomic_load(&XRayInitialized, memory_order_acquire)) + return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized. + + uint8_t NotPatching = false; + if (!atomic_compare_exchange_strong(&XRayPatching, &NotPatching, true, + memory_order_acq_rel)) + return XRayPatchingStatus::ONGOING; // Already patching. + + auto XRayPatchingStatusResetter = at_scope_exit( + [] { atomic_store(&XRayPatching, false, memory_order_release); }); + + return controlPatchingObjectUnchecked(Enable, ObjId); +} + +XRayPatchingStatus mprotectAndPatchFunction(int32_t FuncId, int32_t ObjId, bool Enable) XRAY_NEVER_INSTRUMENT { XRaySledMap InstrMap; { SpinMutexLock Guard(&XRayInstrMapMutex); - InstrMap = XRayInstrMap; + if (ObjId < 0 || static_cast(ObjId) >= + atomic_load(&XRayNumObjects, memory_order_acquire)) { + Report("Unable to patch function: invalid sled map index: %d\n", ObjId); + return XRayPatchingStatus::FAILED; + } + InstrMap = XRayInstrMaps[ObjId]; + } + + // Check if the corresponding DSO has been unloaded. + if (!InstrMap.Loaded) { + Report("Object is not loaded at index: %d\n", ObjId); + return XRayPatchingStatus::FAILED; } // FuncId must be a positive number, less than the number of functions @@ -398,7 +495,7 @@ XRayPatchingStatus mprotectAndPatchFunction(int32_t FuncId, Report("Failed mprotect: %d\n", errno); return XRayPatchingStatus::FAILED; } - return patchFunction(FuncId, Enable); + return patchFunction(FuncId, ObjId, Enable); } } // namespace @@ -412,12 +509,10 @@ using namespace __xray; int __xray_set_handler(void (*entry)(int32_t, XRayEntryType)) XRAY_NEVER_INSTRUMENT { - if (atomic_load(&XRayInitialized, - memory_order_acquire)) { + if (atomic_load(&XRayInitialized, memory_order_acquire)) { atomic_store(&__xray::XRayPatchedFunction, - reinterpret_cast(entry), - memory_order_release); + reinterpret_cast(entry), memory_order_release); return 1; } return 0; @@ -425,11 +520,9 @@ int __xray_set_handler(void (*entry)(int32_t, int __xray_set_customevent_handler(void (*entry)(void *, size_t)) XRAY_NEVER_INSTRUMENT { - if (atomic_load(&XRayInitialized, - memory_order_acquire)) { + if (atomic_load(&XRayInitialized, memory_order_acquire)) { atomic_store(&__xray::XRayPatchedCustomEvent, - reinterpret_cast(entry), - memory_order_release); + reinterpret_cast(entry), memory_order_release); return 1; } return 0; @@ -437,11 +530,9 @@ int __xray_set_customevent_handler(void (*entry)(void *, size_t)) int __xray_set_typedevent_handler(void (*entry)(size_t, const void *, size_t)) XRAY_NEVER_INSTRUMENT { - if (atomic_load(&XRayInitialized, - memory_order_acquire)) { + if (atomic_load(&XRayInitialized, memory_order_acquire)) { atomic_store(&__xray::XRayPatchedTypedEvent, - reinterpret_cast(entry), - memory_order_release); + reinterpret_cast(entry), memory_order_release); return 1; } return 0; @@ -474,39 +565,78 @@ XRayPatchingStatus __xray_patch() XRAY_NEVER_INSTRUMENT { return controlPatching(true); } +XRayPatchingStatus __xray_patch_object(int32_t ObjId) XRAY_NEVER_INSTRUMENT { + return controlPatching(true, ObjId); +} + XRayPatchingStatus __xray_unpatch() XRAY_NEVER_INSTRUMENT { return controlPatching(false); } +XRayPatchingStatus __xray_unpatch_object(int32_t ObjId) XRAY_NEVER_INSTRUMENT { + return controlPatching(false, ObjId); +} + XRayPatchingStatus __xray_patch_function(int32_t FuncId) XRAY_NEVER_INSTRUMENT { - return mprotectAndPatchFunction(FuncId, true); + auto Ids = __xray::UnpackId(FuncId); + auto ObjId = Ids.first; + auto FnId = Ids.second; + return mprotectAndPatchFunction(FnId, ObjId, true); +} + +XRayPatchingStatus +__xray_patch_function_in_object(int32_t FuncId, + int32_t ObjId) XRAY_NEVER_INSTRUMENT { + return mprotectAndPatchFunction(FuncId, ObjId, true); } XRayPatchingStatus __xray_unpatch_function(int32_t FuncId) XRAY_NEVER_INSTRUMENT { - return mprotectAndPatchFunction(FuncId, false); + auto Ids = __xray::UnpackId(FuncId); + auto ObjId = Ids.first; + auto FnId = Ids.second; + return mprotectAndPatchFunction(FnId, ObjId, false); +} + +XRayPatchingStatus +__xray_unpatch_function_in_object(int32_t FuncId, + int32_t ObjId) XRAY_NEVER_INSTRUMENT { + return mprotectAndPatchFunction(FuncId, ObjId, false); } int __xray_set_handler_arg1(void (*entry)(int32_t, XRayEntryType, uint64_t)) { - if (!atomic_load(&XRayInitialized, - memory_order_acquire)) + if (!atomic_load(&XRayInitialized, memory_order_acquire)) return 0; // A relaxed write might not be visible even if the current thread gets // scheduled on a different CPU/NUMA node. We need to wait for everyone to // have this handler installed for consistency of collected data across CPUs. atomic_store(&XRayArgLogger, reinterpret_cast(entry), - memory_order_release); + memory_order_release); return 1; } int __xray_remove_handler_arg1() { return __xray_set_handler_arg1(nullptr); } -uintptr_t __xray_function_address(int32_t FuncId) XRAY_NEVER_INSTRUMENT { +uintptr_t +__xray_function_address(int32_t CombinedFuncId) XRAY_NEVER_INSTRUMENT { + auto Ids = __xray::UnpackId(CombinedFuncId); + return __xray_function_address_in_object(Ids.second, Ids.first); +} + +uintptr_t __xray_function_address_in_object(int32_t FuncId, int32_t ObjId) + XRAY_NEVER_INSTRUMENT { XRaySledMap InstrMap; { SpinMutexLock Guard(&XRayInstrMapMutex); - InstrMap = XRayInstrMap; + auto count = atomic_load(&XRayNumObjects, memory_order_acquire); + if (ObjId < 0 || static_cast(ObjId) >= count) { + Report("Unable to determine function address: invalid sled map index %d " + "(size is %d)\n", + ObjId, (int)count); + return 0; + } + InstrMap = XRayInstrMaps[ObjId]; } if (FuncId <= 0 || static_cast(FuncId) > InstrMap.Functions) @@ -525,6 +655,30 @@ uintptr_t __xray_function_address(int32_t FuncId) XRAY_NEVER_INSTRUMENT { } size_t __xray_max_function_id() XRAY_NEVER_INSTRUMENT { + return __xray_max_function_id_in_object(0); +} + +size_t __xray_max_function_id_in_object(int32_t ObjId) XRAY_NEVER_INSTRUMENT { + SpinMutexLock Guard(&XRayInstrMapMutex); + if (ObjId < 0 || static_cast(ObjId) >= + atomic_load(&XRayNumObjects, memory_order_acquire)) + return 0; + return XRayInstrMaps[ObjId].Functions; +} + +size_t __xray_num_objects() XRAY_NEVER_INSTRUMENT { SpinMutexLock Guard(&XRayInstrMapMutex); - return XRayInstrMap.Functions; + return atomic_load(&XRayNumObjects, memory_order_acquire); +} + +int32_t __xray_unpack_function_id(int32_t PackedId) { + return __xray::UnpackId(PackedId).second; +} + +int32_t __xray_unpack_object_id(int32_t PackedId) { + return __xray::UnpackId(PackedId).first; +} + +int32_t __xray_pack_id(int32_t FuncId, int32_t ObjId) { + return __xray::MakePackedId(FuncId, ObjId); } diff --git a/compiler-rt/lib/xray/xray_interface_internal.h b/compiler-rt/lib/xray/xray_interface_internal.h index 80c07c167f64618a6ea8e5a68fd3a25a690588e3..a8cfe0fde84dd21e70e42d611d7fc9a4f03b418b 100644 --- a/compiler-rt/lib/xray/xray_interface_internal.h +++ b/compiler-rt/lib/xray/xray_interface_internal.h @@ -18,6 +18,18 @@ #include "xray/xray_interface.h" #include #include +#include + +extern "C" { +// The following functions have to be defined in assembler, on a per-platform +// basis. See xray_trampoline_*.S files for implementations. +extern void __xray_FunctionEntry(); +extern void __xray_FunctionExit(); +extern void __xray_FunctionTailExit(); +extern void __xray_ArgLoggerEntry(); +extern void __xray_CustomEvent(); +extern void __xray_TypedEvent(); +} extern "C" { @@ -67,36 +79,72 @@ struct XRayFunctionSledIndex { uintptr_t(Begin)); } }; + +struct XRayTrampolines { + void (*EntryTrampoline)(); + void (*ExitTrampoline)(); + void (*TailExitTrampoline)(); + void (*LogArgsTrampoline)(); + + XRayTrampolines() { + // These resolve to the definitions in the respective executable or DSO. + EntryTrampoline = __xray_FunctionEntry; + ExitTrampoline = __xray_FunctionExit; + TailExitTrampoline = __xray_FunctionTailExit; + LogArgsTrampoline = __xray_ArgLoggerEntry; + } +}; + +extern int32_t __xray_register_dso(const XRaySledEntry *SledsBegin, + const XRaySledEntry *SledsEnd, + const XRayFunctionSledIndex *FnIndexBegin, + const XRayFunctionSledIndex *FnIndexEnd, + XRayTrampolines Trampolines); + +extern bool __xray_deregister_dso(int32_t ObjId); } namespace __xray { +constexpr uint32_t XRayNFnBits = 24; +constexpr uint32_t XRayNObjBits = 8; + +constexpr uint32_t XRayFnBitMask = 0x00FFFFFF; +constexpr uint32_t XRayObjBitMask = 0xFF000000; + +constexpr size_t XRayMaxFunctions = 1 << XRayNFnBits; +constexpr size_t XRayMaxObjects = 1 << XRayNObjBits; + +inline int32_t MakePackedId(int32_t FnId, int32_t ObjId) { + return ((ObjId << XRayNFnBits) & XRayObjBitMask) | (FnId & XRayFnBitMask); +} + +inline std::pair UnpackId(int32_t PackedId) { + uint32_t ObjId = (PackedId & XRayObjBitMask) >> XRayNFnBits; + uint32_t FnId = PackedId & XRayFnBitMask; + return {ObjId, FnId}; +} + struct XRaySledMap { const XRaySledEntry *Sleds; size_t Entries; const XRayFunctionSledIndex *SledsIndex; size_t Functions; + XRayTrampolines Trampolines; + bool FromDSO; + bool Loaded; }; bool patchFunctionEntry(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled, - void (*Trampoline)()); -bool patchFunctionExit(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled); + const XRayTrampolines &Trampolines, bool LogArgs); +bool patchFunctionExit(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines); bool patchFunctionTailExit(bool Enable, uint32_t FuncId, - const XRaySledEntry &Sled); + const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines); bool patchCustomEvent(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled); bool patchTypedEvent(bool Enable, uint32_t FuncId, const XRaySledEntry &Sled); } // namespace __xray -extern "C" { -// The following functions have to be defined in assembler, on a per-platform -// basis. See xray_trampoline_*.S files for implementations. -extern void __xray_FunctionEntry(); -extern void __xray_FunctionExit(); -extern void __xray_FunctionTailExit(); -extern void __xray_ArgLoggerEntry(); -extern void __xray_CustomEvent(); -extern void __xray_TypedEvent(); -} - #endif diff --git a/compiler-rt/lib/xray/xray_loongarch64.cpp b/compiler-rt/lib/xray/xray_loongarch64.cpp index b839adba00d225f07c285313bd11fc7e3bcba0ac..b72417d4f2aadb844aacbf392bccc1c40a50ff13 100644 --- a/compiler-rt/lib/xray/xray_loongarch64.cpp +++ b/compiler-rt/lib/xray/xray_loongarch64.cpp @@ -126,20 +126,25 @@ static inline bool patchSled(const bool Enable, const uint32_t FuncId, bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, - void (*Trampoline)()) XRAY_NEVER_INSTRUMENT { + const XRayTrampolines &Trampolines, + bool LogArgs) XRAY_NEVER_INSTRUMENT { + auto Trampoline = + LogArgs ? Trampolines.LogArgsTrampoline : Trampolines.EntryTrampoline; return patchSled(Enable, FuncId, Sled, Trampoline); } -bool patchFunctionExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { - return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); +bool patchFunctionExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, Trampolines.ExitTrampoline); } -bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { +bool patchFunctionTailExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { // TODO: In the future we'd need to distinguish between non-tail exits and // tail exits for better information preservation. - return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); + return patchSled(Enable, FuncId, Sled, Trampolines.ExitTrampoline); } bool patchCustomEvent(const bool Enable, const uint32_t FuncId, @@ -158,3 +163,7 @@ bool patchTypedEvent(const bool Enable, const uint32_t FuncId, extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT { // TODO: This will have to be implemented in the trampoline assembly file. } + +extern "C" void __xray_FunctionTailExit() XRAY_NEVER_INSTRUMENT { + // FIXME: this will have to be implemented in the trampoline assembly file +} diff --git a/compiler-rt/lib/xray/xray_mips.cpp b/compiler-rt/lib/xray/xray_mips.cpp index dc9e837a555dd7884ffe72783f64cebe9691cda2..4d2a7c82bddb9d8412e8f0731f678e2c82143fd4 100644 --- a/compiler-rt/lib/xray/xray_mips.cpp +++ b/compiler-rt/lib/xray/xray_mips.cpp @@ -136,20 +136,25 @@ inline static bool patchSled(const bool Enable, const uint32_t FuncId, bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, - void (*Trampoline)()) XRAY_NEVER_INSTRUMENT { + const XRayTrampolines &Trampolines, + bool LogArgs) XRAY_NEVER_INSTRUMENT { + auto Trampoline = + LogArgs ? Trampolines.LogArgsTrampoline : Trampolines.EntryTrampoline; return patchSled(Enable, FuncId, Sled, Trampoline); } -bool patchFunctionExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { - return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); +bool patchFunctionExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, Trampolines.ExitTrampoline); } -bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { +bool patchFunctionTailExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { // FIXME: In the future we'd need to distinguish between non-tail exits and // tail exits for better information preservation. - return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); + return patchSled(Enable, FuncId, Sled, Trampolines.ExitTrampoline); } bool patchCustomEvent(const bool Enable, const uint32_t FuncId, @@ -169,3 +174,7 @@ bool patchTypedEvent(const bool Enable, const uint32_t FuncId, extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT { // FIXME: this will have to be implemented in the trampoline assembly file } + +extern "C" void __xray_FunctionTailExit() XRAY_NEVER_INSTRUMENT { + // FIXME: this will have to be implemented in the trampoline assembly file +} \ No newline at end of file diff --git a/compiler-rt/lib/xray/xray_mips64.cpp b/compiler-rt/lib/xray/xray_mips64.cpp index 5b221bb6ddc05d6c631295f3fb28c7a052be80e9..a088a322cc15681e96e5efff576493cfb3f48ab4 100644 --- a/compiler-rt/lib/xray/xray_mips64.cpp +++ b/compiler-rt/lib/xray/xray_mips64.cpp @@ -144,20 +144,25 @@ inline static bool patchSled(const bool Enable, const uint32_t FuncId, bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, - void (*Trampoline)()) XRAY_NEVER_INSTRUMENT { + const XRayTrampolines &Trampolines, + bool LogArgs) XRAY_NEVER_INSTRUMENT { + auto Trampoline = + LogArgs ? Trampolines.LogArgsTrampoline : Trampolines.EntryTrampoline; return patchSled(Enable, FuncId, Sled, Trampoline); } -bool patchFunctionExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { - return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); +bool patchFunctionExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + return patchSled(Enable, FuncId, Sled, Trampolines.ExitTrampoline); } -bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { +bool patchFunctionTailExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { // FIXME: In the future we'd need to distinguish between non-tail exits and // tail exits for better information preservation. - return patchSled(Enable, FuncId, Sled, __xray_FunctionExit); + return patchSled(Enable, FuncId, Sled, Trampolines.ExitTrampoline); } bool patchCustomEvent(const bool Enable, const uint32_t FuncId, @@ -176,3 +181,7 @@ bool patchTypedEvent(const bool Enable, const uint32_t FuncId, extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT { // FIXME: this will have to be implemented in the trampoline assembly file } + +extern "C" void __xray_FunctionTailExit() XRAY_NEVER_INSTRUMENT { + // FIXME: this will have to be implemented in the trampoline assembly file +} diff --git a/compiler-rt/lib/xray/xray_powerpc64.cpp b/compiler-rt/lib/xray/xray_powerpc64.cpp index c3553d848313f999d8416a72aa212b9eca80f341..a568c568c418606cdce7c3cfecade5c415ed3151 100644 --- a/compiler-rt/lib/xray/xray_powerpc64.cpp +++ b/compiler-rt/lib/xray/xray_powerpc64.cpp @@ -51,7 +51,12 @@ namespace __xray { bool patchFunctionEntry(const bool Enable, uint32_t FuncId, const XRaySledEntry &Sled, - void (*Trampoline)()) XRAY_NEVER_INSTRUMENT { + const XRayTrampolines &Trampolines, + bool LogArgs) XRAY_NEVER_INSTRUMENT { + // TODO: Trampoline addresses are currently inserted at compile-time, using + // __xray_FunctionEntry and __xray_FunctionExit only. + // To support DSO instrumentation, trampolines have to be written during + // patching (see implementation on X86_64, e.g.). const uint64_t Address = Sled.address(); if (Enable) { // lis 0, FuncId[16..32] @@ -68,8 +73,13 @@ bool patchFunctionEntry(const bool Enable, uint32_t FuncId, return true; } -bool patchFunctionExit(const bool Enable, uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { +bool patchFunctionExit( + const bool Enable, uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + // TODO: Trampoline addresses are currently inserted at compile-time, using + // __xray_FunctionEntry and __xray_FunctionExit only. + // To support DSO instrumentation, trampolines have to be written during + // patching (see implementation on X86_64, e.g.). const uint64_t Address = Sled.address(); if (Enable) { // lis 0, FuncId[16..32] @@ -86,9 +96,10 @@ bool patchFunctionExit(const bool Enable, uint32_t FuncId, return true; } -bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { - return patchFunctionExit(Enable, FuncId, Sled); +bool patchFunctionTailExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { + return patchFunctionExit(Enable, FuncId, Sled, Trampolines); } // FIXME: Maybe implement this better? @@ -111,3 +122,10 @@ bool patchTypedEvent(const bool Enable, const uint32_t FuncId, extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT { // FIXME: this will have to be implemented in the trampoline assembly file } + +extern "C" void __xray_FunctionTailExit() XRAY_NEVER_INSTRUMENT { + // For PowerPC, calls to __xray_FunctionEntry and __xray_FunctionExit + // are statically inserted into the sled. Tail exits are handled like normal + // function exits. This trampoline is therefore not implemented. + // This stub is placed here to avoid linking issues. +} diff --git a/compiler-rt/lib/xray/xray_trampoline_x86_64.S b/compiler-rt/lib/xray/xray_trampoline_x86_64.S index 01098f60eeab8b39681c63e11e0fa6fb72b524d2..0f480547b52cc6c478e6f64a70f4929f96a5819d 100644 --- a/compiler-rt/lib/xray/xray_trampoline_x86_64.S +++ b/compiler-rt/lib/xray/xray_trampoline_x86_64.S @@ -107,6 +107,16 @@ .section __TEXT,__text #endif +.macro LOAD_HANDLER_ADDR handler +#if !defined(XRAY_PIC) + movq ASM_SYMBOL(\handler)(%rip), %rax +#else + movq ASM_SYMBOL(\handler)@GOTPCREL(%rip), %rax + movq (%rax), %rax +#endif +.endm + + //===----------------------------------------------------------------------===// .globl ASM_SYMBOL(__xray_FunctionEntry) @@ -121,7 +131,7 @@ ASM_SYMBOL(__xray_FunctionEntry): // This load has to be atomic, it's concurrent with __xray_patch(). // On x86/amd64, a simple (type-aligned) MOV instruction is enough. - movq ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE)(%rip), %rax + LOAD_HANDLER_ADDR _ZN6__xray19XRayPatchedFunctionE testq %rax, %rax je LOCAL_LABEL(tmp0) @@ -159,7 +169,7 @@ ASM_SYMBOL(__xray_FunctionExit): movupd %xmm1, 16(%rsp) movq %rax, 8(%rsp) movq %rdx, 0(%rsp) - movq ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE)(%rip), %rax + LOAD_HANDLER_ADDR _ZN6__xray19XRayPatchedFunctionE testq %rax,%rax je LOCAL_LABEL(tmp2) @@ -195,7 +205,7 @@ ASM_SYMBOL(__xray_FunctionTailExit): SAVE_REGISTERS ALIGN_STACK_16B - movq ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE)(%rip), %rax + LOAD_HANDLER_ADDR _ZN6__xray19XRayPatchedFunctionE testq %rax,%rax je LOCAL_LABEL(tmp4) @@ -224,12 +234,12 @@ ASM_SYMBOL(__xray_ArgLoggerEntry): ALIGN_STACK_16B // Again, these function pointer loads must be atomic; MOV is fine. - movq ASM_SYMBOL(_ZN6__xray13XRayArgLoggerE)(%rip), %rax + LOAD_HANDLER_ADDR _ZN6__xray13XRayArgLoggerE testq %rax, %rax jne LOCAL_LABEL(arg1entryLog) // If [arg1 logging handler] not set, defer to no-arg logging. - movq ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE)(%rip), %rax + LOAD_HANDLER_ADDR _ZN6__xray19XRayPatchedFunctionE testq %rax, %rax je LOCAL_LABEL(arg1entryFail) @@ -268,7 +278,7 @@ ASM_SYMBOL(__xray_CustomEvent): // We take two arguments to this trampoline, which should be in rdi and rsi // already. - movq ASM_SYMBOL(_ZN6__xray22XRayPatchedCustomEventE)(%rip), %rax + LOAD_HANDLER_ADDR _ZN6__xray22XRayPatchedCustomEventE testq %rax,%rax je LOCAL_LABEL(customEventCleanup) @@ -293,7 +303,7 @@ ASM_SYMBOL(__xray_TypedEvent): // We pass three arguments to this trampoline, which should be in rdi, rsi // and rdx without our intervention. - movq ASM_SYMBOL(_ZN6__xray21XRayPatchedTypedEventE)(%rip), %rax + LOAD_HANDLER_ADDR _ZN6__xray21XRayPatchedTypedEventE testq %rax,%rax je LOCAL_LABEL(typedEventCleanup) diff --git a/compiler-rt/lib/xray/xray_x86_64.cpp b/compiler-rt/lib/xray/xray_x86_64.cpp index b9666a40861d48cfaceea88598a2e6fe5e61a530..8542351ca2689365792f9c888f579c1513094339 100644 --- a/compiler-rt/lib/xray/xray_x86_64.cpp +++ b/compiler-rt/lib/xray/xray_x86_64.cpp @@ -122,7 +122,8 @@ static constexpr int64_t MaxOffset{std::numeric_limits::max()}; bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, - void (*Trampoline)()) XRAY_NEVER_INSTRUMENT { + const XRayTrampolines &Trampolines, + bool LogArgs) XRAY_NEVER_INSTRUMENT { // Here we do the dance of replacing the following sled: // // xray_sled_n: @@ -144,6 +145,8 @@ bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, // opcode and first operand. // // Prerequisite is to compute the relative offset to the trampoline's address. + auto Trampoline = + LogArgs ? Trampolines.LogArgsTrampoline : Trampolines.EntryTrampoline; const uint64_t Address = Sled.address(); int64_t TrampolineOffset = reinterpret_cast(Trampoline) - (static_cast(Address) + 11); @@ -169,8 +172,9 @@ bool patchFunctionEntry(const bool Enable, const uint32_t FuncId, return true; } -bool patchFunctionExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { +bool patchFunctionExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { // Here we do the dance of replacing the following sled: // // xray_sled_n: @@ -191,12 +195,13 @@ bool patchFunctionExit(const bool Enable, const uint32_t FuncId, // // Prerequisite is to compute the relative offset fo the // __xray_FunctionExit function's address. + auto Trampoline = Trampolines.ExitTrampoline; const uint64_t Address = Sled.address(); - int64_t TrampolineOffset = reinterpret_cast(__xray_FunctionExit) - + int64_t TrampolineOffset = reinterpret_cast(Trampoline) - (static_cast(Address) + 11); if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) { Report("XRay Exit trampoline (%p) too far from sled (%p)\n", - reinterpret_cast(__xray_FunctionExit), + reinterpret_cast(Trampoline), reinterpret_cast(Address)); return false; } @@ -216,17 +221,18 @@ bool patchFunctionExit(const bool Enable, const uint32_t FuncId, return true; } -bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { +bool patchFunctionTailExit( + const bool Enable, const uint32_t FuncId, const XRaySledEntry &Sled, + const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT { // Here we do the dance of replacing the tail call sled with a similar // sequence as the entry sled, but calls the tail exit sled instead. + auto Trampoline = Trampolines.TailExitTrampoline; const uint64_t Address = Sled.address(); - int64_t TrampolineOffset = - reinterpret_cast(__xray_FunctionTailExit) - - (static_cast(Address) + 11); + int64_t TrampolineOffset = reinterpret_cast(Trampoline) - + (static_cast(Address) + 11); if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) { Report("XRay Tail Exit trampoline (%p) too far from sled (%p)\n", - reinterpret_cast(__xray_FunctionTailExit), + reinterpret_cast(Trampoline), reinterpret_cast(Address)); return false; } @@ -275,7 +281,7 @@ bool patchCustomEvent(const bool Enable, const uint32_t FuncId, } bool patchTypedEvent(const bool Enable, const uint32_t FuncId, - const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { + const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { // Here we do the dance of replacing the following sled: // // xray_sled_n: diff --git a/compiler-rt/test/CMakeLists.txt b/compiler-rt/test/CMakeLists.txt index 84a98f36747495aaf43d60a5ede9ada964eea0c3..f9e23710d3e4f7aec9110c6bf03610646a1114ce 100644 --- a/compiler-rt/test/CMakeLists.txt +++ b/compiler-rt/test/CMakeLists.txt @@ -12,6 +12,8 @@ pythonize_bool(COMPILER_RT_ENABLE_INTERNAL_SYMBOLIZER) pythonize_bool(COMPILER_RT_HAS_AARCH64_SME) +pythonize_bool(COMPILER_RT_HAS_NO_DEFAULT_CONFIG_FLAG) + configure_compiler_rt_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/lit.common.configured.in ${CMAKE_CURRENT_BINARY_DIR}/lit.common.configured) diff --git a/compiler-rt/test/asan/lit.cfg.py b/compiler-rt/test/asan/lit.cfg.py index dac3ef00a99af8c9677a2548efe7d69a979e46a1..c57f5ca0fa652c7ba5f698cbb67be1d035f2e61b 100644 --- a/compiler-rt/test/asan/lit.cfg.py +++ b/compiler-rt/test/asan/lit.cfg.py @@ -10,7 +10,7 @@ import lit.formats def get_required_attr(config, attr_name): attr_value = getattr(config, attr_name, None) - if attr_value == None: + if attr_value is None: lit_config.fatal( "No attribute %r in test configuration! You may need to run " "tests from your build directory or add this attribute " diff --git a/compiler-rt/test/builtins/Unit/lit.cfg.py b/compiler-rt/test/builtins/Unit/lit.cfg.py index f63d15919888efa6dbbda1be3ff3b7a6430492e6..c18c973d54c13594c8bd873fdbb3303d442bb647 100644 --- a/compiler-rt/test/builtins/Unit/lit.cfg.py +++ b/compiler-rt/test/builtins/Unit/lit.cfg.py @@ -21,7 +21,7 @@ else: def get_required_attr(config, attr_name): attr_value = getattr(config, attr_name, None) - if attr_value == None: + if attr_value is None: lit_config.fatal( "No attribute %r in test configuration! You may need to run " "tests from your build directory or add this attribute " diff --git a/compiler-rt/test/ctx_profile/lit.cfg.py b/compiler-rt/test/ctx_profile/lit.cfg.py index 3034fadbb7a611adfaaed3ff770a2fea9f2b1ba9..74d9bfd11ae28c96bc9cbd44fb2d66a1c627a36c 100644 --- a/compiler-rt/test/ctx_profile/lit.cfg.py +++ b/compiler-rt/test/ctx_profile/lit.cfg.py @@ -13,7 +13,7 @@ if config.host_os not in ["Linux"]: def get_required_attr(config, attr_name): attr_value = getattr(config, attr_name, None) - if attr_value == None: + if attr_value is None: lit_config.fatal( "No attribute %r in test configuration! You may need to run " "tests from your build directory or add this attribute " diff --git a/compiler-rt/test/lit.common.cfg.py b/compiler-rt/test/lit.common.cfg.py index c3435dd2c52a9e0aaa569fdc7e5da56b34af7a39..4bbce4c073666d04d9437d361e61b2796d72e16e 100644 --- a/compiler-rt/test/lit.common.cfg.py +++ b/compiler-rt/test/lit.common.cfg.py @@ -993,7 +993,11 @@ if config.host_os == "Darwin": # default configs for the test runs. In particular, anything hardening # related is likely to cause issues with sanitizer tests, because it may # preempt something we're looking to trap (e.g. _FORTIFY_SOURCE vs our ASAN). -config.environment["CLANG_NO_DEFAULT_CONFIG"] = "1" +# +# Only set this if we know we can still build for the target while disabling +# default configs. +if config.has_no_default_config_flag: + config.environment["CLANG_NO_DEFAULT_CONFIG"] = "1" if config.has_compiler_rt_libatomic: base_lib = os.path.join(config.compiler_rt_libdir, "libclang_rt.atomic%s.so" diff --git a/compiler-rt/test/lit.common.configured.in b/compiler-rt/test/lit.common.configured.in index 049133dc965c319d6a91f78a514cc6ca0c0a5153..66935c358afeddba0fefbc26066304c2166696fc 100644 --- a/compiler-rt/test/lit.common.configured.in +++ b/compiler-rt/test/lit.common.configured.in @@ -53,6 +53,7 @@ set_default("test_standalone_build_libs", @COMPILER_RT_TEST_STANDALONE_BUILD_LIB set_default("has_compiler_rt_libatomic", @COMPILER_RT_BUILD_STANDALONE_LIBATOMIC_PYBOOL@) set_default("aarch64_sme", @COMPILER_RT_HAS_AARCH64_SME_PYBOOL@) set_default("darwin_linker_version", "@COMPILER_RT_DARWIN_LINKER_VERSION@") +set_default("has_no_default_config_flag", @COMPILER_RT_HAS_NO_DEFAULT_CONFIG_FLAG_PYBOOL@) # True iff the test suite supports ignoring the test compiler's runtime library path # and using `config.compiler_rt_libdir` instead. This only matters when the runtime # library paths differ. diff --git a/compiler-rt/test/lsan/lit.common.cfg.py b/compiler-rt/test/lsan/lit.common.cfg.py index e9b974955730d329a7f7c501046e2f8148590b6f..9426b7d108bbf09acb330400b1cbaa39edaa09ce 100644 --- a/compiler-rt/test/lsan/lit.common.cfg.py +++ b/compiler-rt/test/lsan/lit.common.cfg.py @@ -10,7 +10,7 @@ import lit.util def get_required_attr(config, attr_name): attr_value = getattr(config, attr_name, None) - if attr_value == None: + if attr_value is None: lit_config.fatal( "No attribute %r in test configuration! You may need to run " "tests from your build directory or add this attribute " diff --git a/compiler-rt/test/memprof/lit.cfg.py b/compiler-rt/test/memprof/lit.cfg.py index 4e5d7ba405a20198698b5e0f4a3c6d5aae928985..4057da0c65b51593d137c81e4541609a5bad94a8 100644 --- a/compiler-rt/test/memprof/lit.cfg.py +++ b/compiler-rt/test/memprof/lit.cfg.py @@ -9,7 +9,7 @@ import lit.formats def get_required_attr(config, attr_name): attr_value = getattr(config, attr_name, None) - if attr_value == None: + if attr_value is None: lit_config.fatal( "No attribute %r in test configuration! You may need to run " "tests from your build directory or add this attribute " diff --git a/compiler-rt/test/profile/Inputs/.gitattributes b/compiler-rt/test/profile/Inputs/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..c363807c4e95df177a1ee8f5012538c90700486a --- /dev/null +++ b/compiler-rt/test/profile/Inputs/.gitattributes @@ -0,0 +1,3 @@ +instrprof-gcov-*.c text eol=lf +instrprof-gcov-*.cpp text eol=lf +instrprof-shared-*.c text eol=lf diff --git a/compiler-rt/test/profile/lit.cfg.py b/compiler-rt/test/profile/lit.cfg.py index c8c78a746b4c9b66ebf209e3a9c82b038193fac1..ca6df08ad0436d522f65afb569be2b07e3e07c90 100644 --- a/compiler-rt/test/profile/lit.cfg.py +++ b/compiler-rt/test/profile/lit.cfg.py @@ -6,7 +6,7 @@ import re def get_required_attr(config, attr_name): attr_value = getattr(config, attr_name, None) - if attr_value == None: + if attr_value is None: lit_config.fatal( "No attribute %r in test configuration! You may need to run " "tests from your build directory or add this attribute " diff --git a/compiler-rt/test/sanitizer_common/android_commands/android_compile.py b/compiler-rt/test/sanitizer_common/android_commands/android_compile.py index f86831ffef89910b1c24a542477afed439bc43de..e9c6738a09a3fdf90e84bd63fae14c7b65fba9f9 100755 --- a/compiler-rt/test/sanitizer_common/android_commands/android_compile.py +++ b/compiler-rt/test/sanitizer_common/android_commands/android_compile.py @@ -20,7 +20,7 @@ while args: elif arg == "-o": output = args.pop(0) -if output == None: +if output is None: print("No output file name!") sys.exit(1) diff --git a/compiler-rt/test/sanitizer_common/ios_commands/iossim_compile.py b/compiler-rt/test/sanitizer_common/ios_commands/iossim_compile.py index 39b211b093c92d4b5d53053a061bf8dbabba0a1b..2eac1a9bab4552fb3a92ab9a6d8ef447b05af826 100755 --- a/compiler-rt/test/sanitizer_common/ios_commands/iossim_compile.py +++ b/compiler-rt/test/sanitizer_common/ios_commands/iossim_compile.py @@ -19,7 +19,7 @@ while args: elif arg == "-o": output = args.pop(0) -if output == None: +if output is None: print("No output file name!") sys.exit(1) diff --git a/compiler-rt/test/ubsan/lit.common.cfg.py b/compiler-rt/test/ubsan/lit.common.cfg.py index 61f6818cce064ff590f5e99ed87f639131811a0a..04d6f24de5a9fe6549a07358ec1b4d766d2ccf12 100644 --- a/compiler-rt/test/ubsan/lit.common.cfg.py +++ b/compiler-rt/test/ubsan/lit.common.cfg.py @@ -5,7 +5,7 @@ import os def get_required_attr(config, attr_name): attr_value = getattr(config, attr_name, None) - if attr_value == None: + if attr_value is None: lit_config.fatal( "No attribute %r in test configuration! You may need to run " "tests from your build directory or add this attribute " diff --git a/compiler-rt/test/ubsan_minimal/lit.common.cfg.py b/compiler-rt/test/ubsan_minimal/lit.common.cfg.py index d398d3a0a81626e854718165f19e6ddda21816ea..e60aed6512fb9e61828c00a64616f259005d01df 100644 --- a/compiler-rt/test/ubsan_minimal/lit.common.cfg.py +++ b/compiler-rt/test/ubsan_minimal/lit.common.cfg.py @@ -5,7 +5,7 @@ import os def get_required_attr(config, attr_name): attr_value = getattr(config, attr_name, None) - if attr_value == None: + if attr_value is None: lit_config.fatal( "No attribute %r in test configuration! You may need to run " "tests from your build directory or add this attribute " diff --git a/compiler-rt/test/xray/TestCases/Posix/basic-mode-dso.cpp b/compiler-rt/test/xray/TestCases/Posix/basic-mode-dso.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31c615bd1f81bfe514cfc0f443653e8e67dccb59 --- /dev/null +++ b/compiler-rt/test/xray/TestCases/Posix/basic-mode-dso.cpp @@ -0,0 +1,47 @@ +// Testing shared library support in basic logging mode. + +// RUN: split-file %s %t +// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlib.cpp -o %t/testlib.so +// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -std=c++11 %t/main.cpp %t/testlib.so -Wl,-rpath,%t -o %t/main.o + +// RUN: XRAY_OPTIONS="patch_premain=false,xray_mode=xray-basic,xray_logfile_base=basic-mode-dso-,verbosity=1" XRAY_BASIC_OPTIONS="func_duration_threshold_us=0" %run %t/main.o 2>&1 | FileCheck %s +// RUN: %llvm_xray account --format=csv --sort=funcid "`ls basic-mode-dso-* | head -1`" | FileCheck --check-prefix=ACCOUNT %s +// RUN: rm basic-mode-dso-* + +// REQUIRES: target=x86_64{{.*}} + +//--- main.cpp + +#include "xray/xray_interface.h" + +#include +#include + +[[clang::xray_always_instrument]] void instrumented_in_executable() { + printf("instrumented_in_executable called\n"); + sleep(1); +} + +extern void instrumented_in_dso(); + +int main() { + // Explicit patching to ensure the DSO has been loaded + __xray_patch(); + instrumented_in_executable(); + // CHECK: instrumented_in_executable called + instrumented_in_dso(); + // CHECK-NEXT: instrumented_in_dso called +} + +//--- testlib.cpp + +#include +#include + +[[clang::xray_always_instrument]] void instrumented_in_dso() { + printf("instrumented_in_dso called\n"); +} + +// ACCOUNT: funcid,count,min,median,90%ile,99%ile,max,sum,debug,function +// ACCOUNT-NEXT: 1,1,{{.*}} +// ACCOUNT-NEXT: 16777217,1,{{.*}} diff --git a/compiler-rt/test/xray/TestCases/Posix/clang-xray-shared.cpp b/compiler-rt/test/xray/TestCases/Posix/clang-xray-shared.cpp new file mode 100644 index 0000000000000000000000000000000000000000..92f3c29e970d42c1c489cac0ff0497cf512b4ce7 --- /dev/null +++ b/compiler-rt/test/xray/TestCases/Posix/clang-xray-shared.cpp @@ -0,0 +1,14 @@ +// Test that the DSO-local runtime library has been linked if -fxray-shared is passed. +// +// RUN: %clangxx -fxray-instrument -fxray-shared %s -shared -o %t.so +// RUN: llvm-nm %t.so | FileCheck %s --check-prefix ENABLED + +// RUN: %clangxx -fxray-instrument %s -shared -o %t.so +// RUN: llvm-nm %t.so | FileCheck %s --check-prefix DISABLED +// +// REQUIRES: target=x86_64{{.*}} + +[[clang::xray_always_instrument]] int always_instrumented() { return 42; } + +// ENABLED: __start_xray_instr_map +// DISABLED-NOT: __start_xray_instr_map diff --git a/compiler-rt/test/xray/TestCases/Posix/dlopen.cpp b/compiler-rt/test/xray/TestCases/Posix/dlopen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9db411d5ff1c6ee1220f518f74fc7da627ff71bc --- /dev/null +++ b/compiler-rt/test/xray/TestCases/Posix/dlopen.cpp @@ -0,0 +1,107 @@ +// Check that we can patch and un-patch DSOs loaded with dlopen. +// + +// RUN: split-file %s %t +// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlib.cpp -o %t/testlib.so +// RUN: %clangxx_xray -g -fPIC -rdynamic -fxray-instrument -fxray-shared -std=c++11 %t/main.cpp -o %t/main.o +// +// RUN: XRAY_OPTIONS="patch_premain=true" %run %t/main.o %t/testlib.so 2>&1 | FileCheck %s + +// REQUIRES: target=x86_64{{.*}} + +//--- main.cpp + +#include "xray/xray_interface.h" + +#include +#include + +void test_handler(int32_t fid, XRayEntryType type) { + printf("called: %d, type=%d\n", fid, static_cast(type)); +} + +[[clang::xray_always_instrument]] void instrumented_in_executable() { + printf("instrumented_in_executable called\n"); +} + +typedef void (*dso_func_type)(); + +int main(int argc, char **argv) { + if (argc < 2) { + printf("Shared library argument missing\n"); + // CHECK-NOT: Shared library argument missing + return 1; + } + + const char *dso_path = argv[1]; + + void *dso_handle = dlopen(dso_path, RTLD_LAZY); + if (!dso_handle) { + printf("Failed to load shared library\n"); + char *error = dlerror(); + if (error) { + fprintf(stderr, "%s\n", error); + return 1; + } + return 1; + } + + dso_func_type instrumented_in_dso = + (dso_func_type)dlsym(dso_handle, "_Z19instrumented_in_dsov"); + if (!instrumented_in_dso) { + printf("Failed to find symbol\n"); + char *error = dlerror(); + if (error) { + fprintf(stderr, "%s\n", error); + return 1; + } + return 1; + } + + __xray_set_handler(test_handler); + + instrumented_in_executable(); + // CHECK: called: {{.*}}, type=0 + // CHECK-NEXT: instrumented_in_executable called + // CHECK-NEXT: called: {{.*}}, type=1 + instrumented_in_dso(); + // CHECK-NEXT: called: {{.*}}, type=0 + // CHECK-NEXT: instrumented_in_dso called + // CHECK-NEXT: called: {{.*}}, type=1 + + auto status = __xray_unpatch(); + printf("unpatching status: %d\n", static_cast(status)); + // CHECK-NEXT: unpatching status: 1 + + instrumented_in_executable(); + // CHECK-NEXT: instrumented_in_executable called + instrumented_in_dso(); + // CHECK-NEXT: instrumented_in_dso called + + status = __xray_patch(); + printf("patching status: %d\n", static_cast(status)); + // CHECK-NEXT: patching status: 1 + + instrumented_in_executable(); + // CHECK-NEXT: called: {{.*}}, type=0 + // CHECK-NEXT: instrumented_in_executable called + // CHECK-NEXT: called: {{.*}}, type=1 + instrumented_in_dso(); + // CHECK-NEXT: called: {{.*}}, type=0 + // CHECK-NEXT: instrumented_in_dso called + // CHECK-NEXT: called: {{.*}}, type=1 + + dlclose(dso_handle); + + status = __xray_unpatch(); + printf("unpatching status: %d\n", static_cast(status)); + // CHECK-NEXT: unpatching status: 1 +} + +//--- testlib.cpp + +#include + +[[clang::xray_always_instrument]] void instrumented_in_dso() { + printf("instrumented_in_dso called\n"); +} diff --git a/compiler-rt/test/xray/TestCases/Posix/dso-dep-chains.cpp b/compiler-rt/test/xray/TestCases/Posix/dso-dep-chains.cpp new file mode 100644 index 0000000000000000000000000000000000000000..89da2764c35ceeef22a16c66c28723fc0346571b --- /dev/null +++ b/compiler-rt/test/xray/TestCases/Posix/dso-dep-chains.cpp @@ -0,0 +1,197 @@ +// Check that loading libraries with different modes (RTLD_LOCAL/RTLD_GLOBAL) +// and dependencies on other DSOs work correctly. +// + +// RUN: split-file %s %t +// +// Build shared libs with dependencies b->c and e->f +// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testliba.cpp -o %t/testliba.so +// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlibc.cpp -o %t/testlibc.so +// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlibb.cpp %t/testlibc.so -o %t/testlibb.so +// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlibd.cpp -o %t/testlibd.so +// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlibf.cpp -o %t/testlibf.so +// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlibe.cpp %t/testlibf.so -o %t/testlibe.so +// +// Executable links with a and b explicitly and loads d and e at runtime. +// RUN: %clangxx_xray -g -fPIC -rdynamic -fxray-instrument -fxray-shared -std=c++11 %t/main.cpp %t/testliba.so %t/testlibb.so -o %t/main.o +// +// RUN: XRAY_OPTIONS="patch_premain=true" %run %t/main.o %t/testlibd.so %t/testlibe.so 2>&1 | FileCheck %s + +// REQUIRES: target=x86_64{{.*}} + +//--- main.cpp + +#include "xray/xray_interface.h" + +#include +#include + +[[clang::xray_never_instrument]] void test_handler(int32_t fid, + XRayEntryType type) { + printf("called: %d, object=%d, fn=%d, type=%d\n", fid, (fid >> 24) & 0xFF, + fid & 0x00FFFFFF, static_cast(type)); +} + +[[clang::xray_always_instrument]] void instrumented_in_executable() { + printf("instrumented_in_executable called\n"); +} + +typedef void (*dso_func_type)(); + +[[clang::xray_never_instrument]] void *load_dso(const char *path, int mode) { + void *dso_handle = dlopen(path, mode); + if (!dso_handle) { + printf("failed to load shared library\n"); + char *error = dlerror(); + if (error) { + fprintf(stderr, "%s\n", error); + } + return nullptr; + } + return dso_handle; +} + +[[clang::xray_never_instrument]] void find_and_call(void *dso_handle, + const char *fn) { + dso_func_type dso_fn = (dso_func_type)dlsym(dso_handle, fn); + if (!dso_fn) { + printf("failed to find symbol\n"); + char *error = dlerror(); + if (error) { + fprintf(stderr, "%s\n", error); + } + return; + } + dso_fn(); +} + +extern void a(); +extern void b(); + +int main(int argc, char **argv) { + + if (argc < 3) { + printf("Shared library arguments missing\n"); + // CHECK-NOT: Shared library arguments missing + return 1; + } + + const char *dso_path_d = argv[1]; + const char *dso_path_e = argv[2]; + + __xray_set_handler(test_handler); + + instrumented_in_executable(); + // CHECK: called: {{[0-9]+}}, object=0, fn={{[0-9]+}}, type=0 + // CHECK-NEXT: instrumented_in_executable called + // CHECK-NEXT: called: {{[0-9]+}}, object=0, fn={{[0-9]+}}, type=1 + + a(); + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ1:[0-9]+]], fn=1, type=0 + // CHECK-NEXT: a called + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ1]], fn=1, type=1 + + // Make sure this object ID does not appear again + // CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ1]] + + b(); // b calls c + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ2:[0-9]+]], fn=1, type=0 + // CHECK-NEXT: b called + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ3:[0-9]+]], fn=1, type=0 + // CHECK-NEXT: c called + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ3]], fn=1, type=1 + // CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ3]] + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ2]], fn=1, type=1 + // CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ2]] + + // Now check explicit loading with RTLD_LOCAL + + void *dso_handle_d = load_dso(dso_path_d, RTLD_LAZY | RTLD_LOCAL); + void *dso_handle_e = load_dso(dso_path_e, RTLD_LAZY | RTLD_LOCAL); + // CHECK-NOT: failed to load shared library + + find_and_call(dso_handle_d, "_Z1dv"); + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ4:[0-9]+]], fn=1, type=0 + // CHECK-NEXT: d called + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ4]], fn=1, type=1 + // CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ4]] + + find_and_call(dso_handle_e, "_Z1ev"); + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ5:[0-9]+]], fn=1, type=0 + // CHECK-NEXT: e called + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ6:[0-9]+]], fn=1, type=0 + // CHECK-NEXT: f called + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ6]], fn=1, type=1 + // CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ6]] + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ5]], fn=1, type=1 + // CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ5]] + + // Unload DSOs + dlclose(dso_handle_d); + dlclose(dso_handle_e); + + // Repeat test with RTLD_GLOBAL + dso_handle_d = load_dso(dso_path_d, RTLD_LAZY | RTLD_GLOBAL); + dso_handle_e = load_dso(dso_path_e, RTLD_LAZY | RTLD_GLOBAL); + // CHECK-NOT: failed to load shared library + + find_and_call(dso_handle_d, "_Z1dv"); + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ7:[0-9]+]], fn=1, type=0 + // CHECK-NEXT: d called + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ7]], fn=1, type=1 + // CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ7]] + + find_and_call(dso_handle_e, "_Z1ev"); + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ8:[0-9]+]], fn=1, type=0 + // CHECK-NEXT: e called + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ9:[0-9]+]], fn=1, type=0 + // CHECK-NEXT: f called + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ9]], fn=1, type=1 + // CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ9]] + // CHECK-NEXT: called: {{[0-9]+}}, object=[[OBJ8]], fn=1, type=1 + // CHECK-NOT: called: {{[0-9]+}}, object=[[OBJ8]] + + auto status = __xray_unpatch(); + printf("unpatching status: %d\n", static_cast(status)); + // CHECK-NEXT: unpatching status: 1 + + dlclose(dso_handle_d); + dlclose(dso_handle_e); +} + +//--- libgenmacro.inc +#include +// Helper macros to quickly generate libraries containing a single function. +#define GENERATE_LIB(NAME) \ + [[clang::xray_always_instrument]] void NAME() { printf(#NAME " called\n"); } + +#define GENERATE_LIB_WITH_CALL(NAME, FN) \ + extern void FN(); \ + [[clang::xray_always_instrument]] void NAME() { \ + printf(#NAME " called\n"); \ + FN(); \ + } + +//--- testliba.cpp +#include "libgenmacro.inc" +GENERATE_LIB(a) + +//--- testlibb.cpp +#include "libgenmacro.inc" +GENERATE_LIB_WITH_CALL(b, c) + +//--- testlibc.cpp +#include "libgenmacro.inc" +GENERATE_LIB(c) + +//--- testlibd.cpp +#include "libgenmacro.inc" +GENERATE_LIB(d) + +//--- testlibe.cpp +#include "libgenmacro.inc" +GENERATE_LIB_WITH_CALL(e, f) + +//--- testlibf.cpp +#include "libgenmacro.inc" +GENERATE_LIB(f) diff --git a/compiler-rt/test/xray/TestCases/Posix/patch-premain-dso.cpp b/compiler-rt/test/xray/TestCases/Posix/patch-premain-dso.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0708d0383439d001f07cb00fe68baa5679aef4f3 --- /dev/null +++ b/compiler-rt/test/xray/TestCases/Posix/patch-premain-dso.cpp @@ -0,0 +1,45 @@ +// Checking that DSOs are automatically patched upon load, if patch_premain is passed. + +// RUN: split-file %s %t +// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlib.cpp -o %t/testlib.so +// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -std=c++11 %t/main.cpp %t/testlib.so -Wl,-rpath,%t -o %t/main.o + +// RUN: XRAY_OPTIONS="patch_premain=true,verbosity=1" %run %t/main.o 2>&1 | FileCheck %s + +// REQUIRES: target=x86_64{{.*}} + +//--- main.cpp + +#include "xray/xray_interface.h" + +#include + +void test_handler(int32_t fid, XRayEntryType type) { + printf("called: %d, type=%d\n", fid, static_cast(type)); +} + +[[clang::xray_always_instrument]] void instrumented_in_executable() { + printf("instrumented_in_executable called\n"); +} + +extern void instrumented_in_dso(); + +int main() { + __xray_set_handler(test_handler); + instrumented_in_executable(); + // CHECK: called: {{.*}}, type=0 + // CHECK-NEXT: instrumented_in_executable called + // CHECK-NEXT: called: {{.*}}, type=1 + instrumented_in_dso(); + // CHECK-NEXT: called: {{.*}}, type=0 + // CHECK-NEXT: instrumented_in_dso called + // CHECK-NEXT: called: {{.*}}, type=1 +} + +//--- testlib.cpp + +#include + +[[clang::xray_always_instrument]] void instrumented_in_dso() { + printf("instrumented_in_dso called\n"); +} diff --git a/compiler-rt/test/xray/TestCases/Posix/patching-unpatching-dso.cpp b/compiler-rt/test/xray/TestCases/Posix/patching-unpatching-dso.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d3e992dd497725767c6e0abb0878e702ec5880bf --- /dev/null +++ b/compiler-rt/test/xray/TestCases/Posix/patching-unpatching-dso.cpp @@ -0,0 +1,75 @@ +// Check that we can patch and un-patch on demand, and that logging gets invoked +// appropriately. +// + +// RUN: split-file %s %t +// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -shared -std=c++11 %t/testlib.cpp -o %t/testlib.so +// RUN: %clangxx_xray -g -fPIC -fxray-instrument -fxray-shared -std=c++11 %t/main.cpp %t/testlib.so -Wl,-rpath,%t -o %t/main.o + +// RUN: XRAY_OPTIONS="patch_premain=false" %run %t/main.o 2>&1 | FileCheck %s + +// REQUIRES: target=x86_64{{.*}} + +//--- main.cpp + +#include "xray/xray_interface.h" + +#include + +bool called = false; + +void test_handler(int32_t fid, XRayEntryType type) { + printf("called: %d, type=%d\n", fid, static_cast(type)); + called = true; +} + +[[clang::xray_always_instrument]] void instrumented_in_executable() { + printf("instrumented_in_executable called\n"); +} + +extern void instrumented_in_dso(); + +int main() { + __xray_set_handler(test_handler); + instrumented_in_executable(); + // CHECK: instrumented_in_executable called + instrumented_in_dso(); + // CHECK: instrumented_in_dso called + auto status = __xray_patch(); + printf("patching status: %d\n", static_cast(status)); + // CHECK-NEXT: patching status: 1 + instrumented_in_executable(); + // CHECK-NEXT: called: {{.*}}, type=0 + // CHECK-NEXT: instrumented_in_executable called + // CHECK-NEXT: called: {{.*}}, type=1 + instrumented_in_dso(); + // CHECK-NEXT: called: {{.*}}, type=0 + // CHECK-NEXT: instrumented_in_dso called + // CHECK-NEXT: called: {{.*}}, type=1 + status = __xray_unpatch(); + printf("patching status: %d\n", static_cast(status)); + // CHECK-NEXT: patching status: 1 + instrumented_in_executable(); + // CHECK-NEXT: instrumented_in_executable called + instrumented_in_dso(); + // CHECK-NEXT: instrumented_in_dso called + status = __xray_patch(); + printf("patching status: %d\n", static_cast(status)); + // CHECK-NEXT: patching status: 1 + __xray_remove_handler(); + instrumented_in_executable(); + // CHECK-NEXT: instrumented_in_executable called + instrumented_in_dso(); + // CHECK-NEXT: instrumented_in_dso called + status = __xray_unpatch(); + printf("patching status: %d\n", static_cast(status)); + // CHECK-NEXT: patching status: 1 +} + +//--- testlib.cpp + +#include + +[[clang::xray_always_instrument]] void instrumented_in_dso() { + printf("instrumented_in_dso called\n"); +} diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp index 06ca12a492d29b042222c187ec1bbf0351129d9b..62f8d39a8abaa5fb5ce81a52919bbc1066e0aa64 100644 --- a/flang/examples/FeatureList/FeatureList.cpp +++ b/flang/examples/FeatureList/FeatureList.cpp @@ -473,8 +473,8 @@ public: READ_FEATURE(OmpDependClause::InOut) READ_FEATURE(OmpDependClause::Sink) READ_FEATURE(OmpDependClause::Source) - READ_FEATURE(OmpDependenceType) - READ_FEATURE(OmpDependenceType::Type) + READ_FEATURE(OmpTaskDependenceType) + READ_FEATURE(OmpTaskDependenceType::Type) READ_FEATURE(OmpDependSinkVec) READ_FEATURE(OmpDependSinkVecLength) READ_FEATURE(OmpEndAllocators) @@ -483,6 +483,8 @@ public: READ_FEATURE(OmpEndCriticalDirective) READ_FEATURE(OmpEndLoopDirective) READ_FEATURE(OmpEndSectionsDirective) + READ_FEATURE(OmpGrainsizeClause) + READ_FEATURE(OmpGrainsizeClause::Prescriptiveness) READ_FEATURE(OmpIfClause) READ_FEATURE(OmpIfClause::DirectiveNameModifier) READ_FEATURE(OmpLinearClause) @@ -494,6 +496,8 @@ public: READ_FEATURE(OmpMapClause) READ_FEATURE(OmpMapClause::TypeModifier) READ_FEATURE(OmpMapClause::Type) + READ_FEATURE(OmpNumTasksClause) + READ_FEATURE(OmpNumTasksClause::Prescriptiveness) READ_FEATURE(OmpObject) READ_FEATURE(OmpObjectList) READ_FEATURE(OmpOrderClause) diff --git a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp index 5d3c5cd72eef04d217c4b8b8f4f4a2b677da6c98..d28ed0534d6002639e4d5b4e7e10821bbdf20ed5 100644 --- a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp +++ b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp @@ -222,9 +222,9 @@ void OpenMPCounterVisitor::Post(const OmpLinearModifier::Type &c) { clauseDetails += "modifier=" + std::string{OmpLinearModifier::EnumToString(c)} + ";"; } -void OpenMPCounterVisitor::Post(const OmpDependenceType::Type &c) { +void OpenMPCounterVisitor::Post(const OmpTaskDependenceType::Type &c) { clauseDetails += - "type=" + std::string{OmpDependenceType::EnumToString(c)} + ";"; + "type=" + std::string{OmpTaskDependenceType::EnumToString(c)} + ";"; } void OpenMPCounterVisitor::Post(const OmpMapClause::Type &c) { clauseDetails += "type=" + std::string{OmpMapClause::EnumToString(c)} + ";"; diff --git a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h index 380534ebbfd70ac95b1efc48d3be83891c0aaccc..68c52db46e2f0089c8d395ad97e606236834c3c6 100644 --- a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h +++ b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h @@ -73,7 +73,7 @@ struct OpenMPCounterVisitor { void Post(const OmpDeviceTypeClause::Type &c); void Post(const OmpScheduleModifierType::ModType &c); void Post(const OmpLinearModifier::Type &c); - void Post(const OmpDependenceType::Type &c); + void Post(const OmpTaskDependenceType::Type &c); void Post(const OmpMapClause::Type &c); void Post(const OmpScheduleClause::ScheduleType &c); void Post(const OmpIfClause::DirectiveNameModifier &c); diff --git a/flang/include/flang/Optimizer/Transforms/CUFCommon.h b/flang/include/flang/Optimizer/Transforms/CUFCommon.h new file mode 100644 index 0000000000000000000000000000000000000000..b88133489df5e2423289bb3648da71bf0d20cdab --- /dev/null +++ b/flang/include/flang/Optimizer/Transforms/CUFCommon.h @@ -0,0 +1,25 @@ +//===-- CUFCommon.h -------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_OPTIMIZER_TRANSFORMS_CUFCOMMON_H_ +#define FORTRAN_OPTIMIZER_TRANSFORMS_CUFCOMMON_H_ + +#include "mlir/Dialect/GPU/IR/GPUDialect.h" +#include "mlir/IR/BuiltinOps.h" + +static constexpr llvm::StringRef cudaDeviceModuleName = "cuda_device_mod"; + +namespace cuf { + +/// Retrieve or create the CUDA Fortran GPU module in the given \p mod. +mlir::gpu::GPUModuleOp getOrCreateGPUModule(mlir::ModuleOp mod, + mlir::SymbolTable &symTab); + +} // namespace cuf + +#endif // FORTRAN_OPTIMIZER_TRANSFORMS_CUFCOMMON_H_ diff --git a/flang/include/flang/Optimizer/Transforms/CUFGPUToLLVMConversion.h b/flang/include/flang/Optimizer/Transforms/CUFGPUToLLVMConversion.h new file mode 100644 index 0000000000000000000000000000000000000000..7d76c1f4e5218770e3ec57ef29f72b302d1defac --- /dev/null +++ b/flang/include/flang/Optimizer/Transforms/CUFGPUToLLVMConversion.h @@ -0,0 +1,28 @@ +//===------- Optimizer/Transforms/CUFGPUToLLVMConversion.h ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_OPTIMIZER_TRANSFORMS_CUFGPUTOLLVMCONVERSION_H_ +#define FORTRAN_OPTIMIZER_TRANSFORMS_CUFGPUTOLLVMCONVERSION_H_ + +#include "mlir/Pass/Pass.h" +#include "mlir/Pass/PassRegistry.h" +#include "mlir/Transforms/DialectConversion.h" + +namespace fir { +class LLVMTypeConverter; +} + +namespace cuf { + +void populateCUFGPUToLLVMConversionPatterns( + const fir::LLVMTypeConverter &converter, mlir::RewritePatternSet &patterns, + mlir::PatternBenefit benefit = 1); + +} // namespace cuf + +#endif // FORTRAN_OPTIMIZER_TRANSFORMS_CUFGPUTOLLVMCONVERSION_H_ diff --git a/flang/include/flang/Optimizer/Transforms/Passes.h b/flang/include/flang/Optimizer/Transforms/Passes.h index 5d3067aa35981368c8544925f2431cbe685d99c9..e8f0a8444a31a1e63bb5e9af0df4dd6702e06ac9 100644 --- a/flang/include/flang/Optimizer/Transforms/Passes.h +++ b/flang/include/flang/Optimizer/Transforms/Passes.h @@ -41,6 +41,7 @@ namespace fir { #define GEN_PASS_DECL_CFGCONVERSION #define GEN_PASS_DECL_CUFADDCONSTRUCTOR #define GEN_PASS_DECL_CUFDEVICEGLOBAL +#define GEN_PASS_DECL_CUFGPUTOLLVMCONVERSION #define GEN_PASS_DECL_CUFOPCONVERSION #define GEN_PASS_DECL_EXTERNALNAMECONVERSION #define GEN_PASS_DECL_MEMREFDATAFLOWOPT diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td index 2efa543ca07148883181b052922acad2de219a3d..a41f0f348f27a65ed4aa001502756bc5ef0ab7b2 100644 --- a/flang/include/flang/Optimizer/Transforms/Passes.td +++ b/flang/include/flang/Optimizer/Transforms/Passes.td @@ -443,4 +443,11 @@ def CUFAddConstructor : Pass<"cuf-add-constructor", "mlir::ModuleOp"> { ]; } +def CUFGPUToLLVMConversion : Pass<"cuf-gpu-convert-to-llvm", "mlir::ModuleOp"> { + let summary = "Convert some GPU operations lowered from CUF to runtime calls"; + let dependentDialects = [ + "mlir::LLVM::LLVMDialect" + ]; +} + #endif // FLANG_OPTIMIZER_TRANSFORMS_PASSES diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index e5565ee9ac0df715f15f6ef5258887bea32fb98a..55c1acd59f7c0b4c697fca5b65414e0f62265aa2 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -479,6 +479,7 @@ public: NODE(parser, OldParameterStmt) NODE(parser, OmpIteratorSpecifier) NODE(parser, OmpIteratorModifier) + NODE(parser, OmpAffinityClause) NODE(parser, OmpAlignedClause) NODE(parser, OmpAtomic) NODE(parser, OmpAtomicCapture) @@ -515,8 +516,8 @@ public: NODE(OmpDependClause, InOut) NODE(OmpDependClause, Sink) NODE(OmpDependClause, Source) - NODE(parser, OmpDependenceType) - NODE_ENUM(OmpDependenceType, Type) + NODE(parser, OmpTaskDependenceType) + NODE_ENUM(OmpTaskDependenceType, Type) NODE(parser, OmpDependSinkVec) NODE(parser, OmpDependSinkVecLength) NODE(parser, OmpEndAllocators) @@ -549,6 +550,10 @@ public: NODE_ENUM(OmpOrderClause, Type) NODE(parser, OmpOrderModifier) NODE_ENUM(OmpOrderModifier, Kind) + NODE(parser, OmpGrainsizeClause) + NODE_ENUM(OmpGrainsizeClause, Prescriptiveness) + NODE(parser, OmpNumTasksClause) + NODE_ENUM(OmpNumTasksClause, Prescriptiveness) NODE(parser, OmpProcBindClause) NODE_ENUM(OmpProcBindClause, Type) NODE_ENUM(OmpReductionClause, ReductionModifier) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index 8577c6c6436349b60d0e6b8217c71eb8751d9641..e6a5e1e0c1129d349f61c24116b0707984f93e47 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3456,7 +3456,32 @@ struct AssignedGotoStmt { WRAPPER_CLASS(PauseStmt, std::optional); -// Parse tree nodes for OpenMP 5.2 directives and clauses +// Parse tree nodes for OpenMP directives and clauses + +// --- Common definitions + +// 2.1 Directives or clauses may accept a list or extended-list. +// A list item is a variable, array section or common block name (enclosed +// in slashes). An extended list item is a list item or a procedure Name. +// variable-name | / common-block / | array-sections +struct OmpObject { + UNION_CLASS_BOILERPLATE(OmpObject); + std::variant u; +}; + +WRAPPER_CLASS(OmpObjectList, std::list); + +// Ref: [4.5:169-170], [5.0:254-256], [5.1:287-289], [5.2:321] +// +// task-dependence-type -> // "dependence-type" in 5.1 and before +// IN | OUT | INOUT | // since 4.5 +// SOURCE | SINK | // since 4.5, until 5.1 +// MUTEXINOUTSET | DEPOBJ | // since 5.0 +// INOUTSET // since 5.2 +struct OmpTaskDependenceType { + ENUM_CLASS(Type, In, Out, Inout, Source, Sink) + WRAPPER_CLASS_BOILERPLATE(OmpTaskDependenceType, Type); +}; // [5.0] 2.1.6 iterator-specifier -> type-declaration-stmt = subscript-triple // iterator-modifier -> iterator-specifier-list @@ -3468,50 +3493,61 @@ struct OmpIteratorSpecifier { WRAPPER_CLASS(OmpIteratorModifier, std::list); -// 2.5 proc-bind-clause -> PROC_BIND (MASTER | CLOSE | SPREAD) -struct OmpProcBindClause { - ENUM_CLASS(Type, Close, Master, Spread, Primary) - WRAPPER_CLASS_BOILERPLATE(OmpProcBindClause, Type); +// 2.15.3.6 reduction-identifier -> + | - | * | .AND. | .OR. | .EQV. | .NEQV. | +// MAX | MIN | IAND | IOR | IEOR +struct OmpReductionOperator { + UNION_CLASS_BOILERPLATE(OmpReductionOperator); + std::variant u; }; -// 2.15.3.1 default-clause -> DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE) -struct OmpDefaultClause { - ENUM_CLASS(Type, Private, Firstprivate, Shared, None) - WRAPPER_CLASS_BOILERPLATE(OmpDefaultClause, Type); +// --- Clauses + +// OMP 5.0 2.10.1 affinity([aff-modifier:] locator-list) +// aff-modifier: interator-modifier +struct OmpAffinityClause { + TUPLE_CLASS_BOILERPLATE(OmpAffinityClause); + std::tuple, OmpObjectList> t; }; -// 2.1 Directives or clauses may accept a list or extended-list. -// A list item is a variable, array section or common block name (enclosed -// in slashes). An extended list item is a list item or a procedure Name. -// variable-name | / common-block / | array-sections -struct OmpObject { - UNION_CLASS_BOILERPLATE(OmpObject); - std::variant u; +// 2.8.1 aligned-clause -> ALIGNED (variable-name-list[ : scalar-constant]) +struct OmpAlignedClause { + TUPLE_CLASS_BOILERPLATE(OmpAlignedClause); + CharBlock source; + std::tuple> t; }; -WRAPPER_CLASS(OmpObjectList, std::list); +// OMP 5.0 2.11.4 allocate-clause -> ALLOCATE ([allocator:] variable-name-list) +// OMP 5.2 2.13.4 allocate-clause -> ALLOCATE ([allocate-modifier [, +// allocate-modifier] :] +// variable-name-list) +// allocate-modifier -> allocator | align +struct OmpAllocateClause { + struct AllocateModifier { + WRAPPER_CLASS(Allocator, ScalarIntExpr); + WRAPPER_CLASS(Align, ScalarIntExpr); + struct ComplexModifier { + TUPLE_CLASS_BOILERPLATE(ComplexModifier); + std::tuple t; + }; + UNION_CLASS_BOILERPLATE(AllocateModifier); + std::variant u; + }; + TUPLE_CLASS_BOILERPLATE(OmpAllocateClause); + std::tuple, OmpObjectList> t; +}; -// 2.15.5.1 map -> -// MAP ([[map-type-modifier-list [,]] [iterator-modifier [,]] map-type : ] -// variable-name-list) -// map-type-modifier-list -> map-type-modifier [,] [...] -// map-type-modifier -> ALWAYS | CLOSE | PRESENT | OMPX_HOLD -// map-type -> TO | FROM | TOFROM | ALLOC | RELEASE | DELETE -struct OmpMapClause { - ENUM_CLASS(TypeModifier, Always, Close, Present, Ompx_Hold); - ENUM_CLASS(Type, To, From, Tofrom, Alloc, Release, Delete) - TUPLE_CLASS_BOILERPLATE(OmpMapClause); +// OMP 5.0 2.4 atomic-default-mem-order-clause -> +// ATOMIC_DEFAULT_MEM_ORDER (SEQ_CST | ACQ_REL | +// RELAXED) +struct OmpAtomicDefaultMemOrderClause { + WRAPPER_CLASS_BOILERPLATE( + OmpAtomicDefaultMemOrderClause, common::OmpAtomicDefaultMemOrderType); +}; - // All modifiers are parsed into optional lists, even if they are unique. - // The checks for satisfying those constraints are deferred to semantics. - // In OpenMP 5.2 the non-comma syntax has been deprecated: keep the - // information about separator presence to emit a diagnostic if needed. - std::tuple>, - std::optional>, // unique - std::optional>, // unique - OmpObjectList, - bool> // were the modifiers comma-separated? - t; +// 2.15.3.1 default-clause -> DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE) +struct OmpDefaultClause { + ENUM_CLASS(Type, Private, Firstprivate, Shared, None) + WRAPPER_CLASS_BOILERPLATE(OmpDefaultClause, Type); }; // 2.15.5.2 defaultmap -> DEFAULTMAP (implicit-behavior[:variable-category]) @@ -3523,29 +3559,6 @@ struct OmpDefaultmapClause { std::tuple> t; }; -// 2.7.1 sched-modifier -> MONOTONIC | NONMONOTONIC | SIMD -struct OmpScheduleModifierType { - ENUM_CLASS(ModType, Monotonic, Nonmonotonic, Simd) - WRAPPER_CLASS_BOILERPLATE(OmpScheduleModifierType, ModType); -}; - -struct OmpScheduleModifier { - TUPLE_CLASS_BOILERPLATE(OmpScheduleModifier); - WRAPPER_CLASS(Modifier1, OmpScheduleModifierType); - WRAPPER_CLASS(Modifier2, OmpScheduleModifierType); - std::tuple> t; -}; - -// 2.7.1 schedule-clause -> SCHEDULE ([sched-modifier1] [, sched-modifier2]:] -// kind[, chunk_size]) -struct OmpScheduleClause { - TUPLE_CLASS_BOILERPLATE(OmpScheduleClause); - ENUM_CLASS(ScheduleType, Static, Dynamic, Guided, Auto, Runtime) - std::tuple, ScheduleType, - std::optional> - t; -}; - // device([ device-modifier :] scalar-integer-expression) struct OmpDeviceClause { TUPLE_CLASS_BOILERPLATE(OmpDeviceClause); @@ -3559,6 +3572,46 @@ struct OmpDeviceTypeClause { WRAPPER_CLASS_BOILERPLATE(OmpDeviceTypeClause, Type); }; +// 2.13.9 depend-vec-length -> +/- non-negative-constant +struct OmpDependSinkVecLength { + TUPLE_CLASS_BOILERPLATE(OmpDependSinkVecLength); + std::tuple t; +}; + +// 2.13.9 depend-vec -> induction-variable [depend-vec-length], ... +struct OmpDependSinkVec { + TUPLE_CLASS_BOILERPLATE(OmpDependSinkVec); + std::tuple> t; +}; + +// Ref: [4.5:169-170], [5.0:255-256], [5.1:288-289], [5.2:323-324] +// +// depend-clause -> +// DEPEND(SOURCE) | // since 4.5, until 5.1 +// DEPEND(SINK: depend-vec) | // since 4.5, until 5.1 +// DEPEND([depend-modifier,]dependence-type: locator-list) // since 4.5 +// +// depend-modifier -> iterator-modifier // since 5.0 +struct OmpDependClause { + UNION_CLASS_BOILERPLATE(OmpDependClause); + EMPTY_CLASS(Source); + WRAPPER_CLASS(Sink, std::list); + struct InOut { + TUPLE_CLASS_BOILERPLATE(InOut); + std::tuple, OmpTaskDependenceType, + OmpObjectList> + t; + }; + std::variant u; +}; + +// OMP 5.2 12.6.1 grainsize-clause -> grainsize ([prescriptiveness :] value) +struct OmpGrainsizeClause { + TUPLE_CLASS_BOILERPLATE(OmpGrainsizeClause); + ENUM_CLASS(Prescriptiveness, Strict); + std::tuple, ScalarIntExpr> t; +}; + // 2.12 if-clause -> IF ([ directive-name-modifier :] scalar-logical-expr) struct OmpIfClause { TUPLE_CLASS_BOILERPLATE(OmpIfClause); @@ -3567,24 +3620,20 @@ struct OmpIfClause { std::tuple, ScalarLogicalExpr> t; }; -// 2.8.1 aligned-clause -> ALIGNED (variable-name-list[ : scalar-constant]) -struct OmpAlignedClause { - TUPLE_CLASS_BOILERPLATE(OmpAlignedClause); - CharBlock source; - std::tuple> t; -}; - -// 2.9.5 order-clause -> ORDER ([order-modifier :]concurrent) -struct OmpOrderModifier { - UNION_CLASS_BOILERPLATE(OmpOrderModifier); - ENUM_CLASS(Kind, Reproducible, Unconstrained) - std::variant u; +// OMP 5.0 2.19.5.6 in_reduction-clause -> IN_REDUCTION (reduction-identifier: +// variable-name-list) +struct OmpInReductionClause { + TUPLE_CLASS_BOILERPLATE(OmpInReductionClause); + std::tuple t; }; -struct OmpOrderClause { - TUPLE_CLASS_BOILERPLATE(OmpOrderClause); - ENUM_CLASS(Type, Concurrent) - std::tuple, Type> t; +// OMP 5.0 2.19.4.5 lastprivate-clause -> +// LASTPRIVATE ([lastprivate-modifier :] list) +// lastprivate-modifier -> CONDITIONAL +struct OmpLastprivateClause { + TUPLE_CLASS_BOILERPLATE(OmpLastprivateClause); + ENUM_CLASS(LastprivateModifier, Conditional); + std::tuple, OmpObjectList> t; }; // 2.15.3.7 linear-modifier -> REF | VAL | UVAL @@ -3617,96 +3666,86 @@ struct OmpLinearClause { std::variant u; }; -// 2.15.3.6 reduction-identifier -> + | - | * | .AND. | .OR. | .EQV. | .NEQV. | -// MAX | MIN | IAND | IOR | IEOR -struct OmpReductionOperator { - UNION_CLASS_BOILERPLATE(OmpReductionOperator); - std::variant u; -}; +// 2.15.5.1 map -> +// MAP ([[map-type-modifier-list [,]] [iterator-modifier [,]] map-type : ] +// variable-name-list) +// map-type-modifier-list -> map-type-modifier [,] [...] +// map-type-modifier -> ALWAYS | CLOSE | PRESENT | OMPX_HOLD +// map-type -> TO | FROM | TOFROM | ALLOC | RELEASE | DELETE +struct OmpMapClause { + ENUM_CLASS(TypeModifier, Always, Close, Present, Ompx_Hold); + ENUM_CLASS(Type, To, From, Tofrom, Alloc, Release, Delete) + TUPLE_CLASS_BOILERPLATE(OmpMapClause); -// 2.15.3.6 reduction-clause -> REDUCTION (reduction-identifier: -// variable-name-list) -struct OmpReductionClause { - TUPLE_CLASS_BOILERPLATE(OmpReductionClause); - ENUM_CLASS(ReductionModifier, Inscan, Task, Default) - std::tuple, OmpReductionOperator, - OmpObjectList> + // All modifiers are parsed into optional lists, even if they are unique. + // The checks for satisfying those constraints are deferred to semantics. + // In OpenMP 5.2 the non-comma syntax has been deprecated: keep the + // information about separator presence to emit a diagnostic if needed. + std::tuple>, + std::optional>, // unique + std::optional>, // unique + OmpObjectList, + bool> // were the modifiers comma-separated? t; }; -// OMP 5.0 2.19.5.6 in_reduction-clause -> IN_REDUCTION (reduction-identifier: -// variable-name-list) -struct OmpInReductionClause { - TUPLE_CLASS_BOILERPLATE(OmpInReductionClause); - std::tuple t; +// 2.9.5 order-clause -> ORDER ([order-modifier :]concurrent) +struct OmpOrderModifier { + UNION_CLASS_BOILERPLATE(OmpOrderModifier); + ENUM_CLASS(Kind, Reproducible, Unconstrained) + std::variant u; }; -// OMP 5.0 2.11.4 allocate-clause -> ALLOCATE ([allocator:] variable-name-list) -// OMP 5.2 2.13.4 allocate-clause -> ALLOCATE ([allocate-modifier [, -// allocate-modifier] :] -// variable-name-list) -// allocate-modifier -> allocator | align -struct OmpAllocateClause { - struct AllocateModifier { - WRAPPER_CLASS(Allocator, ScalarIntExpr); - WRAPPER_CLASS(Align, ScalarIntExpr); - struct ComplexModifier { - TUPLE_CLASS_BOILERPLATE(ComplexModifier); - std::tuple t; - }; - UNION_CLASS_BOILERPLATE(AllocateModifier); - std::variant u; - }; - TUPLE_CLASS_BOILERPLATE(OmpAllocateClause); - std::tuple, OmpObjectList> t; +struct OmpOrderClause { + TUPLE_CLASS_BOILERPLATE(OmpOrderClause); + ENUM_CLASS(Type, Concurrent) + std::tuple, Type> t; }; -// 2.13.9 depend-vec-length -> +/- non-negative-constant -struct OmpDependSinkVecLength { - TUPLE_CLASS_BOILERPLATE(OmpDependSinkVecLength); - std::tuple t; +// 2.5 proc-bind-clause -> PROC_BIND (MASTER | CLOSE | SPREAD) +struct OmpProcBindClause { + ENUM_CLASS(Type, Close, Master, Spread, Primary) + WRAPPER_CLASS_BOILERPLATE(OmpProcBindClause, Type); }; -// 2.13.9 depend-vec -> iterator [+/- depend-vec-length],...,iterator[...] -struct OmpDependSinkVec { - TUPLE_CLASS_BOILERPLATE(OmpDependSinkVec); - std::tuple> t; +// 2.15.3.6 reduction-clause -> REDUCTION (reduction-identifier: +// variable-name-list) +struct OmpReductionClause { + TUPLE_CLASS_BOILERPLATE(OmpReductionClause); + ENUM_CLASS(ReductionModifier, Inscan, Task, Default) + std::tuple, OmpReductionOperator, + OmpObjectList> + t; }; -// 2.13.9 depend-type -> IN | OUT | INOUT | SOURCE | SINK -struct OmpDependenceType { - ENUM_CLASS(Type, In, Out, Inout, Source, Sink) - WRAPPER_CLASS_BOILERPLATE(OmpDependenceType, Type); +// 2.7.1 sched-modifier -> MONOTONIC | NONMONOTONIC | SIMD +struct OmpScheduleModifierType { + ENUM_CLASS(ModType, Monotonic, Nonmonotonic, Simd) + WRAPPER_CLASS_BOILERPLATE(OmpScheduleModifierType, ModType); }; -// 2.13.9 depend-clause -> DEPEND (((IN | OUT | INOUT) : variable-name-list) | -// SOURCE | SINK : depend-vec) -struct OmpDependClause { - UNION_CLASS_BOILERPLATE(OmpDependClause); - EMPTY_CLASS(Source); - WRAPPER_CLASS(Sink, std::list); - struct InOut { - TUPLE_CLASS_BOILERPLATE(InOut); - std::tuple> t; - }; - std::variant u; +struct OmpScheduleModifier { + TUPLE_CLASS_BOILERPLATE(OmpScheduleModifier); + WRAPPER_CLASS(Modifier1, OmpScheduleModifierType); + WRAPPER_CLASS(Modifier2, OmpScheduleModifierType); + std::tuple> t; }; -// OMP 5.0 2.4 atomic-default-mem-order-clause -> -// ATOMIC_DEFAULT_MEM_ORDER (SEQ_CST | ACQ_REL | -// RELAXED) -struct OmpAtomicDefaultMemOrderClause { - WRAPPER_CLASS_BOILERPLATE( - OmpAtomicDefaultMemOrderClause, common::OmpAtomicDefaultMemOrderType); +// 2.7.1 schedule-clause -> SCHEDULE ([sched-modifier1] [, sched-modifier2]:] +// kind[, chunk_size]) +struct OmpScheduleClause { + TUPLE_CLASS_BOILERPLATE(OmpScheduleClause); + ENUM_CLASS(ScheduleType, Static, Dynamic, Guided, Auto, Runtime) + std::tuple, ScheduleType, + std::optional> + t; }; -// OMP 5.0 2.19.4.5 lastprivate-clause -> -// LASTPRIVATE ([lastprivate-modifier :] list) -// lastprivate-modifier -> CONDITIONAL -struct OmpLastprivateClause { - TUPLE_CLASS_BOILERPLATE(OmpLastprivateClause); - ENUM_CLASS(LastprivateModifier, Conditional); - std::tuple, OmpObjectList> t; +// OMP 5.2 12.6.2 num_tasks-clause -> num_tasks ([prescriptiveness :] value) +struct OmpNumTasksClause { + TUPLE_CLASS_BOILERPLATE(OmpNumTasksClause); + ENUM_CLASS(Prescriptiveness, Strict); + std::tuple, ScalarIntExpr> t; }; // OpenMP Clauses @@ -3731,6 +3770,8 @@ struct OmpClauseList { CharBlock source; }; +// --- Directives and constructs + // 2.7.2 SECTIONS // 2.11.2 PARALLEL SECTIONS struct OmpSectionsDirective { diff --git a/flang/include/flang/Runtime/CUDA/common.h b/flang/include/flang/Runtime/CUDA/common.h index b73bc390ea8c9e66a9122057cd9264548da2dc8e..e9f61932230e952166d31ee737c23868b188e04a 100644 --- a/flang/include/flang/Runtime/CUDA/common.h +++ b/flang/include/flang/Runtime/CUDA/common.h @@ -30,7 +30,7 @@ static constexpr unsigned kDeviceToDevice = 2; const char *name = cudaGetErrorName(err); \ if (!name) \ name = ""; \ - Terminator terminator{__FILE__, __LINE__}; \ + Fortran::runtime::Terminator terminator{__FILE__, __LINE__}; \ terminator.Crash("'%s' failed with '%s'", #expr, name); \ }(expr) diff --git a/flang/include/flang/Runtime/CUDA/kernel.h b/flang/include/flang/Runtime/CUDA/kernel.h new file mode 100644 index 0000000000000000000000000000000000000000..cf07d874a082c0b3916dbeff4bb4bdad84e7b1c6 --- /dev/null +++ b/flang/include/flang/Runtime/CUDA/kernel.h @@ -0,0 +1,27 @@ +//===-- include/flang/Runtime/CUDA/kernel.h ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_RUNTIME_CUDA_KERNEL_H_ +#define FORTRAN_RUNTIME_CUDA_KERNEL_H_ + +#include "flang/Runtime/entry-names.h" +#include +#include + +extern "C" { + +// This function uses intptr_t instead of CUDA's unsigned int to match +// the type of MLIR's index type. This avoids the need for casts in the +// generated MLIR code. +void RTDEF(CUFLaunchKernel)(const void *kernelName, intptr_t gridX, + intptr_t gridY, intptr_t gridZ, intptr_t blockX, intptr_t blockY, + intptr_t blockZ, int32_t smem, void **params, void **extra); + +} // extern "C" + +#endif // FORTRAN_RUNTIME_CUDA_KERNEL_H_ diff --git a/flang/include/flang/Runtime/CUDA/registration.h b/flang/include/flang/Runtime/CUDA/registration.h index cbe202c4d23e0d8c589bf4aaf1965f9c3c768731..5237069a4c739c5e159c2606751a516fb2e71584 100644 --- a/flang/include/flang/Runtime/CUDA/registration.h +++ b/flang/include/flang/Runtime/CUDA/registration.h @@ -11,6 +11,7 @@ #include "flang/Runtime/entry-names.h" #include +#include namespace Fortran::runtime::cuda { @@ -20,7 +21,12 @@ extern "C" { void *RTDECL(CUFRegisterModule)(void *data); /// Register a device function. -void RTDECL(CUFRegisterFunction)(void **module, const char *fct); +void RTDECL(CUFRegisterFunction)( + void **module, const char *fctSym, char *fctName); + +/// Register a device variable. +void RTDECL(CUFRegisterVariable)( + void **module, char *varSym, const char *varName, int64_t size); } // extern "C" diff --git a/flang/include/flang/Semantics/openmp-directive-sets.h b/flang/include/flang/Semantics/openmp-directive-sets.h index 8eb736bb098fe4e7963a8f8c648956438130050e..50d6d5b59ef7dd9a890c5fea6d33999f097414de 100644 --- a/flang/include/flang/Semantics/openmp-directive-sets.h +++ b/flang/include/flang/Semantics/openmp-directive-sets.h @@ -211,6 +211,7 @@ static const OmpDirectiveSet blockConstructSet{ Directive::OMPD_parallel, Directive::OMPD_parallel_masked, Directive::OMPD_parallel_workshare, + Directive::OMPD_scope, Directive::OMPD_single, Directive::OMPD_target, Directive::OMPD_target_data, @@ -281,6 +282,7 @@ static const OmpDirectiveSet workShareSet{ Directive::OMPD_workshare, Directive::OMPD_parallel_workshare, Directive::OMPD_parallel_sections, + Directive::OMPD_scope, Directive::OMPD_sections, Directive::OMPD_single, } | allDoSet, diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h index cf0350735b5b94c17494bb2a4836da2204db6d7f..0767d8ea84bc6ba79c04aea199304c52ee7805d3 100644 --- a/flang/include/flang/Semantics/symbol.h +++ b/flang/include/flang/Semantics/symbol.h @@ -778,7 +778,7 @@ public: void set_offset(std::size_t offset) { offset_ = offset; } // Give the symbol a name with a different source location but same chars. void ReplaceName(const SourceName &); - std::string OmpFlagToClauseName(Flag ompFlag); + static std::string OmpFlagToClauseName(Flag ompFlag); // Does symbol have this type of details? template bool has() const { diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index fbc031f3a93d7d75bfb4da958e1189e3644b7b2e..7c254ce673855ac7dfcd3ede39f358d75340cc3c 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp @@ -795,35 +795,43 @@ bool ClauseProcessor::processCopyprivate( bool ClauseProcessor::processDepend(mlir::omp::DependClauseOps &result) const { fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); - return findRepeatableClause( - [&](const omp::clause::Depend &clause, const parser::CharBlock &) { - using Depend = omp::clause::Depend; - assert(std::holds_alternative(clause.u) && - "Only the modern form is handled at the moment"); - auto &modern = std::get(clause.u); - auto kind = std::get(modern.t); - auto &objects = std::get(modern.t); - - mlir::omp::ClauseTaskDependAttr dependTypeOperand = - genDependKindAttr(firOpBuilder, kind); - result.dependKinds.append(objects.size(), dependTypeOperand); - - for (const omp::Object &object : objects) { - assert(object.ref() && "Expecting designator"); - - if (evaluate::ExtractSubstring(*object.ref())) { - TODO(converter.getCurrentLocation(), - "substring not supported for task depend"); - } else if (evaluate::IsArrayElement(*object.ref())) { - TODO(converter.getCurrentLocation(), - "array sections not supported for task depend"); - } + auto process = [&](const omp::clause::Depend &clause, + const parser::CharBlock &) { + using Depend = omp::clause::Depend; + if (!std::holds_alternative(clause.u)) { + TODO(converter.getCurrentLocation(), + "DEPEND clause with SINK or SOURCE is not supported yet"); + } + auto &depType = std::get(clause.u); + auto kind = std::get(depType.t); + auto &objects = std::get(depType.t); - semantics::Symbol *sym = object.sym(); - const mlir::Value variable = converter.getSymbolAddress(*sym); - result.dependVars.push_back(variable); - } - }); + if (std::get>(depType.t)) { + TODO(converter.getCurrentLocation(), + "Support for iterator modifiers is not implemented yet"); + } + mlir::omp::ClauseTaskDependAttr dependTypeOperand = + genDependKindAttr(firOpBuilder, kind); + result.dependKinds.append(objects.size(), dependTypeOperand); + + for (const omp::Object &object : objects) { + assert(object.ref() && "Expecting designator"); + + if (evaluate::ExtractSubstring(*object.ref())) { + TODO(converter.getCurrentLocation(), + "substring not supported for task depend"); + } else if (evaluate::IsArrayElement(*object.ref())) { + TODO(converter.getCurrentLocation(), + "array sections not supported for task depend"); + } + + semantics::Symbol *sym = object.sym(); + const mlir::Value variable = converter.getSymbolAddress(*sym); + result.dependVars.push_back(variable); + } + }; + + return findRepeatableClause(process); } bool ClauseProcessor::processHasDeviceAddr( diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp index 3a2ae370b46b2568846c042e8c27a7d24eaf83fd..38d7e7ef4abae5c0daaaaa298ea336871efcb878 100644 --- a/flang/lib/Lower/OpenMP/Clauses.cpp +++ b/flang/lib/Lower/OpenMP/Clauses.cpp @@ -358,8 +358,15 @@ Absent make(const parser::OmpClause::Absent &inp, Affinity make(const parser::OmpClause::Affinity &inp, semantics::SemanticsContext &semaCtx) { - // inp -> empty - llvm_unreachable("Empty: affinity"); + // inp.v -> parser::OmpAffinityClause + auto &t0 = std::get>(inp.v.t); + auto &t1 = std::get(inp.v.t); + + auto &&maybeIter = + maybeApply([&](auto &&s) { return makeIterator(s, semaCtx); }, t0); + + return Affinity{{/*Iterator=*/std::move(maybeIter), + /*LocatorList=*/makeObjects(t1, semaCtx)}}; } Align make(const parser::OmpClause::Align &inp, @@ -554,7 +561,7 @@ Depend make(const parser::OmpClause::Depend &inp, using Iteration = Doacross::Vector::value_type; // LoopIterationT CLAUSET_ENUM_CONVERT( // - convert1, parser::OmpDependenceType::Type, Depend::TaskDependenceType, + convert1, parser::OmpTaskDependenceType::Type, Depend::TaskDependenceType, // clang-format off MS(In, In) MS(Out, Out) @@ -592,17 +599,18 @@ Depend make(const parser::OmpClause::Depend &inp, return Doacross{{/*DependenceType=*/Doacross::DependenceType::Sink, /*Vector=*/makeList(s.v, convert2)}}; }, - // Depend::WithLocators + // Depend::DepType [&](const wrapped::InOut &s) -> Variant { - auto &t0 = std::get(s.t); - auto &t1 = std::get>(s.t); - auto convert4 = [&](const parser::Designator &t) { - return makeObject(t, semaCtx); - }; - return Depend::WithLocators{ - {/*TaskDependenceType=*/convert1(t0.v), - /*Iterator=*/std::nullopt, - /*LocatorList=*/makeList(t1, convert4)}}; + auto &t0 = + std::get>(s.t); + auto &t1 = std::get(s.t); + auto &t2 = std::get(s.t); + + auto &&maybeIter = maybeApply( + [&](auto &&s) { return makeIterator(s, semaCtx); }, t0); + return Depend::DepType{{/*TaskDependenceType=*/convert1(t1.v), + /*Iterator=*/std::move(maybeIter), + /*LocatorList=*/makeObjects(t2, semaCtx)}}; }, }, inp.v.u)}; @@ -720,10 +728,20 @@ From make(const parser::OmpClause::From &inp, // Full: empty Grainsize make(const parser::OmpClause::Grainsize &inp, - semantics::SemanticsContext &semaCtx) { - // inp.v -> parser::ScalarIntExpr - return Grainsize{{/*Prescriptiveness=*/std::nullopt, - /*GrainSize=*/makeExpr(inp.v, semaCtx)}}; + semantics::SemanticsContext &semaCtx) { + // inp.v -> parser::OmpGrainsizeClause + using wrapped = parser::OmpGrainsizeClause; + + CLAUSET_ENUM_CONVERT( // + convert, parser::OmpGrainsizeClause::Prescriptiveness, Grainsize::Prescriptiveness, + // clang-format off + MS(Strict, Strict) + // clang-format on + ); + auto &t0 = std::get>(inp.v.t); + auto &t1 = std::get(inp.v.t); + return Grainsize{{/*Prescriptiveness=*/maybeApply(convert, t0), + /*Grainsize=*/makeExpr(t1, semaCtx)}}; } HasDeviceAddr make(const parser::OmpClause::HasDeviceAddr &inp, @@ -970,9 +988,20 @@ Novariants make(const parser::OmpClause::Novariants &inp, NumTasks make(const parser::OmpClause::NumTasks &inp, semantics::SemanticsContext &semaCtx) { - // inp.v -> parser::ScalarIntExpr - return NumTasks{{/*Prescriptiveness=*/std::nullopt, - /*NumTasks=*/makeExpr(inp.v, semaCtx)}}; + // inp.v -> parser::OmpNumTasksClause + using wrapped = parser::OmpNumTasksClause; + + CLAUSET_ENUM_CONVERT( // + convert, parser::OmpNumTasksClause::Prescriptiveness, + NumTasks::Prescriptiveness, + // clang-format off + MS(Strict, Strict) + // clang-format on + ); + auto &t0 = std::get>(inp.v.t); + auto &t1 = std::get(inp.v.t); + return NumTasks{{/*Prescriptiveness=*/maybeApply(convert, t0), + /*NumTasks=*/makeExpr(t1, semaCtx)}}; } NumTeams make(const parser::OmpClause::NumTeams &inp, diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index 52a077cd5a797a3c9e31b6db348f1f42d69248c5..01a40d6e2204ef2ff0ac0b4634281b03a75f26a0 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -1650,6 +1650,15 @@ genSectionsOp(lower::AbstractConverter &converter, lower::SymMap &symTable, return sectionsOp; } +static void genScopeOp(lower::AbstractConverter &converter, + lower::SymMap &symTable, + semantics::SemanticsContext &semaCtx, + lower::pft::Evaluation &eval, mlir::Location loc, + const ConstructQueue &queue, + ConstructQueue::const_iterator item) { + TODO(loc, "Scope construct"); +} + static mlir::omp::SingleOp genSingleOp(lower::AbstractConverter &converter, lower::SymMap &symTable, semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval, @@ -2478,6 +2487,9 @@ static void genOMPDispatch(lower::AbstractConverter &converter, case llvm::omp::Directive::OMPD_simd: genStandaloneSimd(converter, symTable, semaCtx, eval, loc, queue, item); break; + case llvm::omp::Directive::OMPD_scope: + genScopeOp(converter, symTable, semaCtx, eval, loc, queue, item); + break; case llvm::omp::Directive::OMPD_single: genSingleOp(converter, symTable, semaCtx, eval, loc, queue, item); break; @@ -2769,7 +2781,8 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, for (const Clause &clause : clauses) { mlir::Location clauseLocation = converter.genLocation(clause.source); - if (!std::holds_alternative(clause.u) && + if (!std::holds_alternative(clause.u) && + !std::holds_alternative(clause.u) && !std::holds_alternative(clause.u) && !std::holds_alternative(clause.u) && !std::holds_alternative(clause.u) && diff --git a/flang/lib/Optimizer/Dialect/CUF/CUFToLLVMIRTranslation.cpp b/flang/lib/Optimizer/Dialect/CUF/CUFToLLVMIRTranslation.cpp index c6c9f96b81135296710b9be20ce6059edf0d6233..63eac46a997718176ac33647765adad2f1b0dd9d 100644 --- a/flang/lib/Optimizer/Dialect/CUF/CUFToLLVMIRTranslation.cpp +++ b/flang/lib/Optimizer/Dialect/CUF/CUFToLLVMIRTranslation.cpp @@ -63,13 +63,15 @@ LogicalResult registerKernel(cuf::RegisterKernelOp op, llvm::Type *ptrTy = builder.getPtrTy(0); llvm::FunctionCallee fct = module->getOrInsertFunction( RTNAME_STRING(CUFRegisterFunction), - llvm::FunctionType::get(ptrTy, ArrayRef({ptrTy, ptrTy}), - false)); + llvm::FunctionType::get( + ptrTy, ArrayRef({ptrTy, ptrTy, ptrTy}), false)); llvm::Value *modulePtr = moduleTranslation.lookupValue(op.getModulePtr()); - builder.CreateCall( - fct, {modulePtr, getOrCreateFunctionName(module, builder, - op.getKernelModuleName().str(), - op.getKernelName().str())}); + llvm::Function *fctSym = + moduleTranslation.lookupFunction(op.getKernelName().str()); + builder.CreateCall(fct, {modulePtr, fctSym, + getOrCreateFunctionName( + module, builder, op.getKernelModuleName().str(), + op.getKernelName().str())}); return mlir::success(); } diff --git a/flang/lib/Optimizer/Transforms/CMakeLists.txt b/flang/lib/Optimizer/Transforms/CMakeLists.txt index 8f4f731e009221e124892770ba08ac7d40b2669f..9eafa4ec234bddf6661bd97d6a8f73b2493cb4b7 100644 --- a/flang/lib/Optimizer/Transforms/CMakeLists.txt +++ b/flang/lib/Optimizer/Transforms/CMakeLists.txt @@ -9,9 +9,11 @@ add_flang_library(FIRTransforms CompilerGeneratedNames.cpp ConstantArgumentGlobalisation.cpp ControlFlowConverter.cpp + CUFCommon.cpp CUFAddConstructor.cpp CUFDeviceGlobal.cpp CUFOpConversion.cpp + CUFGPUToLLVMConversion.cpp ArrayValueCopy.cpp ExternalNameConversion.cpp MemoryUtils.cpp diff --git a/flang/lib/Optimizer/Transforms/CUFAddConstructor.cpp b/flang/lib/Optimizer/Transforms/CUFAddConstructor.cpp index f260437e7104171da0c0b1c38e2fce637cfb05ea..4da06be8ef7dd95e159988d6e00454fca3547361 100644 --- a/flang/lib/Optimizer/Transforms/CUFAddConstructor.cpp +++ b/flang/lib/Optimizer/Transforms/CUFAddConstructor.cpp @@ -11,6 +11,7 @@ #include "flang/Optimizer/Dialect/FIRAttr.h" #include "flang/Optimizer/Dialect/FIRDialect.h" #include "flang/Optimizer/Dialect/FIROpsSupport.h" +#include "flang/Optimizer/Transforms/CUFCommon.h" #include "flang/Runtime/entry-names.h" #include "mlir/Dialect/GPU/IR/GPUDialect.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" @@ -24,8 +25,6 @@ namespace fir { namespace { -static constexpr llvm::StringRef cudaModName{"cuda_device_mod"}; - static constexpr llvm::StringRef cudaFortranCtorName{ "__cudaFortranConstructor"}; @@ -60,7 +59,7 @@ struct CUFAddConstructor builder.create(loc, funcTy, cufRegisterAllocatorRef); // Register kernels - auto gpuMod = symTab.lookup(cudaModName); + auto gpuMod = symTab.lookup(cudaDeviceModuleName); if (gpuMod) { auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(ctx); auto registeredMod = builder.create( @@ -68,7 +67,7 @@ struct CUFAddConstructor for (auto func : gpuMod.getOps()) { if (func.isKernel()) { auto kernelName = mlir::SymbolRefAttr::get( - builder.getStringAttr(cudaModName), + builder.getStringAttr(cudaDeviceModuleName), {mlir::SymbolRefAttr::get(builder.getContext(), func.getName())}); builder.create(loc, kernelName, registeredMod); } diff --git a/flang/lib/Optimizer/Transforms/CUFCommon.cpp b/flang/lib/Optimizer/Transforms/CUFCommon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5eca86529f9e17c3c2736ea556b1d58191ae85f2 --- /dev/null +++ b/flang/lib/Optimizer/Transforms/CUFCommon.cpp @@ -0,0 +1,31 @@ +//===-- CUFCommon.cpp - Shared functions between passes ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/Transforms/CUFCommon.h" +#include "mlir/Dialect/LLVMIR/NVVMDialect.h" + +/// Retrieve or create the CUDA Fortran GPU module in the give in \p mod. +mlir::gpu::GPUModuleOp cuf::getOrCreateGPUModule(mlir::ModuleOp mod, + mlir::SymbolTable &symTab) { + if (auto gpuMod = symTab.lookup(cudaDeviceModuleName)) + return gpuMod; + + auto *ctx = mod.getContext(); + mod->setAttr(mlir::gpu::GPUDialect::getContainerModuleAttrName(), + mlir::UnitAttr::get(ctx)); + + mlir::OpBuilder builder(ctx); + auto gpuMod = builder.create(mod.getLoc(), + cudaDeviceModuleName); + llvm::SmallVector targets; + targets.push_back(mlir::NVVM::NVVMTargetAttr::get(ctx)); + gpuMod.setTargetsAttr(builder.getArrayAttr(targets)); + mlir::Block::iterator insertPt(mod.getBodyRegion().front().end()); + symTab.insert(gpuMod, insertPt); + return gpuMod; +} diff --git a/flang/lib/Optimizer/Transforms/CUFDeviceGlobal.cpp b/flang/lib/Optimizer/Transforms/CUFDeviceGlobal.cpp index a4761f24f16d7be9d465f088afc06aea0082cb6c..dc39be8574f844857ad58e00aefee78ff3063921 100644 --- a/flang/lib/Optimizer/Transforms/CUFDeviceGlobal.cpp +++ b/flang/lib/Optimizer/Transforms/CUFDeviceGlobal.cpp @@ -11,6 +11,7 @@ #include "flang/Optimizer/Dialect/FIRDialect.h" #include "flang/Optimizer/Dialect/FIROps.h" #include "flang/Optimizer/HLFIR/HLFIROps.h" +#include "flang/Optimizer/Transforms/CUFCommon.h" #include "flang/Runtime/CUDA/common.h" #include "flang/Runtime/allocatable.h" #include "mlir/IR/SymbolTable.h" @@ -58,6 +59,32 @@ public: prepareImplicitDeviceGlobals(funcOp, symTable); return mlir::WalkResult::advance(); }); + + // Copying the device global variable into the gpu module + mlir::SymbolTable parentSymTable(mod); + auto gpuMod = + parentSymTable.lookup(cudaDeviceModuleName); + if (gpuMod) { + mlir::SymbolTable gpuSymTable(gpuMod); + for (auto globalOp : mod.getOps()) { + auto attr = globalOp.getDataAttrAttr(); + if (!attr) + continue; + switch (attr.getValue()) { + case cuf::DataAttribute::Device: + case cuf::DataAttribute::Constant: + case cuf::DataAttribute::Managed: { + auto globalName{globalOp.getSymbol().getValue()}; + if (gpuSymTable.lookup(globalName)) { + break; + } + gpuSymTable.insert(globalOp->clone()); + } break; + default: + break; + } + } + } } }; } // namespace diff --git a/flang/lib/Optimizer/Transforms/CUFGPUToLLVMConversion.cpp b/flang/lib/Optimizer/Transforms/CUFGPUToLLVMConversion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5645ce6e6858c826f77ed6d5544da3c4d798a883 --- /dev/null +++ b/flang/lib/Optimizer/Transforms/CUFGPUToLLVMConversion.cpp @@ -0,0 +1,180 @@ +//===-- CUFGPUToLLVMConversion.cpp ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/Transforms/CUFGPUToLLVMConversion.h" +#include "flang/Common/Fortran.h" +#include "flang/Optimizer/CodeGen/TypeConverter.h" +#include "flang/Optimizer/Support/DataLayout.h" +#include "flang/Runtime/CUDA/common.h" +#include "mlir/Conversion/LLVMCommon/Pattern.h" +#include "mlir/Dialect/GPU/IR/GPUDialect.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Transforms/DialectConversion.h" +#include "mlir/Transforms/GreedyPatternRewriteDriver.h" +#include "llvm/Support/FormatVariadic.h" + +namespace fir { +#define GEN_PASS_DEF_CUFGPUTOLLVMCONVERSION +#include "flang/Optimizer/Transforms/Passes.h.inc" +} // namespace fir + +using namespace fir; +using namespace mlir; +using namespace Fortran::runtime; + +namespace { + +static mlir::Value createKernelArgArray(mlir::Location loc, + mlir::ValueRange operands, + mlir::PatternRewriter &rewriter) { + + auto *ctx = rewriter.getContext(); + llvm::SmallVector structTypes(operands.size(), nullptr); + + for (auto [i, arg] : llvm::enumerate(operands)) + structTypes[i] = arg.getType(); + + auto structTy = mlir::LLVM::LLVMStructType::getLiteral(ctx, structTypes); + auto ptrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext()); + mlir::Type i32Ty = rewriter.getI32Type(); + auto one = rewriter.create( + loc, i32Ty, rewriter.getIntegerAttr(i32Ty, 1)); + mlir::Value argStruct = + rewriter.create(loc, ptrTy, structTy, one); + auto size = rewriter.create( + loc, i32Ty, rewriter.getIntegerAttr(i32Ty, structTypes.size())); + mlir::Value argArray = + rewriter.create(loc, ptrTy, ptrTy, size); + + for (auto [i, arg] : llvm::enumerate(operands)) { + auto indice = rewriter.create( + loc, i32Ty, rewriter.getIntegerAttr(i32Ty, i)); + mlir::Value structMember = rewriter.create( + loc, ptrTy, structTy, argStruct, mlir::ArrayRef({indice})); + rewriter.create(loc, arg, structMember); + mlir::Value arrayMember = rewriter.create( + loc, ptrTy, structTy, argArray, mlir::ArrayRef({indice})); + rewriter.create(loc, structMember, arrayMember); + } + return argArray; +} + +struct GPULaunchKernelConversion + : public mlir::ConvertOpToLLVMPattern { + explicit GPULaunchKernelConversion( + const fir::LLVMTypeConverter &typeConverter, mlir::PatternBenefit benefit) + : mlir::ConvertOpToLLVMPattern(typeConverter, + benefit) {} + + using OpAdaptor = typename mlir::gpu::LaunchFuncOp::Adaptor; + + mlir::LogicalResult + matchAndRewrite(mlir::gpu::LaunchFuncOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + + if (op.hasClusterSize()) { + return mlir::failure(); + } + + mlir::Location loc = op.getLoc(); + auto *ctx = rewriter.getContext(); + mlir::ModuleOp mod = op->getParentOfType(); + mlir::Value dynamicMemorySize = op.getDynamicSharedMemorySize(); + mlir::Type i32Ty = rewriter.getI32Type(); + if (!dynamicMemorySize) + dynamicMemorySize = rewriter.create( + loc, i32Ty, rewriter.getIntegerAttr(i32Ty, 0)); + + mlir::Value kernelArgs = + createKernelArgArray(loc, adaptor.getKernelOperands(), rewriter); + + auto ptrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext()); + auto kernel = mod.lookupSymbol(op.getKernelName()); + mlir::Value kernelPtr; + if (!kernel) { + auto funcOp = mod.lookupSymbol(op.getKernelName()); + if (!funcOp) + return mlir::failure(); + kernelPtr = + rewriter.create(loc, ptrTy, funcOp.getName()); + } else { + kernelPtr = + rewriter.create(loc, ptrTy, kernel.getName()); + } + + auto funcOp = mod.lookupSymbol( + RTNAME_STRING(CUFLaunchKernel)); + + auto llvmIntPtrType = mlir::IntegerType::get( + ctx, this->getTypeConverter()->getPointerBitwidth(0)); + auto voidTy = mlir::LLVM::LLVMVoidType::get(ctx); + auto funcTy = mlir::LLVM::LLVMFunctionType::get( + voidTy, + {ptrTy, llvmIntPtrType, llvmIntPtrType, llvmIntPtrType, llvmIntPtrType, + llvmIntPtrType, llvmIntPtrType, i32Ty, ptrTy, ptrTy}, + /*isVarArg=*/false); + + auto cufLaunchKernel = mlir::SymbolRefAttr::get( + mod.getContext(), RTNAME_STRING(CUFLaunchKernel)); + if (!funcOp) { + mlir::OpBuilder::InsertionGuard insertGuard(rewriter); + rewriter.setInsertionPointToStart(mod.getBody()); + auto launchKernelFuncOp = rewriter.create( + loc, RTNAME_STRING(CUFLaunchKernel), funcTy); + launchKernelFuncOp.setVisibility(mlir::SymbolTable::Visibility::Private); + } + + mlir::Value nullPtr = rewriter.create(loc, ptrTy); + + rewriter.replaceOpWithNewOp( + op, funcTy, cufLaunchKernel, + mlir::ValueRange{kernelPtr, adaptor.getGridSizeX(), + adaptor.getGridSizeY(), adaptor.getGridSizeZ(), + adaptor.getBlockSizeX(), adaptor.getBlockSizeY(), + adaptor.getBlockSizeZ(), dynamicMemorySize, kernelArgs, + nullPtr}); + + return mlir::success(); + } +}; + +class CUFGPUToLLVMConversion + : public fir::impl::CUFGPUToLLVMConversionBase { +public: + void runOnOperation() override { + auto *ctx = &getContext(); + mlir::RewritePatternSet patterns(ctx); + mlir::ConversionTarget target(*ctx); + + mlir::Operation *op = getOperation(); + mlir::ModuleOp module = mlir::dyn_cast(op); + if (!module) + return signalPassFailure(); + + std::optional dl = + fir::support::getOrSetDataLayout(module, /*allowDefaultLayout=*/false); + fir::LLVMTypeConverter typeConverter(module, /*applyTBAA=*/false, + /*forceUnifiedTBAATree=*/false, *dl); + cuf::populateCUFGPUToLLVMConversionPatterns(typeConverter, patterns); + target.addIllegalOp(); + target.addLegalDialect(); + if (mlir::failed(mlir::applyPartialConversion(getOperation(), target, + std::move(patterns)))) { + mlir::emitError(mlir::UnknownLoc::get(ctx), + "error in CUF GPU op conversion\n"); + signalPassFailure(); + } + } +}; +} // namespace + +void cuf::populateCUFGPUToLLVMConversionPatterns( + const fir::LLVMTypeConverter &converter, mlir::RewritePatternSet &patterns, + mlir::PatternBenefit benefit) { + patterns.add(converter, benefit); +} diff --git a/flang/lib/Optimizer/Transforms/CUFOpConversion.cpp b/flang/lib/Optimizer/Transforms/CUFOpConversion.cpp index 069d88e0afca47d4030e9a3695bfc138ed1303f5..9c2b882c7f46fef0274f90aab99f68c6cc01620c 100644 --- a/flang/lib/Optimizer/Transforms/CUFOpConversion.cpp +++ b/flang/lib/Optimizer/Transforms/CUFOpConversion.cpp @@ -20,6 +20,7 @@ #include "flang/Runtime/CUDA/descriptor.h" #include "flang/Runtime/CUDA/memory.h" #include "flang/Runtime/allocatable.h" +#include "mlir/Conversion/LLVMCommon/Pattern.h" #include "mlir/Dialect/GPU/IR/GPUDialect.h" #include "mlir/Pass/Pass.h" #include "mlir/Transforms/DialectConversion.h" diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp index 71e534b4f2e2a39f4031c7c0b0bd1b4cbdb8f968..8e516734a9087904778ce4b92304746ffd8551e3 100644 --- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp +++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp @@ -15,6 +15,7 @@ #include "DebugTypeGenerator.h" #include "flang/Optimizer/CodeGen/DescriptorModel.h" #include "flang/Optimizer/Support/InternalNames.h" +#include "flang/Optimizer/Support/Utils.h" #include "mlir/Pass/Pass.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/BinaryFormat/Dwarf.h" @@ -298,6 +299,8 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType( fir::TypeInfoOp tiOp = symbolTable->lookup(Ty.getName()); unsigned line = (tiOp) ? getLineFromLoc(tiOp.getLoc()) : 1; + mlir::OpBuilder builder(context); + mlir::IntegerType intTy = mlir::IntegerType::get(context, 64); std::uint64_t offset = 0; for (auto [fieldName, fieldTy] : Ty.getTypeList()) { mlir::Type llvmTy; @@ -307,11 +310,38 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType( else llvmTy = llvmTypeConverter.convertType(fieldTy); - // FIXME: Handle non defaults array bound in derived types uint64_t byteSize = dataLayout->getTypeSize(llvmTy); unsigned short byteAlign = dataLayout->getTypeABIAlignment(llvmTy); - mlir::LLVM::DITypeAttr elemTy = - convertType(fieldTy, fileAttr, scope, /*declOp=*/nullptr); + std::optional> lowerBounds = + fir::getComponentLowerBoundsIfNonDefault(Ty, fieldName, module, + symbolTable); + auto seqTy = mlir::dyn_cast_or_null(fieldTy); + + // For members of the derived types, the information about the shift in + // lower bounds is not part of the declOp but has to be extracted from the + // TypeInfoOp (using getComponentLowerBoundsIfNonDefault). + mlir::LLVM::DITypeAttr elemTy; + if (lowerBounds && seqTy && + lowerBounds->size() == seqTy.getShape().size()) { + llvm::SmallVector elements; + for (auto [bound, dim] : + llvm::zip_equal(*lowerBounds, seqTy.getShape())) { + auto countAttr = mlir::IntegerAttr::get(intTy, llvm::APInt(64, dim)); + auto lowerAttr = mlir::IntegerAttr::get(intTy, llvm::APInt(64, bound)); + auto subrangeTy = mlir::LLVM::DISubrangeAttr::get( + context, countAttr, lowerAttr, /*upperBound=*/nullptr, + /*stride=*/nullptr); + elements.push_back(subrangeTy); + } + elemTy = mlir::LLVM::DICompositeTypeAttr::get( + context, llvm::dwarf::DW_TAG_array_type, /*name=*/nullptr, + /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, + convertType(seqTy.getEleTy(), fileAttr, scope, declOp), + mlir::LLVM::DIFlags::Zero, /*sizeInBits=*/0, /*alignInBits=*/0, + elements, /*dataLocation=*/nullptr, /*rank=*/nullptr, + /*allocated=*/nullptr, /*associated=*/nullptr); + } else + elemTy = convertType(fieldTy, fileAttr, scope, /*declOp=*/nullptr); offset = llvm::alignTo(offset, byteAlign); mlir::LLVM::DIDerivedTypeAttr tyAttr = mlir::LLVM::DIDerivedTypeAttr::get( context, llvm::dwarf::DW_TAG_member, @@ -401,6 +431,39 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertSequenceType( /*associated=*/nullptr); } +mlir::LLVM::DITypeAttr DebugTypeGenerator::convertVectorType( + fir::VectorType vecTy, mlir::LLVM::DIFileAttr fileAttr, + mlir::LLVM::DIScopeAttr scope, fir::cg::XDeclareOp declOp) { + mlir::MLIRContext *context = module.getContext(); + + llvm::SmallVector elements; + mlir::LLVM::DITypeAttr elemTy = + convertType(vecTy.getEleTy(), fileAttr, scope, declOp); + auto intTy = mlir::IntegerType::get(context, 64); + auto countAttr = + mlir::IntegerAttr::get(intTy, llvm::APInt(64, vecTy.getLen())); + auto subrangeTy = mlir::LLVM::DISubrangeAttr::get( + context, countAttr, /*lowerBound=*/nullptr, /*upperBound=*/nullptr, + /*stride=*/nullptr); + elements.push_back(subrangeTy); + mlir::Type llvmTy = llvmTypeConverter.convertType(vecTy.getEleTy()); + uint64_t sizeInBits = dataLayout->getTypeSize(llvmTy) * vecTy.getLen() * 8; + std::string name("vector"); + // The element type of the vector must be integer or real so it will be a + // DIBasicTypeAttr. + if (auto ty = mlir::dyn_cast_if_present(elemTy)) + name += " " + ty.getName().str(); + + name += " (" + std::to_string(vecTy.getLen()) + ")"; + return mlir::LLVM::DICompositeTypeAttr::get( + context, llvm::dwarf::DW_TAG_array_type, + mlir::StringAttr::get(context, name), + /*file=*/nullptr, /*line=*/0, /*scope=*/nullptr, elemTy, + mlir::LLVM::DIFlags::Vector, sizeInBits, /*alignInBits=*/0, elements, + /*dataLocation=*/nullptr, /*rank=*/nullptr, /*allocated=*/nullptr, + /*associated=*/nullptr); +} + mlir::LLVM::DITypeAttr DebugTypeGenerator::convertCharacterType( fir::CharacterType charTy, mlir::LLVM::DIFileAttr fileAttr, mlir::LLVM::DIScopeAttr scope, fir::cg::XDeclareOp declOp, @@ -511,6 +574,17 @@ DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr, /*hasDescriptor=*/false); } else if (auto recTy = mlir::dyn_cast_or_null(Ty)) { return convertRecordType(recTy, fileAttr, scope, declOp); + } else if (auto refTy = mlir::dyn_cast_if_present(Ty)) { + auto elTy = refTy.getEleTy(); + return convertPointerLikeType(elTy, fileAttr, scope, declOp, + /*genAllocated=*/false, + /*genAssociated=*/false); + } else if (auto vecTy = mlir::dyn_cast_or_null(Ty)) { + return convertVectorType(vecTy, fileAttr, scope, declOp); + } else if (mlir::isa(Ty)) { + return genBasicType(context, mlir::StringAttr::get(context, "integer"), + llvmTypeConverter.getIndexTypeBitwidth(), + llvm::dwarf::DW_ATE_signed); } else if (auto boxTy = mlir::dyn_cast_or_null(Ty)) { auto elTy = boxTy.getElementType(); if (auto seqTy = mlir::dyn_cast_or_null(elTy)) diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h index ff600e751eb0b19dfa3eae3b065210b37ab32b8c..eeefb6c463d936603d42c256ad877caae71fea59 100644 --- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h +++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h @@ -43,6 +43,10 @@ private: mlir::LLVM::DIFileAttr fileAttr, mlir::LLVM::DIScopeAttr scope, fir::cg::XDeclareOp declOp); + mlir::LLVM::DITypeAttr convertVectorType(fir::VectorType vecTy, + mlir::LLVM::DIFileAttr fileAttr, + mlir::LLVM::DIScopeAttr scope, + fir::cg::XDeclareOp declOp); /// The 'genAllocated' is true when we want to generate 'allocated' field /// in the DICompositeType. It is needed for the allocatable arrays. diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 4a1daed04f3e9d459d2e1898fc0a2249c14e3004..598439cbee87e644e8a4a2122c50f0e0113c27eb 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -177,6 +177,11 @@ TYPE_PARSER(construct( TYPE_PARSER(construct("ITERATOR" >> parenthesized(nonemptyList(sourced(Parser{}))))) +// [5.0] 2.10.1 affinity([aff-modifier:] locator-list) +// aff-modifier: interator-modifier +TYPE_PARSER(construct( + maybe(Parser{} / ":"), Parser{})) + // 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE) TYPE_PARSER(construct( "PRIVATE" >> pure(OmpDefaultClause::Type::Private) || @@ -360,10 +365,10 @@ TYPE_PARSER(construct( TYPE_PARSER( construct(name, maybe(Parser{}))) -TYPE_PARSER( - construct("IN"_id >> pure(OmpDependenceType::Type::In) || - "INOUT" >> pure(OmpDependenceType::Type::Inout) || - "OUT" >> pure(OmpDependenceType::Type::Out))) +TYPE_PARSER(construct( + "IN"_id >> pure(OmpTaskDependenceType::Type::In) || + "INOUT" >> pure(OmpTaskDependenceType::Type::Inout) || + "OUT" >> pure(OmpTaskDependenceType::Type::Out))) TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US, construct(construct( @@ -371,7 +376,8 @@ TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US, construct( construct("SOURCE"_tok)) || construct(construct( - Parser{}, ":" >> nonemptyList(designator)))) + maybe(Parser{} / ","_tok), + Parser{} / ":", Parser{}))) // 2.15.3.7 LINEAR (linear-list: linear-step) // linear-list -> list | modifier(list) @@ -403,6 +409,16 @@ TYPE_PARSER(construct( maybe(Parser{} / ":"), "CONCURRENT" >> pure(OmpOrderClause::Type::Concurrent))) +// OMP 5.2 12.6.1 grainsize([ prescriptiveness :] scalar-integer-expression) +TYPE_PARSER(construct( + maybe("STRICT" >> pure(OmpGrainsizeClause::Prescriptiveness::Strict) / ":"), + scalarIntExpr)) + +// OMP 5.2 12.6.2 num_tasks([ prescriptiveness :] scalar-integer-expression) +TYPE_PARSER(construct( + maybe("STRICT" >> pure(OmpNumTasksClause::Prescriptiveness::Strict) / ":"), + scalarIntExpr)) + TYPE_PARSER( construct(designator) || construct("/" >> name / "/")) @@ -415,6 +431,8 @@ TYPE_PARSER(construct( TYPE_PARSER( "ACQUIRE" >> construct(construct()) || "ACQ_REL" >> construct(construct()) || + "AFFINITY" >> construct(construct( + parenthesized(Parser{}))) || "ALIGNED" >> construct(construct( parenthesized(Parser{}))) || "ALLOCATE" >> construct(construct( @@ -457,7 +475,7 @@ TYPE_PARSER( "FROM" >> construct(construct( parenthesized(Parser{}))) || "GRAINSIZE" >> construct(construct( - parenthesized(scalarIntExpr))) || + parenthesized(Parser{}))) || "HAS_DEVICE_ADDR" >> construct(construct( parenthesized(Parser{}))) || @@ -484,7 +502,7 @@ TYPE_PARSER( construct(construct()) || "NOWAIT" >> construct(construct()) || "NUM_TASKS" >> construct(construct( - parenthesized(scalarIntExpr))) || + parenthesized(Parser{}))) || "NUM_TEAMS" >> construct(construct( parenthesized(scalarIntExpr))) || "NUM_THREADS" >> construct(construct( @@ -690,6 +708,7 @@ TYPE_PARSER(construct(first( "PARALLEL MASKED" >> pure(llvm::omp::Directive::OMPD_parallel_masked), "PARALLEL WORKSHARE" >> pure(llvm::omp::Directive::OMPD_parallel_workshare), "PARALLEL" >> pure(llvm::omp::Directive::OMPD_parallel), + "SCOPE" >> pure(llvm::omp::Directive::OMPD_scope), "SINGLE" >> pure(llvm::omp::Directive::OMPD_single), "TARGET DATA" >> pure(llvm::omp::Directive::OMPD_target_data), "TARGET PARALLEL" >> pure(llvm::omp::Directive::OMPD_target_parallel), diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 417e0cc805188642b09d18c2aa7a74dc247dfaf4..018dd80d9dfe2d5459c80ad791b407f994bac882 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2150,6 +2150,10 @@ public: Walk(std::get>(x.t), ":"); Walk(std::get(x.t)); } + void Unparse(const OmpAffinityClause &x) { + Walk(std::get>(x.t), ":"); + Walk(std::get(x.t)); + } void Unparse(const OmpAlignedClause &x) { Walk(std::get(x.t)); Put(","); @@ -2213,6 +2217,16 @@ public: Walk(std::get>(x.t), ":"); Walk(std::get(x.t)); } + void Unparse(const OmpGrainsizeClause &x) { + Walk(std::get>(x.t), + ":"); + Walk(std::get(x.t)); + } + void Unparse(const OmpNumTasksClause &x) { + Walk( + std::get>(x.t), ":"); + Walk(std::get(x.t)); + } void Unparse(const OmpDependSinkVecLength &x) { Walk(std::get(x.t)); Walk(std::get(x.t)); @@ -2223,9 +2237,9 @@ public: } void Unparse(const OmpDependClause::InOut &x) { Put("("); - Walk(std::get(x.t)); + Walk(std::get(x.t)); Put(":"); - Walk(std::get>(x.t), ","); + Walk(std::get(x.t)); Put(")"); } bool Pre(const OmpDependClause &x) { @@ -2403,6 +2417,9 @@ public: case llvm::omp::Directive::OMPD_parallel: Word("PARALLEL "); break; + case llvm::omp::Directive::OMPD_scope: + Word("SCOPE "); + break; case llvm::omp::Directive::OMPD_single: Word("SINGLE "); break; @@ -2833,7 +2850,7 @@ public: OmpLastprivateClause, LastprivateModifier) // OMP lastprivate-modifier WALK_NESTED_ENUM(OmpScheduleModifierType, ModType) // OMP schedule-modifier WALK_NESTED_ENUM(OmpLinearModifier, Type) // OMP linear-modifier - WALK_NESTED_ENUM(OmpDependenceType, Type) // OMP dependence-type + WALK_NESTED_ENUM(OmpTaskDependenceType, Type) // OMP task-dependence-type WALK_NESTED_ENUM(OmpScheduleClause, ScheduleType) // OMP schedule-type WALK_NESTED_ENUM(OmpDeviceClause, DeviceModifier) // OMP device modifier WALK_NESTED_ENUM(OmpDeviceTypeClause, Type) // OMP DEVICE_TYPE @@ -2843,6 +2860,9 @@ public: WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type WALK_NESTED_ENUM(OmpOrderClause, Type) // OMP order-type WALK_NESTED_ENUM(OmpOrderModifier, Kind) // OMP order-modifier + WALK_NESTED_ENUM( + OmpGrainsizeClause, Prescriptiveness) // OMP grainsize-modifier + WALK_NESTED_ENUM(OmpNumTasksClause, Prescriptiveness) // OMP numtasks-modifier WALK_NESTED_ENUM(OmpMapClause, Type) // OMP map-type WALK_NESTED_ENUM(OmpMapClause, TypeModifier) // OMP map-type-modifier #undef WALK_NESTED_ENUM diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index e7f2af527f25447e347c7b1b1bb2db78a717a46f..5b73848504a33ba9d40e92f554c02e0c9aa1f52b 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -38,6 +38,16 @@ namespace Fortran::semantics { CheckAllowedClause(llvm::omp::Y); \ } +std::string ThisVersion(unsigned version) { + std::string tv{ + std::to_string(version / 10) + "." + std::to_string(version % 10)}; + return "OpenMP v" + tv; +} + +std::string TryVersion(unsigned version) { + return "try -fopenmp-version=" + std::to_string(version); +} + // 'OmpWorkshareBlockChecker' is used to check the validity of the assignment // statements and the expressions enclosed in an OpenMP Workshare construct class OmpWorkshareBlockChecker { @@ -200,14 +210,10 @@ bool OmpStructureChecker::CheckAllowedClause(llvmOmpClause clause) { auto clauseName{parser::ToUpperCaseLetters(getClauseName(clause).str())}; auto dirName{parser::ToUpperCaseLetters(getDirectiveName(dir).str())}; - std::string thisVersion{ - std::to_string(version / 10) + "." + std::to_string(version % 10)}; - std::string goodVersion{std::to_string(allowedInVersion)}; - context_.Say(dirCtx.clauseSource, - "%s clause is not allowed on directive %s in OpenMP v%s, " - "try -fopenmp-version=%d"_err_en_US, - clauseName, dirName, thisVersion, allowedInVersion); + "%s clause is not allowed on directive %s in %s, %s"_err_en_US, + clauseName, dirName, ThisVersion(version), + TryVersion(allowedInVersion)); } } return CheckAllowed(clause); @@ -972,6 +978,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) { HasInvalidWorksharingNesting( beginDir.source, llvm::omp::nestedWorkshareErrSet); break; + case llvm::omp::Directive::OMPD_scope: case llvm::omp::Directive::OMPD_single: // TODO: This check needs to be extended while implementing nesting of // regions checks. @@ -1864,6 +1871,9 @@ void OmpStructureChecker::Enter(const parser::OmpEndBlockDirective &x) { const auto &dir{std::get(x.t)}; ResetPartialContext(dir.source); switch (dir.v) { + case llvm::omp::Directive::OMPD_scope: + PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_end_scope); + break; // 2.7.3 end-single-clause -> copyprivate-clause | // nowait-clause case llvm::omp::Directive::OMPD_single: @@ -1886,7 +1896,8 @@ void OmpStructureChecker::Enter(const parser::OmpEndBlockDirective &x) { // end_workshareare popped as they are pushed while entering the // EndBlockDirective. void OmpStructureChecker::Leave(const parser::OmpEndBlockDirective &x) { - if ((GetContext().directive == llvm::omp::Directive::OMPD_end_single) || + if ((GetContext().directive == llvm::omp::Directive::OMPD_end_scope) || + (GetContext().directive == llvm::omp::Directive::OMPD_end_single) || (GetContext().directive == llvm::omp::Directive::OMPD_end_workshare)) { dirContext_.pop_back(); } @@ -2474,12 +2485,14 @@ CHECK_SIMPLE_CLAUSE(Final, OMPC_final) CHECK_SIMPLE_CLAUSE(Flush, OMPC_flush) CHECK_SIMPLE_CLAUSE(From, OMPC_from) CHECK_SIMPLE_CLAUSE(Full, OMPC_full) +CHECK_SIMPLE_CLAUSE(Grainsize, OMPC_grainsize) CHECK_SIMPLE_CLAUSE(Hint, OMPC_hint) CHECK_SIMPLE_CLAUSE(Holds, OMPC_holds) CHECK_SIMPLE_CLAUSE(InReduction, OMPC_in_reduction) CHECK_SIMPLE_CLAUSE(Inclusive, OMPC_inclusive) CHECK_SIMPLE_CLAUSE(Match, OMPC_match) CHECK_SIMPLE_CLAUSE(Nontemporal, OMPC_nontemporal) +CHECK_SIMPLE_CLAUSE(NumTasks, OMPC_num_tasks) CHECK_SIMPLE_CLAUSE(Order, OMPC_order) CHECK_SIMPLE_CLAUSE(Read, OMPC_read) CHECK_SIMPLE_CLAUSE(Threadprivate, OMPC_threadprivate) @@ -2530,8 +2543,6 @@ CHECK_SIMPLE_CLAUSE(OmpxBare, OMPC_ompx_bare) CHECK_SIMPLE_CLAUSE(Fail, OMPC_fail) CHECK_SIMPLE_CLAUSE(Weak, OMPC_weak) -CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize) -CHECK_REQ_SCALAR_INT_CLAUSE(NumTasks, OMPC_num_tasks) CHECK_REQ_SCALAR_INT_CLAUSE(NumTeams, OMPC_num_teams) CHECK_REQ_SCALAR_INT_CLAUSE(NumThreads, OMPC_num_threads) CHECK_REQ_SCALAR_INT_CLAUSE(OmpxDynCgroupMem, OMPC_ompx_dyn_cgroup_mem) @@ -3313,18 +3324,33 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) { parser::ToUpperCaseLetters(getDirectiveName(GetContext().directive))); } if (const auto *inOut{std::get_if(&x.v.u)}) { - const auto &designators{std::get>(inOut->t)}; - for (const auto &ele : designators) { - if (const auto *dataRef{std::get_if(&ele.u)}) { - CheckDependList(*dataRef); - if (const auto *arr{ - std::get_if>( - &dataRef->u)}) { - CheckArraySection(arr->value(), GetLastName(*dataRef), - llvm::omp::Clause::OMPC_depend); + for (const auto &object : std::get(inOut->t).v) { + if (const auto *name{std::get_if(&object.u)}) { + context_.Say(GetContext().clauseSource, + "Common block name ('%s') cannot appear in a DEPEND " + "clause"_err_en_US, + name->ToString()); + } else if (auto *designator{std::get_if(&object.u)}) { + if (auto *dataRef{std::get_if(&designator->u)}) { + CheckDependList(*dataRef); + if (const auto *arr{ + std::get_if>( + &dataRef->u)}) { + CheckArraySection(arr->value(), GetLastName(*dataRef), + llvm::omp::Clause::OMPC_depend); + } } } } + if (std::get>(inOut->t)) { + unsigned version{context_.langOptions().OpenMPVersion}; + unsigned allowedInVersion{50}; + if (version < allowedInVersion) { + context_.Say(GetContext().clauseSource, + "Iterator modifiers are not supported in %s, %s"_warn_en_US, + ThisVersion(version), TryVersion(allowedInVersion)); + } + } } } @@ -3397,8 +3423,8 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &x) { std::to_string(version / 10) + "." + std::to_string(version % 10)}; context_.Say(GetContext().clauseSource, "LASTPRIVATE clause with CONDITIONAL modifier is not " - "allowed in OpenMP v%s, try -fopenmp-version=%d"_err_en_US, - thisVersion, allowedInVersion); + "allowed in %s, %s"_err_en_US, + ThisVersion(version), TryVersion(allowedInVersion)); } } } diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index 490d802cddf42fbaaa1bff8a26a1ac8a3420f0d5..014b7987a658bd3598a11c614788e1b69a5e48f6 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -435,6 +435,20 @@ public: bool Pre(const parser::OpenMPAllocatorsConstruct &); void Post(const parser::OpenMPAllocatorsConstruct &); + void Post(const parser::OmpObjectList &x) { + // The objects from OMP clauses should have already been resolved, + // except common blocks (the ResolveNamesVisitor does not visit + // parser::Name, those are dealt with as members of other structures). + // Iterate over elements of x, and resolve any common blocks that + // are still unresolved. + for (const parser::OmpObject &obj : x.v) { + auto *name{std::get_if(&obj.u)}; + if (name && !name->symbol) { + Resolve(*name, currScope().MakeCommonBlock(name->source)); + } + } + } + // 2.15.3 Data-Sharing Attribute Clauses void Post(const parser::OmpDefaultClause &); bool Pre(const parser::OmpClause::Shared &x) { @@ -531,16 +545,9 @@ public: return false; } - bool Pre(const parser::OmpDependClause &x) { - if (const auto *dependSink{ - std::get_if(&x.u)}) { - const auto &dependSinkVec{dependSink->v}; - for (const auto &dependSinkElement : dependSinkVec) { - const auto &name{std::get(dependSinkElement.t)}; - ResolveName(&name); - } - } - return false; + void Post(const parser::OmpDependSinkVec &x) { + const auto &name{std::get(x.t)}; + ResolveName(&name); } bool Pre(const parser::OmpClause::UseDevicePtr &x) { @@ -1526,6 +1533,7 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPBlockConstruct &x) { case llvm::omp::Directive::OMPD_master: case llvm::omp::Directive::OMPD_ordered: case llvm::omp::Directive::OMPD_parallel: + case llvm::omp::Directive::OMPD_scope: case llvm::omp::Directive::OMPD_single: case llvm::omp::Directive::OMPD_target: case llvm::omp::Directive::OMPD_target_data: @@ -1557,6 +1565,7 @@ void OmpAttributeVisitor::Post(const parser::OpenMPBlockConstruct &x) { case llvm::omp::Directive::OMPD_masked: case llvm::omp::Directive::OMPD_parallel_masked: case llvm::omp::Directive::OMPD_parallel: + case llvm::omp::Directive::OMPD_scope: case llvm::omp::Directive::OMPD_single: case llvm::omp::Directive::OMPD_target: case llvm::omp::Directive::OMPD_task: @@ -2050,6 +2059,8 @@ void OmpAttributeVisitor::Post(const parser::OpenMPAllocatorsConstruct &x) { static bool IsPrivatizable(const Symbol *sym) { auto *misc{sym->detailsIf()}; return !IsProcedure(*sym) && !IsNamedConstant(*sym) && + !semantics::IsAssumedSizeArray( + *sym) && /* OpenMP 5.2, 5.1.1: Assumed-size arrays are shared*/ !sym->owner().IsDerivedType() && sym->owner().kind() != Scope::Kind::ImpliedDos && !sym->detailsIf() && @@ -2320,7 +2331,7 @@ void OmpAttributeVisitor::ResolveOmpObject( if (auto *symbol{ResolveOmp(*name, ompFlag, currScope())}) { auto checkExclusivelists = [&](const Symbol *symbol1, Symbol::Flag firstOmpFlag, - Symbol *symbol2, Symbol::Flag secondOmpFlag) { + const Symbol *symbol2, Symbol::Flag secondOmpFlag) { if ((symbol1->test(firstOmpFlag) && symbol2->test(secondOmpFlag)) || (symbol1->test(secondOmpFlag) && @@ -2330,9 +2341,8 @@ void OmpAttributeVisitor::ResolveOmpObject( "appear on both %s and %s " "clauses on a %s construct"_err_en_US, symbol2->name(), - const_cast(symbol1)->OmpFlagToClauseName( - firstOmpFlag), - symbol2->OmpFlagToClauseName(secondOmpFlag), + Symbol::OmpFlagToClauseName(firstOmpFlag), + Symbol::OmpFlagToClauseName(secondOmpFlag), parser::ToUpperCaseLetters( llvm::omp::getOpenMPDirectiveName( GetContext().directive) diff --git a/flang/runtime/CUDA/CMakeLists.txt b/flang/runtime/CUDA/CMakeLists.txt index 86523b419f8711d66155a1762e7b6d7483b33da9..ce87f3efdc3632f96a89c665490ba872328b9aa7 100644 --- a/flang/runtime/CUDA/CMakeLists.txt +++ b/flang/runtime/CUDA/CMakeLists.txt @@ -17,6 +17,7 @@ add_flang_library(${CUFRT_LIBNAME} allocator.cpp allocatable.cpp descriptor.cpp + kernel.cpp memory.cpp registration.cpp ) diff --git a/flang/runtime/CUDA/kernel.cpp b/flang/runtime/CUDA/kernel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f81153a1af4bc77e703637438785f0ce279eac2b --- /dev/null +++ b/flang/runtime/CUDA/kernel.cpp @@ -0,0 +1,33 @@ +//===-- runtime/CUDA/kernel.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "flang/Runtime/CUDA/kernel.h" +#include "../terminator.h" +#include "flang/Runtime/CUDA/common.h" + +#include "cuda_runtime.h" + +extern "C" { + +void RTDEF(CUFLaunchKernel)(const void *kernel, intptr_t gridX, intptr_t gridY, + intptr_t gridZ, intptr_t blockX, intptr_t blockY, intptr_t blockZ, + int32_t smem, void **params, void **extra) { + dim3 gridDim; + gridDim.x = gridX; + gridDim.y = gridY; + gridDim.z = gridZ; + dim3 blockDim; + blockDim.x = blockX; + blockDim.y = blockY; + blockDim.z = blockZ; + cudaStream_t stream = 0; + CUDA_REPORT_IF_ERROR( + cudaLaunchKernel(kernel, gridDim, blockDim, params, smem, stream)); +} + +} // extern "C" diff --git a/flang/runtime/CUDA/registration.cpp b/flang/runtime/CUDA/registration.cpp index e5d9503e95fd8fa477d660b56b1519babe4f9ee4..b7b6ef389bffba9e49e843ba5407c7cf6de568b3 100644 --- a/flang/runtime/CUDA/registration.cpp +++ b/flang/runtime/CUDA/registration.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "flang/Runtime/CUDA/registration.h" +#include "../terminator.h" +#include "flang/Runtime/CUDA/common.h" #include "cuda_runtime.h" @@ -19,6 +21,9 @@ extern void __cudaRegisterFatBinaryEnd(void *); extern void __cudaRegisterFunction(void **fatCubinHandle, const char *hostFun, char *deviceFun, const char *deviceName, int thread_limit, uint3 *tid, uint3 *bid, dim3 *bDim, dim3 *gDim, int *wSize); +extern void __cudaRegisterVar(void **fatCubinHandle, char *hostVar, + const char *deviceAddress, const char *deviceName, int ext, size_t size, + int constant, int global); void *RTDECL(CUFRegisterModule)(void *data) { void **fatHandle{__cudaRegisterFatBinary(data)}; @@ -26,9 +31,17 @@ void *RTDECL(CUFRegisterModule)(void *data) { return fatHandle; } -void RTDEF(CUFRegisterFunction)(void **module, const char *fct) { - __cudaRegisterFunction(module, fct, const_cast(fct), fct, -1, - (uint3 *)0, (uint3 *)0, (dim3 *)0, (dim3 *)0, (int *)0); +void RTDEF(CUFRegisterFunction)( + void **module, const char *fctSym, char *fctName) { + __cudaRegisterFunction(module, fctSym, fctName, fctName, -1, (uint3 *)0, + (uint3 *)0, (dim3 *)0, (dim3 *)0, (int *)0); } + +void RTDEF(CUFRegisterVariable)( + void **module, char *varSym, const char *varName, int64_t size) { + __cudaRegisterVar(module, varSym, varName, varName, 0, size, 0, 0); } + +} // extern "C" + } // namespace Fortran::runtime::cuda diff --git a/flang/test/Driver/embed.f90 b/flang/test/Driver/embed.f90 index 60d532a8a94fdfc454c1130913dcec98ed7fb8ed..ce82beec1c6a81051e65041269fd29367b5b54e1 100644 --- a/flang/test/Driver/embed.f90 +++ b/flang/test/Driver/embed.f90 @@ -1,3 +1,5 @@ +!Windows uses 0d+0a as line-endings, and the check fails. +!UNSUPPORTED: system-windows !---------- ! RUN lines diff --git a/flang/test/Fir/CUDA/cuda-device-global.f90 b/flang/test/Fir/CUDA/cuda-device-global.f90 new file mode 100644 index 0000000000000000000000000000000000000000..c83a938d5af214121533a95e90707754505b5fba --- /dev/null +++ b/flang/test/Fir/CUDA/cuda-device-global.f90 @@ -0,0 +1,13 @@ + +// RUN: fir-opt --split-input-file --cuf-device-global %s | FileCheck %s + + +module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module} { + fir.global @_QMmtestsEn(dense<[3, 4, 5, 6, 7]> : tensor<5xi32>) {data_attr = #cuf.cuda} : !fir.array<5xi32> + + gpu.module @cuda_device_mod [#nvvm.target] { + } +} + +// CHECK: gpu.module @cuda_device_mod [#nvvm.target] +// CHECK-NEXT: fir.global @_QMmtestsEn(dense<[3, 4, 5, 6, 7]> : tensor<5xi32>) {data_attr = #cuf.cuda} : !fir.array<5xi32> diff --git a/flang/test/Fir/CUDA/cuda-gpu-launch-func.mlir b/flang/test/Fir/CUDA/cuda-gpu-launch-func.mlir new file mode 100644 index 0000000000000000000000000000000000000000..f10bd82f978dc4d4326f838368e4ce71a9389fee --- /dev/null +++ b/flang/test/Fir/CUDA/cuda-gpu-launch-func.mlir @@ -0,0 +1,104 @@ +// RUN: fir-opt --cuf-gpu-convert-to-llvm %s | FileCheck %s + +module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<4xi64>>, #dlti.dl_entry, dense<32> : vector<4xi64>>, #dlti.dl_entry, dense<32> : vector<4xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry, dense<64> : vector<4xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry<"dlti.endianness", "little">, #dlti.dl_entry<"dlti.stack_alignment", 128 : i64>>, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module, llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", llvm.ident = "flang version 20.0.0 (git@github.com:clementval/llvm-project.git ddcfd4d2dc17bf66cee8c3ef6284118684a2b0e6)", llvm.target_triple = "x86_64-unknown-linux-gnu"} { + llvm.func @_QMmod1Phost_sub() { + %0 = llvm.mlir.constant(1 : i32) : i32 + %1 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr + %2 = llvm.mlir.constant(40 : i64) : i64 + %3 = llvm.mlir.constant(16 : i32) : i32 + %4 = llvm.mlir.constant(25 : i32) : i32 + %5 = llvm.mlir.constant(21 : i32) : i32 + %6 = llvm.mlir.constant(17 : i32) : i32 + %7 = llvm.mlir.constant(1 : index) : i64 + %8 = llvm.mlir.constant(27 : i32) : i32 + %9 = llvm.mlir.constant(6 : i32) : i32 + %10 = llvm.mlir.constant(1 : i32) : i32 + %11 = llvm.mlir.constant(0 : i32) : i32 + %12 = llvm.mlir.constant(10 : index) : i64 + %13 = llvm.mlir.addressof @_QQclX91d13f6e74caa2f03965d7a7c6a8fdd5 : !llvm.ptr + %14 = llvm.call @_FortranACUFMemAlloc(%2, %11, %13, %6) : (i64, i32, !llvm.ptr, i32) -> !llvm.ptr + %15 = llvm.mlir.constant(10 : index) : i64 + %16 = llvm.mlir.constant(1 : index) : i64 + %17 = llvm.alloca %15 x i32 : (i64) -> !llvm.ptr + %18 = llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %19 = llvm.insertvalue %17, %18[0] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %20 = llvm.insertvalue %17, %19[1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %21 = llvm.mlir.constant(0 : index) : i64 + %22 = llvm.insertvalue %21, %20[2] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %23 = llvm.insertvalue %15, %22[3, 0] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %24 = llvm.insertvalue %16, %23[4, 0] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %25 = llvm.extractvalue %24[1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %26 = llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %27 = llvm.insertvalue %25, %26[0] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %28 = llvm.insertvalue %25, %27[1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %29 = llvm.mlir.constant(0 : index) : i64 + %30 = llvm.insertvalue %29, %28[2] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %31 = llvm.mlir.constant(10 : index) : i64 + %32 = llvm.insertvalue %31, %30[3, 0] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %33 = llvm.mlir.constant(1 : index) : i64 + %34 = llvm.insertvalue %33, %32[4, 0] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %35 = llvm.mlir.constant(1 : index) : i64 + %36 = llvm.mlir.constant(11 : index) : i64 + %37 = llvm.mlir.constant(1 : index) : i64 + llvm.br ^bb1(%35 : i64) + ^bb1(%38: i64): // 2 preds: ^bb0, ^bb2 + %39 = llvm.icmp "slt" %38, %36 : i64 + llvm.cond_br %39, ^bb2, ^bb3 + ^bb2: // pred: ^bb1 + %40 = llvm.mlir.constant(-1 : index) : i64 + %41 = llvm.add %38, %40 : i64 + %42 = llvm.extractvalue %34[1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %43 = llvm.getelementptr %42[%41] : (!llvm.ptr, i64) -> !llvm.ptr, i32 + llvm.store %11, %43 : i32, !llvm.ptr + %44 = llvm.add %38, %37 : i64 + llvm.br ^bb1(%44 : i64) + ^bb3: // pred: ^bb1 + %45 = llvm.call @_FortranACUFDataTransferPtrPtr(%14, %25, %2, %11, %13, %5) : (!llvm.ptr, !llvm.ptr, i64, i32, !llvm.ptr, i32) -> !llvm.struct<()> + gpu.launch_func @cuda_device_mod::@_QMmod1Psub1 blocks in (%7, %7, %7) threads in (%12, %7, %7) : i64 dynamic_shared_memory_size %11 args(%14 : !llvm.ptr) + %46 = llvm.call @_FortranACUFDataTransferPtrPtr(%25, %14, %2, %10, %13, %4) : (!llvm.ptr, !llvm.ptr, i64, i32, !llvm.ptr, i32) -> !llvm.struct<()> + %47 = llvm.call @_FortranAioBeginExternalListOutput(%9, %13, %8) {fastmathFlags = #llvm.fastmath} : (i32, !llvm.ptr, i32) -> !llvm.ptr + %48 = llvm.mlir.constant(9 : i32) : i32 + %49 = llvm.mlir.zero : !llvm.ptr + %50 = llvm.getelementptr %49[1] : (!llvm.ptr) -> !llvm.ptr, i32 + %51 = llvm.ptrtoint %50 : !llvm.ptr to i64 + %52 = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %53 = llvm.insertvalue %51, %52[1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %54 = llvm.mlir.constant(20240719 : i32) : i32 + %55 = llvm.insertvalue %54, %53[2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %56 = llvm.mlir.constant(1 : i32) : i32 + %57 = llvm.trunc %56 : i32 to i8 + %58 = llvm.insertvalue %57, %55[3] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %59 = llvm.trunc %48 : i32 to i8 + %60 = llvm.insertvalue %59, %58[4] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %61 = llvm.mlir.constant(0 : i32) : i32 + %62 = llvm.trunc %61 : i32 to i8 + %63 = llvm.insertvalue %62, %60[5] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %64 = llvm.mlir.constant(0 : i32) : i32 + %65 = llvm.trunc %64 : i32 to i8 + %66 = llvm.insertvalue %65, %63[6] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %67 = llvm.mlir.constant(0 : i64) : i64 + %68 = llvm.mlir.constant(1 : i64) : i64 + %69 = llvm.insertvalue %68, %66[7, 0, 0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %70 = llvm.insertvalue %12, %69[7, 0, 1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %71 = llvm.insertvalue %51, %70[7, 0, 2] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + %72 = llvm.mul %51, %12 : i64 + %73 = llvm.insertvalue %25, %71[0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> + llvm.store %73, %1 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, !llvm.ptr + llvm.return + } + llvm.func @_QMmod1Psub1(!llvm.ptr) -> () + llvm.mlir.global linkonce constant @_QQclX91d13f6e74caa2f03965d7a7c6a8fdd5() {addr_space = 0 : i32} : !llvm.array<2 x i8> { + %0 = llvm.mlir.constant("a\00") : !llvm.array<2 x i8> + llvm.return %0 : !llvm.array<2 x i8> + } + llvm.func @_FortranAioBeginExternalListOutput(i32, !llvm.ptr, i32) -> !llvm.ptr attributes {fir.io, fir.runtime, sym_visibility = "private"} + llvm.func @_FortranACUFMemAlloc(i64, i32, !llvm.ptr, i32) -> !llvm.ptr attributes {fir.runtime, sym_visibility = "private"} + llvm.func @_FortranACUFDataTransferPtrPtr(!llvm.ptr, !llvm.ptr, i64, i32, !llvm.ptr, i32) -> !llvm.struct<()> attributes {fir.runtime, sym_visibility = "private"} + llvm.func @_FortranACUFMemFree(!llvm.ptr, i32, !llvm.ptr, i32) -> !llvm.struct<()> attributes {fir.runtime, sym_visibility = "private"} + gpu.binary @cuda_device_mod [#gpu.object<#nvvm.target, "">] +} + +// CHECK-LABEL: _QMmod1Phost_sub + +// CHECK: %[[KERNEL_PTR:.*]] = llvm.mlir.addressof @_QMmod1Psub1 : !llvm.ptr +// CHECK: llvm.call @_FortranACUFLaunchKernel(%[[KERNEL_PTR]], {{.*}}) diff --git a/flang/test/Lower/OpenMP/Todo/affinity-clause.f90 b/flang/test/Lower/OpenMP/Todo/affinity-clause.f90 new file mode 100644 index 0000000000000000000000000000000000000000..3459dd219e4257d1386409929389c55c707c6f0f --- /dev/null +++ b/flang/test/Lower/OpenMP/Todo/affinity-clause.f90 @@ -0,0 +1,10 @@ +!RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %s 2>&1 | FileCheck %s +!RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %s 2>&1 | FileCheck %s + +!CHECK: not yet implemented: Unhandled clause AFFINITY in TASK construct +subroutine f00(x) + integer :: x(10) +!$omp task affinity(x) + x = x + 1 +!$omp end task +end diff --git a/flang/test/Lower/OpenMP/Todo/depend-clause.f90 b/flang/test/Lower/OpenMP/Todo/depend-clause.f90 new file mode 100644 index 0000000000000000000000000000000000000000..74525888c91d6da1b4588c03a6db078d02fa8a9d --- /dev/null +++ b/flang/test/Lower/OpenMP/Todo/depend-clause.f90 @@ -0,0 +1,10 @@ +!RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %s 2>&1 | FileCheck %s +!RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %s 2>&1 | FileCheck %s + +!CHECK: Support for iterator modifiers is not implemented yet +subroutine f00(x) + integer :: x(10) + !$omp task depend(iterator(i = 1:10), in: x(i)) + x = 0 + !$omp end task +end diff --git a/flang/test/Lower/OpenMP/Todo/scope.f90 b/flang/test/Lower/OpenMP/Todo/scope.f90 new file mode 100644 index 0000000000000000000000000000000000000000..16a067dc8f256bec09022ae8aa520d6862932145 --- /dev/null +++ b/flang/test/Lower/OpenMP/Todo/scope.f90 @@ -0,0 +1,13 @@ +! RUN: %not_todo_cmd bbc -emit-fir -fopenmp -o - %s -fopenmp-version=51 2>&1 | FileCheck %s +! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -o - %s -fopenmp-version=51 2>&1 | FileCheck %s + +! CHECK: not yet implemented: Scope construct +program omp_scope + integer i + i = 10 + + !$omp scope private(i) + print *, "omp scope", i + !$omp end scope + +end program omp_scope diff --git a/flang/test/Parser/OpenMP/affinity-clause.f90 b/flang/test/Parser/OpenMP/affinity-clause.f90 new file mode 100644 index 0000000000000000000000000000000000000000..804723cad7b2b3647576048caaf5e53537724e4c --- /dev/null +++ b/flang/test/Parser/OpenMP/affinity-clause.f90 @@ -0,0 +1,79 @@ +!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=50 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s +!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=50 %s | FileCheck --check-prefix="PARSE-TREE" %s + +subroutine f00(x) + integer :: x(10) +!$omp task affinity(x) + x = x + 1 +!$omp end task +end + +!UNPARSE: SUBROUTINE f00 (x) +!UNPARSE: INTEGER x(10_4) +!UNPARSE: !$OMP TASK AFFINITY(x) +!UNPARSE: x=x+1_4 +!UNPARSE: !$OMP END TASK +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: OmpBeginBlockDirective +!PARSE-TREE: | OmpBlockDirective -> llvm::omp::Directive = task +!PARSE-TREE: | OmpClauseList -> OmpClause -> Affinity -> OmpAffinityClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' + +subroutine f01(x) + integer :: x(10) +!$omp task affinity(x(1), x(3)) + x = x + 1 +!$omp end task +end + +!UNPARSE: SUBROUTINE f01 (x) +!UNPARSE: INTEGER x(10_4) +!UNPARSE: !$OMP TASK AFFINITY(x(1_4),x(3_4)) +!UNPARSE: x=x+1_4 +!UNPARSE: !$OMP END TASK +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: OmpBeginBlockDirective +!PARSE-TREE: | OmpBlockDirective -> llvm::omp::Directive = task +!PARSE-TREE: | OmpClauseList -> OmpClause -> Affinity -> OmpAffinityClause +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> ArrayElement +!PARSE-TREE: | | | DataRef -> Name = 'x' +!PARSE-TREE: | | | SectionSubscript -> Integer -> Expr = '1_4' +!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1' +!PARSE-TREE: | | OmpObject -> Designator -> DataRef -> ArrayElement +!PARSE-TREE: | | | DataRef -> Name = 'x' +!PARSE-TREE: | | | SectionSubscript -> Integer -> Expr = '3_4' +!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '3' + +subroutine f02(x) + integer :: x(10) +!$omp task affinity(iterator(i = 1:3): x(i)) + x = x + 1 +!$omp end task +end + +!UNPARSE: SUBROUTINE f02 (x) +!UNPARSE: INTEGER x(10_4) +!UNPARSE: !$OMP TASK AFFINITY(ITERATOR(INTEGER i = 1_4:3_4):x(i)) +!UNPARSE: x=x+1_4 +!UNPARSE: !$OMP END TASK +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: OmpBeginBlockDirective +!PARSE-TREE: | OmpBlockDirective -> llvm::omp::Directive = task +!PARSE-TREE: | OmpClauseList -> OmpClause -> Affinity -> OmpAffinityClause +!PARSE-TREE: | | OmpIteratorModifier -> OmpIteratorSpecifier +!PARSE-TREE: | | | TypeDeclarationStmt +!PARSE-TREE: | | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> +!PARSE-TREE: | | | | EntityDecl +!PARSE-TREE: | | | | | Name = 'i' +!PARSE-TREE: | | | SubscriptTriplet +!PARSE-TREE: | | | | Scalar -> Integer -> Expr = '1_4' +!PARSE-TREE: | | | | | LiteralConstant -> IntLiteralConstant = '1' +!PARSE-TREE: | | | | Scalar -> Integer -> Expr = '3_4' +!PARSE-TREE: | | | | | LiteralConstant -> IntLiteralConstant = '3' +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> ArrayElement +!PARSE-TREE: | | | DataRef -> Name = 'x' +!PARSE-TREE: | | | SectionSubscript -> Integer -> Expr = 'i' +!PARSE-TREE: | | | | Designator -> DataRef -> Name = 'i' diff --git a/flang/test/Parser/OpenMP/scope.f90 b/flang/test/Parser/OpenMP/scope.f90 new file mode 100644 index 0000000000000000000000000000000000000000..6574136311e71873f564a092900b5bb7d50c2c1b --- /dev/null +++ b/flang/test/Parser/OpenMP/scope.f90 @@ -0,0 +1,24 @@ +! RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=51 %s | FileCheck --ignore-case %s +! RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=51 %s | FileCheck --check-prefix="PARSE-TREE" %s + +program omp_scope + integer i + i = 10 + +!CHECK: !$OMP SCOPE PRIVATE(i) +!CHECK: !$OMP END SCOPE + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPBlockConstruct +!PARSE-TREE: OmpBeginBlockDirective +!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = scope +!PARSE-TREE: OmpClauseList -> OmpClause -> Private -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'i' +!PARSE-TREE: Block +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> PrintStmt +!PARSE-TREE: OmpEndBlockDirective +!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = scope +!PARSE-TREE: OmpClauseList -> OmpClause -> Nowait + + !$omp scope private(i) + print *, "omp scope", i + !$omp end scope nowait +end program omp_scope diff --git a/flang/test/Parser/OpenMP/taskloop.f90 b/flang/test/Parser/OpenMP/taskloop.f90 new file mode 100644 index 0000000000000000000000000000000000000000..a9c361046bd5f5d22aaa87c812643cccee5a4445 --- /dev/null +++ b/flang/test/Parser/OpenMP/taskloop.f90 @@ -0,0 +1,41 @@ +! RUN: %flang_fc1 -fdebug-unparse -fopenmp %s | FileCheck --ignore-case %s +! RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s + +subroutine parallel_work + integer :: i + +!CHECK: !$OMP TASKLOOP GRAINSIZE(STRICT:500_4) +!PARSE-TREE: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = taskloop +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Grainsize -> OmpGrainsizeClause +!PARSE-TREE-NEXT: Prescriptiveness = Strict +!PARSE-TREE-NEXT: Scalar -> Integer -> Expr = '500_4' + !$omp taskloop grainsize(strict: 500) + do i=1,10000 + call loop_body(i) + end do + !$omp end taskloop + +!CHECK: !$OMP TASKLOOP GRAINSIZE(500_4) +!PARSE-TREE: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = taskloop +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Grainsize -> OmpGrainsizeClause +!PARSE-TREE-NEXT: Scalar -> Integer -> Expr = '500_4' + !$omp taskloop grainsize(500) + do i=1,10000 + call loop_body(i) + end do + !$omp end taskloop + +!CHECK: !$OMP TASKLOOP NUM_TASKS(STRICT:500_4) +!PARSE-TREE: OmpBeginLoopDirective +!PARSE-TREE-NEXT: OmpLoopDirective -> llvm::omp::Directive = taskloop +!PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> NumTasks -> OmpNumTasksClause +!PARSE-TREE-NEXT: Prescriptiveness = Strict +!PARSE-TREE-NEXT: Scalar -> Integer -> Expr = '500_4' + !$omp taskloop num_tasks(strict: 500) + do i=1,10000 + call loop_body(i) + end do + !$omp end taskloop +end subroutine parallel_work diff --git a/flang/test/Semantics/OpenMP/affinity-clause.f90 b/flang/test/Semantics/OpenMP/affinity-clause.f90 new file mode 100644 index 0000000000000000000000000000000000000000..53b2c4fc56677f01684889301607fc79b272985c --- /dev/null +++ b/flang/test/Semantics/OpenMP/affinity-clause.f90 @@ -0,0 +1,9 @@ +!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=45 + +subroutine f00(x) + integer :: x(10) +!ERROR: AFFINITY clause is not allowed on directive TASK in OpenMP v4.5, try -fopenmp-version=50 +!$omp task affinity(x) + x = x + 1 +!$omp end task +end diff --git a/flang/test/Semantics/OpenMP/default-none.f90 b/flang/test/Semantics/OpenMP/default-none.f90 index 11ba878ea779403c6a964e59ab1c20ec390768cf..761c2385466a0882d11930b8331b57898cef7f45 100644 --- a/flang/test/Semantics/OpenMP/default-none.f90 +++ b/flang/test/Semantics/OpenMP/default-none.f90 @@ -47,3 +47,14 @@ subroutine sb4 end do loop !$omp end parallel end subroutine + +! Test that default(none) does not error for assumed-size array +subroutine sub( aaa) + real,dimension(*),intent(in)::aaa + integer::ip + real::ccc +!$omp parallel do private(ip,ccc) default(none) + do ip = 1, 10 + ccc= aaa(ip) + end do +end subroutine sub diff --git a/flang/test/Semantics/OpenMP/depend04.f90 b/flang/test/Semantics/OpenMP/depend04.f90 new file mode 100644 index 0000000000000000000000000000000000000000..8bdddb017d2c9d928aa8f7c1c10d15426570f58a --- /dev/null +++ b/flang/test/Semantics/OpenMP/depend04.f90 @@ -0,0 +1,10 @@ +!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=50 + +subroutine f00 + integer :: x + common /cc/ x +!ERROR: Common block name ('cc') cannot appear in a DEPEND clause + !$omp task depend(in: /cc/) + x = 0 + !$omp end task +end diff --git a/flang/test/Semantics/OpenMP/depend05.f90 b/flang/test/Semantics/OpenMP/depend05.f90 new file mode 100644 index 0000000000000000000000000000000000000000..53fd82bd08a9eb2f62bc276465a8025abc3a60d2 --- /dev/null +++ b/flang/test/Semantics/OpenMP/depend05.f90 @@ -0,0 +1,9 @@ +!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=45 -Werror + +subroutine f00(x) + integer :: x(10) +!WARNING: Iterator modifiers are not supported in OpenMP v4.5, try -fopenmp-version=50 + !$omp task depend(iterator(i = 1:10), in: x(i)) + x = 0 + !$omp end task +end diff --git a/flang/test/Semantics/OpenMP/invalid-branch.f90 b/flang/test/Semantics/OpenMP/invalid-branch.f90 index ed9e4d268f65a8c49f426723dae6914a7960e4fc..28aab8b122f3f2ca1c59e01279535dc0b4d7c52e 100644 --- a/flang/test/Semantics/OpenMP/invalid-branch.f90 +++ b/flang/test/Semantics/OpenMP/invalid-branch.f90 @@ -105,4 +105,12 @@ program omp_invalid_branch !$omp end parallel 9 print *, "2nd alternate return" + !CHECK: invalid branch into an OpenMP structured block + goto 100 + !$omp scope + 100 continue + !CHECK: invalid branch leaving an OpenMP structured block + goto 200 + !$omp end scope + 200 continue end program diff --git a/flang/test/Semantics/OpenMP/nested01.f90 b/flang/test/Semantics/OpenMP/nested01.f90 index 49c964ab86aa6bd7adc78c8f951c3d21ba665064..0936e4c1b45a5db4c437dd896d47b5a70a2c432c 100644 --- a/flang/test/Semantics/OpenMP/nested01.f90 +++ b/flang/test/Semantics/OpenMP/nested01.f90 @@ -25,6 +25,13 @@ !$omp end target enddo + !$omp do + do i = 1, N + !ERROR: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region + !$omp scope + !$omp end scope + end do + !$omp end do !$omp do do i = 1, N diff --git a/flang/test/Transforms/debug-derived-type-2.fir b/flang/test/Transforms/debug-derived-type-2.fir new file mode 100644 index 0000000000000000000000000000000000000000..63e842619edbecd80e3d38fb10cf4ca482cfe667 --- /dev/null +++ b/flang/test/Transforms/debug-derived-type-2.fir @@ -0,0 +1,16 @@ +// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s + +module attributes {dlti.dl_spec = #dlti.dl_spec<>} { + fir.global @_QMmEvar : !fir.type<_QMmTt1{elm:!fir.array<5xi32>,elm2:!fir.array<5x8xi32>}> {} loc(#loc1) + fir.type_info @_QMmTt1 noinit nodestroy nofinal : !fir.type<_QMmTt1{elm:!fir.array<5xi32>,elm2:!fir.array<5x8xi32>}> component_info { + fir.dt_component "elm" lbs [2] + fir.dt_component "elm2" lbs [1, 3] + } loc(#loc1) +} +#loc1 = loc("derived.f90":24:1) + + +// CHECK-DAG: #[[TY1:.*]] = #llvm.di_composite_type> +// CHECK-DAG: #[[TY2:.*]] = #llvm.di_composite_type, #llvm.di_subrange> +// CHECK-DAG: #llvm.di_derived_type +// CHECK-DAG: #llvm.di_derived_type diff --git a/flang/test/Transforms/debug-index-type.fir b/flang/test/Transforms/debug-index-type.fir new file mode 100644 index 0000000000000000000000000000000000000000..20bd8471d7cf648e1f176b46082e1a2a4853d6ef --- /dev/null +++ b/flang/test/Transforms/debug-index-type.fir @@ -0,0 +1,10 @@ +// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s + +module attributes {dlti.dl_spec = #dlti.dl_spec<>} { + func.func private @str(%arg0: index) -> i32 loc(#loc1) +} +#loc1 = loc("test.f90":5:1) + +// CHECK: #[[INT32_TY:.*]] = #llvm.di_basic_type +// CHECK: #[[INT64_TY:.*]] = #llvm.di_basic_type +// CHECK: #llvm.di_subroutine_type<{{.*}}types = #[[INT32_TY]], #[[INT64_TY]]> diff --git a/flang/test/Transforms/debug-ref-type.fir b/flang/test/Transforms/debug-ref-type.fir new file mode 100644 index 0000000000000000000000000000000000000000..2b3af485385d8ad359b673d2dfeb9b58a3bc16f9 --- /dev/null +++ b/flang/test/Transforms/debug-ref-type.fir @@ -0,0 +1,10 @@ +// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s + +module attributes {dlti.dl_spec = #dlti.dl_spec<>} { + func.func private @_FortranAioBeginExternalListOutput(i8) -> !fir.ref loc(#loc1) +} +#loc1 = loc("test.f90":5:1) + +// CHECK: #[[INT8_TY:.*]] = #llvm.di_basic_type +// CHECK: #[[REF_TY:.*]] = #llvm.di_derived_type +// CHECK: #llvm.di_subroutine_type<{{.*}}types = #[[REF_TY]], #[[INT8_TY]]> diff --git a/flang/test/Transforms/debug-vector-type.fir b/flang/test/Transforms/debug-vector-type.fir new file mode 100644 index 0000000000000000000000000000000000000000..63846ce006c6ce4c8d3a135f99831453b4532a58 --- /dev/null +++ b/flang/test/Transforms/debug-vector-type.fir @@ -0,0 +1,23 @@ +// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s + +module attributes {dlti.dl_spec = #dlti.dl_spec<>} { +func.func private @foo1(%arg0: !fir.vector<20:bf16>) +// CHECK-DAG: #[[F16:.*]] = #llvm.di_basic_type +// CHECK-DAG: #llvm.di_composite_type> + +func.func private @foo2(%arg0: !fir.vector<30:f32>) +// CHECK-DAG: #[[F32:.*]] = #llvm.di_basic_type +// CHECK-DAG: #llvm.di_composite_type> + +func.func private @foo3(%arg0: !fir.vector<10:f64>) +// CHECK-DAG: #[[F64:.*]] = #llvm.di_basic_type +// CHECK-DAG: #llvm.di_composite_type> + +func.func private @foo4(%arg0: !fir.vector<5:i32>) +// CHECK-DAG: #[[I32:.*]] = #llvm.di_basic_type +// CHECK-DAG: #llvm.di_composite_type> + +func.func private @foo5(%arg0: !fir.vector<2:i64>) +// CHECK-DAG: #[[I64:.*]] = #llvm.di_basic_type +// CHECK-DAG: #llvm.di_composite_type> +} diff --git a/flang/tools/fir-opt/fir-opt.cpp b/flang/tools/fir-opt/fir-opt.cpp index 84a74770cf030306f0fc21c1bf761d35609cae70..5f6a856116bc04e1a0a61763095e1de3aeec41fa 100644 --- a/flang/tools/fir-opt/fir-opt.cpp +++ b/flang/tools/fir-opt/fir-opt.cpp @@ -43,6 +43,7 @@ int main(int argc, char **argv) { DialectRegistry registry; fir::support::registerDialects(registry); registry.insert(); + registry.insert(); fir::support::addFIRExtensions(registry); return failed(MlirOptMain(argc, argv, "FIR modular optimizer driver\n", registry)); diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake index 0c658c6866c437587902f9784ba6ddd503b126ea..e30f7d322eb029ef50f65592ac31901e549f56a8 100644 --- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake +++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake @@ -84,7 +84,7 @@ function(_get_compile_options_from_config output_var) endif() if(LIBC_CONF_MATH_OPTIMIZATIONS) - list(APPEND compile_options "-DLIBC_MATH=${LIBC_CONF_MATH_OPTIMIZATIONS}") + list(APPEND config_options "-DLIBC_MATH=${LIBC_CONF_MATH_OPTIMIZATIONS}") endif() set(${output_var} ${config_options} PARENT_SCOPE) diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 71c6e874429fedf28e884e2690dde6ce7feb69e9..b3f94a581c8ad9066ec53d4bfe1fbc626a9407e3 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -607,6 +607,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.canonicalizef16 libc.src.math.ceilf16 libc.src.math.copysignf16 + libc.src.math.cospif16 # TODO: aarch64 bug # Please see https://github.com/llvm/llvm-project/pull/100632#issuecomment-2258772681 # libc.src.math.expf16 diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 9bc63edf06f28c91eb653353f68e3afa8b2c80cd..a2fb97d04584d5b8b65300586077e5b93a99f9bb 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -611,6 +611,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.ceilf16 libc.src.math.copysignf16 libc.src.math.coshf16 + libc.src.math.cospif16 libc.src.math.exp10f16 libc.src.math.exp10m1f16 libc.src.math.exp2f16 diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst index ce4df92393ce7f4e50e02be0f67fac3f9973e50e..a50e054622e1a45efab6253be66cfe98e40bef68 100644 --- a/libc/docs/math/index.rst +++ b/libc/docs/math/index.rst @@ -280,7 +280,7 @@ Higher Math Functions +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | cosh | |check| | | | |check| | | 7.12.5.4 | F.10.2.4 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ -| cospi | |check| | | | | | 7.12.4.12 | F.10.1.12 | +| cospi | |check| | | | |check| | | 7.12.4.12 | F.10.1.12 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | dsqrt | N/A | N/A | |check| | N/A | |check|\* | 7.12.14.6 | F.10.11 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt index 13dc892978bb87a8428caf8f64b3ff82cab50268..80545ee4b359f4eabf133ce206f317932ce9641e 100644 --- a/libc/hdr/CMakeLists.txt +++ b/libc/hdr/CMakeLists.txt @@ -51,10 +51,13 @@ add_proxy_header_library( libc.include.llvm-libc-macros.generic_error_number_macros ) +add_header_library(fcntl_overlay HDRS fcntl_overlay.h) add_proxy_header_library( fcntl_macros HDRS fcntl_macros.h + DEPENDS + .fcntl_overlay FULL_BUILD_DEPENDS libc.include.llvm-libc-macros.fcntl_macros libc.include.fcntl diff --git a/libc/hdr/fcntl_macros.h b/libc/hdr/fcntl_macros.h index 828cb984c0cb1487cc27070733ff56973f2c2e2d..3a1ddeb0a2da1d9e320de10456f8c94d411096d2 100644 --- a/libc/hdr/fcntl_macros.h +++ b/libc/hdr/fcntl_macros.h @@ -15,7 +15,7 @@ #else // Overlay mode -#include +#include "hdr/fcntl_overlay.h" #endif // LLVM_LIBC_FULL_BUILD diff --git a/libc/hdr/fcntl_overlay.h b/libc/hdr/fcntl_overlay.h new file mode 100644 index 0000000000000000000000000000000000000000..c1cc98b0ebb2c7eef9ff699e0c56ed3e05aee52b --- /dev/null +++ b/libc/hdr/fcntl_overlay.h @@ -0,0 +1,37 @@ +//===-- Including fcntl.h in overlay mode ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_FCNTL_OVERLAY_H +#define LLVM_LIBC_HDR_FCNTL_OVERLAY_H + +#ifdef LIBC_FULL_BUILD +#error "This header should only be included in overlay mode" +#endif + +// Overlay mode + +// glibc header might provide extern inline definitions for few +// functions, causing external alias errors. They are guarded by +// `__USE_FORTIFY_LEVEL`, which will be temporarily disabled +// with `_FORTIFY_SOURCE`. + +#ifdef __USE_FORTIFY_LEVEL +#define LIBC_OLD_USE_FORTIFY_LEVEL __USE_FORTIFY_LEVEL +#undef __USE_FORTIFY_LEVEL +#define __USE_FORTIFY_LEVEL 0 +#endif + +#include + +#ifdef LIBC_OLD_USE_FORTIFY_LEVEL +#undef __USE_FORTIFY_LEVEL +#define __USE_FORTIFY_LEVEL LIBC_OLD_USE_FORTIFY_LEVEL +#undef LIBC_OLD_USE_FORTIFY_LEVEL +#endif + +#endif // LLVM_LIBC_HDR_FCNTL_OVERLAY_H diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt index fab5245816bbe198bc23f63a350500ed26e26d0e..e45979857d7955451b22e40602458aa3e58a3add 100644 --- a/libc/hdr/types/CMakeLists.txt +++ b/libc/hdr/types/CMakeLists.txt @@ -46,6 +46,17 @@ add_proxy_header_library( libc.include.llvm-libc-types.struct_timespec ) +add_proxy_header_library( + mode_t + HDRS + mode_t.h + DEPENDS + ../fcntl_overlay + FULL_BUILD_DEPENDS + libc.include.llvm-libc-types.mode_t + libc.include.fcntl +) + add_proxy_header_library( fenv_t HDRS diff --git a/libc/hdr/types/mode_t.h b/libc/hdr/types/mode_t.h new file mode 100644 index 0000000000000000000000000000000000000000..abbbdb0a09d7b6337219ea9bbd0e7a956653030b --- /dev/null +++ b/libc/hdr/types/mode_t.h @@ -0,0 +1,22 @@ +//===-- Definition of macros from mode_t.h --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_MODE_T_H +#define LLVM_LIBC_HDR_MODE_T_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/mode_t.h" + +#else // Overlay mode + +#include "hdr/fcntl_overlay.h" + +#endif // LLVM_LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_MODE_T_H diff --git a/libc/newhdrgen/yaml/math.yaml b/libc/newhdrgen/yaml/math.yaml index fe07803cff06f84a0d216af93b293af1bea06050..3cc4b599c777bff4a21dac4459b324488e79ae77 100644 --- a/libc/newhdrgen/yaml/math.yaml +++ b/libc/newhdrgen/yaml/math.yaml @@ -206,6 +206,13 @@ functions: return_type: float arguments: - type: float + - name: cospif16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 - name: coshf16 standards: - stdc diff --git a/libc/newhdrgen/yaml_to_classes.py b/libc/newhdrgen/yaml_to_classes.py index 237dd21aa5dff55ae53fb315e1cb913a91cb1401..a295058f7dc8210470d8cfa720c3e7c0da9e2384 100644 --- a/libc/newhdrgen/yaml_to_classes.py +++ b/libc/newhdrgen/yaml_to_classes.py @@ -216,52 +216,7 @@ def add_function_to_yaml(yaml_file, function_details): print(f"Added function {new_function.name} to {yaml_file}") -def main( - yaml_file, - output_dir=None, - h_def_file=None, - add_function=None, - entry_points=None, - export_decls=False, -): - """ - Main function to generate header files from YAML and .h.def templates. - - Args: - yaml_file: Path to the YAML file containing header specification. - h_def_file: Path to the .h.def template file. - output_dir: Directory to output the generated header file. - add_function: Details of the function to be added to the YAML file (if any). - entry_points: A list of specific function names to include in the header. - export_decls: Flag to use GpuHeader for exporting declarations. - """ - if add_function: - add_function_to_yaml(yaml_file, add_function) - - header_class = GpuHeader if export_decls else HeaderFile - header = load_yaml_file(yaml_file, header_class, entry_points) - - header_str = str(header) - - if output_dir: - output_file_path = Path(output_dir) - if output_file_path.is_dir(): - output_file_path /= f"{Path(yaml_file).stem}.h" - else: - output_file_path = Path(f"{Path(yaml_file).stem}.h") - - if not export_decls and h_def_file: - with open(h_def_file, "r") as f: - h_def_content = f.read() - final_header_content = fill_public_api(header_str, h_def_content) - with open(output_file_path, "w") as f: - f.write(final_header_content) - else: - with open(output_file_path, "w") as f: - f.write(header_str) - - -if __name__ == "__main__": +def main(): parser = argparse.ArgumentParser(description="Generate header files from YAML") parser.add_argument( "yaml_file", help="Path to the YAML file containing header specification" @@ -297,11 +252,31 @@ if __name__ == "__main__": ) args = parser.parse_args() - main( - args.yaml_file, - args.output_dir, - args.h_def_file, - args.add_function, - args.entry_points, - args.export_decls, - ) + if args.add_function: + add_function_to_yaml(yaml_file, args.add_function) + + header_class = GpuHeader if args.export_decls else HeaderFile + header = load_yaml_file(args.yaml_file, header_class, args.entry_points) + + header_str = str(header) + + if args.output_dir: + output_file_path = Path(args.output_dir) + if output_file_path.is_dir(): + output_file_path /= f"{Path(args.yaml_file).stem}.h" + else: + output_file_path = Path(f"{Path(args.yaml_file).stem}.h") + + if not args.export_decls and args.h_def_file: + with open(args.h_def_file, "r") as f: + h_def_content = f.read() + final_header_content = fill_public_api(header_str, h_def_content) + with open(output_file_path, "w") as f: + f.write(final_header_content) + else: + with open(output_file_path, "w") as f: + f.write(header_str) + + +if __name__ == "__main__": + main() diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt index 4785895b562b5e3a3d816b6c18e3d0e094d4eb3e..14a3acff8fae93582e9bfa4a6c23c7a6b01dcbe0 100644 --- a/libc/src/__support/CMakeLists.txt +++ b/libc/src/__support/CMakeLists.txt @@ -277,6 +277,7 @@ add_header_library( DEPENDS .integer_to_string libc.src.__support.OSUtil.osutil + libc.src.__support.macros.optimization ) add_header_library( diff --git a/libc/src/__support/File/linux/CMakeLists.txt b/libc/src/__support/File/linux/CMakeLists.txt index 5abbf11b3671cd25199b4c5d93cd44d4a2c8f308..84e3d5608361e19bdfb6c728b1904d3d86148097 100644 --- a/libc/src/__support/File/linux/CMakeLists.txt +++ b/libc/src/__support/File/linux/CMakeLists.txt @@ -7,7 +7,7 @@ add_object_library( file.h lseekImpl.h DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.sys_syscall libc.include.sys_stat libc.src.__support.CPP.new @@ -55,7 +55,7 @@ add_object_library( SRCS dir.cpp DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.sys_syscall libc.src.__support.OSUtil.osutil libc.src.__support.error_or diff --git a/libc/src/__support/File/linux/dir.cpp b/libc/src/__support/File/linux/dir.cpp index fc90ff097e4606dd02e84d0b1fc528f43122dbfd..5fe44fa8297b68defe6fde124caf91b78305adfb 100644 --- a/libc/src/__support/File/linux/dir.cpp +++ b/libc/src/__support/File/linux/dir.cpp @@ -12,7 +12,7 @@ #include "src/__support/error_or.h" #include "src/__support/macros/config.h" -#include // For open flags +#include "hdr/fcntl_macros.h" // For open flags #include // For syscall numbers namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp index 22292336f300e21ce0400ea50f651b91a9369676..824c1f200e8c5b19ce9192d6ddb741cc24be9374 100644 --- a/libc/src/__support/File/linux/file.cpp +++ b/libc/src/__support/File/linux/file.cpp @@ -18,7 +18,7 @@ #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" // For error macros -#include // For mode_t and other flags to the open syscall +#include "hdr/fcntl_macros.h" // For mode_t and other flags to the open syscall #include // For S_IS*, S_IF*, and S_IR* flags. #include // For syscall numbers diff --git a/libc/src/__support/libc_assert.h b/libc/src/__support/libc_assert.h index e21a58a0c8aad947d14fe925ab4420c6d3e8bb2b..3db179ff6721248be157274f676a96cd61cb92eb 100644 --- a/libc/src/__support/libc_assert.h +++ b/libc/src/__support/libc_assert.h @@ -24,7 +24,8 @@ #include "src/__support/OSUtil/exit.h" #include "src/__support/OSUtil/io.h" #include "src/__support/integer_to_string.h" -#include "src/__support/macros/attributes.h" // For LIBC_INLINE +#include "src/__support/macros/attributes.h" // For LIBC_INLINE +#include "src/__support/macros/optimization.h" // For LIBC_UNLIKELY namespace LIBC_NAMESPACE_DECL { @@ -71,7 +72,7 @@ LIBC_INLINE void report_assertion_failure(const char *assertion, #define LIBC_ASSERT(COND) \ do { \ - if (!(COND)) { \ + if (LIBC_UNLIKELY(!(COND))) { \ LIBC_NAMESPACE::write_to_stderr(__FILE__ ":" __LIBC_LINE_STR__ \ ": Assertion failed: '" #COND \ "' in function: '"); \ diff --git a/libc/src/__support/threads/linux/CMakeLists.txt b/libc/src/__support/threads/linux/CMakeLists.txt index b6796f40adce7bdab4193135a9125daa77a50b16..fa11458f99b6c9c43d261bee417b4fd07299d6d3 100644 --- a/libc/src/__support/threads/linux/CMakeLists.txt +++ b/libc/src/__support/threads/linux/CMakeLists.txt @@ -79,7 +79,7 @@ add_object_library( .futex_utils libc.config.app_h libc.include.sys_syscall - libc.include.fcntl + libc.hdr.fcntl_macros libc.src.errno.errno libc.src.__support.CPP.atomic libc.src.__support.CPP.stringstream diff --git a/libc/src/__support/threads/linux/thread.cpp b/libc/src/__support/threads/linux/thread.cpp index ee3f63fa3cde32e8dfe3fbb73159a724753ed0e4..c531d74c533550d6f94c8106322a6aeb043edee2 100644 --- a/libc/src/__support/threads/linux/thread.cpp +++ b/libc/src/__support/threads/linux/thread.cpp @@ -22,7 +22,7 @@ #include #endif -#include +#include "hdr/fcntl_macros.h" #include // For EXEC_PAGESIZE. #include // For PR_SET_NAME #include // For CLONE_* flags. diff --git a/libc/src/assert/assert.h b/libc/src/assert/assert.h index 6f352af1988b371f5c875514eec9f88a452d6e07..1ea19ea5554f0aa7428cf477097826d08d5bf1a7 100644 --- a/libc/src/assert/assert.h +++ b/libc/src/assert/assert.h @@ -18,8 +18,18 @@ #ifdef NDEBUG #define assert(e) (void)0 #else + +#ifdef __has_builtin +#if __has_builtin(__builtin_expect) +#define __LIBC_ASSERT_LIKELY(e) __builtin_expect(e, 1) +#endif +#endif +#ifndef __LIBC_ASSERT_LIKELY +#define __LIBC_ASSERT_LIKELY(e) e +#endif + #define assert(e) \ - ((e) ? (void)0 \ - : LIBC_NAMESPACE::__assert_fail(#e, __FILE__, __LINE__, \ - __PRETTY_FUNCTION__)) + (__LIBC_ASSERT_LIKELY(e) ? (void)0 \ + : LIBC_NAMESPACE::__assert_fail( \ + #e, __FILE__, __LINE__, __PRETTY_FUNCTION__)) #endif // NDEBUG diff --git a/libc/src/fcntl/creat.h b/libc/src/fcntl/creat.h index e180e17c2578870dadc9750040e5636750374ca5..3e00427638a36a4b6e2c26d3b628def24b02f255 100644 --- a/libc/src/fcntl/creat.h +++ b/libc/src/fcntl/creat.h @@ -9,8 +9,8 @@ #ifndef LLVM_LIBC_SRC_FCNTL_CREAT_H #define LLVM_LIBC_SRC_FCNTL_CREAT_H +#include "hdr/fcntl_macros.h" #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/fcntl/linux/CMakeLists.txt b/libc/src/fcntl/linux/CMakeLists.txt index ee8ae63b8cf062af87dacadad769b183cf824226..580db16cd4132052afa66b9782f118a124340417 100644 --- a/libc/src/fcntl/linux/CMakeLists.txt +++ b/libc/src/fcntl/linux/CMakeLists.txt @@ -5,7 +5,7 @@ add_entrypoint_object( HDRS ../creat.h DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.src.__support.OSUtil.osutil libc.src.errno.errno ) @@ -17,7 +17,7 @@ add_entrypoint_object( HDRS ../fcntl.h DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.src.__support.OSUtil.osutil ) @@ -28,7 +28,8 @@ add_entrypoint_object( HDRS ../open.h DEPENDS - libc.include.fcntl + libc.hdr.types.mode_t + libc.hdr.fcntl_macros libc.src.__support.OSUtil.osutil libc.src.errno.errno ) @@ -40,7 +41,7 @@ add_entrypoint_object( HDRS ../openat.h DEPENDS - libc.include.fcntl + libc.hdr.types.mode_t libc.src.__support.OSUtil.osutil libc.src.errno.errno ) diff --git a/libc/src/fcntl/linux/creat.cpp b/libc/src/fcntl/linux/creat.cpp index 2c5b5d736a3be3fd128190a06d19a3423c67cd11..23abae243aed92c391f72ca57a2bdc3f1c270325 100644 --- a/libc/src/fcntl/linux/creat.cpp +++ b/libc/src/fcntl/linux/creat.cpp @@ -13,7 +13,7 @@ #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include +#include "hdr/fcntl_macros.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/fcntl/linux/open.cpp b/libc/src/fcntl/linux/open.cpp index 79b7b2b32c887bba40798fc09a0b4416971fa349..8b699ecdd2043c704fd4d34b888f17737c57cf28 100644 --- a/libc/src/fcntl/linux/open.cpp +++ b/libc/src/fcntl/linux/open.cpp @@ -13,7 +13,8 @@ #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include +#include "hdr/fcntl_macros.h" +#include "hdr/types/mode_t.h" #include #include // For syscall numbers. diff --git a/libc/src/fcntl/linux/openat.cpp b/libc/src/fcntl/linux/openat.cpp index 0862082c22ebfcdd35b766397f4c5cd8f4f73188..6063d9c00ad6c4086f34060d05acf381b742ae86 100644 --- a/libc/src/fcntl/linux/openat.cpp +++ b/libc/src/fcntl/linux/openat.cpp @@ -13,7 +13,7 @@ #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include +#include "hdr/types/mode_t.h" #include #include // For syscall numbers. diff --git a/libc/src/fcntl/open.h b/libc/src/fcntl/open.h index 19bb53c2e3203199c79e36c665c74b5dae0228f4..11f0ae53795318c66ea31e06925db6b3ccc48039 100644 --- a/libc/src/fcntl/open.h +++ b/libc/src/fcntl/open.h @@ -9,8 +9,8 @@ #ifndef LLVM_LIBC_SRC_FCNTL_OPEN_H #define LLVM_LIBC_SRC_FCNTL_OPEN_H +#include "hdr/fcntl_macros.h" #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/fcntl/openat.h b/libc/src/fcntl/openat.h index d09791a84f73529b7ec672362b81aea553e20afa..051c8a2304dcbac1be7f28e6f6f9a2328b3df5b8 100644 --- a/libc/src/fcntl/openat.h +++ b/libc/src/fcntl/openat.h @@ -9,8 +9,8 @@ #ifndef LLVM_LIBC_SRC_FCNTL_OPENAT_H #define LLVM_LIBC_SRC_FCNTL_OPENAT_H +#include "hdr/fcntl_macros.h" #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index cb4817348cbba5e11f8d00e0eb27c10e3778027b..80c1867d2116f6291dc2b0a9f455bce211ea5e64 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -95,6 +95,7 @@ add_math_entrypoint_object(coshf) add_math_entrypoint_object(coshf16) add_math_entrypoint_object(cospif) +add_math_entrypoint_object(cospif16) add_math_entrypoint_object(daddl) add_math_entrypoint_object(daddf128) diff --git a/libc/src/math/cbrt.h b/libc/src/math/cbrt.h index a7d5fe80e57b3c4cda5f90ae13b97295f0069261..8cf7d9b221df3f92136e6fa6d0f95d2c30d12826 100644 --- a/libc/src/math/cbrt.h +++ b/libc/src/math/cbrt.h @@ -9,10 +9,12 @@ #ifndef LLVM_LIBC_SRC_MATH_CBRT_H #define LLVM_LIBC_SRC_MATH_CBRT_H -namespace LIBC_NAMESPACE { +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { double cbrt(double x); -} // namespace LIBC_NAMESPACE +} // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC_MATH_CBRT_H diff --git a/libc/src/math/cospif16.h b/libc/src/math/cospif16.h new file mode 100644 index 0000000000000000000000000000000000000000..ef9625dfed45f6f494d2911bf358c160712bcb2f --- /dev/null +++ b/libc/src/math/cospif16.h @@ -0,0 +1,21 @@ +//===-- Implementation header for cospif16 ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_COSPIF16_H +#define LLVM_LIBC_SRC_MATH_COSPIF16_H + +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { + +float16 cospif16(float16 x); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_SINPIF16_H diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 35e7347b91362e471427cd33d1367995b3b2fb62..ca27759d3212f274ca926de6ddd91619294b96b1 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -351,6 +351,17 @@ add_header_library( libc.src.__support.common ) +add_header_library( + sincosf16_utils + HDRS + sincosf16_utils.h + DEPENDS + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.polyeval + libc.src.__support.FPUtil.nearest_integer + libc.src.__support.common +) + add_header_library( sincos_eval HDRS @@ -422,6 +433,25 @@ add_entrypoint_object( -O3 ) +add_entrypoint_object( + cospif16 + SRCS + cospif16.cpp + HDRS + ../cospif16.h + DEPENDS + .sincosf16_utils + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.FPUtil.cast + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.macros.optimization + COMPILE_OPTIONS + -O3 +) + add_entrypoint_object( sin SRCS @@ -535,14 +565,14 @@ add_entrypoint_object( HDRS ../sinpif16.h DEPENDS - libc.src.__support.common + .sincosf16_utils + libc.hdr.errno_macros + libc.hdr.fenv_macros libc.src.__support.FPUtil.cast libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.multiply_add - libc.src.__support.FPUtil.nearest_integer - libc.src.__support.FPUtil.polyeval - libc.src.__support.macros.properties.types + libc.src.__support.macros.optimization COMPILE_OPTIONS -O3 ) diff --git a/libc/src/math/generic/atan2.cpp b/libc/src/math/generic/atan2.cpp index c39deebca4d40ecbeda3f5632e67410c89516e05..1b16e15d29d0b31a4669fab15b0ff8252d1dab84 100644 --- a/libc/src/math/generic/atan2.cpp +++ b/libc/src/math/generic/atan2.cpp @@ -230,8 +230,8 @@ LLVM_LIBC_FUNCTION(double, atan2, (double y, double x)) { if (LIBC_UNLIKELY(max_exp > 0x7ffU - 128U || min_exp < 128U)) { if (x_bits.is_nan() || y_bits.is_nan()) return FPBits::quiet_nan().get_val(); - unsigned x_except = x_abs == 0 ? 0 : (FPBits(x_abs).is_inf() ? 2 : 1); - unsigned y_except = y_abs == 0 ? 0 : (FPBits(y_abs).is_inf() ? 2 : 1); + unsigned x_except = x == 0.0 ? 0 : (FPBits(x_abs).is_inf() ? 2 : 1); + unsigned y_except = y == 0.0 ? 0 : (FPBits(y_abs).is_inf() ? 2 : 1); // Exceptional cases: // EXCEPT[y_except][x_except][x_is_neg] diff --git a/libc/src/math/generic/cbrt.cpp b/libc/src/math/generic/cbrt.cpp index 036664c2aafaf46cf2c84ee6fa4ab22127280e98..ee7d69b2c211facf6e416b964d9f965541d40bd3 100644 --- a/libc/src/math/generic/cbrt.cpp +++ b/libc/src/math/generic/cbrt.cpp @@ -151,9 +151,10 @@ LLVM_LIBC_FUNCTION(double, cbrt, (double x)) { if (LIBC_UNLIKELY(x_abs < FPBits::min_normal().uintval() || x_abs >= FPBits::inf().uintval())) { - if (x_abs == 0 || x_abs >= FPBits::inf().uintval()) + if (x == 0.0 || x_abs >= FPBits::inf().uintval()) // x is 0, Inf, or NaN. - return x; + // Make sure it works for FTZ/DAZ modes. + return static_cast(x + x); // x is non-zero denormal number. // Normalize x. @@ -235,10 +236,10 @@ LLVM_LIBC_FUNCTION(double, cbrt, (double x)) { // Lambda function to update the exponent of the result. auto update_exponent = [=](double r) -> double { - uint64_t r_m = FPBits(r).uintval() & 0x800F'FFFF'FFFF'FFFF; + uint64_t r_m = FPBits(r).uintval() - 0x3FF0'0000'0000'0000; // Adjust exponent and sign. uint64_t r_bits = - r_m | (static_cast(out_e) << FPBits::FRACTION_LEN); + r_m + (static_cast(out_e) << FPBits::FRACTION_LEN); return FPBits(r_bits).get_val(); }; diff --git a/libc/src/math/generic/cbrtf.cpp b/libc/src/math/generic/cbrtf.cpp index 313961bf356b830991dd8e693c7953f6b23ae881..0abbf6e879421c05b23602bb588130d4dab7b018 100644 --- a/libc/src/math/generic/cbrtf.cpp +++ b/libc/src/math/generic/cbrtf.cpp @@ -93,9 +93,10 @@ LLVM_LIBC_FUNCTION(float, cbrtf, (float x)) { uint32_t x_abs = x_bits.uintval() & 0x7fff'ffff; uint32_t sign_bit = (x_bits.uintval() >> 31) << DoubleBits::EXP_LEN; - if (LIBC_UNLIKELY(x_abs == 0 || x_abs >= 0x7f80'0000)) { + if (LIBC_UNLIKELY(x == 0.0f || x_abs >= 0x7f80'0000)) { // x is 0, Inf, or NaN. - return x; + // Make sure it works for FTZ/DAZ modes. + return x + x; } double xd = static_cast(x); diff --git a/libc/src/math/generic/cospif16.cpp b/libc/src/math/generic/cospif16.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd8c7ab6afa3d6a012f0891adfff6d9423a4e158 --- /dev/null +++ b/libc/src/math/generic/cospif16.cpp @@ -0,0 +1,81 @@ +//===-- Half-precision cospif function ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/math/cospif16.h" +#include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" +#include "sincosf16_utils.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/cast.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/macros/optimization.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(float16, cospif16, (float16 x)) { + using FPBits = typename fputil::FPBits; + FPBits xbits(x); + + uint16_t x_u = xbits.uintval(); + uint16_t x_abs = x_u & 0x7fff; + float xf = x; + + // Range reduction: + // For |x| > 1/32, we perform range reduction as follows: + // Find k and y such that: + // x = (k + y) * 1/32 + // k is an integer + // |y| < 0.5 + // + // This is done by performing: + // k = round(x * 32) + // y = x * 32 - k + // + // Once k and y are computed, we then deduce the answer by the sine of sum + // formula: + // cos(x * pi) = cos((k + y) * pi/32) + // = cos(k * pi/32) * cos(y * pi/32) + + // sin(y * pi/32) * sin(k * pi/32) + + // For signed zeros + if (LIBC_UNLIKELY(x_abs == 0U)) + return fputil::cast(1.0f); + + // Numbers greater or equal to 2^10 are integers, or infinity, or NaN + if (LIBC_UNLIKELY(x_abs >= 0x6400)) { + if (LIBC_UNLIKELY(x_abs <= 0x67FF)) + return fputil::cast((x_abs & 0x1) ? -1.0f : 1.0f); + + // Check for NaN or infintiy values + if (LIBC_UNLIKELY(x_abs >= 0x7c00)) { + // If value is equal to infinity + if (x_abs == 0x7c00) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + + return x + FPBits::quiet_nan().get_val(); + } + + return fputil::cast(1.0f); + } + + float sin_k, cos_k, sin_y, cosm1_y; + sincospif16_eval(xf, sin_k, cos_k, sin_y, cosm1_y); + + if (LIBC_UNLIKELY(sin_y == 0 && cos_k == 0)) + return fputil::cast(0.0f); + + // Since, cosm1_y = cos_y - 1, therefore: + // cos(x * pi) = cos_k(cosm1_y) + cos_k - sin_k * sin_y + return fputil::cast(fputil::multiply_add( + cos_k, cosm1_y, fputil::multiply_add(-sin_k, sin_y, cos_k))); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/log.cpp b/libc/src/math/generic/log.cpp index 57c70e31730bf6bd62a917f40446d2dd50171588..4302c64c8abac86723e69d3643cf4b71489f31e3 100644 --- a/libc/src/math/generic/log.cpp +++ b/libc/src/math/generic/log.cpp @@ -749,7 +749,7 @@ LLVM_LIBC_FUNCTION(double, log, (double x)) { if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::min_normal().uintval() || xbits.uintval() > FPBits_t::max_normal().uintval())) { - if (xbits.is_zero()) { + if (x == 0.0) { // return -Inf and raise FE_DIVBYZERO. fputil::set_errno_if_required(ERANGE); fputil::raise_except_if_required(FE_DIVBYZERO); diff --git a/libc/src/math/generic/log10.cpp b/libc/src/math/generic/log10.cpp index b99b22b024fe3cc96399ee26389551c4f58b5462..7df57ef85b81b96e9aa0a4aefdb724445275f9f4 100644 --- a/libc/src/math/generic/log10.cpp +++ b/libc/src/math/generic/log10.cpp @@ -751,7 +751,7 @@ LLVM_LIBC_FUNCTION(double, log10, (double x)) { if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::min_normal().uintval() || xbits.uintval() > FPBits_t::max_normal().uintval())) { - if (xbits.is_zero()) { + if (x == 0.0) { // return -Inf and raise FE_DIVBYZERO. fputil::set_errno_if_required(ERANGE); fputil::raise_except_if_required(FE_DIVBYZERO); diff --git a/libc/src/math/generic/log10f.cpp b/libc/src/math/generic/log10f.cpp index f7dd85cc08bf036f1738e9b7d3fa29ef3ec2d169..c635fa4ef9b63fae8806d499ca41f85be2387465 100644 --- a/libc/src/math/generic/log10f.cpp +++ b/libc/src/math/generic/log10f.cpp @@ -164,7 +164,7 @@ LLVM_LIBC_FUNCTION(float, log10f, (float x)) { if (LIBC_UNLIKELY(x_u < FPBits::min_normal().uintval() || x_u > FPBits::max_normal().uintval())) { - if (xbits.is_zero()) { + if (x == 0.0f) { // Return -inf and raise FE_DIVBYZERO fputil::set_errno_if_required(ERANGE); fputil::raise_except_if_required(FE_DIVBYZERO); diff --git a/libc/src/math/generic/log1p.cpp b/libc/src/math/generic/log1p.cpp index f301a5aba3a57c4cbd6161eacabc26a4945a684d..43eb8a924aef476f9b4c11474d75135b634d8f1f 100644 --- a/libc/src/math/generic/log1p.cpp +++ b/libc/src/math/generic/log1p.cpp @@ -927,8 +927,8 @@ LLVM_LIBC_FUNCTION(double, log1p, (double x)) { // log(1 + x) = nextafter(x, -inf) for FE_DOWNWARD, or // FE_TOWARDZERO and x > 0, // = x otherwise. - if (LIBC_UNLIKELY(xbits.is_zero())) - return x; + if (x == 0.0) + return x + x; // Handle FTZ/DAZ correctly. volatile float tp = 1.0f; volatile float tn = -1.0f; @@ -943,7 +943,7 @@ LLVM_LIBC_FUNCTION(double, log1p, (double x)) { return FPBits_t(x_u + 1).get_val(); } - return x; + return (x + x == 0.0) ? x + x : x; } x_dd = fputil::exact_add(1.0, x); } diff --git a/libc/src/math/generic/log2.cpp b/libc/src/math/generic/log2.cpp index 7d868e2f6f61985986bdcf64c2faefe2c9668d9a..37ea0c8f13431551a886e8bf71f4ff49a300dfc6 100644 --- a/libc/src/math/generic/log2.cpp +++ b/libc/src/math/generic/log2.cpp @@ -871,7 +871,7 @@ LLVM_LIBC_FUNCTION(double, log2, (double x)) { if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::min_normal().uintval() || xbits.uintval() > FPBits_t::max_normal().uintval())) { - if (xbits.is_zero()) { + if (x == 0.0) { // return -Inf and raise FE_DIVBYZERO. fputil::set_errno_if_required(ERANGE); fputil::raise_except_if_required(FE_DIVBYZERO); diff --git a/libc/src/math/generic/log2f.cpp b/libc/src/math/generic/log2f.cpp index 9cad02d796b189c266b2c64dc436d67695a3f0e1..111f3f130bcab18f9c96a2f79c5eddcdcb674749 100644 --- a/libc/src/math/generic/log2f.cpp +++ b/libc/src/math/generic/log2f.cpp @@ -72,7 +72,7 @@ LLVM_LIBC_FUNCTION(float, log2f, (float x)) { // Exceptional inputs. if (LIBC_UNLIKELY(x_u < FPBits::min_normal().uintval() || x_u > FPBits::max_normal().uintval())) { - if (xbits.is_zero()) { + if (x == 0.0f) { fputil::set_errno_if_required(ERANGE); fputil::raise_except_if_required(FE_DIVBYZERO); return FPBits::inf(Sign::NEG).get_val(); diff --git a/libc/src/math/generic/logf.cpp b/libc/src/math/generic/logf.cpp index f8ecf320568ac716f4106bf5fe26c6108a3c370f..30c00edafe21d86aa1504e43b2af37bb91f7089b 100644 --- a/libc/src/math/generic/logf.cpp +++ b/libc/src/math/generic/logf.cpp @@ -82,7 +82,7 @@ LLVM_LIBC_FUNCTION(float, logf, (float x)) { } // Subnormal inputs. if (LIBC_UNLIKELY(x_u < FPBits::min_normal().uintval())) { - if (x_u == 0) { + if (x == 0.0f) { // Return -inf and raise FE_DIVBYZERO fputil::set_errno_if_required(ERANGE); fputil::raise_except_if_required(FE_DIVBYZERO); diff --git a/libc/src/math/generic/pow.cpp b/libc/src/math/generic/pow.cpp index 181d3d40b3c9adf8fce3ece9ea88334bb3eff0f0..213dbd959039c30e29ae5539880504c283645d3b 100644 --- a/libc/src/math/generic/pow.cpp +++ b/libc/src/math/generic/pow.cpp @@ -228,16 +228,18 @@ LLVM_LIBC_FUNCTION(double, pow, (double x, double y)) { x_u >= FPBits::inf().uintval() || x_u < FPBits::min_normal().uintval())) { // Exceptional exponents. - switch (y_a) { - case 0: // y = +-0.0 + if (y == 0.0) return 1.0; + + switch (y_a) { case 0x3fe0'0000'0000'0000: { // y = +-0.5 // TODO: speed up x^(-1/2) with rsqrt(x) when available. - if (LIBC_UNLIKELY(!y_sign && (x_u == FPBits::zero(Sign::NEG).uintval() || - x_u == FPBits::inf(Sign::NEG).uintval()))) { + if (LIBC_UNLIKELY( + (x == 0.0 || x_u == FPBits::inf(Sign::NEG).uintval()))) { // pow(-0, 1/2) = +0 // pow(-inf, 1/2) = +inf - return FPBits(x_abs).get_val(); + // Make sure it works correctly for FTZ/DAZ. + return y_sign ? 1.0 / (x * x) : (x * x); } return y_sign ? (1.0 / fputil::sqrt(x)) : fputil::sqrt(x); } @@ -269,7 +271,7 @@ LLVM_LIBC_FUNCTION(double, pow, (double x, double y)) { return 1.0; } - if (x_a == 0 && y_sign) { + if (x == 0.0 && y_sign) { // pow(+-0, -Inf) = +inf and raise FE_DIVBYZERO fputil::set_errno_if_required(EDOM); fputil::raise_except_if_required(FE_DIVBYZERO); @@ -298,7 +300,7 @@ LLVM_LIBC_FUNCTION(double, pow, (double x, double y)) { // TODO: Speed things up with pow(2, y) = exp2(y) and pow(10, y) = exp10(y). - if (x_a == 0) { + if (x == 0.0) { bool out_is_neg = x_sign && is_odd_integer(y); if (y_sign) { // pow(0, negative number) = inf diff --git a/libc/src/math/generic/powf.cpp b/libc/src/math/generic/powf.cpp index 83477c6ef2acebae6acb48bfa7d7bcff9f8ac61f..c84ce0da34b10a315bc4b44ea0be8e8bc7ba877d 100644 --- a/libc/src/math/generic/powf.cpp +++ b/libc/src/math/generic/powf.cpp @@ -529,10 +529,10 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) { // Hence x^y will either overflow or underflow if x is not zero. if (LIBC_UNLIKELY((y_abs & 0x0007'ffff) == 0) || (y_abs > 0x4f170000)) { // Exceptional exponents. - switch (y_abs) { - case 0x0000'0000: { // y = +-0.0f + if (y == 0.0f) return 1.0f; - } + + switch (y_abs) { case 0x7f80'0000: { // y = +-Inf if (x_abs > 0x7f80'0000) { // pow(NaN, +-Inf) = NaN @@ -542,7 +542,7 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) { // pow(+-1, +-Inf) = 1.0f return 1.0f; } - if (x_abs == 0 && y_u == 0xff80'0000) { + if (x == 0.0f && y_u == 0xff80'0000) { // pow(+-0, -Inf) = +inf and raise FE_DIVBYZERO fputil::set_errno_if_required(EDOM); fputil::raise_except_if_required(FE_DIVBYZERO); @@ -561,12 +561,15 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) { switch (y_u) { case 0x3f00'0000: // y = 0.5f // pow(x, 1/2) = sqrt(x) - if (LIBC_UNLIKELY(x_u == 0x8000'0000 || x_u == 0xff80'0000)) { + if (LIBC_UNLIKELY(x == 0.0f || x_u == 0xff80'0000)) { // pow(-0, 1/2) = +0 // pow(-inf, 1/2) = +inf - return FloatBits(x_abs).get_val(); + // Make sure it is correct for FTZ/DAZ. + return x * x; } - return fputil::sqrt(x); + float r; + r = fputil::sqrt(x); + return (FloatBits(r).uintval() != 0x8000'0000) ? r : 0.0f; case 0x3f80'0000: // y = 1.0f return x; case 0x4000'0000: // y = 2.0f @@ -634,8 +637,7 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) { const bool x_is_neg = x_u >= FloatBits::SIGN_MASK; - switch (x_abs) { - case 0x0000'0000: { // x = +-0.0f + if (x == 0.0f) { const bool out_is_neg = x_is_neg && is_odd_integer(FloatBits(y_u).get_val()); if (y_u > 0x8000'0000U) { @@ -647,7 +649,9 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) { // pow(0, positive number) = 0 return out_is_neg ? -0.0f : 0.0f; } - case 0x7f80'0000: { // x = +-Inf + + if (x_abs == 0x7f80'0000) { + // x = +-Inf const bool out_is_neg = x_is_neg && is_odd_integer(FloatBits(y_u).get_val()); if (y_u >= FloatBits::SIGN_MASK) { @@ -655,7 +659,6 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) { } return FloatBits::inf(out_is_neg ? Sign::NEG : Sign::POS).get_val(); } - } if (x_abs > 0x7f80'0000) { // x is NaN. diff --git a/libc/src/math/generic/sin.cpp b/libc/src/math/generic/sin.cpp index 2e1d3ffd5f37d80f747cf0fbee2319ffaf2ee1ce..b32486dff487cad748dccee3a763a9d456f40014 100644 --- a/libc/src/math/generic/sin.cpp +++ b/libc/src/math/generic/sin.cpp @@ -50,7 +50,7 @@ LLVM_LIBC_FUNCTION(double, sin, (double x)) { if (LIBC_UNLIKELY(x_e < FPBits::EXP_BIAS - 26)) { // Signed zeros. if (LIBC_UNLIKELY(x == 0.0)) - return x; + return x + x; // Make sure it works with FTZ/DAZ. #ifdef LIBC_TARGET_CPU_HAS_FMA return fputil::multiply_add(x, -0x1.0p-54, x); diff --git a/libc/src/math/generic/sincosf16_utils.h b/libc/src/math/generic/sincosf16_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..83511755a56c42d1e822436c90851e173c1e2896 --- /dev/null +++ b/libc/src/math/generic/sincosf16_utils.h @@ -0,0 +1,77 @@ +//===-- Collection of utils for sinf16/cosf16 -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_GENERIC_SINCOSF16_UTILS_H +#define LLVM_LIBC_SRC_MATH_GENERIC_SINCOSF16_UTILS_H + +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +// Lookup table for sin(k * pi / 32) with k = 0, ..., 63. +// Table is generated with Sollya as follows: +// > display = hexadecimmal; +// > for k from 0 to 63 do { round(sin(k * pi/32), SG, RN); }; +constexpr float SIN_K_PI_OVER_32[64] = { + 0x0.0p0, 0x1.917a6cp-4, 0x1.8f8b84p-3, 0x1.294062p-2, + 0x1.87de2ap-2, 0x1.e2b5d4p-2, 0x1.1c73b4p-1, 0x1.44cf32p-1, + 0x1.6a09e6p-1, 0x1.8bc806p-1, 0x1.a9b662p-1, 0x1.c38b3p-1, + 0x1.d906bcp-1, 0x1.e9f416p-1, 0x1.f6297cp-1, 0x1.fd88dap-1, + 0x1p0, 0x1.fd88dap-1, 0x1.f6297cp-1, 0x1.e9f416p-1, + 0x1.d906bcp-1, 0x1.c38b3p-1, 0x1.a9b662p-1, 0x1.8bc806p-1, + 0x1.6a09e6p-1, 0x1.44cf32p-1, 0x1.1c73b4p-1, 0x1.e2b5d4p-2, + 0x1.87de2ap-2, 0x1.294062p-2, 0x1.8f8b84p-3, 0x1.917a6cp-4, + 0x0.0p0, -0x1.917a6cp-4, -0x1.8f8b84p-3, -0x1.294062p-2, + -0x1.87de2ap-2, -0x1.e2b5d4p-2, -0x1.1c73b4p-1, -0x1.44cf32p-1, + -0x1.6a09e6p-1, -0x1.8bc806p-1, -0x1.a9b662p-1, -0x1.c38b3p-1, + -0x1.d906bcp-1, -0x1.e9f416p-1, -0x1.f6297ep-1, -0x1.fd88dap-1, + -0x1p0, -0x1.fd88dap-1, -0x1.f6297cp-1, -0x1.e9f416p-1, + -0x1.d906bcp-1, -0x1.c38b3p-1, -0x1.a9b662p-1, -0x1.8bc806p-1, + -0x1.6a09e6p-1, -0x1.44cf32p-1, -0x1.1c73b4p-1, -0x1.e2b5d4p-2, + -0x1.87de2ap-2, -0x1.294062p-2, -0x1.8f8b84p-3, -0x1.917a6cp-4}; + +LIBC_INLINE int32_t range_reduction_sincospif16(float x, float &y) { + float kf = fputil::nearest_integer(x * 32); + y = fputil::multiply_add(x, 32.0, -kf); + + return static_cast(kf); +} + +LIBC_INLINE void sincospif16_eval(float xf, float &sin_k, float &cos_k, + float &sin_y, float &cosm1_y) { + float y; + int32_t k = range_reduction_sincospif16(xf, y); + + sin_k = SIN_K_PI_OVER_32[k & 63]; + cos_k = SIN_K_PI_OVER_32[(k + 16) & 63]; + + // Recall, after range reduction, -0.5 <= y <= 0.5. For very small values of + // y, calculating sin(y * p/32) can be inaccurate. Generating a polynomial for + // sin(y * p/32)/y instead significantly reduces the relative errors. + float ysq = y * y; + + // Degree-6 minimax even polynomial for sin(y*pi/32)/y generated by Sollya + // with: + // > Q = fpminimax(sin(y * pi/32)/y, [|0, 2, 4, 6|], [|SG...|], [0, 0.5]); + sin_y = y * fputil::polyeval(ysq, 0x1.921fb6p-4f, -0x1.4aeabcp-13f, + 0x1.a03354p-21f, -0x1.ad02d2p-20f); + + // Degree-6 minimax even polynomial for cos(y*pi/32) generated by Sollya + // with: + // > P = fpminimax(cos(y * pi/32), [|0, 2, 4, 6|],[|1, SG...|], [0, 0.5]); + cosm1_y = ysq * fputil::polyeval(ysq, -0x1.3bd3ccp-8f, 0x1.03a61ap-18f, + 0x1.a6f7a2p-29f); +} + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_GENERIC_SINCOSF16_UTILS_H diff --git a/libc/src/math/generic/sinpif16.cpp b/libc/src/math/generic/sinpif16.cpp index 17cca583e0c0ec7e9a76d72d72cd8aee2e89c9b8..51ea595653b4da71ec6945ac367e16bb4a0a0824 100644 --- a/libc/src/math/generic/sinpif16.cpp +++ b/libc/src/math/generic/sinpif16.cpp @@ -7,52 +7,23 @@ //===----------------------------------------------------------------------===// #include "src/math/sinpif16.h" +#include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" +#include "sincosf16_utils.h" #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" #include "src/__support/FPUtil/cast.h" #include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/FPUtil/nearest_integer.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" namespace LIBC_NAMESPACE_DECL { -// Lookup table for sin(k * pi / 32) with k = 0, ..., 63. -// Table is generated with Sollya as follows: -// > display = hexadecimmal; -// > for k from 0 to 63 do { round(sin(k * pi/32), SG, RN); }; -static constexpr float SIN_K_PI_OVER_32[64] = { - 0x0.0p0, 0x1.917a6cp-4, 0x1.8f8b84p-3, 0x1.294062p-2, - 0x1.87de2ap-2, 0x1.e2b5d4p-2, 0x1.1c73b4p-1, 0x1.44cf32p-1, - 0x1.6a09e6p-1, 0x1.8bc806p-1, 0x1.a9b662p-1, 0x1.c38b3p-1, - 0x1.d906bcp-1, 0x1.e9f416p-1, 0x1.f6297cp-1, 0x1.fd88dap-1, - 0x1p0, 0x1.fd88dap-1, 0x1.f6297cp-1, 0x1.e9f416p-1, - 0x1.d906bcp-1, 0x1.c38b3p-1, 0x1.a9b662p-1, 0x1.8bc806p-1, - 0x1.6a09e6p-1, 0x1.44cf32p-1, 0x1.1c73b4p-1, 0x1.e2b5d4p-2, - 0x1.87de2ap-2, 0x1.294062p-2, 0x1.8f8b84p-3, 0x1.917a6cp-4, - 0x0.0p0, -0x1.917a6cp-4, -0x1.8f8b84p-3, -0x1.294062p-2, - -0x1.87de2ap-2, -0x1.e2b5d4p-2, -0x1.1c73b4p-1, -0x1.44cf32p-1, - -0x1.6a09e6p-1, -0x1.8bc806p-1, -0x1.a9b662p-1, -0x1.c38b3p-1, - -0x1.d906bcp-1, -0x1.e9f416p-1, -0x1.f6297ep-1, -0x1.fd88dap-1, - -0x1p0, -0x1.fd88dap-1, -0x1.f6297cp-1, -0x1.e9f416p-1, - -0x1.d906bcp-1, -0x1.c38b3p-1, -0x1.a9b662p-1, -0x1.8bc806p-1, - -0x1.6a09e6p-1, -0x1.44cf32p-1, -0x1.1c73b4p-1, -0x1.e2b5d4p-2, - -0x1.87de2ap-2, -0x1.294062p-2, -0x1.8f8b84p-3, -0x1.917a6cp-4}; - -static LIBC_INLINE int32_t range_reduction(float x, float &y) { - float kf = fputil::nearest_integer(x * 32); - y = fputil::multiply_add(x, 32.0, -kf); - - return static_cast(kf); -} - LLVM_LIBC_FUNCTION(float16, sinpif16, (float16 x)) { using FPBits = typename fputil::FPBits; FPBits xbits(x); uint16_t x_u = xbits.uintval(); uint16_t x_abs = x_u & 0x7fff; + float xf = x; // Range reduction: // For |x| > 1/32, we perform range reduction as follows: @@ -68,12 +39,8 @@ LLVM_LIBC_FUNCTION(float16, sinpif16, (float16 x)) { // Once k and y are computed, we then deduce the answer by the sine of sum // formula: // sin(x * pi) = sin((k + y) * pi/32) - // = sin(k * pi/32) * cos(y * pi/32) + sin (y * pi/32) * cos (k * - // pi/32) - // The values of sin(k * pi/32) and cos (k * pi/32) for k = 0...63 are - // precomputed and stored using a vector of 64 single precision floats. sin(y - // * pi/32) and cos(y * pi/32) are computed using degree-9 chebyshev - // polynomials generated by Sollya. + // = sin(k * pi/32) * cos(y * pi/32) + + // sin(y * pi/32) * cos(k * pi/32) // For signed zeros if (LIBC_UNLIKELY(x_abs == 0U)) @@ -94,36 +61,8 @@ LLVM_LIBC_FUNCTION(float16, sinpif16, (float16 x)) { return FPBits::zero(xbits.sign()).get_val(); } - float f32 = x; - float y; - int32_t k = range_reduction(f32, y); - - float sin_k = SIN_K_PI_OVER_32[k & 63]; - float cos_k = SIN_K_PI_OVER_32[(k + 16) & 63]; - - // Recall; - // sin(x * pi/32) = sin((k + y) * pi/32) - // = sin(y * pi/32) * cos(k * pi/32) + cos(y * pi/32) * sin(k * - // pi/32) Recall, after range reduction, -0.5 <= y <= 0.5. For very small - // values of y, calculating sin(y * p/32) can be inaccurate. Generating a - // polynomial for sin(y * p/32)/y instead significantly reduces the relative - // errors. - float ysq = y * y; - - // Degree-6 minimax even polynomial for sin(y*pi/32)/y generated by Sollya - // with: > Q = fpminimax(sin(y*pi/32)/y, [|0, 2, 4, 6|], [|SG...|], [0, 0.5]); - float sin_y = y * fputil::polyeval(ysq, 0x1.921fb6p-4f, -0x1.4aeabcp-13f, - 0x1.a03354p-21f, -0x1.ad02d2p-20f); - - // Note that cosm1_y = cos(y*pi/32) - 1 = cos_y - 1 - // Derivation: - // sin(x * pi) = sin((k + y) * pi/32) - // = sin_y * cos_k + cos_y * sin_k - // = cos_k * sin_y + sin_k * (1 + cos_y - 1) - // Degree-6 minimax even polynomial for cos(y*pi/32) generated by Sollya with: - // > P = fpminimax(cos(y*pi/32), [|0, 2, 4, 6|],[|1, SG...|], [0, 0.5]); - float cosm1_y = ysq * fputil::polyeval(ysq, -0x1.3bd3ccp-8f, 0x1.03a61ap-18f, - 0x1.a6f7a2p-29f); + float sin_k, cos_k, sin_y, cosm1_y; + sincospif16_eval(xf, sin_k, cos_k, sin_y, cosm1_y); if (LIBC_UNLIKELY(sin_y == 0 && sin_k == 0)) return FPBits::zero(xbits.sign()).get_val(); @@ -133,4 +72,5 @@ LLVM_LIBC_FUNCTION(float16, sinpif16, (float16 x)) { return fputil::cast(fputil::multiply_add( sin_y, cos_k, fputil::multiply_add(cosm1_y, sin_k, sin_k))); } + } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/tan.cpp b/libc/src/math/generic/tan.cpp index f9be25ed866e1d054cb630a26a96789f17d41dbc..19d31a8441efb68baf1c2795c281cdefcd517296 100644 --- a/libc/src/math/generic/tan.cpp +++ b/libc/src/math/generic/tan.cpp @@ -138,7 +138,7 @@ LLVM_LIBC_FUNCTION(double, tan, (double x)) { if (LIBC_UNLIKELY(x_e < FPBits::EXP_BIAS - 27)) { // Signed zeros. if (LIBC_UNLIKELY(x == 0.0)) - return x; + return x + x; // Make sure it works with FTZ/DAZ. #ifdef LIBC_TARGET_CPU_HAS_FMA return fputil::multiply_add(x, 0x1.0p-54, x); diff --git a/libc/src/spawn/linux/CMakeLists.txt b/libc/src/spawn/linux/CMakeLists.txt index 9ef3a9d18b0c690ffb708306b0bd44860b6200ab..26148fe1c76dbdc7d6865860d768bbf79e0c5d84 100644 --- a/libc/src/spawn/linux/CMakeLists.txt +++ b/libc/src/spawn/linux/CMakeLists.txt @@ -5,7 +5,8 @@ add_entrypoint_object( HDRS ../posix_spawn.h DEPENDS - libc.include.fcntl + libc.hdr.types.mode_t + libc.hdr.fcntl_macros libc.include.spawn libc.include.sys_syscall libc.include.signal diff --git a/libc/src/spawn/linux/posix_spawn.cpp b/libc/src/spawn/linux/posix_spawn.cpp index 4c0469b3ce384a24ec342ecda605de43f2e2e097..fe82ba260148a61eb9036b7a3df2526b3d1b6243 100644 --- a/libc/src/spawn/linux/posix_spawn.cpp +++ b/libc/src/spawn/linux/posix_spawn.cpp @@ -14,7 +14,8 @@ #include "src/__support/macros/config.h" #include "src/spawn/file_actions.h" -#include +#include "hdr/fcntl_macros.h" +#include "hdr/types/mode_t.h" #include // For SIGCHLD #include #include // For syscall numbers. diff --git a/libc/src/stdio/gpu/fprintf.cpp b/libc/src/stdio/gpu/fprintf.cpp index 6222589cc4bab96eaa6e49f7cda3b2a1370b39a5..46196d7d2b10f55df536ec16780073c24ca4dc31 100644 --- a/libc/src/stdio/gpu/fprintf.cpp +++ b/libc/src/stdio/gpu/fprintf.cpp @@ -16,7 +16,7 @@ #include -namespace LIBC_NAMESPACE { +namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(int, fprintf, (::FILE *__restrict stream, const char *__restrict format, @@ -29,4 +29,4 @@ LLVM_LIBC_FUNCTION(int, fprintf, return ret_val; } -} // namespace LIBC_NAMESPACE +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/gpu/printf.cpp b/libc/src/stdio/gpu/printf.cpp index d9903193ef1658b33f8e3e94916ac9f563a38bd9..be1885fd6801d07a7cebc22892b76cdb57d31165 100644 --- a/libc/src/stdio/gpu/printf.cpp +++ b/libc/src/stdio/gpu/printf.cpp @@ -15,7 +15,7 @@ #include -namespace LIBC_NAMESPACE { +namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { va_list vlist; @@ -26,4 +26,4 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { return ret_val; } -} // namespace LIBC_NAMESPACE +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/gpu/vfprintf.cpp b/libc/src/stdio/gpu/vfprintf.cpp index 961cfa48579e0af60702191d8a43908476b6e5f7..c92685f48c728ba088f7ca884bf224800490a579 100644 --- a/libc/src/stdio/gpu/vfprintf.cpp +++ b/libc/src/stdio/gpu/vfprintf.cpp @@ -14,7 +14,7 @@ #include "src/errno/libc_errno.h" #include "src/stdio/gpu/vfprintf_utils.h" -namespace LIBC_NAMESPACE { +namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(int, vfprintf, (::FILE *__restrict stream, const char *__restrict format, @@ -24,4 +24,4 @@ LLVM_LIBC_FUNCTION(int, vfprintf, return ret_val; } -} // namespace LIBC_NAMESPACE +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/gpu/vfprintf_utils.h b/libc/src/stdio/gpu/vfprintf_utils.h index 93ce1649869fc10e3770e430894a815b2d2794bc..5010ee16d96074abe1264159e3c18de1b1e3c78e 100644 --- a/libc/src/stdio/gpu/vfprintf_utils.h +++ b/libc/src/stdio/gpu/vfprintf_utils.h @@ -9,10 +9,11 @@ #include "hdr/types/FILE.h" #include "src/__support/RPC/rpc_client.h" #include "src/__support/arg_list.h" +#include "src/__support/macros/config.h" #include "src/stdio/gpu/file.h" #include "src/string/string_utils.h" -namespace LIBC_NAMESPACE { +namespace LIBC_NAMESPACE_DECL { template LIBC_INLINE int vfprintf_impl(::FILE *__restrict file, @@ -82,4 +83,4 @@ LIBC_INLINE int vfprintf_internal(::FILE *__restrict stream, #endif } -} // namespace LIBC_NAMESPACE +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/gpu/vprintf.cpp b/libc/src/stdio/gpu/vprintf.cpp index 2bb74d7f017b594108a7d7a8f32bd94240b57137..54012f3071844d51f23d72eba41fb795c9608bd3 100644 --- a/libc/src/stdio/gpu/vprintf.cpp +++ b/libc/src/stdio/gpu/vprintf.cpp @@ -13,7 +13,7 @@ #include "src/errno/libc_errno.h" #include "src/stdio/gpu/vfprintf_utils.h" -namespace LIBC_NAMESPACE { +namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(int, vprintf, (const char *__restrict format, va_list vlist)) { @@ -22,4 +22,4 @@ LLVM_LIBC_FUNCTION(int, vprintf, return ret_val; } -} // namespace LIBC_NAMESPACE +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/linux/CMakeLists.txt b/libc/src/stdio/linux/CMakeLists.txt index d6241e1ca0439d8b2cc34fe1812af731aba2139d..1b2fcb33ce54d7f34baa3e091164537ce0f2f86b 100644 --- a/libc/src/stdio/linux/CMakeLists.txt +++ b/libc/src/stdio/linux/CMakeLists.txt @@ -5,7 +5,7 @@ add_entrypoint_object( HDRS ../remove.h DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.unistd libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -22,6 +22,7 @@ add_entrypoint_object( libc.include.sys_syscall libc.src.__support.OSUtil.osutil libc.src.errno.errno + libc.hdr.fcntl_macros ) add_entrypoint_object( diff --git a/libc/src/stdio/linux/remove.cpp b/libc/src/stdio/linux/remove.cpp index 9e299aaf43e450bca6b2dd7d0f0300aeba0b71ca..dbb4491d0e6cc1cb99aa49dfd363a50d0d73d977 100644 --- a/libc/src/stdio/linux/remove.cpp +++ b/libc/src/stdio/linux/remove.cpp @@ -11,9 +11,9 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "hdr/fcntl_macros.h" // For AT_* macros. #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include // For AT_* macros. #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/stdio/linux/rename.cpp b/libc/src/stdio/linux/rename.cpp index 69fd22720ed195755be2d063b0031b959b0cc53a..fbcb29be48f4e24773cdc0df32786cb84b1147d9 100644 --- a/libc/src/stdio/linux/rename.cpp +++ b/libc/src/stdio/linux/rename.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/stdio/rename.h" -#include "include/llvm-libc-macros/linux/fcntl-macros.h" +#include "hdr/fcntl_macros.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" #include "src/__support/macros/config.h" diff --git a/libc/src/stdio/vsscanf.h b/libc/src/stdio/vsscanf.h index 992c44d3d95b9a718ad3ae8f9975fe5447ebdebf..c57b1743e477e1b723fbaf659636671d7be6bb13 100644 --- a/libc/src/stdio/vsscanf.h +++ b/libc/src/stdio/vsscanf.h @@ -9,12 +9,14 @@ #ifndef LLVM_LIBC_SRC_STDIO_VSSCANF_H #define LLVM_LIBC_SRC_STDIO_VSSCANF_H +#include "src/__support/macros/config.h" + #include -namespace LIBC_NAMESPACE { +namespace LIBC_NAMESPACE_DECL { int vsscanf(const char *s, const char *format, va_list vlist); -} // namespace LIBC_NAMESPACE +} // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC_STDIO_VSSCANF_H diff --git a/libc/src/sys/mman/linux/CMakeLists.txt b/libc/src/sys/mman/linux/CMakeLists.txt index 11188254cfbd4596a2ef15a1d927abaa25d3a7aa..47c16f79bc8d580627325b8c9c1b8f00d57f04c0 100644 --- a/libc/src/sys/mman/linux/CMakeLists.txt +++ b/libc/src/sys/mman/linux/CMakeLists.txt @@ -187,8 +187,7 @@ add_entrypoint_object( ../shm_open.h DEPENDS libc.src.fcntl.open - libc.include.llvm-libc-macros.fcntl_macros - libc.include.llvm-libc-types.mode_t + libc.hdr.types.mode_t .shm_common ) diff --git a/libc/src/sys/mman/linux/shm_open.cpp b/libc/src/sys/mman/linux/shm_open.cpp index d235e57aefdeb13502e9c69d39a93237f170d8cc..11de482272d00a608a9cc0cf7d7bb0988a194c3d 100644 --- a/libc/src/sys/mman/linux/shm_open.cpp +++ b/libc/src/sys/mman/linux/shm_open.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/sys/mman/shm_open.h" -#include "llvm-libc-macros/fcntl-macros.h" +#include "hdr/types/mode_t.h" #include "src/__support/macros/config.h" #include "src/fcntl/open.h" #include "src/sys/mman/linux/shm_common.h" diff --git a/libc/src/sys/mman/shm_open.h b/libc/src/sys/mman/shm_open.h index c890304aa4acf9b6aea4cd0ae8fdfde9b1850b75..1872dd30cb6f5e3d37576875d1d3a9ea624480a6 100644 --- a/libc/src/sys/mman/shm_open.h +++ b/libc/src/sys/mman/shm_open.h @@ -9,8 +9,8 @@ #ifndef LLVM_LIBC_SRC_SYS_MMAN_SHM_OPEN_H #define LLVM_LIBC_SRC_SYS_MMAN_SHM_OPEN_H +#include "hdr/types/mode_t.h" #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/stat/linux/CMakeLists.txt b/libc/src/sys/stat/linux/CMakeLists.txt index 415d2fa5c87715dc805cb3f9ae36cf8afb54059f..9aeb14636c2c1a5fb982dd139165235493499225 100644 --- a/libc/src/sys/stat/linux/CMakeLists.txt +++ b/libc/src/sys/stat/linux/CMakeLists.txt @@ -5,7 +5,8 @@ add_entrypoint_object( HDRS ../chmod.h DEPENDS - libc.include.fcntl + libc.hdr.types.mode_t + libc.hdr.fcntl_macros libc.include.sys_stat libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -19,6 +20,7 @@ add_entrypoint_object( HDRS ../fchmod.h DEPENDS + libc.hdr.types.mode_t libc.include.sys_stat libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -45,7 +47,8 @@ add_entrypoint_object( HDRS ../mkdir.h DEPENDS - libc.include.fcntl + libc.hdr.types.mode_t + libc.hdr.fcntl_macros libc.include.sys_stat libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -84,7 +87,7 @@ add_entrypoint_object( ../stat.h DEPENDS .kernel_statx - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.sys_stat libc.src.errno.errno ) @@ -97,7 +100,7 @@ add_entrypoint_object( ../lstat.h DEPENDS .kernel_statx - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.sys_stat libc.src.errno.errno ) @@ -110,7 +113,7 @@ add_entrypoint_object( ../fstat.h DEPENDS .kernel_statx - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.sys_stat libc.src.errno.errno ) diff --git a/libc/src/sys/stat/linux/chmod.cpp b/libc/src/sys/stat/linux/chmod.cpp index c91cabb514a8c9ddb1e620a80f83a6372c5e58a9..57d5bae6b81915c60ea52b50fb763f4f2d28966a 100644 --- a/libc/src/sys/stat/linux/chmod.cpp +++ b/libc/src/sys/stat/linux/chmod.cpp @@ -11,9 +11,10 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "hdr/fcntl_macros.h" +#include "hdr/types/mode_t.h" #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include #include #include // For syscall numbers. diff --git a/libc/src/sys/stat/linux/fchmod.cpp b/libc/src/sys/stat/linux/fchmod.cpp index 7b6c7b7091a823950ecdd719c5b87b112185d3b5..0d6fd359169aaff0f31704b71b9295680cc3ed6e 100644 --- a/libc/src/sys/stat/linux/fchmod.cpp +++ b/libc/src/sys/stat/linux/fchmod.cpp @@ -11,9 +11,9 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "hdr/types/mode_t.h" #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include #include #include // For syscall numbers. diff --git a/libc/src/sys/stat/linux/fstat.cpp b/libc/src/sys/stat/linux/fstat.cpp index 411aa47bcda2ad3305ac3e46b45cf0a7578e661a..35cf8f08f782d25e3fa8125299d1aa13678343fa 100644 --- a/libc/src/sys/stat/linux/fstat.cpp +++ b/libc/src/sys/stat/linux/fstat.cpp @@ -13,7 +13,7 @@ #include "src/__support/common.h" -#include +#include "hdr/fcntl_macros.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/stat/linux/lstat.cpp b/libc/src/sys/stat/linux/lstat.cpp index 5a6eff068d1dd79a6944216d56ee7ab6b9b13ce2..354c5b6e029a44b906ddf2627952a97ee88b6679 100644 --- a/libc/src/sys/stat/linux/lstat.cpp +++ b/libc/src/sys/stat/linux/lstat.cpp @@ -14,7 +14,7 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" -#include +#include "hdr/fcntl_macros.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/sys/stat/linux/mkdir.cpp b/libc/src/sys/stat/linux/mkdir.cpp index 527c3d2058d2b7299e3fed504f716576f7eb72f0..b319b5c8393de755d375804bed5f83f883c8c4e4 100644 --- a/libc/src/sys/stat/linux/mkdir.cpp +++ b/libc/src/sys/stat/linux/mkdir.cpp @@ -11,9 +11,10 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "hdr/fcntl_macros.h" +#include "hdr/types/mode_t.h" #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include #include #include // For syscall numbers. diff --git a/libc/src/sys/stat/linux/stat.cpp b/libc/src/sys/stat/linux/stat.cpp index c5149e6e3c8839370c357ded8d333d961fa454f6..de9cdb197d687ce73c4f1ffea9409a950d091ebe 100644 --- a/libc/src/sys/stat/linux/stat.cpp +++ b/libc/src/sys/stat/linux/stat.cpp @@ -13,7 +13,7 @@ #include "src/__support/common.h" -#include +#include "hdr/fcntl_macros.h" #include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt index 9b0d752cefbd8e57a7f86d65f4ba4d4628a67067..472438ca72e49e4bbfa9966543496f2f9f9e4c61 100644 --- a/libc/src/unistd/linux/CMakeLists.txt +++ b/libc/src/unistd/linux/CMakeLists.txt @@ -5,6 +5,7 @@ add_entrypoint_object( HDRS ../access.h DEPENDS + libc.hdr.fcntl_macros libc.include.unistd libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -57,7 +58,7 @@ add_entrypoint_object( HDRS ../dup2.h DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.unistd libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -254,7 +255,7 @@ add_entrypoint_object( HDRS ../link.h DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.unistd libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -268,7 +269,7 @@ add_entrypoint_object( HDRS ../linkat.h DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.unistd libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -377,7 +378,7 @@ add_entrypoint_object( HDRS ../rmdir.h DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.unistd libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -391,7 +392,7 @@ add_entrypoint_object( HDRS ../readlink.h DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.unistd libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -405,7 +406,7 @@ add_entrypoint_object( HDRS ../readlinkat.h DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.unistd libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -419,7 +420,7 @@ add_entrypoint_object( HDRS ../symlink.h DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.unistd libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -433,7 +434,7 @@ add_entrypoint_object( HDRS ../symlinkat.h DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.unistd libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -485,7 +486,7 @@ add_entrypoint_object( HDRS ../unlink.h DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.unistd libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -499,7 +500,7 @@ add_entrypoint_object( HDRS ../unlinkat.h DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.unistd libc.include.sys_syscall libc.src.__support.OSUtil.osutil diff --git a/libc/src/unistd/linux/access.cpp b/libc/src/unistd/linux/access.cpp index e9ad74989b0563645c0ca160eb6c9b89920575ca..2f7ebbcdf9e810d6d25c1d16c777a12dc907bdaa 100644 --- a/libc/src/unistd/linux/access.cpp +++ b/libc/src/unistd/linux/access.cpp @@ -11,9 +11,9 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "hdr/fcntl_macros.h" #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/dup2.cpp b/libc/src/unistd/linux/dup2.cpp index 51a19a71a7d854c01a835edffd36cf5688907f0c..c7c7c1a8ca786f3eb3e4c9a4fbba815d9d9631de 100644 --- a/libc/src/unistd/linux/dup2.cpp +++ b/libc/src/unistd/linux/dup2.cpp @@ -11,9 +11,9 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "hdr/fcntl_macros.h" #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/link.cpp b/libc/src/unistd/linux/link.cpp index 37ca58eab1096dcfe8e8dbc9de09d1c91b9c6f72..477806a70df7427a52c459b64ab0d541b11711fc 100644 --- a/libc/src/unistd/linux/link.cpp +++ b/libc/src/unistd/linux/link.cpp @@ -13,7 +13,7 @@ #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include +#include "hdr/fcntl_macros.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/linkat.cpp b/libc/src/unistd/linux/linkat.cpp index fcd6a5f75a196b4f829e9493b387e32ab6b4d230..40f68cc90c4809a3fe901340d1feb2211c403f46 100644 --- a/libc/src/unistd/linux/linkat.cpp +++ b/libc/src/unistd/linux/linkat.cpp @@ -11,9 +11,9 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "hdr/fcntl_macros.h" #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/readlink.cpp b/libc/src/unistd/linux/readlink.cpp index 7b152450044054aff7cd8a4975710c02dd26ffed..2055e6b3400f2f588023a5a7d78d59d321d107b0 100644 --- a/libc/src/unistd/linux/readlink.cpp +++ b/libc/src/unistd/linux/readlink.cpp @@ -11,9 +11,9 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "hdr/fcntl_macros.h" #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/readlinkat.cpp b/libc/src/unistd/linux/readlinkat.cpp index 19a9ff9fbeb72abccf31d1c9bbfc90d0c54de4c6..e5e4d0d39bc9cf5160b48a06b2aeb358ab3b817b 100644 --- a/libc/src/unistd/linux/readlinkat.cpp +++ b/libc/src/unistd/linux/readlinkat.cpp @@ -11,9 +11,9 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "hdr/fcntl_macros.h" #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/rmdir.cpp b/libc/src/unistd/linux/rmdir.cpp index 8974468ebcf16a388594b81c097974cd0b810567..075af12af64c5c4b65d15f939ba42280caa83137 100644 --- a/libc/src/unistd/linux/rmdir.cpp +++ b/libc/src/unistd/linux/rmdir.cpp @@ -13,7 +13,7 @@ #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include +#include "hdr/fcntl_macros.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/symlink.cpp b/libc/src/unistd/linux/symlink.cpp index 5efd4df85edabde631bc678d357ae970657d2e90..9e1b2886ea0f5f0859da4febbccaf27dbd9469a2 100644 --- a/libc/src/unistd/linux/symlink.cpp +++ b/libc/src/unistd/linux/symlink.cpp @@ -13,7 +13,7 @@ #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include +#include "hdr/fcntl_macros.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/symlinkat.cpp b/libc/src/unistd/linux/symlinkat.cpp index 63d2e6d1507a5731a92bb3f1cb4ae41213f95fe2..bcf2d0f8cc0551b4398257f2c1029319d381771a 100644 --- a/libc/src/unistd/linux/symlinkat.cpp +++ b/libc/src/unistd/linux/symlinkat.cpp @@ -11,9 +11,9 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "hdr/fcntl_macros.h" #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/unlink.cpp b/libc/src/unistd/linux/unlink.cpp index de7cae8b826ebc8aef9780f6e1661d23a9b44afb..72d8e2398e3d76163850ab5626423339840dc5b6 100644 --- a/libc/src/unistd/linux/unlink.cpp +++ b/libc/src/unistd/linux/unlink.cpp @@ -11,9 +11,9 @@ #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "hdr/fcntl_macros.h" #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/unistd/linux/unlinkat.cpp b/libc/src/unistd/linux/unlinkat.cpp index e794f242b9459addd1f0c6f1bda70c9b44d0e373..4ed20f542f17023962067ad4c4a99907130016f3 100644 --- a/libc/src/unistd/linux/unlinkat.cpp +++ b/libc/src/unistd/linux/unlinkat.cpp @@ -13,7 +13,7 @@ #include "src/__support/macros/config.h" #include "src/errno/libc_errno.h" -#include +#include "hdr/fcntl_macros.h" #include // For syscall numbers. namespace LIBC_NAMESPACE_DECL { diff --git a/libc/test/src/fcntl/CMakeLists.txt b/libc/test/src/fcntl/CMakeLists.txt index 48048b7fe88666d4d2f2a9c95c240e1a275b6753..b522fef7439df744985e3a38e4053650002c0861 100644 --- a/libc/test/src/fcntl/CMakeLists.txt +++ b/libc/test/src/fcntl/CMakeLists.txt @@ -42,7 +42,7 @@ add_libc_unittest( SRCS openat_test.cpp DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.src.errno.errno libc.src.fcntl.open libc.src.fcntl.openat diff --git a/libc/test/src/fcntl/openat_test.cpp b/libc/test/src/fcntl/openat_test.cpp index 9dafd125224a406112c443b6aaeca99ccfde956e..547359eb9f7a9dfc6b764d58284c13b8fa57c0ca 100644 --- a/libc/test/src/fcntl/openat_test.cpp +++ b/libc/test/src/fcntl/openat_test.cpp @@ -14,7 +14,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include +#include "hdr/fcntl_macros.h" TEST(LlvmLibcUniStd, OpenAndReadTest) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index 262c717dd27d558e8e483c2bccd52828729dec3b..b46ef4028915ba45fdd7947085361b060bbcf6de 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -45,6 +45,17 @@ add_fp_unittest( ) +add_fp_unittest( + cospif16_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + cospif16_test.cpp + DEPENDS + libc.src.math.cospif16 +) + add_fp_unittest( daddl_test NEED_MPFR diff --git a/libc/test/src/math/cbrt_test.cpp b/libc/test/src/math/cbrt_test.cpp index 2ef2140966f52c5dd819e7bf4b2799cf067cef67..2e2de16fc859d120c339970ee1f7c3744cd772fa 100644 --- a/libc/test/src/math/cbrt_test.cpp +++ b/libc/test/src/math/cbrt_test.cpp @@ -87,12 +87,13 @@ TEST_F(LlvmLibcCbrtTest, InDoubleRange) { TEST_F(LlvmLibcCbrtTest, SpecialValues) { constexpr double INPUTS[] = { - 0x1.4f61672324c8p-1028, 0x1.00152f57068b7p-1, 0x1.006509cda9886p-1, - 0x1.018369b92e523p-1, 0x1.10af932ef2bf9p-1, 0x1.1a41117939fdbp-1, - 0x1.2ae8076520d9ap-1, 0x1.a202bfc89ddffp-1, 0x1.a6bb8c803147bp-1, - 0x1.000197b499b1bp+0, 0x1.00065ed266c6cp+0, 0x1.d4306c202c4c2p+0, - 0x1.8fd409efe4851p+1, 0x1.95fd0eb31cc4p+1, 0x1.7cef1d276e335p+2, - 0x1.94910c4fc98p+2, 0x1.a0cc1327bb4c4p+2, 0x1.e7d6ebed549c4p+2, + 0x1.4f61672324c8p-1028, -0x1.fffffffffffffp-1021, 0x1.00152f57068b7p-1, + 0x1.006509cda9886p-1, 0x1.018369b92e523p-1, 0x1.10af932ef2bf9p-1, + 0x1.1a41117939fdbp-1, 0x1.2ae8076520d9ap-1, 0x1.a202bfc89ddffp-1, + 0x1.a6bb8c803147bp-1, 0x1.000197b499b1bp+0, 0x1.00065ed266c6cp+0, + 0x1.d4306c202c4c2p+0, 0x1.8fd409efe4851p+1, 0x1.95fd0eb31cc4p+1, + 0x1.7cef1d276e335p+2, 0x1.94910c4fc98p+2, 0x1.a0cc1327bb4c4p+2, + 0x1.e7d6ebed549c4p+2, }; for (double v : INPUTS) { double x = FPBits(v).get_val(); diff --git a/libc/test/src/math/cospif16_test.cpp b/libc/test/src/math/cospif16_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a32498b0570ac65f308205b8cca9df4d263a14b --- /dev/null +++ b/libc/test/src/math/cospif16_test.cpp @@ -0,0 +1,40 @@ +//===-- Exhaustive test for cospif16 --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/math/cospif16.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +using LlvmLibcCospif16Test = LIBC_NAMESPACE::testing::FPTest; + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +// Range: [0, Inf] +static constexpr uint16_t POS_START = 0x0000U; +static constexpr uint16_t POS_STOP = 0x7c00U; + +// Range: [-Inf, 0] +static constexpr uint16_t NEG_START = 0x8000U; +static constexpr uint16_t NEG_STOP = 0xfc00U; + +TEST_F(LlvmLibcCospif16Test, PositiveRange) { + for (uint16_t v = POS_START; v <= POS_STOP; ++v) { + float16 x = FPBits(v).get_val(); + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Cospi, x, + LIBC_NAMESPACE::cospif16(x), 0.5); + } +} + +TEST_F(LlvmLibcCospif16Test, NegativeRange) { + for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) { + float16 x = FPBits(v).get_val(); + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Cospi, x, + LIBC_NAMESPACE::cospif16(x), 0.5); + } +} diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index b2d1871541efc9973ba46a420656d93fc70db9e9..269e92c590062817ae118ecd31065deec8301380 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -25,6 +25,17 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + cospif16_test + SUITE + libc-math-smoke-tests + SRCS + cospif16_test.cpp + DEPENDS + libc.src.errno.errno + libc.src.math.cospif16 +) + add_fp_unittest( sinf_test SUITE diff --git a/libc/test/src/math/smoke/HypotTest.h b/libc/test/src/math/smoke/HypotTest.h index d7c62dcbeb0edb16a5a4713ad2c68bb45ca70fc5..30d57a4fe2a2672e4115c640245fe770b60ae351 100644 --- a/libc/test/src/math/smoke/HypotTest.h +++ b/libc/test/src/math/smoke/HypotTest.h @@ -14,13 +14,11 @@ #include "test/UnitTest/Test.h" template -class HypotTestTemplate : public LIBC_NAMESPACE::testing::Test { -private: +struct HypotTestTemplate : public LIBC_NAMESPACE::testing::Test { using Func = T (*)(T, T); DECLARE_SPECIAL_CONSTANTS(T) -public: void test_special_numbers(Func func) { constexpr int N = 4; // Pythagorean triples. diff --git a/libc/test/src/math/smoke/acosf_test.cpp b/libc/test/src/math/smoke/acosf_test.cpp index 039d8c2013830d1ade99b8259c74fc5243ccf87a..e5d56c70f27221df3f8ff8f44a2ba900ad2ebe52 100644 --- a/libc/test/src/math/smoke/acosf_test.cpp +++ b/libc/test/src/math/smoke/acosf_test.cpp @@ -38,3 +38,27 @@ TEST_F(LlvmLibcAcosfTest, SpecialNumbers) { EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::acosf(-2.0f)); EXPECT_MATH_ERRNO(EDOM); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcAcosfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0x1.921fb6p0f, LIBC_NAMESPACE::acosf(min_denormal)); +} + +TEST_F(LlvmLibcAcosfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0x1.921fb6p0f, LIBC_NAMESPACE::acosf(min_denormal)); +} + +TEST_F(LlvmLibcAcosfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0x1.921fb6p0f, LIBC_NAMESPACE::acosf(min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/acoshf_test.cpp b/libc/test/src/math/smoke/acoshf_test.cpp index 91d433df80558d5fb5fce3b845c76e71538f8d6d..c4e88259919c3ccefc2989f6d5495772945cd92d 100644 --- a/libc/test/src/math/smoke/acoshf_test.cpp +++ b/libc/test/src/math/smoke/acoshf_test.cpp @@ -35,3 +35,27 @@ TEST_F(LlvmLibcAcoshfTest, SpecialNumbers) { EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::acoshf(neg_inf)); EXPECT_MATH_ERRNO(EDOM); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcAcoshfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_IS_NAN(LIBC_NAMESPACE::acoshf(min_denormal)); +} + +TEST_F(LlvmLibcAcoshfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_IS_NAN(LIBC_NAMESPACE::acoshf(min_denormal)); +} + +TEST_F(LlvmLibcAcoshfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_IS_NAN(LIBC_NAMESPACE::acoshf(min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/asinf_test.cpp b/libc/test/src/math/smoke/asinf_test.cpp index 450255ccd3020dc4e6e2a5e89600f148bd68c7dd..ce1576e2b57dfca90c96096ab6fcb3207b7b651d 100644 --- a/libc/test/src/math/smoke/asinf_test.cpp +++ b/libc/test/src/math/smoke/asinf_test.cpp @@ -41,3 +41,27 @@ TEST_F(LlvmLibcAsinfTest, SpecialNumbers) { EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::asinf(-2.0f)); EXPECT_MATH_ERRNO(EDOM); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcAsinfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::asinf(min_denormal)); +} + +TEST_F(LlvmLibcAsinfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::asinf(min_denormal)); +} + +TEST_F(LlvmLibcAsinfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::asinf(min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/asinhf_test.cpp b/libc/test/src/math/smoke/asinhf_test.cpp index a8e54f379a1fd012e59aeba1531b12fa792dfd6c..5b83ce6466113f92952d8a9feef10d6bf45faa2e 100644 --- a/libc/test/src/math/smoke/asinhf_test.cpp +++ b/libc/test/src/math/smoke/asinhf_test.cpp @@ -35,3 +35,27 @@ TEST_F(LlvmLibcAsinhfTest, SpecialNumbers) { EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, LIBC_NAMESPACE::asinhf(neg_inf)); EXPECT_MATH_ERRNO(0); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcAsinhfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::asinhf(min_denormal)); +} + +TEST_F(LlvmLibcAsinhfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::asinhf(min_denormal)); +} + +TEST_F(LlvmLibcAsinhfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::asinhf(min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/atan2_test.cpp b/libc/test/src/math/smoke/atan2_test.cpp index 61dd6cab1049fe21777853fa9e6872ede948c265..1606c3f378cb88c0df3ecb779e3102b565bb9090 100644 --- a/libc/test/src/math/smoke/atan2_test.cpp +++ b/libc/test/src/math/smoke/atan2_test.cpp @@ -20,3 +20,40 @@ TEST_F(LlvmLibcAtan2Test, SpecialNumbers) { EXPECT_FP_EQ_ALL_ROUNDING(0.0, LIBC_NAMESPACE::atan2(1.0, inf)); EXPECT_FP_EQ_ALL_ROUNDING(-0.0, LIBC_NAMESPACE::atan2(-1.0, inf)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcAtan2Test, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0x1.921fb54442d18p-1, + LIBC_NAMESPACE::atan2(min_denormal, min_denormal)); + EXPECT_FP_EQ(0x1.0000000000001p-52, + LIBC_NAMESPACE::atan2(min_denormal, max_denormal)); + EXPECT_FP_EQ(0x1.921fb54442d17p0, + LIBC_NAMESPACE::atan2(max_denormal, min_denormal)); + EXPECT_FP_EQ(0x1.921fb54442d18p-1, + LIBC_NAMESPACE::atan2(max_denormal, max_denormal)); +} + +TEST_F(LlvmLibcAtan2Test, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::atan2(min_denormal, min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::atan2(min_denormal, max_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::atan2(max_denormal, min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::atan2(max_denormal, max_denormal)); +} + +TEST_F(LlvmLibcAtan2Test, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::atan2(min_denormal, min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::atan2(min_denormal, max_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::atan2(max_denormal, min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::atan2(max_denormal, max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/atanf_test.cpp b/libc/test/src/math/smoke/atanf_test.cpp index 0fe11d79533810cef8a6352690fae74f06c4a4cc..346b8e8abd19919ca4cac748ed576b1a61f9a1a2 100644 --- a/libc/test/src/math/smoke/atanf_test.cpp +++ b/libc/test/src/math/smoke/atanf_test.cpp @@ -42,3 +42,27 @@ TEST_F(LlvmLibcAtanfTest, SpecialNumbers) { // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcAtanfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::atanf(min_denormal)); +} + +TEST_F(LlvmLibcAtanfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::atanf(min_denormal)); +} + +TEST_F(LlvmLibcAtanfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::atanf(min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/atanhf_test.cpp b/libc/test/src/math/smoke/atanhf_test.cpp index e22926bd2f03762f66f510b7c7560f4ec10999f1..8300b47ea9a3151f899fedb1b4950b4dc8933bf1 100644 --- a/libc/test/src/math/smoke/atanhf_test.cpp +++ b/libc/test/src/math/smoke/atanhf_test.cpp @@ -76,3 +76,27 @@ TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) { EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::atanhf(neg_inf), FE_INVALID); EXPECT_MATH_ERRNO(EDOM); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcAtanhfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::atanhf(min_denormal)); +} + +TEST_F(LlvmLibcAtanhfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::atanhf(min_denormal)); +} + +TEST_F(LlvmLibcAtanhfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::atanhf(min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/cbrt_test.cpp b/libc/test/src/math/smoke/cbrt_test.cpp index 724e0e979decc181bb201611d3660c5273385c7a..092e6dd1aeed32b0c9872cd884d0cf15b36a4a32 100644 --- a/libc/test/src/math/smoke/cbrt_test.cpp +++ b/libc/test/src/math/smoke/cbrt_test.cpp @@ -32,4 +32,33 @@ TEST_F(LlvmLibcCbrtTest, SpecialNumbers) { EXPECT_FP_EQ_ALL_ROUNDING(-0x1.0p42, LIBC_NAMESPACE::cbrt(-0x1.0p126)); EXPECT_FP_EQ_ALL_ROUNDING(0x1.0p341, LIBC_NAMESPACE::cbrt(0x1.0p1023)); EXPECT_FP_EQ_ALL_ROUNDING(-0x1.0p341, LIBC_NAMESPACE::cbrt(-0x1.0p1023)); + EXPECT_FP_EQ(-0x1.0p-340, LIBC_NAMESPACE::cbrt(-0x1.fffffffffffffp-1021)); + EXPECT_FP_EQ(2.0, LIBC_NAMESPACE::cbrt(0x1.fffffffffffffp2)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcCbrtTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0x1.0p-358, LIBC_NAMESPACE::cbrt(min_denormal)); + EXPECT_FP_EQ(0x1.428a2f98d728ap-341, LIBC_NAMESPACE::cbrt(max_denormal)); +} + +TEST_F(LlvmLibcCbrtTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::cbrt(min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::cbrt(max_denormal)); +} + +TEST_F(LlvmLibcCbrtTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::cbrt(min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::cbrt(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/cbrtf_test.cpp b/libc/test/src/math/smoke/cbrtf_test.cpp index a68e57744bd0e78ca5af474425cc774113c4c67b..202a5ce0733585db8e92a5a8d8a23af085e3c3c9 100644 --- a/libc/test/src/math/smoke/cbrtf_test.cpp +++ b/libc/test/src/math/smoke/cbrtf_test.cpp @@ -31,3 +31,30 @@ TEST_F(LlvmLibcCbrtfTest, SpecialNumbers) { EXPECT_FP_EQ_ALL_ROUNDING(0x1.0p42f, LIBC_NAMESPACE::cbrtf(0x1.0p126f)); EXPECT_FP_EQ_ALL_ROUNDING(-0x1.0p42f, LIBC_NAMESPACE::cbrtf(-0x1.0p126f)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcCbrtfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0x1.428a3p-50f, LIBC_NAMESPACE::cbrtf(min_denormal)); + EXPECT_FP_EQ(0x1.fffffep-43f, LIBC_NAMESPACE::cbrtf(max_denormal)); +} + +TEST_F(LlvmLibcCbrtfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::cbrtf(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::cbrtf(max_denormal)); +} + +TEST_F(LlvmLibcCbrtfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::cbrtf(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::cbrtf(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/cos_test.cpp b/libc/test/src/math/smoke/cos_test.cpp index 81c8612dba26e5cbec92536a97a50140433af455..88d8ead1af9922176b0b8fbde0b76b148b764177 100644 --- a/libc/test/src/math/smoke/cos_test.cpp +++ b/libc/test/src/math/smoke/cos_test.cpp @@ -24,3 +24,30 @@ TEST_F(LlvmLibcCosTest, SpecialNumbers) { EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::cos(min_normal)); EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::cos(min_denormal)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcCosTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::cos(min_denormal)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::cos(max_denormal)); +} + +TEST_F(LlvmLibcCosTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::cos(min_denormal)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::cos(max_denormal)); +} + +TEST_F(LlvmLibcCosTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::cos(min_denormal)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::cos(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/cosf_test.cpp b/libc/test/src/math/smoke/cosf_test.cpp index 62f7ede9cf17810413089360b0aea89391e3792e..2e261f9fac3c0cfaa02ddbc8c580003b325c0150 100644 --- a/libc/test/src/math/smoke/cosf_test.cpp +++ b/libc/test/src/math/smoke/cosf_test.cpp @@ -35,3 +35,30 @@ TEST_F(LlvmLibcCosfTest, SpecialNumbers) { EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::cosf(neg_inf)); EXPECT_MATH_ERRNO(EDOM); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcCosfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cosf(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cosf(max_denormal)); +} + +TEST_F(LlvmLibcCosfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cosf(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cosf(max_denormal)); +} + +TEST_F(LlvmLibcCosfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cosf(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cosf(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/coshf_test.cpp b/libc/test/src/math/smoke/coshf_test.cpp index ddaa19f4c392f7d7b2caeb583276c7c3b449175d..fd1556b10116d9a04a410a48da6aa09f6ffcf4a4 100644 --- a/libc/test/src/math/smoke/coshf_test.cpp +++ b/libc/test/src/math/smoke/coshf_test.cpp @@ -51,3 +51,30 @@ TEST_F(LlvmLibcCoshfTest, Overflow) { inf, LIBC_NAMESPACE::coshf(FPBits(0x42d00008U).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcCoshfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::coshf(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::coshf(max_denormal)); +} + +TEST_F(LlvmLibcCoshfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::coshf(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::coshf(max_denormal)); +} + +TEST_F(LlvmLibcCoshfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::coshf(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::coshf(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/cospif16_test.cpp b/libc/test/src/math/smoke/cospif16_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6d7483393191fd3b4bfe0fbc88013ab034aa968 --- /dev/null +++ b/libc/test/src/math/smoke/cospif16_test.cpp @@ -0,0 +1,44 @@ +//===-- Unittests for cospif16 --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/errno/libc_errno.h" +#include "src/math/cospif16.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +using LlvmLibcCospif16Test = LIBC_NAMESPACE::testing::FPTest; + +TEST_F(LlvmLibcCospif16Test, SpecialNumbers) { + LIBC_NAMESPACE::libc_errno = 0; + + EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::cospif16(aNaN)); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cospif16(zero)); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cospif16(neg_zero)); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::cospif16(inf)); + EXPECT_MATH_ERRNO(EDOM); + + EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::cospif16(neg_inf)); + EXPECT_MATH_ERRNO(EDOM); +} + +TEST_F(LlvmLibcCospif16Test, Integers) { + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cospif16(-0x420)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cospif16(-0x1.4p+14)); + EXPECT_FP_EQ(-1.0f, LIBC_NAMESPACE::cospif16(0x421)); + EXPECT_FP_EQ(-1.0f, LIBC_NAMESPACE::cospif16(0x333)); + EXPECT_FP_EQ(zero, LIBC_NAMESPACE::cospif16(-0x1.28p4)); + EXPECT_FP_EQ(zero, LIBC_NAMESPACE::cospif16(-0x1.ffcp9)); + EXPECT_FP_EQ(zero, LIBC_NAMESPACE::cospif16(0x1.01p7)); + EXPECT_FP_EQ(zero, LIBC_NAMESPACE::cospif16(0x1.f6cp9)); +} diff --git a/libc/test/src/math/smoke/cospif_test.cpp b/libc/test/src/math/smoke/cospif_test.cpp index 007c4c45e3b15704cd9823969e8425ead622f2a0..bf6d86bcfe623af5da0a1e404301b0ba3c3c2db7 100644 --- a/libc/test/src/math/smoke/cospif_test.cpp +++ b/libc/test/src/math/smoke/cospif_test.cpp @@ -32,3 +32,30 @@ TEST_F(LlvmLibcCospifTest, SpecialNumbers) { EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::cospif(neg_inf)); EXPECT_MATH_ERRNO(EDOM); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcCospifTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cospif(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cospif(max_denormal)); +} + +TEST_F(LlvmLibcCospifTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cospif(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cospif(max_denormal)); +} + +TEST_F(LlvmLibcCospifTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cospif(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::cospif(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/erff_test.cpp b/libc/test/src/math/smoke/erff_test.cpp index 8a970f3a4b7ed19fc2da5cb9107dde8a60df0184..7d2c1013752c7c0a461c3e66b04c7722aad48c67 100644 --- a/libc/test/src/math/smoke/erff_test.cpp +++ b/libc/test/src/math/smoke/erff_test.cpp @@ -23,3 +23,30 @@ TEST_F(LlvmLibcErffTest, SpecialNumbers) { EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::erff(zero)); EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, LIBC_NAMESPACE::erff(neg_zero)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcErffTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::erff(min_denormal)); + EXPECT_FP_EQ(0x1.20dd72p-126f, LIBC_NAMESPACE::erff(max_denormal)); +} + +TEST_F(LlvmLibcErffTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::erff(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::erff(max_denormal)); +} + +TEST_F(LlvmLibcErffTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::erff(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::erff(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/exp10_test.cpp b/libc/test/src/math/smoke/exp10_test.cpp index 282ddc987b49933819db921bcb201ecd9b6ef328..ca9fc359edeb5a4afe972c168450a4b549864db1 100644 --- a/libc/test/src/math/smoke/exp10_test.cpp +++ b/libc/test/src/math/smoke/exp10_test.cpp @@ -32,3 +32,30 @@ TEST_F(LlvmLibcExp10Test, SpecialNumbers) { EXPECT_FP_EQ_ALL_ROUNDING(100.0, LIBC_NAMESPACE::exp10(2.0)); EXPECT_FP_EQ_ALL_ROUNDING(1000.0, LIBC_NAMESPACE::exp10(3.0)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcExp10Test, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp10(min_denormal)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp10(max_denormal)); +} + +TEST_F(LlvmLibcExp10Test, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp10(min_denormal)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp10(max_denormal)); +} + +TEST_F(LlvmLibcExp10Test, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp10(min_denormal)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp10(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/exp10f_test.cpp b/libc/test/src/math/smoke/exp10f_test.cpp index 9fb15ae75348bb8dde9feeb8b427a087f461e4d6..bcbfc96efd726890040cd202badb1436a0abe0e5 100644 --- a/libc/test/src/math/smoke/exp10f_test.cpp +++ b/libc/test/src/math/smoke/exp10f_test.cpp @@ -54,3 +54,30 @@ TEST_F(LlvmLibcExp10fTest, Overflow) { inf, LIBC_NAMESPACE::exp10f(FPBits(0x43000001U).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcExp10fTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp10f(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp10f(max_denormal)); +} + +TEST_F(LlvmLibcExp10fTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp10f(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp10f(max_denormal)); +} + +TEST_F(LlvmLibcExp10fTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp10f(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp10f(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/exp2_test.cpp b/libc/test/src/math/smoke/exp2_test.cpp index d148d27fad38dc5e2ec1ac772e3bbacea42d7d8e..d97a384367a09f951fe66c305e06bda9acbe6dc2 100644 --- a/libc/test/src/math/smoke/exp2_test.cpp +++ b/libc/test/src/math/smoke/exp2_test.cpp @@ -31,3 +31,30 @@ TEST_F(LlvmLibcExp2Test, SpecialNumbers) { EXPECT_FP_EQ_ALL_ROUNDING(4.0, LIBC_NAMESPACE::exp2(2.0)); EXPECT_FP_EQ_ALL_ROUNDING(0.25, LIBC_NAMESPACE::exp2(-2.0)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcExp2Test, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp2(min_denormal)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp2(max_denormal)); +} + +TEST_F(LlvmLibcExp2Test, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp2(min_denormal)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp2(max_denormal)); +} + +TEST_F(LlvmLibcExp2Test, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp2(min_denormal)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp2(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/exp2f_test.cpp b/libc/test/src/math/smoke/exp2f_test.cpp index 39228eb2f6d8ba2ff5e1628ee74a837b961dce23..d9cdecbf0fe9ba49de8fafeb46b4f3c7d89bb7b3 100644 --- a/libc/test/src/math/smoke/exp2f_test.cpp +++ b/libc/test/src/math/smoke/exp2f_test.cpp @@ -55,3 +55,30 @@ TEST_F(LlvmLibcExp2fTest, Overflow) { inf, LIBC_NAMESPACE::exp2f(FPBits(0x43000001U).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcExp2fTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp2f(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp2f(max_denormal)); +} + +TEST_F(LlvmLibcExp2fTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp2f(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp2f(max_denormal)); +} + +TEST_F(LlvmLibcExp2fTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp2f(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::exp2f(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/exp2m1f_test.cpp b/libc/test/src/math/smoke/exp2m1f_test.cpp index 2df4353852472892ff305c5557e77aa11a0162bf..4657d088f07a893c5a54c24ebb4a5264f3b773a5 100644 --- a/libc/test/src/math/smoke/exp2m1f_test.cpp +++ b/libc/test/src/math/smoke/exp2m1f_test.cpp @@ -61,3 +61,30 @@ TEST_F(LlvmLibcExp2m1fTest, Underflow) { FE_UNDERFLOW); EXPECT_MATH_ERRNO(ERANGE); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcExp2m1fTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::exp2m1f(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::exp2m1f(max_denormal)); +} + +TEST_F(LlvmLibcExp2m1fTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::exp2m1f(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::exp2m1f(max_denormal)); +} + +TEST_F(LlvmLibcExp2m1fTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::exp2m1f(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::exp2m1f(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/exp_test.cpp b/libc/test/src/math/smoke/exp_test.cpp index 5fe6f3e92f4a6a639aa37a8e72f17962d081730f..d2467ff8838969f1b31d408f32da06e95e2e7117 100644 --- a/libc/test/src/math/smoke/exp_test.cpp +++ b/libc/test/src/math/smoke/exp_test.cpp @@ -27,3 +27,30 @@ TEST_F(LlvmLibcExpTest, SpecialNumbers) { EXPECT_FP_EQ_ALL_ROUNDING(1.0, LIBC_NAMESPACE::exp(0.0)); EXPECT_FP_EQ_ALL_ROUNDING(1.0, LIBC_NAMESPACE::exp(-0.0)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcExpTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp(min_denormal)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp(max_denormal)); +} + +TEST_F(LlvmLibcExpTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp(min_denormal)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp(max_denormal)); +} + +TEST_F(LlvmLibcExpTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp(min_denormal)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::exp(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/expf_test.cpp b/libc/test/src/math/smoke/expf_test.cpp index b954125afd7bba0c5d3f335264ff55424be6e114..11181ed1402c9ee3292a3d08bdcfde1563f30073 100644 --- a/libc/test/src/math/smoke/expf_test.cpp +++ b/libc/test/src/math/smoke/expf_test.cpp @@ -50,3 +50,30 @@ TEST_F(LlvmLibcExpfTest, Overflow) { inf, LIBC_NAMESPACE::expf(FPBits(0x42d00008U).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcExpfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::expf(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::expf(max_denormal)); +} + +TEST_F(LlvmLibcExpfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::expf(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::expf(max_denormal)); +} + +TEST_F(LlvmLibcExpfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::expf(min_denormal)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::expf(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/expm1_test.cpp b/libc/test/src/math/smoke/expm1_test.cpp index bafdbda8af03bdb2b17030b5f9bfd451fae767b8..cebd2d757606b0fa6c1c2b732c1e969520f5a435 100644 --- a/libc/test/src/math/smoke/expm1_test.cpp +++ b/libc/test/src/math/smoke/expm1_test.cpp @@ -33,3 +33,30 @@ TEST_F(LlvmLibcExpm1Test, SpecialNumbers) { // log(2^-54) EXPECT_FP_EQ(-1.0, LIBC_NAMESPACE::expm1(-0x1.2b708872320e2p5)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcExpm1Test, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::expm1(min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::expm1(max_denormal)); +} + +TEST_F(LlvmLibcExpm1Test, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::expm1(min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::expm1(max_denormal)); +} + +TEST_F(LlvmLibcExpm1Test, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::expm1(min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::expm1(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/expm1f_test.cpp b/libc/test/src/math/smoke/expm1f_test.cpp index 03b6e47b7c3bc44c24fce4101cc5c2b78319175e..f4138aa05ba7e3a0e31fa7ad555e9b4c52c75952 100644 --- a/libc/test/src/math/smoke/expm1f_test.cpp +++ b/libc/test/src/math/smoke/expm1f_test.cpp @@ -50,3 +50,30 @@ TEST_F(LlvmLibcExpm1fTest, Overflow) { inf, LIBC_NAMESPACE::expm1f(FPBits(0x42d00008U).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcExpm1fTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::expm1f(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::expm1f(max_denormal)); +} + +TEST_F(LlvmLibcExpm1fTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::expm1f(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::expm1f(max_denormal)); +} + +TEST_F(LlvmLibcExpm1fTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::expm1f(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::expm1f(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/hypotf_test.cpp b/libc/test/src/math/smoke/hypotf_test.cpp index 768e7f75e9d678e45b9204ad98d03ab8bcbfb850..62399489987e7eabfbddfbac64edf1548d7a76e4 100644 --- a/libc/test/src/math/smoke/hypotf_test.cpp +++ b/libc/test/src/math/smoke/hypotf_test.cpp @@ -15,3 +15,37 @@ using LlvmLibcHypotfTest = HypotTestTemplate; TEST_F(LlvmLibcHypotfTest, SpecialNumbers) { test_special_numbers(&LIBC_NAMESPACE::hypotf); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcHypotfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::hypotf(min_denormal, min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::hypotf(min_denormal, max_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::hypotf(max_denormal, min_denormal)); + EXPECT_FP_EQ(0x1.6a09e4p-126f, + LIBC_NAMESPACE::hypotf(max_denormal, max_denormal)); +} + +TEST_F(LlvmLibcHypotfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::hypotf(min_denormal, min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::hypotf(min_denormal, max_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::hypotf(max_denormal, min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::hypotf(max_denormal, max_denormal)); +} + +TEST_F(LlvmLibcHypotfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::hypotf(min_denormal, min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::hypotf(min_denormal, max_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::hypotf(max_denormal, min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::hypotf(max_denormal, max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/log10_test.cpp b/libc/test/src/math/smoke/log10_test.cpp index e03416ae20c8f37984340f025c18fed2b724c7d9..9f159f282aad86cabfad803598a1c2f7a1731155 100644 --- a/libc/test/src/math/smoke/log10_test.cpp +++ b/libc/test/src/math/smoke/log10_test.cpp @@ -33,3 +33,29 @@ TEST_F(LlvmLibcLog10Test, SpecialNumbers) { EXPECT_FP_EQ_ALL_ROUNDING(static_cast(i), LIBC_NAMESPACE::log10(x)); } } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcLog10Test, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(-0x1.434e6420f4374p8, LIBC_NAMESPACE::log10(min_denormal)); +} + +TEST_F(LlvmLibcLog10Test, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(FPBits::inf(Sign::NEG).get_val(), + LIBC_NAMESPACE::log10(min_denormal)); +} + +TEST_F(LlvmLibcLog10Test, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(FPBits::inf(Sign::NEG).get_val(), + LIBC_NAMESPACE::log10(min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/log10f_test.cpp b/libc/test/src/math/smoke/log10f_test.cpp index 2524545e0181236120c56014e87fd72feebd4576..4e3bf654ca918a9162bb636f4f5a0b627513c4c3 100644 --- a/libc/test/src/math/smoke/log10f_test.cpp +++ b/libc/test/src/math/smoke/log10f_test.cpp @@ -32,3 +32,29 @@ TEST_F(LlvmLibcLog10fTest, SpecialNumbers) { EXPECT_FP_EQ_ALL_ROUNDING(static_cast(i), LIBC_NAMESPACE::log10f(x)); } } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcLog10fTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(-0x1.66d3e7bd9a403p5f, LIBC_NAMESPACE::log10f(min_denormal)); +} + +TEST_F(LlvmLibcLog10fTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(FPBits::inf(Sign::NEG).get_val(), + LIBC_NAMESPACE::log10f(min_denormal)); +} + +TEST_F(LlvmLibcLog10fTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(FPBits::inf(Sign::NEG).get_val(), + LIBC_NAMESPACE::log10f(min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/log1p_test.cpp b/libc/test/src/math/smoke/log1p_test.cpp index 63237f3259b2151fea315d28e122c89ba5db7b2e..eba65f56df73964c178fa93ae56575e8602b3d80 100644 --- a/libc/test/src/math/smoke/log1p_test.cpp +++ b/libc/test/src/math/smoke/log1p_test.cpp @@ -27,3 +27,27 @@ TEST_F(LlvmLibcLog1pTest, SpecialNumbers) { EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, LIBC_NAMESPACE::log1p(-1.0), FE_DIVBYZERO); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcLog1pTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::log1p(min_denormal)); +} + +TEST_F(LlvmLibcLog1pTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::log1p(min_denormal)); +} + +TEST_F(LlvmLibcLog1pTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::log1p(min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/log1pf_test.cpp b/libc/test/src/math/smoke/log1pf_test.cpp index c14d655294697926e52f7056f3d37362e68c306d..1b0a1d589e684b050d9db721106c92ee7a951c95 100644 --- a/libc/test/src/math/smoke/log1pf_test.cpp +++ b/libc/test/src/math/smoke/log1pf_test.cpp @@ -26,3 +26,27 @@ TEST_F(LlvmLibcLog1pfTest, SpecialNumbers) { EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, LIBC_NAMESPACE::log1pf(-1.0f), FE_DIVBYZERO); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcLog1pfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::log1pf(min_denormal)); +} + +TEST_F(LlvmLibcLog1pfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::log1pf(min_denormal)); +} + +TEST_F(LlvmLibcLog1pfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::log1pf(min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/log2_test.cpp b/libc/test/src/math/smoke/log2_test.cpp index 89d8e56510911854c0435df4987629c9964b3f95..1570d60556df2c3b17c0d80da56f6599c61e0190 100644 --- a/libc/test/src/math/smoke/log2_test.cpp +++ b/libc/test/src/math/smoke/log2_test.cpp @@ -27,3 +27,29 @@ TEST_F(LlvmLibcLog2Test, SpecialNumbers) { EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::log2(-1.0), FE_INVALID); EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::log2(1.0)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcLog2Test, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(-1074.0, LIBC_NAMESPACE::log2(min_denormal)); +} + +TEST_F(LlvmLibcLog2Test, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(FPBits::inf(Sign::NEG).get_val(), + LIBC_NAMESPACE::log2(min_denormal)); +} + +TEST_F(LlvmLibcLog2Test, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(FPBits::inf(Sign::NEG).get_val(), + LIBC_NAMESPACE::log2(min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/log2f_test.cpp b/libc/test/src/math/smoke/log2f_test.cpp index 00bfb7c4abad6704ccd504a8d503646a07a6a74e..67b2c5b2db13d128dd43a5f151747cbdab448cda 100644 --- a/libc/test/src/math/smoke/log2f_test.cpp +++ b/libc/test/src/math/smoke/log2f_test.cpp @@ -28,3 +28,28 @@ TEST_F(LlvmLibcLog2fTest, SpecialNumbers) { EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::log2f(-1.0f), FE_INVALID); EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::log2f(1.0f)); } +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcLog2fTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(-149.0f, LIBC_NAMESPACE::log2f(min_denormal)); +} + +TEST_F(LlvmLibcLog2fTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(FPBits::inf(Sign::NEG).get_val(), + LIBC_NAMESPACE::log2f(min_denormal)); +} + +TEST_F(LlvmLibcLog2fTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(FPBits::inf(Sign::NEG).get_val(), + LIBC_NAMESPACE::log2f(min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/log_test.cpp b/libc/test/src/math/smoke/log_test.cpp index e7897add575fade4e996eaa75c1021dcf1f812c1..20b974d7e167d74ff0101c9cade333e6f04033b3 100644 --- a/libc/test/src/math/smoke/log_test.cpp +++ b/libc/test/src/math/smoke/log_test.cpp @@ -26,3 +26,29 @@ TEST_F(LlvmLibcLogTest, SpecialNumbers) { EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::log(-1.0), FE_INVALID); EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::log(1.0)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcLogTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(-0x1.74385446d71c3p9, LIBC_NAMESPACE::log(min_denormal)); +} + +TEST_F(LlvmLibcLogTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(FPBits::inf(Sign::NEG).get_val(), + LIBC_NAMESPACE::log(min_denormal)); +} + +TEST_F(LlvmLibcLogTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(FPBits::inf(Sign::NEG).get_val(), + LIBC_NAMESPACE::log(min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/logf_test.cpp b/libc/test/src/math/smoke/logf_test.cpp index a27206027614525f615be1c1d9ee50a6f34fb896..1a3102ae2b14101bc474fd96c6f71535ef440151 100644 --- a/libc/test/src/math/smoke/logf_test.cpp +++ b/libc/test/src/math/smoke/logf_test.cpp @@ -27,3 +27,28 @@ TEST_F(LlvmLibcLogfTest, SpecialNumbers) { EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::logf(-1.0f), FE_INVALID); EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::logf(1.0f)); } +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcLogfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(-0x1.9d1d9fccf477p6f, LIBC_NAMESPACE::logf(min_denormal)); +} + +TEST_F(LlvmLibcLogfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(FPBits::inf(Sign::NEG).get_val(), + LIBC_NAMESPACE::logf(min_denormal)); +} + +TEST_F(LlvmLibcLogfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(FPBits::inf(Sign::NEG).get_val(), + LIBC_NAMESPACE::logf(min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/pow_test.cpp b/libc/test/src/math/smoke/pow_test.cpp index 7f0136d783c6ba06698794567561ee8b304b1d94..f9db7f102962b937b28db3a4c4bbc71b90cb4275 100644 --- a/libc/test/src/math/smoke/pow_test.cpp +++ b/libc/test/src/math/smoke/pow_test.cpp @@ -190,3 +190,30 @@ TEST_F(LlvmLibcPowTest, SpecialNumbers) { } } } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcPowTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_IS_NAN(LIBC_NAMESPACE::pow(-min_denormal, 0.5)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::pow(2.0, min_denormal)); +} + +TEST_F(LlvmLibcPowTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::pow(-min_denormal, 0.5)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::pow(2.0, min_denormal)); +} + +TEST_F(LlvmLibcPowTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::pow(-min_denormal, 0.5)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::pow(2.0, min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/powf_test.cpp b/libc/test/src/math/smoke/powf_test.cpp index a0f66f2733a1ea9c041c7326b13082f5c6d25d83..9cc95ce0baef9fc0ce30993c6e025a3fcb529bcf 100644 --- a/libc/test/src/math/smoke/powf_test.cpp +++ b/libc/test/src/math/smoke/powf_test.cpp @@ -194,3 +194,30 @@ TEST_F(LlvmLibcPowfTest, SpecialNumbers) { EXPECT_FP_EQ(-0.0f, LIBC_NAMESPACE::powf(-0.015625f, 25.0f)); EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::powf(-0.015625f, 26.0f)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcPowfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_IS_NAN(LIBC_NAMESPACE::powf(-min_denormal, 0.5f)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::powf(2.0f, min_denormal)); +} + +TEST_F(LlvmLibcPowfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::powf(-min_denormal, 0.5f)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::powf(2.0f, min_denormal)); +} + +TEST_F(LlvmLibcPowfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::powf(-min_denormal, 0.5f)); + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::powf(2.0f, min_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/sin_test.cpp b/libc/test/src/math/smoke/sin_test.cpp index 16ced68709ca755980cefef30aa2268fd2bf5851..7dd1b7fda625b0d96253a8f50614ed6c2914b30d 100644 --- a/libc/test/src/math/smoke/sin_test.cpp +++ b/libc/test/src/math/smoke/sin_test.cpp @@ -24,3 +24,30 @@ TEST_F(LlvmLibcSinTest, SpecialNumbers) { EXPECT_FP_EQ(min_normal, LIBC_NAMESPACE::sin(min_normal)); EXPECT_FP_EQ(min_denormal, LIBC_NAMESPACE::sin(min_denormal)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcSinTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::sin(min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::sin(max_denormal)); +} + +TEST_F(LlvmLibcSinTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::sin(min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::sin(max_denormal)); +} + +TEST_F(LlvmLibcSinTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::sin(min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::sin(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/sinf_test.cpp b/libc/test/src/math/smoke/sinf_test.cpp index 1bf6eaa8b78d7d3ef9068ac0e570978454f5a3d8..776c66dcb37bdee57bdeb5a000f0d8b3698b2501 100644 --- a/libc/test/src/math/smoke/sinf_test.cpp +++ b/libc/test/src/math/smoke/sinf_test.cpp @@ -35,3 +35,30 @@ TEST_F(LlvmLibcSinfTest, SpecialNumbers) { EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::sinf(neg_inf)); EXPECT_MATH_ERRNO(EDOM); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcSinfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinf(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinf(max_denormal)); +} + +TEST_F(LlvmLibcSinfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinf(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinf(max_denormal)); +} + +TEST_F(LlvmLibcSinfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinf(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinf(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/sinhf_test.cpp b/libc/test/src/math/smoke/sinhf_test.cpp index 635a10627a21096689a047b1310b847f6f7d6213..3cc0656967581ab7cec88b97dd5225291127e68f 100644 --- a/libc/test/src/math/smoke/sinhf_test.cpp +++ b/libc/test/src/math/smoke/sinhf_test.cpp @@ -62,3 +62,30 @@ TEST_F(LlvmLibcSinhfTest, Overflow) { inf, LIBC_NAMESPACE::sinhf(FPBits(0x42d00008U).get_val()), FE_OVERFLOW); EXPECT_MATH_ERRNO(ERANGE); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcSinhfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinhf(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinhf(max_denormal)); +} + +TEST_F(LlvmLibcSinhfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinhf(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinhf(max_denormal)); +} + +TEST_F(LlvmLibcSinhfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinhf(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinhf(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/sinpif_test.cpp b/libc/test/src/math/smoke/sinpif_test.cpp index 0918294ab3611c2cd18e00e7f240aace1152d9d1..11bda0b6b28cc77ee3becb8820223ca4b8e474c0 100644 --- a/libc/test/src/math/smoke/sinpif_test.cpp +++ b/libc/test/src/math/smoke/sinpif_test.cpp @@ -41,3 +41,30 @@ TEST_F(LlvmLibcSinpifTest, Integers) { EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::sinpif(0x1.cp+106)); EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::sinpif(0x1.cp+21)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcSinpifTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinpif(min_denormal)); + EXPECT_FP_EQ(0x1.921fb2p-125f, LIBC_NAMESPACE::sinpif(max_denormal)); +} + +TEST_F(LlvmLibcSinpifTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinpif(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinpif(max_denormal)); +} + +TEST_F(LlvmLibcSinpifTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinpif(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::sinpif(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/tan_test.cpp b/libc/test/src/math/smoke/tan_test.cpp index 498dba76b6e719565d61f247f49abe53625eb40f..aa5c23d65886d291ef7fc7022e071e4061c450a1 100644 --- a/libc/test/src/math/smoke/tan_test.cpp +++ b/libc/test/src/math/smoke/tan_test.cpp @@ -24,3 +24,30 @@ TEST_F(LlvmLibcTanTest, SpecialNumbers) { EXPECT_FP_EQ(min_normal, LIBC_NAMESPACE::tan(min_normal)); EXPECT_FP_EQ(min_denormal, LIBC_NAMESPACE::tan(min_denormal)); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcTanTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::tan(min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::tan(max_denormal)); +} + +TEST_F(LlvmLibcTanTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::tan(min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::tan(max_denormal)); +} + +TEST_F(LlvmLibcTanTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::tan(min_denormal)); + EXPECT_FP_EQ(0.0, LIBC_NAMESPACE::tan(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/tanf_test.cpp b/libc/test/src/math/smoke/tanf_test.cpp index b90c5da8741892af42e9556fcf7d390883c34275..93fbfded3f66a1800a0887cd65b6062b28cbbe83 100644 --- a/libc/test/src/math/smoke/tanf_test.cpp +++ b/libc/test/src/math/smoke/tanf_test.cpp @@ -35,3 +35,30 @@ TEST_F(LlvmLibcTanfTest, SpecialNumbers) { EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::tanf(neg_inf)); EXPECT_MATH_ERRNO(EDOM); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcTanfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::tanf(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::tanf(max_denormal)); +} + +TEST_F(LlvmLibcTanfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::tanf(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::tanf(max_denormal)); +} + +TEST_F(LlvmLibcTanfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::tanf(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::tanf(max_denormal)); +} + +#endif diff --git a/libc/test/src/math/smoke/tanhf_test.cpp b/libc/test/src/math/smoke/tanhf_test.cpp index 748e6fe8c62693dfa55a25edcdf0ea5b53b08194..3b7faa81dac2eac8f63a010f2fcdcd0b24c5ad63 100644 --- a/libc/test/src/math/smoke/tanhf_test.cpp +++ b/libc/test/src/math/smoke/tanhf_test.cpp @@ -35,3 +35,30 @@ TEST_F(LlvmLibcTanhfTest, SpecialNumbers) { EXPECT_FP_EQ(-1.0f, LIBC_NAMESPACE::tanhf(neg_inf)); EXPECT_MATH_ERRNO(0); } + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +TEST_F(LlvmLibcTanhfTest, FTZMode) { + ModifyMXCSR mxcsr(FTZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::tanhf(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::tanhf(max_denormal)); +} + +TEST_F(LlvmLibcTanhfTest, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::tanhf(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::tanhf(max_denormal)); +} + +TEST_F(LlvmLibcTanhfTest, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::tanhf(min_denormal)); + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::tanhf(max_denormal)); +} + +#endif diff --git a/libc/test/src/sys/sendfile/CMakeLists.txt b/libc/test/src/sys/sendfile/CMakeLists.txt index 82efaa147bd89d14220ab3cd01bfababb50c52b1..ceaa4accdd06ef2e56143504de3ac5de2f01c6d6 100644 --- a/libc/test/src/sys/sendfile/CMakeLists.txt +++ b/libc/test/src/sys/sendfile/CMakeLists.txt @@ -9,7 +9,7 @@ add_libc_unittest( SRCS sendfile_test.cpp DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.sys_stat libc.src.errno.errno libc.src.fcntl.open diff --git a/libc/test/src/sys/sendfile/sendfile_test.cpp b/libc/test/src/sys/sendfile/sendfile_test.cpp index 59025438a24671e7fb5c25f067417db28df55bb7..a658212ddb72cdd1933c475d99cc5e34e312a1e2 100644 --- a/libc/test/src/sys/sendfile/sendfile_test.cpp +++ b/libc/test/src/sys/sendfile/sendfile_test.cpp @@ -17,7 +17,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include +#include "hdr/fcntl_macros.h" #include namespace cpp = LIBC_NAMESPACE::cpp; diff --git a/libc/test/src/sys/stat/CMakeLists.txt b/libc/test/src/sys/stat/CMakeLists.txt index 877a129b627dd4517717cf31dc7a450575640b81..dd3d0932755b769620baf1bf46afe7e54f1426a6 100644 --- a/libc/test/src/sys/stat/CMakeLists.txt +++ b/libc/test/src/sys/stat/CMakeLists.txt @@ -9,7 +9,7 @@ add_libc_unittest( SRCS chmod_test.cpp DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.sys_stat libc.src.errno.errno libc.src.fcntl.open @@ -25,7 +25,7 @@ add_libc_unittest( SRCS fchmodat_test.cpp DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.sys_stat libc.src.errno.errno libc.src.fcntl.open @@ -41,7 +41,7 @@ add_libc_unittest( SRCS fchmod_test.cpp DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.sys_stat libc.src.errno.errno libc.src.fcntl.open @@ -57,7 +57,7 @@ add_libc_unittest( SRCS mkdirat_test.cpp DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.sys_stat libc.src.errno.errno libc.src.sys.stat.mkdirat @@ -71,7 +71,7 @@ add_libc_unittest( SRCS stat_test.cpp DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.sys_stat libc.src.errno.errno libc.src.sys.stat.stat @@ -87,7 +87,7 @@ add_libc_unittest( SRCS lstat_test.cpp DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.sys_stat libc.src.errno.errno libc.src.sys.stat.lstat @@ -103,7 +103,7 @@ add_libc_unittest( SRCS fstat_test.cpp DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.sys_stat libc.src.errno.errno libc.src.sys.stat.fstat diff --git a/libc/test/src/sys/stat/chmod_test.cpp b/libc/test/src/sys/stat/chmod_test.cpp index c688996615ceef16e7dff1af371003006fc26e7c..83ab0f45b6f08aede37a914458574df8cab9090f 100644 --- a/libc/test/src/sys/stat/chmod_test.cpp +++ b/libc/test/src/sys/stat/chmod_test.cpp @@ -14,7 +14,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include +#include "hdr/fcntl_macros.h" #include TEST(LlvmLibcChmodTest, ChangeAndOpen) { diff --git a/libc/test/src/sys/stat/fchmod_test.cpp b/libc/test/src/sys/stat/fchmod_test.cpp index 91c0f68b8708c842ca3c357678852e30534178f5..03eb79d95ddd6d36458d919237f9c692be3e2e1b 100644 --- a/libc/test/src/sys/stat/fchmod_test.cpp +++ b/libc/test/src/sys/stat/fchmod_test.cpp @@ -14,7 +14,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include +#include "hdr/fcntl_macros.h" #include TEST(LlvmLibcChmodTest, ChangeAndOpen) { diff --git a/libc/test/src/sys/stat/fchmodat_test.cpp b/libc/test/src/sys/stat/fchmodat_test.cpp index c43ef8ae13315a1bd30ef60b81815ae1b2523bc4..09970b6e0fb163d7355578d7cb1020f1aaa85bcd 100644 --- a/libc/test/src/sys/stat/fchmodat_test.cpp +++ b/libc/test/src/sys/stat/fchmodat_test.cpp @@ -14,7 +14,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include +#include "hdr/fcntl_macros.h" #include TEST(LlvmLibcFchmodatTest, ChangeAndOpen) { diff --git a/libc/test/src/sys/stat/fstat_test.cpp b/libc/test/src/sys/stat/fstat_test.cpp index 1379eae26a47aed2669ef6554973df5d6d4fced1..34c675d1a4e2992b097d5786e4ac0d4889a27d09 100644 --- a/libc/test/src/sys/stat/fstat_test.cpp +++ b/libc/test/src/sys/stat/fstat_test.cpp @@ -14,7 +14,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include +#include "hdr/fcntl_macros.h" #include TEST(LlvmLibcFStatTest, CreatAndReadMode) { diff --git a/libc/test/src/sys/stat/lstat_test.cpp b/libc/test/src/sys/stat/lstat_test.cpp index b44b3d1a59ce7bf3327850e3ff537974c92a0b48..a723d5ae2e297bafa8153af5dbf8c6906f9547dc 100644 --- a/libc/test/src/sys/stat/lstat_test.cpp +++ b/libc/test/src/sys/stat/lstat_test.cpp @@ -14,7 +14,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include +#include "hdr/fcntl_macros.h" #include TEST(LlvmLibcLStatTest, CreatAndReadMode) { diff --git a/libc/test/src/sys/stat/mkdirat_test.cpp b/libc/test/src/sys/stat/mkdirat_test.cpp index cbacc16b402d7abc3d95bff383272e5e58f5d711..85e013de234e76aed8a35a44fc234230afc34d32 100644 --- a/libc/test/src/sys/stat/mkdirat_test.cpp +++ b/libc/test/src/sys/stat/mkdirat_test.cpp @@ -11,7 +11,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include +#include "hdr/fcntl_macros.h" TEST(LlvmLibcMkdiratTest, CreateAndRemove) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; diff --git a/libc/test/src/sys/stat/stat_test.cpp b/libc/test/src/sys/stat/stat_test.cpp index baf363382022ad3f103d293e36a735662fd66a74..0ddd8baaec1c9b780f5a067787c0ebc1f5be69f5 100644 --- a/libc/test/src/sys/stat/stat_test.cpp +++ b/libc/test/src/sys/stat/stat_test.cpp @@ -14,7 +14,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include +#include "hdr/fcntl_macros.h" #include TEST(LlvmLibcStatTest, CreatAndReadMode) { diff --git a/libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp b/libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp index 8cb5f867453e45e4031d4e7e8ff25b53057ee497..2f3e0b96ff09574ab5efc717dd84bb22ab535e65 100644 --- a/libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp +++ b/libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp @@ -1,4 +1,4 @@ -#include "llvm-libc-macros/linux/fcntl-macros.h" +#include "hdr/fcntl_macros.h" #include "src/__support/macros/config.h" #include "src/fcntl/open.h" #include "src/sys/statvfs/fstatvfs.h" diff --git a/libc/test/src/unistd/CMakeLists.txt b/libc/test/src/unistd/CMakeLists.txt index e03e56b3cf8ad71b27df3573b1a2ee646e679ec5..ce936cebad4260cfcdcfd640d556e65b1ae0bdf9 100644 --- a/libc/test/src/unistd/CMakeLists.txt +++ b/libc/test/src/unistd/CMakeLists.txt @@ -24,11 +24,12 @@ add_libc_unittest( SRCS chdir_test.cpp DEPENDS + libc.hdr.fcntl_macros libc.include.unistd libc.src.errno.errno - libc.src.fcntl.open libc.src.unistd.chdir libc.src.unistd.close + libc.src.fcntl.open libc.test.UnitTest.ErrnoSetterMatcher ) @@ -223,7 +224,7 @@ add_libc_unittest( SRCS rmdir_test.cpp DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.src.errno.errno libc.src.sys.stat.mkdir libc.src.unistd.rmdir @@ -262,7 +263,7 @@ add_libc_unittest( SRCS readlinkat_test.cpp DEPENDS - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.unistd libc.src.errno.errno libc.src.unistd.readlinkat @@ -410,7 +411,7 @@ add_libc_unittest( syscall_test.cpp DEPENDS libc.include.unistd - libc.include.fcntl + libc.hdr.fcntl_macros libc.include.sys_syscall libc.src.errno.errno libc.src.unistd.__llvm_libc_syscall diff --git a/libc/test/src/unistd/chdir_test.cpp b/libc/test/src/unistd/chdir_test.cpp index 51dc7bb15d3ee6d822205c2c9c5b143019480d7c..e1bdcd77119f733f79deb8b946b4be9c3756beec 100644 --- a/libc/test/src/unistd/chdir_test.cpp +++ b/libc/test/src/unistd/chdir_test.cpp @@ -13,7 +13,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include +#include "hdr/fcntl_macros.h" TEST(LlvmLibcChdirTest, ChangeAndOpen) { // The idea of this test is that we will first open an existing test file diff --git a/libc/test/src/unistd/fchdir_test.cpp b/libc/test/src/unistd/fchdir_test.cpp index ae88e1f22ed6b7684ce025c37253b383236d25d2..0e39fde17c67bbac51b439d33e1da0129230678a 100644 --- a/libc/test/src/unistd/fchdir_test.cpp +++ b/libc/test/src/unistd/fchdir_test.cpp @@ -13,7 +13,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include +#include "hdr/fcntl_macros.h" TEST(LlvmLibcChdirTest, ChangeAndOpen) { // The idea of this test is that we will first open an existing test file diff --git a/libc/test/src/unistd/readlinkat_test.cpp b/libc/test/src/unistd/readlinkat_test.cpp index 1fa683b02b5b5e67e3d8a1dbffa84c9fb7e2e2d2..9e4bb9af02e76a938723be5d129ea3c3ac1fe108 100644 --- a/libc/test/src/unistd/readlinkat_test.cpp +++ b/libc/test/src/unistd/readlinkat_test.cpp @@ -15,7 +15,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include +#include "hdr/fcntl_macros.h" namespace cpp = LIBC_NAMESPACE::cpp; diff --git a/libc/test/src/unistd/rmdir_test.cpp b/libc/test/src/unistd/rmdir_test.cpp index 93cb0f3f53c1b0bc963c6b33376283c245c7512d..4f4cd94c5cf0b7374d78e3334ad8aa731421e2f6 100644 --- a/libc/test/src/unistd/rmdir_test.cpp +++ b/libc/test/src/unistd/rmdir_test.cpp @@ -12,7 +12,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include +#include "hdr/fcntl_macros.h" TEST(LlvmLibcRmdirTest, CreateAndRemove) { using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; diff --git a/libc/test/src/unistd/syscall_test.cpp b/libc/test/src/unistd/syscall_test.cpp index cee29bd9afa308b4f36f5989b6e725712d0f1f1b..f6cc3eab9aabe876657dd9efd7fd42d3f3806500 100644 --- a/libc/test/src/unistd/syscall_test.cpp +++ b/libc/test/src/unistd/syscall_test.cpp @@ -11,7 +11,7 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include +#include "hdr/fcntl_macros.h" #include // For S_* flags. #include // For syscall numbers. #include diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp index bd4fbe294a622d3b66fbf18aadb32c202233a4cb..60e4abadb5e3c8a5cec780ba82d5da55c855db80 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -255,19 +255,13 @@ public: mpfr_cospi(result.value, value, mpfr_rounding); return result; #else - MPFRNumber value_frac(*this); - mpfr_frac(value_frac.value, value, MPFR_RNDN); - - if (mpfr_cmp_si(value_frac.value, 0.0) == 0) { - mpz_t integer_part; - mpz_init(integer_part); - mpfr_get_z(integer_part, value, MPFR_RNDN); - - if (mpz_tstbit(integer_part, 0)) { - mpfr_set_si(result.value, -1.0, MPFR_RNDN); // odd - } else { - mpfr_set_si(result.value, 1.0, MPFR_RNDN); // even - } + if (mpfr_integer_p(value)) { + mpz_t integer; + mpz_init(integer); + mpfr_get_z(integer, value, mpfr_rounding); + + int d = mpz_tstbit(integer, 0); + mpfr_set_si(result.value, d ? -1 : 1, mpfr_rounding); return result; } diff --git a/libclc/CMakeLists.txt b/libclc/CMakeLists.txt index 3d7c3591a556e56f3e1f7bc066992ba56d96cbfb..16d74e53295cc1258092e830aeb3ab262e4033bc 100644 --- a/libclc/CMakeLists.txt +++ b/libclc/CMakeLists.txt @@ -29,7 +29,13 @@ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ptx-nvidiacl/lib/SOURCES; r600/lib/SOURCES; spirv/lib/SOURCES; - spirv64/lib/SOURCES + spirv64/lib/SOURCES; + # CLC internal libraries + clc/lib/generic/SOURCES; + clc/lib/clspv/SOURCES; + clc/lib/clspv64/SOURCES; + clc/lib/spirv/SOURCES; + clc/lib/spirv64/SOURCES; ) set( LIBCLC_MIN_LLVM 3.9.0 ) @@ -278,49 +284,30 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} ) set( DARCH ${ARCH} ) endif() - # Enumerate SOURCES* files - set( source_list ) - foreach( l ${dirs} ${DARCH} ${DARCH}-${OS} ${DARCH}-${VENDOR}-${OS} ) - foreach( s "SOURCES" "SOURCES_${LLVM_MAJOR}.${LLVM_MINOR}" ) - file( TO_CMAKE_PATH ${l}/lib/${s} file_loc ) - file( TO_CMAKE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${file_loc} loc ) - # Prepend the location to give higher priority to - # specialized implementation - if( EXISTS ${loc} ) - set( source_list ${file_loc} ${source_list} ) - endif() - endforeach() - endforeach() - - # Add the generated convert.cl here to prevent adding the one listed in - # SOURCES - set( objects ) # A "set" of already-added input files - set( rel_files ) # Source directory input files, relative to the root dir - set( gen_files ) # Generated binary input files, relative to the binary dir - if( NOT ${ARCH} STREQUAL "spirv" AND NOT ${ARCH} STREQUAL "spirv64" ) - if( NOT ENABLE_RUNTIME_SUBNORMAL AND NOT ${ARCH} STREQUAL "clspv" AND - NOT ${ARCH} STREQUAL "clspv64" ) - list( APPEND gen_files convert.cl ) - list( APPEND objects convert.cl ) - list( APPEND rel_files generic/lib/subnormal_use_default.ll ) - elseif(${ARCH} STREQUAL "clspv" OR ${ARCH} STREQUAL "clspv64") - list( APPEND gen_files clspv-convert.cl ) - list( APPEND objects clspv-convert.cl ) + set( clc_lib_files ) + libclc_configure_lib_source( + clc_lib_files + CLC_INTERNAL + LIB_ROOT_DIR clc + DIRS ${dirs} ${DARCH} ${DARCH}-${OS} ${DARCH}-${VENDOR}-${OS} + ) + + set( opencl_lib_files ) + set( opencl_gen_files ) + + if( NOT ARCH STREQUAL spirv AND NOT ARCH STREQUAL spirv64 ) + if( ARCH STREQUAL clspv OR ARCH STREQUAL clspv64 ) + list( APPEND opencl_gen_files clspv-convert.cl ) + elseif ( NOT ENABLE_RUNTIME_SUBNORMAL ) + list( APPEND opencl_gen_files convert.cl ) + list( APPEND opencl_lib_files generic/lib/subnormal_use_default.ll ) endif() endif() - foreach( l ${source_list} ) - file( READ ${l} file_list ) - string( REPLACE "\n" ";" file_list ${file_list} ) - get_filename_component( dir ${l} DIRECTORY ) - foreach( f ${file_list} ) - # Only add each file once, so that targets can 'specialize' builtins - if( NOT ${f} IN_LIST objects ) - list( APPEND objects ${f} ) - list( APPEND rel_files ${dir}/${f} ) - endif() - endforeach() - endforeach() + libclc_configure_lib_source( + opencl_lib_files + DIRS ${dirs} ${DARCH} ${DARCH}-${OS} ${DARCH}-${VENDOR}-${OS} + ) foreach( d ${${t}_devices} ) get_libclc_device_info( @@ -331,11 +318,6 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} ) CLANG_TRIPLE clang_triple ) - set( mcpu ) - if( NOT "${cpu}" STREQUAL "" ) - set( mcpu "-mcpu=${cpu}" ) - endif() - message( STATUS " device: ${d} ( ${${d}_aliases} )" ) if ( ARCH STREQUAL spirv OR ARCH STREQUAL spirv64 ) @@ -358,114 +340,41 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} ) list( APPEND build_flags -D__CLC_INTERNAL -D${CLC_TARGET_DEFINE} - -I${CMAKE_CURRENT_SOURCE_DIR}/generic/include + # All libclc builtin libraries see CLC headers + -I${CMAKE_CURRENT_SOURCE_DIR}/clc/include # FIXME: Fix libclc to not require disabling this noisy warning -Wno-bitwise-conditional-parentheses ) - set( bytecode_files "" ) - foreach( file IN LISTS gen_files rel_files ) - # We need to take each file and produce an absolute input file, as well - # as a unique architecture-specific output file. We deal with a mix of - # different input files, which makes this trickier. - if( ${file} IN_LIST gen_files ) - # Generated files are given just as file names, which we must make - # absolute to the binary directory. - set( input_file ${CMAKE_CURRENT_BINARY_DIR}/${file} ) - set( output_file "${LIBCLC_ARCH_OBJFILE_DIR}/${file}.bc" ) - else() - # Other files are originally relative to each SOURCE file, which are - # then make relative to the libclc root directory. We must normalize - # the path (e.g., ironing out any ".."), then make it relative to the - # root directory again, and use that relative path component for the - # binary path. - get_filename_component( abs_path ${file} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR} ) - file( RELATIVE_PATH root_rel_path ${CMAKE_CURRENT_SOURCE_DIR} ${abs_path} ) - set( input_file ${CMAKE_CURRENT_SOURCE_DIR}/${file} ) - set( output_file "${LIBCLC_ARCH_OBJFILE_DIR}/${root_rel_path}.bc" ) - endif() - - get_filename_component( file_dir ${file} DIRECTORY ) - - compile_to_bc( - TRIPLE ${clang_triple} - INPUT ${input_file} - OUTPUT ${output_file} - EXTRA_OPTS "${mcpu}" -fno-builtin -nostdlib - "${build_flags}" -I${CMAKE_CURRENT_SOURCE_DIR}/${file_dir} - DEPENDENCIES generate_convert.cl clspv-generate_convert.cl - ) - list( APPEND bytecode_files ${output_file} ) - endforeach() + if( NOT "${cpu}" STREQUAL "" ) + list( APPEND build_flags -mcpu=${cpu} ) + endif() - set( builtins_comp_lib_tgt builtins.comp.${arch_suffix} ) - add_custom_target( ${builtins_comp_lib_tgt} - DEPENDS ${bytecode_files} + add_libclc_builtin_set( + CLC_INTERNAL + ARCH ${ARCH} + ARCH_SUFFIX clc-${arch_suffix} + TRIPLE ${clang_triple} + COMPILE_FLAGS ${build_flags} + OPT_FLAGS ${opt_flags} + LIB_FILES ${clc_lib_files} ) - set_target_properties( ${builtins_comp_lib_tgt} PROPERTIES FOLDER "libclc/Device IR/Comp" ) - set( builtins_link_lib_tgt builtins.link.${arch_suffix} ) - link_bc( - TARGET ${builtins_link_lib_tgt} - INPUTS ${bytecode_files} - DEPENDENCIES ${builtins_comp_lib_tgt} + list( APPEND build_flags + -I${CMAKE_CURRENT_SOURCE_DIR}/generic/include ) - set( builtins_link_lib $ ) - - if( ARCH STREQUAL spirv OR ARCH STREQUAL spirv64 ) - set( spv_suffix ${arch_suffix}.spv ) - add_custom_command( OUTPUT ${spv_suffix} - COMMAND ${llvm-spirv_exe} ${spvflags} -o ${spv_suffix} ${builtins_link_lib} - DEPENDS ${llvm-spirv_target} ${builtins_link_lib} ${builtins_link_lib_tgt} - ) - add_custom_target( "prepare-${spv_suffix}" ALL DEPENDS "${spv_suffix}" ) - set_target_properties( "prepare-${spv_suffix}" PROPERTIES FOLDER "libclc/Device IR/Prepare" ) - install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${spv_suffix} - DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" ) - else() - set( builtins_opt_lib_tgt builtins.opt.${arch_suffix} ) - - # Add opt target - add_custom_command( OUTPUT ${builtins_opt_lib_tgt}.bc - COMMAND ${opt_exe} ${opt_flags} -o ${builtins_opt_lib_tgt}.bc - ${builtins_link_lib} - DEPENDS ${opt_target} ${builtins_link_lib} ${builtins_link_lib_tgt} - ) - add_custom_target( ${builtins_opt_lib_tgt} - ALL DEPENDS ${builtins_opt_lib_tgt}.bc - ) - set_target_properties( ${builtins_opt_lib_tgt} PROPERTIES - TARGET_FILE ${CMAKE_CURRENT_BINARY_DIR}/${builtins_opt_lib_tgt}.bc - FOLDER "libclc/Device IR/Opt" - ) - - set( builtins_opt_lib $ ) - - # Add prepare target - set( obj_suffix ${arch_suffix}.bc ) - add_custom_command( OUTPUT ${obj_suffix} - COMMAND ${prepare_builtins_exe} -o ${obj_suffix} ${builtins_opt_lib} - DEPENDS ${builtins_opt_lib} ${builtins_opt_lib_tgt} ${prepare_builtins_target} ) - add_custom_target( prepare-${obj_suffix} ALL DEPENDS ${obj_suffix} ) - set_target_properties( "prepare-${obj_suffix}" PROPERTIES FOLDER "libclc/Device IR/Prepare" ) - - # nvptx-- targets don't include workitem builtins - if( NOT clang_triple MATCHES ".*ptx.*--$" ) - add_test( NAME external-calls-${obj_suffix} - COMMAND ./check_external_calls.sh ${CMAKE_CURRENT_BINARY_DIR}/${obj_suffix} ${LLVM_TOOLS_BINARY_DIR} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) - endif() - - install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${obj_suffix} DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" ) - foreach( a ${${d}_aliases} ) - set( alias_suffix "${a}-${clang_triple}.bc" ) - add_custom_target( ${alias_suffix} ALL - COMMAND ${CMAKE_COMMAND} -E create_symlink ${obj_suffix} ${alias_suffix} - DEPENDS prepare-${obj_suffix} ) - set_target_properties( "${alias_suffix}" PROPERTIES FOLDER "libclc/Device IR/Aliases" ) - install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${alias_suffix} DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" ) - endforeach( a ) - endif() + add_libclc_builtin_set( + ARCH ${ARCH} + ARCH_SUFFIX ${arch_suffix} + TRIPLE ${clang_triple} + COMPILE_FLAGS ${build_flags} + OPT_FLAGS ${opt_flags} + LIB_FILES ${opencl_lib_files} + GEN_FILES ${opencl_gen_files} + ALIASES ${${d}_aliases} + # Link in the CLC builtins and internalize their symbols + INTERNAL_LINK_DEPENDENCIES $ + ) endforeach( d ) endforeach( t ) diff --git a/libclc/generic/include/clc/clcfunc.h b/libclc/clc/include/clc/clcfunc.h similarity index 85% rename from libclc/generic/include/clc/clcfunc.h rename to libclc/clc/include/clc/clcfunc.h index 086d780b970859da9e3c163cdf0bbe1f9be56d0d..fe3406f64fecb8d40cc93670852de1cbb1976abf 100644 --- a/libclc/generic/include/clc/clcfunc.h +++ b/libclc/clc/include/clc/clcfunc.h @@ -1,3 +1,6 @@ +#ifndef __CLC_CLCFUNC_H_ +#define __CLC_CLCFUNC_H_ + #define _CLC_OVERLOAD __attribute__((overloadable)) #define _CLC_DECL #define _CLC_INLINE __attribute__((always_inline)) inline @@ -11,3 +14,5 @@ #else #define _CLC_DEF __attribute__((always_inline)) #endif + +#endif // __CLC_CLCFUNC_H_ diff --git a/libclc/generic/include/clc/clctypes.h b/libclc/clc/include/clc/clctypes.h similarity index 94% rename from libclc/generic/include/clc/clctypes.h rename to libclc/clc/include/clc/clctypes.h index 76b816d395c2888719ecbf9f43bae4de69cfebcc..8ededd967e003391fadc5fde458b66278366a0b4 100644 --- a/libclc/generic/include/clc/clctypes.h +++ b/libclc/clc/include/clc/clctypes.h @@ -1,3 +1,6 @@ +#ifndef __CLC_CLCTYPES_H_ +#define __CLC_CLCTYPES_H_ + /* 6.1.1 Built-in Scalar Data Types */ typedef unsigned char uchar; @@ -8,12 +11,12 @@ typedef unsigned long ulong; typedef __SIZE_TYPE__ size_t; typedef __PTRDIFF_TYPE__ ptrdiff_t; -#define __stdint_join3(a,b,c) a ## b ## c +#define __stdint_join3(a, b, c) a##b##c -#define __intn_t(n) __stdint_join3(__INT, n, _TYPE__) +#define __intn_t(n) __stdint_join3(__INT, n, _TYPE__) #define __uintn_t(n) __stdint_join3(unsigned __INT, n, _TYPE__) -typedef __intn_t(__INTPTR_WIDTH__) intptr_t; +typedef __intn_t(__INTPTR_WIDTH__) intptr_t; typedef __uintn_t(__INTPTR_WIDTH__) uintptr_t; #undef __uintn_t @@ -93,3 +96,5 @@ typedef __attribute__((ext_vector_type(4))) half half4; typedef __attribute__((ext_vector_type(8))) half half8; typedef __attribute__((ext_vector_type(16))) half half16; #endif + +#endif // __CLC_CLCTYPES_H_ diff --git a/libclc/clc/include/clc/geometric/clc_dot.h b/libclc/clc/include/clc/geometric/clc_dot.h new file mode 100644 index 0000000000000000000000000000000000000000..e0e47ab2093efdb367df27ae27c0f0293ab70ab5 --- /dev/null +++ b/libclc/clc/include/clc/geometric/clc_dot.h @@ -0,0 +1,2 @@ +#define __CLC_BODY +#include diff --git a/libclc/clc/include/clc/geometric/clc_dot.inc b/libclc/clc/include/clc/geometric/clc_dot.inc new file mode 100644 index 0000000000000000000000000000000000000000..016b564df362d20415e53b889bb0b7d4056d3887 --- /dev/null +++ b/libclc/clc/include/clc/geometric/clc_dot.inc @@ -0,0 +1 @@ +_CLC_OVERLOAD _CLC_DECL __CLC_FLOAT __clc_dot(__CLC_FLOATN p0, __CLC_FLOATN p1); diff --git a/libclc/clc/include/clc/internal/clc.h b/libclc/clc/include/clc/internal/clc.h new file mode 100644 index 0000000000000000000000000000000000000000..c3bdfd754105f741389b68c0b0eabe519d6e3b5f --- /dev/null +++ b/libclc/clc/include/clc/internal/clc.h @@ -0,0 +1,26 @@ +#ifndef __CLC_INTERNAL_CLC_H_ +#define __CLC_INTERNAL_CLC_H_ + +#ifndef cl_clang_storage_class_specifiers +#error Implementation requires cl_clang_storage_class_specifiers extension! +#endif + +#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable + +#ifdef cl_khr_fp64 +#pragma OPENCL EXTENSION cl_khr_fp64 : enable +#endif + +#ifdef cl_khr_fp16 +#pragma OPENCL EXTENSION cl_khr_fp16 : enable +#endif + +/* Function Attributes */ +#include + +/* 6.1 Supported Data Types */ +#include + +#pragma OPENCL EXTENSION all : disable + +#endif // __CLC_INTERNAL_CLC_H_ diff --git a/libclc/clc/lib/clspv/SOURCES b/libclc/clc/lib/clspv/SOURCES new file mode 100644 index 0000000000000000000000000000000000000000..75a3130357c3456797386c41ca3e7cb07b844587 --- /dev/null +++ b/libclc/clc/lib/clspv/SOURCES @@ -0,0 +1 @@ +dummy.cl diff --git a/libclc/clc/lib/clspv/dummy.cl b/libclc/clc/lib/clspv/dummy.cl new file mode 100644 index 0000000000000000000000000000000000000000..fab17ac780e37516a47cc8b0310cae7caa3a1baf --- /dev/null +++ b/libclc/clc/lib/clspv/dummy.cl @@ -0,0 +1 @@ +// Empty file diff --git a/libclc/clc/lib/clspv64 b/libclc/clc/lib/clspv64 new file mode 120000 index 0000000000000000000000000000000000000000..ea01ba94bc636848ddffb84109f76b4ab6e3e5d2 --- /dev/null +++ b/libclc/clc/lib/clspv64 @@ -0,0 +1 @@ +clspv \ No newline at end of file diff --git a/libclc/clc/lib/generic/SOURCES b/libclc/clc/lib/generic/SOURCES new file mode 100644 index 0000000000000000000000000000000000000000..fa2e4f50b99cd7746ea800584623ea50cd68071b --- /dev/null +++ b/libclc/clc/lib/generic/SOURCES @@ -0,0 +1 @@ +geometric/clc_dot.cl diff --git a/libclc/clc/lib/generic/geometric/clc_dot.cl b/libclc/clc/lib/generic/geometric/clc_dot.cl new file mode 100644 index 0000000000000000000000000000000000000000..bf0f19b51bc05eafb0b19ec800d75c7da8c01fde --- /dev/null +++ b/libclc/clc/lib/generic/geometric/clc_dot.cl @@ -0,0 +1,57 @@ +#include + +_CLC_OVERLOAD _CLC_DEF float __clc_dot(float p0, float p1) { return p0 * p1; } + +_CLC_OVERLOAD _CLC_DEF float __clc_dot(float2 p0, float2 p1) { + return p0.x * p1.x + p0.y * p1.y; +} + +_CLC_OVERLOAD _CLC_DEF float __clc_dot(float3 p0, float3 p1) { + return p0.x * p1.x + p0.y * p1.y + p0.z * p1.z; +} + +_CLC_OVERLOAD _CLC_DEF float __clc_dot(float4 p0, float4 p1) { + return p0.x * p1.x + p0.y * p1.y + p0.z * p1.z + p0.w * p1.w; +} + +#ifdef cl_khr_fp64 + +#pragma OPENCL EXTENSION cl_khr_fp64 : enable + +_CLC_OVERLOAD _CLC_DEF double __clc_dot(double p0, double p1) { + return p0 * p1; +} + +_CLC_OVERLOAD _CLC_DEF double __clc_dot(double2 p0, double2 p1) { + return p0.x * p1.x + p0.y * p1.y; +} + +_CLC_OVERLOAD _CLC_DEF double __clc_dot(double3 p0, double3 p1) { + return p0.x * p1.x + p0.y * p1.y + p0.z * p1.z; +} + +_CLC_OVERLOAD _CLC_DEF double __clc_dot(double4 p0, double4 p1) { + return p0.x * p1.x + p0.y * p1.y + p0.z * p1.z + p0.w * p1.w; +} + +#endif + +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + +_CLC_OVERLOAD _CLC_DEF half __clc_dot(half p0, half p1) { return p0 * p1; } + +_CLC_OVERLOAD _CLC_DEF half __clc_dot(half2 p0, half2 p1) { + return p0.x * p1.x + p0.y * p1.y; +} + +_CLC_OVERLOAD _CLC_DEF half __clc_dot(half3 p0, half3 p1) { + return p0.x * p1.x + p0.y * p1.y + p0.z * p1.z; +} + +_CLC_OVERLOAD _CLC_DEF half __clc_dot(half4 p0, half4 p1) { + return p0.x * p1.x + p0.y * p1.y + p0.z * p1.z + p0.w * p1.w; +} + +#endif diff --git a/libclc/clc/lib/spirv/SOURCES b/libclc/clc/lib/spirv/SOURCES new file mode 100644 index 0000000000000000000000000000000000000000..d8effd19613c8b5ca664f8eb4de3c8b836d3893c --- /dev/null +++ b/libclc/clc/lib/spirv/SOURCES @@ -0,0 +1,2 @@ +../generic/geometric/clc_dot.cl + diff --git a/libclc/clc/lib/spirv64/SOURCES b/libclc/clc/lib/spirv64/SOURCES new file mode 100644 index 0000000000000000000000000000000000000000..9200810ace38e7cd0122bffad73d5c0ab0e74577 --- /dev/null +++ b/libclc/clc/lib/spirv64/SOURCES @@ -0,0 +1 @@ +../generic/geometric/clc_dot.cl diff --git a/libclc/cmake/modules/AddLibclc.cmake b/libclc/cmake/modules/AddLibclc.cmake index f2032660ba99b0b6a782d0946a7696eb0e9177e7..ee7c8500c8359fb3593eaba1d8b979ec63d3fb3b 100644 --- a/libclc/cmake/modules/AddLibclc.cmake +++ b/libclc/cmake/modules/AddLibclc.cmake @@ -76,6 +76,8 @@ endfunction() # Links together one or more bytecode files # # Arguments: +# * INTERNALIZE +# Set if -internalize flag should be passed when linking # * TARGET # Custom target to create # * INPUT ... @@ -84,7 +86,7 @@ endfunction() # List of extra dependencies to inject function(link_bc) cmake_parse_arguments(ARG - "" + "INTERNALIZE" "TARGET" "INPUTS;DEPENDENCIES" ${ARGN} @@ -97,7 +99,7 @@ function(link_bc) file( TO_CMAKE_PATH ${LIBCLC_ARCH_OBJFILE_DIR}/${ARG_TARGET}.rsp RSP_FILE ) # Turn it into a space-separate list of input files list( JOIN ARG_INPUTS " " RSP_INPUT ) - file( WRITE ${RSP_FILE} ${RSP_INPUT} ) + file( GENERATE OUTPUT ${RSP_FILE} CONTENT ${RSP_INPUT} ) # Ensure that if this file is removed, we re-run CMake set_property( DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${RSP_FILE} @@ -107,7 +109,7 @@ function(link_bc) add_custom_command( OUTPUT ${ARG_TARGET}.bc - COMMAND ${llvm-link_exe} -o ${ARG_TARGET}.bc ${LINK_INPUT_ARG} + COMMAND ${llvm-link_exe} $<$:--internalize> -o ${ARG_TARGET}.bc ${LINK_INPUT_ARG} DEPENDS ${llvm-link_target} ${ARG_DEPENDENCIES} ${ARG_INPUTS} ${RSP_FILE} ) @@ -178,3 +180,251 @@ function(get_libclc_device_info) set( ${ARG_CLANG_TRIPLE} ${ARG_TRIPLE} PARENT_SCOPE ) endif() endfunction() + +# Compiles a list of library source files (provided by LIB_FILES/GEN_FILES) and +# compiles them to LLVM bytecode (or SPIR-V), links them together and optimizes +# them. +# +# For bytecode libraries, a list of ALIASES may optionally be provided to +# produce additional symlinks. +# +# Arguments: +# * ARCH +# libclc architecture being built +# * ARCH_SUFFIX +# libclc architecture/triple suffix +# * TRIPLE +# Triple used to compile +# +# Optional Arguments: +# * CLC_INTERNAL +# Pass if compiling the internal CLC builtin libraries, which are not +# optimized and do not have aliases created. +# * LIB_FILES ... +# List of files that should be built for this library +# * GEN_FILES ... +# List of generated files (in build dir) that should be built for this library +# * COMPILE_FLAGS ... +# Compilation options (for clang) +# * OPT_FLAGS ... +# Optimization options (for opt) +# * ALIASES ... +# List of aliases +# * INTERNAL_LINK_DEPENDENCIES ... +# A list of extra bytecode files to link into the builtin library. Symbols +# from these link dependencies will be internalized during linking. +function(add_libclc_builtin_set) + cmake_parse_arguments(ARG + "CLC_INTERNAL" + "ARCH;TRIPLE;ARCH_SUFFIX" + "LIB_FILES;GEN_FILES;COMPILE_FLAGS;OPT_FLAGS;ALIASES;INTERNAL_LINK_DEPENDENCIES" + ${ARGN} + ) + + if( NOT ARG_ARCH OR NOT ARG_ARCH_SUFFIX OR NOT ARG_TRIPLE ) + message( FATAL_ERROR "Must provide ARCH, ARCH_SUFFIX, and TRIPLE" ) + endif() + + set( bytecode_files "" ) + foreach( file IN LISTS ARG_GEN_FILES ARG_LIB_FILES ) + # We need to take each file and produce an absolute input file, as well + # as a unique architecture-specific output file. We deal with a mix of + # different input files, which makes this trickier. + if( ${file} IN_LIST ARG_GEN_FILES ) + # Generated files are given just as file names, which we must make + # absolute to the binary directory. + set( input_file ${CMAKE_CURRENT_BINARY_DIR}/${file} ) + set( output_file "${LIBCLC_ARCH_OBJFILE_DIR}/${file}.bc" ) + else() + # Other files are originally relative to each SOURCE file, which are + # then make relative to the libclc root directory. We must normalize + # the path (e.g., ironing out any ".."), then make it relative to the + # root directory again, and use that relative path component for the + # binary path. + get_filename_component( abs_path ${file} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR} ) + file( RELATIVE_PATH root_rel_path ${CMAKE_CURRENT_SOURCE_DIR} ${abs_path} ) + set( input_file ${CMAKE_CURRENT_SOURCE_DIR}/${file} ) + set( output_file "${LIBCLC_ARCH_OBJFILE_DIR}/${root_rel_path}.bc" ) + endif() + + get_filename_component( file_dir ${file} DIRECTORY ) + + compile_to_bc( + TRIPLE ${ARG_TRIPLE} + INPUT ${input_file} + OUTPUT ${output_file} + EXTRA_OPTS -fno-builtin -nostdlib + "${ARG_COMPILE_FLAGS}" -I${CMAKE_CURRENT_SOURCE_DIR}/${file_dir} + DEPENDENCIES generate_convert.cl clspv-generate_convert.cl + ) + list( APPEND bytecode_files ${output_file} ) + endforeach() + + set( builtins_comp_lib_tgt builtins.comp.${ARG_ARCH_SUFFIX} ) + add_custom_target( ${builtins_comp_lib_tgt} + DEPENDS ${bytecode_files} + ) + set_target_properties( ${builtins_comp_lib_tgt} PROPERTIES FOLDER "libclc/Device IR/Comp" ) + + if( NOT bytecode_files ) + message(FATAL_ERROR "Cannot create an empty builtins library") + endif() + + set( builtins_link_lib_tgt builtins.link.${ARG_ARCH_SUFFIX} ) + + if( NOT ARG_INTERNAL_LINK_DEPENDENCIES ) + link_bc( + TARGET ${builtins_link_lib_tgt} + INPUTS ${bytecode_files} + DEPENDENCIES ${builtins_comp_lib_tgt} + ) + else() + # If we have libraries to link while internalizing their symbols, we need + # two separate link steps; the --internalize flag applies to all link + # inputs but the first. + set( builtins_link_lib_tmp_tgt builtins.link.pre-deps.${ARG_ARCH_SUFFIX} ) + link_bc( + TARGET ${builtins_link_lib_tmp_tgt} + INPUTS ${bytecode_files} + DEPENDENCIES ${builtins_comp_lib_tgt} + ) + link_bc( + INTERNALIZE + TARGET ${builtins_link_lib_tgt} + INPUTS $ + ${ARG_INTERNAL_LINK_DEPENDENCIES} + DEPENDENCIES ${builtins_link_lib_tmp_tgt} + ) + endif() + + # For the CLC internal builtins, exit here - we only optimize the targets' + # entry points once we've linked the CLC buitins into them + if( ARG_CLC_INTERNAL ) + return() + endif() + + set( builtins_link_lib $ ) + + if( ARG_ARCH STREQUAL spirv OR ARG_ARCH STREQUAL spirv64 ) + set( spv_suffix ${ARG_ARCH_SUFFIX}.spv ) + add_custom_command( OUTPUT ${spv_suffix} + COMMAND ${llvm-spirv_exe} ${spvflags} -o ${spv_suffix} ${builtins_link_lib} + DEPENDS ${llvm-spirv_target} ${builtins_link_lib} ${builtins_link_lib_tgt} + ) + add_custom_target( "prepare-${spv_suffix}" ALL DEPENDS "${spv_suffix}" ) + set_target_properties( "prepare-${spv_suffix}" PROPERTIES FOLDER "libclc/Device IR/Prepare" ) + install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${spv_suffix} + DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" ) + + return() + endif() + + set( builtins_opt_lib_tgt builtins.opt.${ARG_ARCH_SUFFIX} ) + + # Add opt target + add_custom_command( OUTPUT ${builtins_opt_lib_tgt}.bc + COMMAND ${opt_exe} ${ARG_OPT_FLAGS} -o ${builtins_opt_lib_tgt}.bc + ${builtins_link_lib} + DEPENDS ${opt_target} ${builtins_link_lib} ${builtins_link_lib_tgt} + ) + add_custom_target( ${builtins_opt_lib_tgt} + ALL DEPENDS ${builtins_opt_lib_tgt}.bc + ) + set_target_properties( ${builtins_opt_lib_tgt} PROPERTIES + TARGET_FILE ${CMAKE_CURRENT_BINARY_DIR}/${builtins_opt_lib_tgt}.bc + FOLDER "libclc/Device IR/Opt" + ) + + set( builtins_opt_lib $ ) + + # Add prepare target + set( obj_suffix ${ARG_ARCH_SUFFIX}.bc ) + add_custom_command( OUTPUT ${obj_suffix} + COMMAND ${prepare_builtins_exe} -o ${obj_suffix} ${builtins_opt_lib} + DEPENDS ${builtins_opt_lib} ${builtins_opt_lib_tgt} ${prepare_builtins_target} ) + add_custom_target( prepare-${obj_suffix} ALL DEPENDS ${obj_suffix} ) + set_target_properties( "prepare-${obj_suffix}" PROPERTIES FOLDER "libclc/Device IR/Prepare" ) + + # nvptx-- targets don't include workitem builtins + if( NOT ARG_TRIPLE MATCHES ".*ptx.*--$" ) + add_test( NAME external-calls-${obj_suffix} + COMMAND ./check_external_calls.sh ${CMAKE_CURRENT_BINARY_DIR}/${obj_suffix} ${LLVM_TOOLS_BINARY_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) + endif() + + install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${obj_suffix} DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" ) + foreach( a ${ARG_ALIASES} ) + set( alias_suffix "${a}-${ARG_TRIPLE}.bc" ) + add_custom_target( ${alias_suffix} ALL + COMMAND ${CMAKE_COMMAND} -E create_symlink ${obj_suffix} ${alias_suffix} + DEPENDS prepare-${obj_suffix} ) + set_target_properties( "${alias_suffix}" PROPERTIES FOLDER "libclc/Device IR/Aliases" ) + install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${alias_suffix} DESTINATION "${CMAKE_INSTALL_DATADIR}/clc" ) + endforeach( a ) +endfunction(add_libclc_builtin_set) + +# Produces a list of libclc source files by walking over SOURCES files in a +# given directory. Outputs the list of files in LIB_FILE_LIST. +# +# LIB_FILE_LIST may be pre-populated and is appended to. +# +# Arguments: +# * CLC_INTERNAL +# Pass if compiling the internal CLC builtin libraries, which have a +# different directory structure. +# * LIB_ROOT_DIR +# Root directory containing target's lib files, relative to libclc root +# directory. If not provided, is set to '.'. +# * DIRS ... +# List of directories under LIB_ROOT_DIR to walk over searching for SOURCES +# files +function(libclc_configure_lib_source LIB_FILE_LIST) + cmake_parse_arguments(ARG + "CLC_INTERNAL" + "LIB_ROOT_DIR" + "DIRS" + ${ARGN} + ) + + if( NOT ARG_LIB_ROOT_DIR ) + set(ARG_LIB_ROOT_DIR ".") + endif() + + # Enumerate SOURCES* files + set( source_list ) + foreach( l ${ARG_DIRS} ) + foreach( s "SOURCES" "SOURCES_${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}" ) + if( ARG_CLC_INTERNAL ) + file( TO_CMAKE_PATH ${ARG_LIB_ROOT_DIR}/lib/${l}/${s} file_loc ) + else() + file( TO_CMAKE_PATH ${ARG_LIB_ROOT_DIR}/${l}/lib/${s} file_loc ) + endif() + file( TO_CMAKE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${file_loc} loc ) + # Prepend the location to give higher priority to + # specialized implementation + if( EXISTS ${loc} ) + set( source_list ${file_loc} ${source_list} ) + endif() + endforeach() + endforeach() + + ## Add the generated convert files here to prevent adding the ones listed in + ## SOURCES + set( rel_files ${${LIB_FILE_LIST}} ) # Source directory input files, relative to the root dir + set( objects ${${LIB_FILE_LIST}} ) # A "set" of already-added input files + + foreach( l ${source_list} ) + file( READ ${l} file_list ) + string( REPLACE "\n" ";" file_list ${file_list} ) + get_filename_component( dir ${l} DIRECTORY ) + foreach( f ${file_list} ) + # Only add each file once, so that targets can 'specialize' builtins + if( NOT ${f} IN_LIST objects ) + list( APPEND objects ${f} ) + list( APPEND rel_files ${dir}/${f} ) + endif() + endforeach() + endforeach() + + set( ${LIB_FILE_LIST} ${rel_files} PARENT_SCOPE ) +endfunction(libclc_configure_lib_source LIB_FILE_LIST) diff --git a/libclc/generic/lib/geometric/dot.cl b/libclc/generic/lib/geometric/dot.cl index e58bc26f4333a7efca0faf5251ccb92d9ff7b22d..e790d02636563cdede8b19dc3a02165803f2e0b9 100644 --- a/libclc/generic/lib/geometric/dot.cl +++ b/libclc/generic/lib/geometric/dot.cl @@ -1,19 +1,20 @@ #include +#include _CLC_OVERLOAD _CLC_DEF float dot(float p0, float p1) { - return p0*p1; + return __clc_dot(p0, p1); } _CLC_OVERLOAD _CLC_DEF float dot(float2 p0, float2 p1) { - return p0.x*p1.x + p0.y*p1.y; + return __clc_dot(p0, p1); } _CLC_OVERLOAD _CLC_DEF float dot(float3 p0, float3 p1) { - return p0.x*p1.x + p0.y*p1.y + p0.z*p1.z; + return __clc_dot(p0, p1); } _CLC_OVERLOAD _CLC_DEF float dot(float4 p0, float4 p1) { - return p0.x*p1.x + p0.y*p1.y + p0.z*p1.z + p0.w*p1.w; + return __clc_dot(p0, p1); } #ifdef cl_khr_fp64 @@ -21,19 +22,19 @@ _CLC_OVERLOAD _CLC_DEF float dot(float4 p0, float4 p1) { #pragma OPENCL EXTENSION cl_khr_fp64 : enable _CLC_OVERLOAD _CLC_DEF double dot(double p0, double p1) { - return p0*p1; + return __clc_dot(p0, p1); } _CLC_OVERLOAD _CLC_DEF double dot(double2 p0, double2 p1) { - return p0.x*p1.x + p0.y*p1.y; + return __clc_dot(p0, p1); } _CLC_OVERLOAD _CLC_DEF double dot(double3 p0, double3 p1) { - return p0.x*p1.x + p0.y*p1.y + p0.z*p1.z; + return __clc_dot(p0, p1); } _CLC_OVERLOAD _CLC_DEF double dot(double4 p0, double4 p1) { - return p0.x*p1.x + p0.y*p1.y + p0.z*p1.z + p0.w*p1.w; + return __clc_dot(p0, p1); } #endif @@ -42,20 +43,18 @@ _CLC_OVERLOAD _CLC_DEF double dot(double4 p0, double4 p1) { #pragma OPENCL EXTENSION cl_khr_fp16 : enable -_CLC_OVERLOAD _CLC_DEF half dot(half p0, half p1) { - return p0*p1; -} +_CLC_OVERLOAD _CLC_DEF half dot(half p0, half p1) { return __clc_dot(p0, p1); } _CLC_OVERLOAD _CLC_DEF half dot(half2 p0, half2 p1) { - return p0.x*p1.x + p0.y*p1.y; + return __clc_dot(p0, p1); } _CLC_OVERLOAD _CLC_DEF half dot(half3 p0, half3 p1) { - return p0.x*p1.x + p0.y*p1.y + p0.z*p1.z; + return __clc_dot(p0, p1); } _CLC_OVERLOAD _CLC_DEF half dot(half4 p0, half4 p1) { - return p0.x*p1.x + p0.y*p1.y + p0.z*p1.z + p0.w*p1.w; + return __clc_dot(p0, p1); } #endif diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 05b08da521535011ff8c70547a9ea0c29a44a8d1..db24b65caca6c0a9dc810193ec71d8868afba579 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -264,6 +264,8 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_move_iterator_concept`` ``202207L`` ---------------------------------------------------------- ----------------- + ``__cpp_lib_optional`` ``202106L`` + ---------------------------------------------------------- ----------------- ``__cpp_lib_polymorphic_allocator`` ``201902L`` ---------------------------------------------------------- ----------------- ``__cpp_lib_ranges`` ``202110L`` @@ -300,6 +302,8 @@ Status ---------------------------------------------------------- ----------------- ``__cpp_lib_unwrap_ref`` ``201811L`` ---------------------------------------------------------- ----------------- + ``__cpp_lib_variant`` ``202106L`` + ---------------------------------------------------------- ----------------- **C++23** ---------------------------------------------------------------------------- ``__cpp_lib_adaptor_iterator_pair_constructor`` ``202106L`` @@ -491,5 +495,7 @@ Status ``__cpp_lib_to_string`` *unimplemented* ---------------------------------------------------------- ----------------- ``__cpp_lib_tuple_like`` *unimplemented* + ---------------------------------------------------------- ----------------- + ``__cpp_lib_variant`` ``202306L`` ========================================================== ================= diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst index 44912d2ddafac63cbc3a5609382cacec6b555b28..84080e7cbafe2c4ae712204d595cee6a75852e82 100644 --- a/libcxx/docs/ReleaseNotes/20.rst +++ b/libcxx/docs/ReleaseNotes/20.rst @@ -43,6 +43,7 @@ Implemented Papers - P2985R0: A type trait for detecting virtual base classes (`Github `__) - ``std::jthread`` and ```` are not guarded behind ``-fexperimental-library`` anymore - P2674R1: A trait for implicit lifetime types (`Github `__) +- P0429R9: A Standard ``flat_map`` is partially implemented and ``flat_map`` is provided (`Github `__) Improvements and New Features ----------------------------- @@ -83,7 +84,9 @@ Deprecations and Removals ambiguity in name lookup. Code that expects such ambiguity will possibly not compile in LLVM 20. - The function ``__libcpp_verbose_abort()`` is now ``noexcept``, to match ``std::terminate()``. (The combination of - ``noexcept`` and ``[[noreturn]]`` has special significance for function effects analysis.) + ``noexcept`` and ``[[noreturn]]`` has special significance for function effects analysis.) For backwards compatibility, + the ``_LIBCPP_VERBOSE_ABORT_NOT_NOEXCEPT`` macro can be defined to make the function non-``noexcept``. That macro + will be removed in LLVM 21. Upcoming Deprecations and Removals ---------------------------------- @@ -106,6 +109,9 @@ LLVM 21 If you are using C++03 in your project, you should consider moving to a newer version of the Standard to get the most out of libc++. +- The ``_LIBCPP_VERBOSE_ABORT_NOT_NOEXCEPT`` macro will be removed in LLVM 21, making ``std::__libcpp_verbose_abort`` + unconditionally ``noexcept``. + ABI Affecting Changes --------------------- diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv index cc75d28f14aac20b2944e23663e391a61a660556..9a057be8ad0519c0f4aafb154cdec581d8328a00 100644 --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -192,7 +192,7 @@ "`P2106R0 `__","Alternative wording for GB315 and GB316","2020-02 (Prague)","|Complete|","15.0","" "`P2116R0 `__","Remove tuple-like protocol support from fixed-extent span","2020-02 (Prague)","|Complete|","11.0","" "","","","","","" -"`P2231R1 `__","Missing constexpr in std::optional and std::variant","2021-06 (Virtual)","|Complete|","19.0","" +"`P2231R1 `__","Missing constexpr in std::optional and std::variant","2021-06 (Virtual)","|Complete|","19.0","Changes of feature-test macros are completed in LLVM 20." "`P2325R3 `__","Views should not be required to be default constructible","2021-06 (Virtual)","|Complete|","16.0","" "`P2210R2 `__","Superior String Splitting","2021-06 (Virtual)","|Complete|","16.0","" "`P2216R3 `__","std::format improvements","2021-06 (Virtual)","|Complete|","15.0","" diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index c64f1c4171fce1ac29e2e2922915de10247faf78..6f1626da73507ee75423bf8bbd1dc82bbc9d4589 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -52,7 +52,7 @@ "`P2443R1 `__","``views::chunk_by``","2022-02 (Virtual)","|Complete|","18.0","" "","","","","","" "`P0009R18 `__","mdspan: A Non-Owning Multidimensional Array Reference","2022-07 (Virtual)","|Complete|","18.0","" -"`P0429R9 `__","A Standard ``flat_map``","2022-07 (Virtual)","","","" +"`P0429R9 `__","A Standard ``flat_map``","2022-07 (Virtual)","|In progress|","","" "`P1169R4 `__","``static operator()``","2022-07 (Virtual)","|Complete|","16.0","" "`P1222R4 `__","A Standard ``flat_set``","2022-07 (Virtual)","","","" "`P1223R5 `__","``ranges::find_last()``, ``ranges::find_last_if()``, and ``ranges::find_last_if_not()``","2022-07 (Virtual)","|Complete|","19.0","" diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 8864b1ebe28891061aacbbffd268618f5bfb8ae1..d5d5cdda065ae10fab24326e0acbe72b7dbdb69b 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -17,7 +17,7 @@ "`P0792R14 `__","``function_ref``: a type-erased callable reference","2023-06 (Varna)","","","" "`P2874R2 `__","Mandating Annex D Require No More","2023-06 (Varna)","","","" "`P2757R3 `__","Type-checking format args","2023-06 (Varna)","","","" -"`P2637R3 `__","Member ``visit``","2023-06 (Varna)","|Complete|","19.0","" +"`P2637R3 `__","Member ``visit``","2023-06 (Varna)","|Complete|","19.0","Change of ``__cpp_lib_variant`` is completed in LLVM 20. Change of ``__cpp_lib_format`` is blocked by `P2419R2 `__." "`P2641R4 `__","Checking if a ``union`` alternative is active","2023-06 (Varna)","","","" "`P1759R6 `__","Native handles and file streams","2023-06 (Varna)","|Complete|","18.0","" "`P2697R1 `__","Interfacing ``bitset`` with ``string_view``","2023-06 (Varna)","|Complete|","18.0","" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 86d2fc2c2c679d7cd1f2ac4df8abf3afaa917317..e84a55e25f2fa427137efba1b071775915febc63 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -358,6 +358,8 @@ set(files __filesystem/recursive_directory_iterator.h __filesystem/space_info.h __filesystem/u8path.h + __flat_map/flat_map.h + __flat_map/sorted_unique.h __format/buffer.h __format/concepts.h __format/container_adaptor.h @@ -492,15 +494,16 @@ set(files __locale __locale_dir/locale_base_api.h __locale_dir/locale_base_api/android.h + __locale_dir/locale_base_api/apple.h __locale_dir/locale_base_api/bsd_locale_defaults.h __locale_dir/locale_base_api/bsd_locale_fallbacks.h + __locale_dir/locale_base_api/freebsd.h __locale_dir/locale_base_api/fuchsia.h __locale_dir/locale_base_api/ibm.h - __locale_dir/locale_base_api/locale_guard.h __locale_dir/locale_base_api/musl.h - __locale_dir/locale_base_api/newlib.h __locale_dir/locale_base_api/openbsd.h __locale_dir/locale_base_api/win32.h + __locale_dir/locale_guard.h __math/abs.h __math/copysign.h __math/error_functions.h @@ -882,6 +885,14 @@ set(files __utility/to_underlying.h __utility/unreachable.h __variant/monostate.h + __vector/comparison.h + __vector/container_traits.h + __vector/erase.h + __vector/pmr.h + __vector/swap.h + __vector/vector.h + __vector/vector_bool.h + __vector/vector_bool_formatter.h __verbose_abort algorithm any @@ -950,6 +961,7 @@ set(files ext/hash_set fenv.h filesystem + flat_map float.h format forward_list diff --git a/libcxx/include/__charconv/from_chars_floating_point.h b/libcxx/include/__charconv/from_chars_floating_point.h index 2860b0e8da83af7b47fbd733784c8be3d13059fb..5cd3fc4a41ea1db295eb92267020e67f06c6687f 100644 --- a/libcxx/include/__charconv/from_chars_floating_point.h +++ b/libcxx/include/__charconv/from_chars_floating_point.h @@ -37,13 +37,13 @@ struct __from_chars_result { template _LIBCPP_EXPORTED_FROM_ABI __from_chars_result<_Fp> __from_chars_floating_point( - [[clang::noescape]] const char* __first, [[clang::noescape]] const char* __last, chars_format __fmt); + _LIBCPP_NOESCAPE const char* __first, _LIBCPP_NOESCAPE const char* __last, chars_format __fmt); extern template __from_chars_result __from_chars_floating_point( - [[clang::noescape]] const char* __first, [[clang::noescape]] const char* __last, chars_format __fmt); + _LIBCPP_NOESCAPE const char* __first, _LIBCPP_NOESCAPE const char* __last, chars_format __fmt); extern template __from_chars_result __from_chars_floating_point( - [[clang::noescape]] const char* __first, [[clang::noescape]] const char* __last, chars_format __fmt); + _LIBCPP_NOESCAPE const char* __first, _LIBCPP_NOESCAPE const char* __last, chars_format __fmt); template _LIBCPP_HIDE_FROM_ABI from_chars_result diff --git a/libcxx/include/__chrono/tzdb.h b/libcxx/include/__chrono/tzdb.h index dce97c3adfa1ba4ecdfb2dae9f3622f0efcc5508..5bbb82f4424171fd8e5fd70b363b8fb4e62313a3 100644 --- a/libcxx/include/__chrono/tzdb.h +++ b/libcxx/include/__chrono/tzdb.h @@ -22,10 +22,10 @@ # include <__chrono/time_zone_link.h> # include <__config> # include <__memory/addressof.h> +# include <__vector/vector.h> # include # include # include -# include # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header diff --git a/libcxx/include/__config b/libcxx/include/__config index fcba56f7e3d5b153b2ae4555c28f1525f570245f..fc09a97274d7c781f20b168206103ab48ce3420b 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -408,11 +408,7 @@ typedef __char32_t char32_t; # define _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_VISIBILITY("default") # define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS _LIBCPP_VISIBILITY("default") # define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS - -// TODO: Make this a proper customization point or remove the option to override it. -# ifndef _LIBCPP_OVERRIDABLE_FUNC_VIS -# define _LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_VISIBILITY("default") -# endif +# define _LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_VISIBILITY("default") # if !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) // The inline should be removed once PR32114 is resolved @@ -1167,6 +1163,12 @@ typedef __char32_t char32_t; # define _LIBCPP_LIFETIMEBOUND # endif +# if __has_cpp_attribute(_Clang::__noescape__) +# define _LIBCPP_NOESCAPE [[_Clang::__noescape__]] +# else +# define _LIBCPP_NOESCAPE +# endif + # if __has_attribute(__nodebug__) # define _LIBCPP_NODEBUG __attribute__((__nodebug__)) # else diff --git a/libcxx/include/__cxx03/CMakeLists.txt b/libcxx/include/__cxx03/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..32579272858a8e134b8f568edd83c244162fe96e --- /dev/null +++ b/libcxx/include/__cxx03/CMakeLists.txt @@ -0,0 +1,1092 @@ +set(files + __algorithm/adjacent_find.h + __algorithm/all_of.h + __algorithm/any_of.h + __algorithm/binary_search.h + __algorithm/clamp.h + __algorithm/comp.h + __algorithm/comp_ref_type.h + __algorithm/copy.h + __algorithm/copy_backward.h + __algorithm/copy_if.h + __algorithm/copy_move_common.h + __algorithm/copy_n.h + __algorithm/count.h + __algorithm/count_if.h + __algorithm/equal.h + __algorithm/equal_range.h + __algorithm/fill.h + __algorithm/fill_n.h + __algorithm/find.h + __algorithm/find_end.h + __algorithm/find_first_of.h + __algorithm/find_if.h + __algorithm/find_if_not.h + __algorithm/find_segment_if.h + __algorithm/fold.h + __algorithm/for_each.h + __algorithm/for_each_n.h + __algorithm/for_each_segment.h + __algorithm/generate.h + __algorithm/generate_n.h + __algorithm/half_positive.h + __algorithm/in_found_result.h + __algorithm/in_fun_result.h + __algorithm/in_in_out_result.h + __algorithm/in_in_result.h + __algorithm/in_out_out_result.h + __algorithm/in_out_result.h + __algorithm/includes.h + __algorithm/inplace_merge.h + __algorithm/is_heap.h + __algorithm/is_heap_until.h + __algorithm/is_partitioned.h + __algorithm/is_permutation.h + __algorithm/is_sorted.h + __algorithm/is_sorted_until.h + __algorithm/iter_swap.h + __algorithm/iterator_operations.h + __algorithm/lexicographical_compare.h + __algorithm/lexicographical_compare_three_way.h + __algorithm/lower_bound.h + __algorithm/make_heap.h + __algorithm/make_projected.h + __algorithm/max.h + __algorithm/max_element.h + __algorithm/merge.h + __algorithm/min.h + __algorithm/min_element.h + __algorithm/min_max_result.h + __algorithm/minmax.h + __algorithm/minmax_element.h + __algorithm/mismatch.h + __algorithm/move.h + __algorithm/move_backward.h + __algorithm/next_permutation.h + __algorithm/none_of.h + __algorithm/nth_element.h + __algorithm/partial_sort.h + __algorithm/partial_sort_copy.h + __algorithm/partition.h + __algorithm/partition_copy.h + __algorithm/partition_point.h + __algorithm/pop_heap.h + __algorithm/prev_permutation.h + __algorithm/pstl.h + __algorithm/push_heap.h + __algorithm/ranges_adjacent_find.h + __algorithm/ranges_all_of.h + __algorithm/ranges_any_of.h + __algorithm/ranges_binary_search.h + __algorithm/ranges_clamp.h + __algorithm/ranges_contains.h + __algorithm/ranges_contains_subrange.h + __algorithm/ranges_copy.h + __algorithm/ranges_copy_backward.h + __algorithm/ranges_copy_if.h + __algorithm/ranges_copy_n.h + __algorithm/ranges_count.h + __algorithm/ranges_count_if.h + __algorithm/ranges_ends_with.h + __algorithm/ranges_equal.h + __algorithm/ranges_equal_range.h + __algorithm/ranges_fill.h + __algorithm/ranges_fill_n.h + __algorithm/ranges_find.h + __algorithm/ranges_find_end.h + __algorithm/ranges_find_first_of.h + __algorithm/ranges_find_if.h + __algorithm/ranges_find_if_not.h + __algorithm/ranges_find_last.h + __algorithm/ranges_for_each.h + __algorithm/ranges_for_each_n.h + __algorithm/ranges_generate.h + __algorithm/ranges_generate_n.h + __algorithm/ranges_includes.h + __algorithm/ranges_inplace_merge.h + __algorithm/ranges_is_heap.h + __algorithm/ranges_is_heap_until.h + __algorithm/ranges_is_partitioned.h + __algorithm/ranges_is_permutation.h + __algorithm/ranges_is_sorted.h + __algorithm/ranges_is_sorted_until.h + __algorithm/ranges_iterator_concept.h + __algorithm/ranges_lexicographical_compare.h + __algorithm/ranges_lower_bound.h + __algorithm/ranges_make_heap.h + __algorithm/ranges_max.h + __algorithm/ranges_max_element.h + __algorithm/ranges_merge.h + __algorithm/ranges_min.h + __algorithm/ranges_min_element.h + __algorithm/ranges_minmax.h + __algorithm/ranges_minmax_element.h + __algorithm/ranges_mismatch.h + __algorithm/ranges_move.h + __algorithm/ranges_move_backward.h + __algorithm/ranges_next_permutation.h + __algorithm/ranges_none_of.h + __algorithm/ranges_nth_element.h + __algorithm/ranges_partial_sort.h + __algorithm/ranges_partial_sort_copy.h + __algorithm/ranges_partition.h + __algorithm/ranges_partition_copy.h + __algorithm/ranges_partition_point.h + __algorithm/ranges_pop_heap.h + __algorithm/ranges_prev_permutation.h + __algorithm/ranges_push_heap.h + __algorithm/ranges_remove.h + __algorithm/ranges_remove_copy.h + __algorithm/ranges_remove_copy_if.h + __algorithm/ranges_remove_if.h + __algorithm/ranges_replace.h + __algorithm/ranges_replace_copy.h + __algorithm/ranges_replace_copy_if.h + __algorithm/ranges_replace_if.h + __algorithm/ranges_reverse.h + __algorithm/ranges_reverse_copy.h + __algorithm/ranges_rotate.h + __algorithm/ranges_rotate_copy.h + __algorithm/ranges_sample.h + __algorithm/ranges_search.h + __algorithm/ranges_search_n.h + __algorithm/ranges_set_difference.h + __algorithm/ranges_set_intersection.h + __algorithm/ranges_set_symmetric_difference.h + __algorithm/ranges_set_union.h + __algorithm/ranges_shuffle.h + __algorithm/ranges_sort.h + __algorithm/ranges_sort_heap.h + __algorithm/ranges_stable_partition.h + __algorithm/ranges_stable_sort.h + __algorithm/ranges_starts_with.h + __algorithm/ranges_swap_ranges.h + __algorithm/ranges_transform.h + __algorithm/ranges_unique.h + __algorithm/ranges_unique_copy.h + __algorithm/ranges_upper_bound.h + __algorithm/remove.h + __algorithm/remove_copy.h + __algorithm/remove_copy_if.h + __algorithm/remove_if.h + __algorithm/replace.h + __algorithm/replace_copy.h + __algorithm/replace_copy_if.h + __algorithm/replace_if.h + __algorithm/reverse.h + __algorithm/reverse_copy.h + __algorithm/rotate.h + __algorithm/rotate_copy.h + __algorithm/sample.h + __algorithm/search.h + __algorithm/search_n.h + __algorithm/set_difference.h + __algorithm/set_intersection.h + __algorithm/set_symmetric_difference.h + __algorithm/set_union.h + __algorithm/shift_left.h + __algorithm/shift_right.h + __algorithm/shuffle.h + __algorithm/sift_down.h + __algorithm/simd_utils.h + __algorithm/sort.h + __algorithm/sort_heap.h + __algorithm/stable_partition.h + __algorithm/stable_sort.h + __algorithm/swap_ranges.h + __algorithm/three_way_comp_ref_type.h + __algorithm/transform.h + __algorithm/uniform_random_bit_generator_adaptor.h + __algorithm/unique.h + __algorithm/unique_copy.h + __algorithm/unwrap_iter.h + __algorithm/unwrap_range.h + __algorithm/upper_bound.h + __assert + __atomic/aliases.h + __atomic/atomic.h + __atomic/atomic_base.h + __atomic/atomic_flag.h + __atomic/atomic_init.h + __atomic/atomic_lock_free.h + __atomic/atomic_ref.h + __atomic/atomic_sync.h + __atomic/check_memory_order.h + __atomic/contention_t.h + __atomic/cxx_atomic_impl.h + __atomic/fence.h + __atomic/is_always_lock_free.h + __atomic/kill_dependency.h + __atomic/memory_order.h + __atomic/to_gcc_order.h + __bit/bit_cast.h + __bit/bit_ceil.h + __bit/bit_floor.h + __bit/bit_log2.h + __bit/bit_width.h + __bit/blsr.h + __bit/byteswap.h + __bit/countl.h + __bit/countr.h + __bit/endian.h + __bit/has_single_bit.h + __bit/invert_if.h + __bit/popcount.h + __bit/rotate.h + __bit_reference + __charconv/chars_format.h + __charconv/from_chars_integral.h + __charconv/from_chars_result.h + __charconv/tables.h + __charconv/to_chars.h + __charconv/to_chars_base_10.h + __charconv/to_chars_floating_point.h + __charconv/to_chars_integral.h + __charconv/to_chars_result.h + __charconv/traits.h + __chrono/calendar.h + __chrono/concepts.h + __chrono/convert_to_timespec.h + __chrono/convert_to_tm.h + __chrono/day.h + __chrono/duration.h + __chrono/exception.h + __chrono/file_clock.h + __chrono/formatter.h + __chrono/hh_mm_ss.h + __chrono/high_resolution_clock.h + __chrono/leap_second.h + __chrono/literals.h + __chrono/local_info.h + __chrono/month.h + __chrono/month_weekday.h + __chrono/monthday.h + __chrono/ostream.h + __chrono/parser_std_format_spec.h + __chrono/statically_widen.h + __chrono/steady_clock.h + __chrono/sys_info.h + __chrono/system_clock.h + __chrono/time_point.h + __chrono/time_zone.h + __chrono/time_zone_link.h + __chrono/tzdb.h + __chrono/tzdb_list.h + __chrono/weekday.h + __chrono/year.h + __chrono/year_month.h + __chrono/year_month_day.h + __chrono/year_month_weekday.h + __chrono/zoned_time.h + __compare/common_comparison_category.h + __compare/compare_partial_order_fallback.h + __compare/compare_strong_order_fallback.h + __compare/compare_three_way.h + __compare/compare_three_way_result.h + __compare/compare_weak_order_fallback.h + __compare/is_eq.h + __compare/ordering.h + __compare/partial_order.h + __compare/strong_order.h + __compare/synth_three_way.h + __compare/three_way_comparable.h + __compare/weak_order.h + __concepts/arithmetic.h + __concepts/assignable.h + __concepts/boolean_testable.h + __concepts/class_or_enum.h + __concepts/common_reference_with.h + __concepts/common_with.h + __concepts/constructible.h + __concepts/convertible_to.h + __concepts/copyable.h + __concepts/derived_from.h + __concepts/destructible.h + __concepts/different_from.h + __concepts/equality_comparable.h + __concepts/invocable.h + __concepts/movable.h + __concepts/predicate.h + __concepts/regular.h + __concepts/relation.h + __concepts/same_as.h + __concepts/semiregular.h + __concepts/swappable.h + __concepts/totally_ordered.h + __condition_variable/condition_variable.h + __config + __configuration/abi.h + __configuration/availability.h + __configuration/compiler.h + __configuration/language.h + __configuration/platform.h + __coroutine/coroutine_handle.h + __coroutine/coroutine_traits.h + __coroutine/noop_coroutine_handle.h + __coroutine/trivial_awaitables.h + __debug_utils/randomize_range.h + __debug_utils/sanitizers.h + __debug_utils/strict_weak_ordering_check.h + __exception/exception.h + __exception/exception_ptr.h + __exception/nested_exception.h + __exception/operations.h + __exception/terminate.h + __expected/bad_expected_access.h + __expected/expected.h + __expected/unexpect.h + __expected/unexpected.h + __filesystem/copy_options.h + __filesystem/directory_entry.h + __filesystem/directory_iterator.h + __filesystem/directory_options.h + __filesystem/file_status.h + __filesystem/file_time_type.h + __filesystem/file_type.h + __filesystem/filesystem_error.h + __filesystem/operations.h + __filesystem/path.h + __filesystem/path_iterator.h + __filesystem/perm_options.h + __filesystem/perms.h + __filesystem/recursive_directory_iterator.h + __filesystem/space_info.h + __filesystem/u8path.h + __format/buffer.h + __format/concepts.h + __format/container_adaptor.h + __format/enable_insertable.h + __format/escaped_output_table.h + __format/extended_grapheme_cluster_table.h + __format/format_arg.h + __format/format_arg_store.h + __format/format_args.h + __format/format_context.h + __format/format_error.h + __format/format_functions.h + __format/format_parse_context.h + __format/format_string.h + __format/format_to_n_result.h + __format/formatter.h + __format/formatter_bool.h + __format/formatter_char.h + __format/formatter_floating_point.h + __format/formatter_integer.h + __format/formatter_integral.h + __format/formatter_output.h + __format/formatter_pointer.h + __format/formatter_string.h + __format/formatter_tuple.h + __format/indic_conjunct_break_table.h + __format/parser_std_format_spec.h + __format/range_default_formatter.h + __format/range_formatter.h + __format/unicode.h + __format/width_estimation_table.h + __format/write_escaped.h + __functional/binary_function.h + __functional/binary_negate.h + __functional/bind.h + __functional/bind_back.h + __functional/bind_front.h + __functional/binder1st.h + __functional/binder2nd.h + __functional/boyer_moore_searcher.h + __functional/compose.h + __functional/default_searcher.h + __functional/function.h + __functional/hash.h + __functional/identity.h + __functional/invoke.h + __functional/is_transparent.h + __functional/mem_fn.h + __functional/mem_fun_ref.h + __functional/not_fn.h + __functional/operations.h + __functional/perfect_forward.h + __functional/pointer_to_binary_function.h + __functional/pointer_to_unary_function.h + __functional/ranges_operations.h + __functional/reference_wrapper.h + __functional/unary_function.h + __functional/unary_negate.h + __functional/weak_result_type.h + __fwd/array.h + __fwd/bit_reference.h + __fwd/complex.h + __fwd/deque.h + __fwd/format.h + __fwd/fstream.h + __fwd/functional.h + __fwd/ios.h + __fwd/istream.h + __fwd/mdspan.h + __fwd/memory.h + __fwd/memory_resource.h + __fwd/ostream.h + __fwd/pair.h + __fwd/queue.h + __fwd/span.h + __fwd/sstream.h + __fwd/stack.h + __fwd/streambuf.h + __fwd/string.h + __fwd/string_view.h + __fwd/subrange.h + __fwd/tuple.h + __fwd/vector.h + __hash_table + __ios/fpos.h + __iterator/access.h + __iterator/advance.h + __iterator/aliasing_iterator.h + __iterator/back_insert_iterator.h + __iterator/bounded_iter.h + __iterator/common_iterator.h + __iterator/concepts.h + __iterator/counted_iterator.h + __iterator/cpp17_iterator_concepts.h + __iterator/data.h + __iterator/default_sentinel.h + __iterator/distance.h + __iterator/empty.h + __iterator/erase_if_container.h + __iterator/front_insert_iterator.h + __iterator/incrementable_traits.h + __iterator/indirectly_comparable.h + __iterator/insert_iterator.h + __iterator/istream_iterator.h + __iterator/istreambuf_iterator.h + __iterator/iter_move.h + __iterator/iter_swap.h + __iterator/iterator.h + __iterator/iterator_traits.h + __iterator/iterator_with_data.h + __iterator/mergeable.h + __iterator/move_iterator.h + __iterator/move_sentinel.h + __iterator/next.h + __iterator/ostream_iterator.h + __iterator/ostreambuf_iterator.h + __iterator/permutable.h + __iterator/prev.h + __iterator/projected.h + __iterator/ranges_iterator_traits.h + __iterator/readable_traits.h + __iterator/reverse_access.h + __iterator/reverse_iterator.h + __iterator/segmented_iterator.h + __iterator/size.h + __iterator/sortable.h + __iterator/unreachable_sentinel.h + __iterator/wrap_iter.h + __locale + __locale_dir/locale_base_api.h + __locale_dir/locale_base_api/android.h + __locale_dir/locale_base_api/bsd_locale_defaults.h + __locale_dir/locale_base_api/bsd_locale_fallbacks.h + __locale_dir/locale_base_api/fuchsia.h + __locale_dir/locale_base_api/ibm.h + __locale_dir/locale_base_api/locale_guard.h + __locale_dir/locale_base_api/musl.h + __locale_dir/locale_base_api/newlib.h + __locale_dir/locale_base_api/openbsd.h + __locale_dir/locale_base_api/win32.h + __math/abs.h + __math/copysign.h + __math/error_functions.h + __math/exponential_functions.h + __math/fdim.h + __math/fma.h + __math/gamma.h + __math/hyperbolic_functions.h + __math/hypot.h + __math/inverse_hyperbolic_functions.h + __math/inverse_trigonometric_functions.h + __math/logarithms.h + __math/min_max.h + __math/modulo.h + __math/remainder.h + __math/roots.h + __math/rounding_functions.h + __math/special_functions.h + __math/traits.h + __math/trigonometric_functions.h + __mbstate_t.h + __mdspan/default_accessor.h + __mdspan/extents.h + __mdspan/layout_left.h + __mdspan/layout_right.h + __mdspan/layout_stride.h + __mdspan/mdspan.h + __memory/addressof.h + __memory/align.h + __memory/aligned_alloc.h + __memory/allocate_at_least.h + __memory/allocation_guard.h + __memory/allocator.h + __memory/allocator_arg_t.h + __memory/allocator_destructor.h + __memory/allocator_traits.h + __memory/assume_aligned.h + __memory/auto_ptr.h + __memory/builtin_new_allocator.h + __memory/compressed_pair.h + __memory/concepts.h + __memory/construct_at.h + __memory/destruct_n.h + __memory/inout_ptr.h + __memory/out_ptr.h + __memory/pointer_traits.h + __memory/ranges_construct_at.h + __memory/ranges_uninitialized_algorithms.h + __memory/raw_storage_iterator.h + __memory/shared_ptr.h + __memory/swap_allocator.h + __memory/temp_value.h + __memory/temporary_buffer.h + __memory/uninitialized_algorithms.h + __memory/unique_ptr.h + __memory/uses_allocator.h + __memory/uses_allocator_construction.h + __memory/voidify.h + __memory_resource/memory_resource.h + __memory_resource/monotonic_buffer_resource.h + __memory_resource/polymorphic_allocator.h + __memory_resource/pool_options.h + __memory_resource/synchronized_pool_resource.h + __memory_resource/unsynchronized_pool_resource.h + __mutex/lock_guard.h + __mutex/mutex.h + __mutex/once_flag.h + __mutex/tag_types.h + __mutex/unique_lock.h + __node_handle + __numeric/accumulate.h + __numeric/adjacent_difference.h + __numeric/exclusive_scan.h + __numeric/gcd_lcm.h + __numeric/inclusive_scan.h + __numeric/inner_product.h + __numeric/iota.h + __numeric/midpoint.h + __numeric/partial_sum.h + __numeric/pstl.h + __numeric/reduce.h + __numeric/saturation_arithmetic.h + __numeric/transform_exclusive_scan.h + __numeric/transform_inclusive_scan.h + __numeric/transform_reduce.h + __ostream/basic_ostream.h + __ostream/print.h + __pstl/backend.h + __pstl/backend_fwd.h + __pstl/backends/default.h + __pstl/backends/libdispatch.h + __pstl/backends/serial.h + __pstl/backends/std_thread.h + __pstl/cpu_algos/any_of.h + __pstl/cpu_algos/cpu_traits.h + __pstl/cpu_algos/fill.h + __pstl/cpu_algos/find_if.h + __pstl/cpu_algos/for_each.h + __pstl/cpu_algos/merge.h + __pstl/cpu_algos/stable_sort.h + __pstl/cpu_algos/transform.h + __pstl/cpu_algos/transform_reduce.h + __pstl/dispatch.h + __pstl/handle_exception.h + __random/bernoulli_distribution.h + __random/binomial_distribution.h + __random/cauchy_distribution.h + __random/chi_squared_distribution.h + __random/clamp_to_integral.h + __random/default_random_engine.h + __random/discard_block_engine.h + __random/discrete_distribution.h + __random/exponential_distribution.h + __random/extreme_value_distribution.h + __random/fisher_f_distribution.h + __random/gamma_distribution.h + __random/generate_canonical.h + __random/geometric_distribution.h + __random/independent_bits_engine.h + __random/is_seed_sequence.h + __random/is_valid.h + __random/knuth_b.h + __random/linear_congruential_engine.h + __random/log2.h + __random/lognormal_distribution.h + __random/mersenne_twister_engine.h + __random/negative_binomial_distribution.h + __random/normal_distribution.h + __random/piecewise_constant_distribution.h + __random/piecewise_linear_distribution.h + __random/poisson_distribution.h + __random/random_device.h + __random/ranlux.h + __random/seed_seq.h + __random/shuffle_order_engine.h + __random/student_t_distribution.h + __random/subtract_with_carry_engine.h + __random/uniform_int_distribution.h + __random/uniform_random_bit_generator.h + __random/uniform_real_distribution.h + __random/weibull_distribution.h + __ranges/access.h + __ranges/all.h + __ranges/as_rvalue_view.h + __ranges/chunk_by_view.h + __ranges/common_view.h + __ranges/concepts.h + __ranges/container_compatible_range.h + __ranges/counted.h + __ranges/dangling.h + __ranges/data.h + __ranges/drop_view.h + __ranges/drop_while_view.h + __ranges/elements_view.h + __ranges/empty.h + __ranges/empty_view.h + __ranges/enable_borrowed_range.h + __ranges/enable_view.h + __ranges/filter_view.h + __ranges/from_range.h + __ranges/iota_view.h + __ranges/istream_view.h + __ranges/join_view.h + __ranges/lazy_split_view.h + __ranges/movable_box.h + __ranges/non_propagating_cache.h + __ranges/owning_view.h + __ranges/range_adaptor.h + __ranges/rbegin.h + __ranges/ref_view.h + __ranges/rend.h + __ranges/repeat_view.h + __ranges/reverse_view.h + __ranges/single_view.h + __ranges/size.h + __ranges/split_view.h + __ranges/subrange.h + __ranges/take_view.h + __ranges/take_while_view.h + __ranges/to.h + __ranges/transform_view.h + __ranges/view_interface.h + __ranges/views.h + __ranges/zip_view.h + __split_buffer + __std_clang_module + __std_mbstate_t.h + __stop_token/atomic_unique_lock.h + __stop_token/intrusive_list_view.h + __stop_token/intrusive_shared_ptr.h + __stop_token/stop_callback.h + __stop_token/stop_source.h + __stop_token/stop_state.h + __stop_token/stop_token.h + __string/char_traits.h + __string/constexpr_c_functions.h + __string/extern_template_lists.h + __support/ibm/gettod_zos.h + __support/ibm/locale_mgmt_zos.h + __support/ibm/nanosleep.h + __support/xlocale/__nop_locale_mgmt.h + __support/xlocale/__posix_l_fallback.h + __support/xlocale/__strtonum_fallback.h + __system_error/errc.h + __system_error/error_category.h + __system_error/error_code.h + __system_error/error_condition.h + __system_error/system_error.h + __thread/formatter.h + __thread/id.h + __thread/jthread.h + __thread/poll_with_backoff.h + __thread/support.h + __thread/support/c11.h + __thread/support/external.h + __thread/support/pthread.h + __thread/support/windows.h + __thread/this_thread.h + __thread/thread.h + __thread/timed_backoff_policy.h + __tree + __tuple/find_index.h + __tuple/ignore.h + __tuple/make_tuple_types.h + __tuple/sfinae_helpers.h + __tuple/tuple_element.h + __tuple/tuple_indices.h + __tuple/tuple_like.h + __tuple/tuple_like_ext.h + __tuple/tuple_like_no_subrange.h + __tuple/tuple_size.h + __tuple/tuple_types.h + __type_traits/add_const.h + __type_traits/add_cv.h + __type_traits/add_lvalue_reference.h + __type_traits/add_pointer.h + __type_traits/add_rvalue_reference.h + __type_traits/add_volatile.h + __type_traits/aligned_storage.h + __type_traits/aligned_union.h + __type_traits/alignment_of.h + __type_traits/can_extract_key.h + __type_traits/common_reference.h + __type_traits/common_type.h + __type_traits/conditional.h + __type_traits/conjunction.h + __type_traits/copy_cv.h + __type_traits/copy_cvref.h + __type_traits/datasizeof.h + __type_traits/decay.h + __type_traits/dependent_type.h + __type_traits/desugars_to.h + __type_traits/disjunction.h + __type_traits/enable_if.h + __type_traits/extent.h + __type_traits/has_unique_object_representation.h + __type_traits/has_virtual_destructor.h + __type_traits/integral_constant.h + __type_traits/invoke.h + __type_traits/is_abstract.h + __type_traits/is_aggregate.h + __type_traits/is_allocator.h + __type_traits/is_always_bitcastable.h + __type_traits/is_arithmetic.h + __type_traits/is_array.h + __type_traits/is_assignable.h + __type_traits/is_base_of.h + __type_traits/is_bounded_array.h + __type_traits/is_callable.h + __type_traits/is_char_like_type.h + __type_traits/is_class.h + __type_traits/is_compound.h + __type_traits/is_const.h + __type_traits/is_constant_evaluated.h + __type_traits/is_constructible.h + __type_traits/is_convertible.h + __type_traits/is_core_convertible.h + __type_traits/is_destructible.h + __type_traits/is_empty.h + __type_traits/is_enum.h + __type_traits/is_equality_comparable.h + __type_traits/is_execution_policy.h + __type_traits/is_final.h + __type_traits/is_floating_point.h + __type_traits/is_function.h + __type_traits/is_fundamental.h + __type_traits/is_implicitly_default_constructible.h + __type_traits/is_integral.h + __type_traits/is_literal_type.h + __type_traits/is_member_pointer.h + __type_traits/is_nothrow_assignable.h + __type_traits/is_nothrow_constructible.h + __type_traits/is_nothrow_convertible.h + __type_traits/is_nothrow_destructible.h + __type_traits/is_null_pointer.h + __type_traits/is_object.h + __type_traits/is_pod.h + __type_traits/is_pointer.h + __type_traits/is_polymorphic.h + __type_traits/is_primary_template.h + __type_traits/is_reference.h + __type_traits/is_reference_wrapper.h + __type_traits/is_referenceable.h + __type_traits/is_same.h + __type_traits/is_scalar.h + __type_traits/is_signed.h + __type_traits/is_signed_integer.h + __type_traits/is_specialization.h + __type_traits/is_standard_layout.h + __type_traits/is_swappable.h + __type_traits/is_trivial.h + __type_traits/is_trivially_assignable.h + __type_traits/is_trivially_constructible.h + __type_traits/is_trivially_copyable.h + __type_traits/is_trivially_destructible.h + __type_traits/is_trivially_lexicographically_comparable.h + __type_traits/is_trivially_relocatable.h + __type_traits/is_unbounded_array.h + __type_traits/is_union.h + __type_traits/is_unsigned.h + __type_traits/is_unsigned_integer.h + __type_traits/is_valid_expansion.h + __type_traits/is_void.h + __type_traits/is_volatile.h + __type_traits/lazy.h + __type_traits/make_32_64_or_128_bit.h + __type_traits/make_const_lvalue_ref.h + __type_traits/make_signed.h + __type_traits/make_unsigned.h + __type_traits/maybe_const.h + __type_traits/nat.h + __type_traits/negation.h + __type_traits/noexcept_move_assign_container.h + __type_traits/promote.h + __type_traits/rank.h + __type_traits/remove_all_extents.h + __type_traits/remove_const.h + __type_traits/remove_const_ref.h + __type_traits/remove_cv.h + __type_traits/remove_cvref.h + __type_traits/remove_extent.h + __type_traits/remove_pointer.h + __type_traits/remove_reference.h + __type_traits/remove_volatile.h + __type_traits/result_of.h + __type_traits/strip_signature.h + __type_traits/type_identity.h + __type_traits/type_list.h + __type_traits/underlying_type.h + __type_traits/unwrap_ref.h + __type_traits/void_t.h + __undef_macros + __utility/as_const.h + __utility/as_lvalue.h + __utility/auto_cast.h + __utility/cmp.h + __utility/convert_to_integral.h + __utility/declval.h + __utility/empty.h + __utility/exception_guard.h + __utility/exchange.h + __utility/forward.h + __utility/forward_like.h + __utility/in_place.h + __utility/integer_sequence.h + __utility/is_pointer_in_range.h + __utility/is_valid_range.h + __utility/move.h + __utility/no_destroy.h + __utility/pair.h + __utility/piecewise_construct.h + __utility/priority_tag.h + __utility/private_constructor_tag.h + __utility/rel_ops.h + __utility/small_buffer.h + __utility/swap.h + __utility/to_underlying.h + __utility/unreachable.h + __variant/monostate.h + __verbose_abort + algorithm + any + array + atomic + barrier + bit + bitset + cassert + ccomplex + cctype + cerrno + cfenv + cfloat + charconv + chrono + cinttypes + ciso646 + climits + clocale + cmath + codecvt + compare + complex + complex.h + concepts + condition_variable + coroutine + csetjmp + csignal + cstdarg + cstdbool + cstddef + cstdint + cstdio + cstdlib + cstring + ctgmath + ctime + ctype.h + cuchar + cwchar + cwctype + deque + errno.h + exception + execution + expected + experimental/__config + experimental/__simd/aligned_tag.h + experimental/__simd/declaration.h + experimental/__simd/reference.h + experimental/__simd/scalar.h + experimental/__simd/simd.h + experimental/__simd/simd_mask.h + experimental/__simd/traits.h + experimental/__simd/utility.h + experimental/__simd/vec_ext.h + experimental/iterator + experimental/memory + experimental/propagate_const + experimental/simd + experimental/type_traits + experimental/utility + ext/__hash + ext/hash_map + ext/hash_set + fenv.h + filesystem + float.h + format + forward_list + fstream + functional + future + initializer_list + inttypes.h + iomanip + ios + iosfwd + iostream + istream + iterator + latch + limits + list + locale + locale.h + map + math.h + mdspan + memory + memory_resource + module.modulemap + mutex + new + numbers + numeric + optional + ostream + print + queue + random + ranges + ratio + regex + scoped_allocator + semaphore + set + shared_mutex + source_location + span + sstream + stack + stdatomic.h + stdbool.h + stddef.h + stdexcept + stdint.h + stdio.h + stdlib.h + stop_token + streambuf + string + string.h + string_view + strstream + syncstream + system_error + tgmath.h + thread + tuple + type_traits + typeindex + typeinfo + uchar.h + unordered_map + unordered_set + utility + valarray + variant + vector + version + wchar.h + wctype.h + ) + +configure_file("__config_site.in" "${LIBCXX_GENERATED_INCLUDE_TARGET_DIR}/__config_site" @ONLY) +configure_file("${LIBCXX_ASSERTION_HANDLER_FILE}" "${LIBCXX_GENERATED_INCLUDE_DIR}/__assertion_handler" COPYONLY) + +set(_all_includes "${LIBCXX_GENERATED_INCLUDE_TARGET_DIR}/__config_site" + "${LIBCXX_GENERATED_INCLUDE_DIR}/__assertion_handler") +foreach(f ${files}) + set(src "${CMAKE_CURRENT_SOURCE_DIR}/${f}") + set(dst "${LIBCXX_GENERATED_INCLUDE_DIR}/${f}") + add_custom_command(OUTPUT ${dst} + DEPENDS ${src} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst} + COMMENT "Copying CXX header ${f}") + list(APPEND _all_includes "${dst}") +endforeach() + +# Generate the IWYU mapping. This depends on all header files but it's also considered as an +# "include" for dependency tracking. +add_custom_command(OUTPUT "${LIBCXX_GENERATED_INCLUDE_DIR}/libcxx.imp" + COMMAND "${Python3_EXECUTABLE}" "${LIBCXX_SOURCE_DIR}/utils/generate_iwyu_mapping.py" "-o" "${LIBCXX_GENERATED_INCLUDE_DIR}/libcxx.imp" + DEPENDS ${_all_includes} + COMMENT "Generate the mapping file for include-what-you-use" +) +list(APPEND _all_includes "${LIBCXX_GENERATED_INCLUDE_DIR}/libcxx.imp") + +add_custom_target(generate-cxx-headers ALL DEPENDS ${_all_includes}) + +add_library(cxx-headers INTERFACE) +target_link_libraries(cxx-headers INTERFACE libcxx-libc-headers libcxx-abi-headers) +add_dependencies(cxx-headers generate-cxx-headers) +# It's important that the arch directory be included first so that its header files +# which interpose on the default include dir be included instead of the default ones. +target_include_directories(cxx-headers INTERFACE ${LIBCXX_GENERATED_INCLUDE_TARGET_DIR} + ${LIBCXX_GENERATED_INCLUDE_DIR}) + +if (LIBCXX_INSTALL_HEADERS) + foreach(file ${files}) + get_filename_component(dir ${file} DIRECTORY) + install(FILES ${file} + DESTINATION "${LIBCXX_INSTALL_INCLUDE_DIR}/${dir}" + COMPONENT cxx-headers + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ + ) + endforeach() + + # Install the generated __config_site file to the per-target include dir. + install(FILES "${LIBCXX_GENERATED_INCLUDE_TARGET_DIR}/__config_site" + DESTINATION "${LIBCXX_INSTALL_INCLUDE_TARGET_DIR}" + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ + COMPONENT cxx-headers) + + # Install the generated __assertion_handler file to the generic include dir. + install(FILES "${LIBCXX_GENERATED_INCLUDE_DIR}/__assertion_handler" + DESTINATION "${LIBCXX_INSTALL_INCLUDE_DIR}" + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ + COMPONENT cxx-headers) + + # Install the generated IWYU file to the generic include dir. + install(FILES "${LIBCXX_GENERATED_INCLUDE_DIR}/libcxx.imp" + DESTINATION "${LIBCXX_INSTALL_INCLUDE_DIR}" + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ + COMPONENT cxx-headers) + + if (NOT CMAKE_CONFIGURATION_TYPES) + add_custom_target(install-cxx-headers + DEPENDS cxx-headers + COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=cxx-headers + -P "${CMAKE_BINARY_DIR}/cmake_install.cmake") + # Stripping is a no-op for headers + add_custom_target(install-cxx-headers-stripped DEPENDS install-cxx-headers) + endif() +endif() diff --git a/libcxx/include/__cxx03/__algorithm/adjacent_find.h b/libcxx/include/__cxx03/__algorithm/adjacent_find.h new file mode 100644 index 0000000000000000000000000000000000000000..6f15456e3a4d074c2cf069b1a2cb46b22e184736 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/adjacent_find.h @@ -0,0 +1,58 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_ADJACENT_FIND_H +#define _LIBCPP___ALGORITHM_ADJACENT_FIND_H + +#include <__algorithm/comp.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter +__adjacent_find(_Iter __first, _Sent __last, _BinaryPredicate&& __pred) { + if (__first == __last) + return __first; + _Iter __i = __first; + while (++__i != __last) { + if (__pred(*__first, *__i)) + return __first; + __first = __i; + } + return __i; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +adjacent_find(_ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __pred) { + return std::__adjacent_find(std::move(__first), std::move(__last), __pred); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +adjacent_find(_ForwardIterator __first, _ForwardIterator __last) { + return std::adjacent_find(std::move(__first), std::move(__last), __equal_to()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_ADJACENT_FIND_H diff --git a/libcxx/include/__cxx03/__algorithm/all_of.h b/libcxx/include/__cxx03/__algorithm/all_of.h new file mode 100644 index 0000000000000000000000000000000000000000..ec84eea75929668ebbf84f06ff6a04ea8cf64d57 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/all_of.h @@ -0,0 +1,32 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_ALL_OF_H +#define _LIBCPP___ALGORITHM_ALL_OF_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +all_of(_InputIterator __first, _InputIterator __last, _Predicate __pred) { + for (; __first != __last; ++__first) + if (!__pred(*__first)) + return false; + return true; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_ALL_OF_H diff --git a/libcxx/include/__cxx03/__algorithm/any_of.h b/libcxx/include/__cxx03/__algorithm/any_of.h new file mode 100644 index 0000000000000000000000000000000000000000..b5ff778c4171dc81754bd14e0962fbd9b1277763 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/any_of.h @@ -0,0 +1,32 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_ANY_OF_H +#define _LIBCPP___ALGORITHM_ANY_OF_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +any_of(_InputIterator __first, _InputIterator __last, _Predicate __pred) { + for (; __first != __last; ++__first) + if (__pred(*__first)) + return true; + return false; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_ANY_OF_H diff --git a/libcxx/include/__cxx03/__algorithm/binary_search.h b/libcxx/include/__cxx03/__algorithm/binary_search.h new file mode 100644 index 0000000000000000000000000000000000000000..6065fc37274dce1301006e83ac02e3abea1e6eac --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/binary_search.h @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_BINARY_SEARCH_H +#define _LIBCPP___ALGORITHM_BINARY_SEARCH_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/lower_bound.h> +#include <__config> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +binary_search(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, _Compare __comp) { + __first = std::lower_bound<_ForwardIterator, _Tp, __comp_ref_type<_Compare> >(__first, __last, __value, __comp); + return __first != __last && !__comp(__value, *__first); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +binary_search(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + return std::binary_search(__first, __last, __value, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_BINARY_SEARCH_H diff --git a/libcxx/include/__cxx03/__algorithm/clamp.h b/libcxx/include/__cxx03/__algorithm/clamp.h new file mode 100644 index 0000000000000000000000000000000000000000..1a5a3d0744be9c35d8aa2222a87d0580b4d6b42a --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/clamp.h @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_CLAMP_H +#define _LIBCPP___ALGORITHM_CLAMP_H + +#include <__algorithm/comp.h> +#include <__assert> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 +template +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& +clamp(_LIBCPP_LIFETIMEBOUND const _Tp& __v, + _LIBCPP_LIFETIMEBOUND const _Tp& __lo, + _LIBCPP_LIFETIMEBOUND const _Tp& __hi, + _Compare __comp) { + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(!__comp(__hi, __lo), "Bad bounds passed to std::clamp"); + return __comp(__v, __lo) ? __lo : __comp(__hi, __v) ? __hi : __v; +} + +template +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& +clamp(_LIBCPP_LIFETIMEBOUND const _Tp& __v, + _LIBCPP_LIFETIMEBOUND const _Tp& __lo, + _LIBCPP_LIFETIMEBOUND const _Tp& __hi) { + return std::clamp(__v, __lo, __hi, __less<>()); +} +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_CLAMP_H diff --git a/libcxx/include/__cxx03/__algorithm/comp.h b/libcxx/include/__cxx03/__algorithm/comp.h new file mode 100644 index 0000000000000000000000000000000000000000..a0fa88d6d2acd344744d35cdee7612a20e89ea2a --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/comp.h @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_COMP_H +#define _LIBCPP___ALGORITHM_COMP_H + +#include <__config> +#include <__type_traits/desugars_to.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +struct __equal_to { + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator()(const _T1& __x, const _T2& __y) const { + return __x == __y; + } +}; + +template +inline const bool __desugars_to_v<__equal_tag, __equal_to, _Tp, _Up> = true; + +// The definition is required because __less is part of the ABI, but it's empty +// because all comparisons should be transparent. +template +struct __less {}; + +template <> +struct __less { + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator()(const _Tp& __lhs, const _Up& __rhs) const { + return __lhs < __rhs; + } +}; + +template +inline const bool __desugars_to_v<__less_tag, __less<>, _Tp, _Tp> = true; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_COMP_H diff --git a/libcxx/include/__cxx03/__algorithm/comp_ref_type.h b/libcxx/include/__cxx03/__algorithm/comp_ref_type.h new file mode 100644 index 0000000000000000000000000000000000000000..c367fbb91ac28257b102a7d70b84c86fb483518a --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/comp_ref_type.h @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_COMP_REF_TYPE_H +#define _LIBCPP___ALGORITHM_COMP_REF_TYPE_H + +#include <__assert> +#include <__config> +#include <__utility/declval.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __debug_less { + _Compare& __comp_; + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI __debug_less(_Compare& __c) : __comp_(__c) {} + + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const _Up& __y) { + bool __r = __comp_(__x, __y); + if (__r) + __do_compare_assert(0, __y, __x); + return __r; + } + + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI bool operator()(_Tp& __x, _Up& __y) { + bool __r = __comp_(__x, __y); + if (__r) + __do_compare_assert(0, __y, __x); + return __r; + } + + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 inline + _LIBCPP_HIDE_FROM_ABI decltype((void)std::declval<_Compare&>()(std::declval<_LHS&>(), std::declval<_RHS&>())) + __do_compare_assert(int, _LHS& __l, _RHS& __r) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(!__comp_(__l, __r), "Comparator does not induce a strict weak ordering"); + (void)__l; + (void)__r; + } + + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 inline _LIBCPP_HIDE_FROM_ABI void __do_compare_assert(long, _LHS&, _RHS&) {} +}; + +// Pass the comparator by lvalue reference. Or in the debug mode, using a debugging wrapper that stores a reference. +#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG +template +using __comp_ref_type = __debug_less<_Comp>; +#else +template +using __comp_ref_type = _Comp&; +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_COMP_REF_TYPE_H diff --git a/libcxx/include/__cxx03/__algorithm/copy.h b/libcxx/include/__cxx03/__algorithm/copy.h new file mode 100644 index 0000000000000000000000000000000000000000..0890b895f5409245b5244bd3f5a1d6b8d3b1fcda --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/copy.h @@ -0,0 +1,123 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_COPY_H +#define _LIBCPP___ALGORITHM_COPY_H + +#include <__algorithm/copy_move_common.h> +#include <__algorithm/for_each_segment.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/min.h> +#include <__config> +#include <__iterator/segmented_iterator.h> +#include <__type_traits/common_type.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> __copy(_InIter, _Sent, _OutIter); + +template +struct __copy_impl { + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _Sent __last, _OutIter __result) const { + while (__first != __last) { + *__result = *__first; + ++__first; + ++__result; + } + + return std::make_pair(std::move(__first), std::move(__result)); + } + + template + struct _CopySegment { + using _Traits = __segmented_iterator_traits<_InIter>; + + _OutIter& __result_; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit _CopySegment(_OutIter& __result) + : __result_(__result) {} + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void + operator()(typename _Traits::__local_iterator __lfirst, typename _Traits::__local_iterator __llast) { + __result_ = std::__copy<_AlgPolicy>(__lfirst, __llast, std::move(__result_)).second; + } + }; + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) const { + std::__for_each_segment(__first, __last, _CopySegment<_InIter, _OutIter>(__result)); + return std::make_pair(__last, std::move(__result)); + } + + template ::value && + !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) const { + using _Traits = __segmented_iterator_traits<_OutIter>; + using _DiffT = typename common_type<__iter_diff_t<_InIter>, __iter_diff_t<_OutIter> >::type; + + if (__first == __last) + return std::make_pair(std::move(__first), std::move(__result)); + + auto __local_first = _Traits::__local(__result); + auto __segment_iterator = _Traits::__segment(__result); + while (true) { + auto __local_last = _Traits::__end(__segment_iterator); + auto __size = std::min<_DiffT>(__local_last - __local_first, __last - __first); + auto __iters = std::__copy<_AlgPolicy>(__first, __first + __size, __local_first); + __first = std::move(__iters.first); + + if (__first == __last) + return std::make_pair(std::move(__first), _Traits::__compose(__segment_iterator, std::move(__iters.second))); + + __local_first = _Traits::__begin(++__segment_iterator); + } + } + + // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer. + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> + operator()(_In* __first, _In* __last, _Out* __result) const { + return std::__copy_trivial_impl(__first, __last, __result); + } +}; + +template +pair<_InIter, _OutIter> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +__copy(_InIter __first, _Sent __last, _OutIter __result) { + return std::__copy_move_unwrap_iters<__copy_impl<_AlgPolicy> >( + std::move(__first), std::move(__last), std::move(__result)); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { + return std::__copy<_ClassicAlgPolicy>(__first, __last, __result).second; +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/copy_backward.h b/libcxx/include/__cxx03/__algorithm/copy_backward.h new file mode 100644 index 0000000000000000000000000000000000000000..73dc846a975a44d905bda90a5d5973fb06d34dac --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/copy_backward.h @@ -0,0 +1,137 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_COPY_BACKWARD_H +#define _LIBCPP___ALGORITHM_COPY_BACKWARD_H + +#include <__algorithm/copy_move_common.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/min.h> +#include <__config> +#include <__iterator/segmented_iterator.h> +#include <__type_traits/common_type.h> +#include <__type_traits/is_constructible.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InIter, _OutIter> +__copy_backward(_InIter __first, _Sent __last, _OutIter __result); + +template +struct __copy_backward_impl { + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _Sent __last, _OutIter __result) const { + auto __last_iter = _IterOps<_AlgPolicy>::next(__first, __last); + auto __original_last_iter = __last_iter; + + while (__first != __last_iter) { + *--__result = *--__last_iter; + } + + return std::make_pair(std::move(__original_last_iter), std::move(__result)); + } + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) const { + using _Traits = __segmented_iterator_traits<_InIter>; + auto __sfirst = _Traits::__segment(__first); + auto __slast = _Traits::__segment(__last); + if (__sfirst == __slast) { + auto __iters = + std::__copy_backward<_AlgPolicy>(_Traits::__local(__first), _Traits::__local(__last), std::move(__result)); + return std::make_pair(__last, __iters.second); + } + + __result = + std::__copy_backward<_AlgPolicy>(_Traits::__begin(__slast), _Traits::__local(__last), std::move(__result)) + .second; + --__slast; + while (__sfirst != __slast) { + __result = + std::__copy_backward<_AlgPolicy>(_Traits::__begin(__slast), _Traits::__end(__slast), std::move(__result)) + .second; + --__slast; + } + __result = std::__copy_backward<_AlgPolicy>(_Traits::__local(__first), _Traits::__end(__slast), std::move(__result)) + .second; + return std::make_pair(__last, std::move(__result)); + } + + template ::value && + !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) const { + using _Traits = __segmented_iterator_traits<_OutIter>; + auto __orig_last = __last; + auto __segment_iterator = _Traits::__segment(__result); + + // When the range contains no elements, __result might not be a valid iterator + if (__first == __last) + return std::make_pair(__first, __result); + + auto __local_last = _Traits::__local(__result); + while (true) { + using _DiffT = typename common_type<__iter_diff_t<_InIter>, __iter_diff_t<_OutIter> >::type; + + auto __local_first = _Traits::__begin(__segment_iterator); + auto __size = std::min<_DiffT>(__local_last - __local_first, __last - __first); + auto __iter = std::__copy_backward<_AlgPolicy>(__last - __size, __last, __local_last).second; + __last -= __size; + + if (__first == __last) + return std::make_pair(std::move(__orig_last), _Traits::__compose(__segment_iterator, std::move(__iter))); + --__segment_iterator; + __local_last = _Traits::__end(__segment_iterator); + } + } + + // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer. + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> + operator()(_In* __first, _In* __last, _Out* __result) const { + return std::__copy_backward_trivial_impl(__first, __last, __result); + } +}; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_BidirectionalIterator1, _BidirectionalIterator2> +__copy_backward(_BidirectionalIterator1 __first, _Sentinel __last, _BidirectionalIterator2 __result) { + return std::__copy_move_unwrap_iters<__copy_backward_impl<_AlgPolicy> >( + std::move(__first), std::move(__last), std::move(__result)); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _BidirectionalIterator2 +copy_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last, _BidirectionalIterator2 __result) { + static_assert(std::is_copy_constructible<_BidirectionalIterator1>::value && + std::is_copy_constructible<_BidirectionalIterator1>::value, + "Iterators must be copy constructible."); + + return std::__copy_backward<_ClassicAlgPolicy>(std::move(__first), std::move(__last), std::move(__result)).second; +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_COPY_BACKWARD_H diff --git a/libcxx/include/__cxx03/__algorithm/copy_if.h b/libcxx/include/__cxx03/__algorithm/copy_if.h new file mode 100644 index 0000000000000000000000000000000000000000..228e4d22323e3c8266df2e7acb6d3804430263d0 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/copy_if.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_COPY_IF_H +#define _LIBCPP___ALGORITHM_COPY_IF_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +copy_if(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _Predicate __pred) { + for (; __first != __last; ++__first) { + if (__pred(*__first)) { + *__result = *__first; + ++__result; + } + } + return __result; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_COPY_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/copy_move_common.h b/libcxx/include/__cxx03/__algorithm/copy_move_common.h new file mode 100644 index 0000000000000000000000000000000000000000..8a98451a8f9653ccec214dc76ab0c8f8de975d40 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/copy_move_common.h @@ -0,0 +1,114 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_COPY_MOVE_COMMON_H +#define _LIBCPP___ALGORITHM_COPY_MOVE_COMMON_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/unwrap_iter.h> +#include <__algorithm/unwrap_range.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__memory/pointer_traits.h> +#include <__string/constexpr_c_functions.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_always_bitcastable.h> +#include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_trivially_assignable.h> +#include <__type_traits/is_volatile.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// Type traits. + +template +struct __can_lower_copy_assignment_to_memmove { + static const bool value = + // If the types are always bitcastable, it's valid to do a bitwise copy between them. + __is_always_bitcastable<_From, _To>::value && + // Reject conversions that wouldn't be performed by the regular built-in assignment (e.g. between arrays). + is_trivially_assignable<_To&, const _From&>::value && + // `memmove` doesn't accept `volatile` pointers, make sure the optimization SFINAEs away in that case. + !is_volatile<_From>::value && !is_volatile<_To>::value; +}; + +template +struct __can_lower_move_assignment_to_memmove { + static const bool value = + __is_always_bitcastable<_From, _To>::value && is_trivially_assignable<_To&, _From&&>::value && + !is_volatile<_From>::value && !is_volatile<_To>::value; +}; + +// `memmove` algorithms implementation. + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> +__copy_trivial_impl(_In* __first, _In* __last, _Out* __result) { + const size_t __n = static_cast(__last - __first); + + std::__constexpr_memmove(__result, __first, __element_count(__n)); + + return std::make_pair(__last, __result + __n); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> +__copy_backward_trivial_impl(_In* __first, _In* __last, _Out* __result) { + const size_t __n = static_cast(__last - __first); + __result -= __n; + + std::__constexpr_memmove(__result, __first, __element_count(__n)); + + return std::make_pair(__last, __result); +} + +// Iterator unwrapping and dispatching to the correct overload. + +template +struct __can_rewrap + : integral_constant::value && is_copy_constructible<_OutIter>::value> {}; + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 pair<_InIter, _OutIter> +__copy_move_unwrap_iters(_InIter __first, _Sent __last, _OutIter __out_first) { + auto __range = std::__unwrap_range(__first, std::move(__last)); + auto __result = _Algorithm()(std::move(__range.first), std::move(__range.second), std::__unwrap_iter(__out_first)); + return std::make_pair(std::__rewrap_range<_Sent>(std::move(__first), std::move(__result.first)), + std::__rewrap_iter(std::move(__out_first), std::move(__result.second))); +} + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 pair<_InIter, _OutIter> +__copy_move_unwrap_iters(_InIter __first, _Sent __last, _OutIter __out_first) { + return _Algorithm()(std::move(__first), std::move(__last), std::move(__out_first)); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_COPY_MOVE_COMMON_H diff --git a/libcxx/include/__cxx03/__algorithm/copy_n.h b/libcxx/include/__cxx03/__algorithm/copy_n.h new file mode 100644 index 0000000000000000000000000000000000000000..f93f39203a7e3bbd9972ee0752fc41a1bebbab61 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/copy_n.h @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_COPY_N_H +#define _LIBCPP___ALGORITHM_COPY_N_H + +#include <__algorithm/copy.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__type_traits/enable_if.h> +#include <__utility/convert_to_integral.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template ::value && + !__has_random_access_iterator_category<_InputIterator>::value, + int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) { + typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize; + _IntegralSize __n = __orig_n; + if (__n > 0) { + *__result = *__first; + ++__result; + for (--__n; __n > 0; --__n) { + ++__first; + *__result = *__first; + ++__result; + } + } + return __result; +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) { + typedef typename iterator_traits<_InputIterator>::difference_type difference_type; + typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize; + _IntegralSize __n = __orig_n; + return std::copy(__first, __first + difference_type(__n), __result); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_COPY_N_H diff --git a/libcxx/include/__cxx03/__algorithm/count.h b/libcxx/include/__cxx03/__algorithm/count.h new file mode 100644 index 0000000000000000000000000000000000000000..1cfe7f631ac1b79a435d1e1623fc15c02bf3b4fb --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/count.h @@ -0,0 +1,92 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_COUNT_H +#define _LIBCPP___ALGORITHM_COUNT_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/min.h> +#include <__bit/invert_if.h> +#include <__bit/popcount.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__fwd/bit_reference.h> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// generic implementation +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> +__count(_Iter __first, _Sent __last, const _Tp& __value, _Proj& __proj) { + typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> __r(0); + for (; __first != __last; ++__first) + if (std::__invoke(__proj, *__first) == __value) + ++__r; + return __r; +} + +// __bit_iterator implementation +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __bit_iterator<_Cp, _IsConst>::difference_type +__count_bool(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n) { + using _It = __bit_iterator<_Cp, _IsConst>; + using __storage_type = typename _It::__storage_type; + using difference_type = typename _It::difference_type; + + const int __bits_per_word = _It::__bits_per_word; + difference_type __r = 0; + // do first partial word + if (__first.__ctz_ != 0) { + __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); + __storage_type __dn = std::min(__clz_f, __n); + __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); + __r = std::__libcpp_popcount(std::__invert_if(*__first.__seg_) & __m); + __n -= __dn; + ++__first.__seg_; + } + // do middle whole words + for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) + __r += std::__libcpp_popcount(std::__invert_if(*__first.__seg_)); + // do last partial word + if (__n > 0) { + __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); + __r += std::__libcpp_popcount(std::__invert_if(*__first.__seg_) & __m); + } + return __r; +} + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __iter_diff_t<__bit_iterator<_Cp, _IsConst> > +__count(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, const _Tp& __value, _Proj&) { + if (__value) + return std::__count_bool(__first, static_cast(__last - __first)); + return std::__count_bool(__first, static_cast(__last - __first)); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __iter_diff_t<_InputIterator> +count(_InputIterator __first, _InputIterator __last, const _Tp& __value) { + __identity __proj; + return std::__count<_ClassicAlgPolicy>(__first, __last, __value, __proj); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_COUNT_H diff --git a/libcxx/include/__cxx03/__algorithm/count_if.h b/libcxx/include/__cxx03/__algorithm/count_if.h new file mode 100644 index 0000000000000000000000000000000000000000..25782069d03275dfac35754fca952dc5ccf2a8c5 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/count_if.h @@ -0,0 +1,35 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_COUNT_IF_H +#define _LIBCPP___ALGORITHM_COUNT_IF_H + +#include <__config> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 +typename iterator_traits<_InputIterator>::difference_type +count_if(_InputIterator __first, _InputIterator __last, _Predicate __pred) { + typename iterator_traits<_InputIterator>::difference_type __r(0); + for (; __first != __last; ++__first) + if (__pred(*__first)) + ++__r; + return __r; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_COUNT_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/equal.h b/libcxx/include/__cxx03/__algorithm/equal.h new file mode 100644 index 0000000000000000000000000000000000000000..bfc8f72f6eb1953efb8c01100068f0d976b8eab4 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/equal.h @@ -0,0 +1,133 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_EQUAL_H +#define _LIBCPP___ALGORITHM_EQUAL_H + +#include <__algorithm/comp.h> +#include <__algorithm/unwrap_iter.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__string/constexpr_c_functions.h> +#include <__type_traits/desugars_to.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_equality_comparable.h> +#include <__type_traits/is_volatile.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_iter_impl( + _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate& __pred) { + for (; __first1 != __last1; ++__first1, (void)++__first2) + if (!__pred(*__first1, *__first2)) + return false; + return true; +} + +template && !is_volatile<_Tp>::value && + !is_volatile<_Up>::value && __libcpp_is_trivially_equality_comparable<_Tp, _Up>::value, + int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +__equal_iter_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _BinaryPredicate&) { + return std::__constexpr_memcmp_equal(__first1, __first2, __element_count(__last1 - __first1)); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __pred) { + return std::__equal_iter_impl( + std::__unwrap_iter(__first1), std::__unwrap_iter(__last1), std::__unwrap_iter(__first2), __pred); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2) { + return std::equal(__first1, __last1, __first2, __equal_to()); +} + +#if _LIBCPP_STD_VER >= 14 + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_impl( + _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __comp, _Proj1& __proj1, _Proj2& __proj2) { + while (__first1 != __last1 && __first2 != __last2) { + if (!std::__invoke(__comp, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) + return false; + ++__first1; + ++__first2; + } + return __first1 == __last1 && __first2 == __last2; +} + +template && __is_identity<_Proj1>::value && + __is_identity<_Proj2>::value && !is_volatile<_Tp>::value && !is_volatile<_Up>::value && + __libcpp_is_trivially_equality_comparable<_Tp, _Up>::value, + int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +__equal_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _Up*, _Pred&, _Proj1&, _Proj2&) { + return std::__constexpr_memcmp_equal(__first1, __first2, __element_count(__last1 - __first1)); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +equal(_InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _BinaryPredicate __pred) { + if constexpr (__has_random_access_iterator_category<_InputIterator1>::value && + __has_random_access_iterator_category<_InputIterator2>::value) { + if (std::distance(__first1, __last1) != std::distance(__first2, __last2)) + return false; + } + __identity __proj; + return std::__equal_impl( + std::__unwrap_iter(__first1), + std::__unwrap_iter(__last1), + std::__unwrap_iter(__first2), + std::__unwrap_iter(__last2), + __pred, + __proj, + __proj); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2) { + return std::equal(__first1, __last1, __first2, __last2, __equal_to()); +} + +#endif // _LIBCPP_STD_VER >= 14 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_EQUAL_H diff --git a/libcxx/include/__cxx03/__algorithm/equal_range.h b/libcxx/include/__cxx03/__algorithm/equal_range.h new file mode 100644 index 0000000000000000000000000000000000000000..09bbf8f006021a350cd4a2cd7216ff26f88aeb75 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/equal_range.h @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_EQUAL_RANGE_H +#define _LIBCPP___ALGORITHM_EQUAL_RANGE_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/half_positive.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/lower_bound.h> +#include <__algorithm/upper_bound.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/advance.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__type_traits/is_callable.h> +#include <__type_traits/is_constructible.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Iter, _Iter> +__equal_range(_Iter __first, _Sent __last, const _Tp& __value, _Compare&& __comp, _Proj&& __proj) { + auto __len = _IterOps<_AlgPolicy>::distance(__first, __last); + _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last); + while (__len != 0) { + auto __half_len = std::__half_positive(__len); + _Iter __mid = _IterOps<_AlgPolicy>::next(__first, __half_len); + if (std::__invoke(__comp, std::__invoke(__proj, *__mid), __value)) { + __first = ++__mid; + __len -= __half_len + 1; + } else if (std::__invoke(__comp, __value, std::__invoke(__proj, *__mid))) { + __end = __mid; + __len = __half_len; + } else { + _Iter __mp1 = __mid; + return pair<_Iter, _Iter>(std::__lower_bound<_AlgPolicy>(__first, __mid, __value, __comp, __proj), + std::__upper_bound<_AlgPolicy>(++__mp1, __end, __value, __comp, __proj)); + } + } + return pair<_Iter, _Iter>(__first, __first); +} + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_ForwardIterator, _ForwardIterator> +equal_range(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, _Compare __comp) { + static_assert(__is_callable<_Compare, decltype(*__first), const _Tp&>::value, "The comparator has to be callable"); + static_assert(is_copy_constructible<_ForwardIterator>::value, "Iterator has to be copy constructible"); + return std::__equal_range<_ClassicAlgPolicy>( + std::move(__first), + std::move(__last), + __value, + static_cast<__comp_ref_type<_Compare> >(__comp), + std::__identity()); +} + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_ForwardIterator, _ForwardIterator> +equal_range(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + return std::equal_range(std::move(__first), std::move(__last), __value, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_EQUAL_RANGE_H diff --git a/libcxx/include/__cxx03/__algorithm/fill.h b/libcxx/include/__cxx03/__algorithm/fill.h new file mode 100644 index 0000000000000000000000000000000000000000..1ce3eadb013d05981178f22a898b3d7092c0f643 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/fill.h @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_FILL_H +#define _LIBCPP___ALGORITHM_FILL_H + +#include <__algorithm/fill_n.h> +#include <__config> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// fill isn't specialized for std::memset, because the compiler already optimizes the loop to a call to std::memset. + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +__fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, forward_iterator_tag) { + for (; __first != __last; ++__first) + *__first = __value; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +__fill(_RandomAccessIterator __first, _RandomAccessIterator __last, const _Tp& __value, random_access_iterator_tag) { + std::fill_n(__first, __last - __first, __value); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + std::__fill(__first, __last, __value, typename iterator_traits<_ForwardIterator>::iterator_category()); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_FILL_H diff --git a/libcxx/include/__cxx03/__algorithm/fill_n.h b/libcxx/include/__cxx03/__algorithm/fill_n.h new file mode 100644 index 0000000000000000000000000000000000000000..f29633f88087f01dbd83c78f42f7c3465d629b74 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/fill_n.h @@ -0,0 +1,98 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_FILL_N_H +#define _LIBCPP___ALGORITHM_FILL_N_H + +#include <__algorithm/min.h> +#include <__config> +#include <__fwd/bit_reference.h> +#include <__iterator/iterator_traits.h> +#include <__memory/pointer_traits.h> +#include <__utility/convert_to_integral.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// fill_n isn't specialized for std::memset, because the compiler already optimizes the loop to a call to std::memset. + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +__fill_n(_OutputIterator __first, _Size __n, const _Tp& __value); + +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void +__fill_n_bool(__bit_iterator<_Cp, false> __first, typename _Cp::size_type __n) { + using _It = __bit_iterator<_Cp, false>; + using __storage_type = typename _It::__storage_type; + + const int __bits_per_word = _It::__bits_per_word; + // do first partial word + if (__first.__ctz_ != 0) { + __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); + __storage_type __dn = std::min(__clz_f, __n); + __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); + if (_FillVal) + *__first.__seg_ |= __m; + else + *__first.__seg_ &= ~__m; + __n -= __dn; + ++__first.__seg_; + } + // do middle whole words + __storage_type __nw = __n / __bits_per_word; + std::__fill_n(std::__to_address(__first.__seg_), __nw, _FillVal ? static_cast<__storage_type>(-1) : 0); + __n -= __nw * __bits_per_word; + // do last partial word + if (__n > 0) { + __first.__seg_ += __nw; + __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); + if (_FillVal) + *__first.__seg_ |= __m; + else + *__first.__seg_ &= ~__m; + } +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, false> +__fill_n(__bit_iterator<_Cp, false> __first, _Size __n, const bool& __value) { + if (__n > 0) { + if (__value) + std::__fill_n_bool(__first, __n); + else + std::__fill_n_bool(__first, __n); + } + return __first + __n; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +__fill_n(_OutputIterator __first, _Size __n, const _Tp& __value) { + for (; __n > 0; ++__first, (void)--__n) + *__first = __value; + return __first; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +fill_n(_OutputIterator __first, _Size __n, const _Tp& __value) { + return std::__fill_n(__first, std::__convert_to_integral(__n), __value); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_FILL_N_H diff --git a/libcxx/include/__cxx03/__algorithm/find.h b/libcxx/include/__cxx03/__algorithm/find.h new file mode 100644 index 0000000000000000000000000000000000000000..7f58dbb13a5776e1cca381242275089ffa06a80b --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/find.h @@ -0,0 +1,181 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_FIND_H +#define _LIBCPP___ALGORITHM_FIND_H + +#include <__algorithm/find_segment_if.h> +#include <__algorithm/min.h> +#include <__algorithm/unwrap_iter.h> +#include <__bit/countr.h> +#include <__bit/invert_if.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__fwd/bit_reference.h> +#include <__iterator/segmented_iterator.h> +#include <__string/constexpr_c_functions.h> +#include <__type_traits/is_integral.h> +#include <__type_traits/is_same.h> +#include <__type_traits/is_signed.h> +#include <__utility/move.h> +#include + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +# include +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// generic implementation +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Iter +__find(_Iter __first, _Sent __last, const _Tp& __value, _Proj& __proj) { + for (; __first != __last; ++__first) + if (std::__invoke(__proj, *__first) == __value) + break; + return __first; +} + +// trivially equality comparable implementations +template ::value && __libcpp_is_trivially_equality_comparable<_Tp, _Up>::value && + sizeof(_Tp) == 1, + int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __find(_Tp* __first, _Tp* __last, const _Up& __value, _Proj&) { + if (auto __ret = std::__constexpr_memchr(__first, __value, __last - __first)) + return __ret; + return __last; +} + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template ::value && __libcpp_is_trivially_equality_comparable<_Tp, _Up>::value && + sizeof(_Tp) == sizeof(wchar_t) && _LIBCPP_ALIGNOF(_Tp) >= _LIBCPP_ALIGNOF(wchar_t), + int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __find(_Tp* __first, _Tp* __last, const _Up& __value, _Proj&) { + if (auto __ret = std::__constexpr_wmemchr(__first, __value, __last - __first)) + return __ret; + return __last; +} +#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS + +// TODO: This should also be possible to get right with different signedness +// cast integral types to allow vectorization +template ::value && !__libcpp_is_trivially_equality_comparable<_Tp, _Up>::value && + is_integral<_Tp>::value && is_integral<_Up>::value && + is_signed<_Tp>::value == is_signed<_Up>::value, + int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* +__find(_Tp* __first, _Tp* __last, const _Up& __value, _Proj& __proj) { + if (__value < numeric_limits<_Tp>::min() || __value > numeric_limits<_Tp>::max()) + return __last; + return std::__find(__first, __last, _Tp(__value), __proj); +} + +// __bit_iterator implementation +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, _IsConst> +__find_bool(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n) { + using _It = __bit_iterator<_Cp, _IsConst>; + using __storage_type = typename _It::__storage_type; + + const int __bits_per_word = _It::__bits_per_word; + // do first partial word + if (__first.__ctz_ != 0) { + __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); + __storage_type __dn = std::min(__clz_f, __n); + __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); + __storage_type __b = std::__invert_if(*__first.__seg_) & __m; + if (__b) + return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + if (__n == __dn) + return __first + __n; + __n -= __dn; + ++__first.__seg_; + } + // do middle whole words + for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word) { + __storage_type __b = std::__invert_if(*__first.__seg_); + if (__b) + return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + } + // do last partial word + if (__n > 0) { + __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); + __storage_type __b = std::__invert_if(*__first.__seg_) & __m; + if (__b) + return _It(__first.__seg_, static_cast(std::__libcpp_ctz(__b))); + } + return _It(__first.__seg_, static_cast(__n)); +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, _IsConst> +__find(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, const _Tp& __value, _Proj&) { + if (static_cast(__value)) + return std::__find_bool(__first, static_cast(__last - __first)); + return std::__find_bool(__first, static_cast(__last - __first)); +} + +// segmented iterator implementation + +template +struct __find_segment; + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _SegmentedIterator +__find(_SegmentedIterator __first, _SegmentedIterator __last, const _Tp& __value, _Proj& __proj) { + return std::__find_segment_if(std::move(__first), std::move(__last), __find_segment<_Tp>(__value), __proj); +} + +template +struct __find_segment { + const _Tp& __value_; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __find_segment(const _Tp& __value) : __value_(__value) {} + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _InputIterator + operator()(_InputIterator __first, _InputIterator __last, _Proj& __proj) const { + return std::__find(__first, __last, __value_, __proj); + } +}; + +// public API +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator +find(_InputIterator __first, _InputIterator __last, const _Tp& __value) { + __identity __proj; + return std::__rewrap_iter( + __first, std::__find(std::__unwrap_iter(__first), std::__unwrap_iter(__last), __value, __proj)); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_FIND_H diff --git a/libcxx/include/__cxx03/__algorithm/find_end.h b/libcxx/include/__cxx03/__algorithm/find_end.h new file mode 100644 index 0000000000000000000000000000000000000000..7e08e7953534eb039476ab16505d1885f7286f5c --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/find_end.h @@ -0,0 +1,225 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_FIND_END_OF_H +#define _LIBCPP___ALGORITHM_FIND_END_OF_H + +#include <__algorithm/comp.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/search.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/advance.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/reverse_iterator.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template < class _AlgPolicy, + class _Iter1, + class _Sent1, + class _Iter2, + class _Sent2, + class _Pred, + class _Proj1, + class _Proj2> +_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __find_end_impl( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred& __pred, + _Proj1& __proj1, + _Proj2& __proj2, + forward_iterator_tag, + forward_iterator_tag) { + // modeled after search algorithm + _Iter1 __match_first = _IterOps<_AlgPolicy>::next(__first1, __last1); // __last1 is the "default" answer + _Iter1 __match_last = __match_first; + if (__first2 == __last2) + return pair<_Iter1, _Iter1>(__match_last, __match_last); + while (true) { + while (true) { + if (__first1 == __last1) // if source exhausted return last correct answer (or __last1 if never found) + return pair<_Iter1, _Iter1>(__match_first, __match_last); + if (std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) + break; + ++__first1; + } + // *__first1 matches *__first2, now match elements after here + _Iter1 __m1 = __first1; + _Iter2 __m2 = __first2; + while (true) { + if (++__m2 == __last2) { // Pattern exhaused, record answer and search for another one + __match_first = __first1; + __match_last = ++__m1; + ++__first1; + break; + } + if (++__m1 == __last1) // Source exhausted, return last answer + return pair<_Iter1, _Iter1>(__match_first, __match_last); + // mismatch, restart with a new __first + if (!std::__invoke(__pred, std::__invoke(__proj1, *__m1), std::__invoke(__proj2, *__m2))) { + ++__first1; + break; + } // else there is a match, check next elements + } + } +} + +template < class _IterOps, + class _Pred, + class _Iter1, + class _Sent1, + class _Iter2, + class _Sent2, + class _Proj1, + class _Proj2> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter1 __find_end( + _Iter1 __first1, + _Sent1 __sent1, + _Iter2 __first2, + _Sent2 __sent2, + _Pred& __pred, + _Proj1& __proj1, + _Proj2& __proj2, + bidirectional_iterator_tag, + bidirectional_iterator_tag) { + auto __last1 = _IterOps::next(__first1, __sent1); + auto __last2 = _IterOps::next(__first2, __sent2); + // modeled after search algorithm (in reverse) + if (__first2 == __last2) + return __last1; // Everything matches an empty sequence + _Iter1 __l1 = __last1; + _Iter2 __l2 = __last2; + --__l2; + while (true) { + // Find last element in sequence 1 that matchs *(__last2-1), with a mininum of loop checks + while (true) { + if (__first1 == __l1) // return __last1 if no element matches *__first2 + return __last1; + if (std::__invoke(__pred, std::__invoke(__proj1, *--__l1), std::__invoke(__proj2, *__l2))) + break; + } + // *__l1 matches *__l2, now match elements before here + _Iter1 __m1 = __l1; + _Iter2 __m2 = __l2; + while (true) { + if (__m2 == __first2) // If pattern exhausted, __m1 is the answer (works for 1 element pattern) + return __m1; + if (__m1 == __first1) // Otherwise if source exhaused, pattern not found + return __last1; + + // if there is a mismatch, restart with a new __l1 + if (!std::__invoke(__pred, std::__invoke(__proj1, *--__m1), std::__invoke(__proj2, *--__m2))) { + break; + } // else there is a match, check next elements + } + } +} + +template < class _AlgPolicy, + class _Pred, + class _Iter1, + class _Sent1, + class _Iter2, + class _Sent2, + class _Proj1, + class _Proj2> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Iter1 __find_end( + _Iter1 __first1, + _Sent1 __sent1, + _Iter2 __first2, + _Sent2 __sent2, + _Pred& __pred, + _Proj1& __proj1, + _Proj2& __proj2, + random_access_iterator_tag, + random_access_iterator_tag) { + typedef typename iterator_traits<_Iter1>::difference_type _D1; + auto __last1 = _IterOps<_AlgPolicy>::next(__first1, __sent1); + auto __last2 = _IterOps<_AlgPolicy>::next(__first2, __sent2); + // Take advantage of knowing source and pattern lengths. Stop short when source is smaller than pattern + auto __len2 = __last2 - __first2; + if (__len2 == 0) + return __last1; + auto __len1 = __last1 - __first1; + if (__len1 < __len2) + return __last1; + const _Iter1 __s = __first1 + _D1(__len2 - 1); // End of pattern match can't go before here + _Iter1 __l1 = __last1; + _Iter2 __l2 = __last2; + --__l2; + while (true) { + while (true) { + if (__s == __l1) + return __last1; + if (std::__invoke(__pred, std::__invoke(__proj1, *--__l1), std::__invoke(__proj2, *__l2))) + break; + } + _Iter1 __m1 = __l1; + _Iter2 __m2 = __l2; + while (true) { + if (__m2 == __first2) + return __m1; + // no need to check range on __m1 because __s guarantees we have enough source + if (!std::__invoke(__pred, std::__invoke(__proj1, *--__m1), std::__invoke(*--__m2))) { + break; + } + } + } +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator1 __find_end_classic( + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2, + _BinaryPredicate& __pred) { + auto __proj = __identity(); + return std::__find_end_impl<_ClassicAlgPolicy>( + __first1, + __last1, + __first2, + __last2, + __pred, + __proj, + __proj, + typename iterator_traits<_ForwardIterator1>::iterator_category(), + typename iterator_traits<_ForwardIterator2>::iterator_category()) + .first; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1 find_end( + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2, + _BinaryPredicate __pred) { + return std::__find_end_classic(__first1, __last1, __first2, __last2, __pred); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1 +find_end(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2) { + return std::find_end(__first1, __last1, __first2, __last2, __equal_to()); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_FIND_END_OF_H diff --git a/libcxx/include/__cxx03/__algorithm/find_first_of.h b/libcxx/include/__cxx03/__algorithm/find_first_of.h new file mode 100644 index 0000000000000000000000000000000000000000..6b99f562f8804e3780071a1870ee4388af74b9c6 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/find_first_of.h @@ -0,0 +1,55 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_FIND_FIRST_OF_H +#define _LIBCPP___ALGORITHM_FIND_FIRST_OF_H + +#include <__algorithm/comp.h> +#include <__config> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator1 __find_first_of_ce( + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2, + _BinaryPredicate&& __pred) { + for (; __first1 != __last1; ++__first1) + for (_ForwardIterator2 __j = __first2; __j != __last2; ++__j) + if (__pred(*__first1, *__j)) + return __first1; + return __last1; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1 find_first_of( + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2, + _BinaryPredicate __pred) { + return std::__find_first_of_ce(__first1, __last1, __first2, __last2, __pred); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1 find_first_of( + _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2) { + return std::__find_first_of_ce(__first1, __last1, __first2, __last2, __equal_to()); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_FIND_FIRST_OF_H diff --git a/libcxx/include/__cxx03/__algorithm/find_if.h b/libcxx/include/__cxx03/__algorithm/find_if.h new file mode 100644 index 0000000000000000000000000000000000000000..22092d352b06e7f97319091c8f8e10cc6e1de5ed --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/find_if.h @@ -0,0 +1,32 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_FIND_IF_H +#define _LIBCPP___ALGORITHM_FIND_IF_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator +find_if(_InputIterator __first, _InputIterator __last, _Predicate __pred) { + for (; __first != __last; ++__first) + if (__pred(*__first)) + break; + return __first; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_FIND_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/find_if_not.h b/libcxx/include/__cxx03/__algorithm/find_if_not.h new file mode 100644 index 0000000000000000000000000000000000000000..cc2001967f0c5a82ab91a4412824c1e0ef5806af --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/find_if_not.h @@ -0,0 +1,32 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_FIND_IF_NOT_H +#define _LIBCPP___ALGORITHM_FIND_IF_NOT_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator +find_if_not(_InputIterator __first, _InputIterator __last, _Predicate __pred) { + for (; __first != __last; ++__first) + if (!__pred(*__first)) + break; + return __first; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_FIND_IF_NOT_H diff --git a/libcxx/include/__cxx03/__algorithm/find_segment_if.h b/libcxx/include/__cxx03/__algorithm/find_segment_if.h new file mode 100644 index 0000000000000000000000000000000000000000..9d6064f3e283a6953c03a983baa4ce467a7f1337 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/find_segment_if.h @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_FIND_SEGMENT_IF_H +#define _LIBCPP___ALGORITHM_FIND_SEGMENT_IF_H + +#include <__config> +#include <__iterator/segmented_iterator.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// __find_segment_if is a utility function for optimizing iteration over segmented iterators linearly. +// [__first, __last) has to be a segmented range. __pred is expected to take a range of local iterators and the __proj. +// It returns an iterator to the first element that satisfies the predicate, or a one-past-the-end iterator if there was +// no match. __proj may be anything that should be passed to __pred, but is expected to be a projection to support +// ranges algorithms, or __identity for classic algorithms. + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _SegmentedIterator +__find_segment_if(_SegmentedIterator __first, _SegmentedIterator __last, _Pred __pred, _Proj& __proj) { + using _Traits = __segmented_iterator_traits<_SegmentedIterator>; + + auto __sfirst = _Traits::__segment(__first); + auto __slast = _Traits::__segment(__last); + + // We are in a single segment, so we might not be at the beginning or end + if (__sfirst == __slast) + return _Traits::__compose(__sfirst, __pred(_Traits::__local(__first), _Traits::__local(__last), __proj)); + + { // We have more than one segment. Iterate over the first segment, since we might not start at the beginning + auto __llast = _Traits::__end(__sfirst); + auto __liter = __pred(_Traits::__local(__first), __llast, __proj); + if (__liter != __llast) + return _Traits::__compose(__sfirst, __liter); + } + ++__sfirst; + + // Iterate over the segments which are guaranteed to be completely in the range + while (__sfirst != __slast) { + auto __llast = _Traits::__end(__sfirst); + auto __liter = __pred(_Traits::__begin(__sfirst), _Traits::__end(__sfirst), __proj); + if (__liter != __llast) + return _Traits::__compose(__sfirst, __liter); + ++__sfirst; + } + + // Iterate over the last segment + return _Traits::__compose(__sfirst, __pred(_Traits::__begin(__sfirst), _Traits::__local(__last), __proj)); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_FIND_SEGMENT_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/fold.h b/libcxx/include/__cxx03/__algorithm/fold.h new file mode 100644 index 0000000000000000000000000000000000000000..255658f52324991bdb4601abc87ab9424e8134f2 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/fold.h @@ -0,0 +1,128 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_FOLD_H +#define _LIBCPP___ALGORITHM_FOLD_H + +#include <__concepts/assignable.h> +#include <__concepts/convertible_to.h> +#include <__concepts/invocable.h> +#include <__concepts/movable.h> +#include <__config> +#include <__functional/invoke.h> +#include <__functional/reference_wrapper.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__type_traits/decay.h> +#include <__type_traits/invoke.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +namespace ranges { +template +struct in_value_result { + _LIBCPP_NO_UNIQUE_ADDRESS _Ip in; + _LIBCPP_NO_UNIQUE_ADDRESS _Tp value; + + template + requires convertible_to && convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr operator in_value_result<_I2, _T2>() const& { + return {in, value}; + } + + template + requires convertible_to<_Ip, _I2> && convertible_to<_Tp, _T2> + _LIBCPP_HIDE_FROM_ABI constexpr operator in_value_result<_I2, _T2>() && { + return {std::move(in), std::move(value)}; + } +}; + +template +using fold_left_with_iter_result = in_value_result<_Ip, _Tp>; + +template > +concept __indirectly_binary_left_foldable_impl = + convertible_to<_Rp, _Up> && // + movable<_Tp> && // + movable<_Up> && // + convertible_to<_Tp, _Up> && // + invocable<_Fp&, _Up, iter_reference_t<_Ip>> && // + assignable_from<_Up&, invoke_result_t<_Fp&, _Up, iter_reference_t<_Ip>>>; + +template +concept __indirectly_binary_left_foldable = + copy_constructible<_Fp> && // + invocable<_Fp&, _Tp, iter_reference_t<_Ip>> && // + __indirectly_binary_left_foldable_impl<_Fp, _Tp, _Ip, invoke_result_t<_Fp&, _Tp, iter_reference_t<_Ip>>>; + +struct __fold_left_with_iter { + template _Sp, class _Tp, __indirectly_binary_left_foldable<_Tp, _Ip> _Fp> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Ip __first, _Sp __last, _Tp __init, _Fp __f) { + using _Up = decay_t>>; + + if (__first == __last) { + return fold_left_with_iter_result<_Ip, _Up>{std::move(__first), _Up(std::move(__init))}; + } + + _Up __result = std::invoke(__f, std::move(__init), *__first); + for (++__first; __first != __last; ++__first) { + __result = std::invoke(__f, std::move(__result), *__first); + } + + return fold_left_with_iter_result<_Ip, _Up>{std::move(__first), std::move(__result)}; + } + + template > _Fp> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Rp&& __r, _Tp __init, _Fp __f) { + auto __result = operator()(ranges::begin(__r), ranges::end(__r), std::move(__init), std::ref(__f)); + + using _Up = decay_t>>; + return fold_left_with_iter_result, _Up>{std::move(__result.in), std::move(__result.value)}; + } +}; + +inline constexpr auto fold_left_with_iter = __fold_left_with_iter(); + +struct __fold_left { + template _Sp, class _Tp, __indirectly_binary_left_foldable<_Tp, _Ip> _Fp> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Ip __first, _Sp __last, _Tp __init, _Fp __f) { + return fold_left_with_iter(std::move(__first), std::move(__last), std::move(__init), std::ref(__f)).value; + } + + template > _Fp> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Rp&& __r, _Tp __init, _Fp __f) { + return fold_left_with_iter(ranges::begin(__r), ranges::end(__r), std::move(__init), std::ref(__f)).value; + } +}; + +inline constexpr auto fold_left = __fold_left(); +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_FOLD_H diff --git a/libcxx/include/__cxx03/__algorithm/for_each.h b/libcxx/include/__cxx03/__algorithm/for_each.h new file mode 100644 index 0000000000000000000000000000000000000000..259e527f87f9156cf550854543fa63a2d4698135 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/for_each.h @@ -0,0 +1,57 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_FOR_EACH_H +#define _LIBCPP___ALGORITHM_FOR_EACH_H + +#include <__algorithm/for_each_segment.h> +#include <__config> +#include <__iterator/segmented_iterator.h> +#include <__ranges/movable_box.h> +#include <__type_traits/enable_if.h> +#include <__utility/in_place.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Function +for_each(_InputIterator __first, _InputIterator __last, _Function __f) { + for (; __first != __last; ++__first) + __f(*__first); + return __f; +} + +// __movable_box is available in C++20, but is actually a copyable-box, so optimization is only correct in C++23 +#if _LIBCPP_STD_VER >= 23 +template + requires __is_segmented_iterator<_SegmentedIterator>::value +_LIBCPP_HIDE_FROM_ABI constexpr _Function +for_each(_SegmentedIterator __first, _SegmentedIterator __last, _Function __func) { + ranges::__movable_box<_Function> __wrapped_func(in_place, std::move(__func)); + std::__for_each_segment(__first, __last, [&](auto __lfirst, auto __llast) { + __wrapped_func = + ranges::__movable_box<_Function>(in_place, std::for_each(__lfirst, __llast, std::move(*__wrapped_func))); + }); + return std::move(*__wrapped_func); +} +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_FOR_EACH_H diff --git a/libcxx/include/__cxx03/__algorithm/for_each_n.h b/libcxx/include/__cxx03/__algorithm/for_each_n.h new file mode 100644 index 0000000000000000000000000000000000000000..fce380b49df3e0f0f38ef0dafb3d2bebaa70fa93 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/for_each_n.h @@ -0,0 +1,41 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_FOR_EACH_N_H +#define _LIBCPP___ALGORITHM_FOR_EACH_N_H + +#include <__config> +#include <__utility/convert_to_integral.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator +for_each_n(_InputIterator __first, _Size __orig_n, _Function __f) { + typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize; + _IntegralSize __n = __orig_n; + while (__n > 0) { + __f(*__first); + ++__first; + --__n; + } + return __first; +} + +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_FOR_EACH_N_H diff --git a/libcxx/include/__cxx03/__algorithm/for_each_segment.h b/libcxx/include/__cxx03/__algorithm/for_each_segment.h new file mode 100644 index 0000000000000000000000000000000000000000..93aa8259b2f7f2792f686065f02f4202928ae438 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/for_each_segment.h @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_FOR_EACH_SEGMENT_H +#define _LIBCPP___ALGORITHM_FOR_EACH_SEGMENT_H + +#include <__config> +#include <__iterator/segmented_iterator.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// __for_each_segment is a utility function for optimizing iterating over segmented iterators linearly. +// __first and __last are expected to be a segmented range. __func is expected to take a range of local iterators. +// Anything that is returned from __func is ignored. + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void +__for_each_segment(_SegmentedIterator __first, _SegmentedIterator __last, _Functor __func) { + using _Traits = __segmented_iterator_traits<_SegmentedIterator>; + + auto __sfirst = _Traits::__segment(__first); + auto __slast = _Traits::__segment(__last); + + // We are in a single segment, so we might not be at the beginning or end + if (__sfirst == __slast) { + __func(_Traits::__local(__first), _Traits::__local(__last)); + return; + } + + // We have more than one segment. Iterate over the first segment, since we might not start at the beginning + __func(_Traits::__local(__first), _Traits::__end(__sfirst)); + ++__sfirst; + // iterate over the segments which are guaranteed to be completely in the range + while (__sfirst != __slast) { + __func(_Traits::__begin(__sfirst), _Traits::__end(__sfirst)); + ++__sfirst; + } + // iterate over the last segment + __func(_Traits::__begin(__sfirst), _Traits::__local(__last)); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_FOR_EACH_SEGMENT_H diff --git a/libcxx/include/__cxx03/__algorithm/generate.h b/libcxx/include/__cxx03/__algorithm/generate.h new file mode 100644 index 0000000000000000000000000000000000000000..c95b527402f5db1a89e2517978aae0a60b8cdd62 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/generate.h @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_GENERATE_H +#define _LIBCPP___ALGORITHM_GENERATE_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +generate(_ForwardIterator __first, _ForwardIterator __last, _Generator __gen) { + for (; __first != __last; ++__first) + *__first = __gen(); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_GENERATE_H diff --git a/libcxx/include/__cxx03/__algorithm/generate_n.h b/libcxx/include/__cxx03/__algorithm/generate_n.h new file mode 100644 index 0000000000000000000000000000000000000000..f36403fd0f94a9fd3c8dac9ba569108ff53ed228 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/generate_n.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_GENERATE_N_H +#define _LIBCPP___ALGORITHM_GENERATE_N_H + +#include <__config> +#include <__utility/convert_to_integral.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +generate_n(_OutputIterator __first, _Size __orig_n, _Generator __gen) { + typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize; + _IntegralSize __n = __orig_n; + for (; __n > 0; ++__first, (void)--__n) + *__first = __gen(); + return __first; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_GENERATE_N_H diff --git a/libcxx/include/__cxx03/__algorithm/half_positive.h b/libcxx/include/__cxx03/__algorithm/half_positive.h new file mode 100644 index 0000000000000000000000000000000000000000..ebda0da372369d5b168673a5f541e5f4a49fb5a5 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/half_positive.h @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_HALF_POSITIVE_H +#define _LIBCPP___ALGORITHM_HALF_POSITIVE_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_integral.h> +#include <__type_traits/make_unsigned.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// Perform division by two quickly for positive integers (llvm.org/PR39129) + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Integral __half_positive(_Integral __value) { + return static_cast<_Integral>(static_cast<__make_unsigned_t<_Integral> >(__value) / 2); +} + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp __half_positive(_Tp __value) { + return __value / 2; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_HALF_POSITIVE_H diff --git a/libcxx/include/__cxx03/__algorithm/in_found_result.h b/libcxx/include/__cxx03/__algorithm/in_found_result.h new file mode 100644 index 0000000000000000000000000000000000000000..a67ae387974c0a8b5b6f603a1bc2f5df2fdd96c1 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/in_found_result.h @@ -0,0 +1,54 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_IN_FOUND_RESULT_H +#define _LIBCPP___ALGORITHM_IN_FOUND_RESULT_H + +#include <__concepts/convertible_to.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +template +struct in_found_result { + _LIBCPP_NO_UNIQUE_ADDRESS _InIter1 in; + bool found; + + template + requires convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr operator in_found_result<_InIter2>() const& { + return {in, found}; + } + + template + requires convertible_to<_InIter1, _InIter2> + _LIBCPP_HIDE_FROM_ABI constexpr operator in_found_result<_InIter2>() && { + return {std::move(in), found}; + } +}; +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_IN_FOUND_RESULT_H diff --git a/libcxx/include/__cxx03/__algorithm/in_fun_result.h b/libcxx/include/__cxx03/__algorithm/in_fun_result.h new file mode 100644 index 0000000000000000000000000000000000000000..a22069a9a8ddaaec6930eb4d35caaaf1b0d98c91 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/in_fun_result.h @@ -0,0 +1,54 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_IN_FUN_RESULT_H +#define _LIBCPP___ALGORITHM_IN_FUN_RESULT_H + +#include <__concepts/convertible_to.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace ranges { +template +struct in_fun_result { + _LIBCPP_NO_UNIQUE_ADDRESS _InIter1 in; + _LIBCPP_NO_UNIQUE_ADDRESS _Func1 fun; + + template + requires convertible_to && convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr operator in_fun_result<_InIter2, _Func2>() const& { + return {in, fun}; + } + + template + requires convertible_to<_InIter1, _InIter2> && convertible_to<_Func1, _Func2> + _LIBCPP_HIDE_FROM_ABI constexpr operator in_fun_result<_InIter2, _Func2>() && { + return {std::move(in), std::move(fun)}; + } +}; +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_IN_FUN_RESULT_H diff --git a/libcxx/include/__cxx03/__algorithm/in_in_out_result.h b/libcxx/include/__cxx03/__algorithm/in_in_out_result.h new file mode 100644 index 0000000000000000000000000000000000000000..ba0380b5c68147da37b93dbf72860f9befc9dfcc --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/in_in_out_result.h @@ -0,0 +1,59 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_IN_IN_OUT_RESULT_H +#define _LIBCPP___ALGORITHM_IN_IN_OUT_RESULT_H + +#include <__concepts/convertible_to.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace ranges { + +template +struct in_in_out_result { + _LIBCPP_NO_UNIQUE_ADDRESS _InIter1 in1; + _LIBCPP_NO_UNIQUE_ADDRESS _InIter2 in2; + _LIBCPP_NO_UNIQUE_ADDRESS _OutIter1 out; + + template + requires convertible_to && convertible_to && + convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr operator in_in_out_result<_InIter3, _InIter4, _OutIter2>() const& { + return {in1, in2, out}; + } + + template + requires convertible_to<_InIter1, _InIter3> && convertible_to<_InIter2, _InIter4> && + convertible_to<_OutIter1, _OutIter2> + _LIBCPP_HIDE_FROM_ABI constexpr operator in_in_out_result<_InIter3, _InIter4, _OutIter2>() && { + return {std::move(in1), std::move(in2), std::move(out)}; + } +}; + +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_IN_IN_OUT_RESULT_H diff --git a/libcxx/include/__cxx03/__algorithm/in_in_result.h b/libcxx/include/__cxx03/__algorithm/in_in_result.h new file mode 100644 index 0000000000000000000000000000000000000000..994573fc70fd887f4a3d18a57b6ade6e63cd8dc6 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/in_in_result.h @@ -0,0 +1,56 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_IN_IN_RESULT_H +#define _LIBCPP___ALGORITHM_IN_IN_RESULT_H + +#include <__concepts/convertible_to.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace ranges { + +template +struct in_in_result { + _LIBCPP_NO_UNIQUE_ADDRESS _InIter1 in1; + _LIBCPP_NO_UNIQUE_ADDRESS _InIter2 in2; + + template + requires convertible_to && convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr operator in_in_result<_InIter3, _InIter4>() const& { + return {in1, in2}; + } + + template + requires convertible_to<_InIter1, _InIter3> && convertible_to<_InIter2, _InIter4> + _LIBCPP_HIDE_FROM_ABI constexpr operator in_in_result<_InIter3, _InIter4>() && { + return {std::move(in1), std::move(in2)}; + } +}; + +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_IN_IN_RESULT_H diff --git a/libcxx/include/__cxx03/__algorithm/in_out_out_result.h b/libcxx/include/__cxx03/__algorithm/in_out_out_result.h new file mode 100644 index 0000000000000000000000000000000000000000..8ceb452841a419b894f5f9c1cd8a7d2a9fbd8dc9 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/in_out_out_result.h @@ -0,0 +1,57 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_IN_OUT_OUT_RESULT_H +#define _LIBCPP___ALGORITHM_IN_OUT_OUT_RESULT_H + +#include <__concepts/convertible_to.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace ranges { +template +struct in_out_out_result { + _LIBCPP_NO_UNIQUE_ADDRESS _InIter1 in; + _LIBCPP_NO_UNIQUE_ADDRESS _OutIter1 out1; + _LIBCPP_NO_UNIQUE_ADDRESS _OutIter2 out2; + + template + requires convertible_to && convertible_to && + convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr operator in_out_out_result<_InIter2, _OutIter3, _OutIter4>() const& { + return {in, out1, out2}; + } + + template + requires convertible_to<_InIter1, _InIter2> && convertible_to<_OutIter1, _OutIter3> && + convertible_to<_OutIter2, _OutIter4> + _LIBCPP_HIDE_FROM_ABI constexpr operator in_out_out_result<_InIter2, _OutIter3, _OutIter4>() && { + return {std::move(in), std::move(out1), std::move(out2)}; + } +}; +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_IN_OUT_OUT_RESULT_H diff --git a/libcxx/include/__cxx03/__algorithm/in_out_result.h b/libcxx/include/__cxx03/__algorithm/in_out_result.h new file mode 100644 index 0000000000000000000000000000000000000000..a7a986cf8e6c097112f8dc4a7d3063faee90ba6d --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/in_out_result.h @@ -0,0 +1,56 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_IN_OUT_RESULT_H +#define _LIBCPP___ALGORITHM_IN_OUT_RESULT_H + +#include <__concepts/convertible_to.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace ranges { + +template +struct in_out_result { + _LIBCPP_NO_UNIQUE_ADDRESS _InIter1 in; + _LIBCPP_NO_UNIQUE_ADDRESS _OutIter1 out; + + template + requires convertible_to && convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr operator in_out_result<_InIter2, _OutIter2>() const& { + return {in, out}; + } + + template + requires convertible_to<_InIter1, _InIter2> && convertible_to<_OutIter1, _OutIter2> + _LIBCPP_HIDE_FROM_ABI constexpr operator in_out_result<_InIter2, _OutIter2>() && { + return {std::move(in), std::move(out)}; + } +}; + +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_IN_OUT_RESULT_H diff --git a/libcxx/include/__cxx03/__algorithm/includes.h b/libcxx/include/__cxx03/__algorithm/includes.h new file mode 100644 index 0000000000000000000000000000000000000000..62af03c3742608eac2d3fda827f2c3d6be952b4c --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/includes.h @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_INCLUDES_H +#define _LIBCPP___ALGORITHM_INCLUDES_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_callable.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __includes( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Comp&& __comp, + _Proj1&& __proj1, + _Proj2&& __proj2) { + for (; __first2 != __last2; ++__first1) { + if (__first1 == __last1 || + std::__invoke(__comp, std::__invoke(__proj2, *__first2), std::__invoke(__proj1, *__first1))) + return false; + if (!std::__invoke(__comp, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) + ++__first2; + } + return true; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +includes(_InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _Compare __comp) { + static_assert( + __is_callable<_Compare, decltype(*__first1), decltype(*__first2)>::value, "Comparator has to be callable"); + + return std::__includes( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + static_cast<__comp_ref_type<_Compare> >(__comp), + __identity(), + __identity()); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +includes(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2) { + return std::includes(std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_INCLUDES_H diff --git a/libcxx/include/__cxx03/__algorithm/inplace_merge.h b/libcxx/include/__cxx03/__algorithm/inplace_merge.h new file mode 100644 index 0000000000000000000000000000000000000000..a6bcc66a2fa47ad51523265750b50db1d4b73d49 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/inplace_merge.h @@ -0,0 +1,240 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_INPLACE_MERGE_H +#define _LIBCPP___ALGORITHM_INPLACE_MERGE_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/lower_bound.h> +#include <__algorithm/min.h> +#include <__algorithm/move.h> +#include <__algorithm/rotate.h> +#include <__algorithm/upper_bound.h> +#include <__config> +#include <__functional/identity.h> +#include <__iterator/advance.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/reverse_iterator.h> +#include <__memory/destruct_n.h> +#include <__memory/temporary_buffer.h> +#include <__memory/unique_ptr.h> +#include <__utility/pair.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class __invert // invert the sense of a comparison +{ +private: + _Predicate __p_; + +public: + _LIBCPP_HIDE_FROM_ABI __invert() {} + + _LIBCPP_HIDE_FROM_ABI explicit __invert(_Predicate __p) : __p_(__p) {} + + template + _LIBCPP_HIDE_FROM_ABI bool operator()(const _T1& __x) { + return !__p_(__x); + } + + template + _LIBCPP_HIDE_FROM_ABI bool operator()(const _T1& __x, const _T2& __y) { + return __p_(__y, __x); + } +}; + +template +_LIBCPP_HIDE_FROM_ABI void __half_inplace_merge( + _InputIterator1 __first1, + _Sent1 __last1, + _InputIterator2 __first2, + _Sent2 __last2, + _OutputIterator __result, + _Compare&& __comp) { + for (; __first1 != __last1; ++__result) { + if (__first2 == __last2) { + std::__move<_AlgPolicy>(__first1, __last1, __result); + return; + } + + if (__comp(*__first2, *__first1)) { + *__result = _IterOps<_AlgPolicy>::__iter_move(__first2); + ++__first2; + } else { + *__result = _IterOps<_AlgPolicy>::__iter_move(__first1); + ++__first1; + } + } + // __first2 through __last2 are already in the right spot. +} + +template +_LIBCPP_HIDE_FROM_ABI void __buffered_inplace_merge( + _BidirectionalIterator __first, + _BidirectionalIterator __middle, + _BidirectionalIterator __last, + _Compare&& __comp, + typename iterator_traits<_BidirectionalIterator>::difference_type __len1, + typename iterator_traits<_BidirectionalIterator>::difference_type __len2, + typename iterator_traits<_BidirectionalIterator>::value_type* __buff) { + typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type; + __destruct_n __d(0); + unique_ptr __h2(__buff, __d); + if (__len1 <= __len2) { + value_type* __p = __buff; + for (_BidirectionalIterator __i = __first; __i != __middle; + __d.template __incr(), (void)++__i, (void)++__p) + ::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i)); + std::__half_inplace_merge<_AlgPolicy>(__buff, __p, __middle, __last, __first, __comp); + } else { + value_type* __p = __buff; + for (_BidirectionalIterator __i = __middle; __i != __last; + __d.template __incr(), (void)++__i, (void)++__p) + ::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i)); + typedef reverse_iterator<_BidirectionalIterator> _RBi; + typedef reverse_iterator _Rv; + typedef __invert<_Compare> _Inverted; + std::__half_inplace_merge<_AlgPolicy>( + _Rv(__p), _Rv(__buff), _RBi(__middle), _RBi(__first), _RBi(__last), _Inverted(__comp)); + } +} + +template +void __inplace_merge( + _BidirectionalIterator __first, + _BidirectionalIterator __middle, + _BidirectionalIterator __last, + _Compare&& __comp, + typename iterator_traits<_BidirectionalIterator>::difference_type __len1, + typename iterator_traits<_BidirectionalIterator>::difference_type __len2, + typename iterator_traits<_BidirectionalIterator>::value_type* __buff, + ptrdiff_t __buff_size) { + using _Ops = _IterOps<_AlgPolicy>; + + typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type; + while (true) { + // if __middle == __last, we're done + if (__len2 == 0) + return; + if (__len1 <= __buff_size || __len2 <= __buff_size) + return std::__buffered_inplace_merge<_AlgPolicy>(__first, __middle, __last, __comp, __len1, __len2, __buff); + // shrink [__first, __middle) as much as possible (with no moves), returning if it shrinks to 0 + for (; true; ++__first, (void)--__len1) { + if (__len1 == 0) + return; + if (__comp(*__middle, *__first)) + break; + } + // __first < __middle < __last + // *__first > *__middle + // partition [__first, __m1) [__m1, __middle) [__middle, __m2) [__m2, __last) such that + // all elements in: + // [__first, __m1) <= [__middle, __m2) + // [__middle, __m2) < [__m1, __middle) + // [__m1, __middle) <= [__m2, __last) + // and __m1 or __m2 is in the middle of its range + _BidirectionalIterator __m1; // "median" of [__first, __middle) + _BidirectionalIterator __m2; // "median" of [__middle, __last) + difference_type __len11; // distance(__first, __m1) + difference_type __len21; // distance(__middle, __m2) + // binary search smaller range + if (__len1 < __len2) { // __len >= 1, __len2 >= 2 + __len21 = __len2 / 2; + __m2 = __middle; + _Ops::advance(__m2, __len21); + __m1 = std::__upper_bound<_AlgPolicy>(__first, __middle, *__m2, __comp, std::__identity()); + __len11 = _Ops::distance(__first, __m1); + } else { + if (__len1 == 1) { // __len1 >= __len2 && __len2 > 0, therefore __len2 == 1 + // It is known *__first > *__middle + _Ops::iter_swap(__first, __middle); + return; + } + // __len1 >= 2, __len2 >= 1 + __len11 = __len1 / 2; + __m1 = __first; + _Ops::advance(__m1, __len11); + __m2 = std::lower_bound(__middle, __last, *__m1, __comp); + __len21 = _Ops::distance(__middle, __m2); + } + difference_type __len12 = __len1 - __len11; // distance(__m1, __middle) + difference_type __len22 = __len2 - __len21; // distance(__m2, __last) + // [__first, __m1) [__m1, __middle) [__middle, __m2) [__m2, __last) + // swap middle two partitions + __middle = std::__rotate<_AlgPolicy>(__m1, __middle, __m2).first; + // __len12 and __len21 now have swapped meanings + // merge smaller range with recursive call and larger with tail recursion elimination + if (__len11 + __len21 < __len12 + __len22) { + std::__inplace_merge<_AlgPolicy>(__first, __m1, __middle, __comp, __len11, __len21, __buff, __buff_size); + __first = __middle; + __middle = __m2; + __len1 = __len12; + __len2 = __len22; + } else { + std::__inplace_merge<_AlgPolicy>(__middle, __m2, __last, __comp, __len12, __len22, __buff, __buff_size); + __last = __middle; + __middle = __m1; + __len1 = __len11; + __len2 = __len21; + } + } +} + +template +_LIBCPP_HIDE_FROM_ABI void __inplace_merge( + _BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Compare&& __comp) { + typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type; + typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type; + difference_type __len1 = _IterOps<_AlgPolicy>::distance(__first, __middle); + difference_type __len2 = _IterOps<_AlgPolicy>::distance(__middle, __last); + difference_type __buf_size = std::min(__len1, __len2); + // TODO: Remove the use of std::get_temporary_buffer + _LIBCPP_SUPPRESS_DEPRECATED_PUSH + pair __buf = std::get_temporary_buffer(__buf_size); + _LIBCPP_SUPPRESS_DEPRECATED_POP + unique_ptr __h(__buf.first); + return std::__inplace_merge<_AlgPolicy>( + std::move(__first), std::move(__middle), std::move(__last), __comp, __len1, __len2, __buf.first, __buf.second); +} + +template +inline _LIBCPP_HIDE_FROM_ABI void inplace_merge( + _BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Compare __comp) { + std::__inplace_merge<_ClassicAlgPolicy>( + std::move(__first), std::move(__middle), std::move(__last), static_cast<__comp_ref_type<_Compare> >(__comp)); +} + +template +inline _LIBCPP_HIDE_FROM_ABI void +inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last) { + std::inplace_merge(std::move(__first), std::move(__middle), std::move(__last), __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_INPLACE_MERGE_H diff --git a/libcxx/include/__cxx03/__algorithm/is_heap.h b/libcxx/include/__cxx03/__algorithm/is_heap.h new file mode 100644 index 0000000000000000000000000000000000000000..c589b804a5dc08f3c82fddb6e48be5ef5e7a7ebc --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/is_heap.h @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_IS_HEAP_H +#define _LIBCPP___ALGORITHM_IS_HEAP_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/is_heap_until.h> +#include <__config> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { + return std::__is_heap_until(__first, __last, static_cast<__comp_ref_type<_Compare> >(__comp)) == __last; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) { + return std::is_heap(__first, __last, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_IS_HEAP_H diff --git a/libcxx/include/__cxx03/__algorithm/is_heap_until.h b/libcxx/include/__cxx03/__algorithm/is_heap_until.h new file mode 100644 index 0000000000000000000000000000000000000000..a174f2453cfcc0dc43ae0c3c82d29648fce8cf8f --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/is_heap_until.h @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_IS_HEAP_UNTIL_H +#define _LIBCPP___ALGORITHM_IS_HEAP_UNTIL_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__config> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandomAccessIterator +__is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare&& __comp) { + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; + difference_type __len = __last - __first; + difference_type __p = 0; + difference_type __c = 1; + _RandomAccessIterator __pp = __first; + while (__c < __len) { + _RandomAccessIterator __cp = __first + __c; + if (__comp(*__pp, *__cp)) + return __cp; + ++__c; + ++__cp; + if (__c == __len) + return __last; + if (__comp(*__pp, *__cp)) + return __cp; + ++__p; + ++__pp; + __c = 2 * __p + 1; + } + return __last; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandomAccessIterator +is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { + return std::__is_heap_until(__first, __last, static_cast<__comp_ref_type<_Compare> >(__comp)); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandomAccessIterator +is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last) { + return std::__is_heap_until(__first, __last, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_IS_HEAP_UNTIL_H diff --git a/libcxx/include/__cxx03/__algorithm/is_partitioned.h b/libcxx/include/__cxx03/__algorithm/is_partitioned.h new file mode 100644 index 0000000000000000000000000000000000000000..1f7c8b0b267e75b72b00d6909089e2c127671b11 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/is_partitioned.h @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_IS_PARTITIONED_H +#define _LIBCPP___ALGORITHM_IS_PARTITIONED_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +is_partitioned(_InputIterator __first, _InputIterator __last, _Predicate __pred) { + for (; __first != __last; ++__first) + if (!__pred(*__first)) + break; + if (__first == __last) + return true; + ++__first; + for (; __first != __last; ++__first) + if (__pred(*__first)) + return false; + return true; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_IS_PARTITIONED_H diff --git a/libcxx/include/__cxx03/__algorithm/is_permutation.h b/libcxx/include/__cxx03/__algorithm/is_permutation.h new file mode 100644 index 0000000000000000000000000000000000000000..2ddfb32a212bbb458c89221a8fe484bb8952cb81 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/is_permutation.h @@ -0,0 +1,308 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_IS_PERMUTATION_H +#define _LIBCPP___ALGORITHM_IS_PERMUTATION_H + +#include <__algorithm/comp.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__type_traits/is_callable.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct _ConstTimeDistance : false_type {}; + +#if _LIBCPP_STD_VER >= 20 + +template +struct _ConstTimeDistance<_Iter1, + _Sent1, + _Iter2, + _Sent2, + __enable_if_t< sized_sentinel_for<_Sent1, _Iter1> && sized_sentinel_for<_Sent2, _Iter2> >> + : true_type {}; + +#else + +template +struct _ConstTimeDistance< + _Iter1, + _Iter1, + _Iter2, + _Iter2, + __enable_if_t< is_same::iterator_category, random_access_iterator_tag>::value && + is_same::iterator_category, random_access_iterator_tag>::value > > + : true_type {}; + +#endif // _LIBCPP_STD_VER >= 20 + +// Internal functions + +// For each element in [f1, l1) see if there are the same number of equal elements in [f2, l2) +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation_impl( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred&& __pred, + _Proj1&& __proj1, + _Proj2&& __proj2) { + using _D1 = __iter_diff_t<_Iter1>; + + for (auto __i = __first1; __i != __last1; ++__i) { + // Have we already counted the number of *__i in [f1, l1)? + auto __match = __first1; + for (; __match != __i; ++__match) { + if (std::__invoke(__pred, std::__invoke(__proj1, *__match), std::__invoke(__proj1, *__i))) + break; + } + + if (__match == __i) { + // Count number of *__i in [f2, l2) + _D1 __c2 = 0; + for (auto __j = __first2; __j != __last2; ++__j) { + if (std::__invoke(__pred, std::__invoke(__proj1, *__i), std::__invoke(__proj2, *__j))) + ++__c2; + } + if (__c2 == 0) + return false; + + // Count number of *__i in [__i, l1) (we can start with 1) + _D1 __c1 = 1; + for (auto __j = _IterOps<_AlgPolicy>::next(__i); __j != __last1; ++__j) { + if (std::__invoke(__pred, std::__invoke(__proj1, *__i), std::__invoke(__proj1, *__j))) + ++__c1; + } + if (__c1 != __c2) + return false; + } + } + + return true; +} + +// 2+1 iterators, predicate. Not used by range algorithms. +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation( + _ForwardIterator1 __first1, _Sentinel1 __last1, _ForwardIterator2 __first2, _BinaryPredicate&& __pred) { + // Shorten sequences as much as possible by lopping of any equal prefix. + for (; __first1 != __last1; ++__first1, (void)++__first2) { + if (!__pred(*__first1, *__first2)) + break; + } + + if (__first1 == __last1) + return true; + + // __first1 != __last1 && *__first1 != *__first2 + using _D1 = __iter_diff_t<_ForwardIterator1>; + _D1 __l1 = _IterOps<_AlgPolicy>::distance(__first1, __last1); + if (__l1 == _D1(1)) + return false; + auto __last2 = _IterOps<_AlgPolicy>::next(__first2, __l1); + + return std::__is_permutation_impl<_AlgPolicy>( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + __pred, + __identity(), + __identity()); +} + +// 2+2 iterators, predicate, non-constant time `distance`. +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred&& __pred, + _Proj1&& __proj1, + _Proj2&& __proj2, + /*_ConstTimeDistance=*/false_type) { + // Shorten sequences as much as possible by lopping of any equal prefix. + while (__first1 != __last1 && __first2 != __last2) { + if (!std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) + break; + ++__first1; + ++__first2; + } + + if (__first1 == __last1) + return __first2 == __last2; + if (__first2 == __last2) // Second range is shorter + return false; + + using _D1 = __iter_diff_t<_Iter1>; + _D1 __l1 = _IterOps<_AlgPolicy>::distance(__first1, __last1); + + using _D2 = __iter_diff_t<_Iter2>; + _D2 __l2 = _IterOps<_AlgPolicy>::distance(__first2, __last2); + if (__l1 != __l2) + return false; + + return std::__is_permutation_impl<_AlgPolicy>( + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __pred, __proj1, __proj2); +} + +// 2+2 iterators, predicate, specialization for constant-time `distance` call. +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred&& __pred, + _Proj1&& __proj1, + _Proj2&& __proj2, + /*_ConstTimeDistance=*/true_type) { + if (std::distance(__first1, __last1) != std::distance(__first2, __last2)) + return false; + return std::__is_permutation<_AlgPolicy>( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + __pred, + __proj1, + __proj2, + /*_ConstTimeDistance=*/false_type()); +} + +// 2+2 iterators, predicate +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred&& __pred, + _Proj1&& __proj1, + _Proj2&& __proj2) { + return std::__is_permutation<_AlgPolicy>( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + __pred, + __proj1, + __proj2, + _ConstTimeDistance<_Iter1, _Sent1, _Iter2, _Sent2>()); +} + +// Public interface + +// 2+1 iterators, predicate +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool is_permutation( + _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _BinaryPredicate __pred) { + static_assert(__is_callable<_BinaryPredicate, decltype(*__first1), decltype(*__first2)>::value, + "The predicate has to be callable"); + + return std::__is_permutation<_ClassicAlgPolicy>(std::move(__first1), std::move(__last1), std::move(__first2), __pred); +} + +// 2+1 iterators +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) { + return std::is_permutation(__first1, __last1, __first2, __equal_to()); +} + +#if _LIBCPP_STD_VER >= 14 + +// 2+2 iterators +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool is_permutation( + _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2) { + return std::__is_permutation<_ClassicAlgPolicy>( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + __equal_to(), + __identity(), + __identity()); +} + +// 2+2 iterators, predicate +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool is_permutation( + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2, + _BinaryPredicate __pred) { + static_assert(__is_callable<_BinaryPredicate, decltype(*__first1), decltype(*__first2)>::value, + "The predicate has to be callable"); + + return std::__is_permutation<_ClassicAlgPolicy>( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + __pred, + __identity(), + __identity()); +} + +#endif // _LIBCPP_STD_VER >= 14 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_IS_PERMUTATION_H diff --git a/libcxx/include/__cxx03/__algorithm/is_sorted.h b/libcxx/include/__cxx03/__algorithm/is_sorted.h new file mode 100644 index 0000000000000000000000000000000000000000..3befb1ac9c26a691f89aaa6143597e196fcf1882 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/is_sorted.h @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_IS_SORTED_H +#define _LIBCPP___ALGORITHM_IS_SORTED_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/is_sorted_until.h> +#include <__config> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +is_sorted(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp) { + return std::__is_sorted_until<__comp_ref_type<_Compare> >(__first, __last, __comp) == __last; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +is_sorted(_ForwardIterator __first, _ForwardIterator __last) { + return std::is_sorted(__first, __last, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_IS_SORTED_H diff --git a/libcxx/include/__cxx03/__algorithm/is_sorted_until.h b/libcxx/include/__cxx03/__algorithm/is_sorted_until.h new file mode 100644 index 0000000000000000000000000000000000000000..53a49f00de31e8536a828fc1825c7c94effc2042 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/is_sorted_until.h @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_IS_SORTED_UNTIL_H +#define _LIBCPP___ALGORITHM_IS_SORTED_UNTIL_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__config> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +__is_sorted_until(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp) { + if (__first != __last) { + _ForwardIterator __i = __first; + while (++__i != __last) { + if (__comp(*__i, *__first)) + return __i; + __first = __i; + } + } + return __last; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +is_sorted_until(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp) { + return std::__is_sorted_until<__comp_ref_type<_Compare> >(__first, __last, __comp); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +is_sorted_until(_ForwardIterator __first, _ForwardIterator __last) { + return std::is_sorted_until(__first, __last, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_IS_SORTED_UNTIL_H diff --git a/libcxx/include/__cxx03/__algorithm/iter_swap.h b/libcxx/include/__cxx03/__algorithm/iter_swap.h new file mode 100644 index 0000000000000000000000000000000000000000..a1412e5d8720bedd45c6d79508507f2ae993b592 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/iter_swap.h @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_ITER_SWAP_H +#define _LIBCPP___ALGORITHM_ITER_SWAP_H + +#include <__config> +#include <__utility/declval.h> +#include <__utility/swap.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void iter_swap(_ForwardIterator1 __a, _ForwardIterator2 __b) + // _NOEXCEPT_(_NOEXCEPT_(swap(*__a, *__b))) + _NOEXCEPT_(_NOEXCEPT_(swap(*std::declval<_ForwardIterator1>(), *std::declval<_ForwardIterator2>()))) { + swap(*__a, *__b); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_ITER_SWAP_H diff --git a/libcxx/include/__cxx03/__algorithm/iterator_operations.h b/libcxx/include/__cxx03/__algorithm/iterator_operations.h new file mode 100644 index 0000000000000000000000000000000000000000..8ced989233bc4890136b5d3ef01f7c3f85e1dc2a --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/iterator_operations.h @@ -0,0 +1,223 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H +#define _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H + +#include <__algorithm/iter_swap.h> +#include <__algorithm/ranges_iterator_concept.h> +#include <__assert> +#include <__config> +#include <__iterator/advance.h> +#include <__iterator/distance.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iter_move.h> +#include <__iterator/iter_swap.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/prev.h> +#include <__iterator/readable_traits.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/is_same.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/declval.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct _IterOps; + +#if _LIBCPP_STD_VER >= 20 +struct _RangeAlgPolicy {}; + +template <> +struct _IterOps<_RangeAlgPolicy> { + template + using __value_type = iter_value_t<_Iter>; + + template + using __iterator_category = ranges::__iterator_concept<_Iter>; + + template + using __difference_type = iter_difference_t<_Iter>; + + static constexpr auto advance = ranges::advance; + static constexpr auto distance = ranges::distance; + static constexpr auto __iter_move = ranges::iter_move; + static constexpr auto iter_swap = ranges::iter_swap; + static constexpr auto next = ranges::next; + static constexpr auto prev = ranges::prev; + static constexpr auto __advance_to = ranges::advance; +}; + +#endif + +struct _ClassicAlgPolicy {}; + +template <> +struct _IterOps<_ClassicAlgPolicy> { + template + using __value_type = typename iterator_traits<_Iter>::value_type; + + template + using __iterator_category = typename iterator_traits<_Iter>::iterator_category; + + template + using __difference_type = typename iterator_traits<_Iter>::difference_type; + + // advance + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static void advance(_Iter& __iter, _Distance __count) { + std::advance(__iter, __count); + } + + // distance + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static typename iterator_traits<_Iter>::difference_type + distance(_Iter __first, _Iter __last) { + return std::distance(__first, __last); + } + + template + using __deref_t = decltype(*std::declval<_Iter&>()); + + template + using __move_t = decltype(std::move(*std::declval<_Iter&>())); + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static void __validate_iter_reference() { + static_assert( + is_same<__deref_t<_Iter>, typename iterator_traits<__remove_cvref_t<_Iter> >::reference>::value, + "It looks like your iterator's `iterator_traits::reference` does not match the return type of " + "dereferencing the iterator, i.e., calling `*it`. This is undefined behavior according to [input.iterators] " + "and can lead to dangling reference issues at runtime, so we are flagging this."); + } + + // iter_move + template >::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static + // If the result of dereferencing `_Iter` is a reference type, deduce the result of calling `std::move` on it. + // Note that the C++03 mode doesn't support `decltype(auto)` as the return type. + __move_t<_Iter> + __iter_move(_Iter&& __i) { + __validate_iter_reference<_Iter>(); + + return std::move(*std::forward<_Iter>(__i)); + } + + template >::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static + // If the result of dereferencing `_Iter` is a value type, deduce the return value of this function to also be a + // value -- otherwise, after `operator*` returns a temporary, this function would return a dangling reference to + // that temporary. Note that the C++03 mode doesn't support `auto` as the return type. + __deref_t<_Iter> + __iter_move(_Iter&& __i) { + __validate_iter_reference<_Iter>(); + + return *std::forward<_Iter>(__i); + } + + // iter_swap + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static void iter_swap(_Iter1&& __a, _Iter2&& __b) { + std::iter_swap(std::forward<_Iter1>(__a), std::forward<_Iter2>(__b)); + } + + // next + template + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 _Iterator next(_Iterator, _Iterator __last) { + return __last; + } + + template + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 __remove_cvref_t<_Iter> + next(_Iter&& __it, typename iterator_traits<__remove_cvref_t<_Iter> >::difference_type __n = 1) { + return std::next(std::forward<_Iter>(__it), __n); + } + + // prev + template + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 __remove_cvref_t<_Iter> + prev(_Iter&& __iter, typename iterator_traits<__remove_cvref_t<_Iter> >::difference_type __n = 1) { + return std::prev(std::forward<_Iter>(__iter), __n); + } + + template + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 void __advance_to(_Iter& __first, _Iter __last) { + __first = __last; + } + + // advance with sentinel, a la std::ranges::advance + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_Iter> + __advance_to(_Iter& __iter, __difference_type<_Iter> __count, const _Iter& __sentinel) { + return _IterOps::__advance_to(__iter, __count, __sentinel, typename iterator_traits<_Iter>::iterator_category()); + } + +private: + // advance with sentinel, a la std::ranges::advance -- InputIterator specialization + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_InputIter> __advance_to( + _InputIter& __iter, __difference_type<_InputIter> __count, const _InputIter& __sentinel, input_iterator_tag) { + __difference_type<_InputIter> __dist = 0; + for (; __dist < __count && __iter != __sentinel; ++__dist) + ++__iter; + return __count - __dist; + } + + // advance with sentinel, a la std::ranges::advance -- BidirectionalIterator specialization + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_BiDirIter> + __advance_to(_BiDirIter& __iter, + __difference_type<_BiDirIter> __count, + const _BiDirIter& __sentinel, + bidirectional_iterator_tag) { + __difference_type<_BiDirIter> __dist = 0; + if (__count >= 0) + for (; __dist < __count && __iter != __sentinel; ++__dist) + ++__iter; + else + for (__count = -__count; __dist < __count && __iter != __sentinel; ++__dist) + --__iter; + return __count - __dist; + } + + // advance with sentinel, a la std::ranges::advance -- RandomIterator specialization + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static __difference_type<_RandIter> + __advance_to(_RandIter& __iter, + __difference_type<_RandIter> __count, + const _RandIter& __sentinel, + random_access_iterator_tag) { + auto __dist = _IterOps::distance(__iter, __sentinel); + _LIBCPP_ASSERT_VALID_INPUT_RANGE( + __count == 0 || (__dist < 0) == (__count < 0), "__sentinel must precede __iter when __count < 0"); + if (__count < 0) + __dist = __dist > __count ? __dist : __count; + else + __dist = __dist < __count ? __dist : __count; + __iter += __dist; + return __count - __dist; + } +}; + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_ITERATOR_OPERATIONS_H diff --git a/libcxx/include/__cxx03/__algorithm/lexicographical_compare.h b/libcxx/include/__cxx03/__algorithm/lexicographical_compare.h new file mode 100644 index 0000000000000000000000000000000000000000..edc29e269c88cab309b97c2ef625948fca301eb5 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/lexicographical_compare.h @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_LEXICOGRAPHICAL_COMPARE_H +#define _LIBCPP___ALGORITHM_LEXICOGRAPHICAL_COMPARE_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__config> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __lexicographical_compare( + _InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _Compare __comp) { + for (; __first2 != __last2; ++__first1, (void)++__first2) { + if (__first1 == __last1 || __comp(*__first1, *__first2)) + return true; + if (__comp(*__first2, *__first1)) + return false; + } + return false; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool lexicographical_compare( + _InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _Compare __comp) { + return std::__lexicographical_compare<__comp_ref_type<_Compare> >(__first1, __last1, __first2, __last2, __comp); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool lexicographical_compare( + _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2) { + return std::lexicographical_compare(__first1, __last1, __first2, __last2, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_LEXICOGRAPHICAL_COMPARE_H diff --git a/libcxx/include/__cxx03/__algorithm/lexicographical_compare_three_way.h b/libcxx/include/__cxx03/__algorithm/lexicographical_compare_three_way.h new file mode 100644 index 0000000000000000000000000000000000000000..a5872e90cf8d2960655c953fe486bcce16dc8ee2 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/lexicographical_compare_three_way.h @@ -0,0 +1,125 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_LEXICOGRAPHICAL_COMPARE_THREE_WAY_H +#define _LIBCPP___ALGORITHM_LEXICOGRAPHICAL_COMPARE_THREE_WAY_H + +#include <__algorithm/min.h> +#include <__algorithm/three_way_comp_ref_type.h> +#include <__compare/compare_three_way.h> +#include <__compare/ordering.h> +#include <__concepts/arithmetic.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__type_traits/common_type.h> +#include <__type_traits/is_constructible.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// Fast path for random access iterators which computes the number of loop iterations up-front and +// then skips the iterator comparisons inside the loop. +template +_LIBCPP_HIDE_FROM_ABI constexpr auto __lexicographical_compare_three_way_fast_path( + _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _Cmp& __comp) + -> decltype(__comp(*__first1, *__first2)) { + static_assert( + signed_integral<__iter_diff_t<_InputIterator1>>, "Using a non-integral difference_type is undefined behavior."); + static_assert( + signed_integral<__iter_diff_t<_InputIterator2>>, "Using a non-integral difference_type is undefined behavior."); + + using _Len1 = __iter_diff_t<_InputIterator1>; + using _Len2 = __iter_diff_t<_InputIterator2>; + using _Common = common_type_t<_Len1, _Len2>; + + _Len1 __len1 = __last1 - __first1; + _Len2 __len2 = __last2 - __first2; + _Common __min_len = std::min<_Common>(__len1, __len2); + + for (_Common __i = 0; __i < __min_len; ++__i) { + auto __c = __comp(*__first1, *__first2); + if (__c != 0) { + return __c; + } + ++__first1; + ++__first2; + } + + return __len1 <=> __len2; +} + +// Unoptimized implementation which compares the iterators against the end in every loop iteration +template +_LIBCPP_HIDE_FROM_ABI constexpr auto __lexicographical_compare_three_way_slow_path( + _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _Cmp& __comp) + -> decltype(__comp(*__first1, *__first2)) { + while (true) { + bool __exhausted1 = __first1 == __last1; + bool __exhausted2 = __first2 == __last2; + + if (__exhausted1 || __exhausted2) { + if (!__exhausted1) + return strong_ordering::greater; + if (!__exhausted2) + return strong_ordering::less; + return strong_ordering::equal; + } + + auto __c = __comp(*__first1, *__first2); + if (__c != 0) { + return __c; + } + + ++__first1; + ++__first2; + } +} + +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto lexicographical_compare_three_way( + _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _Cmp __comp) + -> decltype(__comp(*__first1, *__first2)) { + static_assert(__comparison_category, + "The comparator passed to lexicographical_compare_three_way must return a comparison category type."); + static_assert(std::is_copy_constructible_v<_InputIterator1>, "Iterators must be copy constructible."); + static_assert(std::is_copy_constructible_v<_InputIterator2>, "Iterators must be copy constructible."); + __three_way_comp_ref_type<_Cmp> __wrapped_comp_ref(__comp); + if constexpr (__has_random_access_iterator_category<_InputIterator1>::value && + __has_random_access_iterator_category<_InputIterator2>::value) { + return std::__lexicographical_compare_three_way_fast_path( + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __wrapped_comp_ref); + } else { + // Unoptimized implementation which compares the iterators against the end in every loop iteration + return std::__lexicographical_compare_three_way_slow_path( + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __wrapped_comp_ref); + } +} + +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto lexicographical_compare_three_way( + _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2) { + return std::lexicographical_compare_three_way( + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::compare_three_way()); +} + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_LEXICOGRAPHICAL_COMPARE_THREE_WAY_H diff --git a/libcxx/include/__cxx03/__algorithm/lower_bound.h b/libcxx/include/__cxx03/__algorithm/lower_bound.h new file mode 100644 index 0000000000000000000000000000000000000000..c417d84835497dc191b1220c7ed0ae41d6160352 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/lower_bound.h @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_LOWER_BOUND_H +#define _LIBCPP___ALGORITHM_LOWER_BOUND_H + +#include <__algorithm/comp.h> +#include <__algorithm/half_positive.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/advance.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_callable.h> +#include <__type_traits/remove_reference.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter __lower_bound_bisecting( + _Iter __first, + const _Type& __value, + typename iterator_traits<_Iter>::difference_type __len, + _Comp& __comp, + _Proj& __proj) { + while (__len != 0) { + auto __l2 = std::__half_positive(__len); + _Iter __m = __first; + _IterOps<_AlgPolicy>::advance(__m, __l2); + if (std::__invoke(__comp, std::__invoke(__proj, *__m), __value)) { + __first = ++__m; + __len -= __l2 + 1; + } else { + __len = __l2; + } + } + return __first; +} + +// One-sided binary search, aka meta binary search, has been in the public domain for decades, and has the general +// advantage of being \Omega(1) rather than the classic algorithm's \Omega(log(n)), with the downside of executing at +// most 2*log(n) comparisons vs the classic algorithm's exact log(n). There are two scenarios in which it really shines: +// the first one is when operating over non-random-access iterators, because the classic algorithm requires knowing the +// container's size upfront, which adds \Omega(n) iterator increments to the complexity. The second one is when you're +// traversing the container in order, trying to fast-forward to the next value: in that case, the classic algorithm +// would yield \Omega(n*log(n)) comparisons and, for non-random-access iterators, \Omega(n^2) iterator increments, +// whereas the one-sided version will yield O(n) operations on both counts, with a \Omega(log(n)) bound on the number of +// comparisons. +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +__lower_bound_onesided(_ForwardIterator __first, _Sent __last, const _Type& __value, _Comp& __comp, _Proj& __proj) { + // step = 0, ensuring we can always short-circuit when distance is 1 later on + if (__first == __last || !std::__invoke(__comp, std::__invoke(__proj, *__first), __value)) + return __first; + + using _Distance = typename iterator_traits<_ForwardIterator>::difference_type; + for (_Distance __step = 1; __first != __last; __step <<= 1) { + auto __it = __first; + auto __dist = __step - _IterOps<_AlgPolicy>::__advance_to(__it, __step, __last); + // once we reach the last range where needle can be we must start + // looking inwards, bisecting that range + if (__it == __last || !std::__invoke(__comp, std::__invoke(__proj, *__it), __value)) { + // we've already checked the previous value and it was less, we can save + // one comparison by skipping bisection + if (__dist == 1) + return __it; + return std::__lower_bound_bisecting<_AlgPolicy>(__first, __value, __dist, __comp, __proj); + } + // range not found, move forward! + __first = __it; + } + return __first; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +__lower_bound(_ForwardIterator __first, _Sent __last, const _Type& __value, _Comp& __comp, _Proj& __proj) { + const auto __dist = _IterOps<_AlgPolicy>::distance(__first, __last); + return std::__lower_bound_bisecting<_AlgPolicy>(__first, __value, __dist, __comp, __proj); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +lower_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, _Compare __comp) { + static_assert(__is_callable<_Compare, decltype(*__first), const _Tp&>::value, "The comparator has to be callable"); + auto __proj = std::__identity(); + return std::__lower_bound<_ClassicAlgPolicy>(__first, __last, __value, __comp, __proj); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +lower_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + return std::lower_bound(__first, __last, __value, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_LOWER_BOUND_H diff --git a/libcxx/include/__cxx03/__algorithm/make_heap.h b/libcxx/include/__cxx03/__algorithm/make_heap.h new file mode 100644 index 0000000000000000000000000000000000000000..e8f0cdb27333a44b1ac9e0185c917db8d01f3d56 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/make_heap.h @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_MAKE_HEAP_H +#define _LIBCPP___ALGORITHM_MAKE_HEAP_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/sift_down.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void +__make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare&& __comp) { + __comp_ref_type<_Compare> __comp_ref = __comp; + + using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type; + difference_type __n = __last - __first; + if (__n > 1) { + // start from the first parent, there is no need to consider children + for (difference_type __start = (__n - 2) / 2; __start >= 0; --__start) { + std::__sift_down<_AlgPolicy>(__first, __comp_ref, __n, __first + __start); + } + } +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { + std::__make_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) { + std::make_heap(std::move(__first), std::move(__last), __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_MAKE_HEAP_H diff --git a/libcxx/include/__cxx03/__algorithm/make_projected.h b/libcxx/include/__cxx03/__algorithm/make_projected.h new file mode 100644 index 0000000000000000000000000000000000000000..5245e523f3df2112d6461ba63aa7ca6bacbf509d --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/make_projected.h @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_MAKE_PROJECTED_H +#define _LIBCPP___ALGORITHM_MAKE_PROJECTED_H + +#include <__concepts/same_as.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__type_traits/decay.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_member_pointer.h> +#include <__type_traits/is_same.h> +#include <__utility/declval.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct _ProjectedPred { + _Pred& __pred; // Can be a unary or a binary predicate. + _Proj& __proj; + + _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI _ProjectedPred(_Pred& __pred_arg, _Proj& __proj_arg) + : __pred(__pred_arg), __proj(__proj_arg) {} + + template + typename __invoke_of<_Pred&, decltype(std::__invoke(std::declval<_Proj&>(), std::declval<_Tp>()))>::type + _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI + operator()(_Tp&& __v) const { + return std::__invoke(__pred, std::__invoke(__proj, std::forward<_Tp>(__v))); + } + + template + typename __invoke_of<_Pred&, + decltype(std::__invoke(std::declval<_Proj&>(), std::declval<_T1>())), + decltype(std::__invoke(std::declval<_Proj&>(), std::declval<_T2>()))>::type _LIBCPP_CONSTEXPR + _LIBCPP_HIDE_FROM_ABI + operator()(_T1&& __lhs, _T2&& __rhs) const { + return std::__invoke( + __pred, std::__invoke(__proj, std::forward<_T1>(__lhs)), std::__invoke(__proj, std::forward<_T2>(__rhs))); + } +}; + +template < + class _Pred, + class _Proj, + __enable_if_t >::value && __is_identity<__decay_t<_Proj> >::value), int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ProjectedPred<_Pred, _Proj> __make_projected(_Pred& __pred, _Proj& __proj) { + return _ProjectedPred<_Pred, _Proj>(__pred, __proj); +} + +// Avoid creating the functor and just use the pristine comparator -- for certain algorithms, this would enable +// optimizations that rely on the type of the comparator. Additionally, this results in less layers of indirection in +// the call stack when the comparator is invoked, even in an unoptimized build. +template < + class _Pred, + class _Proj, + __enable_if_t >::value && __is_identity<__decay_t<_Proj> >::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Pred& __make_projected(_Pred& __pred, _Proj&) { + return __pred; +} + +_LIBCPP_END_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) __make_projected_comp(_Comp& __comp, _Proj1& __proj1, _Proj2& __proj2) { + if constexpr (__is_identity>::value && __is_identity>::value && + !is_member_pointer_v>) { + // Avoid creating the lambda and just use the pristine comparator -- for certain algorithms, this would enable + // optimizations that rely on the type of the comparator. + return __comp; + + } else { + return [&](auto&& __lhs, auto&& __rhs) -> bool { + return std::invoke(__comp, + std::invoke(__proj1, std::forward(__lhs)), + std::invoke(__proj2, std::forward(__rhs))); + }; + } +} + +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___ALGORITHM_MAKE_PROJECTED_H diff --git a/libcxx/include/__cxx03/__algorithm/max.h b/libcxx/include/__cxx03/__algorithm/max.h new file mode 100644 index 0000000000000000000000000000000000000000..d4c99f6f364367410f83c8ca32f51d4ddb4cef63 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/max.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_MAX_H +#define _LIBCPP___ALGORITHM_MAX_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/max_element.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp& +max(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b, _Compare __comp) { + return __comp(__a, __b) ? __b : __a; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp& +max(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b) { + return std::max(__a, __b, __less<>()); +} + +#ifndef _LIBCPP_CXX03_LANG + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp +max(initializer_list<_Tp> __t, _Compare __comp) { + return *std::__max_element<__comp_ref_type<_Compare> >(__t.begin(), __t.end(), __comp); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp max(initializer_list<_Tp> __t) { + return *std::max_element(__t.begin(), __t.end(), __less<>()); +} + +#endif // _LIBCPP_CXX03_LANG + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_MAX_H diff --git a/libcxx/include/__cxx03/__algorithm/max_element.h b/libcxx/include/__cxx03/__algorithm/max_element.h new file mode 100644 index 0000000000000000000000000000000000000000..c036726cbccd8bca3337c0dfffcd69482b4106d3 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/max_element.h @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_MAX_ELEMENT_H +#define _LIBCPP___ALGORITHM_MAX_ELEMENT_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__config> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator +__max_element(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp) { + static_assert( + __has_forward_iterator_category<_ForwardIterator>::value, "std::max_element requires a ForwardIterator"); + if (__first != __last) { + _ForwardIterator __i = __first; + while (++__i != __last) + if (__comp(*__first, *__i)) + __first = __i; + } + return __first; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator +max_element(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp) { + return std::__max_element<__comp_ref_type<_Compare> >(__first, __last, __comp); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator +max_element(_ForwardIterator __first, _ForwardIterator __last) { + return std::max_element(__first, __last, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_MAX_ELEMENT_H diff --git a/libcxx/include/__cxx03/__algorithm/merge.h b/libcxx/include/__cxx03/__algorithm/merge.h new file mode 100644 index 0000000000000000000000000000000000000000..bad663c4b9f1024805c71ede00db864526466a24 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/merge.h @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_MERGE_H +#define _LIBCPP___ALGORITHM_MERGE_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/copy.h> +#include <__config> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator __merge( + _InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _OutputIterator __result, + _Compare __comp) { + for (; __first1 != __last1; ++__result) { + if (__first2 == __last2) + return std::copy(__first1, __last1, __result); + if (__comp(*__first2, *__first1)) { + *__result = *__first2; + ++__first2; + } else { + *__result = *__first1; + ++__first1; + } + } + return std::copy(__first2, __last2, __result); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +merge(_InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _OutputIterator __result, + _Compare __comp) { + return std::__merge<__comp_ref_type<_Compare> >(__first1, __last1, __first2, __last2, __result, __comp); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +merge(_InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _OutputIterator __result) { + return std::merge(__first1, __last1, __first2, __last2, __result, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_MERGE_H diff --git a/libcxx/include/__cxx03/__algorithm/min.h b/libcxx/include/__cxx03/__algorithm/min.h new file mode 100644 index 0000000000000000000000000000000000000000..1bafad8a461eb93d1d6a2f2a493fe99019861715 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/min.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_MIN_H +#define _LIBCPP___ALGORITHM_MIN_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/min_element.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp& +min(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b, _Compare __comp) { + return __comp(__b, __a) ? __b : __a; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp& +min(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b) { + return std::min(__a, __b, __less<>()); +} + +#ifndef _LIBCPP_CXX03_LANG + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp +min(initializer_list<_Tp> __t, _Compare __comp) { + return *std::__min_element<__comp_ref_type<_Compare> >(__t.begin(), __t.end(), __comp); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp min(initializer_list<_Tp> __t) { + return *std::min_element(__t.begin(), __t.end(), __less<>()); +} + +#endif // _LIBCPP_CXX03_LANG + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_MIN_H diff --git a/libcxx/include/__cxx03/__algorithm/min_element.h b/libcxx/include/__cxx03/__algorithm/min_element.h new file mode 100644 index 0000000000000000000000000000000000000000..65f3594d630cef822b3552d2a182e1de8aa471df --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/min_element.h @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_MIN_ELEMENT_H +#define _LIBCPP___ALGORITHM_MIN_ELEMENT_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_callable.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Iter +__min_element(_Iter __first, _Sent __last, _Comp __comp, _Proj& __proj) { + if (__first == __last) + return __first; + + _Iter __i = __first; + while (++__i != __last) + if (std::__invoke(__comp, std::__invoke(__proj, *__i), std::__invoke(__proj, *__first))) + __first = __i; + + return __first; +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Iter __min_element(_Iter __first, _Sent __last, _Comp __comp) { + auto __proj = __identity(); + return std::__min_element<_Comp>(std::move(__first), std::move(__last), __comp, __proj); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator +min_element(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp) { + static_assert( + __has_forward_iterator_category<_ForwardIterator>::value, "std::min_element requires a ForwardIterator"); + static_assert( + __is_callable<_Compare, decltype(*__first), decltype(*__first)>::value, "The comparator has to be callable"); + + return std::__min_element<__comp_ref_type<_Compare> >(std::move(__first), std::move(__last), __comp); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator +min_element(_ForwardIterator __first, _ForwardIterator __last) { + return std::min_element(__first, __last, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_MIN_ELEMENT_H diff --git a/libcxx/include/__cxx03/__algorithm/min_max_result.h b/libcxx/include/__cxx03/__algorithm/min_max_result.h new file mode 100644 index 0000000000000000000000000000000000000000..e988df7c114ee5baaa91696690a77511c66405ae --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/min_max_result.h @@ -0,0 +1,56 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_MIN_MAX_RESULT_H +#define _LIBCPP___ALGORITHM_MIN_MAX_RESULT_H + +#include <__concepts/convertible_to.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace ranges { + +template +struct min_max_result { + _LIBCPP_NO_UNIQUE_ADDRESS _T1 min; + _LIBCPP_NO_UNIQUE_ADDRESS _T1 max; + + template + requires convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr operator min_max_result<_T2>() const& { + return {min, max}; + } + + template + requires convertible_to<_T1, _T2> + _LIBCPP_HIDE_FROM_ABI constexpr operator min_max_result<_T2>() && { + return {std::move(min), std::move(max)}; + } +}; + +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_MIN_MAX_RESULT_H diff --git a/libcxx/include/__cxx03/__algorithm/minmax.h b/libcxx/include/__cxx03/__algorithm/minmax.h new file mode 100644 index 0000000000000000000000000000000000000000..9feda2b4c0da90f16ac6ae86f208595158ae80d3 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/minmax.h @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_MINMAX_H +#define _LIBCPP___ALGORITHM_MINMAX_H + +#include <__algorithm/comp.h> +#include <__algorithm/minmax_element.h> +#include <__config> +#include <__functional/identity.h> +#include <__type_traits/is_callable.h> +#include <__utility/pair.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair +minmax(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b, _Compare __comp) { + return __comp(__b, __a) ? pair(__b, __a) : pair(__a, __b); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair +minmax(_LIBCPP_LIFETIMEBOUND const _Tp& __a, _LIBCPP_LIFETIMEBOUND const _Tp& __b) { + return std::minmax(__a, __b, __less<>()); +} + +#ifndef _LIBCPP_CXX03_LANG + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Tp, _Tp> +minmax(initializer_list<_Tp> __t, _Compare __comp) { + static_assert(__is_callable<_Compare, _Tp, _Tp>::value, "The comparator has to be callable"); + __identity __proj; + auto __ret = std::__minmax_element_impl(__t.begin(), __t.end(), __comp, __proj); + return pair<_Tp, _Tp>(*__ret.first, *__ret.second); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Tp, _Tp> +minmax(initializer_list<_Tp> __t) { + return std::minmax(__t, __less<>()); +} + +#endif // _LIBCPP_CXX03_LANG + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_MINMAX_H diff --git a/libcxx/include/__cxx03/__algorithm/minmax_element.h b/libcxx/include/__cxx03/__algorithm/minmax_element.h new file mode 100644 index 0000000000000000000000000000000000000000..43cb23347c3465955984f197da4065a2a03a57a2 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/minmax_element.h @@ -0,0 +1,100 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_MINMAX_ELEMENT_H +#define _LIBCPP___ALGORITHM_MINMAX_ELEMENT_H + +#include <__algorithm/comp.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_callable.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class _MinmaxElementLessFunc { + _Comp& __comp_; + _Proj& __proj_; + +public: + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _MinmaxElementLessFunc(_Comp& __comp, _Proj& __proj) + : __comp_(__comp), __proj_(__proj) {} + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator()(_Iter& __it1, _Iter& __it2) { + return std::__invoke(__comp_, std::__invoke(__proj_, *__it1), std::__invoke(__proj_, *__it2)); + } +}; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter, _Iter> +__minmax_element_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) { + auto __less = _MinmaxElementLessFunc<_Comp, _Proj>(__comp, __proj); + + pair<_Iter, _Iter> __result(__first, __first); + if (__first == __last || ++__first == __last) + return __result; + + if (__less(__first, __result.first)) + __result.first = __first; + else + __result.second = __first; + + while (++__first != __last) { + _Iter __i = __first; + if (++__first == __last) { + if (__less(__i, __result.first)) + __result.first = __i; + else if (!__less(__i, __result.second)) + __result.second = __i; + return __result; + } + + if (__less(__first, __i)) { + if (__less(__first, __result.first)) + __result.first = __first; + if (!__less(__i, __result.second)) + __result.second = __i; + } else { + if (__less(__i, __result.first)) + __result.first = __i; + if (!__less(__first, __result.second)) + __result.second = __first; + } + } + + return __result; +} + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_ForwardIterator, _ForwardIterator> +minmax_element(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp) { + static_assert( + __has_forward_iterator_category<_ForwardIterator>::value, "std::minmax_element requires a ForwardIterator"); + static_assert( + __is_callable<_Compare, decltype(*__first), decltype(*__first)>::value, "The comparator has to be callable"); + auto __proj = __identity(); + return std::__minmax_element_impl(__first, __last, __comp, __proj); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_ForwardIterator, _ForwardIterator> +minmax_element(_ForwardIterator __first, _ForwardIterator __last) { + return std::minmax_element(__first, __last, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_MINMAX_ELEMENT_H diff --git a/libcxx/include/__cxx03/__algorithm/mismatch.h b/libcxx/include/__cxx03/__algorithm/mismatch.h new file mode 100644 index 0000000000000000000000000000000000000000..632bec02406a418cdcd7f706395f500e02710687 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/mismatch.h @@ -0,0 +1,217 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_MISMATCH_H +#define _LIBCPP___ALGORITHM_MISMATCH_H + +#include <__algorithm/comp.h> +#include <__algorithm/min.h> +#include <__algorithm/simd_utils.h> +#include <__algorithm/unwrap_iter.h> +#include <__config> +#include <__functional/identity.h> +#include <__iterator/aliasing_iterator.h> +#include <__type_traits/desugars_to.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_equality_comparable.h> +#include <__type_traits/is_integral.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include <__utility/unreachable.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Iter1, _Iter2> +__mismatch_loop(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { + while (__first1 != __last1) { + if (!std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) + break; + ++__first1; + ++__first2; + } + return std::make_pair(std::move(__first1), std::move(__first2)); +} + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Iter1, _Iter2> +__mismatch(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { + return std::__mismatch_loop(__first1, __last1, __first2, __pred, __proj1, __proj2); +} + +#if _LIBCPP_VECTORIZE_ALGORITHMS + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Iter, _Iter> +__mismatch_vectorized(_Iter __first1, _Iter __last1, _Iter __first2) { + using __value_type = __iter_value_type<_Iter>; + constexpr size_t __unroll_count = 4; + constexpr size_t __vec_size = __native_vector_size<__value_type>; + using __vec = __simd_vector<__value_type, __vec_size>; + + if (!__libcpp_is_constant_evaluated()) { + auto __orig_first1 = __first1; + auto __last2 = __first2 + (__last1 - __first1); + while (static_cast(__last1 - __first1) >= __unroll_count * __vec_size) [[__unlikely__]] { + __vec __lhs[__unroll_count]; + __vec __rhs[__unroll_count]; + + for (size_t __i = 0; __i != __unroll_count; ++__i) { + __lhs[__i] = std::__load_vector<__vec>(__first1 + __i * __vec_size); + __rhs[__i] = std::__load_vector<__vec>(__first2 + __i * __vec_size); + } + + for (size_t __i = 0; __i != __unroll_count; ++__i) { + if (auto __cmp_res = __lhs[__i] == __rhs[__i]; !std::__all_of(__cmp_res)) { + auto __offset = __i * __vec_size + std::__find_first_not_set(__cmp_res); + return {__first1 + __offset, __first2 + __offset}; + } + } + + __first1 += __unroll_count * __vec_size; + __first2 += __unroll_count * __vec_size; + } + + // check the remaining 0-3 vectors + while (static_cast(__last1 - __first1) >= __vec_size) { + if (auto __cmp_res = std::__load_vector<__vec>(__first1) == std::__load_vector<__vec>(__first2); + !std::__all_of(__cmp_res)) { + auto __offset = std::__find_first_not_set(__cmp_res); + return {__first1 + __offset, __first2 + __offset}; + } + __first1 += __vec_size; + __first2 += __vec_size; + } + + if (__last1 - __first1 == 0) + return {__first1, __first2}; + + // Check if we can load elements in front of the current pointer. If that's the case load a vector at + // (last - vector_size) to check the remaining elements + if (static_cast(__first1 - __orig_first1) >= __vec_size) { + __first1 = __last1 - __vec_size; + __first2 = __last2 - __vec_size; + auto __offset = + std::__find_first_not_set(std::__load_vector<__vec>(__first1) == std::__load_vector<__vec>(__first2)); + return {__first1 + __offset, __first2 + __offset}; + } // else loop over the elements individually + } + + __equal_to __pred; + __identity __proj; + return std::__mismatch_loop(__first1, __last1, __first2, __pred, __proj, __proj); +} + +template ::value && __desugars_to_v<__equal_tag, _Pred, _Tp, _Tp> && + __is_identity<_Proj1>::value && __is_identity<_Proj2>::value, + int> = 0> +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Tp*, _Tp*> +__mismatch(_Tp* __first1, _Tp* __last1, _Tp* __first2, _Pred&, _Proj1&, _Proj2&) { + return std::__mismatch_vectorized(__first1, __last1, __first2); +} + +template ::value && __desugars_to_v<__equal_tag, _Pred, _Tp, _Tp> && + __is_identity<_Proj1>::value && __is_identity<_Proj2>::value && + __can_map_to_integer_v<_Tp> && __libcpp_is_trivially_equality_comparable<_Tp, _Tp>::value, + int> = 0> +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Tp*, _Tp*> +__mismatch(_Tp* __first1, _Tp* __last1, _Tp* __first2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { + if (__libcpp_is_constant_evaluated()) { + return std::__mismatch_loop(__first1, __last1, __first2, __pred, __proj1, __proj2); + } else { + using _Iter = __aliasing_iterator<_Tp*, __get_as_integer_type_t<_Tp>>; + auto __ret = std::__mismatch_vectorized(_Iter(__first1), _Iter(__last1), _Iter(__first2)); + return {__ret.first.__base(), __ret.second.__base()}; + } +} +#endif // _LIBCPP_VECTORIZE_ALGORITHMS + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InputIterator1, _InputIterator2> +mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __pred) { + __identity __proj; + auto __res = std::__mismatch( + std::__unwrap_iter(__first1), std::__unwrap_iter(__last1), std::__unwrap_iter(__first2), __pred, __proj, __proj); + return std::make_pair(std::__rewrap_iter(__first1, __res.first), std::__rewrap_iter(__first2, __res.second)); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InputIterator1, _InputIterator2> +mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2) { + return std::mismatch(__first1, __last1, __first2, __equal_to()); +} + +#if _LIBCPP_STD_VER >= 14 +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Iter1, _Iter2> __mismatch( + _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { + while (__first1 != __last1 && __first2 != __last2) { + if (!std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) + break; + ++__first1; + ++__first2; + } + return {std::move(__first1), std::move(__first2)}; +} + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Tp*, _Tp*> +__mismatch(_Tp* __first1, _Tp* __last1, _Tp* __first2, _Tp* __last2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { + auto __len = std::min(__last1 - __first1, __last2 - __first2); + return std::__mismatch(__first1, __first1 + __len, __first2, __pred, __proj1, __proj2); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InputIterator1, _InputIterator2> +mismatch(_InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _BinaryPredicate __pred) { + __identity __proj; + auto __res = std::__mismatch( + std::__unwrap_iter(__first1), + std::__unwrap_iter(__last1), + std::__unwrap_iter(__first2), + std::__unwrap_iter(__last2), + __pred, + __proj, + __proj); + return {std::__rewrap_iter(__first1, __res.first), std::__rewrap_iter(__first2, __res.second)}; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InputIterator1, _InputIterator2> +mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2) { + return std::mismatch(__first1, __last1, __first2, __last2, __equal_to()); +} +#endif + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_MISMATCH_H diff --git a/libcxx/include/__cxx03/__algorithm/move.h b/libcxx/include/__cxx03/__algorithm/move.h new file mode 100644 index 0000000000000000000000000000000000000000..1716d43e2a613dd54fdf55e09263a671333b601c --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/move.h @@ -0,0 +1,127 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_MOVE_H +#define _LIBCPP___ALGORITHM_MOVE_H + +#include <__algorithm/copy_move_common.h> +#include <__algorithm/for_each_segment.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/min.h> +#include <__config> +#include <__iterator/segmented_iterator.h> +#include <__type_traits/common_type.h> +#include <__type_traits/is_constructible.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> +__move(_InIter __first, _Sent __last, _OutIter __result); + +template +struct __move_impl { + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _Sent __last, _OutIter __result) const { + while (__first != __last) { + *__result = _IterOps<_AlgPolicy>::__iter_move(__first); + ++__first; + ++__result; + } + return std::make_pair(std::move(__first), std::move(__result)); + } + + template + struct _MoveSegment { + using _Traits = __segmented_iterator_traits<_InIter>; + + _OutIter& __result_; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit _MoveSegment(_OutIter& __result) + : __result_(__result) {} + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void + operator()(typename _Traits::__local_iterator __lfirst, typename _Traits::__local_iterator __llast) { + __result_ = std::__move<_AlgPolicy>(__lfirst, __llast, std::move(__result_)).second; + } + }; + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) const { + std::__for_each_segment(__first, __last, _MoveSegment<_InIter, _OutIter>(__result)); + return std::make_pair(__last, std::move(__result)); + } + + template ::value && + !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) const { + using _Traits = __segmented_iterator_traits<_OutIter>; + using _DiffT = typename common_type<__iter_diff_t<_InIter>, __iter_diff_t<_OutIter> >::type; + + if (__first == __last) + return std::make_pair(std::move(__first), std::move(__result)); + + auto __local_first = _Traits::__local(__result); + auto __segment_iterator = _Traits::__segment(__result); + while (true) { + auto __local_last = _Traits::__end(__segment_iterator); + auto __size = std::min<_DiffT>(__local_last - __local_first, __last - __first); + auto __iters = std::__move<_AlgPolicy>(__first, __first + __size, __local_first); + __first = std::move(__iters.first); + + if (__first == __last) + return std::make_pair(std::move(__first), _Traits::__compose(__segment_iterator, std::move(__iters.second))); + + __local_first = _Traits::__begin(++__segment_iterator); + } + } + + // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer. + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> + operator()(_In* __first, _In* __last, _Out* __result) const { + return std::__copy_trivial_impl(__first, __last, __result); + } +}; + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> +__move(_InIter __first, _Sent __last, _OutIter __result) { + return std::__copy_move_unwrap_iters<__move_impl<_AlgPolicy> >( + std::move(__first), std::move(__last), std::move(__result)); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +move(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { + static_assert(is_copy_constructible<_InputIterator>::value, "Iterators has to be copy constructible."); + static_assert(is_copy_constructible<_OutputIterator>::value, "The output iterator has to be copy constructible."); + + return std::__move<_ClassicAlgPolicy>(std::move(__first), std::move(__last), std::move(__result)).second; +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_MOVE_H diff --git a/libcxx/include/__cxx03/__algorithm/move_backward.h b/libcxx/include/__cxx03/__algorithm/move_backward.h new file mode 100644 index 0000000000000000000000000000000000000000..4beb7bdbaac0d0dc542478f2a39636fd302f4bc6 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/move_backward.h @@ -0,0 +1,137 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_MOVE_BACKWARD_H +#define _LIBCPP___ALGORITHM_MOVE_BACKWARD_H + +#include <__algorithm/copy_move_common.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/min.h> +#include <__config> +#include <__iterator/segmented_iterator.h> +#include <__type_traits/common_type.h> +#include <__type_traits/is_constructible.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_BidirectionalIterator1, _BidirectionalIterator2> +__move_backward(_BidirectionalIterator1 __first, _Sentinel __last, _BidirectionalIterator2 __result); + +template +struct __move_backward_impl { + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _Sent __last, _OutIter __result) const { + auto __last_iter = _IterOps<_AlgPolicy>::next(__first, __last); + auto __original_last_iter = __last_iter; + + while (__first != __last_iter) { + *--__result = _IterOps<_AlgPolicy>::__iter_move(--__last_iter); + } + + return std::make_pair(std::move(__original_last_iter), std::move(__result)); + } + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) const { + using _Traits = __segmented_iterator_traits<_InIter>; + auto __sfirst = _Traits::__segment(__first); + auto __slast = _Traits::__segment(__last); + if (__sfirst == __slast) { + auto __iters = + std::__move_backward<_AlgPolicy>(_Traits::__local(__first), _Traits::__local(__last), std::move(__result)); + return std::make_pair(__last, __iters.second); + } + + __result = + std::__move_backward<_AlgPolicy>(_Traits::__begin(__slast), _Traits::__local(__last), std::move(__result)) + .second; + --__slast; + while (__sfirst != __slast) { + __result = + std::__move_backward<_AlgPolicy>(_Traits::__begin(__slast), _Traits::__end(__slast), std::move(__result)) + .second; + --__slast; + } + __result = std::__move_backward<_AlgPolicy>(_Traits::__local(__first), _Traits::__end(__slast), std::move(__result)) + .second; + return std::make_pair(__last, std::move(__result)); + } + + template ::value && + !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) const { + using _Traits = __segmented_iterator_traits<_OutIter>; + using _DiffT = typename common_type<__iter_diff_t<_InIter>, __iter_diff_t<_OutIter> >::type; + + // When the range contains no elements, __result might not be a valid iterator + if (__first == __last) + return std::make_pair(__first, __result); + + auto __orig_last = __last; + + auto __local_last = _Traits::__local(__result); + auto __segment_iterator = _Traits::__segment(__result); + while (true) { + auto __local_first = _Traits::__begin(__segment_iterator); + auto __size = std::min<_DiffT>(__local_last - __local_first, __last - __first); + auto __iter = std::__move_backward<_AlgPolicy>(__last - __size, __last, __local_last).second; + __last -= __size; + + if (__first == __last) + return std::make_pair(std::move(__orig_last), _Traits::__compose(__segment_iterator, std::move(__iter))); + + __local_last = _Traits::__end(--__segment_iterator); + } + } + + // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer. + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> + operator()(_In* __first, _In* __last, _Out* __result) const { + return std::__copy_backward_trivial_impl(__first, __last, __result); + } +}; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_BidirectionalIterator1, _BidirectionalIterator2> +__move_backward(_BidirectionalIterator1 __first, _Sentinel __last, _BidirectionalIterator2 __result) { + static_assert(std::is_copy_constructible<_BidirectionalIterator1>::value && + std::is_copy_constructible<_BidirectionalIterator1>::value, + "Iterators must be copy constructible."); + + return std::__copy_move_unwrap_iters<__move_backward_impl<_AlgPolicy> >( + std::move(__first), std::move(__last), std::move(__result)); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _BidirectionalIterator2 +move_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last, _BidirectionalIterator2 __result) { + return std::__move_backward<_ClassicAlgPolicy>(std::move(__first), std::move(__last), std::move(__result)).second; +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_MOVE_BACKWARD_H diff --git a/libcxx/include/__cxx03/__algorithm/next_permutation.h b/libcxx/include/__cxx03/__algorithm/next_permutation.h new file mode 100644 index 0000000000000000000000000000000000000000..011ee028cc2f522f030909c82cdc70114fc675e9 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/next_permutation.h @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_NEXT_PERMUTATION_H +#define _LIBCPP___ALGORITHM_NEXT_PERMUTATION_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/reverse.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_BidirectionalIterator, bool> +__next_permutation(_BidirectionalIterator __first, _Sentinel __last, _Compare&& __comp) { + using _Result = pair<_BidirectionalIterator, bool>; + + _BidirectionalIterator __last_iter = _IterOps<_AlgPolicy>::next(__first, __last); + _BidirectionalIterator __i = __last_iter; + if (__first == __last || __first == --__i) + return _Result(std::move(__last_iter), false); + + while (true) { + _BidirectionalIterator __ip1 = __i; + if (__comp(*--__i, *__ip1)) { + _BidirectionalIterator __j = __last_iter; + while (!__comp(*__i, *--__j)) + ; + _IterOps<_AlgPolicy>::iter_swap(__i, __j); + std::__reverse<_AlgPolicy>(__ip1, __last_iter); + return _Result(std::move(__last_iter), true); + } + if (__i == __first) { + std::__reverse<_AlgPolicy>(__first, __last_iter); + return _Result(std::move(__last_iter), false); + } + } +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +next_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) { + return std::__next_permutation<_ClassicAlgPolicy>( + std::move(__first), std::move(__last), static_cast<__comp_ref_type<_Compare> >(__comp)) + .second; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +next_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last) { + return std::next_permutation(__first, __last, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_NEXT_PERMUTATION_H diff --git a/libcxx/include/__cxx03/__algorithm/none_of.h b/libcxx/include/__cxx03/__algorithm/none_of.h new file mode 100644 index 0000000000000000000000000000000000000000..50841ba17cc63ed69c914808cc5184158c466d1f --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/none_of.h @@ -0,0 +1,32 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_NONE_OF_H +#define _LIBCPP___ALGORITHM_NONE_OF_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +none_of(_InputIterator __first, _InputIterator __last, _Predicate __pred) { + for (; __first != __last; ++__first) + if (__pred(*__first)) + return false; + return true; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_NONE_OF_H diff --git a/libcxx/include/__cxx03/__algorithm/nth_element.h b/libcxx/include/__cxx03/__algorithm/nth_element.h new file mode 100644 index 0000000000000000000000000000000000000000..da748d7255aba6a049ac75eb3aa133a89497208c --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/nth_element.h @@ -0,0 +1,261 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_NTH_ELEMENT_H +#define _LIBCPP___ALGORITHM_NTH_ELEMENT_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/sort.h> +#include <__assert> +#include <__config> +#include <__debug_utils/randomize_range.h> +#include <__iterator/iterator_traits.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool __nth_element_find_guard( + _RandomAccessIterator& __i, _RandomAccessIterator& __j, _RandomAccessIterator __m, _Compare __comp) { + // manually guard downward moving __j against __i + while (true) { + if (__i == --__j) { + return false; + } + if (__comp(*__j, *__m)) { + return true; // found guard for downward moving __j, now use unguarded partition + } + } +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +__nth_element( + _RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp) { + using _Ops = _IterOps<_AlgPolicy>; + + // _Compare is known to be a reference type + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; + const difference_type __limit = 7; + while (true) { + if (__nth == __last) + return; + difference_type __len = __last - __first; + switch (__len) { + case 0: + case 1: + return; + case 2: + if (__comp(*--__last, *__first)) + _Ops::iter_swap(__first, __last); + return; + case 3: { + _RandomAccessIterator __m = __first; + std::__sort3<_AlgPolicy, _Compare>(__first, ++__m, --__last, __comp); + return; + } + } + if (__len <= __limit) { + std::__selection_sort<_AlgPolicy, _Compare>(__first, __last, __comp); + return; + } + // __len > __limit >= 3 + _RandomAccessIterator __m = __first + __len / 2; + _RandomAccessIterator __lm1 = __last; + unsigned __n_swaps = std::__sort3<_AlgPolicy, _Compare>(__first, __m, --__lm1, __comp); + // *__m is median + // partition [__first, __m) < *__m and *__m <= [__m, __last) + // (this inhibits tossing elements equivalent to __m around unnecessarily) + _RandomAccessIterator __i = __first; + _RandomAccessIterator __j = __lm1; + // j points beyond range to be tested, *__lm1 is known to be <= *__m + // The search going up is known to be guarded but the search coming down isn't. + // Prime the downward search with a guard. + if (!__comp(*__i, *__m)) // if *__first == *__m + { + // *__first == *__m, *__first doesn't go in first part + if (std::__nth_element_find_guard<_Compare>(__i, __j, __m, __comp)) { + _Ops::iter_swap(__i, __j); + ++__n_swaps; + } else { + // *__first == *__m, *__m <= all other elements + // Partition instead into [__first, __i) == *__first and *__first < [__i, __last) + ++__i; // __first + 1 + __j = __last; + if (!__comp(*__first, *--__j)) { // we need a guard if *__first == *(__last-1) + while (true) { + if (__i == __j) { + return; // [__first, __last) all equivalent elements + } else if (__comp(*__first, *__i)) { + _Ops::iter_swap(__i, __j); + ++__n_swaps; + ++__i; + break; + } + ++__i; + } + } + // [__first, __i) == *__first and *__first < [__j, __last) and __j == __last - 1 + if (__i == __j) { + return; + } + while (true) { + while (!__comp(*__first, *__i)) { + ++__i; + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __i != __last, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + } + do { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __j != __first, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + --__j; + } while (__comp(*__first, *__j)); + if (__i >= __j) + break; + _Ops::iter_swap(__i, __j); + ++__n_swaps; + ++__i; + } + // [__first, __i) == *__first and *__first < [__i, __last) + // The first part is sorted, + if (__nth < __i) { + return; + } + // __nth_element the second part + // std::__nth_element<_Compare>(__i, __nth, __last, __comp); + __first = __i; + continue; + } + } + ++__i; + // j points beyond range to be tested, *__lm1 is known to be <= *__m + // if not yet partitioned... + if (__i < __j) { + // known that *(__i - 1) < *__m + while (true) { + // __m still guards upward moving __i + while (__comp(*__i, *__m)) { + ++__i; + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __i != __last, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + } + // It is now known that a guard exists for downward moving __j + do { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __j != __first, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + --__j; + } while (!__comp(*__j, *__m)); + if (__i >= __j) + break; + _Ops::iter_swap(__i, __j); + ++__n_swaps; + // It is known that __m != __j + // If __m just moved, follow it + if (__m == __i) + __m = __j; + ++__i; + } + } + // [__first, __i) < *__m and *__m <= [__i, __last) + if (__i != __m && __comp(*__m, *__i)) { + _Ops::iter_swap(__i, __m); + ++__n_swaps; + } + // [__first, __i) < *__i and *__i <= [__i+1, __last) + if (__nth == __i) + return; + if (__n_swaps == 0) { + // We were given a perfectly partitioned sequence. Coincidence? + if (__nth < __i) { + // Check for [__first, __i) already sorted + __j = __m = __first; + while (true) { + if (++__j == __i) { + // [__first, __i) sorted + return; + } + if (__comp(*__j, *__m)) { + // not yet sorted, so sort + break; + } + __m = __j; + } + } else { + // Check for [__i, __last) already sorted + __j = __m = __i; + while (true) { + if (++__j == __last) { + // [__i, __last) sorted + return; + } + if (__comp(*__j, *__m)) { + // not yet sorted, so sort + break; + } + __m = __j; + } + } + } + // __nth_element on range containing __nth + if (__nth < __i) { + // std::__nth_element<_Compare>(__first, __nth, __i, __comp); + __last = __i; + } else { + // std::__nth_element<_Compare>(__i+1, __nth, __last, __comp); + __first = ++__i; + } + } +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __nth_element_impl( + _RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare& __comp) { + if (__nth == __last) + return; + + std::__debug_randomize_range<_AlgPolicy>(__first, __last); + + std::__nth_element<_AlgPolicy, __comp_ref_type<_Compare> >(__first, __nth, __last, __comp); + + std::__debug_randomize_range<_AlgPolicy>(__first, __nth); + if (__nth != __last) { + std::__debug_randomize_range<_AlgPolicy>(++__nth, __last); + } +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp) { + std::__nth_element_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__nth), std::move(__last), __comp); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last) { + std::nth_element(std::move(__first), std::move(__nth), std::move(__last), __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_NTH_ELEMENT_H diff --git a/libcxx/include/__cxx03/__algorithm/partial_sort.h b/libcxx/include/__cxx03/__algorithm/partial_sort.h new file mode 100644 index 0000000000000000000000000000000000000000..7f8d0c49147e3af2ee9d25f896f01cd762e7a5ae --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/partial_sort.h @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PARTIAL_SORT_H +#define _LIBCPP___ALGORITHM_PARTIAL_SORT_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_heap.h> +#include <__algorithm/sift_down.h> +#include <__algorithm/sort_heap.h> +#include <__config> +#include <__debug_utils/randomize_range.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_assignable.h> +#include <__type_traits/is_constructible.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandomAccessIterator __partial_sort_impl( + _RandomAccessIterator __first, _RandomAccessIterator __middle, _Sentinel __last, _Compare&& __comp) { + if (__first == __middle) { + return _IterOps<_AlgPolicy>::next(__middle, __last); + } + + std::__make_heap<_AlgPolicy>(__first, __middle, __comp); + + typename iterator_traits<_RandomAccessIterator>::difference_type __len = __middle - __first; + _RandomAccessIterator __i = __middle; + for (; __i != __last; ++__i) { + if (__comp(*__i, *__first)) { + _IterOps<_AlgPolicy>::iter_swap(__i, __first); + std::__sift_down<_AlgPolicy>(__first, __comp, __len, __first); + } + } + std::__sort_heap<_AlgPolicy>(std::move(__first), std::move(__middle), __comp); + + return __i; +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandomAccessIterator +__partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _Sentinel __last, _Compare& __comp) { + if (__first == __middle) + return _IterOps<_AlgPolicy>::next(__middle, __last); + + std::__debug_randomize_range<_AlgPolicy>(__first, __last); + + auto __last_iter = + std::__partial_sort_impl<_AlgPolicy>(__first, __middle, __last, static_cast<__comp_ref_type<_Compare> >(__comp)); + + std::__debug_randomize_range<_AlgPolicy>(__middle, __last); + + return __last_iter; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void partial_sort( + _RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last, _Compare __comp) { + static_assert(std::is_copy_constructible<_RandomAccessIterator>::value, "Iterators must be copy constructible."); + static_assert(std::is_copy_assignable<_RandomAccessIterator>::value, "Iterators must be copy assignable."); + + (void)std::__partial_sort<_ClassicAlgPolicy>(std::move(__first), std::move(__middle), std::move(__last), __comp); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last) { + std::partial_sort(__first, __middle, __last, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_PARTIAL_SORT_H diff --git a/libcxx/include/__cxx03/__algorithm/partial_sort_copy.h b/libcxx/include/__cxx03/__algorithm/partial_sort_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..ef7c9d34d94983107f4ce28add4c63a09d7e150c --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/partial_sort_copy.h @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PARTIAL_SORT_COPY_H +#define _LIBCPP___ALGORITHM_PARTIAL_SORT_COPY_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_heap.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/sift_down.h> +#include <__algorithm/sort_heap.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_callable.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InputIterator, _RandomAccessIterator> __partial_sort_copy( + _InputIterator __first, + _Sentinel1 __last, + _RandomAccessIterator __result_first, + _Sentinel2 __result_last, + _Compare&& __comp, + _Proj1&& __proj1, + _Proj2&& __proj2) { + _RandomAccessIterator __r = __result_first; + auto&& __projected_comp = std::__make_projected(__comp, __proj2); + + if (__r != __result_last) { + for (; __first != __last && __r != __result_last; ++__first, (void)++__r) + *__r = *__first; + std::__make_heap<_AlgPolicy>(__result_first, __r, __projected_comp); + typename iterator_traits<_RandomAccessIterator>::difference_type __len = __r - __result_first; + for (; __first != __last; ++__first) + if (std::__invoke(__comp, std::__invoke(__proj1, *__first), std::__invoke(__proj2, *__result_first))) { + *__result_first = *__first; + std::__sift_down<_AlgPolicy>(__result_first, __projected_comp, __len, __result_first); + } + std::__sort_heap<_AlgPolicy>(__result_first, __r, __projected_comp); + } + + return pair<_InputIterator, _RandomAccessIterator>( + _IterOps<_AlgPolicy>::next(std::move(__first), std::move(__last)), std::move(__r)); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandomAccessIterator partial_sort_copy( + _InputIterator __first, + _InputIterator __last, + _RandomAccessIterator __result_first, + _RandomAccessIterator __result_last, + _Compare __comp) { + static_assert( + __is_callable<_Compare, decltype(*__first), decltype(*__result_first)>::value, "Comparator has to be callable"); + + auto __result = std::__partial_sort_copy<_ClassicAlgPolicy>( + __first, + __last, + __result_first, + __result_last, + static_cast<__comp_ref_type<_Compare> >(__comp), + __identity(), + __identity()); + return __result.second; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandomAccessIterator partial_sort_copy( + _InputIterator __first, + _InputIterator __last, + _RandomAccessIterator __result_first, + _RandomAccessIterator __result_last) { + return std::partial_sort_copy(__first, __last, __result_first, __result_last, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_PARTIAL_SORT_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/partition.h b/libcxx/include/__cxx03/__algorithm/partition.h new file mode 100644 index 0000000000000000000000000000000000000000..824e49b9ec214951d834bf9a49a975fcff2706b5 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/partition.h @@ -0,0 +1,90 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PARTITION_H +#define _LIBCPP___ALGORITHM_PARTITION_H + +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_ForwardIterator, _ForwardIterator> +__partition_impl(_ForwardIterator __first, _Sentinel __last, _Predicate __pred, forward_iterator_tag) { + while (true) { + if (__first == __last) + return std::make_pair(std::move(__first), std::move(__first)); + if (!__pred(*__first)) + break; + ++__first; + } + + _ForwardIterator __p = __first; + while (++__p != __last) { + if (__pred(*__p)) { + _IterOps<_AlgPolicy>::iter_swap(__first, __p); + ++__first; + } + } + return std::make_pair(std::move(__first), std::move(__p)); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_BidirectionalIterator, _BidirectionalIterator> +__partition_impl(_BidirectionalIterator __first, _Sentinel __sentinel, _Predicate __pred, bidirectional_iterator_tag) { + _BidirectionalIterator __original_last = _IterOps<_AlgPolicy>::next(__first, __sentinel); + _BidirectionalIterator __last = __original_last; + + while (true) { + while (true) { + if (__first == __last) + return std::make_pair(std::move(__first), std::move(__original_last)); + if (!__pred(*__first)) + break; + ++__first; + } + do { + if (__first == --__last) + return std::make_pair(std::move(__first), std::move(__original_last)); + } while (!__pred(*__last)); + _IterOps<_AlgPolicy>::iter_swap(__first, __last); + ++__first; + } +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_ForwardIterator, _ForwardIterator> +__partition(_ForwardIterator __first, _Sentinel __last, _Predicate&& __pred, _IterCategory __iter_category) { + return std::__partition_impl<__remove_cvref_t<_Predicate>&, _AlgPolicy>( + std::move(__first), std::move(__last), __pred, __iter_category); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + using _IterCategory = typename iterator_traits<_ForwardIterator>::iterator_category; + auto __result = std::__partition<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __pred, _IterCategory()); + return __result.first; +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_PARTITION_H diff --git a/libcxx/include/__cxx03/__algorithm/partition_copy.h b/libcxx/include/__cxx03/__algorithm/partition_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..147b45c7882a517ec94824df9c5d3908ddf2c9a8 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/partition_copy.h @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PARTITION_COPY_H +#define _LIBCPP___ALGORITHM_PARTITION_COPY_H + +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_OutputIterator1, _OutputIterator2> partition_copy( + _InputIterator __first, + _InputIterator __last, + _OutputIterator1 __out_true, + _OutputIterator2 __out_false, + _Predicate __pred) { + for (; __first != __last; ++__first) { + if (__pred(*__first)) { + *__out_true = *__first; + ++__out_true; + } else { + *__out_false = *__first; + ++__out_false; + } + } + return pair<_OutputIterator1, _OutputIterator2>(__out_true, __out_false); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_PARTITION_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/partition_point.h b/libcxx/include/__cxx03/__algorithm/partition_point.h new file mode 100644 index 0000000000000000000000000000000000000000..504dbf1d1a0556a8a7e6d1301f4397a71a806b6f --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/partition_point.h @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PARTITION_POINT_H +#define _LIBCPP___ALGORITHM_PARTITION_POINT_H + +#include <__algorithm/half_positive.h> +#include <__config> +#include <__iterator/advance.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +partition_point(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + typedef typename iterator_traits<_ForwardIterator>::difference_type difference_type; + difference_type __len = std::distance(__first, __last); + while (__len != 0) { + difference_type __l2 = std::__half_positive(__len); + _ForwardIterator __m = __first; + std::advance(__m, __l2); + if (__pred(*__m)) { + __first = ++__m; + __len -= __l2 + 1; + } else + __len = __l2; + } + return __first; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_PARTITION_POINT_H diff --git a/libcxx/include/__cxx03/__algorithm/pop_heap.h b/libcxx/include/__cxx03/__algorithm/pop_heap.h new file mode 100644 index 0000000000000000000000000000000000000000..6d23830097ff96ca63f7adb1320eefe726a63a55 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/pop_heap.h @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_POP_HEAP_H +#define _LIBCPP___ALGORITHM_POP_HEAP_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/push_heap.h> +#include <__algorithm/sift_down.h> +#include <__assert> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_assignable.h> +#include <__type_traits/is_constructible.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void +__pop_heap(_RandomAccessIterator __first, + _RandomAccessIterator __last, + _Compare& __comp, + typename iterator_traits<_RandomAccessIterator>::difference_type __len) { + // Calling `pop_heap` on an empty range is undefined behavior, but in practice it will be a no-op. + _LIBCPP_ASSERT_PEDANTIC(__len > 0, "The heap given to pop_heap must be non-empty"); + + __comp_ref_type<_Compare> __comp_ref = __comp; + + using value_type = typename iterator_traits<_RandomAccessIterator>::value_type; + if (__len > 1) { + value_type __top = _IterOps<_AlgPolicy>::__iter_move(__first); // create a hole at __first + _RandomAccessIterator __hole = std::__floyd_sift_down<_AlgPolicy>(__first, __comp_ref, __len); + --__last; + + if (__hole == __last) { + *__hole = std::move(__top); + } else { + *__hole = _IterOps<_AlgPolicy>::__iter_move(__last); + ++__hole; + *__last = std::move(__top); + std::__sift_up<_AlgPolicy>(__first, __hole, __comp_ref, __hole - __first); + } + } +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { + static_assert(std::is_copy_constructible<_RandomAccessIterator>::value, "Iterators must be copy constructible."); + static_assert(std::is_copy_assignable<_RandomAccessIterator>::value, "Iterators must be copy assignable."); + + typename iterator_traits<_RandomAccessIterator>::difference_type __len = __last - __first; + std::__pop_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp, __len); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) { + std::pop_heap(std::move(__first), std::move(__last), __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_POP_HEAP_H diff --git a/libcxx/include/__cxx03/__algorithm/prev_permutation.h b/libcxx/include/__cxx03/__algorithm/prev_permutation.h new file mode 100644 index 0000000000000000000000000000000000000000..8d15b6806401d8d1f8b120c4555891d77eb8d663 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/prev_permutation.h @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PREV_PERMUTATION_H +#define _LIBCPP___ALGORITHM_PREV_PERMUTATION_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/reverse.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_BidirectionalIterator, bool> +__prev_permutation(_BidirectionalIterator __first, _Sentinel __last, _Compare&& __comp) { + using _Result = pair<_BidirectionalIterator, bool>; + + _BidirectionalIterator __last_iter = _IterOps<_AlgPolicy>::next(__first, __last); + _BidirectionalIterator __i = __last_iter; + if (__first == __last || __first == --__i) + return _Result(std::move(__last_iter), false); + + while (true) { + _BidirectionalIterator __ip1 = __i; + if (__comp(*__ip1, *--__i)) { + _BidirectionalIterator __j = __last_iter; + while (!__comp(*--__j, *__i)) + ; + _IterOps<_AlgPolicy>::iter_swap(__i, __j); + std::__reverse<_AlgPolicy>(__ip1, __last_iter); + return _Result(std::move(__last_iter), true); + } + if (__i == __first) { + std::__reverse<_AlgPolicy>(__first, __last_iter); + return _Result(std::move(__last_iter), false); + } + } +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +prev_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) { + return std::__prev_permutation<_ClassicAlgPolicy>( + std::move(__first), std::move(__last), static_cast<__comp_ref_type<_Compare> >(__comp)) + .second; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +prev_permutation(_BidirectionalIterator __first, _BidirectionalIterator __last) { + return std::prev_permutation(__first, __last, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_PREV_PERMUTATION_H diff --git a/libcxx/include/__cxx03/__algorithm/pstl.h b/libcxx/include/__cxx03/__algorithm/pstl.h new file mode 100644 index 0000000000000000000000000000000000000000..0bb052b3f97c7604f3e7070fec1cddf54017f4ee --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/pstl.h @@ -0,0 +1,663 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PSTL_H +#define _LIBCPP___ALGORITHM_PSTL_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +# include <__functional/operations.h> +# include <__iterator/cpp17_iterator_concepts.h> +# include <__iterator/iterator_traits.h> +# include <__pstl/backend.h> +# include <__pstl/dispatch.h> +# include <__pstl/handle_exception.h> +# include <__type_traits/enable_if.h> +# include <__type_traits/is_execution_policy.h> +# include <__type_traits/remove_cvref.h> +# include <__utility/forward.h> +# include <__utility/move.h> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template , + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool +any_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "any_of requires a ForwardIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__any_of, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__pred)); +} + +template , + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool +all_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "all_of requires a ForwardIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__all_of, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__pred)); +} + +template , + enable_if_t, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool +none_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "none_of requires a ForwardIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__none_of, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__pred)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator +copy(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR( + _ForwardIterator, "copy(first, last, result) requires [first, last) to be ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR( + _ForwardOutIterator, "copy(first, last, result) requires result to be a ForwardIterator"); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR( + _ForwardOutIterator, decltype(*__first), "copy(first, last, result) requires result to be an OutputIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__copy, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__result)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator +copy_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _ForwardOutIterator __result) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR( + _ForwardIterator, "copy_n(first, n, result) requires first to be a ForwardIterator"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR( + _ForwardOutIterator, "copy_n(first, n, result) requires result to be a ForwardIterator"); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR( + _ForwardOutIterator, decltype(*__first), "copy_n(first, n, result) requires result to be an OutputIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__copy_n, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__n), std::move(__result)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI __iter_diff_t<_ForwardIterator> +count_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR( + _ForwardIterator, "count_if(first, last, pred) requires [first, last) to be ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__count_if, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__pred)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI __iter_diff_t<_ForwardIterator> +count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR( + _ForwardIterator, "count(first, last, val) requires [first, last) to be ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__count, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), __value); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI bool +equal(_ExecutionPolicy&& __policy, + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _Pred __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "equal requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "equal requires ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__equal_3leg, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__pred)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI bool +equal(_ExecutionPolicy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "equal requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "equal requires ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__equal_3leg, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), + std::move(__first1), + std::move(__last1), + std::move(__first2), + equal_to{}); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI bool +equal(_ExecutionPolicy&& __policy, + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2, + _Pred __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "equal requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "equal requires ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__equal, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__pred)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI bool +equal(_ExecutionPolicy&& __policy, + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "equal requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "equal requires ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__equal, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + equal_to{}); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "fill requires ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__fill, __pstl::__current_configuration, _RawPolicy>; + __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), __value); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +fill_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, const _Tp& __value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "fill_n requires a ForwardIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__fill_n, __pstl::__current_configuration, _RawPolicy>; + __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__n), __value); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardIterator +find_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "find_if requires ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__find_if, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__pred)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardIterator +find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "find_if_not requires ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__find_if_not, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__pred)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardIterator +find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "find requires ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__find, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), __value); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +for_each(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Function __func) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "for_each requires ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__for_each, __pstl::__current_configuration, _RawPolicy>; + __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__func)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +for_each_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __size, _Function __func) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "for_each_n requires a ForwardIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__for_each_n, __pstl::__current_configuration, _RawPolicy>; + __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__size), std::move(__func)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +generate(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Generator __gen) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "generate requires ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__generate, __pstl::__current_configuration, _RawPolicy>; + __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__gen)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +generate_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __n, _Generator __gen) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "generate_n requires a ForwardIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__generate_n, __pstl::__current_configuration, _RawPolicy>; + __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__n), std::move(__gen)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI bool +is_partitioned(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "is_partitioned requires ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__is_partitioned, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__pred)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator +merge(_ExecutionPolicy&& __policy, + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2, + _ForwardOutIterator __result, + _Comp __comp) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "merge requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "merge requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(_ForwardOutIterator, decltype(*__first1), "merge requires an OutputIterator"); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(_ForwardOutIterator, decltype(*__first2), "merge requires an OutputIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__merge, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + std::move(__comp)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator +merge(_ExecutionPolicy&& __policy, + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2, + _ForwardOutIterator __result) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "merge requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "merge requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(_ForwardOutIterator, decltype(*__first1), "merge requires an OutputIterator"); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(_ForwardOutIterator, decltype(*__first2), "merge requires an OutputIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__merge, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + less{}); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator +move(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __result) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "move requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardOutIterator, "move requires an OutputIterator"); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR( + _ForwardOutIterator, decltype(std::move(*__first)), "move requires an OutputIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__move, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__result)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +replace_if(_ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + _Pred __pred, + const _Tp& __new_value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "replace_if requires ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__replace_if, __pstl::__current_configuration, _RawPolicy>; + __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__pred), __new_value); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +replace(_ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + const _Tp& __old_value, + const _Tp& __new_value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "replace requires ForwardIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__replace, __pstl::__current_configuration, _RawPolicy>; + __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), __old_value, __new_value); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void replace_copy_if( + _ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + _ForwardOutIterator __result, + _Pred __pred, + const _Tp& __new_value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "replace_copy_if requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardOutIterator, "replace_copy_if requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR( + _ForwardOutIterator, decltype(*__first), "replace_copy_if requires an OutputIterator"); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(_ForwardOutIterator, const _Tp&, "replace_copy requires an OutputIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__replace_copy_if, __pstl::__current_configuration, _RawPolicy>; + __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), + std::move(__first), + std::move(__last), + std::move(__result), + std::move(__pred), + __new_value); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void replace_copy( + _ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + _ForwardOutIterator __result, + const _Tp& __old_value, + const _Tp& __new_value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "replace_copy requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardOutIterator, "replace_copy requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR( + _ForwardOutIterator, decltype(*__first), "replace_copy requires an OutputIterator"); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(_ForwardOutIterator, const _Tp&, "replace_copy requires an OutputIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__replace_copy, __pstl::__current_configuration, _RawPolicy>; + __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), + std::move(__first), + std::move(__last), + std::move(__result), + __old_value, + __new_value); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator rotate_copy( + _ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __middle, + _ForwardIterator __last, + _ForwardOutIterator __result) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "rotate_copy requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardOutIterator, "rotate_copy requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR( + _ForwardOutIterator, decltype(*__first), "rotate_copy requires an OutputIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__rotate_copy, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), + std::move(__first), + std::move(__middle), + std::move(__last), + std::move(__result)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +sort(_ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) { + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(_RandomAccessIterator, "sort requires RandomAccessIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__sort, __pstl::__current_configuration, _RawPolicy>; + __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__comp)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +sort(_ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last) { + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(_RandomAccessIterator, "sort requires RandomAccessIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__sort, __pstl::__current_configuration, _RawPolicy>; + __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), less{}); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +stable_sort(_ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) { + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(_RandomAccessIterator, "stable_sort requires RandomAccessIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__stable_sort, __pstl::__current_configuration, _RawPolicy>; + __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__comp)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI void +stable_sort(_ExecutionPolicy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last) { + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(_RandomAccessIterator, "stable_sort requires RandomAccessIterators"); + using _Implementation = __pstl::__dispatch<__pstl::__stable_sort, __pstl::__current_configuration, _RawPolicy>; + __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), less{}); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform( + _ExecutionPolicy&& __policy, + _ForwardIterator __first, + _ForwardIterator __last, + _ForwardOutIterator __result, + _UnaryOperation __op) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "transform requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardOutIterator, "transform requires an OutputIterator"); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR( + _ForwardOutIterator, decltype(__op(*__first)), "transform requires an OutputIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__transform, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), + std::move(__first), + std::move(__last), + std::move(__result), + std::move(__op)); +} + +template , + enable_if_t, int> = 0> +_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform( + _ExecutionPolicy&& __policy, + _ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardOutIterator __result, + _BinaryOperation __op) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "transform requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "transform requires ForwardIterators"); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardOutIterator, "transform requires an OutputIterator"); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR( + _ForwardOutIterator, decltype(__op(*__first1, *__first2)), "transform requires an OutputIterator"); + using _Implementation = __pstl::__dispatch<__pstl::__transform_binary, __pstl::__current_configuration, _RawPolicy>; + return __pstl::__handle_exception<_Implementation>( + std::forward<_ExecutionPolicy>(__policy), + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__result), + std::move(__op)); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_PSTL_H diff --git a/libcxx/include/__cxx03/__algorithm/push_heap.h b/libcxx/include/__cxx03/__algorithm/push_heap.h new file mode 100644 index 0000000000000000000000000000000000000000..ec0b445f2b70f3dc9ab6a17234de75c487194e4b --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/push_heap.h @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_PUSH_HEAP_H +#define _LIBCPP___ALGORITHM_PUSH_HEAP_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_assignable.h> +#include <__type_traits/is_constructible.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void +__sift_up(_RandomAccessIterator __first, + _RandomAccessIterator __last, + _Compare&& __comp, + typename iterator_traits<_RandomAccessIterator>::difference_type __len) { + using value_type = typename iterator_traits<_RandomAccessIterator>::value_type; + + if (__len > 1) { + __len = (__len - 2) / 2; + _RandomAccessIterator __ptr = __first + __len; + + if (__comp(*__ptr, *--__last)) { + value_type __t(_IterOps<_AlgPolicy>::__iter_move(__last)); + do { + *__last = _IterOps<_AlgPolicy>::__iter_move(__ptr); + __last = __ptr; + if (__len == 0) + break; + __len = (__len - 1) / 2; + __ptr = __first + __len; + } while (__comp(*__ptr, __t)); + + *__last = std::move(__t); + } + } +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void +__push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) { + typename iterator_traits<_RandomAccessIterator>::difference_type __len = __last - __first; + std::__sift_up<_AlgPolicy, __comp_ref_type<_Compare> >(std::move(__first), std::move(__last), __comp, __len); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { + static_assert(std::is_copy_constructible<_RandomAccessIterator>::value, "Iterators must be copy constructible."); + static_assert(std::is_copy_assignable<_RandomAccessIterator>::value, "Iterators must be copy assignable."); + + std::__push_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) { + std::push_heap(std::move(__first), std::move(__last), __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_PUSH_HEAP_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_adjacent_find.h b/libcxx/include/__cxx03/__algorithm/ranges_adjacent_find.h new file mode 100644 index 0000000000000000000000000000000000000000..3c54f723310a6f8257c4d405d71216c2643da742 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_adjacent_find.h @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_ADJACENT_FIND_H +#define _LIBCPP___ALGORITHM_RANGES_ADJACENT_FIND_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __adjacent_find { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static _Iter + __adjacent_find_impl(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) { + if (__first == __last) + return __first; + + auto __i = __first; + while (++__i != __last) { + if (std::invoke(__pred, std::invoke(__proj, *__first), std::invoke(__proj, *__i))) + return __first; + __first = __i; + } + return __i; + } + + template _Sent, + class _Proj = identity, + indirect_binary_predicate, projected<_Iter, _Proj>> _Pred = ranges::equal_to> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Iter + operator()(_Iter __first, _Sent __last, _Pred __pred = {}, _Proj __proj = {}) const { + return __adjacent_find_impl(std::move(__first), std::move(__last), __pred, __proj); + } + + template , _Proj>, projected, _Proj>> + _Pred = ranges::equal_to> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __range, _Pred __pred = {}, _Proj __proj = {}) const { + return __adjacent_find_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj); + } +}; +} // namespace __adjacent_find + +inline namespace __cpo { +inline constexpr auto adjacent_find = __adjacent_find::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_ADJACENT_FIND_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_all_of.h b/libcxx/include/__cxx03/__algorithm/ranges_all_of.h new file mode 100644 index 0000000000000000000000000000000000000000..2f603b32f32d08a29305271e91ac646ebf27ca33 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_all_of.h @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_ALL_OF_H +#define _LIBCPP___ALGORITHM_RANGES_ALL_OF_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __all_of { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static bool __all_of_impl(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) { + for (; __first != __last; ++__first) { + if (!std::invoke(__pred, std::invoke(__proj, *__first))) + return false; + } + return true; + } + + template _Sent, + class _Proj = identity, + indirect_unary_predicate> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { + return __all_of_impl(std::move(__first), std::move(__last), __pred, __proj); + } + + template , _Proj>> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const { + return __all_of_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj); + } +}; +} // namespace __all_of + +inline namespace __cpo { +inline constexpr auto all_of = __all_of::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_ALL_OF_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_any_of.h b/libcxx/include/__cxx03/__algorithm/ranges_any_of.h new file mode 100644 index 0000000000000000000000000000000000000000..205fcecc086e7a65766bea679002819ee889bc21 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_any_of.h @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_ANY_OF_H +#define _LIBCPP___ALGORITHM_RANGES_ANY_OF_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __any_of { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static bool __any_of_impl(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) { + for (; __first != __last; ++__first) { + if (std::invoke(__pred, std::invoke(__proj, *__first))) + return true; + } + return false; + } + + template _Sent, + class _Proj = identity, + indirect_unary_predicate> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Iter __first, _Sent __last, _Pred __pred = {}, _Proj __proj = {}) const { + return __any_of_impl(std::move(__first), std::move(__last), __pred, __proj); + } + + template , _Proj>> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const { + return __any_of_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj); + } +}; +} // namespace __any_of + +inline namespace __cpo { +inline constexpr auto any_of = __any_of::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_ANY_OF_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_binary_search.h b/libcxx/include/__cxx03/__algorithm/ranges_binary_search.h new file mode 100644 index 0000000000000000000000000000000000000000..1ef2bd62b5995ab9799eb766c2f78bbaaa392ccc --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_binary_search.h @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_BINARY_SEARCH_H +#define _LIBCPP___ALGORITHM_RANGES_BINARY_SEARCH_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/lower_bound.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __binary_search { +struct __fn { + template _Sent, + class _Type, + class _Proj = identity, + indirect_strict_weak_order> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Iter __first, _Sent __last, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const { + auto __ret = std::__lower_bound<_RangeAlgPolicy>(__first, __last, __value, __comp, __proj); + return __ret != __last && !std::invoke(__comp, __value, std::invoke(__proj, *__ret)); + } + + template , _Proj>> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Range&& __r, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const { + auto __first = ranges::begin(__r); + auto __last = ranges::end(__r); + auto __ret = std::__lower_bound<_RangeAlgPolicy>(__first, __last, __value, __comp, __proj); + return __ret != __last && !std::invoke(__comp, __value, std::invoke(__proj, *__ret)); + } +}; +} // namespace __binary_search + +inline namespace __cpo { +inline constexpr auto binary_search = __binary_search::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_BINARY_SEARCH_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_clamp.h b/libcxx/include/__cxx03/__algorithm/ranges_clamp.h new file mode 100644 index 0000000000000000000000000000000000000000..e6181ef9435e098862a0e0e38c48978e30589e85 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_clamp.h @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_CLAMP_H +#define _LIBCPP___ALGORITHM_RANGES_CLAMP_H + +#include <__assert> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __clamp { +struct __fn { + template > _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Type& operator()( + const _Type& __value, const _Type& __low, const _Type& __high, _Comp __comp = {}, _Proj __proj = {}) const { + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + !bool(std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __low))), + "Bad bounds passed to std::ranges::clamp"); + + auto&& __projected = std::invoke(__proj, __value); + if (std::invoke(__comp, std::forward(__projected), std::invoke(__proj, __low))) + return __low; + else if (std::invoke(__comp, std::invoke(__proj, __high), std::forward(__projected))) + return __high; + else + return __value; + } +}; +} // namespace __clamp + +inline namespace __cpo { +inline constexpr auto clamp = __clamp::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_CLAMP_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_contains.h b/libcxx/include/__cxx03/__algorithm/ranges_contains.h new file mode 100644 index 0000000000000000000000000000000000000000..4836c3baed173eea19a017784dc7e8df3f4edb64 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_contains.h @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_CONTAINS_H +#define _LIBCPP___ALGORITHM_RANGES_CONTAINS_H + +#include <__algorithm/ranges_find.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__functional/reference_wrapper.h> +#include <__iterator/concepts.h> +#include <__iterator/indirectly_comparable.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __contains { +struct __fn { + template _Sent, class _Type, class _Proj = identity> + requires indirect_binary_predicate, const _Type*> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool static + operator()(_Iter __first, _Sent __last, const _Type& __value, _Proj __proj = {}) { + return ranges::find(std::move(__first), __last, __value, std::ref(__proj)) != __last; + } + + template + requires indirect_binary_predicate, _Proj>, const _Type*> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool static + operator()(_Range&& __range, const _Type& __value, _Proj __proj = {}) { + return ranges::find(ranges::begin(__range), ranges::end(__range), __value, std::ref(__proj)) != + ranges::end(__range); + } +}; +} // namespace __contains + +inline namespace __cpo { +inline constexpr auto contains = __contains::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_CONTAINS_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_contains_subrange.h b/libcxx/include/__cxx03/__algorithm/ranges_contains_subrange.h new file mode 100644 index 0000000000000000000000000000000000000000..4398c457fd054d3c02b774b7543588fb822f9410 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_contains_subrange.h @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_CONTAINS_SUBRANGE_H +#define _LIBCPP___ALGORITHM_RANGES_CONTAINS_SUBRANGE_H + +#include <__algorithm/ranges_search.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__functional/reference_wrapper.h> +#include <__iterator/concepts.h> +#include <__iterator/indirectly_comparable.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/size.h> +#include <__ranges/subrange.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __contains_subrange { +struct __fn { + template _Sent1, + forward_iterator _Iter2, + sentinel_for<_Iter2> _Sent2, + class _Pred = ranges::equal_to, + class _Proj1 = identity, + class _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool static operator()( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred __pred = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) { + if (__first2 == __last2) + return true; + + auto __ret = ranges::search( + std::move(__first1), __last1, std::move(__first2), __last2, __pred, std::ref(__proj1), std::ref(__proj2)); + return __ret.empty() == false; + } + + template + requires indirectly_comparable, iterator_t<_Range2>, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool static + operator()(_Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) { + if constexpr (sized_range<_Range2>) { + if (ranges::size(__range2) == 0) + return true; + } else { + if (ranges::begin(__range2) == ranges::end(__range2)) + return true; + } + + auto __ret = ranges::search(__range1, __range2, __pred, std::ref(__proj1), std::ref(__proj2)); + return __ret.empty() == false; + } +}; +} // namespace __contains_subrange + +inline namespace __cpo { +inline constexpr auto contains_subrange = __contains_subrange::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_CONTAINS_SUBRANGE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_copy.h b/libcxx/include/__cxx03/__algorithm/ranges_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..e1d6d32f05f7e6455178e61ee0009fb510a9bdcc --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_copy.h @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_COPY_H +#define _LIBCPP___ALGORITHM_RANGES_COPY_H + +#include <__algorithm/copy.h> +#include <__algorithm/in_out_result.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__functional/identity.h> +#include <__iterator/concepts.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using copy_result = in_out_result<_InIter, _OutIter>; + +namespace __copy { +struct __fn { + template _Sent, weakly_incrementable _OutIter> + requires indirectly_copyable<_InIter, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr copy_result<_InIter, _OutIter> + operator()(_InIter __first, _Sent __last, _OutIter __result) const { + auto __ret = std::__copy<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__result)); + return {std::move(__ret.first), std::move(__ret.second)}; + } + + template + requires indirectly_copyable, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr copy_result, _OutIter> + operator()(_Range&& __r, _OutIter __result) const { + auto __ret = std::__copy<_RangeAlgPolicy>(ranges::begin(__r), ranges::end(__r), std::move(__result)); + return {std::move(__ret.first), std::move(__ret.second)}; + } +}; +} // namespace __copy + +inline namespace __cpo { +inline constexpr auto copy = __copy::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_copy_backward.h b/libcxx/include/__cxx03/__algorithm/ranges_copy_backward.h new file mode 100644 index 0000000000000000000000000000000000000000..93e326042503fd732e3578ab9ea8126825ba4110 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_copy_backward.h @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_COPY_BACKWARD_H +#define _LIBCPP___ALGORITHM_RANGES_COPY_BACKWARD_H + +#include <__algorithm/copy_backward.h> +#include <__algorithm/in_out_result.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using copy_backward_result = in_out_result<_Ip, _Op>; + +namespace __copy_backward { +struct __fn { + template _Sent1, bidirectional_iterator _InIter2> + requires indirectly_copyable<_InIter1, _InIter2> + _LIBCPP_HIDE_FROM_ABI constexpr copy_backward_result<_InIter1, _InIter2> + operator()(_InIter1 __first, _Sent1 __last, _InIter2 __result) const { + auto __ret = std::__copy_backward<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__result)); + return {std::move(__ret.first), std::move(__ret.second)}; + } + + template + requires indirectly_copyable, _Iter> + _LIBCPP_HIDE_FROM_ABI constexpr copy_backward_result, _Iter> + operator()(_Range&& __r, _Iter __result) const { + auto __ret = std::__copy_backward<_RangeAlgPolicy>(ranges::begin(__r), ranges::end(__r), std::move(__result)); + return {std::move(__ret.first), std::move(__ret.second)}; + } +}; +} // namespace __copy_backward + +inline namespace __cpo { +inline constexpr auto copy_backward = __copy_backward::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_COPY_BACKWARD_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_copy_if.h b/libcxx/include/__cxx03/__algorithm/ranges_copy_if.h new file mode 100644 index 0000000000000000000000000000000000000000..4b41d2154e7f8300cac0f8d873af0247f56cb886 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_copy_if.h @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_COPY_IF_H +#define _LIBCPP___ALGORITHM_RANGES_COPY_IF_H + +#include <__algorithm/in_out_result.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using copy_if_result = in_out_result<_Ip, _Op>; + +namespace __copy_if { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI static constexpr copy_if_result<_InIter, _OutIter> + __copy_if_impl(_InIter __first, _Sent __last, _OutIter __result, _Pred& __pred, _Proj& __proj) { + for (; __first != __last; ++__first) { + if (std::invoke(__pred, std::invoke(__proj, *__first))) { + *__result = *__first; + ++__result; + } + } + return {std::move(__first), std::move(__result)}; + } + + template _Sent, + weakly_incrementable _OutIter, + class _Proj = identity, + indirect_unary_predicate> _Pred> + requires indirectly_copyable<_Iter, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr copy_if_result<_Iter, _OutIter> + operator()(_Iter __first, _Sent __last, _OutIter __result, _Pred __pred, _Proj __proj = {}) const { + return __copy_if_impl(std::move(__first), std::move(__last), std::move(__result), __pred, __proj); + } + + template , _Proj>> _Pred> + requires indirectly_copyable, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr copy_if_result, _OutIter> + operator()(_Range&& __r, _OutIter __result, _Pred __pred, _Proj __proj = {}) const { + return __copy_if_impl(ranges::begin(__r), ranges::end(__r), std::move(__result), __pred, __proj); + } +}; +} // namespace __copy_if + +inline namespace __cpo { +inline constexpr auto copy_if = __copy_if::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_COPY_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_copy_n.h b/libcxx/include/__cxx03/__algorithm/ranges_copy_n.h new file mode 100644 index 0000000000000000000000000000000000000000..4353fa99278c8bfcae4b4fc14d440030273b6d7a --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_copy_n.h @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_COPY_N_H +#define _LIBCPP___ALGORITHM_RANGES_COPY_N_H + +#include <__algorithm/copy.h> +#include <__algorithm/in_out_result.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/ranges_copy.h> +#include <__config> +#include <__functional/identity.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/unreachable_sentinel.h> +#include <__iterator/wrap_iter.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace ranges { + +template +using copy_n_result = in_out_result<_Ip, _Op>; + +namespace __copy_n { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static copy_n_result<_InIter, _OutIter> + __go(_InIter __first, _DiffType __n, _OutIter __result) { + while (__n != 0) { + *__result = *__first; + ++__first; + ++__result; + --__n; + } + return {std::move(__first), std::move(__result)}; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr static copy_n_result<_InIter, _OutIter> + __go(_InIter __first, _DiffType __n, _OutIter __result) { + auto __ret = std::__copy<_RangeAlgPolicy>(__first, __first + __n, __result); + return {__ret.first, __ret.second}; + } + + template + requires indirectly_copyable<_Ip, _Op> + _LIBCPP_HIDE_FROM_ABI constexpr copy_n_result<_Ip, _Op> + operator()(_Ip __first, iter_difference_t<_Ip> __n, _Op __result) const { + return __go(std::move(__first), __n, std::move(__result)); + } +}; +} // namespace __copy_n + +inline namespace __cpo { +inline constexpr auto copy_n = __copy_n::__fn{}; +} // namespace __cpo +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_COPY_N_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_count.h b/libcxx/include/__cxx03/__algorithm/ranges_count.h new file mode 100644 index 0000000000000000000000000000000000000000..4f35117438705d418992cecf12103f23cc5a3259 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_count.h @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_COUNT_H +#define _LIBCPP___ALGORITHM_RANGES_COUNT_H + +#include <__algorithm/count.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __count { +struct __fn { + template _Sent, class _Type, class _Proj = identity> + requires indirect_binary_predicate, const _Type*> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Iter> + operator()(_Iter __first, _Sent __last, const _Type& __value, _Proj __proj = {}) const { + return std::__count<_RangeAlgPolicy>(std::move(__first), std::move(__last), __value, __proj); + } + + template + requires indirect_binary_predicate, _Proj>, const _Type*> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr range_difference_t<_Range> + operator()(_Range&& __r, const _Type& __value, _Proj __proj = {}) const { + return std::__count<_RangeAlgPolicy>(ranges::begin(__r), ranges::end(__r), __value, __proj); + } +}; +} // namespace __count + +inline namespace __cpo { +inline constexpr auto count = __count::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_COUNT_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_count_if.h b/libcxx/include/__cxx03/__algorithm/ranges_count_if.h new file mode 100644 index 0000000000000000000000000000000000000000..5f2396ff7d5315e07d8dba515a85f09d7b9619db --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_count_if.h @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_COUNT_IF_H +#define _LIBCPP___ALGORITHM_RANGES_COUNT_IF_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +template +_LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Iter> +__count_if_impl(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) { + iter_difference_t<_Iter> __counter(0); + for (; __first != __last; ++__first) { + if (std::invoke(__pred, std::invoke(__proj, *__first))) + ++__counter; + } + return __counter; +} + +namespace __count_if { +struct __fn { + template _Sent, + class _Proj = identity, + indirect_unary_predicate> _Predicate> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Iter> + operator()(_Iter __first, _Sent __last, _Predicate __pred, _Proj __proj = {}) const { + return ranges::__count_if_impl(std::move(__first), std::move(__last), __pred, __proj); + } + + template , _Proj>> _Predicate> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr range_difference_t<_Range> + operator()(_Range&& __r, _Predicate __pred, _Proj __proj = {}) const { + return ranges::__count_if_impl(ranges::begin(__r), ranges::end(__r), __pred, __proj); + } +}; +} // namespace __count_if + +inline namespace __cpo { +inline constexpr auto count_if = __count_if::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_COUNT_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_ends_with.h b/libcxx/include/__cxx03/__algorithm/ranges_ends_with.h new file mode 100644 index 0000000000000000000000000000000000000000..06efdef36b7cf22d53972f695b2a319566b3cee4 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_ends_with.h @@ -0,0 +1,201 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_ENDS_WITH_H +#define _LIBCPP___ALGORITHM_RANGES_ENDS_WITH_H + +#include <__algorithm/ranges_equal.h> +#include <__algorithm/ranges_starts_with.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__functional/reference_wrapper.h> +#include <__iterator/advance.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/indirectly_comparable.h> +#include <__iterator/reverse_iterator.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __ends_with { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool __ends_with_fn_impl_bidirectional( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred& __pred, + _Proj1& __proj1, + _Proj2& __proj2) { + auto __rbegin1 = std::make_reverse_iterator(__last1); + auto __rend1 = std::make_reverse_iterator(__first1); + auto __rbegin2 = std::make_reverse_iterator(__last2); + auto __rend2 = std::make_reverse_iterator(__first2); + return ranges::starts_with( + __rbegin1, __rend1, __rbegin2, __rend2, std::ref(__pred), std::ref(__proj1), std::ref(__proj2)); + } + + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool __ends_with_fn_impl( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred& __pred, + _Proj1& __proj1, + _Proj2& __proj2) { + if constexpr (std::bidirectional_iterator<_Sent1> && std::bidirectional_iterator<_Sent2> && + (!std::random_access_iterator<_Sent1>) && (!std::random_access_iterator<_Sent2>)) { + return __ends_with_fn_impl_bidirectional(__first1, __last1, __first2, __last2, __pred, __proj1, __proj2); + + } else { + auto __n1 = ranges::distance(__first1, __last1); + auto __n2 = ranges::distance(__first2, __last2); + if (__n2 == 0) + return true; + if (__n2 > __n1) + return false; + + return __ends_with_fn_impl_with_offset( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + __pred, + __proj1, + __proj2, + __n1 - __n2); + } + } + + template + static _LIBCPP_HIDE_FROM_ABI constexpr bool __ends_with_fn_impl_with_offset( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred& __pred, + _Proj1& __proj1, + _Proj2& __proj2, + _Offset __offset) { + if constexpr (std::bidirectional_iterator<_Sent1> && std::bidirectional_iterator<_Sent2> && + !std::random_access_iterator<_Sent1> && !std::random_access_iterator<_Sent2>) { + return __ends_with_fn_impl_bidirectional( + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __pred, __proj1, __proj2); + + } else { + ranges::advance(__first1, __offset); + return ranges::equal( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::ref(__pred), + std::ref(__proj1), + std::ref(__proj2)); + } + } + + template _Sent1, + input_iterator _Iter2, + sentinel_for<_Iter2> _Sent2, + class _Pred = ranges::equal_to, + class _Proj1 = identity, + class _Proj2 = identity> + requires(forward_iterator<_Iter1> || sized_sentinel_for<_Sent1, _Iter1>) && + (forward_iterator<_Iter2> || sized_sentinel_for<_Sent2, _Iter2>) && + indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred __pred = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + return __ends_with_fn_impl( + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __pred, __proj1, __proj2); + } + + template + requires(forward_range<_Range1> || sized_range<_Range1>) && (forward_range<_Range2> || sized_range<_Range2>) && + indirectly_comparable, iterator_t<_Range2>, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()( + _Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { + if constexpr (sized_range<_Range1> && sized_range<_Range2>) { + auto __n1 = ranges::size(__range1); + auto __n2 = ranges::size(__range2); + if (__n2 == 0) + return true; + if (__n2 > __n1) + return false; + auto __offset = __n1 - __n2; + + return __ends_with_fn_impl_with_offset( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + __pred, + __proj1, + __proj2, + __offset); + + } else { + return __ends_with_fn_impl( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + __pred, + __proj1, + __proj2); + } + } +}; +} // namespace __ends_with + +inline namespace __cpo { +inline constexpr auto ends_with = __ends_with::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_ENDS_WITH_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_equal.h b/libcxx/include/__cxx03/__algorithm/ranges_equal.h new file mode 100644 index 0000000000000000000000000000000000000000..edbd0e3641c1b891a3c10ff32670ec934bbd680d --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_equal.h @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_EQUAL_H +#define _LIBCPP___ALGORITHM_RANGES_EQUAL_H + +#include <__algorithm/equal.h> +#include <__algorithm/unwrap_range.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/indirectly_comparable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __equal { +struct __fn { + template _Sent1, + input_iterator _Iter2, + sentinel_for<_Iter2> _Sent2, + class _Pred = ranges::equal_to, + class _Proj1 = identity, + class _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred __pred = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + if constexpr (sized_sentinel_for<_Sent1, _Iter1> && sized_sentinel_for<_Sent2, _Iter2>) { + if (__last1 - __first1 != __last2 - __first2) + return false; + } + auto __unwrapped1 = std::__unwrap_range(std::move(__first1), std::move(__last1)); + auto __unwrapped2 = std::__unwrap_range(std::move(__first2), std::move(__last2)); + return std::__equal_impl( + std::move(__unwrapped1.first), + std::move(__unwrapped1.second), + std::move(__unwrapped2.first), + std::move(__unwrapped2.second), + __pred, + __proj1, + __proj2); + } + + template + requires indirectly_comparable, iterator_t<_Range2>, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()( + _Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { + if constexpr (sized_range<_Range1> && sized_range<_Range2>) { + if (ranges::distance(__range1) != ranges::distance(__range2)) + return false; + } + auto __unwrapped1 = std::__unwrap_range(ranges::begin(__range1), ranges::end(__range1)); + auto __unwrapped2 = std::__unwrap_range(ranges::begin(__range2), ranges::end(__range2)); + return std::__equal_impl( + std::move(__unwrapped1.first), + std::move(__unwrapped1.second), + std::move(__unwrapped2.first), + std::move(__unwrapped2.second), + __pred, + __proj1, + __proj2); + return false; + } +}; +} // namespace __equal + +inline namespace __cpo { +inline constexpr auto equal = __equal::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_EQUAL_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_equal_range.h b/libcxx/include/__cxx03/__algorithm/ranges_equal_range.h new file mode 100644 index 0000000000000000000000000000000000000000..4a308e016b546a575d2ccafd1f8592c80bbf0871 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_equal_range.h @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_EQUAL_RANGE_H +#define _LIBCPP___ALGORITHM_RANGES_EQUAL_RANGE_H + +#include <__algorithm/equal_range.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__ranges/subrange.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __equal_range { + +struct __fn { + template _Sent, + class _Tp, + class _Proj = identity, + indirect_strict_weak_order> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter> + operator()(_Iter __first, _Sent __last, const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) const { + auto __ret = std::__equal_range<_RangeAlgPolicy>(std::move(__first), std::move(__last), __value, __comp, __proj); + return {std::move(__ret.first), std::move(__ret.second)}; + } + + template , _Proj>> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range> + operator()(_Range&& __range, const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) const { + auto __ret = + std::__equal_range<_RangeAlgPolicy>(ranges::begin(__range), ranges::end(__range), __value, __comp, __proj); + return {std::move(__ret.first), std::move(__ret.second)}; + } +}; + +} // namespace __equal_range + +inline namespace __cpo { +inline constexpr auto equal_range = __equal_range::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_EQUAL_RANGE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_fill.h b/libcxx/include/__cxx03/__algorithm/ranges_fill.h new file mode 100644 index 0000000000000000000000000000000000000000..7a177d85e9f07f1a6512406638cb46fba63e4e9c --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_fill.h @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_FILL_H +#define _LIBCPP___ALGORITHM_RANGES_FILL_H + +#include <__algorithm/ranges_fill_n.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __fill { +struct __fn { + template _Iter, sentinel_for<_Iter> _Sent> + _LIBCPP_HIDE_FROM_ABI constexpr _Iter operator()(_Iter __first, _Sent __last, const _Type& __value) const { + if constexpr (random_access_iterator<_Iter> && sized_sentinel_for<_Sent, _Iter>) { + return ranges::fill_n(__first, __last - __first, __value); + } else { + for (; __first != __last; ++__first) + *__first = __value; + return __first; + } + } + + template _Range> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> operator()(_Range&& __range, const _Type& __value) const { + return (*this)(ranges::begin(__range), ranges::end(__range), __value); + } +}; +} // namespace __fill + +inline namespace __cpo { +inline constexpr auto fill = __fill::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_FILL_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_fill_n.h b/libcxx/include/__cxx03/__algorithm/ranges_fill_n.h new file mode 100644 index 0000000000000000000000000000000000000000..a6e988c0089ce4cbac532bc827e66455afdc452a --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_fill_n.h @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_FILL_N_H +#define _LIBCPP___ALGORITHM_RANGES_FILL_N_H + +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __fill_n { +struct __fn { + template _Iter> + _LIBCPP_HIDE_FROM_ABI constexpr _Iter + operator()(_Iter __first, iter_difference_t<_Iter> __n, const _Type& __value) const { + for (; __n != 0; --__n) { + *__first = __value; + ++__first; + } + return __first; + } +}; +} // namespace __fill_n + +inline namespace __cpo { +inline constexpr auto fill_n = __fill_n::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_FILL_N_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_find.h b/libcxx/include/__cxx03/__algorithm/ranges_find.h new file mode 100644 index 0000000000000000000000000000000000000000..6b0d5efe37ab8f0092f4ca79ba66e05d1f0c3a01 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_find.h @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_FIND_H +#define _LIBCPP___ALGORITHM_RANGES_FIND_H + +#include <__algorithm/find.h> +#include <__algorithm/ranges_find_if.h> +#include <__algorithm/unwrap_range.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __find { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI static constexpr _Iter + __find_unwrap(_Iter __first, _Sent __last, const _Tp& __value, _Proj& __proj) { + if constexpr (forward_iterator<_Iter>) { + auto [__first_un, __last_un] = std::__unwrap_range(__first, std::move(__last)); + return std::__rewrap_range<_Sent>( + std::move(__first), std::__find(std::move(__first_un), std::move(__last_un), __value, __proj)); + } else { + return std::__find(std::move(__first), std::move(__last), __value, __proj); + } + } + + template _Sp, class _Tp, class _Proj = identity> + requires indirect_binary_predicate, const _Tp*> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip + operator()(_Ip __first, _Sp __last, const _Tp& __value, _Proj __proj = {}) const { + return __find_unwrap(std::move(__first), std::move(__last), __value, __proj); + } + + template + requires indirect_binary_predicate, _Proj>, const _Tp*> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Rp> + operator()(_Rp&& __r, const _Tp& __value, _Proj __proj = {}) const { + return __find_unwrap(ranges::begin(__r), ranges::end(__r), __value, __proj); + } +}; +} // namespace __find + +inline namespace __cpo { +inline constexpr auto find = __find::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_FIND_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_find_end.h b/libcxx/include/__cxx03/__algorithm/ranges_find_end.h new file mode 100644 index 0000000000000000000000000000000000000000..e49e66dd4ac04b86f395534b11c800c2a8043220 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_find_end.h @@ -0,0 +1,103 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_FIND_END_H +#define _LIBCPP___ALGORITHM_RANGES_FIND_END_H + +#include <__algorithm/find_end.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/ranges_iterator_concept.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/indirectly_comparable.h> +#include <__iterator/iterator_traits.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/subrange.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __find_end { +struct __fn { + template _Sent1, + forward_iterator _Iter2, + sentinel_for<_Iter2> _Sent2, + class _Pred = ranges::equal_to, + class _Proj1 = identity, + class _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter1> operator()( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred __pred = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + auto __ret = std::__find_end_impl<_RangeAlgPolicy>( + __first1, + __last1, + __first2, + __last2, + __pred, + __proj1, + __proj2, + __iterator_concept<_Iter1>(), + __iterator_concept<_Iter2>()); + return {__ret.first, __ret.second}; + } + + template + requires indirectly_comparable, iterator_t<_Range2>, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range1> operator()( + _Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { + auto __ret = std::__find_end_impl<_RangeAlgPolicy>( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + __pred, + __proj1, + __proj2, + __iterator_concept>(), + __iterator_concept>()); + return {__ret.first, __ret.second}; + } +}; +} // namespace __find_end + +inline namespace __cpo { +inline constexpr auto find_end = __find_end::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_FIND_END_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_find_first_of.h b/libcxx/include/__cxx03/__algorithm/ranges_find_first_of.h new file mode 100644 index 0000000000000000000000000000000000000000..d92d9686bc4420921c76ed170d19dff3a81f75c5 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_find_first_of.h @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_FIND_FIRST_OF_H +#define _LIBCPP___ALGORITHM_RANGES_FIND_FIRST_OF_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/indirectly_comparable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __find_first_of { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static _Iter1 __find_first_of_impl( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred& __pred, + _Proj1& __proj1, + _Proj2& __proj2) { + for (; __first1 != __last1; ++__first1) { + for (auto __j = __first2; __j != __last2; ++__j) { + if (std::invoke(__pred, std::invoke(__proj1, *__first1), std::invoke(__proj2, *__j))) + return __first1; + } + } + return __first1; + } + + template _Sent1, + forward_iterator _Iter2, + sentinel_for<_Iter2> _Sent2, + class _Pred = ranges::equal_to, + class _Proj1 = identity, + class _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Iter1 operator()( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred __pred = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + return __find_first_of_impl( + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __pred, __proj1, __proj2); + } + + template + requires indirectly_comparable, iterator_t<_Range2>, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range1> operator()( + _Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { + return __find_first_of_impl( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + __pred, + __proj1, + __proj2); + } +}; +} // namespace __find_first_of + +inline namespace __cpo { +inline constexpr auto find_first_of = __find_first_of::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_FIND_FIRST_OF_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_find_if.h b/libcxx/include/__cxx03/__algorithm/ranges_find_if.h new file mode 100644 index 0000000000000000000000000000000000000000..888f9ec3cb2d586328a5543ba04ae67502828f0b --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_find_if.h @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_FIND_IF_H +#define _LIBCPP___ALGORITHM_RANGES_FIND_IF_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +_LIBCPP_HIDE_FROM_ABI constexpr _Ip __find_if_impl(_Ip __first, _Sp __last, _Pred& __pred, _Proj& __proj) { + for (; __first != __last; ++__first) { + if (std::invoke(__pred, std::invoke(__proj, *__first))) + break; + } + return __first; +} + +namespace __find_if { +struct __fn { + template _Sp, + class _Proj = identity, + indirect_unary_predicate> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip + operator()(_Ip __first, _Sp __last, _Pred __pred, _Proj __proj = {}) const { + return ranges::__find_if_impl(std::move(__first), std::move(__last), __pred, __proj); + } + + template , _Proj>> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Rp> + operator()(_Rp&& __r, _Pred __pred, _Proj __proj = {}) const { + return ranges::__find_if_impl(ranges::begin(__r), ranges::end(__r), __pred, __proj); + } +}; +} // namespace __find_if + +inline namespace __cpo { +inline constexpr auto find_if = __find_if::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_FIND_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_find_if_not.h b/libcxx/include/__cxx03/__algorithm/ranges_find_if_not.h new file mode 100644 index 0000000000000000000000000000000000000000..ec19545b5a1b7a34e8d80c5aab070f51776f6bc0 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_find_if_not.h @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_FIND_IF_NOT_H +#define _LIBCPP___ALGORITHM_RANGES_FIND_IF_NOT_H + +#include <__algorithm/ranges_find_if.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __find_if_not { +struct __fn { + template _Sp, + class _Proj = identity, + indirect_unary_predicate> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip + operator()(_Ip __first, _Sp __last, _Pred __pred, _Proj __proj = {}) const { + auto __pred2 = [&](auto&& __e) -> bool { return !std::invoke(__pred, std::forward(__e)); }; + return ranges::__find_if_impl(std::move(__first), std::move(__last), __pred2, __proj); + } + + template , _Proj>> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Rp> + operator()(_Rp&& __r, _Pred __pred, _Proj __proj = {}) const { + auto __pred2 = [&](auto&& __e) -> bool { return !std::invoke(__pred, std::forward(__e)); }; + return ranges::__find_if_impl(ranges::begin(__r), ranges::end(__r), __pred2, __proj); + } +}; +} // namespace __find_if_not + +inline namespace __cpo { +inline constexpr auto find_if_not = __find_if_not::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_FIND_IF_NOT_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_find_last.h b/libcxx/include/__cxx03/__algorithm/ranges_find_last.h new file mode 100644 index 0000000000000000000000000000000000000000..95f7e77b8ccbeac28cc404efe2ea15a0e6d27327 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_find_last.h @@ -0,0 +1,175 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_FIND_LAST_H +#define _LIBCPP___ALGORITHM_RANGES_FIND_LAST_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/indirectly_comparable.h> +#include <__iterator/next.h> +#include <__iterator/prev.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/subrange.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +_LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter> +__find_last_impl(_Iter __first, _Sent __last, _Pred __pred, _Proj& __proj) { + if (__first == __last) { + return subrange<_Iter>(__first, __first); + } + + if constexpr (bidirectional_iterator<_Iter>) { + auto __last_it = ranges::next(__first, __last); + for (auto __it = ranges::prev(__last_it); __it != __first; --__it) { + if (__pred(std::invoke(__proj, *__it))) { + return subrange<_Iter>(std::move(__it), std::move(__last_it)); + } + } + if (__pred(std::invoke(__proj, *__first))) { + return subrange<_Iter>(std::move(__first), std::move(__last_it)); + } + return subrange<_Iter>(__last_it, __last_it); + } else { + bool __found = false; + _Iter __found_it; + for (; __first != __last; ++__first) { + if (__pred(std::invoke(__proj, *__first))) { + __found = true; + __found_it = __first; + } + } + + if (__found) { + return subrange<_Iter>(std::move(__found_it), std::move(__first)); + } else { + return subrange<_Iter>(__first, __first); + } + } +} + +namespace __find_last { +struct __fn { + template + struct __op { + const _Type& __value; + template + _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator()(_Elem&& __elem) const { + return std::forward<_Elem>(__elem) == __value; + } + }; + + template _Sent, class _Type, class _Proj = identity> + requires indirect_binary_predicate, const _Type*> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static subrange<_Iter> + operator()(_Iter __first, _Sent __last, const _Type& __value, _Proj __proj = {}) { + return ranges::__find_last_impl(std::move(__first), std::move(__last), __op<_Type>{__value}, __proj); + } + + template + requires indirect_binary_predicate, _Proj>, const _Type*> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static borrowed_subrange_t<_Range> + operator()(_Range&& __range, const _Type& __value, _Proj __proj = {}) { + return ranges::__find_last_impl(ranges::begin(__range), ranges::end(__range), __op<_Type>{__value}, __proj); + } +}; +} // namespace __find_last + +namespace __find_last_if { +struct __fn { + template + struct __op { + _Pred& __pred; + template + _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator()(_Elem&& __elem) const { + return std::invoke(__pred, std::forward<_Elem>(__elem)); + } + }; + + template _Sent, + class _Proj = identity, + indirect_unary_predicate> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static subrange<_Iter> + operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) { + return ranges::__find_last_impl(std::move(__first), std::move(__last), __op<_Pred>{__pred}, __proj); + } + + template , _Proj>> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static borrowed_subrange_t<_Range> + operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) { + return ranges::__find_last_impl(ranges::begin(__range), ranges::end(__range), __op<_Pred>{__pred}, __proj); + } +}; +} // namespace __find_last_if + +namespace __find_last_if_not { +struct __fn { + template + struct __op { + _Pred& __pred; + template + _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator()(_Elem&& __elem) const { + return !std::invoke(__pred, std::forward<_Elem>(__elem)); + } + }; + + template _Sent, + class _Proj = identity, + indirect_unary_predicate> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static subrange<_Iter> + operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) { + return ranges::__find_last_impl(std::move(__first), std::move(__last), __op<_Pred>{__pred}, __proj); + } + + template , _Proj>> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static borrowed_subrange_t<_Range> + operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) { + return ranges::__find_last_impl(ranges::begin(__range), ranges::end(__range), __op<_Pred>{__pred}, __proj); + } +}; +} // namespace __find_last_if_not + +inline namespace __cpo { +inline constexpr auto find_last = __find_last::__fn{}; +inline constexpr auto find_last_if = __find_last_if::__fn{}; +inline constexpr auto find_last_if_not = __find_last_if_not::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_FIND_LAST_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_for_each.h b/libcxx/include/__cxx03/__algorithm/ranges_for_each.h new file mode 100644 index 0000000000000000000000000000000000000000..225dc774c8764aac0c168717aa5c4760c3872355 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_for_each.h @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_FOR_EACH_H +#define _LIBCPP___ALGORITHM_RANGES_FOR_EACH_H + +#include <__algorithm/in_fun_result.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using for_each_result = in_fun_result<_Iter, _Func>; + +namespace __for_each { +struct __fn { +private: + template + _LIBCPP_HIDE_FROM_ABI constexpr static for_each_result<_Iter, _Func> + __for_each_impl(_Iter __first, _Sent __last, _Func& __func, _Proj& __proj) { + for (; __first != __last; ++__first) + std::invoke(__func, std::invoke(__proj, *__first)); + return {std::move(__first), std::move(__func)}; + } + +public: + template _Sent, + class _Proj = identity, + indirectly_unary_invocable> _Func> + _LIBCPP_HIDE_FROM_ABI constexpr for_each_result<_Iter, _Func> + operator()(_Iter __first, _Sent __last, _Func __func, _Proj __proj = {}) const { + return __for_each_impl(std::move(__first), std::move(__last), __func, __proj); + } + + template , _Proj>> _Func> + _LIBCPP_HIDE_FROM_ABI constexpr for_each_result, _Func> + operator()(_Range&& __range, _Func __func, _Proj __proj = {}) const { + return __for_each_impl(ranges::begin(__range), ranges::end(__range), __func, __proj); + } +}; +} // namespace __for_each + +inline namespace __cpo { +inline constexpr auto for_each = __for_each::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_FOR_EACH_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_for_each_n.h b/libcxx/include/__cxx03/__algorithm/ranges_for_each_n.h new file mode 100644 index 0000000000000000000000000000000000000000..d1fdca34cc5a1934e85843e9680b8370e4e49a3a --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_for_each_n.h @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_FOR_EACH_N_H +#define _LIBCPP___ALGORITHM_RANGES_FOR_EACH_N_H + +#include <__algorithm/in_fun_result.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/projected.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using for_each_n_result = in_fun_result<_Iter, _Func>; + +namespace __for_each_n { +struct __fn { + template > _Func> + _LIBCPP_HIDE_FROM_ABI constexpr for_each_n_result<_Iter, _Func> + operator()(_Iter __first, iter_difference_t<_Iter> __count, _Func __func, _Proj __proj = {}) const { + while (__count-- > 0) { + std::invoke(__func, std::invoke(__proj, *__first)); + ++__first; + } + return {std::move(__first), std::move(__func)}; + } +}; +} // namespace __for_each_n + +inline namespace __cpo { +inline constexpr auto for_each_n = __for_each_n::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_FOR_EACH_N_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_generate.h b/libcxx/include/__cxx03/__algorithm/ranges_generate.h new file mode 100644 index 0000000000000000000000000000000000000000..e6467198e6ba2f7c3aac4dd4400262fde6f2d789 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_generate.h @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_GENERATE_H +#define _LIBCPP___ALGORITHM_RANGES_GENERATE_H + +#include <__concepts/constructible.h> +#include <__concepts/invocable.h> +#include <__config> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __generate { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static _OutIter __generate_fn_impl(_OutIter __first, _Sent __last, _Func& __gen) { + for (; __first != __last; ++__first) { + *__first = __gen(); + } + + return __first; + } + + template _Sent, copy_constructible _Func> + requires invocable<_Func&> && indirectly_writable<_OutIter, invoke_result_t<_Func&>> + _LIBCPP_HIDE_FROM_ABI constexpr _OutIter operator()(_OutIter __first, _Sent __last, _Func __gen) const { + return __generate_fn_impl(std::move(__first), std::move(__last), __gen); + } + + template + requires invocable<_Func&> && output_range<_Range, invoke_result_t<_Func&>> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> operator()(_Range&& __range, _Func __gen) const { + return __generate_fn_impl(ranges::begin(__range), ranges::end(__range), __gen); + } +}; + +} // namespace __generate + +inline namespace __cpo { +inline constexpr auto generate = __generate::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_GENERATE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_generate_n.h b/libcxx/include/__cxx03/__algorithm/ranges_generate_n.h new file mode 100644 index 0000000000000000000000000000000000000000..cd5fd7483ab2c6acc81f5ac15ba49d3f57979571 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_generate_n.h @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_GENERATE_N_H +#define _LIBCPP___ALGORITHM_RANGES_GENERATE_N_H + +#include <__concepts/constructible.h> +#include <__concepts/invocable.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iterator_traits.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __generate_n { + +struct __fn { + template + requires invocable<_Func&> && indirectly_writable<_OutIter, invoke_result_t<_Func&>> + _LIBCPP_HIDE_FROM_ABI constexpr _OutIter + operator()(_OutIter __first, iter_difference_t<_OutIter> __n, _Func __gen) const { + for (; __n > 0; --__n) { + *__first = __gen(); + ++__first; + } + + return __first; + } +}; + +} // namespace __generate_n + +inline namespace __cpo { +inline constexpr auto generate_n = __generate_n::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_GENERATE_N_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_includes.h b/libcxx/include/__cxx03/__algorithm/ranges_includes.h new file mode 100644 index 0000000000000000000000000000000000000000..c4c3b8ed088d313381e462e9b5135fc13e87cc59 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_includes.h @@ -0,0 +1,98 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_INCLUDES_H +#define _LIBCPP___ALGORITHM_RANGES_INCLUDES_H + +#include <__algorithm/includes.h> +#include <__algorithm/make_projected.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __includes { + +struct __fn { + template _Sent1, + input_iterator _Iter2, + sentinel_for<_Iter2> _Sent2, + class _Proj1 = identity, + class _Proj2 = identity, + indirect_strict_weak_order, projected<_Iter2, _Proj2>> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Comp __comp = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + return std::__includes( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__comp), + std::move(__proj1), + std::move(__proj2)); + } + + template , _Proj1>, projected, _Proj2>> + _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()( + _Range1&& __range1, _Range2&& __range2, _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { + return std::__includes( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + std::move(__comp), + std::move(__proj1), + std::move(__proj2)); + } +}; + +} // namespace __includes + +inline namespace __cpo { +inline constexpr auto includes = __includes::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_INCLUDES_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_inplace_merge.h b/libcxx/include/__cxx03/__algorithm/ranges_inplace_merge.h new file mode 100644 index 0000000000000000000000000000000000000000..d94c0ad4656776eedc025ff69015c81255688297 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_inplace_merge.h @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_INPLACE_MERGE_H +#define _LIBCPP___ALGORITHM_RANGES_INPLACE_MERGE_H + +#include <__algorithm/inplace_merge.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/projected.h> +#include <__iterator/sortable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __inplace_merge { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __inplace_merge_impl(_Iter __first, _Iter __middle, _Sent __last, _Comp&& __comp, _Proj&& __proj) { + auto __last_iter = ranges::next(__middle, __last); + std::__inplace_merge<_RangeAlgPolicy>( + std::move(__first), std::move(__middle), __last_iter, std::__make_projected(__comp, __proj)); + return __last_iter; + } + + template _Sent, class _Comp = ranges::less, class _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI _Iter + operator()(_Iter __first, _Iter __middle, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + return __inplace_merge_impl( + std::move(__first), std::move(__middle), std::move(__last), std::move(__comp), std::move(__proj)); + } + + template + requires sortable, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI borrowed_iterator_t<_Range> + operator()(_Range&& __range, iterator_t<_Range> __middle, _Comp __comp = {}, _Proj __proj = {}) const { + return __inplace_merge_impl( + ranges::begin(__range), std::move(__middle), ranges::end(__range), std::move(__comp), std::move(__proj)); + } +}; + +} // namespace __inplace_merge + +inline namespace __cpo { +inline constexpr auto inplace_merge = __inplace_merge::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_INPLACE_MERGE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_is_heap.h b/libcxx/include/__cxx03/__algorithm/ranges_is_heap.h new file mode 100644 index 0000000000000000000000000000000000000000..3d9e18ce1d9067806dd7acfda121caebe472fc35 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_is_heap.h @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_IS_HEAP_H +#define _LIBCPP___ALGORITHM_RANGES_IS_HEAP_H + +#include <__algorithm/is_heap_until.h> +#include <__algorithm/make_projected.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __is_heap { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static bool + __is_heap_fn_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) { + auto __last_iter = ranges::next(__first, __last); + auto&& __projected_comp = std::__make_projected(__comp, __proj); + + auto __result = std::__is_heap_until(std::move(__first), std::move(__last_iter), __projected_comp); + return __result == __last; + } + + template _Sent, + class _Proj = identity, + indirect_strict_weak_order> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + return __is_heap_fn_impl(std::move(__first), std::move(__last), __comp, __proj); + } + + template , _Proj>> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const { + return __is_heap_fn_impl(ranges::begin(__range), ranges::end(__range), __comp, __proj); + } +}; + +} // namespace __is_heap + +inline namespace __cpo { +inline constexpr auto is_heap = __is_heap::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_IS_HEAP_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_is_heap_until.h b/libcxx/include/__cxx03/__algorithm/ranges_is_heap_until.h new file mode 100644 index 0000000000000000000000000000000000000000..7a2e1fc7705b6fd81cb6e0f4a50915c805422236 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_is_heap_until.h @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_IS_HEAP_UNTIL_H +#define _LIBCPP___ALGORITHM_RANGES_IS_HEAP_UNTIL_H + +#include <__algorithm/is_heap_until.h> +#include <__algorithm/make_projected.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __is_heap_until { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static _Iter + __is_heap_until_fn_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) { + auto __last_iter = ranges::next(__first, __last); + auto&& __projected_comp = std::__make_projected(__comp, __proj); + + return std::__is_heap_until(std::move(__first), std::move(__last_iter), __projected_comp); + } + + template _Sent, + class _Proj = identity, + indirect_strict_weak_order> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Iter + operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + return __is_heap_until_fn_impl(std::move(__first), std::move(__last), __comp, __proj); + } + + template , _Proj>> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const { + return __is_heap_until_fn_impl(ranges::begin(__range), ranges::end(__range), __comp, __proj); + } +}; + +} // namespace __is_heap_until + +inline namespace __cpo { +inline constexpr auto is_heap_until = __is_heap_until::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_IS_HEAP_UNTIL_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_is_partitioned.h b/libcxx/include/__cxx03/__algorithm/ranges_is_partitioned.h new file mode 100644 index 0000000000000000000000000000000000000000..5be6fba46fd9e247689594a7977d9637ea354114 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_is_partitioned.h @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_IS_PARTITIONED_H +#define _LIBCPP___ALGORITHM_RANGES_IS_PARTITIONED_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/indirectly_comparable.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __is_partitioned { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static bool + __is_partitioned_impl(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) { + for (; __first != __last; ++__first) { + if (!std::invoke(__pred, std::invoke(__proj, *__first))) + break; + } + + if (__first == __last) + return true; + ++__first; + + for (; __first != __last; ++__first) { + if (std::invoke(__pred, std::invoke(__proj, *__first))) + return false; + } + + return true; + } + + template _Sent, + class _Proj = identity, + indirect_unary_predicate> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { + return __is_partitioned_impl(std::move(__first), std::move(__last), __pred, __proj); + } + + template , _Proj>> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const { + return __is_partitioned_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj); + } +}; +} // namespace __is_partitioned + +inline namespace __cpo { +inline constexpr auto is_partitioned = __is_partitioned::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_IS_PARTITIONED_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_is_permutation.h b/libcxx/include/__cxx03/__algorithm/ranges_is_permutation.h new file mode 100644 index 0000000000000000000000000000000000000000..1f8d67007a573820c2697c938bf668083746ced0 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_is_permutation.h @@ -0,0 +1,107 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_IS_PERMUTATION_H +#define _LIBCPP___ALGORITHM_RANGES_IS_PERMUTATION_H + +#include <__algorithm/is_permutation.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __is_permutation { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static bool __is_permutation_func_impl( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred& __pred, + _Proj1& __proj1, + _Proj2& __proj2) { + return std::__is_permutation<_RangeAlgPolicy>( + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __pred, __proj1, __proj2); + } + + template < + forward_iterator _Iter1, + sentinel_for<_Iter1> _Sent1, + forward_iterator _Iter2, + sentinel_for<_Iter2> _Sent2, + class _Proj1 = identity, + class _Proj2 = identity, + indirect_equivalence_relation, projected<_Iter2, _Proj2>> _Pred = ranges::equal_to> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred __pred = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + return __is_permutation_func_impl( + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __pred, __proj1, __proj2); + } + + template , _Proj1>, + projected, _Proj2>> _Pred = ranges::equal_to> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()( + _Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { + if constexpr (sized_range<_Range1> && sized_range<_Range2>) { + if (ranges::distance(__range1) != ranges::distance(__range2)) + return false; + } + + return __is_permutation_func_impl( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + __pred, + __proj1, + __proj2); + } +}; +} // namespace __is_permutation + +inline namespace __cpo { +inline constexpr auto is_permutation = __is_permutation::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_IS_PERMUTATION_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_is_sorted.h b/libcxx/include/__cxx03/__algorithm/ranges_is_sorted.h new file mode 100644 index 0000000000000000000000000000000000000000..5b88d422b4b091c8ec8e534ded75e1efb3995fe9 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_is_sorted.h @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP__ALGORITHM_RANGES_IS_SORTED_H +#define _LIBCPP__ALGORITHM_RANGES_IS_SORTED_H + +#include <__algorithm/ranges_is_sorted_until.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __is_sorted { +struct __fn { + template _Sent, + class _Proj = identity, + indirect_strict_weak_order> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + return ranges::__is_sorted_until_impl(std::move(__first), __last, __comp, __proj) == __last; + } + + template , _Proj>> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const { + auto __last = ranges::end(__range); + return ranges::__is_sorted_until_impl(ranges::begin(__range), __last, __comp, __proj) == __last; + } +}; +} // namespace __is_sorted + +inline namespace __cpo { +inline constexpr auto is_sorted = __is_sorted::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP__ALGORITHM_RANGES_IS_SORTED_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_is_sorted_until.h b/libcxx/include/__cxx03/__algorithm/ranges_is_sorted_until.h new file mode 100644 index 0000000000000000000000000000000000000000..54de530c8b2fd8bc3d9cc72fd6310616456270fc --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_is_sorted_until.h @@ -0,0 +1,82 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP__ALGORITHM_RANGES_IS_SORTED_UNTIL_H +#define _LIBCPP__ALGORITHM_RANGES_IS_SORTED_UNTIL_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +_LIBCPP_HIDE_FROM_ABI constexpr _Iter +__is_sorted_until_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) { + if (__first == __last) + return __first; + auto __i = __first; + while (++__i != __last) { + if (std::invoke(__comp, std::invoke(__proj, *__i), std::invoke(__proj, *__first))) + return __i; + __first = __i; + } + return __i; +} + +namespace __is_sorted_until { +struct __fn { + template _Sent, + class _Proj = identity, + indirect_strict_weak_order> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Iter + operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + return ranges::__is_sorted_until_impl(std::move(__first), std::move(__last), __comp, __proj); + } + + template , _Proj>> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const { + return ranges::__is_sorted_until_impl(ranges::begin(__range), ranges::end(__range), __comp, __proj); + } +}; +} // namespace __is_sorted_until + +inline namespace __cpo { +inline constexpr auto is_sorted_until = __is_sorted_until::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP__ALGORITHM_RANGES_IS_SORTED_UNTIL_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_iterator_concept.h b/libcxx/include/__cxx03/__algorithm/ranges_iterator_concept.h new file mode 100644 index 0000000000000000000000000000000000000000..2af891d3af005a11315f602bb67a02f6578649f8 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_iterator_concept.h @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_ITERATOR_CONCEPT_H +#define _LIBCPP___ALGORITHM_RANGES_ITERATOR_CONCEPT_H + +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/remove_cvref.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +consteval auto __get_iterator_concept() { + using _Iter = __remove_cvref_t<_IterMaybeQualified>; + + if constexpr (contiguous_iterator<_Iter>) + return contiguous_iterator_tag(); + else if constexpr (random_access_iterator<_Iter>) + return random_access_iterator_tag(); + else if constexpr (bidirectional_iterator<_Iter>) + return bidirectional_iterator_tag(); + else if constexpr (forward_iterator<_Iter>) + return forward_iterator_tag(); + else if constexpr (input_iterator<_Iter>) + return input_iterator_tag(); +} + +template +using __iterator_concept = decltype(__get_iterator_concept<_Iter>()); + +} // namespace ranges +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_ITERATOR_CONCEPT_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_lexicographical_compare.h b/libcxx/include/__cxx03/__algorithm/ranges_lexicographical_compare.h new file mode 100644 index 0000000000000000000000000000000000000000..6d82017e302a70b3f5022399517240867d5e08ed --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_lexicographical_compare.h @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_LEXICOGRAPHICAL_COMPARE_H +#define _LIBCPP___ALGORITHM_RANGES_LEXICOGRAPHICAL_COMPARE_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __lexicographical_compare { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static bool __lexicographical_compare_impl( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Comp& __comp, + _Proj1& __proj1, + _Proj2& __proj2) { + while (__first2 != __last2) { + if (__first1 == __last1 || std::invoke(__comp, std::invoke(__proj1, *__first1), std::invoke(__proj2, *__first2))) + return true; + if (std::invoke(__comp, std::invoke(__proj2, *__first2), std::invoke(__proj1, *__first1))) + return false; + ++__first1; + ++__first2; + } + return false; + } + + template _Sent1, + input_iterator _Iter2, + sentinel_for<_Iter2> _Sent2, + class _Proj1 = identity, + class _Proj2 = identity, + indirect_strict_weak_order, projected<_Iter2, _Proj2>> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Comp __comp = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + return __lexicographical_compare_impl( + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __comp, __proj1, __proj2); + } + + template , _Proj1>, projected, _Proj2>> + _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()( + _Range1&& __range1, _Range2&& __range2, _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { + return __lexicographical_compare_impl( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + __comp, + __proj1, + __proj2); + } +}; +} // namespace __lexicographical_compare + +inline namespace __cpo { +inline constexpr auto lexicographical_compare = __lexicographical_compare::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_LEXICOGRAPHICAL_COMPARE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_lower_bound.h b/libcxx/include/__cxx03/__algorithm/ranges_lower_bound.h new file mode 100644 index 0000000000000000000000000000000000000000..0651147e0424952f4fd82a76b35128f08e551964 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_lower_bound.h @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_LOWER_BOUND_H +#define _LIBCPP___ALGORITHM_RANGES_LOWER_BOUND_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/lower_bound.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/advance.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +namespace __lower_bound { +struct __fn { + template _Sent, + class _Type, + class _Proj = identity, + indirect_strict_weak_order> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Iter + operator()(_Iter __first, _Sent __last, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const { + return std::__lower_bound<_RangeAlgPolicy>(__first, __last, __value, __comp, __proj); + } + + template , _Proj>> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __r, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const { + return std::__lower_bound<_RangeAlgPolicy>(ranges::begin(__r), ranges::end(__r), __value, __comp, __proj); + } +}; +} // namespace __lower_bound + +inline namespace __cpo { +inline constexpr auto lower_bound = __lower_bound::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_LOWER_BOUND_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_make_heap.h b/libcxx/include/__cxx03/__algorithm/ranges_make_heap.h new file mode 100644 index 0000000000000000000000000000000000000000..fe9c024fbf8a83d1c41b8b844ca3b4b19314bb3a --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_make_heap.h @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_MAKE_HEAP_H +#define _LIBCPP___ALGORITHM_RANGES_MAKE_HEAP_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_heap.h> +#include <__algorithm/make_projected.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/projected.h> +#include <__iterator/sortable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __make_heap { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static _Iter + __make_heap_fn_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) { + auto __last_iter = ranges::next(__first, __last); + + auto&& __projected_comp = std::__make_projected(__comp, __proj); + std::__make_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp); + + return __last_iter; + } + + template _Sent, class _Comp = ranges::less, class _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr _Iter + operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + return __make_heap_fn_impl(std::move(__first), std::move(__last), __comp, __proj); + } + + template + requires sortable, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { + return __make_heap_fn_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj); + } +}; + +} // namespace __make_heap + +inline namespace __cpo { +inline constexpr auto make_heap = __make_heap::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_MAKE_HEAP_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_max.h b/libcxx/include/__cxx03/__algorithm/ranges_max.h new file mode 100644 index 0000000000000000000000000000000000000000..d0ee6f314b0c3f4a8258cc4bd8ecda05dd9ea477 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_max.h @@ -0,0 +1,103 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_MAX_H +#define _LIBCPP___ALGORITHM_RANGES_MAX_H + +#include <__algorithm/ranges_min_element.h> +#include <__assert> +#include <__concepts/copyable.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__type_traits/is_trivially_copyable.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __max { +struct __fn { + template > _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& + operator()(_LIBCPP_LIFETIMEBOUND const _Tp& __a, + _LIBCPP_LIFETIMEBOUND const _Tp& __b, + _Comp __comp = {}, + _Proj __proj = {}) const { + return std::invoke(__comp, std::invoke(__proj, __a), std::invoke(__proj, __b)) ? __b : __a; + } + + template > _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp + operator()(initializer_list<_Tp> __il, _Comp __comp = {}, _Proj __proj = {}) const { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __il.begin() != __il.end(), "initializer_list must contain at least one element"); + + auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) -> bool { return std::invoke(__comp, __rhs, __lhs); }; + return *ranges::__min_element_impl(__il.begin(), __il.end(), __comp_lhs_rhs_swapped, __proj); + } + + template , _Proj>> _Comp = ranges::less> + requires indirectly_copyable_storable, range_value_t<_Rp>*> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr range_value_t<_Rp> + operator()(_Rp&& __r, _Comp __comp = {}, _Proj __proj = {}) const { + auto __first = ranges::begin(__r); + auto __last = ranges::end(__r); + + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__first != __last, "range must contain at least one element"); + + if constexpr (forward_range<_Rp> && !__is_cheap_to_copy>) { + auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) -> bool { + return std::invoke(__comp, __rhs, __lhs); + }; + return *ranges::__min_element_impl(std::move(__first), std::move(__last), __comp_lhs_rhs_swapped, __proj); + } else { + range_value_t<_Rp> __result = *__first; + while (++__first != __last) { + if (std::invoke(__comp, std::invoke(__proj, __result), std::invoke(__proj, *__first))) + __result = *__first; + } + return __result; + } + } +}; +} // namespace __max + +inline namespace __cpo { +inline constexpr auto max = __max::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___ALGORITHM_RANGES_MAX_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_max_element.h b/libcxx/include/__cxx03/__algorithm/ranges_max_element.h new file mode 100644 index 0000000000000000000000000000000000000000..c577309271165be731e810098d7ffca0e0732f21 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_max_element.h @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_MAX_ELEMENT_H +#define _LIBCPP___ALGORITHM_RANGES_MAX_ELEMENT_H + +#include <__algorithm/ranges_min_element.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __max_element { +struct __fn { + template _Sp, + class _Proj = identity, + indirect_strict_weak_order> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip + operator()(_Ip __first, _Sp __last, _Comp __comp = {}, _Proj __proj = {}) const { + auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) -> bool { return std::invoke(__comp, __rhs, __lhs); }; + return ranges::__min_element_impl(__first, __last, __comp_lhs_rhs_swapped, __proj); + } + + template , _Proj>> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Rp> + operator()(_Rp&& __r, _Comp __comp = {}, _Proj __proj = {}) const { + auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) -> bool { return std::invoke(__comp, __rhs, __lhs); }; + return ranges::__min_element_impl(ranges::begin(__r), ranges::end(__r), __comp_lhs_rhs_swapped, __proj); + } +}; +} // namespace __max_element + +inline namespace __cpo { +inline constexpr auto max_element = __max_element::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_MAX_ELEMENT_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_merge.h b/libcxx/include/__cxx03/__algorithm/ranges_merge.h new file mode 100644 index 0000000000000000000000000000000000000000..bdf9a62d90bd247235936dfeb36b07131ddec9a6 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_merge.h @@ -0,0 +1,138 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_MERGE_H +#define _LIBCPP___ALGORITHM_RANGES_MERGE_H + +#include <__algorithm/in_in_out_result.h> +#include <__algorithm/ranges_copy.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/mergeable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using merge_result = in_in_out_result<_InIter1, _InIter2, _OutIter>; + +namespace __merge { + +template < class _InIter1, + class _Sent1, + class _InIter2, + class _Sent2, + class _OutIter, + class _Comp, + class _Proj1, + class _Proj2> +_LIBCPP_HIDE_FROM_ABI constexpr merge_result<__remove_cvref_t<_InIter1>, + __remove_cvref_t<_InIter2>, + __remove_cvref_t<_OutIter>> +__merge_impl(_InIter1&& __first1, + _Sent1&& __last1, + _InIter2&& __first2, + _Sent2&& __last2, + _OutIter&& __result, + _Comp&& __comp, + _Proj1&& __proj1, + _Proj2&& __proj2) { + for (; __first1 != __last1 && __first2 != __last2; ++__result) { + if (std::invoke(__comp, std::invoke(__proj2, *__first2), std::invoke(__proj1, *__first1))) { + *__result = *__first2; + ++__first2; + } else { + *__result = *__first1; + ++__first1; + } + } + auto __ret1 = ranges::copy(std::move(__first1), std::move(__last1), std::move(__result)); + auto __ret2 = ranges::copy(std::move(__first2), std::move(__last2), std::move(__ret1.out)); + return {std::move(__ret1.in), std::move(__ret2.in), std::move(__ret2.out)}; +} + +struct __fn { + template _Sent1, + input_iterator _InIter2, + sentinel_for<_InIter2> _Sent2, + weakly_incrementable _OutIter, + class _Comp = less, + class _Proj1 = identity, + class _Proj2 = identity> + requires mergeable<_InIter1, _InIter2, _OutIter, _Comp, _Proj1, _Proj2> + _LIBCPP_HIDE_FROM_ABI constexpr merge_result<_InIter1, _InIter2, _OutIter> operator()( + _InIter1 __first1, + _Sent1 __last1, + _InIter2 __first2, + _Sent2 __last2, + _OutIter __result, + _Comp __comp = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + return __merge::__merge_impl(__first1, __last1, __first2, __last2, __result, __comp, __proj1, __proj2); + } + + template + requires mergeable, iterator_t<_Range2>, _OutIter, _Comp, _Proj1, _Proj2> + _LIBCPP_HIDE_FROM_ABI constexpr merge_result, borrowed_iterator_t<_Range2>, _OutIter> + operator()(_Range1&& __range1, + _Range2&& __range2, + _OutIter __result, + _Comp __comp = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + return __merge::__merge_impl( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + __result, + __comp, + __proj1, + __proj2); + } +}; + +} // namespace __merge + +inline namespace __cpo { +inline constexpr auto merge = __merge::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_MERGE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_min.h b/libcxx/include/__cxx03/__algorithm/ranges_min.h new file mode 100644 index 0000000000000000000000000000000000000000..cc569d2a060c220c132b6ed7a0ae0f78d96fb6f6 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_min.h @@ -0,0 +1,95 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_MIN_H +#define _LIBCPP___ALGORITHM_RANGES_MIN_H + +#include <__algorithm/ranges_min_element.h> +#include <__assert> +#include <__concepts/copyable.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__type_traits/is_trivially_copyable.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __min { +struct __fn { + template > _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& + operator()(_LIBCPP_LIFETIMEBOUND const _Tp& __a, + _LIBCPP_LIFETIMEBOUND const _Tp& __b, + _Comp __comp = {}, + _Proj __proj = {}) const { + return std::invoke(__comp, std::invoke(__proj, __b), std::invoke(__proj, __a)) ? __b : __a; + } + + template > _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp + operator()(initializer_list<_Tp> __il, _Comp __comp = {}, _Proj __proj = {}) const { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __il.begin() != __il.end(), "initializer_list must contain at least one element"); + return *ranges::__min_element_impl(__il.begin(), __il.end(), __comp, __proj); + } + + template , _Proj>> _Comp = ranges::less> + requires indirectly_copyable_storable, range_value_t<_Rp>*> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr range_value_t<_Rp> + operator()(_Rp&& __r, _Comp __comp = {}, _Proj __proj = {}) const { + auto __first = ranges::begin(__r); + auto __last = ranges::end(__r); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__first != __last, "range must contain at least one element"); + if constexpr (forward_range<_Rp> && !__is_cheap_to_copy>) { + return *ranges::__min_element_impl(__first, __last, __comp, __proj); + } else { + range_value_t<_Rp> __result = *__first; + while (++__first != __last) { + if (std::invoke(__comp, std::invoke(__proj, *__first), std::invoke(__proj, __result))) + __result = *__first; + } + return __result; + } + } +}; +} // namespace __min + +inline namespace __cpo { +inline constexpr auto min = __min::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___ALGORITHM_RANGES_MIN_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_min_element.h b/libcxx/include/__cxx03/__algorithm/ranges_min_element.h new file mode 100644 index 0000000000000000000000000000000000000000..588ef258e26f5d746b347d01d4979b12c9bf6a14 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_min_element.h @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_MIN_ELEMENT_H +#define _LIBCPP___ALGORITHM_RANGES_MIN_ELEMENT_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +// TODO(ranges): `ranges::min_element` can now simply delegate to `std::__min_element`. +template +_LIBCPP_HIDE_FROM_ABI constexpr _Ip __min_element_impl(_Ip __first, _Sp __last, _Comp& __comp, _Proj& __proj) { + if (__first == __last) + return __first; + + _Ip __i = __first; + while (++__i != __last) + if (std::invoke(__comp, std::invoke(__proj, *__i), std::invoke(__proj, *__first))) + __first = __i; + return __first; +} + +namespace __min_element { +struct __fn { + template _Sp, + class _Proj = identity, + indirect_strict_weak_order> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip + operator()(_Ip __first, _Sp __last, _Comp __comp = {}, _Proj __proj = {}) const { + return ranges::__min_element_impl(__first, __last, __comp, __proj); + } + + template , _Proj>> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Rp> + operator()(_Rp&& __r, _Comp __comp = {}, _Proj __proj = {}) const { + return ranges::__min_element_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj); + } +}; +} // namespace __min_element + +inline namespace __cpo { +inline constexpr auto min_element = __min_element::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_MIN_ELEMENT_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_minmax.h b/libcxx/include/__cxx03/__algorithm/ranges_minmax.h new file mode 100644 index 0000000000000000000000000000000000000000..09cbefd91a8c77cc5b93d10894712998ef89dcb6 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_minmax.h @@ -0,0 +1,175 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_MINMAX_H +#define _LIBCPP___ALGORITHM_RANGES_MINMAX_H + +#include <__algorithm/min_max_result.h> +#include <__algorithm/minmax_element.h> +#include <__assert> +#include <__concepts/copyable.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/next.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__type_traits/desugars_to.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/is_trivially_copyable.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +template +using minmax_result = min_max_result<_T1>; + +namespace __minmax { +struct __fn { + template > _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr ranges::minmax_result + operator()(_LIBCPP_LIFETIMEBOUND const _Type& __a, + _LIBCPP_LIFETIMEBOUND const _Type& __b, + _Comp __comp = {}, + _Proj __proj = {}) const { + if (std::invoke(__comp, std::invoke(__proj, __b), std::invoke(__proj, __a))) + return {__b, __a}; + return {__a, __b}; + } + + template > _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr ranges::minmax_result<_Type> + operator()(initializer_list<_Type> __il, _Comp __comp = {}, _Proj __proj = {}) const { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __il.begin() != __il.end(), "initializer_list has to contain at least one element"); + auto __iters = std::__minmax_element_impl(__il.begin(), __il.end(), __comp, __proj); + return ranges::minmax_result<_Type>{*__iters.first, *__iters.second}; + } + + template , _Proj>> _Comp = ranges::less> + requires indirectly_copyable_storable, range_value_t<_Range>*> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr ranges::minmax_result> + operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { + auto __first = ranges::begin(__r); + auto __last = ranges::end(__r); + using _ValueT = range_value_t<_Range>; + + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__first != __last, "range has to contain at least one element"); + + // This optimiation is not in minmax_element because clang doesn't see through the pointers and as a result doesn't + // vectorize the code. + if constexpr (contiguous_range<_Range> && is_integral_v<_ValueT> && + __is_cheap_to_copy<_ValueT> & __is_identity<_Proj>::value && + __desugars_to_v<__less_tag, _Comp, _ValueT, _ValueT>) { + minmax_result<_ValueT> __result = {__r[0], __r[0]}; + for (auto __e : __r) { + if (__e < __result.min) + __result.min = __e; + if (__result.max < __e) + __result.max = __e; + } + return __result; + } else if constexpr (forward_range<_Range>) { + // Special-case the one element case. Avoid repeatedly initializing objects from the result of an iterator + // dereference when doing so might not be idempotent. The `if constexpr` avoids the extra branch in cases where + // it's not needed. + if constexpr (!same_as>, _ValueT> || + is_rvalue_reference_v>) { + if (ranges::next(__first) == __last) { + // During initialization, members are allowed to refer to already initialized members + // (see http://eel.is/c++draft/dcl.init.aggr#6) + minmax_result<_ValueT> __result = {*__first, __result.min}; + return __result; + } + } + auto __result = std::__minmax_element_impl(__first, __last, __comp, __proj); + return {*__result.first, *__result.second}; + } else { + // input_iterators can't be copied, so the implementation for input_iterators has to store + // the values instead of a pointer to the correct values + auto __less = [&](auto&& __a, auto&& __b) -> bool { + return std::invoke(__comp, + std::invoke(__proj, std::forward(__a)), + std::invoke(__proj, std::forward(__b))); + }; + + // During initialization, members are allowed to refer to already initialized members + // (see http://eel.is/c++draft/dcl.init.aggr#6) + ranges::minmax_result<_ValueT> __result = {*__first, __result.min}; + if (__first == __last || ++__first == __last) + return __result; + + if (__less(*__first, __result.min)) + __result.min = *__first; + else + __result.max = *__first; + + while (++__first != __last) { + _ValueT __i = *__first; + if (++__first == __last) { + if (__less(__i, __result.min)) + __result.min = __i; + else if (!__less(__i, __result.max)) + __result.max = __i; + return __result; + } + + if (__less(*__first, __i)) { + if (__less(*__first, __result.min)) + __result.min = *__first; + if (!__less(__i, __result.max)) + __result.max = std::move(__i); + } else { + if (__less(__i, __result.min)) + __result.min = std::move(__i); + if (!__less(*__first, __result.max)) + __result.max = *__first; + } + } + return __result; + } + } +}; +} // namespace __minmax + +inline namespace __cpo { +inline constexpr auto minmax = __minmax::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___ALGORITHM_RANGES_MINMAX_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_minmax_element.h b/libcxx/include/__cxx03/__algorithm/ranges_minmax_element.h new file mode 100644 index 0000000000000000000000000000000000000000..4bf6d2404e463d960bfed6ca4af3b9ffc8d5c754 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_minmax_element.h @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_MINMAX_ELEMENT_H +#define _LIBCPP___ALGORITHM_RANGES_MINMAX_ELEMENT_H + +#include <__algorithm/min_max_result.h> +#include <__algorithm/minmax_element.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using minmax_element_result = min_max_result<_T1>; + +namespace __minmax_element { +struct __fn { + template _Sp, + class _Proj = identity, + indirect_strict_weak_order> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr ranges::minmax_element_result<_Ip> + operator()(_Ip __first, _Sp __last, _Comp __comp = {}, _Proj __proj = {}) const { + auto __ret = std::__minmax_element_impl(std::move(__first), std::move(__last), __comp, __proj); + return {__ret.first, __ret.second}; + } + + template , _Proj>> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr ranges::minmax_element_result> + operator()(_Rp&& __r, _Comp __comp = {}, _Proj __proj = {}) const { + auto __ret = std::__minmax_element_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj); + return {__ret.first, __ret.second}; + } +}; +} // namespace __minmax_element + +inline namespace __cpo { +inline constexpr auto minmax_element = __minmax_element::__fn{}; +} // namespace __cpo + +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_MINMAX_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_mismatch.h b/libcxx/include/__cxx03/__algorithm/ranges_mismatch.h new file mode 100644 index 0000000000000000000000000000000000000000..c4bf0022a9bcc0dd335f388bd94c75ff15293096 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_mismatch.h @@ -0,0 +1,100 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_MISMATCH_H +#define _LIBCPP___ALGORITHM_RANGES_MISMATCH_H + +#include <__algorithm/in_in_result.h> +#include <__algorithm/mismatch.h> +#include <__algorithm/unwrap_range.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/indirectly_comparable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace ranges { + +template +using mismatch_result = in_in_result<_I1, _I2>; + +namespace __mismatch { +struct __fn { + template + static _LIBCPP_HIDE_FROM_ABI constexpr mismatch_result<_I1, _I2> + __go(_I1 __first1, _S1 __last1, _I2 __first2, _S2 __last2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { + if constexpr (forward_iterator<_I1> && forward_iterator<_I2>) { + auto __range1 = std::__unwrap_range(__first1, __last1); + auto __range2 = std::__unwrap_range(__first2, __last2); + auto __res = + std::__mismatch(__range1.first, __range1.second, __range2.first, __range2.second, __pred, __proj1, __proj2); + return {std::__rewrap_range<_S1>(__first1, __res.first), std::__rewrap_range<_S2>(__first2, __res.second)}; + } else { + auto __res = std::__mismatch( + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __pred, __proj1, __proj2); + return {std::move(__res.first), std::move(__res.second)}; + } + } + + template _S1, + input_iterator _I2, + sentinel_for<_I2> _S2, + class _Pred = ranges::equal_to, + class _Proj1 = identity, + class _Proj2 = identity> + requires indirectly_comparable<_I1, _I2, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr mismatch_result<_I1, _I2> operator()( + _I1 __first1, _S1 __last1, _I2 __first2, _S2 __last2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + const { + return __go(std::move(__first1), __last1, std::move(__first2), __last2, __pred, __proj1, __proj2); + } + + template + requires indirectly_comparable, iterator_t<_R2>, _Pred, _Proj1, _Proj2> + [[nodiscard]] + _LIBCPP_HIDE_FROM_ABI constexpr mismatch_result, borrowed_iterator_t<_R2>> + operator()(_R1&& __r1, _R2&& __r2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { + return __go( + ranges::begin(__r1), ranges::end(__r1), ranges::begin(__r2), ranges::end(__r2), __pred, __proj1, __proj2); + } +}; +} // namespace __mismatch + +inline namespace __cpo { +constexpr inline auto mismatch = __mismatch::__fn{}; +} // namespace __cpo +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_MISMATCH_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_move.h b/libcxx/include/__cxx03/__algorithm/ranges_move.h new file mode 100644 index 0000000000000000000000000000000000000000..be869f36c9730442e274c2c460fe0fa9ddebbc35 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_move.h @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_MOVE_H +#define _LIBCPP___ALGORITHM_RANGES_MOVE_H + +#include <__algorithm/in_out_result.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/move.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using move_result = in_out_result<_InIter, _OutIter>; + +namespace __move { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static move_result<_InIter, _OutIter> + __move_impl(_InIter __first, _Sent __last, _OutIter __result) { + auto __ret = std::__move<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__result)); + return {std::move(__ret.first), std::move(__ret.second)}; + } + + template _Sent, weakly_incrementable _OutIter> + requires indirectly_movable<_InIter, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr move_result<_InIter, _OutIter> + operator()(_InIter __first, _Sent __last, _OutIter __result) const { + return __move_impl(std::move(__first), std::move(__last), std::move(__result)); + } + + template + requires indirectly_movable, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr move_result, _OutIter> + operator()(_Range&& __range, _OutIter __result) const { + return __move_impl(ranges::begin(__range), ranges::end(__range), std::move(__result)); + } +}; +} // namespace __move + +inline namespace __cpo { +inline constexpr auto move = __move::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_MOVE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_move_backward.h b/libcxx/include/__cxx03/__algorithm/ranges_move_backward.h new file mode 100644 index 0000000000000000000000000000000000000000..6d4071a33b8125f0ac8322a15a9c06ee9546da7a --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_move_backward.h @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_MOVE_BACKWARD_H +#define _LIBCPP___ALGORITHM_RANGES_MOVE_BACKWARD_H + +#include <__algorithm/in_out_result.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/move_backward.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/iter_move.h> +#include <__iterator/next.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using move_backward_result = in_out_result<_InIter, _OutIter>; + +namespace __move_backward { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static move_backward_result<_InIter, _OutIter> + __move_backward_impl(_InIter __first, _Sent __last, _OutIter __result) { + auto __ret = std::__move_backward<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__result)); + return {std::move(__ret.first), std::move(__ret.second)}; + } + + template _Sent, bidirectional_iterator _OutIter> + requires indirectly_movable<_InIter, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr move_backward_result<_InIter, _OutIter> + operator()(_InIter __first, _Sent __last, _OutIter __result) const { + return __move_backward_impl(std::move(__first), std::move(__last), std::move(__result)); + } + + template + requires indirectly_movable, _Iter> + _LIBCPP_HIDE_FROM_ABI constexpr move_backward_result, _Iter> + operator()(_Range&& __range, _Iter __result) const { + return __move_backward_impl(ranges::begin(__range), ranges::end(__range), std::move(__result)); + } +}; +} // namespace __move_backward + +inline namespace __cpo { +inline constexpr auto move_backward = __move_backward::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_MOVE_BACKWARD_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_next_permutation.h b/libcxx/include/__cxx03/__algorithm/ranges_next_permutation.h new file mode 100644 index 0000000000000000000000000000000000000000..18535e0a6254a1eaeeacb18541d9abc8c1b83f2b --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_next_permutation.h @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_NEXT_PERMUTATION_H +#define _LIBCPP___ALGORITHM_RANGES_NEXT_PERMUTATION_H + +#include <__algorithm/in_found_result.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/next_permutation.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/sortable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using next_permutation_result = in_found_result<_InIter>; + +namespace __next_permutation { + +struct __fn { + template _Sent, class _Comp = ranges::less, class _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr next_permutation_result<_Iter> + operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + auto __result = std::__next_permutation<_RangeAlgPolicy>( + std::move(__first), std::move(__last), std::__make_projected(__comp, __proj)); + return {std::move(__result.first), std::move(__result.second)}; + } + + template + requires sortable, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr next_permutation_result> + operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const { + auto __result = std::__next_permutation<_RangeAlgPolicy>( + ranges::begin(__range), ranges::end(__range), std::__make_projected(__comp, __proj)); + return {std::move(__result.first), std::move(__result.second)}; + } +}; + +} // namespace __next_permutation + +inline namespace __cpo { +constexpr inline auto next_permutation = __next_permutation::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_NEXT_PERMUTATION_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_none_of.h b/libcxx/include/__cxx03/__algorithm/ranges_none_of.h new file mode 100644 index 0000000000000000000000000000000000000000..7df3c1829fcfcb990ff2bbc728b8e9fc07ab2b40 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_none_of.h @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_NONE_OF_H +#define _LIBCPP___ALGORITHM_RANGES_NONE_OF_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __none_of { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static bool + __none_of_impl(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) { + for (; __first != __last; ++__first) { + if (std::invoke(__pred, std::invoke(__proj, *__first))) + return false; + } + return true; + } + + template _Sent, + class _Proj = identity, + indirect_unary_predicate> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Iter __first, _Sent __last, _Pred __pred = {}, _Proj __proj = {}) const { + return __none_of_impl(std::move(__first), std::move(__last), __pred, __proj); + } + + template , _Proj>> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const { + return __none_of_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj); + } +}; +} // namespace __none_of + +inline namespace __cpo { +inline constexpr auto none_of = __none_of::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_NONE_OF_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_nth_element.h b/libcxx/include/__cxx03/__algorithm/ranges_nth_element.h new file mode 100644 index 0000000000000000000000000000000000000000..90ade9efe10da6fcdc194f1631cc4fa3f9478cb1 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_nth_element.h @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_NTH_ELEMENT_H +#define _LIBCPP___ALGORITHM_RANGES_NTH_ELEMENT_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/nth_element.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/projected.h> +#include <__iterator/sortable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __nth_element { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static _Iter + __nth_element_fn_impl(_Iter __first, _Iter __nth, _Sent __last, _Comp& __comp, _Proj& __proj) { + auto __last_iter = ranges::next(__first, __last); + + auto&& __projected_comp = std::__make_projected(__comp, __proj); + std::__nth_element_impl<_RangeAlgPolicy>(std::move(__first), std::move(__nth), __last_iter, __projected_comp); + + return __last_iter; + } + + template _Sent, class _Comp = ranges::less, class _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr _Iter + operator()(_Iter __first, _Iter __nth, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + return __nth_element_fn_impl(std::move(__first), std::move(__nth), std::move(__last), __comp, __proj); + } + + template + requires sortable, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __r, iterator_t<_Range> __nth, _Comp __comp = {}, _Proj __proj = {}) const { + return __nth_element_fn_impl(ranges::begin(__r), std::move(__nth), ranges::end(__r), __comp, __proj); + } +}; + +} // namespace __nth_element + +inline namespace __cpo { +inline constexpr auto nth_element = __nth_element::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_NTH_ELEMENT_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_partial_sort.h b/libcxx/include/__cxx03/__algorithm/ranges_partial_sort.h new file mode 100644 index 0000000000000000000000000000000000000000..c67247d2e0a77ea2fef4bce2a326c2c30b228ae2 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_partial_sort.h @@ -0,0 +1,82 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_PARTIAL_SORT_H +#define _LIBCPP___ALGORITHM_RANGES_PARTIAL_SORT_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/partial_sort.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/projected.h> +#include <__iterator/sortable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __partial_sort { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static _Iter + __partial_sort_fn_impl(_Iter __first, _Iter __middle, _Sent __last, _Comp& __comp, _Proj& __proj) { + auto&& __projected_comp = std::__make_projected(__comp, __proj); + return std::__partial_sort<_RangeAlgPolicy>(std::move(__first), std::move(__middle), __last, __projected_comp); + } + + template _Sent, class _Comp = ranges::less, class _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr _Iter + operator()(_Iter __first, _Iter __middle, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + return __partial_sort_fn_impl(std::move(__first), std::move(__middle), std::move(__last), __comp, __proj); + } + + template + requires sortable, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __r, iterator_t<_Range> __middle, _Comp __comp = {}, _Proj __proj = {}) const { + return __partial_sort_fn_impl(ranges::begin(__r), std::move(__middle), ranges::end(__r), __comp, __proj); + } +}; + +} // namespace __partial_sort + +inline namespace __cpo { +inline constexpr auto partial_sort = __partial_sort::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_PARTIAL_SORT_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_partial_sort_copy.h b/libcxx/include/__cxx03/__algorithm/ranges_partial_sort_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..b3bdeb78fb6f65f9255bd9c1cc6ca1b10a8bd022 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_partial_sort_copy.h @@ -0,0 +1,114 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_PARTIAL_SORT_COPY_H +#define _LIBCPP___ALGORITHM_RANGES_PARTIAL_SORT_COPY_H + +#include <__algorithm/in_out_result.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/partial_sort_copy.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/projected.h> +#include <__iterator/sortable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using partial_sort_copy_result = in_out_result<_InIter, _OutIter>; + +namespace __partial_sort_copy { + +struct __fn { + template _Sent1, + random_access_iterator _Iter2, + sentinel_for<_Iter2> _Sent2, + class _Comp = ranges::less, + class _Proj1 = identity, + class _Proj2 = identity> + requires indirectly_copyable<_Iter1, _Iter2> && sortable<_Iter2, _Comp, _Proj2> && + indirect_strict_weak_order<_Comp, projected<_Iter1, _Proj1>, projected<_Iter2, _Proj2>> + _LIBCPP_HIDE_FROM_ABI constexpr partial_sort_copy_result<_Iter1, _Iter2> operator()( + _Iter1 __first, + _Sent1 __last, + _Iter2 __result_first, + _Sent2 __result_last, + _Comp __comp = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + auto __result = std::__partial_sort_copy<_RangeAlgPolicy>( + std::move(__first), + std::move(__last), + std::move(__result_first), + std::move(__result_last), + __comp, + __proj1, + __proj2); + return {std::move(__result.first), std::move(__result.second)}; + } + + template + requires indirectly_copyable, iterator_t<_Range2>> && + sortable, _Comp, _Proj2> && + indirect_strict_weak_order<_Comp, + projected, _Proj1>, + projected, _Proj2>> + _LIBCPP_HIDE_FROM_ABI constexpr partial_sort_copy_result, borrowed_iterator_t<_Range2>> + operator()( + _Range1&& __range, _Range2&& __result_range, _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { + auto __result = std::__partial_sort_copy<_RangeAlgPolicy>( + ranges::begin(__range), + ranges::end(__range), + ranges::begin(__result_range), + ranges::end(__result_range), + __comp, + __proj1, + __proj2); + return {std::move(__result.first), std::move(__result.second)}; + } +}; + +} // namespace __partial_sort_copy + +inline namespace __cpo { +inline constexpr auto partial_sort_copy = __partial_sort_copy::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_PARTIAL_SORT_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_partition.h b/libcxx/include/__cxx03/__algorithm/ranges_partition.h new file mode 100644 index 0000000000000000000000000000000000000000..a67ac4c967570f8f7a8f0eee76761e8efa0a77eb --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_partition.h @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_PARTITION_H +#define _LIBCPP___ALGORITHM_RANGES_PARTITION_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/partition.h> +#include <__algorithm/ranges_iterator_concept.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/permutable.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/subrange.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __partition { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI static constexpr subrange<__remove_cvref_t<_Iter>> + __partition_fn_impl(_Iter&& __first, _Sent&& __last, _Pred&& __pred, _Proj&& __proj) { + auto&& __projected_pred = std::__make_projected(__pred, __proj); + auto __result = std::__partition<_RangeAlgPolicy>( + std::move(__first), std::move(__last), __projected_pred, __iterator_concept<_Iter>()); + + return {std::move(__result.first), std::move(__result.second)}; + } + + template _Sent, + class _Proj = identity, + indirect_unary_predicate> _Pred> + _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter> + operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { + return __partition_fn_impl(__first, __last, __pred, __proj); + } + + template , _Proj>> _Pred> + requires permutable> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range> + operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const { + return __partition_fn_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj); + } +}; + +} // namespace __partition + +inline namespace __cpo { +inline constexpr auto partition = __partition::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_PARTITION_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_partition_copy.h b/libcxx/include/__cxx03/__algorithm/ranges_partition_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..d60c865dd2a8a33ac9e66aff73179d8e34e4b4c8 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_partition_copy.h @@ -0,0 +1,110 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_PARTITION_COPY_H +#define _LIBCPP___ALGORITHM_RANGES_PARTITION_COPY_H + +#include <__algorithm/in_out_out_result.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using partition_copy_result = in_out_out_result<_InIter, _OutIter1, _OutIter2>; + +namespace __partition_copy { + +struct __fn { + // TODO(ranges): delegate to the classic algorithm. + template + _LIBCPP_HIDE_FROM_ABI constexpr static partition_copy_result<__remove_cvref_t<_InIter>, + __remove_cvref_t<_OutIter1>, + __remove_cvref_t<_OutIter2> > + __partition_copy_fn_impl( + _InIter&& __first, + _Sent&& __last, + _OutIter1&& __out_true, + _OutIter2&& __out_false, + _Pred& __pred, + _Proj& __proj) { + for (; __first != __last; ++__first) { + if (std::invoke(__pred, std::invoke(__proj, *__first))) { + *__out_true = *__first; + ++__out_true; + + } else { + *__out_false = *__first; + ++__out_false; + } + } + + return {std::move(__first), std::move(__out_true), std::move(__out_false)}; + } + + template _Sent, + weakly_incrementable _OutIter1, + weakly_incrementable _OutIter2, + class _Proj = identity, + indirect_unary_predicate> _Pred> + requires indirectly_copyable<_InIter, _OutIter1> && indirectly_copyable<_InIter, _OutIter2> + _LIBCPP_HIDE_FROM_ABI constexpr partition_copy_result<_InIter, _OutIter1, _OutIter2> operator()( + _InIter __first, _Sent __last, _OutIter1 __out_true, _OutIter2 __out_false, _Pred __pred, _Proj __proj = {}) + const { + return __partition_copy_fn_impl( + std::move(__first), std::move(__last), std::move(__out_true), std::move(__out_false), __pred, __proj); + } + + template , _Proj>> _Pred> + requires indirectly_copyable, _OutIter1> && indirectly_copyable, _OutIter2> + _LIBCPP_HIDE_FROM_ABI constexpr partition_copy_result, _OutIter1, _OutIter2> + operator()(_Range&& __range, _OutIter1 __out_true, _OutIter2 __out_false, _Pred __pred, _Proj __proj = {}) const { + return __partition_copy_fn_impl( + ranges::begin(__range), ranges::end(__range), std::move(__out_true), std::move(__out_false), __pred, __proj); + } +}; + +} // namespace __partition_copy + +inline namespace __cpo { +inline constexpr auto partition_copy = __partition_copy::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_PARTITION_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_partition_point.h b/libcxx/include/__cxx03/__algorithm/ranges_partition_point.h new file mode 100644 index 0000000000000000000000000000000000000000..c5b11b5fed192a3140b3bb3ba490bfb4280d889d --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_partition_point.h @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_PARTITION_POINT_H +#define _LIBCPP___ALGORITHM_RANGES_PARTITION_POINT_H + +#include <__algorithm/half_positive.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __partition_point { + +struct __fn { + // TODO(ranges): delegate to the classic algorithm. + template + _LIBCPP_HIDE_FROM_ABI constexpr static _Iter + __partition_point_fn_impl(_Iter&& __first, _Sent&& __last, _Pred& __pred, _Proj& __proj) { + auto __len = ranges::distance(__first, __last); + + while (__len != 0) { + auto __half_len = std::__half_positive(__len); + auto __mid = ranges::next(__first, __half_len); + + if (std::invoke(__pred, std::invoke(__proj, *__mid))) { + __first = ++__mid; + __len -= __half_len + 1; + + } else { + __len = __half_len; + } + } + + return __first; + } + + template _Sent, + class _Proj = identity, + indirect_unary_predicate> _Pred> + _LIBCPP_HIDE_FROM_ABI constexpr _Iter operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { + return __partition_point_fn_impl(std::move(__first), std::move(__last), __pred, __proj); + } + + template , _Proj>> _Pred> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const { + return __partition_point_fn_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj); + } +}; + +} // namespace __partition_point + +inline namespace __cpo { +inline constexpr auto partition_point = __partition_point::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_PARTITION_POINT_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_pop_heap.h b/libcxx/include/__cxx03/__algorithm/ranges_pop_heap.h new file mode 100644 index 0000000000000000000000000000000000000000..01f92c0f228887524263f2f4b731ec9350074ab6 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_pop_heap.h @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_POP_HEAP_H +#define _LIBCPP___ALGORITHM_RANGES_POP_HEAP_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/pop_heap.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/projected.h> +#include <__iterator/sortable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __pop_heap { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static _Iter + __pop_heap_fn_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) { + auto __last_iter = ranges::next(__first, __last); + auto __len = __last_iter - __first; + + auto&& __projected_comp = std::__make_projected(__comp, __proj); + std::__pop_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp, __len); + + return __last_iter; + } + + template _Sent, class _Comp = ranges::less, class _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr _Iter + operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + return __pop_heap_fn_impl(std::move(__first), std::move(__last), __comp, __proj); + } + + template + requires sortable, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { + return __pop_heap_fn_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj); + } +}; + +} // namespace __pop_heap + +inline namespace __cpo { +inline constexpr auto pop_heap = __pop_heap::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_POP_HEAP_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_prev_permutation.h b/libcxx/include/__cxx03/__algorithm/ranges_prev_permutation.h new file mode 100644 index 0000000000000000000000000000000000000000..225cee9b75ec6b4418d7333db94ddd10a25ed24a --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_prev_permutation.h @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_PREV_PERMUTATION_H +#define _LIBCPP___ALGORITHM_RANGES_PREV_PERMUTATION_H + +#include <__algorithm/in_found_result.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/prev_permutation.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/sortable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using prev_permutation_result = in_found_result<_InIter>; + +namespace __prev_permutation { + +struct __fn { + template _Sent, class _Comp = ranges::less, class _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr prev_permutation_result<_Iter> + operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + auto __result = std::__prev_permutation<_RangeAlgPolicy>( + std::move(__first), std::move(__last), std::__make_projected(__comp, __proj)); + return {std::move(__result.first), std::move(__result.second)}; + } + + template + requires sortable, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr prev_permutation_result> + operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const { + auto __result = std::__prev_permutation<_RangeAlgPolicy>( + ranges::begin(__range), ranges::end(__range), std::__make_projected(__comp, __proj)); + return {std::move(__result.first), std::move(__result.second)}; + } +}; + +} // namespace __prev_permutation + +inline namespace __cpo { +constexpr inline auto prev_permutation = __prev_permutation::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_PREV_PERMUTATION_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_push_heap.h b/libcxx/include/__cxx03/__algorithm/ranges_push_heap.h new file mode 100644 index 0000000000000000000000000000000000000000..9d187af38c53194ba01366837cba125a388ad0d9 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_push_heap.h @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_PUSH_HEAP_H +#define _LIBCPP___ALGORITHM_RANGES_PUSH_HEAP_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/push_heap.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/projected.h> +#include <__iterator/sortable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __push_heap { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static _Iter + __push_heap_fn_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) { + auto __last_iter = ranges::next(__first, __last); + + auto&& __projected_comp = std::__make_projected(__comp, __proj); + std::__push_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp); + + return __last_iter; + } + + template _Sent, class _Comp = ranges::less, class _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr _Iter + operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + return __push_heap_fn_impl(std::move(__first), std::move(__last), __comp, __proj); + } + + template + requires sortable, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { + return __push_heap_fn_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj); + } +}; + +} // namespace __push_heap + +inline namespace __cpo { +inline constexpr auto push_heap = __push_heap::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_PUSH_HEAP_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_remove.h b/libcxx/include/__cxx03/__algorithm/ranges_remove.h new file mode 100644 index 0000000000000000000000000000000000000000..17c3a2c5cd06b6f57a3d1fb4a7d5814e8f1d3936 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_remove.h @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_REMOVE_H +#define _LIBCPP___ALGORITHM_RANGES_REMOVE_H +#include <__config> + +#include <__algorithm/ranges_remove_if.h> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/permutable.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/subrange.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __remove { +struct __fn { + template _Sent, class _Type, class _Proj = identity> + requires indirect_binary_predicate, const _Type*> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter> + operator()(_Iter __first, _Sent __last, const _Type& __value, _Proj __proj = {}) const { + auto __pred = [&](auto&& __other) -> bool { return __value == __other; }; + return ranges::__remove_if_impl(std::move(__first), std::move(__last), __pred, __proj); + } + + template + requires permutable> && + indirect_binary_predicate, _Proj>, const _Type*> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range> + operator()(_Range&& __range, const _Type& __value, _Proj __proj = {}) const { + auto __pred = [&](auto&& __other) -> bool { return __value == __other; }; + return ranges::__remove_if_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj); + } +}; +} // namespace __remove + +inline namespace __cpo { +inline constexpr auto remove = __remove::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_REMOVE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_remove_copy.h b/libcxx/include/__cxx03/__algorithm/ranges_remove_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..84529eceac68c5bcab3fa95271b3f91a358e81bc --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_remove_copy.h @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_REMOVE_COPY_H +#define _LIBCPP___ALGORITHM_RANGES_REMOVE_COPY_H + +#include <__algorithm/in_out_result.h> +#include <__algorithm/ranges_remove_copy_if.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using remove_copy_result = in_out_result<_InIter, _OutIter>; + +namespace __remove_copy { + +struct __fn { + template _Sent, + weakly_incrementable _OutIter, + class _Type, + class _Proj = identity> + requires indirectly_copyable<_InIter, _OutIter> && + indirect_binary_predicate, const _Type*> + _LIBCPP_HIDE_FROM_ABI constexpr remove_copy_result<_InIter, _OutIter> + operator()(_InIter __first, _Sent __last, _OutIter __result, const _Type& __value, _Proj __proj = {}) const { + auto __pred = [&](auto&& __val) -> bool { return __value == __val; }; + return ranges::__remove_copy_if_impl(std::move(__first), std::move(__last), std::move(__result), __pred, __proj); + } + + template + requires indirectly_copyable, _OutIter> && + indirect_binary_predicate, _Proj>, const _Type*> + _LIBCPP_HIDE_FROM_ABI constexpr remove_copy_result, _OutIter> + operator()(_Range&& __range, _OutIter __result, const _Type& __value, _Proj __proj = {}) const { + auto __pred = [&](auto&& __val) -> bool { return __value == __val; }; + return ranges::__remove_copy_if_impl( + ranges::begin(__range), ranges::end(__range), std::move(__result), __pred, __proj); + } +}; + +} // namespace __remove_copy + +inline namespace __cpo { +inline constexpr auto remove_copy = __remove_copy::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_REMOVE_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_remove_copy_if.h b/libcxx/include/__cxx03/__algorithm/ranges_remove_copy_if.h new file mode 100644 index 0000000000000000000000000000000000000000..56fe017533120b445db41d6fb9c2a6c01885be7f --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_remove_copy_if.h @@ -0,0 +1,95 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_REMOVE_COPY_IF_H +#define _LIBCPP___ALGORITHM_RANGES_REMOVE_COPY_IF_H + +#include <__algorithm/in_out_result.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/remove_copy_if.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using remove_copy_if_result = in_out_result<_InIter, _OutIter>; + +template +_LIBCPP_HIDE_FROM_ABI constexpr in_out_result<_InIter, _OutIter> +__remove_copy_if_impl(_InIter __first, _Sent __last, _OutIter __result, _Pred& __pred, _Proj& __proj) { + for (; __first != __last; ++__first) { + if (!std::invoke(__pred, std::invoke(__proj, *__first))) { + *__result = *__first; + ++__result; + } + } + return {std::move(__first), std::move(__result)}; +} + +namespace __remove_copy_if { + +struct __fn { + template _Sent, + weakly_incrementable _OutIter, + class _Proj = identity, + indirect_unary_predicate> _Pred> + requires indirectly_copyable<_InIter, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr remove_copy_if_result<_InIter, _OutIter> + operator()(_InIter __first, _Sent __last, _OutIter __result, _Pred __pred, _Proj __proj = {}) const { + return ranges::__remove_copy_if_impl(std::move(__first), std::move(__last), std::move(__result), __pred, __proj); + } + + template , _Proj>> _Pred> + requires indirectly_copyable, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr remove_copy_if_result, _OutIter> + operator()(_Range&& __range, _OutIter __result, _Pred __pred, _Proj __proj = {}) const { + return ranges::__remove_copy_if_impl( + ranges::begin(__range), ranges::end(__range), std::move(__result), __pred, __proj); + } +}; + +} // namespace __remove_copy_if + +inline namespace __cpo { +inline constexpr auto remove_copy_if = __remove_copy_if::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_REMOVE_COPY_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_remove_if.h b/libcxx/include/__cxx03/__algorithm/ranges_remove_if.h new file mode 100644 index 0000000000000000000000000000000000000000..0ea5d9a01b88183aea02bceb5d2e051112d9c639 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_remove_if.h @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_REMOVE_IF_H +#define _LIBCPP___ALGORITHM_RANGES_REMOVE_IF_H +#include <__config> + +#include <__algorithm/ranges_find_if.h> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iter_move.h> +#include <__iterator/permutable.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/subrange.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +_LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter> +__remove_if_impl(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) { + auto __new_end = ranges::__find_if_impl(__first, __last, __pred, __proj); + if (__new_end == __last) + return {__new_end, __new_end}; + + _Iter __i = __new_end; + while (++__i != __last) { + if (!std::invoke(__pred, std::invoke(__proj, *__i))) { + *__new_end = ranges::iter_move(__i); + ++__new_end; + } + } + return {__new_end, __i}; +} + +namespace __remove_if { +struct __fn { + template _Sent, + class _Proj = identity, + indirect_unary_predicate> _Pred> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter> + operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { + return ranges::__remove_if_impl(std::move(__first), std::move(__last), __pred, __proj); + } + + template , _Proj>> _Pred> + requires permutable> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range> + operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const { + return ranges::__remove_if_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj); + } +}; +} // namespace __remove_if + +inline namespace __cpo { +inline constexpr auto remove_if = __remove_if::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_REMOVE_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_replace.h b/libcxx/include/__cxx03/__algorithm/ranges_replace.h new file mode 100644 index 0000000000000000000000000000000000000000..2b88dc032972f427a4852a1dddccebe67acca8c6 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_replace.h @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_REPLACE_H +#define _LIBCPP___ALGORITHM_RANGES_REPLACE_H + +#include <__algorithm/ranges_replace_if.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __replace { +struct __fn { + template _Sent, class _Type1, class _Type2, class _Proj = identity> + requires indirectly_writable<_Iter, const _Type2&> && + indirect_binary_predicate, const _Type1*> + _LIBCPP_HIDE_FROM_ABI constexpr _Iter operator()( + _Iter __first, _Sent __last, const _Type1& __old_value, const _Type2& __new_value, _Proj __proj = {}) const { + auto __pred = [&](const auto& __val) -> bool { return __val == __old_value; }; + return ranges::__replace_if_impl(std::move(__first), std::move(__last), __pred, __new_value, __proj); + } + + template + requires indirectly_writable, const _Type2&> && + indirect_binary_predicate, _Proj>, const _Type1*> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __range, const _Type1& __old_value, const _Type2& __new_value, _Proj __proj = {}) const { + auto __pred = [&](auto&& __val) -> bool { return __val == __old_value; }; + return ranges::__replace_if_impl(ranges::begin(__range), ranges::end(__range), __pred, __new_value, __proj); + } +}; +} // namespace __replace + +inline namespace __cpo { +inline constexpr auto replace = __replace::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_REPLACE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_replace_copy.h b/libcxx/include/__cxx03/__algorithm/ranges_replace_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..633f993e5c9484ab221611dcb036744fa2b6ad7b --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_replace_copy.h @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_REPLACE_COPY_H +#define _LIBCPP___ALGORITHM_RANGES_REPLACE_COPY_H + +#include <__algorithm/in_out_result.h> +#include <__algorithm/ranges_replace_copy_if.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using replace_copy_result = in_out_result<_InIter, _OutIter>; + +namespace __replace_copy { + +struct __fn { + template _Sent, + class _OldType, + class _NewType, + output_iterator _OutIter, + class _Proj = identity> + requires indirectly_copyable<_InIter, _OutIter> && + indirect_binary_predicate, const _OldType*> + _LIBCPP_HIDE_FROM_ABI constexpr replace_copy_result<_InIter, _OutIter> + operator()(_InIter __first, + _Sent __last, + _OutIter __result, + const _OldType& __old_value, + const _NewType& __new_value, + _Proj __proj = {}) const { + auto __pred = [&](const auto& __value) -> bool { return __value == __old_value; }; + return ranges::__replace_copy_if_impl( + std::move(__first), std::move(__last), std::move(__result), __pred, __new_value, __proj); + } + + template _OutIter, + class _Proj = identity> + requires indirectly_copyable, _OutIter> && + indirect_binary_predicate, _Proj>, const _OldType*> + _LIBCPP_HIDE_FROM_ABI constexpr replace_copy_result, _OutIter> operator()( + _Range&& __range, _OutIter __result, const _OldType& __old_value, const _NewType& __new_value, _Proj __proj = {}) + const { + auto __pred = [&](const auto& __value) -> bool { return __value == __old_value; }; + return ranges::__replace_copy_if_impl( + ranges::begin(__range), ranges::end(__range), std::move(__result), __pred, __new_value, __proj); + } +}; + +} // namespace __replace_copy + +inline namespace __cpo { +inline constexpr auto replace_copy = __replace_copy::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_REPLACE_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_replace_copy_if.h b/libcxx/include/__cxx03/__algorithm/ranges_replace_copy_if.h new file mode 100644 index 0000000000000000000000000000000000000000..e065c3ac0acc903028623dd0e14b45b156b9dc97 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_replace_copy_if.h @@ -0,0 +1,98 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_REPLACE_COPY_IF_H +#define _LIBCPP___ALGORITHM_RANGES_REPLACE_COPY_IF_H + +#include <__algorithm/in_out_result.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using replace_copy_if_result = in_out_result<_InIter, _OutIter>; + +template +_LIBCPP_HIDE_FROM_ABI constexpr replace_copy_if_result<_InIter, _OutIter> __replace_copy_if_impl( + _InIter __first, _Sent __last, _OutIter __result, _Pred& __pred, const _Type& __new_value, _Proj& __proj) { + while (__first != __last) { + if (std::invoke(__pred, std::invoke(__proj, *__first))) + *__result = __new_value; + else + *__result = *__first; + + ++__first; + ++__result; + } + + return {std::move(__first), std::move(__result)}; +} + +namespace __replace_copy_if { + +struct __fn { + template _Sent, + class _Type, + output_iterator _OutIter, + class _Proj = identity, + indirect_unary_predicate> _Pred> + requires indirectly_copyable<_InIter, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr replace_copy_if_result<_InIter, _OutIter> operator()( + _InIter __first, _Sent __last, _OutIter __result, _Pred __pred, const _Type& __new_value, _Proj __proj = {}) + const { + return ranges::__replace_copy_if_impl( + std::move(__first), std::move(__last), std::move(__result), __pred, __new_value, __proj); + } + + template _OutIter, + class _Proj = identity, + indirect_unary_predicate, _Proj>> _Pred> + requires indirectly_copyable, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr replace_copy_if_result, _OutIter> + operator()(_Range&& __range, _OutIter __result, _Pred __pred, const _Type& __new_value, _Proj __proj = {}) const { + return ranges::__replace_copy_if_impl( + ranges::begin(__range), ranges::end(__range), std::move(__result), __pred, __new_value, __proj); + } +}; + +} // namespace __replace_copy_if + +inline namespace __cpo { +inline constexpr auto replace_copy_if = __replace_copy_if::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_REPLACE_COPY_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_replace_if.h b/libcxx/include/__cxx03/__algorithm/ranges_replace_if.h new file mode 100644 index 0000000000000000000000000000000000000000..6445f42aea1908fd320bf0e5eea0a5b10161464f --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_replace_if.h @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_REPLACE_IF_H +#define _LIBCPP___ALGORITHM_RANGES_REPLACE_IF_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +_LIBCPP_HIDE_FROM_ABI constexpr _Iter +__replace_if_impl(_Iter __first, _Sent __last, _Pred& __pred, const _Type& __new_value, _Proj& __proj) { + for (; __first != __last; ++__first) { + if (std::invoke(__pred, std::invoke(__proj, *__first))) + *__first = __new_value; + } + return __first; +} + +namespace __replace_if { +struct __fn { + template _Sent, + class _Type, + class _Proj = identity, + indirect_unary_predicate> _Pred> + requires indirectly_writable<_Iter, const _Type&> + _LIBCPP_HIDE_FROM_ABI constexpr _Iter + operator()(_Iter __first, _Sent __last, _Pred __pred, const _Type& __new_value, _Proj __proj = {}) const { + return ranges::__replace_if_impl(std::move(__first), std::move(__last), __pred, __new_value, __proj); + } + + template , _Proj>> _Pred> + requires indirectly_writable, const _Type&> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __range, _Pred __pred, const _Type& __new_value, _Proj __proj = {}) const { + return ranges::__replace_if_impl(ranges::begin(__range), ranges::end(__range), __pred, __new_value, __proj); + } +}; +} // namespace __replace_if + +inline namespace __cpo { +inline constexpr auto replace_if = __replace_if::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_REPLACE_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_reverse.h b/libcxx/include/__cxx03/__algorithm/ranges_reverse.h new file mode 100644 index 0000000000000000000000000000000000000000..9ec865995b4a5490b240b61659292cfcbe96ab6e --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_reverse.h @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_REVERSE_H +#define _LIBCPP___ALGORITHM_RANGES_REVERSE_H + +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/iter_swap.h> +#include <__iterator/next.h> +#include <__iterator/permutable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __reverse { +struct __fn { + template _Sent> + requires permutable<_Iter> + _LIBCPP_HIDE_FROM_ABI constexpr _Iter operator()(_Iter __first, _Sent __last) const { + if constexpr (random_access_iterator<_Iter>) { + if (__first == __last) + return __first; + + auto __end = ranges::next(__first, __last); + auto __ret = __end; + + while (__first < --__end) { + ranges::iter_swap(__first, __end); + ++__first; + } + return __ret; + } else { + auto __end = ranges::next(__first, __last); + auto __ret = __end; + + while (__first != __end) { + if (__first == --__end) + break; + + ranges::iter_swap(__first, __end); + ++__first; + } + return __ret; + } + } + + template + requires permutable> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> operator()(_Range&& __range) const { + return (*this)(ranges::begin(__range), ranges::end(__range)); + } +}; +} // namespace __reverse + +inline namespace __cpo { +inline constexpr auto reverse = __reverse::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___ALGORITHM_RANGES_REVERSE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_reverse_copy.h b/libcxx/include/__cxx03/__algorithm/ranges_reverse_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..60043787a7170530dfeea7f1b03d63f2876fe2e6 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_reverse_copy.h @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_REVERSE_COPY_H +#define _LIBCPP___ALGORITHM_RANGES_REVERSE_COPY_H + +#include <__algorithm/in_out_result.h> +#include <__algorithm/ranges_copy.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/next.h> +#include <__iterator/reverse_iterator.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__ranges/subrange.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using reverse_copy_result = in_out_result<_InIter, _OutIter>; + +namespace __reverse_copy { +struct __fn { + template _Sent, weakly_incrementable _OutIter> + requires indirectly_copyable<_InIter, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr reverse_copy_result<_InIter, _OutIter> + operator()(_InIter __first, _Sent __last, _OutIter __result) const { + return (*this)(subrange(std::move(__first), std::move(__last)), std::move(__result)); + } + + template + requires indirectly_copyable, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr reverse_copy_result, _OutIter> + operator()(_Range&& __range, _OutIter __result) const { + auto __ret = ranges::copy(std::__reverse_range(__range), std::move(__result)); + return {ranges::next(ranges::begin(__range), ranges::end(__range)), std::move(__ret.out)}; + } +}; +} // namespace __reverse_copy + +inline namespace __cpo { +inline constexpr auto reverse_copy = __reverse_copy::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_REVERSE_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_rotate.h b/libcxx/include/__cxx03/__algorithm/ranges_rotate.h new file mode 100644 index 0000000000000000000000000000000000000000..8d33a6f0799bf7570b435b14295cb358a752ce60 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_rotate.h @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_ROTATE_H +#define _LIBCPP___ALGORITHM_RANGES_ROTATE_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/ranges_iterator_concept.h> +#include <__algorithm/rotate.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/permutable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/subrange.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __rotate { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static subrange<_Iter> __rotate_fn_impl(_Iter __first, _Iter __middle, _Sent __last) { + auto __ret = std::__rotate<_RangeAlgPolicy>(std::move(__first), std::move(__middle), std::move(__last)); + return {std::move(__ret.first), std::move(__ret.second)}; + } + + template _Sent> + _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter> operator()(_Iter __first, _Iter __middle, _Sent __last) const { + return __rotate_fn_impl(std::move(__first), std::move(__middle), std::move(__last)); + } + + template + requires permutable> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range> + operator()(_Range&& __range, iterator_t<_Range> __middle) const { + return __rotate_fn_impl(ranges::begin(__range), std::move(__middle), ranges::end(__range)); + } +}; + +} // namespace __rotate + +inline namespace __cpo { +inline constexpr auto rotate = __rotate::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_ROTATE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_rotate_copy.h b/libcxx/include/__cxx03/__algorithm/ranges_rotate_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..26fe110b538963eaa2d6ebc9fb6b08823754ac0f --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_rotate_copy.h @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_ROTATE_COPY_H +#define _LIBCPP___ALGORITHM_RANGES_ROTATE_COPY_H + +#include <__algorithm/in_out_result.h> +#include <__algorithm/ranges_copy.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using rotate_copy_result = in_out_result<_InIter, _OutIter>; + +namespace __rotate_copy { +struct __fn { + template _Sent, weakly_incrementable _OutIter> + requires indirectly_copyable<_InIter, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr rotate_copy_result<_InIter, _OutIter> + operator()(_InIter __first, _InIter __middle, _Sent __last, _OutIter __result) const { + auto __res1 = ranges::copy(__middle, __last, std::move(__result)); + auto __res2 = ranges::copy(__first, __middle, std::move(__res1.out)); + return {std::move(__res1.in), std::move(__res2.out)}; + } + + template + requires indirectly_copyable, _OutIter> + _LIBCPP_HIDE_FROM_ABI constexpr rotate_copy_result, _OutIter> + operator()(_Range&& __range, iterator_t<_Range> __middle, _OutIter __result) const { + return (*this)(ranges::begin(__range), std::move(__middle), ranges::end(__range), std::move(__result)); + } +}; +} // namespace __rotate_copy + +inline namespace __cpo { +inline constexpr auto rotate_copy = __rotate_copy::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_ROTATE_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_sample.h b/libcxx/include/__cxx03/__algorithm/ranges_sample.h new file mode 100644 index 0000000000000000000000000000000000000000..e4f60a7b66be2b0baf1dbb275ad99f1c16b10abf --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_sample.h @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_SAMPLE_H +#define _LIBCPP___ALGORITHM_RANGES_SAMPLE_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/sample.h> +#include <__algorithm/uniform_random_bit_generator_adaptor.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iterator_traits.h> +#include <__random/uniform_random_bit_generator.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__type_traits/remove_reference.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __sample { + +struct __fn { + template _Sent, weakly_incrementable _OutIter, class _Gen> + requires(forward_iterator<_Iter> || random_access_iterator<_OutIter>) && indirectly_copyable<_Iter, _OutIter> && + uniform_random_bit_generator> + _LIBCPP_HIDE_FROM_ABI _OutIter + operator()(_Iter __first, _Sent __last, _OutIter __out_first, iter_difference_t<_Iter> __n, _Gen&& __gen) const { + _ClassicGenAdaptor<_Gen> __adapted_gen(__gen); + return std::__sample<_RangeAlgPolicy>( + std::move(__first), std::move(__last), std::move(__out_first), __n, __adapted_gen); + } + + template + requires(forward_range<_Range> || random_access_iterator<_OutIter>) && + indirectly_copyable, _OutIter> && uniform_random_bit_generator> + _LIBCPP_HIDE_FROM_ABI _OutIter + operator()(_Range&& __range, _OutIter __out_first, range_difference_t<_Range> __n, _Gen&& __gen) const { + return (*this)( + ranges::begin(__range), ranges::end(__range), std::move(__out_first), __n, std::forward<_Gen>(__gen)); + } +}; + +} // namespace __sample + +inline namespace __cpo { +inline constexpr auto sample = __sample::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_SAMPLE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_search.h b/libcxx/include/__cxx03/__algorithm/ranges_search.h new file mode 100644 index 0000000000000000000000000000000000000000..55294c60631b18964f4f679ad275fe6cbcf35344 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_search.h @@ -0,0 +1,134 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_SEARCH_H +#define _LIBCPP___ALGORITHM_RANGES_SEARCH_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/search.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/advance.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/indirectly_comparable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/size.h> +#include <__ranges/subrange.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __search { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI static constexpr subrange<_Iter1> __ranges_search_impl( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred& __pred, + _Proj1& __proj1, + _Proj2& __proj2) { + if constexpr (sized_sentinel_for<_Sent2, _Iter2>) { + auto __size2 = ranges::distance(__first2, __last2); + if (__size2 == 0) + return {__first1, __first1}; + + if constexpr (sized_sentinel_for<_Sent1, _Iter1>) { + auto __size1 = ranges::distance(__first1, __last1); + if (__size1 < __size2) { + ranges::advance(__first1, __last1); + return {__first1, __first1}; + } + + if constexpr (random_access_iterator<_Iter1> && random_access_iterator<_Iter2>) { + auto __ret = std::__search_random_access_impl<_RangeAlgPolicy>( + __first1, __last1, __first2, __last2, __pred, __proj1, __proj2, __size1, __size2); + return {__ret.first, __ret.second}; + } + } + } + + auto __ret = + std::__search_forward_impl<_RangeAlgPolicy>(__first1, __last1, __first2, __last2, __pred, __proj1, __proj2); + return {__ret.first, __ret.second}; + } + + template _Sent1, + forward_iterator _Iter2, + sentinel_for<_Iter2> _Sent2, + class _Pred = ranges::equal_to, + class _Proj1 = identity, + class _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter1> operator()( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred __pred = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + return __ranges_search_impl(__first1, __last1, __first2, __last2, __pred, __proj1, __proj2); + } + + template + requires indirectly_comparable, iterator_t<_Range2>, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range1> operator()( + _Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { + auto __first1 = ranges::begin(__range1); + if constexpr (sized_range<_Range2>) { + auto __size2 = ranges::size(__range2); + if (__size2 == 0) + return {__first1, __first1}; + if constexpr (sized_range<_Range1>) { + auto __size1 = ranges::size(__range1); + if (__size1 < __size2) { + ranges::advance(__first1, ranges::end(__range1)); + return {__first1, __first1}; + } + } + } + + return __ranges_search_impl( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + __pred, + __proj1, + __proj2); + } +}; +} // namespace __search + +inline namespace __cpo { +inline constexpr auto search = __search::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___ALGORITHM_RANGES_SEARCH_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_search_n.h b/libcxx/include/__cxx03/__algorithm/ranges_search_n.h new file mode 100644 index 0000000000000000000000000000000000000000..56e12755b9bf6b5d2e235e50055c8ade711cc54f --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_search_n.h @@ -0,0 +1,116 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_SEARCH_N_H +#define _LIBCPP___ALGORITHM_RANGES_SEARCH_N_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/search_n.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/advance.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/indirectly_comparable.h> +#include <__iterator/iterator_traits.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/size.h> +#include <__ranges/subrange.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __search_n { +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI static constexpr subrange<_Iter1> __ranges_search_n_impl( + _Iter1 __first, _Sent1 __last, _SizeT __count, const _Type& __value, _Pred& __pred, _Proj& __proj) { + if (__count == 0) + return {__first, __first}; + + if constexpr (sized_sentinel_for<_Sent1, _Iter1>) { + auto __size = ranges::distance(__first, __last); + if (__size < __count) { + ranges::advance(__first, __last); + return {__first, __first}; + } + + if constexpr (random_access_iterator<_Iter1>) { + auto __ret = std::__search_n_random_access_impl<_RangeAlgPolicy>( + __first, __last, __count, __value, __pred, __proj, __size); + return {std::move(__ret.first), std::move(__ret.second)}; + } + } + + auto __ret = std::__search_n_forward_impl<_RangeAlgPolicy>(__first, __last, __count, __value, __pred, __proj); + return {std::move(__ret.first), std::move(__ret.second)}; + } + + template _Sent, + class _Type, + class _Pred = ranges::equal_to, + class _Proj = identity> + requires indirectly_comparable<_Iter, const _Type*, _Pred, _Proj> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter> + operator()(_Iter __first, + _Sent __last, + iter_difference_t<_Iter> __count, + const _Type& __value, + _Pred __pred = {}, + _Proj __proj = _Proj{}) const { + return __ranges_search_n_impl(__first, __last, __count, __value, __pred, __proj); + } + + template + requires indirectly_comparable, const _Type*, _Pred, _Proj> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range> operator()( + _Range&& __range, range_difference_t<_Range> __count, const _Type& __value, _Pred __pred = {}, _Proj __proj = {}) + const { + auto __first = ranges::begin(__range); + if (__count <= 0) + return {__first, __first}; + if constexpr (sized_range<_Range>) { + auto __size1 = ranges::size(__range); + if (__size1 < static_cast>(__count)) { + ranges::advance(__first, ranges::end(__range)); + return {__first, __first}; + } + } + + return __ranges_search_n_impl(ranges::begin(__range), ranges::end(__range), __count, __value, __pred, __proj); + } +}; +} // namespace __search_n + +inline namespace __cpo { +inline constexpr auto search_n = __search_n::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_SEARCH_N_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_set_difference.h b/libcxx/include/__cxx03/__algorithm/ranges_set_difference.h new file mode 100644 index 0000000000000000000000000000000000000000..0841fb4ffd0c065ecab0fa69a4b6b7a0d2deb273 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_set_difference.h @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_SET_DIFFERENCE_H +#define _LIBCPP___ALGORITHM_RANGES_SET_DIFFERENCE_H + +#include <__algorithm/in_out_result.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/set_difference.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/mergeable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__type_traits/decay.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using set_difference_result = in_out_result<_InIter, _OutIter>; + +namespace __set_difference { + +struct __fn { + template _Sent1, + input_iterator _InIter2, + sentinel_for<_InIter2> _Sent2, + weakly_incrementable _OutIter, + class _Comp = less, + class _Proj1 = identity, + class _Proj2 = identity> + requires mergeable<_InIter1, _InIter2, _OutIter, _Comp, _Proj1, _Proj2> + _LIBCPP_HIDE_FROM_ABI constexpr set_difference_result<_InIter1, _OutIter> operator()( + _InIter1 __first1, + _Sent1 __last1, + _InIter2 __first2, + _Sent2 __last2, + _OutIter __result, + _Comp __comp = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + auto __ret = std::__set_difference<_RangeAlgPolicy>( + __first1, __last1, __first2, __last2, __result, ranges::__make_projected_comp(__comp, __proj1, __proj2)); + return {std::move(__ret.first), std::move(__ret.second)}; + } + + template + requires mergeable, iterator_t<_Range2>, _OutIter, _Comp, _Proj1, _Proj2> + _LIBCPP_HIDE_FROM_ABI constexpr set_difference_result, _OutIter> + operator()(_Range1&& __range1, + _Range2&& __range2, + _OutIter __result, + _Comp __comp = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + auto __ret = std::__set_difference<_RangeAlgPolicy>( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + __result, + ranges::__make_projected_comp(__comp, __proj1, __proj2)); + return {std::move(__ret.first), std::move(__ret.second)}; + } +}; + +} // namespace __set_difference + +inline namespace __cpo { +inline constexpr auto set_difference = __set_difference::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_SET_DIFFERENCE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_set_intersection.h b/libcxx/include/__cxx03/__algorithm/ranges_set_intersection.h new file mode 100644 index 0000000000000000000000000000000000000000..9427379745b60f52c69121a19448c7a281540427 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_set_intersection.h @@ -0,0 +1,114 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_SET_INTERSECTION_H +#define _LIBCPP___ALGORITHM_RANGES_SET_INTERSECTION_H + +#include <__algorithm/in_in_out_result.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/set_intersection.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/mergeable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using set_intersection_result = in_in_out_result<_InIter1, _InIter2, _OutIter>; + +namespace __set_intersection { + +struct __fn { + template _Sent1, + input_iterator _InIter2, + sentinel_for<_InIter2> _Sent2, + weakly_incrementable _OutIter, + class _Comp = less, + class _Proj1 = identity, + class _Proj2 = identity> + requires mergeable<_InIter1, _InIter2, _OutIter, _Comp, _Proj1, _Proj2> + _LIBCPP_HIDE_FROM_ABI constexpr set_intersection_result<_InIter1, _InIter2, _OutIter> operator()( + _InIter1 __first1, + _Sent1 __last1, + _InIter2 __first2, + _Sent2 __last2, + _OutIter __result, + _Comp __comp = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + auto __ret = std::__set_intersection<_RangeAlgPolicy>( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + ranges::__make_projected_comp(__comp, __proj1, __proj2)); + return {std::move(__ret.__in1_), std::move(__ret.__in2_), std::move(__ret.__out_)}; + } + + template + requires mergeable, iterator_t<_Range2>, _OutIter, _Comp, _Proj1, _Proj2> + _LIBCPP_HIDE_FROM_ABI constexpr set_intersection_result, + borrowed_iterator_t<_Range2>, + _OutIter> + operator()(_Range1&& __range1, + _Range2&& __range2, + _OutIter __result, + _Comp __comp = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + auto __ret = std::__set_intersection<_RangeAlgPolicy>( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + std::move(__result), + ranges::__make_projected_comp(__comp, __proj1, __proj2)); + return {std::move(__ret.__in1_), std::move(__ret.__in2_), std::move(__ret.__out_)}; + } +}; + +} // namespace __set_intersection + +inline namespace __cpo { +inline constexpr auto set_intersection = __set_intersection::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_SET_INTERSECTION_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_set_symmetric_difference.h b/libcxx/include/__cxx03/__algorithm/ranges_set_symmetric_difference.h new file mode 100644 index 0000000000000000000000000000000000000000..995eb0999d940ac87f462e37f7acf4d8c28bbb7f --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_set_symmetric_difference.h @@ -0,0 +1,114 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_SET_SYMMETRIC_DIFFERENCE_H +#define _LIBCPP___ALGORITHM_RANGES_SET_SYMMETRIC_DIFFERENCE_H + +#include <__algorithm/in_in_out_result.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/set_symmetric_difference.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/mergeable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using set_symmetric_difference_result = in_in_out_result<_InIter1, _InIter2, _OutIter>; + +namespace __set_symmetric_difference { + +struct __fn { + template _Sent1, + input_iterator _InIter2, + sentinel_for<_InIter2> _Sent2, + weakly_incrementable _OutIter, + class _Comp = ranges::less, + class _Proj1 = identity, + class _Proj2 = identity> + requires mergeable<_InIter1, _InIter2, _OutIter, _Comp, _Proj1, _Proj2> + _LIBCPP_HIDE_FROM_ABI constexpr set_symmetric_difference_result<_InIter1, _InIter2, _OutIter> operator()( + _InIter1 __first1, + _Sent1 __last1, + _InIter2 __first2, + _Sent2 __last2, + _OutIter __result, + _Comp __comp = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + auto __ret = std::__set_symmetric_difference<_RangeAlgPolicy>( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + ranges::__make_projected_comp(__comp, __proj1, __proj2)); + return {std::move(__ret.__in1_), std::move(__ret.__in2_), std::move(__ret.__out_)}; + } + + template + requires mergeable, iterator_t<_Range2>, _OutIter, _Comp, _Proj1, _Proj2> + _LIBCPP_HIDE_FROM_ABI constexpr set_symmetric_difference_result, + borrowed_iterator_t<_Range2>, + _OutIter> + operator()(_Range1&& __range1, + _Range2&& __range2, + _OutIter __result, + _Comp __comp = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + auto __ret = std::__set_symmetric_difference<_RangeAlgPolicy>( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + std::move(__result), + ranges::__make_projected_comp(__comp, __proj1, __proj2)); + return {std::move(__ret.__in1_), std::move(__ret.__in2_), std::move(__ret.__out_)}; + } +}; + +} // namespace __set_symmetric_difference + +inline namespace __cpo { +inline constexpr auto set_symmetric_difference = __set_symmetric_difference::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_SET_SYMMETRIC_DIFFERENCE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_set_union.h b/libcxx/include/__cxx03/__algorithm/ranges_set_union.h new file mode 100644 index 0000000000000000000000000000000000000000..e870e390cc665948abae3f6c3c3db27977708c13 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_set_union.h @@ -0,0 +1,115 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_SET_UNION_H +#define _LIBCPP___ALGORITHM_RANGES_SET_UNION_H + +#include <__algorithm/in_in_out_result.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/set_union.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/mergeable.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using set_union_result = in_in_out_result<_InIter1, _InIter2, _OutIter>; + +namespace __set_union { + +struct __fn { + template _Sent1, + input_iterator _InIter2, + sentinel_for<_InIter2> _Sent2, + weakly_incrementable _OutIter, + class _Comp = ranges::less, + class _Proj1 = identity, + class _Proj2 = identity> + requires mergeable<_InIter1, _InIter2, _OutIter, _Comp, _Proj1, _Proj2> + _LIBCPP_HIDE_FROM_ABI constexpr set_union_result<_InIter1, _InIter2, _OutIter> operator()( + _InIter1 __first1, + _Sent1 __last1, + _InIter2 __first2, + _Sent2 __last2, + _OutIter __result, + _Comp __comp = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + auto __ret = std::__set_union<_RangeAlgPolicy>( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + ranges::__make_projected_comp(__comp, __proj1, __proj2)); + return {std::move(__ret.__in1_), std::move(__ret.__in2_), std::move(__ret.__out_)}; + } + + template + requires mergeable, iterator_t<_Range2>, _OutIter, _Comp, _Proj1, _Proj2> + _LIBCPP_HIDE_FROM_ABI constexpr set_union_result, borrowed_iterator_t<_Range2>, _OutIter> + operator()(_Range1&& __range1, + _Range2&& __range2, + _OutIter __result, + _Comp __comp = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) const { + auto __ret = std::__set_union<_RangeAlgPolicy>( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + std::move(__result), + ranges::__make_projected_comp(__comp, __proj1, __proj2)); + return {std::move(__ret.__in1_), std::move(__ret.__in2_), std::move(__ret.__out_)}; + } +}; + +} // namespace __set_union + +inline namespace __cpo { +inline constexpr auto set_union = __set_union::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_SET_UNION_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_shuffle.h b/libcxx/include/__cxx03/__algorithm/ranges_shuffle.h new file mode 100644 index 0000000000000000000000000000000000000000..ab98ea22caabec810bcbdd8faf11f3e4503e8301 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_shuffle.h @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_SHUFFLE_H +#define _LIBCPP___ALGORITHM_RANGES_SHUFFLE_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/shuffle.h> +#include <__algorithm/uniform_random_bit_generator_adaptor.h> +#include <__config> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/permutable.h> +#include <__random/uniform_random_bit_generator.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__type_traits/remove_reference.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __shuffle { + +struct __fn { + template _Sent, class _Gen> + requires permutable<_Iter> && uniform_random_bit_generator> + _LIBCPP_HIDE_FROM_ABI _Iter operator()(_Iter __first, _Sent __last, _Gen&& __gen) const { + _ClassicGenAdaptor<_Gen> __adapted_gen(__gen); + return std::__shuffle<_RangeAlgPolicy>(std::move(__first), std::move(__last), __adapted_gen); + } + + template + requires permutable> && uniform_random_bit_generator> + _LIBCPP_HIDE_FROM_ABI borrowed_iterator_t<_Range> operator()(_Range&& __range, _Gen&& __gen) const { + return (*this)(ranges::begin(__range), ranges::end(__range), std::forward<_Gen>(__gen)); + } +}; + +} // namespace __shuffle + +inline namespace __cpo { +inline constexpr auto shuffle = __shuffle::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_SHUFFLE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_sort.h b/libcxx/include/__cxx03/__algorithm/ranges_sort.h new file mode 100644 index 0000000000000000000000000000000000000000..0296c146b3edeeaa84ed4af051e1fab9876dc3ac --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_sort.h @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_SORT_H +#define _LIBCPP___ALGORITHM_RANGES_SORT_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/sort.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/projected.h> +#include <__iterator/sortable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __sort { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static _Iter + __sort_fn_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) { + auto __last_iter = ranges::next(__first, __last); + + auto&& __projected_comp = std::__make_projected(__comp, __proj); + std::__sort_impl<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp); + + return __last_iter; + } + + template _Sent, class _Comp = ranges::less, class _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr _Iter + operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + return __sort_fn_impl(std::move(__first), std::move(__last), __comp, __proj); + } + + template + requires sortable, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { + return __sort_fn_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj); + } +}; + +} // namespace __sort + +inline namespace __cpo { +inline constexpr auto sort = __sort::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_SORT_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_sort_heap.h b/libcxx/include/__cxx03/__algorithm/ranges_sort_heap.h new file mode 100644 index 0000000000000000000000000000000000000000..bab30df1708c75d647a724c8e4be3620ee8158b9 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_sort_heap.h @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_SORT_HEAP_H +#define _LIBCPP___ALGORITHM_RANGES_SORT_HEAP_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/sort_heap.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/projected.h> +#include <__iterator/sortable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __sort_heap { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr static _Iter + __sort_heap_fn_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) { + auto __last_iter = ranges::next(__first, __last); + + auto&& __projected_comp = std::__make_projected(__comp, __proj); + std::__sort_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp); + + return __last_iter; + } + + template _Sent, class _Comp = ranges::less, class _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr _Iter + operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + return __sort_heap_fn_impl(std::move(__first), std::move(__last), __comp, __proj); + } + + template + requires sortable, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { + return __sort_heap_fn_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj); + } +}; + +} // namespace __sort_heap + +inline namespace __cpo { +inline constexpr auto sort_heap = __sort_heap::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_SORT_HEAP_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_stable_partition.h b/libcxx/include/__cxx03/__algorithm/ranges_stable_partition.h new file mode 100644 index 0000000000000000000000000000000000000000..f34027ff772c78e1f654190b9b1432f78fa77e8e --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_stable_partition.h @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_STABLE_PARTITION_H +#define _LIBCPP___ALGORITHM_RANGES_STABLE_PARTITION_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/ranges_iterator_concept.h> +#include <__algorithm/stable_partition.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/permutable.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__ranges/subrange.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __stable_partition { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI static subrange<__remove_cvref_t<_Iter>> + __stable_partition_fn_impl(_Iter&& __first, _Sent&& __last, _Pred&& __pred, _Proj&& __proj) { + auto __last_iter = ranges::next(__first, __last); + + auto&& __projected_pred = std::__make_projected(__pred, __proj); + auto __result = std::__stable_partition<_RangeAlgPolicy>( + std::move(__first), __last_iter, __projected_pred, __iterator_concept<_Iter>()); + + return {std::move(__result), std::move(__last_iter)}; + } + + template _Sent, + class _Proj = identity, + indirect_unary_predicate> _Pred> + requires permutable<_Iter> + _LIBCPP_HIDE_FROM_ABI subrange<_Iter> operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const { + return __stable_partition_fn_impl(__first, __last, __pred, __proj); + } + + template , _Proj>> _Pred> + requires permutable> + _LIBCPP_HIDE_FROM_ABI borrowed_subrange_t<_Range> + operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const { + return __stable_partition_fn_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj); + } +}; + +} // namespace __stable_partition + +inline namespace __cpo { +inline constexpr auto stable_partition = __stable_partition::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_STABLE_PARTITION_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_stable_sort.h b/libcxx/include/__cxx03/__algorithm/ranges_stable_sort.h new file mode 100644 index 0000000000000000000000000000000000000000..93909e253cc0f2ac0ec1e4efcc2f3e06ae978711 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_stable_sort.h @@ -0,0 +1,82 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_STABLE_SORT_H +#define _LIBCPP___ALGORITHM_RANGES_STABLE_SORT_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/stable_sort.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/projected.h> +#include <__iterator/sortable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __stable_sort { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI static _Iter __stable_sort_fn_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) { + auto __last_iter = ranges::next(__first, __last); + + auto&& __projected_comp = std::__make_projected(__comp, __proj); + std::__stable_sort_impl<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp); + + return __last_iter; + } + + template _Sent, class _Comp = ranges::less, class _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI _Iter operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + return __stable_sort_fn_impl(std::move(__first), std::move(__last), __comp, __proj); + } + + template + requires sortable, _Comp, _Proj> + _LIBCPP_HIDE_FROM_ABI borrowed_iterator_t<_Range> + operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const { + return __stable_sort_fn_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj); + } +}; + +} // namespace __stable_sort + +inline namespace __cpo { +inline constexpr auto stable_sort = __stable_sort::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_STABLE_SORT_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_starts_with.h b/libcxx/include/__cxx03/__algorithm/ranges_starts_with.h new file mode 100644 index 0000000000000000000000000000000000000000..17084e4f24336acbbfb20fda4a0ba5c9e604aacb --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_starts_with.h @@ -0,0 +1,95 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_STARTS_WITH_H +#define _LIBCPP___ALGORITHM_RANGES_STARTS_WITH_H + +#include <__algorithm/in_in_result.h> +#include <__algorithm/ranges_mismatch.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/indirectly_comparable.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __starts_with { +struct __fn { + template _Sent1, + input_iterator _Iter2, + sentinel_for<_Iter2> _Sent2, + class _Pred = ranges::equal_to, + class _Proj1 = identity, + class _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr bool operator()( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred __pred = {}, + _Proj1 __proj1 = {}, + _Proj2 __proj2 = {}) { + return __mismatch::__fn::__go( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + __pred, + __proj1, + __proj2) + .in2 == __last2; + } + + template + requires indirectly_comparable, iterator_t<_Range2>, _Pred, _Proj1, _Proj2> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr bool + operator()(_Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) { + return __mismatch::__fn::__go( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + __pred, + __proj1, + __proj2) + .in2 == ranges::end(__range2); + } +}; +} // namespace __starts_with +inline namespace __cpo { +inline constexpr auto starts_with = __starts_with::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_STARTS_WITH_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_swap_ranges.h b/libcxx/include/__cxx03/__algorithm/ranges_swap_ranges.h new file mode 100644 index 0000000000000000000000000000000000000000..b6d9f618395a5e6cfe6ec14f7222b7b9fd05db8f --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_swap_ranges.h @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_SWAP_RANGES_H +#define _LIBCPP___ALGORITHM_RANGES_SWAP_RANGES_H + +#include <__algorithm/in_in_result.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/swap_ranges.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/iter_swap.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using swap_ranges_result = in_in_result<_I1, _I2>; + +namespace __swap_ranges { +struct __fn { + template _S1, input_iterator _I2, sentinel_for<_I2> _S2> + requires indirectly_swappable<_I1, _I2> + _LIBCPP_HIDE_FROM_ABI constexpr swap_ranges_result<_I1, _I2> + operator()(_I1 __first1, _S1 __last1, _I2 __first2, _S2 __last2) const { + auto __ret = std::__swap_ranges<_RangeAlgPolicy>( + std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2)); + return {std::move(__ret.first), std::move(__ret.second)}; + } + + template + requires indirectly_swappable, iterator_t<_R2>> + _LIBCPP_HIDE_FROM_ABI constexpr swap_ranges_result, borrowed_iterator_t<_R2>> + operator()(_R1&& __r1, _R2&& __r2) const { + return operator()(ranges::begin(__r1), ranges::end(__r1), ranges::begin(__r2), ranges::end(__r2)); + } +}; +} // namespace __swap_ranges + +inline namespace __cpo { +inline constexpr auto swap_ranges = __swap_ranges::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_SWAP_RANGES_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_transform.h b/libcxx/include/__cxx03/__algorithm/ranges_transform.h new file mode 100644 index 0000000000000000000000000000000000000000..7850ec4f84656013d3b9ff1900e7dbb2c71a1b38 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_transform.h @@ -0,0 +1,177 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_TRANSFORM_H +#define _LIBCPP___ALGORITHM_RANGES_TRANSFORM_H + +#include <__algorithm/in_in_out_result.h> +#include <__algorithm/in_out_result.h> +#include <__concepts/constructible.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using unary_transform_result = in_out_result<_Ip, _Op>; + +template +using binary_transform_result = in_in_out_result<_I1, _I2, _O1>; + +namespace __transform { +struct __fn { +private: + template + _LIBCPP_HIDE_FROM_ABI static constexpr unary_transform_result<_InIter, _OutIter> + __unary(_InIter __first, _Sent __last, _OutIter __result, _Func& __operation, _Proj& __projection) { + while (__first != __last) { + *__result = std::invoke(__operation, std::invoke(__projection, *__first)); + ++__first; + ++__result; + } + + return {std::move(__first), std::move(__result)}; + } + + template + _LIBCPP_HIDE_FROM_ABI static constexpr binary_transform_result<_InIter1, _InIter2, _OutIter> + __binary(_InIter1 __first1, + _Sent1 __last1, + _InIter2 __first2, + _Sent2 __last2, + _OutIter __result, + _Func& __binary_operation, + _Proj1& __projection1, + _Proj2& __projection2) { + while (__first1 != __last1 && __first2 != __last2) { + *__result = + std::invoke(__binary_operation, std::invoke(__projection1, *__first1), std::invoke(__projection2, *__first2)); + ++__first1; + ++__first2; + ++__result; + } + return {std::move(__first1), std::move(__first2), std::move(__result)}; + } + +public: + template _Sent, + weakly_incrementable _OutIter, + copy_constructible _Func, + class _Proj = identity> + requires indirectly_writable<_OutIter, indirect_result_t<_Func&, projected<_InIter, _Proj>>> + _LIBCPP_HIDE_FROM_ABI constexpr unary_transform_result<_InIter, _OutIter> + operator()(_InIter __first, _Sent __last, _OutIter __result, _Func __operation, _Proj __proj = {}) const { + return __unary(std::move(__first), std::move(__last), std::move(__result), __operation, __proj); + } + + template + requires indirectly_writable<_OutIter, indirect_result_t<_Func, projected, _Proj>>> + _LIBCPP_HIDE_FROM_ABI constexpr unary_transform_result, _OutIter> + operator()(_Range&& __range, _OutIter __result, _Func __operation, _Proj __projection = {}) const { + return __unary(ranges::begin(__range), ranges::end(__range), std::move(__result), __operation, __projection); + } + + template _Sent1, + input_iterator _InIter2, + sentinel_for<_InIter2> _Sent2, + weakly_incrementable _OutIter, + copy_constructible _Func, + class _Proj1 = identity, + class _Proj2 = identity> + requires indirectly_writable<_OutIter, + indirect_result_t<_Func&, projected<_InIter1, _Proj1>, projected<_InIter2, _Proj2>>> + _LIBCPP_HIDE_FROM_ABI constexpr binary_transform_result<_InIter1, _InIter2, _OutIter> operator()( + _InIter1 __first1, + _Sent1 __last1, + _InIter2 __first2, + _Sent2 __last2, + _OutIter __result, + _Func __binary_operation, + _Proj1 __projection1 = {}, + _Proj2 __projection2 = {}) const { + return __binary( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + __binary_operation, + __projection1, + __projection2); + } + + template + requires indirectly_writable< + _OutIter, + indirect_result_t<_Func&, projected, _Proj1>, projected, _Proj2>>> + _LIBCPP_HIDE_FROM_ABI constexpr binary_transform_result, + borrowed_iterator_t<_Range2>, + _OutIter> + operator()(_Range1&& __range1, + _Range2&& __range2, + _OutIter __result, + _Func __binary_operation, + _Proj1 __projection1 = {}, + _Proj2 __projection2 = {}) const { + return __binary( + ranges::begin(__range1), + ranges::end(__range1), + ranges::begin(__range2), + ranges::end(__range2), + std::move(__result), + __binary_operation, + __projection1, + __projection2); + } +}; +} // namespace __transform + +inline namespace __cpo { +inline constexpr auto transform = __transform::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_TRANSFORM_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_unique.h b/libcxx/include/__cxx03/__algorithm/ranges_unique.h new file mode 100644 index 0000000000000000000000000000000000000000..7a9b7843218737e6dc8a4a75de7d50a6fc4c8306 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_unique.h @@ -0,0 +1,82 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_UNIQUE_H +#define _LIBCPP___ALGORITHM_RANGES_UNIQUE_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/unique.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/permutable.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__ranges/subrange.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __unique { + +struct __fn { + template _Sent, + class _Proj = identity, + indirect_equivalence_relation> _Comp = ranges::equal_to> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter> + operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const { + auto __ret = + std::__unique<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::__make_projected(__comp, __proj)); + return {std::move(__ret.first), std::move(__ret.second)}; + } + + template , _Proj>> _Comp = ranges::equal_to> + requires permutable> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range> + operator()(_Range&& __range, _Comp __comp = {}, _Proj __proj = {}) const { + auto __ret = std::__unique<_RangeAlgPolicy>( + ranges::begin(__range), ranges::end(__range), std::__make_projected(__comp, __proj)); + return {std::move(__ret.first), std::move(__ret.second)}; + } +}; + +} // namespace __unique + +inline namespace __cpo { +inline constexpr auto unique = __unique::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_UNIQUE_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_unique_copy.h b/libcxx/include/__cxx03/__algorithm/ranges_unique_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..61133885ae809defd1a529c69ef3892f73028ab2 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_unique_copy.h @@ -0,0 +1,120 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_UNIQUE_COPY_H +#define _LIBCPP___ALGORITHM_RANGES_UNIQUE_COPY_H + +#include <__algorithm/in_out_result.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/make_projected.h> +#include <__algorithm/unique_copy.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template +using unique_copy_result = in_out_result<_InIter, _OutIter>; + +namespace __unique_copy { + +template +concept __can_reread_from_output = (input_iterator<_OutIter> && same_as, iter_value_t<_OutIter>>); + +struct __fn { + template + static consteval auto __get_algo_tag() { + if constexpr (forward_iterator<_InIter>) { + return __unique_copy_tags::__reread_from_input_tag{}; + } else if constexpr (__can_reread_from_output<_InIter, _OutIter>) { + return __unique_copy_tags::__reread_from_output_tag{}; + } else if constexpr (indirectly_copyable_storable<_InIter, _OutIter>) { + return __unique_copy_tags::__read_from_tmp_value_tag{}; + } + } + + template + using __algo_tag_t = decltype(__get_algo_tag<_InIter, _OutIter>()); + + template _Sent, + weakly_incrementable _OutIter, + class _Proj = identity, + indirect_equivalence_relation> _Comp = ranges::equal_to> + requires indirectly_copyable<_InIter, _OutIter> && + (forward_iterator<_InIter> || + (input_iterator<_OutIter> && same_as, iter_value_t<_OutIter>>) || + indirectly_copyable_storable<_InIter, _OutIter>) + _LIBCPP_HIDE_FROM_ABI constexpr unique_copy_result<_InIter, _OutIter> + operator()(_InIter __first, _Sent __last, _OutIter __result, _Comp __comp = {}, _Proj __proj = {}) const { + auto __ret = std::__unique_copy<_RangeAlgPolicy>( + std::move(__first), + std::move(__last), + std::move(__result), + std::__make_projected(__comp, __proj), + __algo_tag_t<_InIter, _OutIter>()); + return {std::move(__ret.first), std::move(__ret.second)}; + } + + template , _Proj>> _Comp = ranges::equal_to> + requires indirectly_copyable, _OutIter> && + (forward_iterator> || + (input_iterator<_OutIter> && same_as, iter_value_t<_OutIter>>) || + indirectly_copyable_storable, _OutIter>) + _LIBCPP_HIDE_FROM_ABI constexpr unique_copy_result, _OutIter> + operator()(_Range&& __range, _OutIter __result, _Comp __comp = {}, _Proj __proj = {}) const { + auto __ret = std::__unique_copy<_RangeAlgPolicy>( + ranges::begin(__range), + ranges::end(__range), + std::move(__result), + std::__make_projected(__comp, __proj), + __algo_tag_t, _OutIter>()); + return {std::move(__ret.first), std::move(__ret.second)}; + } +}; + +} // namespace __unique_copy + +inline namespace __cpo { +inline constexpr auto unique_copy = __unique_copy::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_UNIQUE_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/ranges_upper_bound.h b/libcxx/include/__cxx03/__algorithm/ranges_upper_bound.h new file mode 100644 index 0000000000000000000000000000000000000000..fa6fa7f70ed5a7316a4021bac054e1d1d5a980c4 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/ranges_upper_bound.h @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_UPPER_BOUND_H +#define _LIBCPP___ALGORITHM_RANGES_UPPER_BOUND_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/lower_bound.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __upper_bound { +struct __fn { + template _Sent, + class _Type, + class _Proj = identity, + indirect_strict_weak_order> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Iter + operator()(_Iter __first, _Sent __last, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const { + auto __comp_lhs_rhs_swapped = [&](const auto& __lhs, const auto& __rhs) -> bool { + return !std::invoke(__comp, __rhs, __lhs); + }; + + return std::__lower_bound<_RangeAlgPolicy>(__first, __last, __value, __comp_lhs_rhs_swapped, __proj); + } + + template , _Proj>> _Comp = ranges::less> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __r, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const { + auto __comp_lhs_rhs_swapped = [&](const auto& __lhs, const auto& __rhs) -> bool { + return !std::invoke(__comp, __rhs, __lhs); + }; + + return std::__lower_bound<_RangeAlgPolicy>( + ranges::begin(__r), ranges::end(__r), __value, __comp_lhs_rhs_swapped, __proj); + } +}; +} // namespace __upper_bound + +inline namespace __cpo { +inline constexpr auto upper_bound = __upper_bound::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___ALGORITHM_RANGES_UPPER_BOUND_H diff --git a/libcxx/include/__cxx03/__algorithm/remove.h b/libcxx/include/__cxx03/__algorithm/remove.h new file mode 100644 index 0000000000000000000000000000000000000000..fd01c23cb6708a8ed9a9378511383b81848f8b6d --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/remove.h @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_REMOVE_H +#define _LIBCPP___ALGORITHM_REMOVE_H + +#include <__algorithm/find.h> +#include <__algorithm/find_if.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +remove(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + __first = std::find(__first, __last, __value); + if (__first != __last) { + _ForwardIterator __i = __first; + while (++__i != __last) { + if (!(*__i == __value)) { + *__first = std::move(*__i); + ++__first; + } + } + } + return __first; +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_REMOVE_H diff --git a/libcxx/include/__cxx03/__algorithm/remove_copy.h b/libcxx/include/__cxx03/__algorithm/remove_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..7be4c166ce3d7171a521ff5cb79e8417a5d5be85 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/remove_copy.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_REMOVE_COPY_H +#define _LIBCPP___ALGORITHM_REMOVE_COPY_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +remove_copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result, const _Tp& __value) { + for (; __first != __last; ++__first) { + if (!(*__first == __value)) { + *__result = *__first; + ++__result; + } + } + return __result; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_REMOVE_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/remove_copy_if.h b/libcxx/include/__cxx03/__algorithm/remove_copy_if.h new file mode 100644 index 0000000000000000000000000000000000000000..dcafed169157d9740ba1038b5c25771adf15628d --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/remove_copy_if.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_REMOVE_COPY_IF_H +#define _LIBCPP___ALGORITHM_REMOVE_COPY_IF_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +remove_copy_if(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _Predicate __pred) { + for (; __first != __last; ++__first) { + if (!__pred(*__first)) { + *__result = *__first; + ++__result; + } + } + return __result; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_REMOVE_COPY_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/remove_if.h b/libcxx/include/__cxx03/__algorithm/remove_if.h new file mode 100644 index 0000000000000000000000000000000000000000..b14f3c0efa7e97e4b9c20362e7a962c4ca443232 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/remove_if.h @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_REMOVE_IF_H +#define _LIBCPP___ALGORITHM_REMOVE_IF_H + +#include <__algorithm/find_if.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +remove_if(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + __first = std::find_if<_ForwardIterator, _Predicate&>(__first, __last, __pred); + if (__first != __last) { + _ForwardIterator __i = __first; + while (++__i != __last) { + if (!__pred(*__i)) { + *__first = std::move(*__i); + ++__first; + } + } + } + return __first; +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_REMOVE_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/replace.h b/libcxx/include/__cxx03/__algorithm/replace.h new file mode 100644 index 0000000000000000000000000000000000000000..8057c78686e111e5dc5e3a4ff6af99245b9cb4c9 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/replace.h @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_REPLACE_H +#define _LIBCPP___ALGORITHM_REPLACE_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +replace(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __old_value, const _Tp& __new_value) { + for (; __first != __last; ++__first) + if (*__first == __old_value) + *__first = __new_value; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_REPLACE_H diff --git a/libcxx/include/__cxx03/__algorithm/replace_copy.h b/libcxx/include/__cxx03/__algorithm/replace_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..9a2258d9f58eddd80d1fde2f24bcf7e89fada86a --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/replace_copy.h @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_REPLACE_COPY_H +#define _LIBCPP___ALGORITHM_REPLACE_COPY_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator replace_copy( + _InputIterator __first, + _InputIterator __last, + _OutputIterator __result, + const _Tp& __old_value, + const _Tp& __new_value) { + for (; __first != __last; ++__first, (void)++__result) + if (*__first == __old_value) + *__result = __new_value; + else + *__result = *__first; + return __result; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_REPLACE_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/replace_copy_if.h b/libcxx/include/__cxx03/__algorithm/replace_copy_if.h new file mode 100644 index 0000000000000000000000000000000000000000..c2ed30f08d598b4dd5f30b37e638c1ce8d1ae545 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/replace_copy_if.h @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_REPLACE_COPY_IF_H +#define _LIBCPP___ALGORITHM_REPLACE_COPY_IF_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator replace_copy_if( + _InputIterator __first, + _InputIterator __last, + _OutputIterator __result, + _Predicate __pred, + const _Tp& __new_value) { + for (; __first != __last; ++__first, (void)++__result) + if (__pred(*__first)) + *__result = __new_value; + else + *__result = *__first; + return __result; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_REPLACE_COPY_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/replace_if.h b/libcxx/include/__cxx03/__algorithm/replace_if.h new file mode 100644 index 0000000000000000000000000000000000000000..78487e3deed70929da486b5013dcff09656deb0b --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/replace_if.h @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_REPLACE_IF_H +#define _LIBCPP___ALGORITHM_REPLACE_IF_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +replace_if(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred, const _Tp& __new_value) { + for (; __first != __last; ++__first) + if (__pred(*__first)) + *__first = __new_value; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_REPLACE_IF_H diff --git a/libcxx/include/__cxx03/__algorithm/reverse.h b/libcxx/include/__cxx03/__algorithm/reverse.h new file mode 100644 index 0000000000000000000000000000000000000000..4167c9116d96e77a14d5b359640c5ced92c276a2 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/reverse.h @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_REVERSE_H +#define _LIBCPP___ALGORITHM_REVERSE_H + +#include <__algorithm/iter_swap.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +__reverse_impl(_BidirectionalIterator __first, _BidirectionalIterator __last, bidirectional_iterator_tag) { + while (__first != __last) { + if (__first == --__last) + break; + _IterOps<_AlgPolicy>::iter_swap(__first, __last); + ++__first; + } +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +__reverse_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, random_access_iterator_tag) { + if (__first != __last) + for (; __first < --__last; ++__first) + _IterOps<_AlgPolicy>::iter_swap(__first, __last); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __reverse(_BidirectionalIterator __first, _Sentinel __last) { + using _IterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_BidirectionalIterator>; + std::__reverse_impl<_AlgPolicy>(std::move(__first), std::move(__last), _IterCategory()); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +reverse(_BidirectionalIterator __first, _BidirectionalIterator __last) { + std::__reverse<_ClassicAlgPolicy>(std::move(__first), std::move(__last)); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_REVERSE_H diff --git a/libcxx/include/__cxx03/__algorithm/reverse_copy.h b/libcxx/include/__cxx03/__algorithm/reverse_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..0fcecc3923268172ad0d325e4c7c5ed4d4e13332 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/reverse_copy.h @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_REVERSE_COPY_H +#define _LIBCPP___ALGORITHM_REVERSE_COPY_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +reverse_copy(_BidirectionalIterator __first, _BidirectionalIterator __last, _OutputIterator __result) { + for (; __first != __last; ++__result) + *__result = *--__last; + return __result; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_REVERSE_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/rotate.h b/libcxx/include/__cxx03/__algorithm/rotate.h new file mode 100644 index 0000000000000000000000000000000000000000..df4ca95aac95bc972a0644de68fdd5358df71a12 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/rotate.h @@ -0,0 +1,198 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_ROTATE_H +#define _LIBCPP___ALGORITHM_ROTATE_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/move.h> +#include <__algorithm/move_backward.h> +#include <__algorithm/swap_ranges.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_trivially_assignable.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator +__rotate_left(_ForwardIterator __first, _ForwardIterator __last) { + typedef typename iterator_traits<_ForwardIterator>::value_type value_type; + using _Ops = _IterOps<_AlgPolicy>; + + value_type __tmp = _Ops::__iter_move(__first); + _ForwardIterator __lm1 = std::__move<_AlgPolicy>(_Ops::next(__first), __last, __first).second; + *__lm1 = std::move(__tmp); + return __lm1; +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _BidirectionalIterator +__rotate_right(_BidirectionalIterator __first, _BidirectionalIterator __last) { + typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type; + using _Ops = _IterOps<_AlgPolicy>; + + _BidirectionalIterator __lm1 = _Ops::prev(__last); + value_type __tmp = _Ops::__iter_move(__lm1); + _BidirectionalIterator __fp1 = std::__move_backward<_AlgPolicy>(__first, __lm1, std::move(__last)).second; + *__first = std::move(__tmp); + return __fp1; +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _ForwardIterator +__rotate_forward(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last) { + _ForwardIterator __i = __middle; + while (true) { + _IterOps<_AlgPolicy>::iter_swap(__first, __i); + ++__first; + if (++__i == __last) + break; + if (__first == __middle) + __middle = __i; + } + _ForwardIterator __r = __first; + if (__first != __middle) { + __i = __middle; + while (true) { + _IterOps<_AlgPolicy>::iter_swap(__first, __i); + ++__first; + if (++__i == __last) { + if (__first == __middle) + break; + __i = __middle; + } else if (__first == __middle) + __middle = __i; + } + } + return __r; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _Integral __algo_gcd(_Integral __x, _Integral __y) { + do { + _Integral __t = __x % __y; + __x = __y; + __y = __t; + } while (__y); + return __x; +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _RandomAccessIterator +__rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last) { + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; + typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; + using _Ops = _IterOps<_AlgPolicy>; + + const difference_type __m1 = __middle - __first; + const difference_type __m2 = _Ops::distance(__middle, __last); + if (__m1 == __m2) { + std::__swap_ranges<_AlgPolicy>(__first, __middle, __middle, __last); + return __middle; + } + const difference_type __g = std::__algo_gcd(__m1, __m2); + for (_RandomAccessIterator __p = __first + __g; __p != __first;) { + value_type __t(_Ops::__iter_move(--__p)); + _RandomAccessIterator __p1 = __p; + _RandomAccessIterator __p2 = __p1 + __m1; + do { + *__p1 = _Ops::__iter_move(__p2); + __p1 = __p2; + const difference_type __d = _Ops::distance(__p2, __last); + if (__m1 < __d) + __p2 += __m1; + else + __p2 = __first + (__m1 - __d); + } while (__p2 != __p); + *__p1 = std::move(__t); + } + return __first + __m2; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator +__rotate_impl(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last, std::forward_iterator_tag) { + typedef typename iterator_traits<_ForwardIterator>::value_type value_type; + if (is_trivially_move_assignable::value) { + if (_IterOps<_AlgPolicy>::next(__first) == __middle) + return std::__rotate_left<_AlgPolicy>(__first, __last); + } + return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _BidirectionalIterator __rotate_impl( + _BidirectionalIterator __first, + _BidirectionalIterator __middle, + _BidirectionalIterator __last, + bidirectional_iterator_tag) { + typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type; + if (is_trivially_move_assignable::value) { + if (_IterOps<_AlgPolicy>::next(__first) == __middle) + return std::__rotate_left<_AlgPolicy>(__first, __last); + if (_IterOps<_AlgPolicy>::next(__middle) == __last) + return std::__rotate_right<_AlgPolicy>(__first, __last); + } + return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _RandomAccessIterator __rotate_impl( + _RandomAccessIterator __first, + _RandomAccessIterator __middle, + _RandomAccessIterator __last, + random_access_iterator_tag) { + typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; + if (is_trivially_move_assignable::value) { + if (_IterOps<_AlgPolicy>::next(__first) == __middle) + return std::__rotate_left<_AlgPolicy>(__first, __last); + if (_IterOps<_AlgPolicy>::next(__middle) == __last) + return std::__rotate_right<_AlgPolicy>(__first, __last); + return std::__rotate_gcd<_AlgPolicy>(__first, __middle, __last); + } + return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iterator, _Iterator> +__rotate(_Iterator __first, _Iterator __middle, _Sentinel __last) { + using _Ret = pair<_Iterator, _Iterator>; + _Iterator __last_iter = _IterOps<_AlgPolicy>::next(__middle, __last); + + if (__first == __middle) + return _Ret(__last_iter, __last_iter); + if (__middle == __last) + return _Ret(std::move(__first), std::move(__last_iter)); + + using _IterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_Iterator>; + auto __result = std::__rotate_impl<_AlgPolicy>(std::move(__first), std::move(__middle), __last_iter, _IterCategory()); + + return _Ret(std::move(__result), std::move(__last_iter)); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last) { + return std::__rotate<_ClassicAlgPolicy>(std::move(__first), std::move(__middle), std::move(__last)).first; +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_ROTATE_H diff --git a/libcxx/include/__cxx03/__algorithm/rotate_copy.h b/libcxx/include/__cxx03/__algorithm/rotate_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..cddcadd237d902970497a7cf9fbf808875a095b3 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/rotate_copy.h @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_ROTATE_COPY_H +#define _LIBCPP___ALGORITHM_ROTATE_COPY_H + +#include <__algorithm/copy.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +rotate_copy(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last, _OutputIterator __result) { + return std::copy(__first, __middle, std::copy(__middle, __last, __result)); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_ROTATE_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/sample.h b/libcxx/include/__cxx03/__algorithm/sample.h new file mode 100644 index 0000000000000000000000000000000000000000..ebe5180b7eeca6120dd565f42b8cc68e1c1987ee --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/sample.h @@ -0,0 +1,123 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SAMPLE_H +#define _LIBCPP___ALGORITHM_SAMPLE_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/min.h> +#include <__assert> +#include <__config> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__random/uniform_int_distribution.h> +#include <__type_traits/common_type.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _SampleIterator __sample( + _PopulationIterator __first, + _PopulationSentinel __last, + _SampleIterator __output_iter, + _Distance __n, + _UniformRandomNumberGenerator& __g, + input_iterator_tag) { + _Distance __k = 0; + for (; __first != __last && __k < __n; ++__first, (void)++__k) + __output_iter[__k] = *__first; + _Distance __sz = __k; + for (; __first != __last; ++__first, (void)++__k) { + _Distance __r = uniform_int_distribution<_Distance>(0, __k)(__g); + if (__r < __sz) + __output_iter[__r] = *__first; + } + return __output_iter + std::min(__n, __k); +} + +template +_LIBCPP_HIDE_FROM_ABI _SampleIterator __sample( + _PopulationIterator __first, + _PopulationSentinel __last, + _SampleIterator __output_iter, + _Distance __n, + _UniformRandomNumberGenerator& __g, + forward_iterator_tag) { + _Distance __unsampled_sz = _IterOps<_AlgPolicy>::distance(__first, __last); + for (__n = std::min(__n, __unsampled_sz); __n != 0; ++__first) { + _Distance __r = uniform_int_distribution<_Distance>(0, --__unsampled_sz)(__g); + if (__r < __n) { + *__output_iter++ = *__first; + --__n; + } + } + return __output_iter; +} + +template +_LIBCPP_HIDE_FROM_ABI _SampleIterator __sample( + _PopulationIterator __first, + _PopulationSentinel __last, + _SampleIterator __output_iter, + _Distance __n, + _UniformRandomNumberGenerator& __g) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n >= 0, "N must be a positive number."); + + using _PopIterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_PopulationIterator>; + using _Difference = typename _IterOps<_AlgPolicy>::template __difference_type<_PopulationIterator>; + using _CommonType = typename common_type<_Distance, _Difference>::type; + + return std::__sample<_AlgPolicy>( + std::move(__first), std::move(__last), std::move(__output_iter), _CommonType(__n), __g, _PopIterCategory()); +} + +#if _LIBCPP_STD_VER >= 17 +template +inline _LIBCPP_HIDE_FROM_ABI _SampleIterator +sample(_PopulationIterator __first, + _PopulationIterator __last, + _SampleIterator __output_iter, + _Distance __n, + _UniformRandomNumberGenerator&& __g) { + static_assert(__has_forward_iterator_category<_PopulationIterator>::value || + __has_random_access_iterator_category<_SampleIterator>::value, + "SampleIterator must meet the requirements of RandomAccessIterator"); + + return std::__sample<_ClassicAlgPolicy>(std::move(__first), std::move(__last), std::move(__output_iter), __n, __g); +} + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_SAMPLE_H diff --git a/libcxx/include/__cxx03/__algorithm/search.h b/libcxx/include/__cxx03/__algorithm/search.h new file mode 100644 index 0000000000000000000000000000000000000000..b82ca7809535416c4005fd2c4f97744fed439cc9 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/search.h @@ -0,0 +1,192 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SEARCH_H +#define _LIBCPP___ALGORITHM_SEARCH_H + +#include <__algorithm/comp.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/advance.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_callable.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_forward_impl( + _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { + if (__first2 == __last2) + return std::make_pair(__first1, __first1); // Everything matches an empty sequence + while (true) { + // Find first element in sequence 1 that matchs *__first2, with a mininum of loop checks + while (true) { + if (__first1 == __last1) { // return __last1 if no element matches *__first2 + _IterOps<_AlgPolicy>::__advance_to(__first1, __last1); + return std::make_pair(__first1, __first1); + } + if (std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) + break; + ++__first1; + } + // *__first1 matches *__first2, now match elements after here + _Iter1 __m1 = __first1; + _Iter2 __m2 = __first2; + while (true) { + if (++__m2 == __last2) // If pattern exhausted, __first1 is the answer (works for 1 element pattern) + return std::make_pair(__first1, ++__m1); + if (++__m1 == __last1) { // Otherwise if source exhaused, pattern not found + return std::make_pair(__m1, __m1); + } + + // if there is a mismatch, restart with a new __first1 + if (!std::__invoke(__pred, std::__invoke(__proj1, *__m1), std::__invoke(__proj2, *__m2))) { + ++__first1; + break; + } // else there is a match, check next elements + } + } +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_random_access_impl( + _Iter1 __first1, + _Sent1 __last1, + _Iter2 __first2, + _Sent2 __last2, + _Pred& __pred, + _Proj1& __proj1, + _Proj2& __proj2, + _DiffT1 __size1, + _DiffT2 __size2) { + const _Iter1 __s = __first1 + __size1 - _DiffT1(__size2 - 1); // Start of pattern match can't go beyond here + + while (true) { + while (true) { + if (__first1 == __s) { + _IterOps<_AlgPolicy>::__advance_to(__first1, __last1); + return std::make_pair(__first1, __first1); + } + if (std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) + break; + ++__first1; + } + + _Iter1 __m1 = __first1; + _Iter2 __m2 = __first2; + while (true) { + if (++__m2 == __last2) + return std::make_pair(__first1, __first1 + _DiffT1(__size2)); + ++__m1; // no need to check range on __m1 because __s guarantees we have enough source + if (!std::__invoke(__pred, std::__invoke(__proj1, *__m1), std::__invoke(__proj2, *__m2))) { + ++__first1; + break; + } + } + } +} + +template ::value && + __has_random_access_iterator_category<_Iter2>::value, + int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_impl( + _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { + auto __size2 = __last2 - __first2; + if (__size2 == 0) + return std::make_pair(__first1, __first1); + + auto __size1 = __last1 - __first1; + if (__size1 < __size2) { + return std::make_pair(__last1, __last1); + } + + return std::__search_random_access_impl<_ClassicAlgPolicy>( + __first1, __last1, __first2, __last2, __pred, __proj1, __proj2, __size1, __size2); +} + +template < + class _Iter1, + class _Sent1, + class _Iter2, + class _Sent2, + class _Pred, + class _Proj1, + class _Proj2, + __enable_if_t<__has_forward_iterator_category<_Iter1>::value && __has_forward_iterator_category<_Iter2>::value && + !(__has_random_access_iterator_category<_Iter1>::value && + __has_random_access_iterator_category<_Iter2>::value), + int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_impl( + _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { + return std::__search_forward_impl<_ClassicAlgPolicy>(__first1, __last1, __first2, __last2, __pred, __proj1, __proj2); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1 +search(_ForwardIterator1 __first1, + _ForwardIterator1 __last1, + _ForwardIterator2 __first2, + _ForwardIterator2 __last2, + _BinaryPredicate __pred) { + static_assert(__is_callable<_BinaryPredicate, decltype(*__first1), decltype(*__first2)>::value, + "BinaryPredicate has to be callable"); + auto __proj = __identity(); + return std::__search_impl(__first1, __last1, __first2, __last2, __pred, __proj, __proj).first; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1 +search(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2) { + return std::search(__first1, __last1, __first2, __last2, __equal_to()); +} + +#if _LIBCPP_STD_VER >= 17 +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +search(_ForwardIterator __f, _ForwardIterator __l, const _Searcher& __s) { + return __s(__f, __l).first; +} + +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_SEARCH_H diff --git a/libcxx/include/__cxx03/__algorithm/search_n.h b/libcxx/include/__cxx03/__algorithm/search_n.h new file mode 100644 index 0000000000000000000000000000000000000000..771647d3168a43f03bef02f88d7ee6de0bdb154b --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/search_n.h @@ -0,0 +1,155 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SEARCH_N_H +#define _LIBCPP___ALGORITHM_SEARCH_N_H + +#include <__algorithm/comp.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/advance.h> +#include <__iterator/concepts.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__ranges/concepts.h> +#include <__type_traits/is_callable.h> +#include <__utility/convert_to_integral.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter, _Iter> __search_n_forward_impl( + _Iter __first, _Sent __last, _SizeT __count, const _Type& __value, _Pred& __pred, _Proj& __proj) { + if (__count <= 0) + return std::make_pair(__first, __first); + while (true) { + // Find first element in sequence that matchs __value, with a mininum of loop checks + while (true) { + if (__first == __last) { // return __last if no element matches __value + _IterOps<_AlgPolicy>::__advance_to(__first, __last); + return std::make_pair(__first, __first); + } + if (std::__invoke(__pred, std::__invoke(__proj, *__first), __value)) + break; + ++__first; + } + // *__first matches __value, now match elements after here + _Iter __m = __first; + _SizeT __c(0); + while (true) { + if (++__c == __count) // If pattern exhausted, __first is the answer (works for 1 element pattern) + return std::make_pair(__first, ++__m); + if (++__m == __last) { // Otherwise if source exhaused, pattern not found + _IterOps<_AlgPolicy>::__advance_to(__first, __last); + return std::make_pair(__first, __first); + } + + // if there is a mismatch, restart with a new __first + if (!std::__invoke(__pred, std::__invoke(__proj, *__m), __value)) { + __first = __m; + ++__first; + break; + } // else there is a match, check next elements + } + } +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 std::pair<_Iter, _Iter> __search_n_random_access_impl( + _Iter __first, _Sent __last, _SizeT __count, const _Type& __value, _Pred& __pred, _Proj& __proj, _DiffT __size1) { + using difference_type = typename iterator_traits<_Iter>::difference_type; + if (__count == 0) + return std::make_pair(__first, __first); + if (__size1 < static_cast<_DiffT>(__count)) { + _IterOps<_AlgPolicy>::__advance_to(__first, __last); + return std::make_pair(__first, __first); + } + + const auto __s = __first + __size1 - difference_type(__count - 1); // Start of pattern match can't go beyond here + while (true) { + // Find first element in sequence that matchs __value, with a mininum of loop checks + while (true) { + if (__first >= __s) { // return __last if no element matches __value + _IterOps<_AlgPolicy>::__advance_to(__first, __last); + return std::make_pair(__first, __first); + } + if (std::__invoke(__pred, std::__invoke(__proj, *__first), __value)) + break; + ++__first; + } + // *__first matches __value_, now match elements after here + auto __m = __first; + _SizeT __c(0); + while (true) { + if (++__c == __count) // If pattern exhausted, __first is the answer (works for 1 element pattern) + return std::make_pair(__first, __first + _DiffT(__count)); + ++__m; // no need to check range on __m because __s guarantees we have enough source + + // if there is a mismatch, restart with a new __first + if (!std::__invoke(__pred, std::__invoke(__proj, *__m), __value)) { + __first = __m; + ++__first; + break; + } // else there is a match, check next elements + } + } +} + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter, _Iter> +__search_n_impl(_Iter __first, _Sent __last, _DiffT __count, const _Type& __value, _Pred& __pred, _Proj& __proj) { + return std::__search_n_random_access_impl<_ClassicAlgPolicy>( + __first, __last, __count, __value, __pred, __proj, __last - __first); +} + +template ::value && + !__has_random_access_iterator_category<_Iter1>::value, + int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> +__search_n_impl(_Iter1 __first, _Sent1 __last, _DiffT __count, const _Type& __value, _Pred& __pred, _Proj& __proj) { + return std::__search_n_forward_impl<_ClassicAlgPolicy>(__first, __last, __count, __value, __pred, __proj); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator search_n( + _ForwardIterator __first, _ForwardIterator __last, _Size __count, const _Tp& __value, _BinaryPredicate __pred) { + static_assert( + __is_callable<_BinaryPredicate, decltype(*__first), const _Tp&>::value, "BinaryPredicate has to be callable"); + auto __proj = __identity(); + return std::__search_n_impl(__first, __last, std::__convert_to_integral(__count), __value, __pred, __proj).first; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +search_n(_ForwardIterator __first, _ForwardIterator __last, _Size __count, const _Tp& __value) { + return std::search_n(__first, __last, std::__convert_to_integral(__count), __value, __equal_to()); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_SEARCH_N_H diff --git a/libcxx/include/__cxx03/__algorithm/set_difference.h b/libcxx/include/__cxx03/__algorithm/set_difference.h new file mode 100644 index 0000000000000000000000000000000000000000..f414bcecb50df1823287a798a961ced46ffb3984 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/set_difference.h @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SET_DIFFERENCE_H +#define _LIBCPP___ALGORITHM_SET_DIFFERENCE_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/copy.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__remove_cvref_t<_InIter1>, __remove_cvref_t<_OutIter> > +__set_difference( + _InIter1&& __first1, _Sent1&& __last1, _InIter2&& __first2, _Sent2&& __last2, _OutIter&& __result, _Comp&& __comp) { + while (__first1 != __last1 && __first2 != __last2) { + if (__comp(*__first1, *__first2)) { + *__result = *__first1; + ++__first1; + ++__result; + } else if (__comp(*__first2, *__first1)) { + ++__first2; + } else { + ++__first1; + ++__first2; + } + } + return std::__copy<_AlgPolicy>(std::move(__first1), std::move(__last1), std::move(__result)); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_difference( + _InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _OutputIterator __result, + _Compare __comp) { + return std::__set_difference<_ClassicAlgPolicy, __comp_ref_type<_Compare> >( + __first1, __last1, __first2, __last2, __result, __comp) + .second; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_difference( + _InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _OutputIterator __result) { + return std::__set_difference<_ClassicAlgPolicy>(__first1, __last1, __first2, __last2, __result, __less<>()).second; +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_SET_DIFFERENCE_H diff --git a/libcxx/include/__cxx03/__algorithm/set_intersection.h b/libcxx/include/__cxx03/__algorithm/set_intersection.h new file mode 100644 index 0000000000000000000000000000000000000000..bb0d86cd0f58d2e73624bd42cc97400d983d6a2d --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/set_intersection.h @@ -0,0 +1,217 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SET_INTERSECTION_H +#define _LIBCPP___ALGORITHM_SET_INTERSECTION_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/lower_bound.h> +#include <__config> +#include <__functional/identity.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__type_traits/is_same.h> +#include <__utility/exchange.h> +#include <__utility/move.h> +#include <__utility/swap.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __set_intersection_result { + _InIter1 __in1_; + _InIter2 __in2_; + _OutIter __out_; + + // need a constructor as C++03 aggregate init is hard + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + __set_intersection_result(_InIter1&& __in_iter1, _InIter2&& __in_iter2, _OutIter&& __out_iter) + : __in1_(std::move(__in_iter1)), __in2_(std::move(__in_iter2)), __out_(std::move(__out_iter)) {} +}; + +// Helper for __set_intersection() with one-sided binary search: populate result and advance input iterators if they +// are found to potentially contain the same value in two consecutive calls. This function is very intimately related to +// the way it is used and doesn't attempt to abstract that, it's not appropriate for general usage outside of its +// context. +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_intersection_add_output_if_equal( + bool __may_be_equal, + _InForwardIter1& __first1, + _InForwardIter2& __first2, + _OutIter& __result, + bool& __prev_may_be_equal) { + if (__may_be_equal && __prev_may_be_equal) { + *__result = *__first1; + ++__result; + ++__first1; + ++__first2; + __prev_may_be_equal = false; + } else { + __prev_may_be_equal = __may_be_equal; + } +} + +// With forward iterators we can make multiple passes over the data, allowing the use of one-sided binary search to +// reduce best-case complexity to log(N). Understanding how we can use binary search and still respect complexity +// guarantees is _not_ straightforward: the guarantee is "at most 2*(N+M)-1 comparisons", and one-sided binary search +// will necessarily overshoot depending on the position of the needle in the haystack -- for instance, if we're +// searching for 3 in (1, 2, 3, 4), we'll check if 3<1, then 3<2, then 3<4, and, finally, 3<3, for a total of 4 +// comparisons, when linear search would have yielded 3. However, because we won't need to perform the intervening +// reciprocal comparisons (ie 1<3, 2<3, 4<3), that extra comparison doesn't run afoul of the guarantee. Additionally, +// this type of scenario can only happen for match distances of up to 5 elements, because 2*log2(8) is 6, and we'll +// still be worse-off at position 5 of an 8-element set. From then onwards these scenarios can't happen. TL;DR: we'll be +// 1 comparison worse-off compared to the classic linear-searching algorithm if matching position 3 of a set with 4 +// elements, or position 5 if the set has 7 or 8 elements, but we'll never exceed the complexity guarantees from the +// standard. +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InForwardIter1, _InForwardIter2, _OutIter> +__set_intersection( + _InForwardIter1 __first1, + _Sent1 __last1, + _InForwardIter2 __first2, + _Sent2 __last2, + _OutIter __result, + _Compare&& __comp, + std::forward_iterator_tag, + std::forward_iterator_tag) { + _LIBCPP_CONSTEXPR std::__identity __proj; + bool __prev_may_be_equal = false; + + while (__first2 != __last2) { + _InForwardIter1 __first1_next = + std::__lower_bound_onesided<_AlgPolicy>(__first1, __last1, *__first2, __comp, __proj); + std::swap(__first1_next, __first1); + // keeping in mind that a==b iff !(a(__first2, __last2, *__first1, __comp, __proj); + std::swap(__first2_next, __first2); + std::__set_intersection_add_output_if_equal( + __first2 == __first2_next, __first1, __first2, __result, __prev_may_be_equal); + } + return __set_intersection_result<_InForwardIter1, _InForwardIter2, _OutIter>( + _IterOps<_AlgPolicy>::next(std::move(__first1), std::move(__last1)), + _IterOps<_AlgPolicy>::next(std::move(__first2), std::move(__last2)), + std::move(__result)); +} + +// input iterators are not suitable for multipass algorithms, so we stick to the classic single-pass version +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InInputIter1, _InInputIter2, _OutIter> +__set_intersection( + _InInputIter1 __first1, + _Sent1 __last1, + _InInputIter2 __first2, + _Sent2 __last2, + _OutIter __result, + _Compare&& __comp, + std::input_iterator_tag, + std::input_iterator_tag) { + while (__first1 != __last1 && __first2 != __last2) { + if (__comp(*__first1, *__first2)) + ++__first1; + else { + if (!__comp(*__first2, *__first1)) { + *__result = *__first1; + ++__result; + ++__first1; + } + ++__first2; + } + } + + return __set_intersection_result<_InInputIter1, _InInputIter2, _OutIter>( + _IterOps<_AlgPolicy>::next(std::move(__first1), std::move(__last1)), + _IterOps<_AlgPolicy>::next(std::move(__first2), std::move(__last2)), + std::move(__result)); +} + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InIter1, _InIter2, _OutIter> +__set_intersection( + _InIter1 __first1, _Sent1 __last1, _InIter2 __first2, _Sent2 __last2, _OutIter __result, _Compare&& __comp) { + return std::__set_intersection<_AlgPolicy>( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + std::forward<_Compare>(__comp), + typename std::_IterOps<_AlgPolicy>::template __iterator_category<_InIter1>(), + typename std::_IterOps<_AlgPolicy>::template __iterator_category<_InIter2>()); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_intersection( + _InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _OutputIterator __result, + _Compare __comp) { + return std::__set_intersection<_ClassicAlgPolicy, __comp_ref_type<_Compare> >( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + __comp) + .__out_; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_intersection( + _InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _OutputIterator __result) { + return std::__set_intersection<_ClassicAlgPolicy>( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + __less<>()) + .__out_; +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_SET_INTERSECTION_H diff --git a/libcxx/include/__cxx03/__algorithm/set_symmetric_difference.h b/libcxx/include/__cxx03/__algorithm/set_symmetric_difference.h new file mode 100644 index 0000000000000000000000000000000000000000..db36665a61365cdfe2892f6d19f5b97a544fe8e1 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/set_symmetric_difference.h @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SET_SYMMETRIC_DIFFERENCE_H +#define _LIBCPP___ALGORITHM_SET_SYMMETRIC_DIFFERENCE_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/copy.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __set_symmetric_difference_result { + _InIter1 __in1_; + _InIter2 __in2_; + _OutIter __out_; + + // need a constructor as C++03 aggregate init is hard + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + __set_symmetric_difference_result(_InIter1&& __in_iter1, _InIter2&& __in_iter2, _OutIter&& __out_iter) + : __in1_(std::move(__in_iter1)), __in2_(std::move(__in_iter2)), __out_(std::move(__out_iter)) {} +}; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_symmetric_difference_result<_InIter1, _InIter2, _OutIter> +__set_symmetric_difference( + _InIter1 __first1, _Sent1 __last1, _InIter2 __first2, _Sent2 __last2, _OutIter __result, _Compare&& __comp) { + while (__first1 != __last1) { + if (__first2 == __last2) { + auto __ret1 = std::__copy<_AlgPolicy>(std::move(__first1), std::move(__last1), std::move(__result)); + return __set_symmetric_difference_result<_InIter1, _InIter2, _OutIter>( + std::move(__ret1.first), std::move(__first2), std::move((__ret1.second))); + } + if (__comp(*__first1, *__first2)) { + *__result = *__first1; + ++__result; + ++__first1; + } else { + if (__comp(*__first2, *__first1)) { + *__result = *__first2; + ++__result; + } else { + ++__first1; + } + ++__first2; + } + } + auto __ret2 = std::__copy<_AlgPolicy>(std::move(__first2), std::move(__last2), std::move(__result)); + return __set_symmetric_difference_result<_InIter1, _InIter2, _OutIter>( + std::move(__first1), std::move(__ret2.first), std::move((__ret2.second))); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_symmetric_difference( + _InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _OutputIterator __result, + _Compare __comp) { + return std::__set_symmetric_difference<_ClassicAlgPolicy, __comp_ref_type<_Compare> >( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + __comp) + .__out_; +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_symmetric_difference( + _InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _OutputIterator __result) { + return std::set_symmetric_difference( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_SET_SYMMETRIC_DIFFERENCE_H diff --git a/libcxx/include/__cxx03/__algorithm/set_union.h b/libcxx/include/__cxx03/__algorithm/set_union.h new file mode 100644 index 0000000000000000000000000000000000000000..a79c50fd3cf2f080405d0fc4b1e04e3813266d33 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/set_union.h @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SET_UNION_H +#define _LIBCPP___ALGORITHM_SET_UNION_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/copy.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __set_union_result { + _InIter1 __in1_; + _InIter2 __in2_; + _OutIter __out_; + + // need a constructor as C++03 aggregate init is hard + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + __set_union_result(_InIter1&& __in_iter1, _InIter2&& __in_iter2, _OutIter&& __out_iter) + : __in1_(std::move(__in_iter1)), __in2_(std::move(__in_iter2)), __out_(std::move(__out_iter)) {} +}; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_union_result<_InIter1, _InIter2, _OutIter> __set_union( + _InIter1 __first1, _Sent1 __last1, _InIter2 __first2, _Sent2 __last2, _OutIter __result, _Compare&& __comp) { + for (; __first1 != __last1; ++__result) { + if (__first2 == __last2) { + auto __ret1 = std::__copy<_AlgPolicy>(std::move(__first1), std::move(__last1), std::move(__result)); + return __set_union_result<_InIter1, _InIter2, _OutIter>( + std::move(__ret1.first), std::move(__first2), std::move((__ret1.second))); + } + if (__comp(*__first2, *__first1)) { + *__result = *__first2; + ++__first2; + } else { + if (!__comp(*__first1, *__first2)) { + ++__first2; + } + *__result = *__first1; + ++__first1; + } + } + auto __ret2 = std::__copy<_AlgPolicy>(std::move(__first2), std::move(__last2), std::move(__result)); + return __set_union_result<_InIter1, _InIter2, _OutIter>( + std::move(__first1), std::move(__ret2.first), std::move((__ret2.second))); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_union( + _InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _OutputIterator __result, + _Compare __comp) { + return std::__set_union<_ClassicAlgPolicy, __comp_ref_type<_Compare> >( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + __comp) + .__out_; +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_union( + _InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _OutputIterator __result) { + return std::set_union( + std::move(__first1), + std::move(__last1), + std::move(__first2), + std::move(__last2), + std::move(__result), + __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_SET_UNION_H diff --git a/libcxx/include/__cxx03/__algorithm/shift_left.h b/libcxx/include/__cxx03/__algorithm/shift_left.h new file mode 100644 index 0000000000000000000000000000000000000000..06cd7c5f87644e93dbd8d4aa49a672ab9cc693ef --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/shift_left.h @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SHIFT_LEFT_H +#define _LIBCPP___ALGORITHM_SHIFT_LEFT_H + +#include <__algorithm/move.h> +#include <__config> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +inline _LIBCPP_HIDE_FROM_ABI constexpr _ForwardIterator +shift_left(_ForwardIterator __first, + _ForwardIterator __last, + typename iterator_traits<_ForwardIterator>::difference_type __n) { + if (__n == 0) { + return __last; + } + + _ForwardIterator __m = __first; + if constexpr (__has_random_access_iterator_category<_ForwardIterator>::value) { + if (__n >= __last - __first) { + return __first; + } + __m += __n; + } else { + for (; __n > 0; --__n) { + if (__m == __last) { + return __first; + } + ++__m; + } + } + return std::move(__m, __last, __first); +} + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_SHIFT_LEFT_H diff --git a/libcxx/include/__cxx03/__algorithm/shift_right.h b/libcxx/include/__cxx03/__algorithm/shift_right.h new file mode 100644 index 0000000000000000000000000000000000000000..01853057fc47887f0b86c3f97da356d0fe643d9d --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/shift_right.h @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SHIFT_RIGHT_H +#define _LIBCPP___ALGORITHM_SHIFT_RIGHT_H + +#include <__algorithm/move.h> +#include <__algorithm/move_backward.h> +#include <__algorithm/swap_ranges.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__utility/swap.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +inline _LIBCPP_HIDE_FROM_ABI constexpr _ForwardIterator +shift_right(_ForwardIterator __first, + _ForwardIterator __last, + typename iterator_traits<_ForwardIterator>::difference_type __n) { + if (__n == 0) { + return __first; + } + + if constexpr (__has_random_access_iterator_category<_ForwardIterator>::value) { + decltype(__n) __d = __last - __first; + if (__n >= __d) { + return __last; + } + _ForwardIterator __m = __first + (__d - __n); + return std::move_backward(__first, __m, __last); + } else if constexpr (__has_bidirectional_iterator_category<_ForwardIterator>::value) { + _ForwardIterator __m = __last; + for (; __n > 0; --__n) { + if (__m == __first) { + return __last; + } + --__m; + } + return std::move_backward(__first, __m, __last); + } else { + _ForwardIterator __ret = __first; + for (; __n > 0; --__n) { + if (__ret == __last) { + return __last; + } + ++__ret; + } + + // We have an __n-element scratch space from __first to __ret. + // Slide an __n-element window [__trail, __lead) from left to right. + // We're essentially doing swap_ranges(__first, __ret, __trail, __lead) + // over and over; but once __lead reaches __last we needn't bother + // to save the values of elements [__trail, __last). + + auto __trail = __first; + auto __lead = __ret; + while (__trail != __ret) { + if (__lead == __last) { + std::move(__first, __trail, __ret); + return __ret; + } + ++__trail; + ++__lead; + } + + _ForwardIterator __mid = __first; + while (true) { + if (__lead == __last) { + __trail = std::move(__mid, __ret, __trail); + std::move(__first, __mid, __trail); + return __ret; + } + swap(*__mid, *__trail); + ++__mid; + ++__trail; + ++__lead; + if (__mid == __ret) { + __mid = __first; + } + } + } +} + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_SHIFT_RIGHT_H diff --git a/libcxx/include/__cxx03/__algorithm/shuffle.h b/libcxx/include/__cxx03/__algorithm/shuffle.h new file mode 100644 index 0000000000000000000000000000000000000000..c9c56ce8c2c0b1e81b047ff56ce8718cf9173992 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/shuffle.h @@ -0,0 +1,167 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SHUFFLE_H +#define _LIBCPP___ALGORITHM_SHUFFLE_H + +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__random/uniform_int_distribution.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <__utility/swap.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +class _LIBCPP_EXPORTED_FROM_ABI __libcpp_debug_randomizer { +public: + _LIBCPP_HIDE_FROM_ABI __libcpp_debug_randomizer() { + __state_ = __seed(); + __inc_ = __state_ + 0xda3e39cb94b95bdbULL; + __inc_ = (__inc_ << 1) | 1; + } + typedef uint_fast32_t result_type; + + static const result_type _Min = 0; + static const result_type _Max = 0xFFFFFFFF; + + _LIBCPP_HIDE_FROM_ABI result_type operator()() { + uint_fast64_t __oldstate = __state_; + __state_ = __oldstate * 6364136223846793005ULL + __inc_; + return __oldstate >> 32; + } + + static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR result_type min() { return _Min; } + static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR result_type max() { return _Max; } + +private: + uint_fast64_t __state_; + uint_fast64_t __inc_; + _LIBCPP_HIDE_FROM_ABI static uint_fast64_t __seed() { +#ifdef _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY_SEED + return _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY_SEED; +#else + static char __x; + return reinterpret_cast(&__x); +#endif + } +}; + +#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_RANDOM_SHUFFLE) || defined(_LIBCPP_BUILDING_LIBRARY) +class _LIBCPP_EXPORTED_FROM_ABI __rs_default; + +_LIBCPP_EXPORTED_FROM_ABI __rs_default __rs_get(); + +class _LIBCPP_EXPORTED_FROM_ABI __rs_default { + static unsigned __c_; + + __rs_default(); + +public: + typedef uint_fast32_t result_type; + + static const result_type _Min = 0; + static const result_type _Max = 0xFFFFFFFF; + + __rs_default(const __rs_default&); + ~__rs_default(); + + result_type operator()(); + + static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR result_type min() { return _Min; } + static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR result_type max() { return _Max; } + + friend _LIBCPP_EXPORTED_FROM_ABI __rs_default __rs_get(); +}; + +_LIBCPP_EXPORTED_FROM_ABI __rs_default __rs_get(); + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_IN_CXX14 void +random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last) { + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; + typedef uniform_int_distribution _Dp; + typedef typename _Dp::param_type _Pp; + difference_type __d = __last - __first; + if (__d > 1) { + _Dp __uid; + __rs_default __g = __rs_get(); + for (--__last, (void)--__d; __first < __last; ++__first, (void)--__d) { + difference_type __i = __uid(__g, _Pp(0, __d)); + if (__i != difference_type(0)) + swap(*__first, *(__first + __i)); + } + } +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_IN_CXX14 void +random_shuffle(_RandomAccessIterator __first, + _RandomAccessIterator __last, +# ifndef _LIBCPP_CXX03_LANG + _RandomNumberGenerator&& __rand) +# else + _RandomNumberGenerator& __rand) +# endif +{ + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; + difference_type __d = __last - __first; + if (__d > 1) { + for (--__last; __first < __last; ++__first, (void)--__d) { + difference_type __i = __rand(__d); + if (__i != difference_type(0)) + swap(*__first, *(__first + __i)); + } + } +} +#endif + +template +_LIBCPP_HIDE_FROM_ABI _RandomAccessIterator +__shuffle(_RandomAccessIterator __first, _Sentinel __last_sentinel, _UniformRandomNumberGenerator&& __g) { + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; + typedef uniform_int_distribution _Dp; + typedef typename _Dp::param_type _Pp; + + auto __original_last = _IterOps<_AlgPolicy>::next(__first, __last_sentinel); + auto __last = __original_last; + difference_type __d = __last - __first; + if (__d > 1) { + _Dp __uid; + for (--__last, (void)--__d; __first < __last; ++__first, (void)--__d) { + difference_type __i = __uid(__g, _Pp(0, __d)); + if (__i != difference_type(0)) + _IterOps<_AlgPolicy>::iter_swap(__first, __first + __i); + } + } + + return __original_last; +} + +template +_LIBCPP_HIDE_FROM_ABI void +shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last, _UniformRandomNumberGenerator&& __g) { + (void)std::__shuffle<_ClassicAlgPolicy>( + std::move(__first), std::move(__last), std::forward<_UniformRandomNumberGenerator>(__g)); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_SHUFFLE_H diff --git a/libcxx/include/__cxx03/__algorithm/sift_down.h b/libcxx/include/__cxx03/__algorithm/sift_down.h new file mode 100644 index 0000000000000000000000000000000000000000..42803e30631fb12b322e65dfa21cc45c15718e1d --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/sift_down.h @@ -0,0 +1,118 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SIFT_DOWN_H +#define _LIBCPP___ALGORITHM_SIFT_DOWN_H + +#include <__algorithm/iterator_operations.h> +#include <__assert> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void +__sift_down(_RandomAccessIterator __first, + _Compare&& __comp, + typename iterator_traits<_RandomAccessIterator>::difference_type __len, + _RandomAccessIterator __start) { + using _Ops = _IterOps<_AlgPolicy>; + + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; + typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; + // left-child of __start is at 2 * __start + 1 + // right-child of __start is at 2 * __start + 2 + difference_type __child = __start - __first; + + if (__len < 2 || (__len - 2) / 2 < __child) + return; + + __child = 2 * __child + 1; + _RandomAccessIterator __child_i = __first + __child; + + if ((__child + 1) < __len && __comp(*__child_i, *(__child_i + difference_type(1)))) { + // right-child exists and is greater than left-child + ++__child_i; + ++__child; + } + + // check if we are in heap-order + if (__comp(*__child_i, *__start)) + // we are, __start is larger than its largest child + return; + + value_type __top(_Ops::__iter_move(__start)); + do { + // we are not in heap-order, swap the parent with its largest child + *__start = _Ops::__iter_move(__child_i); + __start = __child_i; + + if ((__len - 2) / 2 < __child) + break; + + // recompute the child based off of the updated parent + __child = 2 * __child + 1; + __child_i = __first + __child; + + if ((__child + 1) < __len && __comp(*__child_i, *(__child_i + difference_type(1)))) { + // right-child exists and is greater than left-child + ++__child_i; + ++__child; + } + + // check if we are in heap-order + } while (!__comp(*__child_i, __top)); + *__start = std::move(__top); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _RandomAccessIterator __floyd_sift_down( + _RandomAccessIterator __first, + _Compare&& __comp, + typename iterator_traits<_RandomAccessIterator>::difference_type __len) { + using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type; + _LIBCPP_ASSERT_INTERNAL(__len >= 2, "shouldn't be called unless __len >= 2"); + + _RandomAccessIterator __hole = __first; + _RandomAccessIterator __child_i = __first; + difference_type __child = 0; + + while (true) { + __child_i += difference_type(__child + 1); + __child = 2 * __child + 1; + + if ((__child + 1) < __len && __comp(*__child_i, *(__child_i + difference_type(1)))) { + // right-child exists and is greater than left-child + ++__child_i; + ++__child; + } + + // swap __hole with its largest child + *__hole = _IterOps<_AlgPolicy>::__iter_move(__child_i); + __hole = __child_i; + + // if __hole is now a leaf, we're done + if (__child > (__len - 2) / 2) + return __hole; + } +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_SIFT_DOWN_H diff --git a/libcxx/include/__cxx03/__algorithm/simd_utils.h b/libcxx/include/__cxx03/__algorithm/simd_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..549197be80183f9116b6e48a0db5ab247dcdec5b --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/simd_utils.h @@ -0,0 +1,164 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SIMD_UTILS_H +#define _LIBCPP___ALGORITHM_SIMD_UTILS_H + +#include <__algorithm/min.h> +#include <__bit/bit_cast.h> +#include <__bit/countl.h> +#include <__bit/countr.h> +#include <__config> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_same.h> +#include <__utility/integer_sequence.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +// TODO: Find out how altivec changes things and allow vectorizations there too. +#if _LIBCPP_STD_VER >= 14 && defined(_LIBCPP_CLANG_VER) && !defined(__ALTIVEC__) +# define _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS 1 +#else +# define _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS 0 +#endif + +#if _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS && !defined(__OPTIMIZE_SIZE__) +# define _LIBCPP_VECTORIZE_ALGORITHMS 1 +#else +# define _LIBCPP_VECTORIZE_ALGORITHMS 0 +#endif + +#if _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline constexpr bool __can_map_to_integer_v = + sizeof(_Tp) == alignof(_Tp) && (sizeof(_Tp) == 1 || sizeof(_Tp) == 2 || sizeof(_Tp) == 4 || sizeof(_Tp) == 8); + +template +struct __get_as_integer_type_impl; + +template <> +struct __get_as_integer_type_impl<1> { + using type = uint8_t; +}; + +template <> +struct __get_as_integer_type_impl<2> { + using type = uint16_t; +}; +template <> +struct __get_as_integer_type_impl<4> { + using type = uint32_t; +}; +template <> +struct __get_as_integer_type_impl<8> { + using type = uint64_t; +}; + +template +using __get_as_integer_type_t = typename __get_as_integer_type_impl::type; + +// This isn't specialized for 64 byte vectors on purpose. They have the potential to significantly reduce performance +// in mixed simd/non-simd workloads and don't provide any performance improvement for currently vectorized algorithms +// as far as benchmarks are concerned. +# if defined(__AVX__) || defined(__MVS__) +template +inline constexpr size_t __native_vector_size = 32 / sizeof(_Tp); +# elif defined(__SSE__) || defined(__ARM_NEON__) +template +inline constexpr size_t __native_vector_size = 16 / sizeof(_Tp); +# elif defined(__MMX__) +template +inline constexpr size_t __native_vector_size = 8 / sizeof(_Tp); +# else +template +inline constexpr size_t __native_vector_size = 1; +# endif + +template +using __simd_vector __attribute__((__ext_vector_type__(_Np))) = _ArithmeticT; + +template +inline constexpr size_t __simd_vector_size_v = []() -> size_t { + static_assert(_False, "Not a vector!"); +}(); + +template +inline constexpr size_t __simd_vector_size_v<__simd_vector<_Tp, _Np>> = _Np; + +template +_LIBCPP_HIDE_FROM_ABI _Tp __simd_vector_underlying_type_impl(__simd_vector<_Tp, _Np>) { + return _Tp{}; +} + +template +using __simd_vector_underlying_type_t = decltype(std::__simd_vector_underlying_type_impl(_VecT{})); + +// This isn't inlined without always_inline when loading chars. +template +_LIBCPP_NODISCARD _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _VecT __load_vector(_Iter __iter) noexcept { + return [=](index_sequence<_Indices...>) _LIBCPP_ALWAYS_INLINE noexcept { + return _VecT{__iter[_Indices]...}; + }(make_index_sequence<__simd_vector_size_v<_VecT>>{}); +} + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI bool __all_of(__simd_vector<_Tp, _Np> __vec) noexcept { + return __builtin_reduce_and(__builtin_convertvector(__vec, __simd_vector)); +} + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI size_t __find_first_set(__simd_vector<_Tp, _Np> __vec) noexcept { + using __mask_vec = __simd_vector; + + // This has MSan disabled du to https://github.com/llvm/llvm-project/issues/85876 + auto __impl = [&](_MaskT) _LIBCPP_NO_SANITIZE("memory") noexcept { +# if defined(_LIBCPP_BIG_ENDIAN) + return std::min( + _Np, std::__countl_zero(__builtin_bit_cast(_MaskT, __builtin_convertvector(__vec, __mask_vec)))); +# else + return std::min( + _Np, std::__countr_zero(__builtin_bit_cast(_MaskT, __builtin_convertvector(__vec, __mask_vec)))); +# endif + }; + + if constexpr (sizeof(__mask_vec) == sizeof(uint8_t)) { + return __impl(uint8_t{}); + } else if constexpr (sizeof(__mask_vec) == sizeof(uint16_t)) { + return __impl(uint16_t{}); + } else if constexpr (sizeof(__mask_vec) == sizeof(uint32_t)) { + return __impl(uint32_t{}); + } else if constexpr (sizeof(__mask_vec) == sizeof(uint64_t)) { + return __impl(uint64_t{}); + } else { + static_assert(sizeof(__mask_vec) == 0, "unexpected required size for mask integer type"); + return 0; + } +} + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI size_t __find_first_not_set(__simd_vector<_Tp, _Np> __vec) noexcept { + return std::__find_first_set(~__vec); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_SIMD_UTILS_H diff --git a/libcxx/include/__cxx03/__algorithm/sort.h b/libcxx/include/__cxx03/__algorithm/sort.h new file mode 100644 index 0000000000000000000000000000000000000000..07b5814639e9e48fd1a428a3a6989b48ce88ce15 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/sort.h @@ -0,0 +1,1016 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SORT_H +#define _LIBCPP___ALGORITHM_SORT_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/iter_swap.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/min_element.h> +#include <__algorithm/partial_sort.h> +#include <__algorithm/unwrap_iter.h> +#include <__assert> +#include <__bit/blsr.h> +#include <__bit/countl.h> +#include <__bit/countr.h> +#include <__config> +#include <__debug_utils/randomize_range.h> +#include <__debug_utils/strict_weak_ordering_check.h> +#include <__functional/operations.h> +#include <__functional/ranges_operations.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/conditional.h> +#include <__type_traits/disjunction.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_constant_evaluated.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// stable, 2-3 compares, 0-2 swaps + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 unsigned +__sort3(_ForwardIterator __x, _ForwardIterator __y, _ForwardIterator __z, _Compare __c) { + using _Ops = _IterOps<_AlgPolicy>; + + unsigned __r = 0; + if (!__c(*__y, *__x)) // if x <= y + { + if (!__c(*__z, *__y)) // if y <= z + return __r; // x <= y && y <= z + // x <= y && y > z + _Ops::iter_swap(__y, __z); // x <= z && y < z + __r = 1; + if (__c(*__y, *__x)) // if x > y + { + _Ops::iter_swap(__x, __y); // x < y && y <= z + __r = 2; + } + return __r; // x <= y && y < z + } + if (__c(*__z, *__y)) // x > y, if y > z + { + _Ops::iter_swap(__x, __z); // x < y && y < z + __r = 1; + return __r; + } + _Ops::iter_swap(__x, __y); // x > y && y <= z + __r = 1; // x < y && x <= z + if (__c(*__z, *__y)) // if y > z + { + _Ops::iter_swap(__y, __z); // x <= y && y < z + __r = 2; + } + return __r; +} // x <= y && y <= z + +// stable, 3-6 compares, 0-5 swaps + +template +_LIBCPP_HIDE_FROM_ABI void +__sort4(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3, _ForwardIterator __x4, _Compare __c) { + using _Ops = _IterOps<_AlgPolicy>; + std::__sort3<_AlgPolicy, _Compare>(__x1, __x2, __x3, __c); + if (__c(*__x4, *__x3)) { + _Ops::iter_swap(__x3, __x4); + if (__c(*__x3, *__x2)) { + _Ops::iter_swap(__x2, __x3); + if (__c(*__x2, *__x1)) { + _Ops::iter_swap(__x1, __x2); + } + } + } +} + +// stable, 4-10 compares, 0-9 swaps + +template +_LIBCPP_HIDE_FROM_ABI void +__sort5(_ForwardIterator __x1, + _ForwardIterator __x2, + _ForwardIterator __x3, + _ForwardIterator __x4, + _ForwardIterator __x5, + _Comp __comp) { + using _Ops = _IterOps<_AlgPolicy>; + + std::__sort4<_AlgPolicy, _Comp>(__x1, __x2, __x3, __x4, __comp); + if (__comp(*__x5, *__x4)) { + _Ops::iter_swap(__x4, __x5); + if (__comp(*__x4, *__x3)) { + _Ops::iter_swap(__x3, __x4); + if (__comp(*__x3, *__x2)) { + _Ops::iter_swap(__x2, __x3); + if (__comp(*__x2, *__x1)) { + _Ops::iter_swap(__x1, __x2); + } + } + } + } +} + +// The comparator being simple is a prerequisite for using the branchless optimization. +template +struct __is_simple_comparator : false_type {}; +template <> +struct __is_simple_comparator<__less<>&> : true_type {}; +template +struct __is_simple_comparator&> : true_type {}; +template +struct __is_simple_comparator&> : true_type {}; +#if _LIBCPP_STD_VER >= 20 +template <> +struct __is_simple_comparator : true_type {}; +template <> +struct __is_simple_comparator : true_type {}; +#endif + +template ::value_type> +using __use_branchless_sort = + integral_constant::value && sizeof(_Tp) <= sizeof(void*) && + is_arithmetic<_Tp>::value && __is_simple_comparator<_Compare>::value>; + +namespace __detail { + +// Size in bits for the bitset in use. +enum { __block_size = sizeof(uint64_t) * 8 }; + +} // namespace __detail + +// Ensures that __c(*__x, *__y) is true by swapping *__x and *__y if necessary. +template +inline _LIBCPP_HIDE_FROM_ABI void __cond_swap(_RandomAccessIterator __x, _RandomAccessIterator __y, _Compare __c) { + // Note: this function behaves correctly even with proxy iterators (because it relies on `value_type`). + using value_type = typename iterator_traits<_RandomAccessIterator>::value_type; + bool __r = __c(*__x, *__y); + value_type __tmp = __r ? *__x : *__y; + *__y = __r ? *__y : *__x; + *__x = __tmp; +} + +// Ensures that *__x, *__y and *__z are ordered according to the comparator __c, +// under the assumption that *__y and *__z are already ordered. +template +inline _LIBCPP_HIDE_FROM_ABI void +__partially_sorted_swap(_RandomAccessIterator __x, _RandomAccessIterator __y, _RandomAccessIterator __z, _Compare __c) { + // Note: this function behaves correctly even with proxy iterators (because it relies on `value_type`). + using value_type = typename iterator_traits<_RandomAccessIterator>::value_type; + bool __r = __c(*__z, *__x); + value_type __tmp = __r ? *__z : *__x; + *__z = __r ? *__x : *__z; + __r = __c(__tmp, *__y); + *__x = __r ? *__x : *__y; + *__y = __r ? *__y : __tmp; +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI void __sort3_maybe_branchless( + _RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3, _Compare __c) { + std::__cond_swap<_Compare>(__x2, __x3, __c); + std::__partially_sorted_swap<_Compare>(__x1, __x2, __x3, __c); +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI void __sort3_maybe_branchless( + _RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3, _Compare __c) { + std::__sort3<_AlgPolicy, _Compare>(__x1, __x2, __x3, __c); +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI void __sort4_maybe_branchless( + _RandomAccessIterator __x1, + _RandomAccessIterator __x2, + _RandomAccessIterator __x3, + _RandomAccessIterator __x4, + _Compare __c) { + std::__cond_swap<_Compare>(__x1, __x3, __c); + std::__cond_swap<_Compare>(__x2, __x4, __c); + std::__cond_swap<_Compare>(__x1, __x2, __c); + std::__cond_swap<_Compare>(__x3, __x4, __c); + std::__cond_swap<_Compare>(__x2, __x3, __c); +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI void __sort4_maybe_branchless( + _RandomAccessIterator __x1, + _RandomAccessIterator __x2, + _RandomAccessIterator __x3, + _RandomAccessIterator __x4, + _Compare __c) { + std::__sort4<_AlgPolicy, _Compare>(__x1, __x2, __x3, __x4, __c); +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI void __sort5_maybe_branchless( + _RandomAccessIterator __x1, + _RandomAccessIterator __x2, + _RandomAccessIterator __x3, + _RandomAccessIterator __x4, + _RandomAccessIterator __x5, + _Compare __c) { + std::__cond_swap<_Compare>(__x1, __x2, __c); + std::__cond_swap<_Compare>(__x4, __x5, __c); + std::__partially_sorted_swap<_Compare>(__x3, __x4, __x5, __c); + std::__cond_swap<_Compare>(__x2, __x5, __c); + std::__partially_sorted_swap<_Compare>(__x1, __x3, __x4, __c); + std::__partially_sorted_swap<_Compare>(__x2, __x3, __x4, __c); +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI void __sort5_maybe_branchless( + _RandomAccessIterator __x1, + _RandomAccessIterator __x2, + _RandomAccessIterator __x3, + _RandomAccessIterator __x4, + _RandomAccessIterator __x5, + _Compare __c) { + std::__sort5<_AlgPolicy, _Compare, _RandomAccessIterator>( + std::move(__x1), std::move(__x2), std::move(__x3), std::move(__x4), std::move(__x5), __c); +} + +// Assumes size > 0 +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void +__selection_sort(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) { + _BidirectionalIterator __lm1 = __last; + for (--__lm1; __first != __lm1; ++__first) { + _BidirectionalIterator __i = std::__min_element<_Compare>(__first, __last, __comp); + if (__i != __first) + _IterOps<_AlgPolicy>::iter_swap(__first, __i); + } +} + +// Sort the iterator range [__first, __last) using the comparator __comp using +// the insertion sort algorithm. +template +_LIBCPP_HIDE_FROM_ABI void +__insertion_sort(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) { + using _Ops = _IterOps<_AlgPolicy>; + + typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type; + if (__first == __last) + return; + _BidirectionalIterator __i = __first; + for (++__i; __i != __last; ++__i) { + _BidirectionalIterator __j = __i; + --__j; + if (__comp(*__i, *__j)) { + value_type __t(_Ops::__iter_move(__i)); + _BidirectionalIterator __k = __j; + __j = __i; + do { + *__j = _Ops::__iter_move(__k); + __j = __k; + } while (__j != __first && __comp(__t, *--__k)); + *__j = std::move(__t); + } + } +} + +// Sort the iterator range [__first, __last) using the comparator __comp using +// the insertion sort algorithm. Insertion sort has two loops, outer and inner. +// The implementation below has no bounds check (unguarded) for the inner loop. +// Assumes that there is an element in the position (__first - 1) and that each +// element in the input range is greater or equal to the element at __first - 1. +template +_LIBCPP_HIDE_FROM_ABI void +__insertion_sort_unguarded(_RandomAccessIterator const __first, _RandomAccessIterator __last, _Compare __comp) { + using _Ops = _IterOps<_AlgPolicy>; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; + typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; + if (__first == __last) + return; + const _RandomAccessIterator __leftmost = __first - difference_type(1); + (void)__leftmost; // can be unused when assertions are disabled + for (_RandomAccessIterator __i = __first + difference_type(1); __i != __last; ++__i) { + _RandomAccessIterator __j = __i - difference_type(1); + if (__comp(*__i, *__j)) { + value_type __t(_Ops::__iter_move(__i)); + _RandomAccessIterator __k = __j; + __j = __i; + do { + *__j = _Ops::__iter_move(__k); + __j = __k; + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __k != __leftmost, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + } while (__comp(__t, *--__k)); // No need for bounds check due to the assumption stated above. + *__j = std::move(__t); + } + } +} + +template +_LIBCPP_HIDE_FROM_ABI bool +__insertion_sort_incomplete(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) { + using _Ops = _IterOps<_AlgPolicy>; + + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; + switch (__last - __first) { + case 0: + case 1: + return true; + case 2: + if (__comp(*--__last, *__first)) + _Ops::iter_swap(__first, __last); + return true; + case 3: + std::__sort3_maybe_branchless<_AlgPolicy, _Comp>(__first, __first + difference_type(1), --__last, __comp); + return true; + case 4: + std::__sort4_maybe_branchless<_AlgPolicy, _Comp>( + __first, __first + difference_type(1), __first + difference_type(2), --__last, __comp); + return true; + case 5: + std::__sort5_maybe_branchless<_AlgPolicy, _Comp>( + __first, + __first + difference_type(1), + __first + difference_type(2), + __first + difference_type(3), + --__last, + __comp); + return true; + } + typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; + _RandomAccessIterator __j = __first + difference_type(2); + std::__sort3_maybe_branchless<_AlgPolicy, _Comp>(__first, __first + difference_type(1), __j, __comp); + const unsigned __limit = 8; + unsigned __count = 0; + for (_RandomAccessIterator __i = __j + difference_type(1); __i != __last; ++__i) { + if (__comp(*__i, *__j)) { + value_type __t(_Ops::__iter_move(__i)); + _RandomAccessIterator __k = __j; + __j = __i; + do { + *__j = _Ops::__iter_move(__k); + __j = __k; + } while (__j != __first && __comp(__t, *--__k)); + *__j = std::move(__t); + if (++__count == __limit) + return ++__i == __last; + } + __j = __i; + } + return true; +} + +template +inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos( + _RandomAccessIterator __first, _RandomAccessIterator __last, uint64_t& __left_bitset, uint64_t& __right_bitset) { + using _Ops = _IterOps<_AlgPolicy>; + typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type difference_type; + // Swap one pair on each iteration as long as both bitsets have at least one + // element for swapping. + while (__left_bitset != 0 && __right_bitset != 0) { + difference_type __tz_left = __libcpp_ctz(__left_bitset); + __left_bitset = __libcpp_blsr(__left_bitset); + difference_type __tz_right = __libcpp_ctz(__right_bitset); + __right_bitset = __libcpp_blsr(__right_bitset); + _Ops::iter_swap(__first + __tz_left, __last - __tz_right); + } +} + +template ::value_type> +inline _LIBCPP_HIDE_FROM_ABI void +__populate_left_bitset(_RandomAccessIterator __first, _Compare __comp, _ValueType& __pivot, uint64_t& __left_bitset) { + // Possible vectorization. With a proper "-march" flag, the following loop + // will be compiled into a set of SIMD instructions. + _RandomAccessIterator __iter = __first; + for (int __j = 0; __j < __detail::__block_size;) { + bool __comp_result = !__comp(*__iter, __pivot); + __left_bitset |= (static_cast(__comp_result) << __j); + __j++; + ++__iter; + } +} + +template ::value_type> +inline _LIBCPP_HIDE_FROM_ABI void +__populate_right_bitset(_RandomAccessIterator __lm1, _Compare __comp, _ValueType& __pivot, uint64_t& __right_bitset) { + // Possible vectorization. With a proper "-march" flag, the following loop + // will be compiled into a set of SIMD instructions. + _RandomAccessIterator __iter = __lm1; + for (int __j = 0; __j < __detail::__block_size;) { + bool __comp_result = __comp(*__iter, __pivot); + __right_bitset |= (static_cast(__comp_result) << __j); + __j++; + --__iter; + } +} + +template ::value_type> +inline _LIBCPP_HIDE_FROM_ABI void __bitset_partition_partial_blocks( + _RandomAccessIterator& __first, + _RandomAccessIterator& __lm1, + _Compare __comp, + _ValueType& __pivot, + uint64_t& __left_bitset, + uint64_t& __right_bitset) { + typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type difference_type; + difference_type __remaining_len = __lm1 - __first + 1; + difference_type __l_size; + difference_type __r_size; + if (__left_bitset == 0 && __right_bitset == 0) { + __l_size = __remaining_len / 2; + __r_size = __remaining_len - __l_size; + } else if (__left_bitset == 0) { + // We know at least one side is a full block. + __l_size = __remaining_len - __detail::__block_size; + __r_size = __detail::__block_size; + } else { // if (__right_bitset == 0) + __l_size = __detail::__block_size; + __r_size = __remaining_len - __detail::__block_size; + } + // Record the comparison outcomes for the elements currently on the left side. + if (__left_bitset == 0) { + _RandomAccessIterator __iter = __first; + for (int __j = 0; __j < __l_size; __j++) { + bool __comp_result = !__comp(*__iter, __pivot); + __left_bitset |= (static_cast(__comp_result) << __j); + ++__iter; + } + } + // Record the comparison outcomes for the elements currently on the right + // side. + if (__right_bitset == 0) { + _RandomAccessIterator __iter = __lm1; + for (int __j = 0; __j < __r_size; __j++) { + bool __comp_result = __comp(*__iter, __pivot); + __right_bitset |= (static_cast(__comp_result) << __j); + --__iter; + } + } + std::__swap_bitmap_pos<_AlgPolicy, _RandomAccessIterator>(__first, __lm1, __left_bitset, __right_bitset); + __first += (__left_bitset == 0) ? __l_size : 0; + __lm1 -= (__right_bitset == 0) ? __r_size : 0; +} + +template +inline _LIBCPP_HIDE_FROM_ABI void __swap_bitmap_pos_within( + _RandomAccessIterator& __first, _RandomAccessIterator& __lm1, uint64_t& __left_bitset, uint64_t& __right_bitset) { + using _Ops = _IterOps<_AlgPolicy>; + typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type difference_type; + if (__left_bitset) { + // Swap within the left side. Need to find set positions in the reverse + // order. + while (__left_bitset != 0) { + difference_type __tz_left = __detail::__block_size - 1 - __libcpp_clz(__left_bitset); + __left_bitset &= (static_cast(1) << __tz_left) - 1; + _RandomAccessIterator __it = __first + __tz_left; + if (__it != __lm1) { + _Ops::iter_swap(__it, __lm1); + } + --__lm1; + } + __first = __lm1 + difference_type(1); + } else if (__right_bitset) { + // Swap within the right side. Need to find set positions in the reverse + // order. + while (__right_bitset != 0) { + difference_type __tz_right = __detail::__block_size - 1 - __libcpp_clz(__right_bitset); + __right_bitset &= (static_cast(1) << __tz_right) - 1; + _RandomAccessIterator __it = __lm1 - __tz_right; + if (__it != __first) { + _Ops::iter_swap(__it, __first); + } + ++__first; + } + } +} + +// Partition [__first, __last) using the comparator __comp. *__first has the +// chosen pivot. Elements that are equivalent are kept to the left of the +// pivot. Returns the iterator for the pivot and a bool value which is true if +// the provided range is already sorted, false otherwise. We assume that the +// length of the range is at least three elements. +// +// __bitset_partition uses bitsets for storing outcomes of the comparisons +// between the pivot and other elements. +template +_LIBCPP_HIDE_FROM_ABI std::pair<_RandomAccessIterator, bool> +__bitset_partition(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { + using _Ops = _IterOps<_AlgPolicy>; + typedef typename std::iterator_traits<_RandomAccessIterator>::value_type value_type; + typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type difference_type; + _LIBCPP_ASSERT_INTERNAL(__last - __first >= difference_type(3), ""); + const _RandomAccessIterator __begin = __first; // used for bounds checking, those are not moved around + const _RandomAccessIterator __end = __last; + (void)__end; // + + value_type __pivot(_Ops::__iter_move(__first)); + // Find the first element greater than the pivot. + if (__comp(__pivot, *(__last - difference_type(1)))) { + // Not guarded since we know the last element is greater than the pivot. + do { + ++__first; + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __first != __end, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + } while (!__comp(__pivot, *__first)); + } else { + while (++__first < __last && !__comp(__pivot, *__first)) { + } + } + // Find the last element less than or equal to the pivot. + if (__first < __last) { + // It will be always guarded because __introsort will do the median-of-three + // before calling this. + do { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __last != __begin, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + --__last; + } while (__comp(__pivot, *__last)); + } + // If the first element greater than the pivot is at or after the + // last element less than or equal to the pivot, then we have covered the + // entire range without swapping elements. This implies the range is already + // partitioned. + bool __already_partitioned = __first >= __last; + if (!__already_partitioned) { + _Ops::iter_swap(__first, __last); + ++__first; + } + + // In [__first, __last) __last is not inclusive. From now on, it uses last + // minus one to be inclusive on both sides. + _RandomAccessIterator __lm1 = __last - difference_type(1); + uint64_t __left_bitset = 0; + uint64_t __right_bitset = 0; + + // Reminder: length = __lm1 - __first + 1. + while (__lm1 - __first >= 2 * __detail::__block_size - 1) { + // Record the comparison outcomes for the elements currently on the left + // side. + if (__left_bitset == 0) + std::__populate_left_bitset<_Compare>(__first, __comp, __pivot, __left_bitset); + // Record the comparison outcomes for the elements currently on the right + // side. + if (__right_bitset == 0) + std::__populate_right_bitset<_Compare>(__lm1, __comp, __pivot, __right_bitset); + // Swap the elements recorded to be the candidates for swapping in the + // bitsets. + std::__swap_bitmap_pos<_AlgPolicy, _RandomAccessIterator>(__first, __lm1, __left_bitset, __right_bitset); + // Only advance the iterator if all the elements that need to be moved to + // other side were moved. + __first += (__left_bitset == 0) ? difference_type(__detail::__block_size) : difference_type(0); + __lm1 -= (__right_bitset == 0) ? difference_type(__detail::__block_size) : difference_type(0); + } + // Now, we have a less-than a block worth of elements on at least one of the + // sides. + std::__bitset_partition_partial_blocks<_AlgPolicy, _Compare>( + __first, __lm1, __comp, __pivot, __left_bitset, __right_bitset); + // At least one the bitsets would be empty. For the non-empty one, we need to + // properly partition the elements that appear within that bitset. + std::__swap_bitmap_pos_within<_AlgPolicy>(__first, __lm1, __left_bitset, __right_bitset); + + // Move the pivot to its correct position. + _RandomAccessIterator __pivot_pos = __first - difference_type(1); + if (__begin != __pivot_pos) { + *__begin = _Ops::__iter_move(__pivot_pos); + } + *__pivot_pos = std::move(__pivot); + return std::make_pair(__pivot_pos, __already_partitioned); +} + +// Partition [__first, __last) using the comparator __comp. *__first has the +// chosen pivot. Elements that are equivalent are kept to the right of the +// pivot. Returns the iterator for the pivot and a bool value which is true if +// the provided range is already sorted, false otherwise. We assume that the +// length of the range is at least three elements. +template +_LIBCPP_HIDE_FROM_ABI std::pair<_RandomAccessIterator, bool> +__partition_with_equals_on_right(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { + using _Ops = _IterOps<_AlgPolicy>; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; + typedef typename std::iterator_traits<_RandomAccessIterator>::value_type value_type; + _LIBCPP_ASSERT_INTERNAL(__last - __first >= difference_type(3), ""); + const _RandomAccessIterator __begin = __first; // used for bounds checking, those are not moved around + const _RandomAccessIterator __end = __last; + (void)__end; // + value_type __pivot(_Ops::__iter_move(__first)); + // Find the first element greater or equal to the pivot. It will be always + // guarded because __introsort will do the median-of-three before calling + // this. + do { + ++__first; + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __first != __end, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + } while (__comp(*__first, __pivot)); + + // Find the last element less than the pivot. + if (__begin == __first - difference_type(1)) { + while (__first < __last && !__comp(*--__last, __pivot)) + ; + } else { + // Guarded. + do { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __last != __begin, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + --__last; + } while (!__comp(*__last, __pivot)); + } + + // If the first element greater than or equal to the pivot is at or after the + // last element less than the pivot, then we have covered the entire range + // without swapping elements. This implies the range is already partitioned. + bool __already_partitioned = __first >= __last; + // Go through the remaining elements. Swap pairs of elements (one to the + // right of the pivot and the other to left of the pivot) that are not on the + // correct side of the pivot. + while (__first < __last) { + _Ops::iter_swap(__first, __last); + do { + ++__first; + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __first != __end, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + } while (__comp(*__first, __pivot)); + do { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __last != __begin, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + --__last; + } while (!__comp(*__last, __pivot)); + } + // Move the pivot to its correct position. + _RandomAccessIterator __pivot_pos = __first - difference_type(1); + if (__begin != __pivot_pos) { + *__begin = _Ops::__iter_move(__pivot_pos); + } + *__pivot_pos = std::move(__pivot); + return std::make_pair(__pivot_pos, __already_partitioned); +} + +// Similar to the above function. Elements equivalent to the pivot are put to +// the left of the pivot. Returns the iterator to the pivot element. +template +_LIBCPP_HIDE_FROM_ABI _RandomAccessIterator +__partition_with_equals_on_left(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { + using _Ops = _IterOps<_AlgPolicy>; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; + typedef typename std::iterator_traits<_RandomAccessIterator>::value_type value_type; + const _RandomAccessIterator __begin = __first; // used for bounds checking, those are not moved around + const _RandomAccessIterator __end = __last; + (void)__end; // + value_type __pivot(_Ops::__iter_move(__first)); + if (__comp(__pivot, *(__last - difference_type(1)))) { + // Guarded. + do { + ++__first; + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __first != __end, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + } while (!__comp(__pivot, *__first)); + } else { + while (++__first < __last && !__comp(__pivot, *__first)) { + } + } + + if (__first < __last) { + // It will be always guarded because __introsort will do the + // median-of-three before calling this. + do { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __last != __begin, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + --__last; + } while (__comp(__pivot, *__last)); + } + while (__first < __last) { + _Ops::iter_swap(__first, __last); + do { + ++__first; + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __first != __end, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + } while (!__comp(__pivot, *__first)); + do { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __last != __begin, + "Would read out of bounds, does your comparator satisfy the strict-weak ordering requirement?"); + --__last; + } while (__comp(__pivot, *__last)); + } + _RandomAccessIterator __pivot_pos = __first - difference_type(1); + if (__begin != __pivot_pos) { + *__begin = _Ops::__iter_move(__pivot_pos); + } + *__pivot_pos = std::move(__pivot); + return __first; +} + +// The main sorting function. Implements introsort combined with other ideas: +// - option of using block quick sort for partitioning, +// - guarded and unguarded insertion sort for small lengths, +// - Tuckey's ninther technique for computing the pivot, +// - check on whether partition was not required. +// The implementation is partly based on Orson Peters' pattern-defeating +// quicksort, published at: . +template +void __introsort(_RandomAccessIterator __first, + _RandomAccessIterator __last, + _Compare __comp, + typename iterator_traits<_RandomAccessIterator>::difference_type __depth, + bool __leftmost = true) { + using _Ops = _IterOps<_AlgPolicy>; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; + using _Comp_ref = __comp_ref_type<_Compare>; + // Upper bound for using insertion sort for sorting. + _LIBCPP_CONSTEXPR difference_type __limit = 24; + // Lower bound for using Tuckey's ninther technique for median computation. + _LIBCPP_CONSTEXPR difference_type __ninther_threshold = 128; + while (true) { + difference_type __len = __last - __first; + switch (__len) { + case 0: + case 1: + return; + case 2: + if (__comp(*--__last, *__first)) + _Ops::iter_swap(__first, __last); + return; + case 3: + std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + difference_type(1), --__last, __comp); + return; + case 4: + std::__sort4_maybe_branchless<_AlgPolicy, _Compare>( + __first, __first + difference_type(1), __first + difference_type(2), --__last, __comp); + return; + case 5: + std::__sort5_maybe_branchless<_AlgPolicy, _Compare>( + __first, + __first + difference_type(1), + __first + difference_type(2), + __first + difference_type(3), + --__last, + __comp); + return; + } + // Use insertion sort if the length of the range is below the specified limit. + if (__len < __limit) { + if (__leftmost) { + std::__insertion_sort<_AlgPolicy, _Compare>(__first, __last, __comp); + } else { + std::__insertion_sort_unguarded<_AlgPolicy, _Compare>(__first, __last, __comp); + } + return; + } + if (__depth == 0) { + // Fallback to heap sort as Introsort suggests. + std::__partial_sort<_AlgPolicy, _Compare>(__first, __last, __last, __comp); + return; + } + --__depth; + { + difference_type __half_len = __len / 2; + // Use Tuckey's ninther technique or median of 3 for pivot selection + // depending on the length of the range being sorted. + if (__len > __ninther_threshold) { + std::__sort3<_AlgPolicy, _Compare>(__first, __first + __half_len, __last - difference_type(1), __comp); + std::__sort3<_AlgPolicy, _Compare>( + __first + difference_type(1), __first + (__half_len - 1), __last - difference_type(2), __comp); + std::__sort3<_AlgPolicy, _Compare>( + __first + difference_type(2), __first + (__half_len + 1), __last - difference_type(3), __comp); + std::__sort3<_AlgPolicy, _Compare>( + __first + (__half_len - 1), __first + __half_len, __first + (__half_len + 1), __comp); + _Ops::iter_swap(__first, __first + __half_len); + } else { + std::__sort3<_AlgPolicy, _Compare>(__first + __half_len, __first, __last - difference_type(1), __comp); + } + } + // The elements to the left of the current iterator range are already + // sorted. If the current iterator range to be sorted is not the + // leftmost part of the entire iterator range and the pivot is same as + // the highest element in the range to the left, then we know that all + // the elements in the range [first, pivot] would be equal to the pivot, + // assuming the equal elements are put on the left side when + // partitioned. This also means that we do not need to sort the left + // side of the partition. + if (!__leftmost && !__comp(*(__first - difference_type(1)), *__first)) { + __first = std::__partition_with_equals_on_left<_AlgPolicy, _RandomAccessIterator, _Comp_ref>( + __first, __last, _Comp_ref(__comp)); + continue; + } + // Use bitset partition only if asked for. + auto __ret = _UseBitSetPartition + ? std::__bitset_partition<_AlgPolicy, _RandomAccessIterator, _Compare>(__first, __last, __comp) + : std::__partition_with_equals_on_right<_AlgPolicy, _RandomAccessIterator, _Compare>( + __first, __last, __comp); + _RandomAccessIterator __i = __ret.first; + // [__first, __i) < *__i and *__i <= [__i+1, __last) + // If we were given a perfect partition, see if insertion sort is quick... + if (__ret.second) { + bool __fs = std::__insertion_sort_incomplete<_AlgPolicy, _Compare>(__first, __i, __comp); + if (std::__insertion_sort_incomplete<_AlgPolicy, _Compare>(__i + difference_type(1), __last, __comp)) { + if (__fs) + return; + __last = __i; + continue; + } else { + if (__fs) { + __first = ++__i; + continue; + } + } + } + // Sort the left partiton recursively and the right partition with tail recursion elimination. + std::__introsort<_AlgPolicy, _Compare, _RandomAccessIterator, _UseBitSetPartition>( + __first, __i, __comp, __depth, __leftmost); + __leftmost = false; + __first = ++__i; + } +} + +template +inline _LIBCPP_HIDE_FROM_ABI _Number __log2i(_Number __n) { + if (__n == 0) + return 0; + if (sizeof(__n) <= sizeof(unsigned)) + return sizeof(unsigned) * CHAR_BIT - 1 - __libcpp_clz(static_cast(__n)); + if (sizeof(__n) <= sizeof(unsigned long)) + return sizeof(unsigned long) * CHAR_BIT - 1 - __libcpp_clz(static_cast(__n)); + if (sizeof(__n) <= sizeof(unsigned long long)) + return sizeof(unsigned long long) * CHAR_BIT - 1 - __libcpp_clz(static_cast(__n)); + + _Number __log2 = 0; + while (__n > 1) { + __log2++; + __n >>= 1; + } + return __log2; +} + +template +void __sort(_RandomAccessIterator, _RandomAccessIterator, _Comp); + +extern template _LIBCPP_EXPORTED_FROM_ABI void __sort<__less&, char*>(char*, char*, __less&); +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +extern template _LIBCPP_EXPORTED_FROM_ABI void __sort<__less&, wchar_t*>(wchar_t*, wchar_t*, __less&); +#endif +extern template _LIBCPP_EXPORTED_FROM_ABI void +__sort<__less&, signed char*>(signed char*, signed char*, __less&); +extern template _LIBCPP_EXPORTED_FROM_ABI void +__sort<__less&, unsigned char*>(unsigned char*, unsigned char*, __less&); +extern template _LIBCPP_EXPORTED_FROM_ABI void __sort<__less&, short*>(short*, short*, __less&); +extern template _LIBCPP_EXPORTED_FROM_ABI void +__sort<__less&, unsigned short*>(unsigned short*, unsigned short*, __less&); +extern template _LIBCPP_EXPORTED_FROM_ABI void __sort<__less&, int*>(int*, int*, __less&); +extern template _LIBCPP_EXPORTED_FROM_ABI void +__sort<__less&, unsigned*>(unsigned*, unsigned*, __less&); +extern template _LIBCPP_EXPORTED_FROM_ABI void __sort<__less&, long*>(long*, long*, __less&); +extern template _LIBCPP_EXPORTED_FROM_ABI void +__sort<__less&, unsigned long*>(unsigned long*, unsigned long*, __less&); +extern template _LIBCPP_EXPORTED_FROM_ABI void +__sort<__less&, long long*>(long long*, long long*, __less&); +extern template _LIBCPP_EXPORTED_FROM_ABI void __sort<__less&, unsigned long long*>( + unsigned long long*, unsigned long long*, __less&); +extern template _LIBCPP_EXPORTED_FROM_ABI void __sort<__less&, float*>(float*, float*, __less&); +extern template _LIBCPP_EXPORTED_FROM_ABI void __sort<__less&, double*>(double*, double*, __less&); +extern template _LIBCPP_EXPORTED_FROM_ABI void +__sort<__less&, long double*>(long double*, long double*, __less&); + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +__sort_dispatch(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp& __comp) { + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; + difference_type __depth_limit = 2 * std::__log2i(__last - __first); + + // Only use bitset partitioning for arithmetic types. We should also check + // that the default comparator is in use so that we are sure that there are no + // branches in the comparator. + std::__introsort<_AlgPolicy, + _Comp&, + _RandomAccessIterator, + __use_branchless_sort<_Comp, _RandomAccessIterator>::value>(__first, __last, __comp, __depth_limit); +} + +template +using __is_any_of = _Or...>; + +template +using __sort_is_specialized_in_library = __is_any_of< + _Type, + char, +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS + wchar_t, +#endif + signed char, + unsigned char, + short, + unsigned short, + int, + unsigned int, + long, + unsigned long, + long long, + unsigned long long, + float, + double, + long double>; + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, __less<>&) { + __less<_Type> __comp; + std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp); +} + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, less<_Type>&) { + __less<_Type> __comp; + std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp); +} + +#if _LIBCPP_STD_VER >= 14 +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, less<>&) { + __less<_Type> __comp; + std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp); +} +#endif + +#if _LIBCPP_STD_VER >= 20 +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI void __sort_dispatch(_Type* __first, _Type* __last, ranges::less&) { + __less<_Type> __comp; + std::__sort<__less<_Type>&, _Type*>(__first, __last, __comp); +} +#endif + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +__sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp& __comp) { + std::__debug_randomize_range<_AlgPolicy>(__first, __last); + + if (__libcpp_is_constant_evaluated()) { + std::__partial_sort<_AlgPolicy>( + std::__unwrap_iter(__first), std::__unwrap_iter(__last), std::__unwrap_iter(__last), __comp); + } else { + std::__sort_dispatch<_AlgPolicy>(std::__unwrap_iter(__first), std::__unwrap_iter(__last), __comp); + } + std::__check_strict_weak_ordering_sorted(std::__unwrap_iter(__first), std::__unwrap_iter(__last), __comp); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) { + std::__sort_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +sort(_RandomAccessIterator __first, _RandomAccessIterator __last) { + std::sort(__first, __last, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_SORT_H diff --git a/libcxx/include/__cxx03/__algorithm/sort_heap.h b/libcxx/include/__cxx03/__algorithm/sort_heap.h new file mode 100644 index 0000000000000000000000000000000000000000..f20b110c7fd12e8d8a5cfb8e300b12b509fff4b5 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/sort_heap.h @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SORT_HEAP_H +#define _LIBCPP___ALGORITHM_SORT_HEAP_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/pop_heap.h> +#include <__config> +#include <__debug_utils/strict_weak_ordering_check.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_assignable.h> +#include <__type_traits/is_constructible.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void +__sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare&& __comp) { + _RandomAccessIterator __saved_last = __last; + __comp_ref_type<_Compare> __comp_ref = __comp; + + using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type; + for (difference_type __n = __last - __first; __n > 1; --__last, (void)--__n) + std::__pop_heap<_AlgPolicy>(__first, __last, __comp_ref, __n); + std::__check_strict_weak_ordering_sorted(__first, __saved_last, __comp_ref); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { + static_assert(std::is_copy_constructible<_RandomAccessIterator>::value, "Iterators must be copy constructible."); + static_assert(std::is_copy_assignable<_RandomAccessIterator>::value, "Iterators must be copy assignable."); + + std::__sort_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) { + std::sort_heap(std::move(__first), std::move(__last), __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_SORT_HEAP_H diff --git a/libcxx/include/__cxx03/__algorithm/stable_partition.h b/libcxx/include/__cxx03/__algorithm/stable_partition.h new file mode 100644 index 0000000000000000000000000000000000000000..8bb1eaf2d224956c5e19ae660ccf191824a6c7f6 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/stable_partition.h @@ -0,0 +1,307 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_STABLE_PARTITION_H +#define _LIBCPP___ALGORITHM_STABLE_PARTITION_H + +#include <__algorithm/iterator_operations.h> +#include <__algorithm/rotate.h> +#include <__config> +#include <__iterator/advance.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__memory/destruct_n.h> +#include <__memory/temporary_buffer.h> +#include <__memory/unique_ptr.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition_impl( + _ForwardIterator __first, + _ForwardIterator __last, + _Predicate __pred, + _Distance __len, + _Pair __p, + forward_iterator_tag __fit) { + using _Ops = _IterOps<_AlgPolicy>; + + // *__first is known to be false + // __len >= 1 + if (__len == 1) + return __first; + if (__len == 2) { + _ForwardIterator __m = __first; + if (__pred(*++__m)) { + _Ops::iter_swap(__first, __m); + return __m; + } + return __first; + } + if (__len <= __p.second) { // The buffer is big enough to use + typedef typename iterator_traits<_ForwardIterator>::value_type value_type; + __destruct_n __d(0); + unique_ptr __h(__p.first, __d); + // Move the falses into the temporary buffer, and the trues to the front of the line + // Update __first to always point to the end of the trues + value_type* __t = __p.first; + ::new ((void*)__t) value_type(_Ops::__iter_move(__first)); + __d.template __incr(); + ++__t; + _ForwardIterator __i = __first; + while (++__i != __last) { + if (__pred(*__i)) { + *__first = _Ops::__iter_move(__i); + ++__first; + } else { + ::new ((void*)__t) value_type(_Ops::__iter_move(__i)); + __d.template __incr(); + ++__t; + } + } + // All trues now at start of range, all falses in buffer + // Move falses back into range, but don't mess up __first which points to first false + __i = __first; + for (value_type* __t2 = __p.first; __t2 < __t; ++__t2, (void)++__i) + *__i = _Ops::__iter_move(__t2); + // __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer + return __first; + } + // Else not enough buffer, do in place + // __len >= 3 + _ForwardIterator __m = __first; + _Distance __len2 = __len / 2; // __len2 >= 2 + _Ops::advance(__m, __len2); + // recurse on [__first, __m), *__first know to be false + // F????????????????? + // f m l + _ForwardIterator __first_false = + std::__stable_partition_impl<_AlgPolicy, _Predicate&>(__first, __m, __pred, __len2, __p, __fit); + // TTTFFFFF?????????? + // f ff m l + // recurse on [__m, __last], except increase __m until *(__m) is false, *__last know to be true + _ForwardIterator __m1 = __m; + _ForwardIterator __second_false = __last; + _Distance __len_half = __len - __len2; + while (__pred(*__m1)) { + if (++__m1 == __last) + goto __second_half_done; + --__len_half; + } + // TTTFFFFFTTTF?????? + // f ff m m1 l + __second_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(__m1, __last, __pred, __len_half, __p, __fit); +__second_half_done: + // TTTFFFFFTTTTTFFFFF + // f ff m sf l + return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false).first; + // TTTTTTTTFFFFFFFFFF + // | +} + +template +_LIBCPP_HIDE_FROM_ABI _ForwardIterator +__stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred, forward_iterator_tag) { + typedef typename iterator_traits<_ForwardIterator>::difference_type difference_type; + typedef typename iterator_traits<_ForwardIterator>::value_type value_type; + + const difference_type __alloc_limit = 3; // might want to make this a function of trivial assignment + // Either prove all true and return __first or point to first false + while (true) { + if (__first == __last) + return __first; + if (!__pred(*__first)) + break; + ++__first; + } + // We now have a reduced range [__first, __last) + // *__first is known to be false + difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last); + pair __p(0, 0); + unique_ptr __h; + if (__len >= __alloc_limit) { + // TODO: Remove the use of std::get_temporary_buffer + _LIBCPP_SUPPRESS_DEPRECATED_PUSH + __p = std::get_temporary_buffer(__len); + _LIBCPP_SUPPRESS_DEPRECATED_POP + __h.reset(__p.first); + } + return std::__stable_partition_impl<_AlgPolicy, _Predicate&>( + std::move(__first), std::move(__last), __pred, __len, __p, forward_iterator_tag()); +} + +template +_BidirectionalIterator __stable_partition_impl( + _BidirectionalIterator __first, + _BidirectionalIterator __last, + _Predicate __pred, + _Distance __len, + _Pair __p, + bidirectional_iterator_tag __bit) { + using _Ops = _IterOps<_AlgPolicy>; + + // *__first is known to be false + // *__last is known to be true + // __len >= 2 + if (__len == 2) { + _Ops::iter_swap(__first, __last); + return __last; + } + if (__len == 3) { + _BidirectionalIterator __m = __first; + if (__pred(*++__m)) { + _Ops::iter_swap(__first, __m); + _Ops::iter_swap(__m, __last); + return __last; + } + _Ops::iter_swap(__m, __last); + _Ops::iter_swap(__first, __m); + return __m; + } + if (__len <= __p.second) { // The buffer is big enough to use + typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type; + __destruct_n __d(0); + unique_ptr __h(__p.first, __d); + // Move the falses into the temporary buffer, and the trues to the front of the line + // Update __first to always point to the end of the trues + value_type* __t = __p.first; + ::new ((void*)__t) value_type(_Ops::__iter_move(__first)); + __d.template __incr(); + ++__t; + _BidirectionalIterator __i = __first; + while (++__i != __last) { + if (__pred(*__i)) { + *__first = _Ops::__iter_move(__i); + ++__first; + } else { + ::new ((void*)__t) value_type(_Ops::__iter_move(__i)); + __d.template __incr(); + ++__t; + } + } + // move *__last, known to be true + *__first = _Ops::__iter_move(__i); + __i = ++__first; + // All trues now at start of range, all falses in buffer + // Move falses back into range, but don't mess up __first which points to first false + for (value_type* __t2 = __p.first; __t2 < __t; ++__t2, (void)++__i) + *__i = _Ops::__iter_move(__t2); + // __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer + return __first; + } + // Else not enough buffer, do in place + // __len >= 4 + _BidirectionalIterator __m = __first; + _Distance __len2 = __len / 2; // __len2 >= 2 + _Ops::advance(__m, __len2); + // recurse on [__first, __m-1], except reduce __m-1 until *(__m-1) is true, *__first know to be false + // F????????????????T + // f m l + _BidirectionalIterator __m1 = __m; + _BidirectionalIterator __first_false = __first; + _Distance __len_half = __len2; + while (!__pred(*--__m1)) { + if (__m1 == __first) + goto __first_half_done; + --__len_half; + } + // F???TFFF?????????T + // f m1 m l + __first_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(__first, __m1, __pred, __len_half, __p, __bit); +__first_half_done: + // TTTFFFFF?????????T + // f ff m l + // recurse on [__m, __last], except increase __m until *(__m) is false, *__last know to be true + __m1 = __m; + _BidirectionalIterator __second_false = __last; + ++__second_false; + __len_half = __len - __len2; + while (__pred(*__m1)) { + if (++__m1 == __last) + goto __second_half_done; + --__len_half; + } + // TTTFFFFFTTTF?????T + // f ff m m1 l + __second_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(__m1, __last, __pred, __len_half, __p, __bit); +__second_half_done: + // TTTFFFFFTTTTTFFFFF + // f ff m sf l + return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false).first; + // TTTTTTTTFFFFFFFFFF + // | +} + +template +_LIBCPP_HIDE_FROM_ABI _BidirectionalIterator __stable_partition_impl( + _BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred, bidirectional_iterator_tag) { + typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type; + typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type; + const difference_type __alloc_limit = 4; // might want to make this a function of trivial assignment + // Either prove all true and return __first or point to first false + while (true) { + if (__first == __last) + return __first; + if (!__pred(*__first)) + break; + ++__first; + } + // __first points to first false, everything prior to __first is already set. + // Either prove [__first, __last) is all false and return __first, or point __last to last true + do { + if (__first == --__last) + return __first; + } while (!__pred(*__last)); + // We now have a reduced range [__first, __last] + // *__first is known to be false + // *__last is known to be true + // __len >= 2 + difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last) + 1; + pair __p(0, 0); + unique_ptr __h; + if (__len >= __alloc_limit) { + // TODO: Remove the use of std::get_temporary_buffer + _LIBCPP_SUPPRESS_DEPRECATED_PUSH + __p = std::get_temporary_buffer(__len); + _LIBCPP_SUPPRESS_DEPRECATED_POP + __h.reset(__p.first); + } + return std::__stable_partition_impl<_AlgPolicy, _Predicate&>( + std::move(__first), std::move(__last), __pred, __len, __p, bidirectional_iterator_tag()); +} + +template +_LIBCPP_HIDE_FROM_ABI _ForwardIterator __stable_partition( + _ForwardIterator __first, _ForwardIterator __last, _Predicate&& __pred, _IterCategory __iter_category) { + return std::__stable_partition_impl<_AlgPolicy, __remove_cvref_t<_Predicate>&>( + std::move(__first), std::move(__last), __pred, __iter_category); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator +stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + using _IterCategory = typename iterator_traits<_ForwardIterator>::iterator_category; + return std::__stable_partition<_ClassicAlgPolicy, _Predicate&>( + std::move(__first), std::move(__last), __pred, _IterCategory()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_STABLE_PARTITION_H diff --git a/libcxx/include/__cxx03/__algorithm/stable_sort.h b/libcxx/include/__cxx03/__algorithm/stable_sort.h new file mode 100644 index 0000000000000000000000000000000000000000..726e7e16b3564a236a41e6dbddc7e597d1d13beb --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/stable_sort.h @@ -0,0 +1,273 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_STABLE_SORT_H +#define _LIBCPP___ALGORITHM_STABLE_SORT_H + +#include <__algorithm/comp.h> +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/inplace_merge.h> +#include <__algorithm/iterator_operations.h> +#include <__algorithm/sort.h> +#include <__config> +#include <__debug_utils/strict_weak_ordering_check.h> +#include <__iterator/iterator_traits.h> +#include <__memory/destruct_n.h> +#include <__memory/temporary_buffer.h> +#include <__memory/unique_ptr.h> +#include <__type_traits/is_trivially_assignable.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI void __insertion_sort_move( + _BidirectionalIterator __first1, + _BidirectionalIterator __last1, + typename iterator_traits<_BidirectionalIterator>::value_type* __first2, + _Compare __comp) { + using _Ops = _IterOps<_AlgPolicy>; + + typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type; + if (__first1 != __last1) { + __destruct_n __d(0); + unique_ptr __h(__first2, __d); + value_type* __last2 = __first2; + ::new ((void*)__last2) value_type(_Ops::__iter_move(__first1)); + __d.template __incr(); + for (++__last2; ++__first1 != __last1; ++__last2) { + value_type* __j2 = __last2; + value_type* __i2 = __j2; + if (__comp(*__first1, *--__i2)) { + ::new ((void*)__j2) value_type(std::move(*__i2)); + __d.template __incr(); + for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2) + *__j2 = std::move(*__i2); + *__j2 = _Ops::__iter_move(__first1); + } else { + ::new ((void*)__j2) value_type(_Ops::__iter_move(__first1)); + __d.template __incr(); + } + } + __h.release(); + } +} + +template +_LIBCPP_HIDE_FROM_ABI void __merge_move_construct( + _InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + typename iterator_traits<_InputIterator1>::value_type* __result, + _Compare __comp) { + using _Ops = _IterOps<_AlgPolicy>; + + typedef typename iterator_traits<_InputIterator1>::value_type value_type; + __destruct_n __d(0); + unique_ptr __h(__result, __d); + for (; true; ++__result) { + if (__first1 == __last1) { + for (; __first2 != __last2; ++__first2, (void)++__result, __d.template __incr()) + ::new ((void*)__result) value_type(_Ops::__iter_move(__first2)); + __h.release(); + return; + } + if (__first2 == __last2) { + for (; __first1 != __last1; ++__first1, (void)++__result, __d.template __incr()) + ::new ((void*)__result) value_type(_Ops::__iter_move(__first1)); + __h.release(); + return; + } + if (__comp(*__first2, *__first1)) { + ::new ((void*)__result) value_type(_Ops::__iter_move(__first2)); + __d.template __incr(); + ++__first2; + } else { + ::new ((void*)__result) value_type(_Ops::__iter_move(__first1)); + __d.template __incr(); + ++__first1; + } + } +} + +template +_LIBCPP_HIDE_FROM_ABI void __merge_move_assign( + _InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _OutputIterator __result, + _Compare __comp) { + using _Ops = _IterOps<_AlgPolicy>; + + for (; __first1 != __last1; ++__result) { + if (__first2 == __last2) { + for (; __first1 != __last1; ++__first1, (void)++__result) + *__result = _Ops::__iter_move(__first1); + return; + } + if (__comp(*__first2, *__first1)) { + *__result = _Ops::__iter_move(__first2); + ++__first2; + } else { + *__result = _Ops::__iter_move(__first1); + ++__first1; + } + } + for (; __first2 != __last2; ++__first2, (void)++__result) + *__result = _Ops::__iter_move(__first2); +} + +template +void __stable_sort(_RandomAccessIterator __first, + _RandomAccessIterator __last, + _Compare __comp, + typename iterator_traits<_RandomAccessIterator>::difference_type __len, + typename iterator_traits<_RandomAccessIterator>::value_type* __buff, + ptrdiff_t __buff_size); + +template +void __stable_sort_move(_RandomAccessIterator __first1, + _RandomAccessIterator __last1, + _Compare __comp, + typename iterator_traits<_RandomAccessIterator>::difference_type __len, + typename iterator_traits<_RandomAccessIterator>::value_type* __first2) { + using _Ops = _IterOps<_AlgPolicy>; + + typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; + switch (__len) { + case 0: + return; + case 1: + ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1)); + return; + case 2: + __destruct_n __d(0); + unique_ptr __h2(__first2, __d); + if (__comp(*--__last1, *__first1)) { + ::new ((void*)__first2) value_type(_Ops::__iter_move(__last1)); + __d.template __incr(); + ++__first2; + ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1)); + } else { + ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1)); + __d.template __incr(); + ++__first2; + ::new ((void*)__first2) value_type(_Ops::__iter_move(__last1)); + } + __h2.release(); + return; + } + if (__len <= 8) { + std::__insertion_sort_move<_AlgPolicy, _Compare>(__first1, __last1, __first2, __comp); + return; + } + typename iterator_traits<_RandomAccessIterator>::difference_type __l2 = __len / 2; + _RandomAccessIterator __m = __first1 + __l2; + std::__stable_sort<_AlgPolicy, _Compare>(__first1, __m, __comp, __l2, __first2, __l2); + std::__stable_sort<_AlgPolicy, _Compare>(__m, __last1, __comp, __len - __l2, __first2 + __l2, __len - __l2); + std::__merge_move_construct<_AlgPolicy, _Compare>(__first1, __m, __m, __last1, __first2, __comp); +} + +template +struct __stable_sort_switch { + static const unsigned value = 128 * is_trivially_copy_assignable<_Tp>::value; +}; + +template +void __stable_sort(_RandomAccessIterator __first, + _RandomAccessIterator __last, + _Compare __comp, + typename iterator_traits<_RandomAccessIterator>::difference_type __len, + typename iterator_traits<_RandomAccessIterator>::value_type* __buff, + ptrdiff_t __buff_size) { + typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; + switch (__len) { + case 0: + case 1: + return; + case 2: + if (__comp(*--__last, *__first)) + _IterOps<_AlgPolicy>::iter_swap(__first, __last); + return; + } + if (__len <= static_cast(__stable_sort_switch::value)) { + std::__insertion_sort<_AlgPolicy, _Compare>(__first, __last, __comp); + return; + } + typename iterator_traits<_RandomAccessIterator>::difference_type __l2 = __len / 2; + _RandomAccessIterator __m = __first + __l2; + if (__len <= __buff_size) { + __destruct_n __d(0); + unique_ptr __h2(__buff, __d); + std::__stable_sort_move<_AlgPolicy, _Compare>(__first, __m, __comp, __l2, __buff); + __d.__set(__l2, (value_type*)nullptr); + std::__stable_sort_move<_AlgPolicy, _Compare>(__m, __last, __comp, __len - __l2, __buff + __l2); + __d.__set(__len, (value_type*)nullptr); + std::__merge_move_assign<_AlgPolicy, _Compare>( + __buff, __buff + __l2, __buff + __l2, __buff + __len, __first, __comp); + // std::__merge<_Compare>(move_iterator(__buff), + // move_iterator(__buff + __l2), + // move_iterator<_RandomAccessIterator>(__buff + __l2), + // move_iterator<_RandomAccessIterator>(__buff + __len), + // __first, __comp); + return; + } + std::__stable_sort<_AlgPolicy, _Compare>(__first, __m, __comp, __l2, __buff, __buff_size); + std::__stable_sort<_AlgPolicy, _Compare>(__m, __last, __comp, __len - __l2, __buff, __buff_size); + std::__inplace_merge<_AlgPolicy>(__first, __m, __last, __comp, __l2, __len - __l2, __buff, __buff_size); +} + +template +inline _LIBCPP_HIDE_FROM_ABI void +__stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) { + using value_type = typename iterator_traits<_RandomAccessIterator>::value_type; + using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type; + + difference_type __len = __last - __first; + pair __buf(0, 0); + unique_ptr __h; + if (__len > static_cast(__stable_sort_switch::value)) { + // TODO: Remove the use of std::get_temporary_buffer + _LIBCPP_SUPPRESS_DEPRECATED_PUSH + __buf = std::get_temporary_buffer(__len); + _LIBCPP_SUPPRESS_DEPRECATED_POP + __h.reset(__buf.first); + } + + std::__stable_sort<_AlgPolicy, __comp_ref_type<_Compare> >(__first, __last, __comp, __len, __buf.first, __buf.second); + std::__check_strict_weak_ordering_sorted(__first, __last, __comp); +} + +template +inline _LIBCPP_HIDE_FROM_ABI void +stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { + std::__stable_sort_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp); +} + +template +inline _LIBCPP_HIDE_FROM_ABI void stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) { + std::stable_sort(__first, __last, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_STABLE_SORT_H diff --git a/libcxx/include/__cxx03/__algorithm/swap_ranges.h b/libcxx/include/__cxx03/__algorithm/swap_ranges.h new file mode 100644 index 0000000000000000000000000000000000000000..54b453b72360e0b707d0f95e193502a2b9b70bea --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/swap_ranges.h @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_SWAP_RANGES_H +#define _LIBCPP___ALGORITHM_SWAP_RANGES_H + +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// 2+2 iterators: the shorter size will be used. +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_ForwardIterator1, _ForwardIterator2> +__swap_ranges(_ForwardIterator1 __first1, _Sentinel1 __last1, _ForwardIterator2 __first2, _Sentinel2 __last2) { + while (__first1 != __last1 && __first2 != __last2) { + _IterOps<_AlgPolicy>::iter_swap(__first1, __first2); + ++__first1; + ++__first2; + } + + return pair<_ForwardIterator1, _ForwardIterator2>(std::move(__first1), std::move(__first2)); +} + +// 2+1 iterators: size2 >= size1. +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_ForwardIterator1, _ForwardIterator2> +__swap_ranges(_ForwardIterator1 __first1, _Sentinel1 __last1, _ForwardIterator2 __first2) { + while (__first1 != __last1) { + _IterOps<_AlgPolicy>::iter_swap(__first1, __first2); + ++__first1; + ++__first2; + } + + return pair<_ForwardIterator1, _ForwardIterator2>(std::move(__first1), std::move(__first2)); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator2 +swap_ranges(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) { + return std::__swap_ranges<_ClassicAlgPolicy>(std::move(__first1), std::move(__last1), std::move(__first2)).second; +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_SWAP_RANGES_H diff --git a/libcxx/include/__cxx03/__algorithm/three_way_comp_ref_type.h b/libcxx/include/__cxx03/__algorithm/three_way_comp_ref_type.h new file mode 100644 index 0000000000000000000000000000000000000000..5702a1fee08262376f7d69a19c15f3325c1a5959 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/three_way_comp_ref_type.h @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_THREE_WAY_COMP_REF_TYPE_H +#define _LIBCPP___ALGORITHM_THREE_WAY_COMP_REF_TYPE_H + +#include <__assert> +#include <__compare/ordering.h> +#include <__config> +#include <__utility/declval.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +struct __debug_three_way_comp { + _Comp& __comp_; + _LIBCPP_HIDE_FROM_ABI constexpr __debug_three_way_comp(_Comp& __c) : __comp_(__c) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(const _Tp& __x, const _Up& __y) { + auto __r = __comp_(__x, __y); + if constexpr (__comparison_category) + __do_compare_assert(__y, __x, __r); + return __r; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp& __x, _Up& __y) { + auto __r = __comp_(__x, __y); + if constexpr (__comparison_category) + __do_compare_assert(__y, __x, __r); + return __r; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr void __do_compare_assert(_LHS& __l, _RHS& __r, _Order __o) { + _Order __expected = __o; + if (__o == _Order::less) + __expected = _Order::greater; + if (__o == _Order::greater) + __expected = _Order::less; + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __comp_(__l, __r) == __expected, "Comparator does not induce a strict weak ordering"); + (void)__l; + (void)__r; + } +}; + +// Pass the comparator by lvalue reference. Or in the debug mode, using a debugging wrapper that stores a reference. +# if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG +template +using __three_way_comp_ref_type = __debug_three_way_comp<_Comp>; +# else +template +using __three_way_comp_ref_type = _Comp&; +# endif + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_THREE_WAY_COMP_REF_TYPE_H diff --git a/libcxx/include/__cxx03/__algorithm/transform.h b/libcxx/include/__cxx03/__algorithm/transform.h new file mode 100644 index 0000000000000000000000000000000000000000..1b424409591cece7a96bca1f4b23d7b03d25033b --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/transform.h @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_TRANSFORM_H +#define _LIBCPP___ALGORITHM_TRANSFORM_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +transform(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _UnaryOperation __op) { + for (; __first != __last; ++__first, (void)++__result) + *__result = __op(*__first); + return __result; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator transform( + _InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _OutputIterator __result, + _BinaryOperation __binary_op) { + for (; __first1 != __last1; ++__first1, (void)++__first2, ++__result) + *__result = __binary_op(*__first1, *__first2); + return __result; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_TRANSFORM_H diff --git a/libcxx/include/__cxx03/__algorithm/uniform_random_bit_generator_adaptor.h b/libcxx/include/__cxx03/__algorithm/uniform_random_bit_generator_adaptor.h new file mode 100644 index 0000000000000000000000000000000000000000..aef0fbfb7c2842ea9e6f279422f96fb098887bc5 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/uniform_random_bit_generator_adaptor.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_UNIFORM_RANDOM_BIT_GENERATOR_ADAPTOR_H +#define _LIBCPP___ALGORITHM_RANGES_UNIFORM_RANDOM_BIT_GENERATOR_ADAPTOR_H + +#include <__config> +#include <__functional/invoke.h> +#include <__type_traits/remove_cvref.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// Range versions of random algorithms (e.g. `std::shuffle`) are less constrained than their classic counterparts. +// Range algorithms only require the given generator to satisfy the `std::uniform_random_bit_generator` concept. +// Classic algorithms require the given generator to meet the uniform random bit generator requirements; these +// requirements include satisfying `std::uniform_random_bit_generator` and add a requirement for the generator to +// provide a nested `result_type` typedef (see `[rand.req.urng]`). +// +// To be able to reuse classic implementations, make the given generator meet the classic requirements by wrapping +// it into an adaptor type that forwards all of its interface and adds the required typedef. +template +class _ClassicGenAdaptor { +private: + // The generator is not required to be copyable or movable, so it has to be stored as a reference. + _Gen& __gen_; + +public: + using result_type = invoke_result_t<_Gen&>; + + _LIBCPP_HIDE_FROM_ABI static constexpr auto min() { return __remove_cvref_t<_Gen>::min(); } + _LIBCPP_HIDE_FROM_ABI static constexpr auto max() { return __remove_cvref_t<_Gen>::max(); } + + _LIBCPP_HIDE_FROM_ABI constexpr explicit _ClassicGenAdaptor(_Gen& __g) : __gen_(__g) {} + + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()() const { return __gen_(); } +}; + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___ALGORITHM_RANGES_UNIFORM_RANDOM_BIT_GENERATOR_ADAPTOR_H diff --git a/libcxx/include/__cxx03/__algorithm/unique.h b/libcxx/include/__cxx03/__algorithm/unique.h new file mode 100644 index 0000000000000000000000000000000000000000..d597014596f2ea4245c70e071a3d806c95098adb --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/unique.h @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_UNIQUE_H +#define _LIBCPP___ALGORITHM_UNIQUE_H + +#include <__algorithm/adjacent_find.h> +#include <__algorithm/comp.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// unique + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 std::pair<_Iter, _Iter> +__unique(_Iter __first, _Sent __last, _BinaryPredicate&& __pred) { + __first = std::__adjacent_find(__first, __last, __pred); + if (__first != __last) { + // ... a a ? ... + // f i + _Iter __i = __first; + for (++__i; ++__i != __last;) + if (!__pred(*__first, *__i)) + *++__first = _IterOps<_AlgPolicy>::__iter_move(__i); + ++__first; + return std::pair<_Iter, _Iter>(std::move(__first), std::move(__i)); + } + return std::pair<_Iter, _Iter>(__first, __first); +} + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +unique(_ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __pred) { + return std::__unique<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __pred).first; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +unique(_ForwardIterator __first, _ForwardIterator __last) { + return std::unique(__first, __last, __equal_to()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_UNIQUE_H diff --git a/libcxx/include/__cxx03/__algorithm/unique_copy.h b/libcxx/include/__cxx03/__algorithm/unique_copy.h new file mode 100644 index 0000000000000000000000000000000000000000..16ce80cab32f0dfba19bdbb9c3da7677e9e7c901 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/unique_copy.h @@ -0,0 +1,127 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_UNIQUE_COPY_H +#define _LIBCPP___ALGORITHM_UNIQUE_COPY_H + +#include <__algorithm/comp.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__type_traits/conditional.h> +#include <__type_traits/is_base_of.h> +#include <__type_traits/is_same.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __unique_copy_tags { + +struct __reread_from_input_tag {}; +struct __reread_from_output_tag {}; +struct __read_from_tmp_value_tag {}; + +} // namespace __unique_copy_tags + +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _OutputIterator> +__unique_copy(_InputIterator __first, + _Sent __last, + _OutputIterator __result, + _BinaryPredicate&& __pred, + __unique_copy_tags::__read_from_tmp_value_tag) { + if (__first != __last) { + typename _IterOps<_AlgPolicy>::template __value_type<_InputIterator> __t(*__first); + *__result = __t; + ++__result; + while (++__first != __last) { + if (!__pred(__t, *__first)) { + __t = *__first; + *__result = __t; + ++__result; + } + } + } + return pair<_InputIterator, _OutputIterator>(std::move(__first), std::move(__result)); +} + +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pair<_ForwardIterator, _OutputIterator> +__unique_copy(_ForwardIterator __first, + _Sent __last, + _OutputIterator __result, + _BinaryPredicate&& __pred, + __unique_copy_tags::__reread_from_input_tag) { + if (__first != __last) { + _ForwardIterator __i = __first; + *__result = *__i; + ++__result; + while (++__first != __last) { + if (!__pred(*__i, *__first)) { + *__result = *__first; + ++__result; + __i = __first; + } + } + } + return pair<_ForwardIterator, _OutputIterator>(std::move(__first), std::move(__result)); +} + +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _InputAndOutputIterator> +__unique_copy(_InputIterator __first, + _Sent __last, + _InputAndOutputIterator __result, + _BinaryPredicate&& __pred, + __unique_copy_tags::__reread_from_output_tag) { + if (__first != __last) { + *__result = *__first; + while (++__first != __last) + if (!__pred(*__result, *__first)) + *++__result = *__first; + ++__result; + } + return pair<_InputIterator, _InputAndOutputIterator>(std::move(__first), std::move(__result)); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +unique_copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _BinaryPredicate __pred) { + using __algo_tag = __conditional_t< + is_base_of::iterator_category>::value, + __unique_copy_tags::__reread_from_input_tag, + __conditional_t< + is_base_of::iterator_category>::value && + is_same< typename iterator_traits<_InputIterator>::value_type, + typename iterator_traits<_OutputIterator>::value_type>::value, + __unique_copy_tags::__reread_from_output_tag, + __unique_copy_tags::__read_from_tmp_value_tag> >; + return std::__unique_copy<_ClassicAlgPolicy>( + std::move(__first), std::move(__last), std::move(__result), __pred, __algo_tag()) + .second; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +unique_copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { + return std::unique_copy(std::move(__first), std::move(__last), std::move(__result), __equal_to()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_UNIQUE_COPY_H diff --git a/libcxx/include/__cxx03/__algorithm/unwrap_iter.h b/libcxx/include/__cxx03/__algorithm/unwrap_iter.h new file mode 100644 index 0000000000000000000000000000000000000000..8cc0d22d4fc21133c4c527726644925f836bb210 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/unwrap_iter.h @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_UNWRAP_ITER_H +#define _LIBCPP___ALGORITHM_UNWRAP_ITER_H + +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__memory/pointer_traits.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_constructible.h> +#include <__utility/declval.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// TODO: Change the name of __unwrap_iter_impl to something more appropriate +// The job of __unwrap_iter is to remove iterator wrappers (like reverse_iterator or __wrap_iter), +// to reduce the number of template instantiations and to enable pointer-based optimizations e.g. in std::copy. +// +// Some algorithms (e.g. std::copy, but not std::sort) need to convert an +// "unwrapped" result back into the original iterator type. Doing that is the job of __rewrap_iter. + +// Default case - we can't unwrap anything +template ::value> +struct __unwrap_iter_impl { + static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Iter __rewrap(_Iter, _Iter __iter) { return __iter; } + static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Iter __unwrap(_Iter __i) _NOEXCEPT { return __i; } +}; + +// TODO(hardening): make sure that the following unwrapping doesn't unexpectedly turn hardened iterators into raw +// pointers. + +// It's a contiguous iterator, so we can use a raw pointer instead +template +struct __unwrap_iter_impl<_Iter, true> { + using _ToAddressT = decltype(std::__to_address(std::declval<_Iter>())); + + static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Iter __rewrap(_Iter __orig_iter, _ToAddressT __unwrapped_iter) { + return __orig_iter + (__unwrapped_iter - std::__to_address(__orig_iter)); + } + + static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToAddressT __unwrap(_Iter __i) _NOEXCEPT { + return std::__to_address(__i); + } +}; + +template , + __enable_if_t::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 decltype(_Impl::__unwrap(std::declval<_Iter>())) +__unwrap_iter(_Iter __i) _NOEXCEPT { + return _Impl::__unwrap(__i); +} + +// Allow input_iterators to be passed to __unwrap_iter (but not __rewrap_iter) +#if _LIBCPP_STD_VER >= 20 +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI constexpr _Iter __unwrap_iter(_Iter __i) noexcept { + return __i; +} +#endif + +template > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _OrigIter __rewrap_iter(_OrigIter __orig_iter, _Iter __iter) _NOEXCEPT { + return _Impl::__rewrap(std::move(__orig_iter), std::move(__iter)); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_UNWRAP_ITER_H diff --git a/libcxx/include/__cxx03/__algorithm/unwrap_range.h b/libcxx/include/__cxx03/__algorithm/unwrap_range.h new file mode 100644 index 0000000000000000000000000000000000000000..2d4b9bb5545ad3e900b2e2e9cb8508155c57eded --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/unwrap_range.h @@ -0,0 +1,99 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_UNWRAP_RANGE_H +#define _LIBCPP___ALGORITHM_UNWRAP_RANGE_H + +#include <__algorithm/unwrap_iter.h> +#include <__concepts/constructible.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/next.h> +#include <__utility/declval.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// __unwrap_range and __rewrap_range are used to unwrap ranges which may have different iterator and sentinel types. +// __unwrap_iter and __rewrap_iter don't work for this, because they assume that the iterator and sentinel have +// the same type. __unwrap_range tries to get two iterators and then forward to __unwrap_iter. + +#if _LIBCPP_STD_VER >= 20 +template +struct __unwrap_range_impl { + _LIBCPP_HIDE_FROM_ABI static constexpr auto __unwrap(_Iter __first, _Sent __sent) + requires random_access_iterator<_Iter> && sized_sentinel_for<_Sent, _Iter> + { + auto __last = ranges::next(__first, __sent); + return pair{std::__unwrap_iter(std::move(__first)), std::__unwrap_iter(std::move(__last))}; + } + + _LIBCPP_HIDE_FROM_ABI static constexpr auto __unwrap(_Iter __first, _Sent __last) { + return pair{std::move(__first), std::move(__last)}; + } + + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __rewrap(_Iter __orig_iter, decltype(std::__unwrap_iter(std::move(__orig_iter))) __iter) + requires random_access_iterator<_Iter> && sized_sentinel_for<_Sent, _Iter> + { + return std::__rewrap_iter(std::move(__orig_iter), std::move(__iter)); + } + + _LIBCPP_HIDE_FROM_ABI static constexpr auto __rewrap(const _Iter&, _Iter __iter) + requires(!(random_access_iterator<_Iter> && sized_sentinel_for<_Sent, _Iter>)) + { + return __iter; + } +}; + +template +struct __unwrap_range_impl<_Iter, _Iter> { + _LIBCPP_HIDE_FROM_ABI static constexpr auto __unwrap(_Iter __first, _Iter __last) { + return pair{std::__unwrap_iter(std::move(__first)), std::__unwrap_iter(std::move(__last))}; + } + + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __rewrap(_Iter __orig_iter, decltype(std::__unwrap_iter(__orig_iter)) __iter) { + return std::__rewrap_iter(std::move(__orig_iter), std::move(__iter)); + } +}; + +template +_LIBCPP_HIDE_FROM_ABI constexpr auto __unwrap_range(_Iter __first, _Sent __last) { + return __unwrap_range_impl<_Iter, _Sent>::__unwrap(std::move(__first), std::move(__last)); +} + +template < class _Sent, class _Iter, class _Unwrapped> +_LIBCPP_HIDE_FROM_ABI constexpr _Iter __rewrap_range(_Iter __orig_iter, _Unwrapped __iter) { + return __unwrap_range_impl<_Iter, _Sent>::__rewrap(std::move(__orig_iter), std::move(__iter)); +} +#else // _LIBCPP_STD_VER >= 20 +template ()))> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR pair<_Unwrapped, _Unwrapped> __unwrap_range(_Iter __first, _Iter __last) { + return std::make_pair(std::__unwrap_iter(std::move(__first)), std::__unwrap_iter(std::move(__last))); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Iter __rewrap_range(_Iter __orig_iter, _Unwrapped __iter) { + return std::__rewrap_iter(std::move(__orig_iter), std::move(__iter)); +} +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_UNWRAP_RANGE_H diff --git a/libcxx/include/__cxx03/__algorithm/upper_bound.h b/libcxx/include/__cxx03/__algorithm/upper_bound.h new file mode 100644 index 0000000000000000000000000000000000000000..c39dec2e89698247a20678edf575690aceef9f11 --- /dev/null +++ b/libcxx/include/__cxx03/__algorithm/upper_bound.h @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_UPPER_BOUND_H +#define _LIBCPP___ALGORITHM_UPPER_BOUND_H + +#include <__algorithm/comp.h> +#include <__algorithm/half_positive.h> +#include <__algorithm/iterator_operations.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/invoke.h> +#include <__iterator/advance.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_constructible.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter +__upper_bound(_Iter __first, _Sent __last, const _Tp& __value, _Compare&& __comp, _Proj&& __proj) { + auto __len = _IterOps<_AlgPolicy>::distance(__first, __last); + while (__len != 0) { + auto __half_len = std::__half_positive(__len); + auto __mid = _IterOps<_AlgPolicy>::next(__first, __half_len); + if (std::__invoke(__comp, __value, std::__invoke(__proj, *__mid))) + __len = __half_len; + else { + __first = ++__mid; + __len -= __half_len + 1; + } + } + return __first; +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +upper_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, _Compare __comp) { + static_assert(is_copy_constructible<_ForwardIterator>::value, "Iterator has to be copy constructible"); + return std::__upper_bound<_ClassicAlgPolicy>( + std::move(__first), std::move(__last), __value, std::move(__comp), std::__identity()); +} + +template +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +upper_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + return std::upper_bound(std::move(__first), std::move(__last), __value, __less<>()); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_UPPER_BOUND_H diff --git a/libcxx/include/__cxx03/__assert b/libcxx/include/__cxx03/__assert new file mode 100644 index 0000000000000000000000000000000000000000..49769fb4d449783d05647e3e910b7cb5e3715e67 --- /dev/null +++ b/libcxx/include/__cxx03/__assert @@ -0,0 +1,118 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ASSERT +#define _LIBCPP___ASSERT + +#include <__assertion_handler> // Note: this include is generated by CMake and is potentially vendor-provided. +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#define _LIBCPP_ASSERT(expression, message) \ + (__builtin_expect(static_cast(expression), 1) \ + ? (void)0 \ + : _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(__LINE__) ": assertion " _LIBCPP_TOSTRING( \ + expression) " failed: " message "\n")) + +// TODO: __builtin_assume can currently inhibit optimizations. Until this has been fixed and we can add +// assumptions without a clear optimization intent, disable that to avoid worsening the code generation. +// See https://discourse.llvm.org/t/llvm-assume-blocks-optimization/71609 for a discussion. +#if 0 && __has_builtin(__builtin_assume) +# define _LIBCPP_ASSUME(expression) \ + (_LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wassume") \ + __builtin_assume(static_cast(expression)) _LIBCPP_DIAGNOSTIC_POP) +#else +# define _LIBCPP_ASSUME(expression) ((void)0) +#endif + +// clang-format off +// Fast hardening mode checks. + +#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_FAST + +// Enabled checks. +# define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSERT(expression, message) +// Disabled checks. +// On most modern platforms, dereferencing a null pointer does not lead to an actual memory access. +# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression) +// Overlapping ranges will make algorithms produce incorrect results but don't directly lead to a security +// vulnerability. +# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression) + +// Extensive hardening mode checks. + +#elif _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_EXTENSIVE + +// Enabled checks. +# define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message) +// Disabled checks. +# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) + +// Debug hardening mode checks. + +#elif _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG + +// All checks enabled. +# define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message) + +// Disable all checks if hardening is not enabled. + +#else + +// All checks disabled. +# define _LIBCPP_ASSERT_VALID_INPUT_RANGE(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_VALID_DEALLOCATION(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression) + +#endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_FAST +// clang-format on + +#endif // _LIBCPP___ASSERT diff --git a/libcxx/include/__cxx03/__atomic/aliases.h b/libcxx/include/__cxx03/__atomic/aliases.h new file mode 100644 index 0000000000000000000000000000000000000000..e27e09af6b77d90a7d314d5a531e17fbb36b6e8a --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/aliases.h @@ -0,0 +1,110 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_ALIASES_H +#define _LIBCPP___ATOMIC_ALIASES_H + +#include <__atomic/atomic.h> +#include <__atomic/atomic_lock_free.h> +#include <__atomic/contention_t.h> +#include <__atomic/is_always_lock_free.h> +#include <__config> +#include <__type_traits/conditional.h> +#include <__type_traits/make_unsigned.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +using atomic_bool = atomic; +using atomic_char = atomic; +using atomic_schar = atomic; +using atomic_uchar = atomic; +using atomic_short = atomic; +using atomic_ushort = atomic; +using atomic_int = atomic; +using atomic_uint = atomic; +using atomic_long = atomic; +using atomic_ulong = atomic; +using atomic_llong = atomic; +using atomic_ullong = atomic; +#ifndef _LIBCPP_HAS_NO_CHAR8_T +using atomic_char8_t = atomic; +#endif +using atomic_char16_t = atomic; +using atomic_char32_t = atomic; +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +using atomic_wchar_t = atomic; +#endif + +using atomic_int_least8_t = atomic; +using atomic_uint_least8_t = atomic; +using atomic_int_least16_t = atomic; +using atomic_uint_least16_t = atomic; +using atomic_int_least32_t = atomic; +using atomic_uint_least32_t = atomic; +using atomic_int_least64_t = atomic; +using atomic_uint_least64_t = atomic; + +using atomic_int_fast8_t = atomic; +using atomic_uint_fast8_t = atomic; +using atomic_int_fast16_t = atomic; +using atomic_uint_fast16_t = atomic; +using atomic_int_fast32_t = atomic; +using atomic_uint_fast32_t = atomic; +using atomic_int_fast64_t = atomic; +using atomic_uint_fast64_t = atomic; + +using atomic_int8_t = atomic< int8_t>; +using atomic_uint8_t = atomic; +using atomic_int16_t = atomic< int16_t>; +using atomic_uint16_t = atomic; +using atomic_int32_t = atomic< int32_t>; +using atomic_uint32_t = atomic; +using atomic_int64_t = atomic< int64_t>; +using atomic_uint64_t = atomic; + +using atomic_intptr_t = atomic; +using atomic_uintptr_t = atomic; +using atomic_size_t = atomic; +using atomic_ptrdiff_t = atomic; +using atomic_intmax_t = atomic; +using atomic_uintmax_t = atomic; + +// C++20 atomic_{signed,unsigned}_lock_free: prefer the contention type most highly, then the largest lock-free type +#if _LIBCPP_STD_VER >= 20 +# if ATOMIC_LLONG_LOCK_FREE == 2 +using __largest_lock_free_type = long long; +# elif ATOMIC_INT_LOCK_FREE == 2 +using __largest_lock_free_type = int; +# elif ATOMIC_SHORT_LOCK_FREE == 2 +using __largest_lock_free_type = short; +# elif ATOMIC_CHAR_LOCK_FREE == 2 +using __largest_lock_free_type = char; +# else +# define _LIBCPP_NO_LOCK_FREE_TYPES // There are no lockfree types (this can happen on unusual platforms) +# endif + +# ifndef _LIBCPP_NO_LOCK_FREE_TYPES +using __contention_t_or_largest = + __conditional_t<__libcpp_is_always_lock_free<__cxx_contention_t>::__value, + __cxx_contention_t, + __largest_lock_free_type>; + +using atomic_signed_lock_free = atomic<__contention_t_or_largest>; +using atomic_unsigned_lock_free = atomic>; +# endif // !_LIBCPP_NO_LOCK_FREE_TYPES +#endif // C++20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_ALIASES_H diff --git a/libcxx/include/__cxx03/__atomic/atomic.h b/libcxx/include/__cxx03/__atomic/atomic.h new file mode 100644 index 0000000000000000000000000000000000000000..bd3f659c22df01e23498f6caa1f7659812c4f7e4 --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/atomic.h @@ -0,0 +1,622 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_ATOMIC_H +#define _LIBCPP___ATOMIC_ATOMIC_H + +#include <__atomic/atomic_base.h> +#include <__atomic/check_memory_order.h> +#include <__atomic/cxx_atomic_impl.h> +#include <__atomic/memory_order.h> +#include <__config> +#include <__functional/operations.h> +#include <__memory/addressof.h> +#include <__type_traits/is_floating_point.h> +#include <__type_traits/is_function.h> +#include <__type_traits/is_same.h> +#include <__type_traits/remove_const.h> +#include <__type_traits/remove_pointer.h> +#include <__type_traits/remove_volatile.h> +#include <__utility/forward.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct atomic : public __atomic_base<_Tp> { + using __base = __atomic_base<_Tp>; + using value_type = _Tp; + using difference_type = value_type; + +#if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI atomic() = default; +#else + _LIBCPP_HIDE_FROM_ABI atomic() _NOEXCEPT = default; +#endif + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR atomic(_Tp __d) _NOEXCEPT : __base(__d) {} + + _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) volatile _NOEXCEPT { + __base::store(__d); + return __d; + } + _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) _NOEXCEPT { + __base::store(__d); + return __d; + } + + atomic& operator=(const atomic&) = delete; + atomic& operator=(const atomic&) volatile = delete; +}; + +// atomic + +template +struct atomic<_Tp*> : public __atomic_base<_Tp*> { + using __base = __atomic_base<_Tp*>; + using value_type = _Tp*; + using difference_type = ptrdiff_t; + + _LIBCPP_HIDE_FROM_ABI atomic() _NOEXCEPT = default; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR atomic(_Tp* __d) _NOEXCEPT : __base(__d) {} + + _LIBCPP_HIDE_FROM_ABI _Tp* operator=(_Tp* __d) volatile _NOEXCEPT { + __base::store(__d); + return __d; + } + _LIBCPP_HIDE_FROM_ABI _Tp* operator=(_Tp* __d) _NOEXCEPT { + __base::store(__d); + return __d; + } + + _LIBCPP_HIDE_FROM_ABI _Tp* fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + // __atomic_fetch_add accepts function pointers, guard against them. + static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed"); + return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m); + } + + _LIBCPP_HIDE_FROM_ABI _Tp* fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT { + // __atomic_fetch_add accepts function pointers, guard against them. + static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed"); + return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m); + } + + _LIBCPP_HIDE_FROM_ABI _Tp* fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + // __atomic_fetch_add accepts function pointers, guard against them. + static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed"); + return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m); + } + + _LIBCPP_HIDE_FROM_ABI _Tp* fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT { + // __atomic_fetch_add accepts function pointers, guard against them. + static_assert(!is_function<__remove_pointer_t<_Tp> >::value, "Pointer to function isn't allowed"); + return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m); + } + + _LIBCPP_HIDE_FROM_ABI _Tp* operator++(int) volatile _NOEXCEPT { return fetch_add(1); } + _LIBCPP_HIDE_FROM_ABI _Tp* operator++(int) _NOEXCEPT { return fetch_add(1); } + _LIBCPP_HIDE_FROM_ABI _Tp* operator--(int) volatile _NOEXCEPT { return fetch_sub(1); } + _LIBCPP_HIDE_FROM_ABI _Tp* operator--(int) _NOEXCEPT { return fetch_sub(1); } + _LIBCPP_HIDE_FROM_ABI _Tp* operator++() volatile _NOEXCEPT { return fetch_add(1) + 1; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator++() _NOEXCEPT { return fetch_add(1) + 1; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator--() volatile _NOEXCEPT { return fetch_sub(1) - 1; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator--() _NOEXCEPT { return fetch_sub(1) - 1; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator+=(ptrdiff_t __op) volatile _NOEXCEPT { return fetch_add(__op) + __op; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator+=(ptrdiff_t __op) _NOEXCEPT { return fetch_add(__op) + __op; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator-=(ptrdiff_t __op) volatile _NOEXCEPT { return fetch_sub(__op) - __op; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator-=(ptrdiff_t __op) _NOEXCEPT { return fetch_sub(__op) - __op; } + + atomic& operator=(const atomic&) = delete; + atomic& operator=(const atomic&) volatile = delete; +}; + +#if _LIBCPP_STD_VER >= 20 +template + requires is_floating_point_v<_Tp> +struct atomic<_Tp> : __atomic_base<_Tp> { +private: + _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_fp80_long_double() { + // Only x87-fp80 long double has 64-bit mantissa + return __LDBL_MANT_DIG__ == 64 && std::is_same_v<_Tp, long double>; + } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool __has_rmw_builtin() { +# ifndef _LIBCPP_COMPILER_CLANG_BASED + return false; +# else + // The builtin __cxx_atomic_fetch_add errors during compilation for + // long double on platforms with fp80 format. + // For more details, see + // lib/Sema/SemaChecking.cpp function IsAllowedValueType + // LLVM Parser does not allow atomicrmw with x86_fp80 type. + // if (ValType->isSpecificBuiltinType(BuiltinType::LongDouble) && + // &Context.getTargetInfo().getLongDoubleFormat() == + // &llvm::APFloat::x87DoubleExtended()) + // For more info + // https://github.com/llvm/llvm-project/issues/68602 + // https://reviews.llvm.org/D53965 + return !__is_fp80_long_double(); +# endif + } + + template + _LIBCPP_HIDE_FROM_ABI static _Tp + __rmw_op(_This&& __self, _Tp __operand, memory_order __m, _Operation __operation, _BuiltinOp __builtin_op) { + if constexpr (__has_rmw_builtin()) { + return __builtin_op(std::addressof(std::forward<_This>(__self).__a_), __operand, __m); + } else { + _Tp __old = __self.load(memory_order_relaxed); + _Tp __new = __operation(__old, __operand); + while (!__self.compare_exchange_weak(__old, __new, __m, memory_order_relaxed)) { +# ifdef _LIBCPP_COMPILER_CLANG_BASED + if constexpr (__is_fp80_long_double()) { + // https://github.com/llvm/llvm-project/issues/47978 + // clang bug: __old is not updated on failure for atomic::compare_exchange_weak + // Note __old = __self.load(memory_order_relaxed) will not work + std::__cxx_atomic_load_inplace(std::addressof(__self.__a_), &__old, memory_order_relaxed); + } +# endif + __new = __operation(__old, __operand); + } + return __old; + } + } + + template + _LIBCPP_HIDE_FROM_ABI static _Tp __fetch_add(_This&& __self, _Tp __operand, memory_order __m) { + auto __builtin_op = [](auto __a, auto __builtin_operand, auto __order) { + return std::__cxx_atomic_fetch_add(__a, __builtin_operand, __order); + }; + return __rmw_op(std::forward<_This>(__self), __operand, __m, std::plus<>{}, __builtin_op); + } + + template + _LIBCPP_HIDE_FROM_ABI static _Tp __fetch_sub(_This&& __self, _Tp __operand, memory_order __m) { + auto __builtin_op = [](auto __a, auto __builtin_operand, auto __order) { + return std::__cxx_atomic_fetch_sub(__a, __builtin_operand, __order); + }; + return __rmw_op(std::forward<_This>(__self), __operand, __m, std::minus<>{}, __builtin_op); + } + +public: + using __base = __atomic_base<_Tp>; + using value_type = _Tp; + using difference_type = value_type; + + _LIBCPP_HIDE_FROM_ABI constexpr atomic() noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr atomic(_Tp __d) noexcept : __base(__d) {} + + atomic(const atomic&) = delete; + atomic& operator=(const atomic&) = delete; + atomic& operator=(const atomic&) volatile = delete; + + _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) volatile noexcept + requires __base::is_always_lock_free + { + __base::store(__d); + return __d; + } + _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) noexcept { + __base::store(__d); + return __d; + } + + _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept + requires __base::is_always_lock_free + { + return __fetch_add(*this, __op, __m); + } + + _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) noexcept { + return __fetch_add(*this, __op, __m); + } + + _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept + requires __base::is_always_lock_free + { + return __fetch_sub(*this, __op, __m); + } + + _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) noexcept { + return __fetch_sub(*this, __op, __m); + } + + _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) volatile noexcept + requires __base::is_always_lock_free + { + return fetch_add(__op) + __op; + } + + _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) noexcept { return fetch_add(__op) + __op; } + + _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) volatile noexcept + requires __base::is_always_lock_free + { + return fetch_sub(__op) - __op; + } + + _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) noexcept { return fetch_sub(__op) - __op; } +}; + +#endif // _LIBCPP_STD_VER >= 20 + +// atomic_is_lock_free + +template +_LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const volatile atomic<_Tp>* __o) _NOEXCEPT { + return __o->is_lock_free(); +} + +template +_LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const atomic<_Tp>* __o) _NOEXCEPT { + return __o->is_lock_free(); +} + +// atomic_init + +template +_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI void +atomic_init(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT { + std::__cxx_atomic_init(std::addressof(__o->__a_), __d); +} + +template +_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI void +atomic_init(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT { + std::__cxx_atomic_init(std::addressof(__o->__a_), __d); +} + +// atomic_store + +template +_LIBCPP_HIDE_FROM_ABI void atomic_store(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT { + __o->store(__d); +} + +template +_LIBCPP_HIDE_FROM_ABI void atomic_store(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT { + __o->store(__d); +} + +// atomic_store_explicit + +template +_LIBCPP_HIDE_FROM_ABI void +atomic_store_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d, memory_order __m) _NOEXCEPT + _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) { + __o->store(__d, __m); +} + +template +_LIBCPP_HIDE_FROM_ABI void +atomic_store_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d, memory_order __m) _NOEXCEPT + _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) { + __o->store(__d, __m); +} + +// atomic_load + +template +_LIBCPP_HIDE_FROM_ABI _Tp atomic_load(const volatile atomic<_Tp>* __o) _NOEXCEPT { + return __o->load(); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp atomic_load(const atomic<_Tp>* __o) _NOEXCEPT { + return __o->load(); +} + +// atomic_load_explicit + +template +_LIBCPP_HIDE_FROM_ABI _Tp atomic_load_explicit(const volatile atomic<_Tp>* __o, memory_order __m) _NOEXCEPT + _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { + return __o->load(__m); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp atomic_load_explicit(const atomic<_Tp>* __o, memory_order __m) _NOEXCEPT + _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { + return __o->load(__m); +} + +// atomic_exchange + +template +_LIBCPP_HIDE_FROM_ABI _Tp atomic_exchange(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT { + return __o->exchange(__d); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp atomic_exchange(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d) _NOEXCEPT { + return __o->exchange(__d); +} + +// atomic_exchange_explicit + +template +_LIBCPP_HIDE_FROM_ABI _Tp +atomic_exchange_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d, memory_order __m) _NOEXCEPT { + return __o->exchange(__d, __m); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +atomic_exchange_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d, memory_order __m) _NOEXCEPT { + return __o->exchange(__d, __m); +} + +// atomic_compare_exchange_weak + +template +_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_weak( + volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e, typename atomic<_Tp>::value_type __d) _NOEXCEPT { + return __o->compare_exchange_weak(*__e, __d); +} + +template +_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_weak( + atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e, typename atomic<_Tp>::value_type __d) _NOEXCEPT { + return __o->compare_exchange_weak(*__e, __d); +} + +// atomic_compare_exchange_strong + +template +_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_strong( + volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e, typename atomic<_Tp>::value_type __d) _NOEXCEPT { + return __o->compare_exchange_strong(*__e, __d); +} + +template +_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_strong( + atomic<_Tp>* __o, typename atomic<_Tp>::value_type* __e, typename atomic<_Tp>::value_type __d) _NOEXCEPT { + return __o->compare_exchange_strong(*__e, __d); +} + +// atomic_compare_exchange_weak_explicit + +template +_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_weak_explicit( + volatile atomic<_Tp>* __o, + typename atomic<_Tp>::value_type* __e, + typename atomic<_Tp>::value_type __d, + memory_order __s, + memory_order __f) _NOEXCEPT _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) { + return __o->compare_exchange_weak(*__e, __d, __s, __f); +} + +template +_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_weak_explicit( + atomic<_Tp>* __o, + typename atomic<_Tp>::value_type* __e, + typename atomic<_Tp>::value_type __d, + memory_order __s, + memory_order __f) _NOEXCEPT _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) { + return __o->compare_exchange_weak(*__e, __d, __s, __f); +} + +// atomic_compare_exchange_strong_explicit + +template +_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_strong_explicit( + volatile atomic<_Tp>* __o, + typename atomic<_Tp>::value_type* __e, + typename atomic<_Tp>::value_type __d, + memory_order __s, + memory_order __f) _NOEXCEPT _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) { + return __o->compare_exchange_strong(*__e, __d, __s, __f); +} + +template +_LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_strong_explicit( + atomic<_Tp>* __o, + typename atomic<_Tp>::value_type* __e, + typename atomic<_Tp>::value_type __d, + memory_order __s, + memory_order __f) _NOEXCEPT _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) { + return __o->compare_exchange_strong(*__e, __d, __s, __f); +} + +// atomic_wait + +template +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void +atomic_wait(const volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __v) _NOEXCEPT { + return __o->wait(__v); +} + +template +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void +atomic_wait(const atomic<_Tp>* __o, typename atomic<_Tp>::value_type __v) _NOEXCEPT { + return __o->wait(__v); +} + +// atomic_wait_explicit + +template +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void +atomic_wait_explicit(const volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __v, memory_order __m) _NOEXCEPT + _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { + return __o->wait(__v, __m); +} + +template +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void +atomic_wait_explicit(const atomic<_Tp>* __o, typename atomic<_Tp>::value_type __v, memory_order __m) _NOEXCEPT + _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { + return __o->wait(__v, __m); +} + +// atomic_notify_one + +template +_LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void +atomic_notify_one(volatile atomic<_Tp>* __o) _NOEXCEPT { + __o->notify_one(); +} +template +_LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void +atomic_notify_one(atomic<_Tp>* __o) _NOEXCEPT { + __o->notify_one(); +} + +// atomic_notify_all + +template +_LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void +atomic_notify_all(volatile atomic<_Tp>* __o) _NOEXCEPT { + __o->notify_all(); +} +template +_LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void +atomic_notify_all(atomic<_Tp>* __o) _NOEXCEPT { + __o->notify_all(); +} + +// atomic_fetch_add + +template +_LIBCPP_HIDE_FROM_ABI _Tp +atomic_fetch_add(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT { + return __o->fetch_add(__op); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_add(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT { + return __o->fetch_add(__op); +} + +// atomic_fetch_add_explicit + +template +_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_add_explicit( + volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT { + return __o->fetch_add(__op, __m); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +atomic_fetch_add_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT { + return __o->fetch_add(__op, __m); +} + +// atomic_fetch_sub + +template +_LIBCPP_HIDE_FROM_ABI _Tp +atomic_fetch_sub(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT { + return __o->fetch_sub(__op); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_sub(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT { + return __o->fetch_sub(__op); +} + +// atomic_fetch_sub_explicit + +template +_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_sub_explicit( + volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT { + return __o->fetch_sub(__op, __m); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +atomic_fetch_sub_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT { + return __o->fetch_sub(__op, __m); +} + +// atomic_fetch_and + +template ::value && !is_same<_Tp, bool>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_and(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT { + return __o->fetch_and(__op); +} + +template ::value && !is_same<_Tp, bool>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_and(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT { + return __o->fetch_and(__op); +} + +// atomic_fetch_and_explicit + +template ::value && !is_same<_Tp, bool>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_and_explicit( + volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT { + return __o->fetch_and(__op, __m); +} + +template ::value && !is_same<_Tp, bool>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp +atomic_fetch_and_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT { + return __o->fetch_and(__op, __m); +} + +// atomic_fetch_or + +template ::value && !is_same<_Tp, bool>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_or(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT { + return __o->fetch_or(__op); +} + +template ::value && !is_same<_Tp, bool>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_or(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT { + return __o->fetch_or(__op); +} + +// atomic_fetch_or_explicit + +template ::value && !is_same<_Tp, bool>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp +atomic_fetch_or_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT { + return __o->fetch_or(__op, __m); +} + +template ::value && !is_same<_Tp, bool>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp +atomic_fetch_or_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT { + return __o->fetch_or(__op, __m); +} + +// atomic_fetch_xor + +template ::value && !is_same<_Tp, bool>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_xor(volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT { + return __o->fetch_xor(__op); +} + +template ::value && !is_same<_Tp, bool>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_xor(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op) _NOEXCEPT { + return __o->fetch_xor(__op); +} + +// atomic_fetch_xor_explicit + +template ::value && !is_same<_Tp, bool>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp atomic_fetch_xor_explicit( + volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT { + return __o->fetch_xor(__op, __m); +} + +template ::value && !is_same<_Tp, bool>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Tp +atomic_fetch_xor_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __op, memory_order __m) _NOEXCEPT { + return __o->fetch_xor(__op, __m); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_ATOMIC_H diff --git a/libcxx/include/__cxx03/__atomic/atomic_base.h b/libcxx/include/__cxx03/__atomic/atomic_base.h new file mode 100644 index 0000000000000000000000000000000000000000..7e26434c9c3a0abb1673f1bc118a93ae7789c94f --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/atomic_base.h @@ -0,0 +1,221 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_ATOMIC_BASE_H +#define _LIBCPP___ATOMIC_ATOMIC_BASE_H + +#include <__atomic/atomic_sync.h> +#include <__atomic/check_memory_order.h> +#include <__atomic/cxx_atomic_impl.h> +#include <__atomic/is_always_lock_free.h> +#include <__atomic/memory_order.h> +#include <__config> +#include <__memory/addressof.h> +#include <__type_traits/is_integral.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_same.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template ::value && !is_same<_Tp, bool>::value> +struct __atomic_base // false +{ + mutable __cxx_atomic_impl<_Tp> __a_; + +#if _LIBCPP_STD_VER >= 17 + static constexpr bool is_always_lock_free = __libcpp_is_always_lock_free<__cxx_atomic_impl<_Tp> >::__value; +#endif + + _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const volatile _NOEXCEPT { + return __cxx_atomic_is_lock_free(sizeof(__cxx_atomic_impl<_Tp>)); + } + _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const _NOEXCEPT { + return static_cast<__atomic_base const volatile*>(this)->is_lock_free(); + } + _LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT + _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) { + std::__cxx_atomic_store(std::addressof(__a_), __d, __m); + } + _LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT + _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) { + std::__cxx_atomic_store(std::addressof(__a_), __d, __m); + } + _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT + _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { + return std::__cxx_atomic_load(std::addressof(__a_), __m); + } + _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const _NOEXCEPT + _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { + return std::__cxx_atomic_load(std::addressof(__a_), __m); + } + _LIBCPP_HIDE_FROM_ABI operator _Tp() const volatile _NOEXCEPT { return load(); } + _LIBCPP_HIDE_FROM_ABI operator _Tp() const _NOEXCEPT { return load(); } + _LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + return std::__cxx_atomic_exchange(std::addressof(__a_), __d, __m); + } + _LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT { + return std::__cxx_atomic_exchange(std::addressof(__a_), __d, __m); + } + _LIBCPP_HIDE_FROM_ABI bool + compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) volatile _NOEXCEPT + _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) { + return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __s, __f); + } + _LIBCPP_HIDE_FROM_ABI bool compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) _NOEXCEPT + _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) { + return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __s, __f); + } + _LIBCPP_HIDE_FROM_ABI bool + compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) volatile _NOEXCEPT + _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) { + return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __s, __f); + } + _LIBCPP_HIDE_FROM_ABI bool compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __s, memory_order __f) _NOEXCEPT + _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__s, __f) { + return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __s, __f); + } + _LIBCPP_HIDE_FROM_ABI bool + compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __m, __m); + } + _LIBCPP_HIDE_FROM_ABI bool + compare_exchange_weak(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT { + return std::__cxx_atomic_compare_exchange_weak(std::addressof(__a_), std::addressof(__e), __d, __m, __m); + } + _LIBCPP_HIDE_FROM_ABI bool + compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __m, __m); + } + _LIBCPP_HIDE_FROM_ABI bool + compare_exchange_strong(_Tp& __e, _Tp __d, memory_order __m = memory_order_seq_cst) _NOEXCEPT { + return std::__cxx_atomic_compare_exchange_strong(std::addressof(__a_), std::addressof(__e), __d, __m, __m); + } + + _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait(_Tp __v, memory_order __m = memory_order_seq_cst) const + volatile _NOEXCEPT { + std::__atomic_wait(*this, __v, __m); + } + _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void + wait(_Tp __v, memory_order __m = memory_order_seq_cst) const _NOEXCEPT { + std::__atomic_wait(*this, __v, __m); + } + _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() volatile _NOEXCEPT { + std::__atomic_notify_one(*this); + } + _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() _NOEXCEPT { std::__atomic_notify_one(*this); } + _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() volatile _NOEXCEPT { + std::__atomic_notify_all(*this); + } + _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT { std::__atomic_notify_all(*this); } + +#if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI constexpr __atomic_base() noexcept(is_nothrow_default_constructible_v<_Tp>) : __a_(_Tp()) {} +#else + _LIBCPP_HIDE_FROM_ABI __atomic_base() _NOEXCEPT = default; +#endif + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __a_(__d) {} + + __atomic_base(const __atomic_base&) = delete; +}; + +// atomic + +template +struct __atomic_base<_Tp, true> : public __atomic_base<_Tp, false> { + using __base = __atomic_base<_Tp, false>; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __atomic_base() _NOEXCEPT = default; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __atomic_base(_Tp __d) _NOEXCEPT : __base(__d) {} + + _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT { + return std::__cxx_atomic_fetch_add(std::addressof(this->__a_), __op, __m); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT { + return std::__cxx_atomic_fetch_sub(std::addressof(this->__a_), __op, __m); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_and(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + return std::__cxx_atomic_fetch_and(std::addressof(this->__a_), __op, __m); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_and(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT { + return std::__cxx_atomic_fetch_and(std::addressof(this->__a_), __op, __m); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_or(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + return std::__cxx_atomic_fetch_or(std::addressof(this->__a_), __op, __m); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_or(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT { + return std::__cxx_atomic_fetch_or(std::addressof(this->__a_), __op, __m); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_xor(_Tp __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + return std::__cxx_atomic_fetch_xor(std::addressof(this->__a_), __op, __m); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_xor(_Tp __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT { + return std::__cxx_atomic_fetch_xor(std::addressof(this->__a_), __op, __m); + } + + _LIBCPP_HIDE_FROM_ABI _Tp operator++(int) volatile _NOEXCEPT { return fetch_add(_Tp(1)); } + _LIBCPP_HIDE_FROM_ABI _Tp operator++(int) _NOEXCEPT { return fetch_add(_Tp(1)); } + _LIBCPP_HIDE_FROM_ABI _Tp operator--(int) volatile _NOEXCEPT { return fetch_sub(_Tp(1)); } + _LIBCPP_HIDE_FROM_ABI _Tp operator--(int) _NOEXCEPT { return fetch_sub(_Tp(1)); } + _LIBCPP_HIDE_FROM_ABI _Tp operator++() volatile _NOEXCEPT { return fetch_add(_Tp(1)) + _Tp(1); } + _LIBCPP_HIDE_FROM_ABI _Tp operator++() _NOEXCEPT { return fetch_add(_Tp(1)) + _Tp(1); } + _LIBCPP_HIDE_FROM_ABI _Tp operator--() volatile _NOEXCEPT { return fetch_sub(_Tp(1)) - _Tp(1); } + _LIBCPP_HIDE_FROM_ABI _Tp operator--() _NOEXCEPT { return fetch_sub(_Tp(1)) - _Tp(1); } + _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) volatile _NOEXCEPT { return fetch_add(__op) + __op; } + _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) _NOEXCEPT { return fetch_add(__op) + __op; } + _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) volatile _NOEXCEPT { return fetch_sub(__op) - __op; } + _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) _NOEXCEPT { return fetch_sub(__op) - __op; } + _LIBCPP_HIDE_FROM_ABI _Tp operator&=(_Tp __op) volatile _NOEXCEPT { return fetch_and(__op) & __op; } + _LIBCPP_HIDE_FROM_ABI _Tp operator&=(_Tp __op) _NOEXCEPT { return fetch_and(__op) & __op; } + _LIBCPP_HIDE_FROM_ABI _Tp operator|=(_Tp __op) volatile _NOEXCEPT { return fetch_or(__op) | __op; } + _LIBCPP_HIDE_FROM_ABI _Tp operator|=(_Tp __op) _NOEXCEPT { return fetch_or(__op) | __op; } + _LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) volatile _NOEXCEPT { return fetch_xor(__op) ^ __op; } + _LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) _NOEXCEPT { return fetch_xor(__op) ^ __op; } +}; + +// Here we need _IsIntegral because the default template argument is not enough +// e.g __atomic_base is __atomic_base, which inherits from +// __atomic_base and the caller of the wait function is +// __atomic_base. So specializing __atomic_base<_Tp> does not work +template +struct __atomic_waitable_traits<__atomic_base<_Tp, _IsIntegral> > { + static _LIBCPP_HIDE_FROM_ABI _Tp __atomic_load(const __atomic_base<_Tp, _IsIntegral>& __a, memory_order __order) { + return __a.load(__order); + } + + static _LIBCPP_HIDE_FROM_ABI _Tp + __atomic_load(const volatile __atomic_base<_Tp, _IsIntegral>& __this, memory_order __order) { + return __this.load(__order); + } + + static _LIBCPP_HIDE_FROM_ABI const __cxx_atomic_impl<_Tp>* + __atomic_contention_address(const __atomic_base<_Tp, _IsIntegral>& __a) { + return std::addressof(__a.__a_); + } + + static _LIBCPP_HIDE_FROM_ABI const volatile __cxx_atomic_impl<_Tp>* + __atomic_contention_address(const volatile __atomic_base<_Tp, _IsIntegral>& __this) { + return std::addressof(__this.__a_); + } +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_ATOMIC_BASE_H diff --git a/libcxx/include/__cxx03/__atomic/atomic_flag.h b/libcxx/include/__cxx03/__atomic/atomic_flag.h new file mode 100644 index 0000000000000000000000000000000000000000..00b157cdff78b7677013ff9541fdea811ba0d5ef --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/atomic_flag.h @@ -0,0 +1,189 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_ATOMIC_FLAG_H +#define _LIBCPP___ATOMIC_ATOMIC_FLAG_H + +#include <__atomic/atomic_sync.h> +#include <__atomic/contention_t.h> +#include <__atomic/cxx_atomic_impl.h> +#include <__atomic/memory_order.h> +#include <__chrono/duration.h> +#include <__config> +#include <__memory/addressof.h> +#include <__thread/support.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +struct atomic_flag { + __cxx_atomic_impl<_LIBCPP_ATOMIC_FLAG_TYPE> __a_; + + _LIBCPP_HIDE_FROM_ABI bool test(memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT { + return _LIBCPP_ATOMIC_FLAG_TYPE(true) == __cxx_atomic_load(&__a_, __m); + } + _LIBCPP_HIDE_FROM_ABI bool test(memory_order __m = memory_order_seq_cst) const _NOEXCEPT { + return _LIBCPP_ATOMIC_FLAG_TYPE(true) == __cxx_atomic_load(&__a_, __m); + } + + _LIBCPP_HIDE_FROM_ABI bool test_and_set(memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + return __cxx_atomic_exchange(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(true), __m); + } + _LIBCPP_HIDE_FROM_ABI bool test_and_set(memory_order __m = memory_order_seq_cst) _NOEXCEPT { + return __cxx_atomic_exchange(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(true), __m); + } + _LIBCPP_HIDE_FROM_ABI void clear(memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + __cxx_atomic_store(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(false), __m); + } + _LIBCPP_HIDE_FROM_ABI void clear(memory_order __m = memory_order_seq_cst) _NOEXCEPT { + __cxx_atomic_store(&__a_, _LIBCPP_ATOMIC_FLAG_TYPE(false), __m); + } + + _LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void + wait(bool __v, memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT { + std::__atomic_wait(*this, _LIBCPP_ATOMIC_FLAG_TYPE(__v), __m); + } + _LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void + wait(bool __v, memory_order __m = memory_order_seq_cst) const _NOEXCEPT { + std::__atomic_wait(*this, _LIBCPP_ATOMIC_FLAG_TYPE(__v), __m); + } + _LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() volatile _NOEXCEPT { + std::__atomic_notify_one(*this); + } + _LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() _NOEXCEPT { + std::__atomic_notify_one(*this); + } + _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() volatile _NOEXCEPT { + std::__atomic_notify_all(*this); + } + _LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT { + std::__atomic_notify_all(*this); + } + +#if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI constexpr atomic_flag() _NOEXCEPT : __a_(false) {} +#else + atomic_flag() _NOEXCEPT = default; +#endif + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR atomic_flag(bool __b) _NOEXCEPT : __a_(__b) {} // EXTENSION + + atomic_flag(const atomic_flag&) = delete; + atomic_flag& operator=(const atomic_flag&) = delete; + atomic_flag& operator=(const atomic_flag&) volatile = delete; +}; + +template <> +struct __atomic_waitable_traits { + static _LIBCPP_HIDE_FROM_ABI _LIBCPP_ATOMIC_FLAG_TYPE __atomic_load(const atomic_flag& __a, memory_order __order) { + return std::__cxx_atomic_load(&__a.__a_, __order); + } + + static _LIBCPP_HIDE_FROM_ABI _LIBCPP_ATOMIC_FLAG_TYPE + __atomic_load(const volatile atomic_flag& __a, memory_order __order) { + return std::__cxx_atomic_load(&__a.__a_, __order); + } + + static _LIBCPP_HIDE_FROM_ABI const __cxx_atomic_impl<_LIBCPP_ATOMIC_FLAG_TYPE>* + __atomic_contention_address(const atomic_flag& __a) { + return std::addressof(__a.__a_); + } + + static _LIBCPP_HIDE_FROM_ABI const volatile __cxx_atomic_impl<_LIBCPP_ATOMIC_FLAG_TYPE>* + __atomic_contention_address(const volatile atomic_flag& __a) { + return std::addressof(__a.__a_); + } +}; + +inline _LIBCPP_HIDE_FROM_ABI bool atomic_flag_test(const volatile atomic_flag* __o) _NOEXCEPT { return __o->test(); } + +inline _LIBCPP_HIDE_FROM_ABI bool atomic_flag_test(const atomic_flag* __o) _NOEXCEPT { return __o->test(); } + +inline _LIBCPP_HIDE_FROM_ABI bool +atomic_flag_test_explicit(const volatile atomic_flag* __o, memory_order __m) _NOEXCEPT { + return __o->test(__m); +} + +inline _LIBCPP_HIDE_FROM_ABI bool atomic_flag_test_explicit(const atomic_flag* __o, memory_order __m) _NOEXCEPT { + return __o->test(__m); +} + +inline _LIBCPP_HIDE_FROM_ABI bool atomic_flag_test_and_set(volatile atomic_flag* __o) _NOEXCEPT { + return __o->test_and_set(); +} + +inline _LIBCPP_HIDE_FROM_ABI bool atomic_flag_test_and_set(atomic_flag* __o) _NOEXCEPT { return __o->test_and_set(); } + +inline _LIBCPP_HIDE_FROM_ABI bool +atomic_flag_test_and_set_explicit(volatile atomic_flag* __o, memory_order __m) _NOEXCEPT { + return __o->test_and_set(__m); +} + +inline _LIBCPP_HIDE_FROM_ABI bool atomic_flag_test_and_set_explicit(atomic_flag* __o, memory_order __m) _NOEXCEPT { + return __o->test_and_set(__m); +} + +inline _LIBCPP_HIDE_FROM_ABI void atomic_flag_clear(volatile atomic_flag* __o) _NOEXCEPT { __o->clear(); } + +inline _LIBCPP_HIDE_FROM_ABI void atomic_flag_clear(atomic_flag* __o) _NOEXCEPT { __o->clear(); } + +inline _LIBCPP_HIDE_FROM_ABI void atomic_flag_clear_explicit(volatile atomic_flag* __o, memory_order __m) _NOEXCEPT { + __o->clear(__m); +} + +inline _LIBCPP_HIDE_FROM_ABI void atomic_flag_clear_explicit(atomic_flag* __o, memory_order __m) _NOEXCEPT { + __o->clear(__m); +} + +inline _LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void +atomic_flag_wait(const volatile atomic_flag* __o, bool __v) _NOEXCEPT { + __o->wait(__v); +} + +inline _LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void +atomic_flag_wait(const atomic_flag* __o, bool __v) _NOEXCEPT { + __o->wait(__v); +} + +inline _LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void +atomic_flag_wait_explicit(const volatile atomic_flag* __o, bool __v, memory_order __m) _NOEXCEPT { + __o->wait(__v, __m); +} + +inline _LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void +atomic_flag_wait_explicit(const atomic_flag* __o, bool __v, memory_order __m) _NOEXCEPT { + __o->wait(__v, __m); +} + +inline _LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void +atomic_flag_notify_one(volatile atomic_flag* __o) _NOEXCEPT { + __o->notify_one(); +} + +inline _LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void +atomic_flag_notify_one(atomic_flag* __o) _NOEXCEPT { + __o->notify_one(); +} + +inline _LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void +atomic_flag_notify_all(volatile atomic_flag* __o) _NOEXCEPT { + __o->notify_all(); +} + +inline _LIBCPP_DEPRECATED_ATOMIC_SYNC _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void +atomic_flag_notify_all(atomic_flag* __o) _NOEXCEPT { + __o->notify_all(); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_ATOMIC_FLAG_H diff --git a/libcxx/include/__cxx03/__atomic/atomic_init.h b/libcxx/include/__cxx03/__atomic/atomic_init.h new file mode 100644 index 0000000000000000000000000000000000000000..8e86ba31b4ac3ba5d2b9bc982b811d1f97cb1f67 --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/atomic_init.h @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_ATOMIC_INIT_H +#define _LIBCPP___ATOMIC_ATOMIC_INIT_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#define ATOMIC_FLAG_INIT {false} +#define ATOMIC_VAR_INIT(__v) {__v} + +#if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_COMPILER_CLANG_BASED) && !defined(_LIBCPP_DISABLE_DEPRECATION_WARNINGS) +# pragma clang deprecated(ATOMIC_VAR_INIT) +#endif + +#endif // _LIBCPP___ATOMIC_ATOMIC_INIT_H diff --git a/libcxx/include/__cxx03/__atomic/atomic_lock_free.h b/libcxx/include/__cxx03/__atomic/atomic_lock_free.h new file mode 100644 index 0000000000000000000000000000000000000000..0715439db45039131e833d0f4dfc400e8a459b6b --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/atomic_lock_free.h @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_ATOMIC_LOCK_FREE_H +#define _LIBCPP___ATOMIC_ATOMIC_LOCK_FREE_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if defined(__CLANG_ATOMIC_BOOL_LOCK_FREE) +# define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE +# define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE +# ifndef _LIBCPP_HAS_NO_CHAR8_T +# define ATOMIC_CHAR8_T_LOCK_FREE __CLANG_ATOMIC_CHAR8_T_LOCK_FREE +# endif +# define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE +# define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE +# define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE +# define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE +# define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE +# define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE +# define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE +# define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE +#elif defined(__GCC_ATOMIC_BOOL_LOCK_FREE) +# define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE +# define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE +# ifndef _LIBCPP_HAS_NO_CHAR8_T +# define ATOMIC_CHAR8_T_LOCK_FREE __GCC_ATOMIC_CHAR8_T_LOCK_FREE +# endif +# define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE +# define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE +# define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE +# define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE +# define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE +# define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE +# define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE +# define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE +#endif + +#endif // _LIBCPP___ATOMIC_ATOMIC_LOCK_FREE_H diff --git a/libcxx/include/__cxx03/__atomic/atomic_ref.h b/libcxx/include/__cxx03/__atomic/atomic_ref.h new file mode 100644 index 0000000000000000000000000000000000000000..b0180a37ab500c20739240d4f0552c039b7fa3df --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/atomic_ref.h @@ -0,0 +1,378 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Kokkos v. 4.0 +// Copyright (2022) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_ATOMIC_REF_H +#define _LIBCPP___ATOMIC_ATOMIC_REF_H + +#include <__assert> +#include <__atomic/atomic_sync.h> +#include <__atomic/check_memory_order.h> +#include <__atomic/to_gcc_order.h> +#include <__concepts/arithmetic.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__memory/addressof.h> +#include <__type_traits/has_unique_object_representation.h> +#include <__type_traits/is_trivially_copyable.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// These types are required to make __atomic_is_always_lock_free work across GCC and Clang. +// The purpose of this trick is to make sure that we provide an object with the correct alignment +// to __atomic_is_always_lock_free, since that answer depends on the alignment. +template +struct __alignment_checker_type { + alignas(_Alignment) char __data; +}; + +template +struct __get_aligner_instance { + static constexpr __alignment_checker_type<_Alignment> __instance{}; +}; + +template +struct __atomic_ref_base { +private: + _LIBCPP_HIDE_FROM_ABI static _Tp* __clear_padding(_Tp& __val) noexcept { + _Tp* __ptr = std::addressof(__val); +# if __has_builtin(__builtin_clear_padding) + __builtin_clear_padding(__ptr); +# endif + return __ptr; + } + + _LIBCPP_HIDE_FROM_ABI static bool __compare_exchange( + _Tp* __ptr, _Tp* __expected, _Tp* __desired, bool __is_weak, int __success, int __failure) noexcept { + if constexpr ( +# if __has_builtin(__builtin_clear_padding) + has_unique_object_representations_v<_Tp> || floating_point<_Tp> +# else + true // NOLINT(readability-simplify-boolean-expr) +# endif + ) { + return __atomic_compare_exchange(__ptr, __expected, __desired, __is_weak, __success, __failure); + } else { // _Tp has padding bits and __builtin_clear_padding is available + __clear_padding(*__desired); + _Tp __copy = *__expected; + __clear_padding(__copy); + // The algorithm we use here is basically to perform `__atomic_compare_exchange` on the + // values until it has either succeeded, or failed because the value representation of the + // objects involved was different. This is why we loop around __atomic_compare_exchange: + // we basically loop until its failure is caused by the value representation of the objects + // being different, not only their object representation. + while (true) { + _Tp __prev = __copy; + if (__atomic_compare_exchange(__ptr, std::addressof(__copy), __desired, __is_weak, __success, __failure)) { + return true; + } + _Tp __curr = __copy; + if (std::memcmp(__clear_padding(__prev), __clear_padding(__curr), sizeof(_Tp)) != 0) { + // Value representation without padding bits do not compare equal -> + // write the current content of *ptr into *expected + std::memcpy(__expected, std::addressof(__copy), sizeof(_Tp)); + return false; + } + } + } + } + + friend struct __atomic_waitable_traits<__atomic_ref_base<_Tp>>; + + // require types that are 1, 2, 4, 8, or 16 bytes in length to be aligned to at least their size to be potentially + // used lock-free + static constexpr size_t __min_alignment = (sizeof(_Tp) & (sizeof(_Tp) - 1)) || (sizeof(_Tp) > 16) ? 0 : sizeof(_Tp); + +public: + using value_type = _Tp; + + static constexpr size_t required_alignment = alignof(_Tp) > __min_alignment ? alignof(_Tp) : __min_alignment; + + // The __atomic_always_lock_free builtin takes into account the alignment of the pointer if provided, + // so we create a fake pointer with a suitable alignment when querying it. Note that we are guaranteed + // that the pointer is going to be aligned properly at runtime because that is a (checked) precondition + // of atomic_ref's constructor. + static constexpr bool is_always_lock_free = + __atomic_always_lock_free(sizeof(_Tp), &__get_aligner_instance::__instance); + + _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { return __atomic_is_lock_free(sizeof(_Tp), __ptr_); } + + _LIBCPP_HIDE_FROM_ABI void store(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept + _LIBCPP_CHECK_STORE_MEMORY_ORDER(__order) { + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + __order == memory_order::relaxed || __order == memory_order::release || __order == memory_order::seq_cst, + "atomic_ref: memory order argument to atomic store operation is invalid"); + __atomic_store(__ptr_, __clear_padding(__desired), std::__to_gcc_order(__order)); + } + + _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { + store(__desired); + return __desired; + } + + _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __order = memory_order::seq_cst) const noexcept + _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__order) { + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || + __order == memory_order::seq_cst, + "atomic_ref: memory order argument to atomic load operation is invalid"); + alignas(_Tp) byte __mem[sizeof(_Tp)]; + auto* __ret = reinterpret_cast<_Tp*>(__mem); + __atomic_load(__ptr_, __ret, std::__to_gcc_order(__order)); + return *__ret; + } + + _LIBCPP_HIDE_FROM_ABI operator _Tp() const noexcept { return load(); } + + _LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { + alignas(_Tp) byte __mem[sizeof(_Tp)]; + auto* __ret = reinterpret_cast<_Tp*>(__mem); + __atomic_exchange(__ptr_, __clear_padding(__desired), __ret, std::__to_gcc_order(__order)); + return *__ret; + } + + _LIBCPP_HIDE_FROM_ABI bool + compare_exchange_weak(_Tp& __expected, _Tp __desired, memory_order __success, memory_order __failure) const noexcept + _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__success, __failure) { + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + __failure == memory_order::relaxed || __failure == memory_order::consume || + __failure == memory_order::acquire || __failure == memory_order::seq_cst, + "atomic_ref: failure memory order argument to weak atomic compare-and-exchange operation is invalid"); + return __compare_exchange( + __ptr_, + std::addressof(__expected), + std::addressof(__desired), + true, + std::__to_gcc_order(__success), + std::__to_gcc_order(__failure)); + } + _LIBCPP_HIDE_FROM_ABI bool + compare_exchange_strong(_Tp& __expected, _Tp __desired, memory_order __success, memory_order __failure) const noexcept + _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__success, __failure) { + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + __failure == memory_order::relaxed || __failure == memory_order::consume || + __failure == memory_order::acquire || __failure == memory_order::seq_cst, + "atomic_ref: failure memory order argument to strong atomic compare-and-exchange operation is invalid"); + return __compare_exchange( + __ptr_, + std::addressof(__expected), + std::addressof(__desired), + false, + std::__to_gcc_order(__success), + std::__to_gcc_order(__failure)); + } + + _LIBCPP_HIDE_FROM_ABI bool + compare_exchange_weak(_Tp& __expected, _Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { + return __compare_exchange( + __ptr_, + std::addressof(__expected), + std::addressof(__desired), + true, + std::__to_gcc_order(__order), + std::__to_gcc_failure_order(__order)); + } + _LIBCPP_HIDE_FROM_ABI bool + compare_exchange_strong(_Tp& __expected, _Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept { + return __compare_exchange( + __ptr_, + std::addressof(__expected), + std::addressof(__desired), + false, + std::__to_gcc_order(__order), + std::__to_gcc_failure_order(__order)); + } + + _LIBCPP_HIDE_FROM_ABI void wait(_Tp __old, memory_order __order = memory_order::seq_cst) const noexcept + _LIBCPP_CHECK_WAIT_MEMORY_ORDER(__order) { + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || + __order == memory_order::seq_cst, + "atomic_ref: memory order argument to atomic wait operation is invalid"); + std::__atomic_wait(*this, __old, __order); + } + _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { std::__atomic_notify_one(*this); } + _LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { std::__atomic_notify_all(*this); } + +protected: + typedef _Tp _Aligned_Tp __attribute__((aligned(required_alignment))); + _Aligned_Tp* __ptr_; + + _LIBCPP_HIDE_FROM_ABI __atomic_ref_base(_Tp& __obj) : __ptr_(std::addressof(__obj)) {} +}; + +template +struct __atomic_waitable_traits<__atomic_ref_base<_Tp>> { + static _LIBCPP_HIDE_FROM_ABI _Tp __atomic_load(const __atomic_ref_base<_Tp>& __a, memory_order __order) { + return __a.load(__order); + } + static _LIBCPP_HIDE_FROM_ABI const _Tp* __atomic_contention_address(const __atomic_ref_base<_Tp>& __a) { + return __a.__ptr_; + } +}; + +template +struct atomic_ref : public __atomic_ref_base<_Tp> { + static_assert(is_trivially_copyable_v<_Tp>, "std::atomic_ref requires that 'T' be a trivially copyable type"); + + using __base = __atomic_ref_base<_Tp>; + + _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + reinterpret_cast(std::addressof(__obj)) % __base::required_alignment == 0, + "atomic_ref ctor: referenced object must be aligned to required_alignment"); + } + + _LIBCPP_HIDE_FROM_ABI atomic_ref(const atomic_ref&) noexcept = default; + + _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { return __base::operator=(__desired); } + + atomic_ref& operator=(const atomic_ref&) = delete; +}; + +template + requires(std::integral<_Tp> && !std::same_as) +struct atomic_ref<_Tp> : public __atomic_ref_base<_Tp> { + using __base = __atomic_ref_base<_Tp>; + + using difference_type = __base::value_type; + + _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + reinterpret_cast(std::addressof(__obj)) % __base::required_alignment == 0, + "atomic_ref ctor: referenced object must be aligned to required_alignment"); + } + + _LIBCPP_HIDE_FROM_ABI atomic_ref(const atomic_ref&) noexcept = default; + + _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { return __base::operator=(__desired); } + + atomic_ref& operator=(const atomic_ref&) = delete; + + _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __atomic_fetch_add(this->__ptr_, __arg, std::__to_gcc_order(__order)); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __atomic_fetch_sub(this->__ptr_, __arg, std::__to_gcc_order(__order)); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_and(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __atomic_fetch_and(this->__ptr_, __arg, std::__to_gcc_order(__order)); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_or(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __atomic_fetch_or(this->__ptr_, __arg, std::__to_gcc_order(__order)); + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_xor(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __atomic_fetch_xor(this->__ptr_, __arg, std::__to_gcc_order(__order)); + } + + _LIBCPP_HIDE_FROM_ABI _Tp operator++(int) const noexcept { return fetch_add(_Tp(1)); } + _LIBCPP_HIDE_FROM_ABI _Tp operator--(int) const noexcept { return fetch_sub(_Tp(1)); } + _LIBCPP_HIDE_FROM_ABI _Tp operator++() const noexcept { return fetch_add(_Tp(1)) + _Tp(1); } + _LIBCPP_HIDE_FROM_ABI _Tp operator--() const noexcept { return fetch_sub(_Tp(1)) - _Tp(1); } + _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __arg) const noexcept { return fetch_add(__arg) + __arg; } + _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __arg) const noexcept { return fetch_sub(__arg) - __arg; } + _LIBCPP_HIDE_FROM_ABI _Tp operator&=(_Tp __arg) const noexcept { return fetch_and(__arg) & __arg; } + _LIBCPP_HIDE_FROM_ABI _Tp operator|=(_Tp __arg) const noexcept { return fetch_or(__arg) | __arg; } + _LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __arg) const noexcept { return fetch_xor(__arg) ^ __arg; } +}; + +template + requires std::floating_point<_Tp> +struct atomic_ref<_Tp> : public __atomic_ref_base<_Tp> { + using __base = __atomic_ref_base<_Tp>; + + using difference_type = __base::value_type; + + _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp& __obj) : __base(__obj) { + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + reinterpret_cast(std::addressof(__obj)) % __base::required_alignment == 0, + "atomic_ref ctor: referenced object must be aligned to required_alignment"); + } + + _LIBCPP_HIDE_FROM_ABI atomic_ref(const atomic_ref&) noexcept = default; + + _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __desired) const noexcept { return __base::operator=(__desired); } + + atomic_ref& operator=(const atomic_ref&) = delete; + + _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { + _Tp __old = this->load(memory_order_relaxed); + _Tp __new = __old + __arg; + while (!this->compare_exchange_weak(__old, __new, __order, memory_order_relaxed)) { + __new = __old + __arg; + } + return __old; + } + _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { + _Tp __old = this->load(memory_order_relaxed); + _Tp __new = __old - __arg; + while (!this->compare_exchange_weak(__old, __new, __order, memory_order_relaxed)) { + __new = __old - __arg; + } + return __old; + } + + _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __arg) const noexcept { return fetch_add(__arg) + __arg; } + _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __arg) const noexcept { return fetch_sub(__arg) - __arg; } +}; + +template +struct atomic_ref<_Tp*> : public __atomic_ref_base<_Tp*> { + using __base = __atomic_ref_base<_Tp*>; + + using difference_type = ptrdiff_t; + + _LIBCPP_HIDE_FROM_ABI explicit atomic_ref(_Tp*& __ptr) : __base(__ptr) {} + + _LIBCPP_HIDE_FROM_ABI _Tp* operator=(_Tp* __desired) const noexcept { return __base::operator=(__desired); } + + atomic_ref& operator=(const atomic_ref&) = delete; + + _LIBCPP_HIDE_FROM_ABI _Tp* fetch_add(ptrdiff_t __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __atomic_fetch_add(this->__ptr_, __arg * sizeof(_Tp), std::__to_gcc_order(__order)); + } + _LIBCPP_HIDE_FROM_ABI _Tp* fetch_sub(ptrdiff_t __arg, memory_order __order = memory_order_seq_cst) const noexcept { + return __atomic_fetch_sub(this->__ptr_, __arg * sizeof(_Tp), std::__to_gcc_order(__order)); + } + + _LIBCPP_HIDE_FROM_ABI _Tp* operator++(int) const noexcept { return fetch_add(1); } + _LIBCPP_HIDE_FROM_ABI _Tp* operator--(int) const noexcept { return fetch_sub(1); } + _LIBCPP_HIDE_FROM_ABI _Tp* operator++() const noexcept { return fetch_add(1) + 1; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator--() const noexcept { return fetch_sub(1) - 1; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator+=(ptrdiff_t __arg) const noexcept { return fetch_add(__arg) + __arg; } + _LIBCPP_HIDE_FROM_ABI _Tp* operator-=(ptrdiff_t __arg) const noexcept { return fetch_sub(__arg) - __arg; } +}; + +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(atomic_ref); + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP__ATOMIC_ATOMIC_REF_H diff --git a/libcxx/include/__cxx03/__atomic/atomic_sync.h b/libcxx/include/__cxx03/__atomic/atomic_sync.h new file mode 100644 index 0000000000000000000000000000000000000000..aaf81f58731a987882ff36f6189c3ed9bb359a35 --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/atomic_sync.h @@ -0,0 +1,205 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_ATOMIC_SYNC_H +#define _LIBCPP___ATOMIC_ATOMIC_SYNC_H + +#include <__atomic/contention_t.h> +#include <__atomic/cxx_atomic_impl.h> +#include <__atomic/memory_order.h> +#include <__atomic/to_gcc_order.h> +#include <__chrono/duration.h> +#include <__config> +#include <__memory/addressof.h> +#include <__thread/poll_with_backoff.h> +#include <__thread/support.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/decay.h> +#include <__type_traits/invoke.h> +#include <__type_traits/void_t.h> +#include <__utility/declval.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// The customisation points to enable the following functions: +// - __atomic_wait +// - __atomic_wait_unless +// - __atomic_notify_one +// - __atomic_notify_all +// Note that std::atomic::wait was back-ported to C++03 +// The below implementations look ugly to support C++03 +template +struct __atomic_waitable_traits { + template + static void __atomic_load(_AtomicWaitable&&, memory_order) = delete; + + template + static void __atomic_contention_address(_AtomicWaitable&&) = delete; +}; + +template +struct __atomic_waitable : false_type {}; + +template +struct __atomic_waitable< _Tp, + __void_t >::__atomic_load( + std::declval(), std::declval())), + decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_contention_address( + std::declval()))> > : true_type {}; + +template +struct __atomic_wait_poll_impl { + const _AtomicWaitable& __a_; + _Poll __poll_; + memory_order __order_; + + _LIBCPP_HIDE_FROM_ABI bool operator()() const { + auto __current_val = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_load(__a_, __order_); + return __poll_(__current_val); + } +}; + +#ifndef _LIBCPP_HAS_NO_THREADS + +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile*) _NOEXCEPT; +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(void const volatile*) _NOEXCEPT; +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t +__libcpp_atomic_monitor(void const volatile*) _NOEXCEPT; +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void +__libcpp_atomic_wait(void const volatile*, __cxx_contention_t) _NOEXCEPT; + +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void +__cxx_atomic_notify_one(__cxx_atomic_contention_t const volatile*) _NOEXCEPT; +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void +__cxx_atomic_notify_all(__cxx_atomic_contention_t const volatile*) _NOEXCEPT; +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t +__libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile*) _NOEXCEPT; +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void +__libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention_t) _NOEXCEPT; + +template +struct __atomic_wait_backoff_impl { + const _AtomicWaitable& __a_; + _Poll __poll_; + memory_order __order_; + + using __waitable_traits = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >; + + _LIBCPP_AVAILABILITY_SYNC + _LIBCPP_HIDE_FROM_ABI bool + __update_monitor_val_and_poll(__cxx_atomic_contention_t const volatile*, __cxx_contention_t& __monitor_val) const { + // In case the contention type happens to be __cxx_atomic_contention_t, i.e. __cxx_atomic_impl, + // the platform wait is directly monitoring the atomic value itself. + // `__poll_` takes the current value of the atomic as an in-out argument + // to potentially modify it. After it returns, `__monitor` has a value + // which can be safely waited on by `std::__libcpp_atomic_wait` without any + // ABA style issues. + __monitor_val = __waitable_traits::__atomic_load(__a_, __order_); + return __poll_(__monitor_val); + } + + _LIBCPP_AVAILABILITY_SYNC + _LIBCPP_HIDE_FROM_ABI bool + __update_monitor_val_and_poll(void const volatile* __contention_address, __cxx_contention_t& __monitor_val) const { + // In case the contention type is anything else, platform wait is monitoring a __cxx_atomic_contention_t + // from the global pool, the monitor comes from __libcpp_atomic_monitor + __monitor_val = std::__libcpp_atomic_monitor(__contention_address); + auto __current_val = __waitable_traits::__atomic_load(__a_, __order_); + return __poll_(__current_val); + } + + _LIBCPP_AVAILABILITY_SYNC + _LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const { + if (__elapsed > chrono::microseconds(64)) { + auto __contention_address = __waitable_traits::__atomic_contention_address(__a_); + __cxx_contention_t __monitor_val; + if (__update_monitor_val_and_poll(__contention_address, __monitor_val)) + return true; + std::__libcpp_atomic_wait(__contention_address, __monitor_val); + } else if (__elapsed > chrono::microseconds(4)) + __libcpp_thread_yield(); + else { + } // poll + return false; + } +}; + +// The semantics of this function are similar to `atomic`'s +// `.wait(T old, std::memory_order order)`, but instead of having a hardcoded +// predicate (is the loaded value unequal to `old`?), the predicate function is +// specified as an argument. The loaded value is given as an in-out argument to +// the predicate. If the predicate function returns `true`, +// `__atomic_wait_unless` will return. If the predicate function returns +// `false`, it must set the argument to its current understanding of the atomic +// value. The predicate function must not return `false` spuriously. +template +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void +__atomic_wait_unless(const _AtomicWaitable& __a, _Poll&& __poll, memory_order __order) { + static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); + __atomic_wait_poll_impl<_AtomicWaitable, __decay_t<_Poll> > __poll_impl = {__a, __poll, __order}; + __atomic_wait_backoff_impl<_AtomicWaitable, __decay_t<_Poll> > __backoff_fn = {__a, __poll, __order}; + std::__libcpp_thread_poll_with_backoff(__poll_impl, __backoff_fn); +} + +template +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) { + static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); + std::__cxx_atomic_notify_one(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a)); +} + +template +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) { + static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); + std::__cxx_atomic_notify_all(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a)); +} + +#else // _LIBCPP_HAS_NO_THREADS + +template +_LIBCPP_HIDE_FROM_ABI void __atomic_wait_unless(const _AtomicWaitable& __a, _Poll&& __poll, memory_order __order) { + __atomic_wait_poll_impl<_AtomicWaitable, __decay_t<_Poll> > __poll_fn = {__a, __poll, __order}; + std::__libcpp_thread_poll_with_backoff(__poll_fn, __spinning_backoff_policy()); +} + +template +_LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable&) {} + +template +_LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable&) {} + +#endif // _LIBCPP_HAS_NO_THREADS + +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_nonatomic_compare_equal(_Tp const& __lhs, _Tp const& __rhs) { + return std::memcmp(std::addressof(__lhs), std::addressof(__rhs), sizeof(_Tp)) == 0; +} + +template +struct __atomic_compare_unequal_to { + _Tp __val_; + _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __arg) const { + return !std::__cxx_nonatomic_compare_equal(__arg, __val_); + } +}; + +template +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void +__atomic_wait(_AtomicWaitable& __a, _Up __val, memory_order __order) { + static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); + __atomic_compare_unequal_to<_Up> __nonatomic_equal = {__val}; + std::__atomic_wait_unless(__a, __nonatomic_equal, __order); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_ATOMIC_SYNC_H diff --git a/libcxx/include/__cxx03/__atomic/check_memory_order.h b/libcxx/include/__cxx03/__atomic/check_memory_order.h new file mode 100644 index 0000000000000000000000000000000000000000..536f764a619026c34363d8588d7570703e2e2a34 --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/check_memory_order.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_CHECK_MEMORY_ORDER_H +#define _LIBCPP___ATOMIC_CHECK_MEMORY_ORDER_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#define _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) \ + _LIBCPP_DIAGNOSE_WARNING(__m == memory_order_consume || __m == memory_order_acquire || __m == memory_order_acq_rel, \ + "memory order argument to atomic operation is invalid") + +#define _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) \ + _LIBCPP_DIAGNOSE_WARNING(__m == memory_order_release || __m == memory_order_acq_rel, \ + "memory order argument to atomic operation is invalid") + +#define _LIBCPP_CHECK_EXCHANGE_MEMORY_ORDER(__m, __f) \ + _LIBCPP_DIAGNOSE_WARNING(__f == memory_order_release || __f == memory_order_acq_rel, \ + "memory order argument to atomic operation is invalid") + +#define _LIBCPP_CHECK_WAIT_MEMORY_ORDER(__m) \ + _LIBCPP_DIAGNOSE_WARNING(__m == memory_order_release || __m == memory_order_acq_rel, \ + "memory order argument to atomic operation is invalid") + +#endif // _LIBCPP___ATOMIC_CHECK_MEMORY_ORDER_H diff --git a/libcxx/include/__cxx03/__atomic/contention_t.h b/libcxx/include/__cxx03/__atomic/contention_t.h new file mode 100644 index 0000000000000000000000000000000000000000..65890f338ce990fdb276642a3706c162c120f7f4 --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/contention_t.h @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_CONTENTION_T_H +#define _LIBCPP___ATOMIC_CONTENTION_T_H + +#include <__atomic/cxx_atomic_impl.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if defined(__linux__) || (defined(_AIX) && !defined(__64BIT__)) +using __cxx_contention_t = int32_t; +#else +using __cxx_contention_t = int64_t; +#endif // __linux__ || (_AIX && !__64BIT__) + +using __cxx_atomic_contention_t = __cxx_atomic_impl<__cxx_contention_t>; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_CONTENTION_T_H diff --git a/libcxx/include/__cxx03/__atomic/cxx_atomic_impl.h b/libcxx/include/__cxx03/__atomic/cxx_atomic_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..18e88aa97bec755dc3396bd84eff693b7954122f --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/cxx_atomic_impl.h @@ -0,0 +1,510 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_CXX_ATOMIC_IMPL_H +#define _LIBCPP___ATOMIC_CXX_ATOMIC_IMPL_H + +#include <__atomic/memory_order.h> +#include <__atomic/to_gcc_order.h> +#include <__config> +#include <__memory/addressof.h> +#include <__type_traits/is_assignable.h> +#include <__type_traits/is_trivially_copyable.h> +#include <__type_traits/remove_const.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if defined(_LIBCPP_HAS_GCC_ATOMIC_IMP) + +// [atomics.types.generic]p1 guarantees _Tp is trivially copyable. Because +// the default operator= in an object is not volatile, a byte-by-byte copy +// is required. +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_assign_volatile(_Tp& __a_value, _Tv const& __val) { + __a_value = __val; +} +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_assign_volatile(_Tp volatile& __a_value, _Tv volatile const& __val) { + volatile char* __to = reinterpret_cast(std::addressof(__a_value)); + volatile char* __end = __to + sizeof(_Tp); + volatile const char* __from = reinterpret_cast(std::addressof(__val)); + while (__to != __end) + *__to++ = *__from++; +} + +template +struct __cxx_atomic_base_impl { + _LIBCPP_HIDE_FROM_ABI +# ifndef _LIBCPP_CXX03_LANG + __cxx_atomic_base_impl() _NOEXCEPT = default; +# else + __cxx_atomic_base_impl() _NOEXCEPT : __a_value() { + } +# endif // _LIBCPP_CXX03_LANG + _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp value) _NOEXCEPT : __a_value(value) {} + _Tp __a_value; +}; + +template +_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val) { + __cxx_atomic_assign_volatile(__a->__a_value, __val); +} + +template +_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val) { + __a->__a_value = __val; +} + +_LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_thread_fence(memory_order __order) { + __atomic_thread_fence(__to_gcc_order(__order)); +} + +_LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_signal_fence(memory_order __order) { + __atomic_signal_fence(__to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_store(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) { + __atomic_store(std::addressof(__a->__a_value), std::addressof(__val), __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_store(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) { + __atomic_store(std::addressof(__a->__a_value), std::addressof(__val), __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_load(const volatile __cxx_atomic_base_impl<_Tp>* __a, memory_order __order) { + _Tp __ret; + __atomic_load(std::addressof(__a->__a_value), std::addressof(__ret), __to_gcc_order(__order)); + return __ret; +} + +template +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_load_inplace(const volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp* __dst, memory_order __order) { + __atomic_load(std::addressof(__a->__a_value), __dst, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_load_inplace(const __cxx_atomic_base_impl<_Tp>* __a, _Tp* __dst, memory_order __order) { + __atomic_load(std::addressof(__a->__a_value), __dst, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_load(const __cxx_atomic_base_impl<_Tp>* __a, memory_order __order) { + _Tp __ret; + __atomic_load(std::addressof(__a->__a_value), std::addressof(__ret), __to_gcc_order(__order)); + return __ret; +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_exchange(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) { + _Tp __ret; + __atomic_exchange( + std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), __to_gcc_order(__order)); + return __ret; +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) { + _Tp __ret; + __atomic_exchange( + std::addressof(__a->__a_value), std::addressof(__value), std::addressof(__ret), __to_gcc_order(__order)); + return __ret; +} + +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong( + volatile __cxx_atomic_base_impl<_Tp>* __a, + _Tp* __expected, + _Tp __value, + memory_order __success, + memory_order __failure) { + return __atomic_compare_exchange( + std::addressof(__a->__a_value), + __expected, + std::addressof(__value), + false, + __to_gcc_order(__success), + __to_gcc_failure_order(__failure)); +} + +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong( + __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) { + return __atomic_compare_exchange( + std::addressof(__a->__a_value), + __expected, + std::addressof(__value), + false, + __to_gcc_order(__success), + __to_gcc_failure_order(__failure)); +} + +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak( + volatile __cxx_atomic_base_impl<_Tp>* __a, + _Tp* __expected, + _Tp __value, + memory_order __success, + memory_order __failure) { + return __atomic_compare_exchange( + std::addressof(__a->__a_value), + __expected, + std::addressof(__value), + true, + __to_gcc_order(__success), + __to_gcc_failure_order(__failure)); +} + +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak( + __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) { + return __atomic_compare_exchange( + std::addressof(__a->__a_value), + __expected, + std::addressof(__value), + true, + __to_gcc_order(__success), + __to_gcc_failure_order(__failure)); +} + +template +struct __skip_amt { + enum { value = 1 }; +}; + +template +struct __skip_amt<_Tp*> { + enum { value = sizeof(_Tp) }; +}; + +// FIXME: Haven't figured out what the spec says about using arrays with +// atomic_fetch_add. Force a failure rather than creating bad behavior. +template +struct __skip_amt<_Tp[]> {}; +template +struct __skip_amt<_Tp[n]> {}; + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_add(volatile __cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) { + return __atomic_fetch_add(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) { + return __atomic_fetch_add(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_sub(volatile __cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) { + return __atomic_fetch_sub(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp>* __a, _Td __delta, memory_order __order) { + return __atomic_fetch_sub(std::addressof(__a->__a_value), __delta * __skip_amt<_Tp>::value, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_and(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { + return __atomic_fetch_and(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_and(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { + return __atomic_fetch_and(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_or(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { + return __atomic_fetch_or(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_fetch_or(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { + return __atomic_fetch_or(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_xor(volatile __cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { + return __atomic_fetch_xor(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_xor(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) { + return __atomic_fetch_xor(std::addressof(__a->__a_value), __pattern, __to_gcc_order(__order)); +} + +# define __cxx_atomic_is_lock_free(__s) __atomic_is_lock_free(__s, 0) + +#elif defined(_LIBCPP_HAS_C_ATOMIC_IMP) + +template +struct __cxx_atomic_base_impl { + _LIBCPP_HIDE_FROM_ABI +# ifndef _LIBCPP_CXX03_LANG + __cxx_atomic_base_impl() _NOEXCEPT = default; +# else + __cxx_atomic_base_impl() _NOEXCEPT : __a_value() { + } +# endif // _LIBCPP_CXX03_LANG + _LIBCPP_CONSTEXPR explicit __cxx_atomic_base_impl(_Tp __value) _NOEXCEPT : __a_value(__value) {} + _LIBCPP_DISABLE_EXTENSION_WARNING _Atomic(_Tp) __a_value; +}; + +# define __cxx_atomic_is_lock_free(__s) __c11_atomic_is_lock_free(__s) + +_LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_thread_fence(memory_order __order) _NOEXCEPT { + __c11_atomic_thread_fence(static_cast<__memory_order_underlying_t>(__order)); +} + +_LIBCPP_HIDE_FROM_ABI inline void __cxx_atomic_signal_fence(memory_order __order) _NOEXCEPT { + __c11_atomic_signal_fence(static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __val) _NOEXCEPT { + __c11_atomic_init(std::addressof(__a->__a_value), __val); +} +template +_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_init(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val) _NOEXCEPT { + __c11_atomic_init(std::addressof(__a->__a_value), __val); +} + +template +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_store(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __val, memory_order __order) _NOEXCEPT { + __c11_atomic_store(std::addressof(__a->__a_value), __val, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_store(__cxx_atomic_base_impl<_Tp>* __a, _Tp __val, memory_order __order) _NOEXCEPT { + __c11_atomic_store(std::addressof(__a->__a_value), __val, static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_load(__cxx_atomic_base_impl<_Tp> const volatile* __a, memory_order __order) _NOEXCEPT { + using __ptr_type = __remove_const_t__a_value)>*; + return __c11_atomic_load( + const_cast<__ptr_type>(std::addressof(__a->__a_value)), static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp __cxx_atomic_load(__cxx_atomic_base_impl<_Tp> const* __a, memory_order __order) _NOEXCEPT { + using __ptr_type = __remove_const_t__a_value)>*; + return __c11_atomic_load( + const_cast<__ptr_type>(std::addressof(__a->__a_value)), static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_load_inplace(__cxx_atomic_base_impl<_Tp> const volatile* __a, _Tp* __dst, memory_order __order) _NOEXCEPT { + using __ptr_type = __remove_const_t__a_value)>*; + *__dst = __c11_atomic_load( + const_cast<__ptr_type>(std::addressof(__a->__a_value)), static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI void +__cxx_atomic_load_inplace(__cxx_atomic_base_impl<_Tp> const* __a, _Tp* __dst, memory_order __order) _NOEXCEPT { + using __ptr_type = __remove_const_t__a_value)>*; + *__dst = __c11_atomic_load( + const_cast<__ptr_type>(std::addressof(__a->__a_value)), static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __value, memory_order __order) _NOEXCEPT { + return __c11_atomic_exchange( + std::addressof(__a->__a_value), __value, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_exchange(__cxx_atomic_base_impl<_Tp>* __a, _Tp __value, memory_order __order) _NOEXCEPT { + return __c11_atomic_exchange( + std::addressof(__a->__a_value), __value, static_cast<__memory_order_underlying_t>(__order)); +} + +_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR memory_order __to_failure_order(memory_order __order) { + // Avoid switch statement to make this a constexpr. + return __order == memory_order_release + ? memory_order_relaxed + : (__order == memory_order_acq_rel ? memory_order_acquire : __order); +} + +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong( + __cxx_atomic_base_impl<_Tp> volatile* __a, + _Tp* __expected, + _Tp __value, + memory_order __success, + memory_order __failure) _NOEXCEPT { + return __c11_atomic_compare_exchange_strong( + std::addressof(__a->__a_value), + __expected, + __value, + static_cast<__memory_order_underlying_t>(__success), + static_cast<__memory_order_underlying_t>(__to_failure_order(__failure))); +} +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_strong( + __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) + _NOEXCEPT { + return __c11_atomic_compare_exchange_strong( + std::addressof(__a->__a_value), + __expected, + __value, + static_cast<__memory_order_underlying_t>(__success), + static_cast<__memory_order_underlying_t>(__to_failure_order(__failure))); +} + +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak( + __cxx_atomic_base_impl<_Tp> volatile* __a, + _Tp* __expected, + _Tp __value, + memory_order __success, + memory_order __failure) _NOEXCEPT { + return __c11_atomic_compare_exchange_weak( + std::addressof(__a->__a_value), + __expected, + __value, + static_cast<__memory_order_underlying_t>(__success), + static_cast<__memory_order_underlying_t>(__to_failure_order(__failure))); +} +template +_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_compare_exchange_weak( + __cxx_atomic_base_impl<_Tp>* __a, _Tp* __expected, _Tp __value, memory_order __success, memory_order __failure) + _NOEXCEPT { + return __c11_atomic_compare_exchange_weak( + std::addressof(__a->__a_value), + __expected, + __value, + static_cast<__memory_order_underlying_t>(__success), + static_cast<__memory_order_underlying_t>(__to_failure_order(__failure))); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_add( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp>* __a, _Tp __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_add( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp* +__cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp*> volatile* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_add( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp* +__cxx_atomic_fetch_add(__cxx_atomic_base_impl<_Tp*>* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_add( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_sub( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp>* __a, _Tp __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_sub( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp* +__cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp*> volatile* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_sub( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp* +__cxx_atomic_fetch_sub(__cxx_atomic_base_impl<_Tp*>* __a, ptrdiff_t __delta, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_sub( + std::addressof(__a->__a_value), __delta, static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_and(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_and( + std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_and(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_and( + std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_or(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_or( + std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_or(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_or( + std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_xor(__cxx_atomic_base_impl<_Tp> volatile* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_xor( + std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); +} +template +_LIBCPP_HIDE_FROM_ABI _Tp +__cxx_atomic_fetch_xor(__cxx_atomic_base_impl<_Tp>* __a, _Tp __pattern, memory_order __order) _NOEXCEPT { + return __c11_atomic_fetch_xor( + std::addressof(__a->__a_value), __pattern, static_cast<__memory_order_underlying_t>(__order)); +} + +#endif // _LIBCPP_HAS_GCC_ATOMIC_IMP, _LIBCPP_HAS_C_ATOMIC_IMP + +template > +struct __cxx_atomic_impl : public _Base { + static_assert(is_trivially_copyable<_Tp>::value, "std::atomic requires that 'T' be a trivially copyable type"); + + _LIBCPP_HIDE_FROM_ABI __cxx_atomic_impl() _NOEXCEPT = default; + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __cxx_atomic_impl(_Tp __value) _NOEXCEPT : _Base(__value) {} +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_CXX_ATOMIC_IMPL_H diff --git a/libcxx/include/__cxx03/__atomic/fence.h b/libcxx/include/__cxx03/__atomic/fence.h new file mode 100644 index 0000000000000000000000000000000000000000..8c27ea54d62dd0333c8585db856034fbed39cabc --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/fence.h @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_FENCE_H +#define _LIBCPP___ATOMIC_FENCE_H + +#include <__atomic/cxx_atomic_impl.h> +#include <__atomic/memory_order.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +inline _LIBCPP_HIDE_FROM_ABI void atomic_thread_fence(memory_order __m) _NOEXCEPT { __cxx_atomic_thread_fence(__m); } + +inline _LIBCPP_HIDE_FROM_ABI void atomic_signal_fence(memory_order __m) _NOEXCEPT { __cxx_atomic_signal_fence(__m); } + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_FENCE_H diff --git a/libcxx/include/__cxx03/__atomic/is_always_lock_free.h b/libcxx/include/__cxx03/__atomic/is_always_lock_free.h new file mode 100644 index 0000000000000000000000000000000000000000..f928e79f70cea3cac8a1482fe9e84b81e6e58a71 --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/is_always_lock_free.h @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_IS_ALWAYS_LOCK_FREE_H +#define _LIBCPP___ATOMIC_IS_ALWAYS_LOCK_FREE_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __libcpp_is_always_lock_free { + // __atomic_always_lock_free is available in all Standard modes + static const bool __value = __atomic_always_lock_free(sizeof(_Tp), nullptr); +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_IS_ALWAYS_LOCK_FREE_H diff --git a/libcxx/include/__cxx03/__atomic/kill_dependency.h b/libcxx/include/__cxx03/__atomic/kill_dependency.h new file mode 100644 index 0000000000000000000000000000000000000000..103d52d35787fefb9d0f8701789fd6d467979074 --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/kill_dependency.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_KILL_DEPENDENCY_H +#define _LIBCPP___ATOMIC_KILL_DEPENDENCY_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _Tp kill_dependency(_Tp __y) _NOEXCEPT { + return __y; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_KILL_DEPENDENCY_H diff --git a/libcxx/include/__cxx03/__atomic/memory_order.h b/libcxx/include/__cxx03/__atomic/memory_order.h new file mode 100644 index 0000000000000000000000000000000000000000..294121d1c4e7f4acfa031b5e6284d72f37ff7926 --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/memory_order.h @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_MEMORY_ORDER_H +#define _LIBCPP___ATOMIC_MEMORY_ORDER_H + +#include <__config> +#include <__type_traits/is_same.h> +#include <__type_traits/underlying_type.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// Figure out what the underlying type for `memory_order` would be if it were +// declared as an unscoped enum (accounting for -fshort-enums). Use this result +// to pin the underlying type in C++20. +enum __legacy_memory_order { __mo_relaxed, __mo_consume, __mo_acquire, __mo_release, __mo_acq_rel, __mo_seq_cst }; + +using __memory_order_underlying_t = underlying_type<__legacy_memory_order>::type; + +#if _LIBCPP_STD_VER >= 20 + +enum class memory_order : __memory_order_underlying_t { + relaxed = __mo_relaxed, + consume = __mo_consume, + acquire = __mo_acquire, + release = __mo_release, + acq_rel = __mo_acq_rel, + seq_cst = __mo_seq_cst +}; + +static_assert(is_same::type, __memory_order_underlying_t>::value, + "unexpected underlying type for std::memory_order"); + +inline constexpr auto memory_order_relaxed = memory_order::relaxed; +inline constexpr auto memory_order_consume = memory_order::consume; +inline constexpr auto memory_order_acquire = memory_order::acquire; +inline constexpr auto memory_order_release = memory_order::release; +inline constexpr auto memory_order_acq_rel = memory_order::acq_rel; +inline constexpr auto memory_order_seq_cst = memory_order::seq_cst; + +#else + +enum memory_order { + memory_order_relaxed = __mo_relaxed, + memory_order_consume = __mo_consume, + memory_order_acquire = __mo_acquire, + memory_order_release = __mo_release, + memory_order_acq_rel = __mo_acq_rel, + memory_order_seq_cst = __mo_seq_cst, +}; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_MEMORY_ORDER_H diff --git a/libcxx/include/__cxx03/__atomic/to_gcc_order.h b/libcxx/include/__cxx03/__atomic/to_gcc_order.h new file mode 100644 index 0000000000000000000000000000000000000000..d04c111addd3143d474eb23844fca6c5c09e88c9 --- /dev/null +++ b/libcxx/include/__cxx03/__atomic/to_gcc_order.h @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_TO_GCC_ORDER_H +#define _LIBCPP___ATOMIC_TO_GCC_ORDER_H + +#include <__atomic/memory_order.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if defined(__ATOMIC_RELAXED) && defined(__ATOMIC_CONSUME) && defined(__ATOMIC_ACQUIRE) && \ + defined(__ATOMIC_RELEASE) && defined(__ATOMIC_ACQ_REL) && defined(__ATOMIC_SEQ_CST) + +_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR int __to_gcc_order(memory_order __order) { + // Avoid switch statement to make this a constexpr. + return __order == memory_order_relaxed + ? __ATOMIC_RELAXED + : (__order == memory_order_acquire + ? __ATOMIC_ACQUIRE + : (__order == memory_order_release + ? __ATOMIC_RELEASE + : (__order == memory_order_seq_cst + ? __ATOMIC_SEQ_CST + : (__order == memory_order_acq_rel ? __ATOMIC_ACQ_REL : __ATOMIC_CONSUME)))); +} + +_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR int __to_gcc_failure_order(memory_order __order) { + // Avoid switch statement to make this a constexpr. + return __order == memory_order_relaxed + ? __ATOMIC_RELAXED + : (__order == memory_order_acquire + ? __ATOMIC_ACQUIRE + : (__order == memory_order_release + ? __ATOMIC_RELAXED + : (__order == memory_order_seq_cst + ? __ATOMIC_SEQ_CST + : (__order == memory_order_acq_rel ? __ATOMIC_ACQUIRE : __ATOMIC_CONSUME)))); +} + +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_TO_GCC_ORDER_H diff --git a/libcxx/include/__cxx03/__bit/bit_cast.h b/libcxx/include/__cxx03/__bit/bit_cast.h new file mode 100644 index 0000000000000000000000000000000000000000..cd0456738179326923610cac599e8ed53ebe07a3 --- /dev/null +++ b/libcxx/include/__cxx03/__bit/bit_cast.h @@ -0,0 +1,44 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___BIT_BIT_CAST_H +#define _LIBCPP___BIT_BIT_CAST_H + +#include <__config> +#include <__type_traits/is_trivially_copyable.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#ifndef _LIBCPP_CXX03_LANG + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI constexpr _ToType __bit_cast(const _FromType& __from) noexcept { + return __builtin_bit_cast(_ToType, __from); +} + +#endif // _LIBCPP_CXX03_LANG + +#if _LIBCPP_STD_VER >= 20 + +template + requires(sizeof(_ToType) == sizeof(_FromType) && is_trivially_copyable_v<_ToType> && + is_trivially_copyable_v<_FromType>) +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _ToType bit_cast(const _FromType& __from) noexcept { + return __builtin_bit_cast(_ToType, __from); +} + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___BIT_BIT_CAST_H diff --git a/libcxx/include/__cxx03/__bit/bit_ceil.h b/libcxx/include/__cxx03/__bit/bit_ceil.h new file mode 100644 index 0000000000000000000000000000000000000000..cfd792dc2e2adbd04f0a1dc2177e06ec6d30e146 --- /dev/null +++ b/libcxx/include/__cxx03/__bit/bit_ceil.h @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___BIT_BIT_CEIL_H +#define _LIBCPP___BIT_BIT_CEIL_H + +#include <__assert> +#include <__bit/countl.h> +#include <__concepts/arithmetic.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp __bit_ceil(_Tp __t) noexcept { + if (__t < 2) + return 1; + const unsigned __n = numeric_limits<_Tp>::digits - std::__countl_zero((_Tp)(__t - 1u)); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__n != numeric_limits<_Tp>::digits, "Bad input to bit_ceil"); + + if constexpr (sizeof(_Tp) >= sizeof(unsigned)) + return _Tp{1} << __n; + else { + const unsigned __extra = numeric_limits::digits - numeric_limits<_Tp>::digits; + const unsigned __ret_val = 1u << (__n + __extra); + return (_Tp)(__ret_val >> __extra); + } +} + +# if _LIBCPP_STD_VER >= 20 + +template <__libcpp_unsigned_integer _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp bit_ceil(_Tp __t) noexcept { + return std::__bit_ceil(__t); +} + +# endif // _LIBCPP_STD_VER >= 20 +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___BIT_BIT_CEIL_H diff --git a/libcxx/include/__cxx03/__bit/bit_floor.h b/libcxx/include/__cxx03/__bit/bit_floor.h new file mode 100644 index 0000000000000000000000000000000000000000..133e369504e431c137505bf48affd394eb2c5bdb --- /dev/null +++ b/libcxx/include/__cxx03/__bit/bit_floor.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___BIT_BIT_FLOOR_H +#define _LIBCPP___BIT_BIT_FLOOR_H + +#include <__bit/bit_log2.h> +#include <__concepts/arithmetic.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template <__libcpp_unsigned_integer _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp bit_floor(_Tp __t) noexcept { + return __t == 0 ? 0 : _Tp{1} << std::__bit_log2(__t); +} + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___BIT_BIT_FLOOR_H diff --git a/libcxx/include/__cxx03/__bit/bit_log2.h b/libcxx/include/__cxx03/__bit/bit_log2.h new file mode 100644 index 0000000000000000000000000000000000000000..62936f6786860032510fad83eb5b4a5ef9eaf45b --- /dev/null +++ b/libcxx/include/__cxx03/__bit/bit_log2.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___BIT_BIT_LOG2_H +#define _LIBCPP___BIT_BIT_LOG2_H + +#include <__bit/countl.h> +#include <__concepts/arithmetic.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template <__libcpp_unsigned_integer _Tp> +_LIBCPP_HIDE_FROM_ABI constexpr _Tp __bit_log2(_Tp __t) noexcept { + return numeric_limits<_Tp>::digits - 1 - std::countl_zero(__t); +} + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___BIT_BIT_LOG2_H diff --git a/libcxx/include/__cxx03/__bit/bit_width.h b/libcxx/include/__cxx03/__bit/bit_width.h new file mode 100644 index 0000000000000000000000000000000000000000..853e481776f7d2d2e705a978fa26ce5365072896 --- /dev/null +++ b/libcxx/include/__cxx03/__bit/bit_width.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___BIT_BIT_WIDTH_H +#define _LIBCPP___BIT_BIT_WIDTH_H + +#include <__bit/bit_log2.h> +#include <__concepts/arithmetic.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template <__libcpp_unsigned_integer _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int bit_width(_Tp __t) noexcept { + return __t == 0 ? 0 : std::__bit_log2(__t) + 1; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___BIT_BIT_WIDTH_H diff --git a/libcxx/include/__cxx03/__bit/blsr.h b/libcxx/include/__cxx03/__bit/blsr.h new file mode 100644 index 0000000000000000000000000000000000000000..76bd521f5c3071158f1b929ca88ef1455505d937 --- /dev/null +++ b/libcxx/include/__cxx03/__bit/blsr.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___BIT_BLSR_H +#define _LIBCPP___BIT_BLSR_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unsigned __libcpp_blsr(unsigned __x) _NOEXCEPT { + return __x ^ (__x & -__x); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unsigned long __libcpp_blsr(unsigned long __x) _NOEXCEPT { + return __x ^ (__x & -__x); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unsigned long long __libcpp_blsr(unsigned long long __x) _NOEXCEPT { + return __x ^ (__x & -__x); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___BIT_BLSR_H diff --git a/libcxx/include/__cxx03/__bit/byteswap.h b/libcxx/include/__cxx03/__bit/byteswap.h new file mode 100644 index 0000000000000000000000000000000000000000..6225ecf2f92dfb4fff1146e73a7272ccf2af7e1d --- /dev/null +++ b/libcxx/include/__cxx03/__bit/byteswap.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___BIT_BYTESWAP_H +#define _LIBCPP___BIT_BYTESWAP_H + +#include <__concepts/arithmetic.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp byteswap(_Tp __val) noexcept { + if constexpr (sizeof(_Tp) == 1) { + return __val; + } else if constexpr (sizeof(_Tp) == 2) { + return __builtin_bswap16(__val); + } else if constexpr (sizeof(_Tp) == 4) { + return __builtin_bswap32(__val); + } else if constexpr (sizeof(_Tp) == 8) { + return __builtin_bswap64(__val); +# ifndef _LIBCPP_HAS_NO_INT128 + } else if constexpr (sizeof(_Tp) == 16) { +# if __has_builtin(__builtin_bswap128) + return __builtin_bswap128(__val); +# else + return static_cast<_Tp>(byteswap(static_cast(__val))) << 64 | + static_cast<_Tp>(byteswap(static_cast(__val >> 64))); +# endif // __has_builtin(__builtin_bswap128) +# endif // _LIBCPP_HAS_NO_INT128 + } else { + static_assert(sizeof(_Tp) == 0, "byteswap is unimplemented for integral types of this size"); + } +} + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___BIT_BYTESWAP_H diff --git a/libcxx/include/__cxx03/__bit/countl.h b/libcxx/include/__cxx03/__bit/countl.h new file mode 100644 index 0000000000000000000000000000000000000000..998a0b44c19dcb90fa4614fe309cadb19a9e1eb6 --- /dev/null +++ b/libcxx/include/__cxx03/__bit/countl.h @@ -0,0 +1,113 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// TODO: __builtin_clzg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can +// refactor this code to exclusively use __builtin_clzg. + +#ifndef _LIBCPP___BIT_COUNTL_H +#define _LIBCPP___BIT_COUNTL_H + +#include <__bit/rotate.h> +#include <__concepts/arithmetic.h> +#include <__config> +#include <__type_traits/is_unsigned_integer.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(unsigned __x) _NOEXCEPT { + return __builtin_clz(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(unsigned long __x) _NOEXCEPT { + return __builtin_clzl(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(unsigned long long __x) _NOEXCEPT { + return __builtin_clzll(__x); +} + +#ifndef _LIBCPP_HAS_NO_INT128 +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_clz(__uint128_t __x) _NOEXCEPT { +# if __has_builtin(__builtin_clzg) + return __builtin_clzg(__x); +# else + // The function is written in this form due to C++ constexpr limitations. + // The algorithm: + // - Test whether any bit in the high 64-bits is set + // - No bits set: + // - The high 64-bits contain 64 leading zeros, + // - Add the result of the low 64-bits. + // - Any bits set: + // - The number of leading zeros of the input is the number of leading + // zeros in the high 64-bits. + return ((__x >> 64) == 0) ? (64 + __builtin_clzll(static_cast(__x))) + : __builtin_clzll(static_cast(__x >> 64)); +# endif +} +#endif // _LIBCPP_HAS_NO_INT128 + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countl_zero(_Tp __t) _NOEXCEPT { + static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__countl_zero requires an unsigned integer type"); +#if __has_builtin(__builtin_clzg) + return __builtin_clzg(__t, numeric_limits<_Tp>::digits); +#else // __has_builtin(__builtin_clzg) + if (__t == 0) + return numeric_limits<_Tp>::digits; + + if (sizeof(_Tp) <= sizeof(unsigned int)) + return std::__libcpp_clz(static_cast(__t)) - + (numeric_limits::digits - numeric_limits<_Tp>::digits); + else if (sizeof(_Tp) <= sizeof(unsigned long)) + return std::__libcpp_clz(static_cast(__t)) - + (numeric_limits::digits - numeric_limits<_Tp>::digits); + else if (sizeof(_Tp) <= sizeof(unsigned long long)) + return std::__libcpp_clz(static_cast(__t)) - + (numeric_limits::digits - numeric_limits<_Tp>::digits); + else { + int __ret = 0; + int __iter = 0; + const unsigned int __ulldigits = numeric_limits::digits; + while (true) { + __t = std::__rotl(__t, __ulldigits); + if ((__iter = std::__countl_zero(static_cast(__t))) != __ulldigits) + break; + __ret += __iter; + } + return __ret + __iter; + } +#endif // __has_builtin(__builtin_clzg) +} + +#if _LIBCPP_STD_VER >= 20 + +template <__libcpp_unsigned_integer _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countl_zero(_Tp __t) noexcept { + return std::__countl_zero(__t); +} + +template <__libcpp_unsigned_integer _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countl_one(_Tp __t) noexcept { + return __t != numeric_limits<_Tp>::max() ? std::countl_zero(static_cast<_Tp>(~__t)) : numeric_limits<_Tp>::digits; +} + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___BIT_COUNTL_H diff --git a/libcxx/include/__cxx03/__bit/countr.h b/libcxx/include/__cxx03/__bit/countr.h new file mode 100644 index 0000000000000000000000000000000000000000..9e92021fba355188732e130c3449bf8b57dbe039 --- /dev/null +++ b/libcxx/include/__cxx03/__bit/countr.h @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// TODO: __builtin_ctzg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can +// refactor this code to exclusively use __builtin_ctzg. + +#ifndef _LIBCPP___BIT_COUNTR_H +#define _LIBCPP___BIT_COUNTR_H + +#include <__bit/rotate.h> +#include <__concepts/arithmetic.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz(unsigned __x) _NOEXCEPT { + return __builtin_ctz(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz(unsigned long __x) _NOEXCEPT { + return __builtin_ctzl(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz(unsigned long long __x) _NOEXCEPT { + return __builtin_ctzll(__x); +} + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero(_Tp __t) _NOEXCEPT { +#if __has_builtin(__builtin_ctzg) + return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); +#else // __has_builtin(__builtin_ctzg) + if (__t == 0) + return numeric_limits<_Tp>::digits; + if (sizeof(_Tp) <= sizeof(unsigned int)) + return std::__libcpp_ctz(static_cast(__t)); + else if (sizeof(_Tp) <= sizeof(unsigned long)) + return std::__libcpp_ctz(static_cast(__t)); + else if (sizeof(_Tp) <= sizeof(unsigned long long)) + return std::__libcpp_ctz(static_cast(__t)); + else { + int __ret = 0; + const unsigned int __ulldigits = numeric_limits::digits; + while (static_cast(__t) == 0uLL) { + __ret += __ulldigits; + __t >>= __ulldigits; + } + return __ret + std::__libcpp_ctz(static_cast(__t)); + } +#endif // __has_builtin(__builtin_ctzg) +} + +#if _LIBCPP_STD_VER >= 20 + +template <__libcpp_unsigned_integer _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_zero(_Tp __t) noexcept { + return std::__countr_zero(__t); +} + +template <__libcpp_unsigned_integer _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_one(_Tp __t) noexcept { + return __t != numeric_limits<_Tp>::max() ? std::countr_zero(static_cast<_Tp>(~__t)) : numeric_limits<_Tp>::digits; +} + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___BIT_COUNTR_H diff --git a/libcxx/include/__cxx03/__bit/endian.h b/libcxx/include/__cxx03/__bit/endian.h new file mode 100644 index 0000000000000000000000000000000000000000..2d31e5ddff4f1ff1da770967a81ee2066e8f0a19 --- /dev/null +++ b/libcxx/include/__cxx03/__bit/endian.h @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___BIT_ENDIAN_H +#define _LIBCPP___BIT_ENDIAN_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +enum class endian { + little = 0xDEAD, + big = 0xFACE, +# if defined(_LIBCPP_LITTLE_ENDIAN) + native = little +# elif defined(_LIBCPP_BIG_ENDIAN) + native = big +# else + native = 0xCAFE +# endif +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___BIT_ENDIAN_H diff --git a/libcxx/include/__cxx03/__bit/has_single_bit.h b/libcxx/include/__cxx03/__bit/has_single_bit.h new file mode 100644 index 0000000000000000000000000000000000000000..52f5853a1bc8a4092c636db0d5c4d683a9733f51 --- /dev/null +++ b/libcxx/include/__cxx03/__bit/has_single_bit.h @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___BIT_HAS_SINGLE_BIT_H +#define _LIBCPP___BIT_HAS_SINGLE_BIT_H + +#include <__concepts/arithmetic.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template <__libcpp_unsigned_integer _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_single_bit(_Tp __t) noexcept { + return __t != 0 && (((__t & (__t - 1)) == 0)); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___BIT_HAS_SINGLE_BIT_H diff --git a/libcxx/include/__cxx03/__bit/invert_if.h b/libcxx/include/__cxx03/__bit/invert_if.h new file mode 100644 index 0000000000000000000000000000000000000000..f7606ede26da0071a2d1f8f62592d8bdb0db744a --- /dev/null +++ b/libcxx/include/__cxx03/__bit/invert_if.h @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___BIT_INVERT_IF_H +#define _LIBCPP___BIT_INVERT_IF_H + +#include <__concepts/arithmetic.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __invert_if(_Tp __v) { + if (_Invert) + return ~__v; + return __v; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___BIT_INVERT_IF_H diff --git a/libcxx/include/__cxx03/__bit/popcount.h b/libcxx/include/__cxx03/__bit/popcount.h new file mode 100644 index 0000000000000000000000000000000000000000..5cf0a01d0733823c9708c4a9a11c50bc1a091f6c --- /dev/null +++ b/libcxx/include/__cxx03/__bit/popcount.h @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// TODO: __builtin_popcountg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can +// refactor this code to exclusively use __builtin_popcountg. + +#ifndef _LIBCPP___BIT_POPCOUNT_H +#define _LIBCPP___BIT_POPCOUNT_H + +#include <__bit/rotate.h> +#include <__concepts/arithmetic.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned __x) _NOEXCEPT { + return __builtin_popcount(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned long __x) _NOEXCEPT { + return __builtin_popcountl(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned long long __x) _NOEXCEPT { + return __builtin_popcountll(__x); +} + +#if _LIBCPP_STD_VER >= 20 + +template <__libcpp_unsigned_integer _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int popcount(_Tp __t) noexcept { +# if __has_builtin(__builtin_popcountg) + return __builtin_popcountg(__t); +# else // __has_builtin(__builtin_popcountg) + if (sizeof(_Tp) <= sizeof(unsigned int)) + return std::__libcpp_popcount(static_cast(__t)); + else if (sizeof(_Tp) <= sizeof(unsigned long)) + return std::__libcpp_popcount(static_cast(__t)); + else if (sizeof(_Tp) <= sizeof(unsigned long long)) + return std::__libcpp_popcount(static_cast(__t)); + else { + int __ret = 0; + while (__t != 0) { + __ret += std::__libcpp_popcount(static_cast(__t)); + __t >>= numeric_limits::digits; + } + return __ret; + } +# endif // __has_builtin(__builtin_popcountg) +} + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___BIT_POPCOUNT_H diff --git a/libcxx/include/__cxx03/__bit/rotate.h b/libcxx/include/__cxx03/__bit/rotate.h new file mode 100644 index 0000000000000000000000000000000000000000..90e430e9d04256a190a04a0ab8dbf6e7cc0c8a5e --- /dev/null +++ b/libcxx/include/__cxx03/__bit/rotate.h @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___BIT_ROTATE_H +#define _LIBCPP___BIT_ROTATE_H + +#include <__concepts/arithmetic.h> +#include <__config> +#include <__type_traits/is_unsigned_integer.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// Writing two full functions for rotl and rotr makes it easier for the compiler +// to optimize the code. On x86 this function becomes the ROL instruction and +// the rotr function becomes the ROR instruction. +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotl(_Tp __x, int __s) _NOEXCEPT { + static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__rotl requires an unsigned integer type"); + const int __N = numeric_limits<_Tp>::digits; + int __r = __s % __N; + + if (__r == 0) + return __x; + + if (__r > 0) + return (__x << __r) | (__x >> (__N - __r)); + + return (__x >> -__r) | (__x << (__N + __r)); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotr(_Tp __x, int __s) _NOEXCEPT { + static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__rotr requires an unsigned integer type"); + const int __N = numeric_limits<_Tp>::digits; + int __r = __s % __N; + + if (__r == 0) + return __x; + + if (__r > 0) + return (__x >> __r) | (__x << (__N - __r)); + + return (__x << -__r) | (__x >> (__N + __r)); +} + +#if _LIBCPP_STD_VER >= 20 + +template <__libcpp_unsigned_integer _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp rotl(_Tp __t, int __cnt) noexcept { + return std::__rotl(__t, __cnt); +} + +template <__libcpp_unsigned_integer _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp rotr(_Tp __t, int __cnt) noexcept { + return std::__rotr(__t, __cnt); +} + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___BIT_ROTATE_H diff --git a/libcxx/include/__cxx03/__bit_reference b/libcxx/include/__cxx03/__bit_reference new file mode 100644 index 0000000000000000000000000000000000000000..22637d43974123c15b1b04cfcc1141366c6bd3eb --- /dev/null +++ b/libcxx/include/__cxx03/__bit_reference @@ -0,0 +1,1024 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___BIT_REFERENCE +#define _LIBCPP___BIT_REFERENCE + +#include <__algorithm/copy_n.h> +#include <__algorithm/fill_n.h> +#include <__algorithm/min.h> +#include <__bit/countr.h> +#include <__bit/invert_if.h> +#include <__bit/popcount.h> +#include <__compare/ordering.h> +#include <__config> +#include <__fwd/bit_reference.h> +#include <__iterator/iterator_traits.h> +#include <__memory/construct_at.h> +#include <__memory/pointer_traits.h> +#include <__type_traits/conditional.h> +#include <__utility/swap.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class __bit_const_reference; + +template +struct __has_storage_type { + static const bool value = false; +}; + +template ::value> +class __bit_reference { + using __storage_type = typename _Cp::__storage_type; + using __storage_pointer = typename _Cp::__storage_pointer; + + __storage_pointer __seg_; + __storage_type __mask_; + + friend typename _Cp::__self; + + friend class __bit_const_reference<_Cp>; + friend class __bit_iterator<_Cp, false>; + +public: + using __container = typename _Cp::__self; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_reference(const __bit_reference&) = default; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 operator bool() const _NOEXCEPT { + return static_cast(*__seg_ & __mask_); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool operator~() const _NOEXCEPT { + return !static_cast(*this); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_reference& operator=(bool __x) _NOEXCEPT { + if (__x) + *__seg_ |= __mask_; + else + *__seg_ &= ~__mask_; + return *this; + } + +#if _LIBCPP_STD_VER >= 23 + _LIBCPP_HIDE_FROM_ABI constexpr const __bit_reference& operator=(bool __x) const noexcept { + if (__x) + *__seg_ |= __mask_; + else + *__seg_ &= ~__mask_; + return *this; + } +#endif + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_reference& operator=(const __bit_reference& __x) _NOEXCEPT { + return operator=(static_cast(__x)); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void flip() _NOEXCEPT { *__seg_ ^= __mask_; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, false> operator&() const _NOEXCEPT { + return __bit_iterator<_Cp, false>(__seg_, static_cast(std::__libcpp_ctz(__mask_))); + } + +private: + _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit __bit_reference(__storage_pointer __s, __storage_type __m) _NOEXCEPT + : __seg_(__s), + __mask_(__m) {} +}; + +template +class __bit_reference<_Cp, false> {}; + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +swap(__bit_reference<_Cp> __x, __bit_reference<_Cp> __y) _NOEXCEPT { + bool __t = __x; + __x = __y; + __y = __t; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +swap(__bit_reference<_Cp> __x, __bit_reference<_Dp> __y) _NOEXCEPT { + bool __t = __x; + __x = __y; + __y = __t; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(__bit_reference<_Cp> __x, bool& __y) _NOEXCEPT { + bool __t = __x; + __x = __y; + __y = __t; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(bool& __x, __bit_reference<_Cp> __y) _NOEXCEPT { + bool __t = __x; + __x = __y; + __y = __t; +} + +template +class __bit_const_reference { + using __storage_type = typename _Cp::__storage_type; + using __storage_pointer = typename _Cp::__const_storage_pointer; + + __storage_pointer __seg_; + __storage_type __mask_; + + friend typename _Cp::__self; + friend class __bit_iterator<_Cp, true>; + +public: + using __container = typename _Cp::__self; + + _LIBCPP_HIDE_FROM_ABI __bit_const_reference(const __bit_const_reference&) = default; + __bit_const_reference& operator=(const __bit_const_reference&) = delete; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_const_reference(const __bit_reference<_Cp>& __x) _NOEXCEPT + : __seg_(__x.__seg_), + __mask_(__x.__mask_) {} + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR operator bool() const _NOEXCEPT { + return static_cast(*__seg_ & __mask_); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, true> operator&() const _NOEXCEPT { + return __bit_iterator<_Cp, true>(__seg_, static_cast(std::__libcpp_ctz(__mask_))); + } + +private: + _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR explicit __bit_const_reference(__storage_pointer __s, __storage_type __m) _NOEXCEPT + : __seg_(__s), + __mask_(__m) {} +}; + +// copy + +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> __copy_aligned( + __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { + using _In = __bit_iterator<_Cp, _IsConst>; + using difference_type = typename _In::difference_type; + using __storage_type = typename _In::__storage_type; + + const int __bits_per_word = _In::__bits_per_word; + difference_type __n = __last - __first; + if (__n > 0) { + // do first word + if (__first.__ctz_ != 0) { + unsigned __clz = __bits_per_word - __first.__ctz_; + difference_type __dn = std::min(static_cast(__clz), __n); + __n -= __dn; + __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz - __dn)); + __storage_type __b = *__first.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b; + __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word; + __result.__ctz_ = static_cast((__dn + __result.__ctz_) % __bits_per_word); + ++__first.__seg_; + // __first.__ctz_ = 0; + } + // __first.__ctz_ == 0; + // do middle words + __storage_type __nw = __n / __bits_per_word; + std::copy_n(std::__to_address(__first.__seg_), __nw, std::__to_address(__result.__seg_)); + __n -= __nw * __bits_per_word; + __result.__seg_ += __nw; + // do last word + if (__n > 0) { + __first.__seg_ += __nw; + __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); + __storage_type __b = *__first.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b; + __result.__ctz_ = static_cast(__n); + } + } + return __result; +} + +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> __copy_unaligned( + __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { + using _In = __bit_iterator<_Cp, _IsConst>; + using difference_type = typename _In::difference_type; + using __storage_type = typename _In::__storage_type; + + const int __bits_per_word = _In::__bits_per_word; + difference_type __n = __last - __first; + if (__n > 0) { + // do first word + if (__first.__ctz_ != 0) { + unsigned __clz_f = __bits_per_word - __first.__ctz_; + difference_type __dn = std::min(static_cast(__clz_f), __n); + __n -= __dn; + __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); + __storage_type __b = *__first.__seg_ & __m; + unsigned __clz_r = __bits_per_word - __result.__ctz_; + __storage_type __ddn = std::min<__storage_type>(__dn, __clz_r); + __m = (~__storage_type(0) << __result.__ctz_) & (~__storage_type(0) >> (__clz_r - __ddn)); + *__result.__seg_ &= ~__m; + if (__result.__ctz_ > __first.__ctz_) + *__result.__seg_ |= __b << (__result.__ctz_ - __first.__ctz_); + else + *__result.__seg_ |= __b >> (__first.__ctz_ - __result.__ctz_); + __result.__seg_ += (__ddn + __result.__ctz_) / __bits_per_word; + __result.__ctz_ = static_cast((__ddn + __result.__ctz_) % __bits_per_word); + __dn -= __ddn; + if (__dn > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __dn); + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b >> (__first.__ctz_ + __ddn); + __result.__ctz_ = static_cast(__dn); + } + ++__first.__seg_; + // __first.__ctz_ = 0; + } + // __first.__ctz_ == 0; + // do middle words + unsigned __clz_r = __bits_per_word - __result.__ctz_; + __storage_type __m = ~__storage_type(0) << __result.__ctz_; + for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_) { + __storage_type __b = *__first.__seg_; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b << __result.__ctz_; + ++__result.__seg_; + *__result.__seg_ &= __m; + *__result.__seg_ |= __b >> __clz_r; + } + // do last word + if (__n > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __n); + __storage_type __b = *__first.__seg_ & __m; + __storage_type __dn = std::min(__n, static_cast(__clz_r)); + __m = (~__storage_type(0) << __result.__ctz_) & (~__storage_type(0) >> (__clz_r - __dn)); + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b << __result.__ctz_; + __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word; + __result.__ctz_ = static_cast((__dn + __result.__ctz_) % __bits_per_word); + __n -= __dn; + if (__n > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __n); + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b >> __dn; + __result.__ctz_ = static_cast(__n); + } + } + } + return __result; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, false> +copy(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { + if (__first.__ctz_ == __result.__ctz_) + return std::__copy_aligned(__first, __last, __result); + return std::__copy_unaligned(__first, __last, __result); +} + +// copy_backward + +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> __copy_backward_aligned( + __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { + using _In = __bit_iterator<_Cp, _IsConst>; + using difference_type = typename _In::difference_type; + using __storage_type = typename _In::__storage_type; + + const int __bits_per_word = _In::__bits_per_word; + difference_type __n = __last - __first; + if (__n > 0) { + // do first word + if (__last.__ctz_ != 0) { + difference_type __dn = std::min(static_cast(__last.__ctz_), __n); + __n -= __dn; + unsigned __clz = __bits_per_word - __last.__ctz_; + __storage_type __m = (~__storage_type(0) << (__last.__ctz_ - __dn)) & (~__storage_type(0) >> __clz); + __storage_type __b = *__last.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b; + __result.__ctz_ = static_cast(((-__dn & (__bits_per_word - 1)) + __result.__ctz_) % __bits_per_word); + // __last.__ctz_ = 0 + } + // __last.__ctz_ == 0 || __n == 0 + // __result.__ctz_ == 0 || __n == 0 + // do middle words + __storage_type __nw = __n / __bits_per_word; + __result.__seg_ -= __nw; + __last.__seg_ -= __nw; + std::copy_n(std::__to_address(__last.__seg_), __nw, std::__to_address(__result.__seg_)); + __n -= __nw * __bits_per_word; + // do last word + if (__n > 0) { + __storage_type __m = ~__storage_type(0) << (__bits_per_word - __n); + __storage_type __b = *--__last.__seg_ & __m; + *--__result.__seg_ &= ~__m; + *__result.__seg_ |= __b; + __result.__ctz_ = static_cast(-__n & (__bits_per_word - 1)); + } + } + return __result; +} + +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> __copy_backward_unaligned( + __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { + using _In = __bit_iterator<_Cp, _IsConst>; + using difference_type = typename _In::difference_type; + using __storage_type = typename _In::__storage_type; + + const int __bits_per_word = _In::__bits_per_word; + difference_type __n = __last - __first; + if (__n > 0) { + // do first word + if (__last.__ctz_ != 0) { + difference_type __dn = std::min(static_cast(__last.__ctz_), __n); + __n -= __dn; + unsigned __clz_l = __bits_per_word - __last.__ctz_; + __storage_type __m = (~__storage_type(0) << (__last.__ctz_ - __dn)) & (~__storage_type(0) >> __clz_l); + __storage_type __b = *__last.__seg_ & __m; + unsigned __clz_r = __bits_per_word - __result.__ctz_; + __storage_type __ddn = std::min(__dn, static_cast(__result.__ctz_)); + if (__ddn > 0) { + __m = (~__storage_type(0) << (__result.__ctz_ - __ddn)) & (~__storage_type(0) >> __clz_r); + *__result.__seg_ &= ~__m; + if (__result.__ctz_ > __last.__ctz_) + *__result.__seg_ |= __b << (__result.__ctz_ - __last.__ctz_); + else + *__result.__seg_ |= __b >> (__last.__ctz_ - __result.__ctz_); + __result.__ctz_ = static_cast(((-__ddn & (__bits_per_word - 1)) + __result.__ctz_) % __bits_per_word); + __dn -= __ddn; + } + if (__dn > 0) { + // __result.__ctz_ == 0 + --__result.__seg_; + __result.__ctz_ = static_cast(-__dn & (__bits_per_word - 1)); + __m = ~__storage_type(0) << __result.__ctz_; + *__result.__seg_ &= ~__m; + __last.__ctz_ -= __dn + __ddn; + *__result.__seg_ |= __b << (__result.__ctz_ - __last.__ctz_); + } + // __last.__ctz_ = 0 + } + // __last.__ctz_ == 0 || __n == 0 + // __result.__ctz_ != 0 || __n == 0 + // do middle words + unsigned __clz_r = __bits_per_word - __result.__ctz_; + __storage_type __m = ~__storage_type(0) >> __clz_r; + for (; __n >= __bits_per_word; __n -= __bits_per_word) { + __storage_type __b = *--__last.__seg_; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b >> __clz_r; + *--__result.__seg_ &= __m; + *__result.__seg_ |= __b << __result.__ctz_; + } + // do last word + if (__n > 0) { + __m = ~__storage_type(0) << (__bits_per_word - __n); + __storage_type __b = *--__last.__seg_ & __m; + __clz_r = __bits_per_word - __result.__ctz_; + __storage_type __dn = std::min(__n, static_cast(__result.__ctz_)); + __m = (~__storage_type(0) << (__result.__ctz_ - __dn)) & (~__storage_type(0) >> __clz_r); + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b >> (__bits_per_word - __result.__ctz_); + __result.__ctz_ = static_cast(((-__dn & (__bits_per_word - 1)) + __result.__ctz_) % __bits_per_word); + __n -= __dn; + if (__n > 0) { + // __result.__ctz_ == 0 + --__result.__seg_; + __result.__ctz_ = static_cast(-__n & (__bits_per_word - 1)); + __m = ~__storage_type(0) << __result.__ctz_; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b << (__result.__ctz_ - (__bits_per_word - __n - __dn)); + } + } + } + return __result; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, false> copy_backward( + __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { + if (__last.__ctz_ == __result.__ctz_) + return std::__copy_backward_aligned(__first, __last, __result); + return std::__copy_backward_unaligned(__first, __last, __result); +} + +// move + +template +inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> +move(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { + return std::copy(__first, __last, __result); +} + +// move_backward + +template +inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> move_backward( + __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { + return std::copy_backward(__first, __last, __result); +} + +// swap_ranges + +template +_LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cr, false> __swap_ranges_aligned( + __bit_iterator<_Cl, false> __first, __bit_iterator<_Cl, false> __last, __bit_iterator<_Cr, false> __result) { + using _I1 = __bit_iterator<_Cl, false>; + using difference_type = typename _I1::difference_type; + using __storage_type = typename _I1::__storage_type; + + const int __bits_per_word = _I1::__bits_per_word; + difference_type __n = __last - __first; + if (__n > 0) { + // do first word + if (__first.__ctz_ != 0) { + unsigned __clz = __bits_per_word - __first.__ctz_; + difference_type __dn = std::min(static_cast(__clz), __n); + __n -= __dn; + __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz - __dn)); + __storage_type __b1 = *__first.__seg_ & __m; + *__first.__seg_ &= ~__m; + __storage_type __b2 = *__result.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b1; + *__first.__seg_ |= __b2; + __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word; + __result.__ctz_ = static_cast((__dn + __result.__ctz_) % __bits_per_word); + ++__first.__seg_; + // __first.__ctz_ = 0; + } + // __first.__ctz_ == 0; + // do middle words + for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_, ++__result.__seg_) + swap(*__first.__seg_, *__result.__seg_); + // do last word + if (__n > 0) { + __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); + __storage_type __b1 = *__first.__seg_ & __m; + *__first.__seg_ &= ~__m; + __storage_type __b2 = *__result.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b1; + *__first.__seg_ |= __b2; + __result.__ctz_ = static_cast(__n); + } + } + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cr, false> __swap_ranges_unaligned( + __bit_iterator<_Cl, false> __first, __bit_iterator<_Cl, false> __last, __bit_iterator<_Cr, false> __result) { + using _I1 = __bit_iterator<_Cl, false>; + using difference_type = typename _I1::difference_type; + using __storage_type = typename _I1::__storage_type; + + const int __bits_per_word = _I1::__bits_per_word; + difference_type __n = __last - __first; + if (__n > 0) { + // do first word + if (__first.__ctz_ != 0) { + unsigned __clz_f = __bits_per_word - __first.__ctz_; + difference_type __dn = std::min(static_cast(__clz_f), __n); + __n -= __dn; + __storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); + __storage_type __b1 = *__first.__seg_ & __m; + *__first.__seg_ &= ~__m; + unsigned __clz_r = __bits_per_word - __result.__ctz_; + __storage_type __ddn = std::min<__storage_type>(__dn, __clz_r); + __m = (~__storage_type(0) << __result.__ctz_) & (~__storage_type(0) >> (__clz_r - __ddn)); + __storage_type __b2 = *__result.__seg_ & __m; + *__result.__seg_ &= ~__m; + if (__result.__ctz_ > __first.__ctz_) { + unsigned __s = __result.__ctz_ - __first.__ctz_; + *__result.__seg_ |= __b1 << __s; + *__first.__seg_ |= __b2 >> __s; + } else { + unsigned __s = __first.__ctz_ - __result.__ctz_; + *__result.__seg_ |= __b1 >> __s; + *__first.__seg_ |= __b2 << __s; + } + __result.__seg_ += (__ddn + __result.__ctz_) / __bits_per_word; + __result.__ctz_ = static_cast((__ddn + __result.__ctz_) % __bits_per_word); + __dn -= __ddn; + if (__dn > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __dn); + __b2 = *__result.__seg_ & __m; + *__result.__seg_ &= ~__m; + unsigned __s = __first.__ctz_ + __ddn; + *__result.__seg_ |= __b1 >> __s; + *__first.__seg_ |= __b2 << __s; + __result.__ctz_ = static_cast(__dn); + } + ++__first.__seg_; + // __first.__ctz_ = 0; + } + // __first.__ctz_ == 0; + // do middle words + __storage_type __m = ~__storage_type(0) << __result.__ctz_; + unsigned __clz_r = __bits_per_word - __result.__ctz_; + for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_) { + __storage_type __b1 = *__first.__seg_; + __storage_type __b2 = *__result.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b1 << __result.__ctz_; + *__first.__seg_ = __b2 >> __result.__ctz_; + ++__result.__seg_; + __b2 = *__result.__seg_ & ~__m; + *__result.__seg_ &= __m; + *__result.__seg_ |= __b1 >> __clz_r; + *__first.__seg_ |= __b2 << __clz_r; + } + // do last word + if (__n > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __n); + __storage_type __b1 = *__first.__seg_ & __m; + *__first.__seg_ &= ~__m; + __storage_type __dn = std::min<__storage_type>(__n, __clz_r); + __m = (~__storage_type(0) << __result.__ctz_) & (~__storage_type(0) >> (__clz_r - __dn)); + __storage_type __b2 = *__result.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b1 << __result.__ctz_; + *__first.__seg_ |= __b2 >> __result.__ctz_; + __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word; + __result.__ctz_ = static_cast((__dn + __result.__ctz_) % __bits_per_word); + __n -= __dn; + if (__n > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __n); + __b2 = *__result.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b1 >> __dn; + *__first.__seg_ |= __b2 << __dn; + __result.__ctz_ = static_cast(__n); + } + } + } + return __result; +} + +template +inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cr, false> swap_ranges( + __bit_iterator<_Cl, false> __first1, __bit_iterator<_Cl, false> __last1, __bit_iterator<_Cr, false> __first2) { + if (__first1.__ctz_ == __first2.__ctz_) + return std::__swap_ranges_aligned(__first1, __last1, __first2); + return std::__swap_ranges_unaligned(__first1, __last1, __first2); +} + +// rotate + +template +struct __bit_array { + using difference_type = typename _Cp::difference_type; + using __storage_type = typename _Cp::__storage_type; + using __storage_pointer = typename _Cp::__storage_pointer; + using iterator = typename _Cp::iterator; + + static const unsigned __bits_per_word = _Cp::__bits_per_word; + static const unsigned _Np = 4; + + difference_type __size_; + __storage_type __word_[_Np]; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static difference_type capacity() { + return static_cast(_Np * __bits_per_word); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit __bit_array(difference_type __s) : __size_(__s) { + if (__libcpp_is_constant_evaluated()) { + for (size_t __i = 0; __i != __bit_array<_Cp>::_Np; ++__i) + std::__construct_at(__word_ + __i, 0); + } + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator begin() { + return iterator(pointer_traits<__storage_pointer>::pointer_to(__word_[0]), 0); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator end() { + return iterator(pointer_traits<__storage_pointer>::pointer_to(__word_[0]) + __size_ / __bits_per_word, + static_cast(__size_ % __bits_per_word)); + } +}; + +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> +rotate(__bit_iterator<_Cp, false> __first, __bit_iterator<_Cp, false> __middle, __bit_iterator<_Cp, false> __last) { + using _I1 = __bit_iterator<_Cp, false>; + using difference_type = typename _I1::difference_type; + + difference_type __d1 = __middle - __first; + difference_type __d2 = __last - __middle; + _I1 __r = __first + __d2; + while (__d1 != 0 && __d2 != 0) { + if (__d1 <= __d2) { + if (__d1 <= __bit_array<_Cp>::capacity()) { + __bit_array<_Cp> __b(__d1); + std::copy(__first, __middle, __b.begin()); + std::copy(__b.begin(), __b.end(), std::copy(__middle, __last, __first)); + break; + } else { + __bit_iterator<_Cp, false> __mp = std::swap_ranges(__first, __middle, __middle); + __first = __middle; + __middle = __mp; + __d2 -= __d1; + } + } else { + if (__d2 <= __bit_array<_Cp>::capacity()) { + __bit_array<_Cp> __b(__d2); + std::copy(__middle, __last, __b.begin()); + std::copy_backward(__b.begin(), __b.end(), std::copy_backward(__first, __middle, __last)); + break; + } else { + __bit_iterator<_Cp, false> __mp = __first + __d2; + std::swap_ranges(__first, __mp, __middle); + __first = __mp; + __d1 -= __d2; + } + } + } + return __r; +} + +// equal + +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __equal_unaligned( + __bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) { + using _It = __bit_iterator<_Cp, _IC1>; + using difference_type = typename _It::difference_type; + using __storage_type = typename _It::__storage_type; + + const int __bits_per_word = _It::__bits_per_word; + difference_type __n = __last1 - __first1; + if (__n > 0) { + // do first word + if (__first1.__ctz_ != 0) { + unsigned __clz_f = __bits_per_word - __first1.__ctz_; + difference_type __dn = std::min(static_cast(__clz_f), __n); + __n -= __dn; + __storage_type __m = (~__storage_type(0) << __first1.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn)); + __storage_type __b = *__first1.__seg_ & __m; + unsigned __clz_r = __bits_per_word - __first2.__ctz_; + __storage_type __ddn = std::min<__storage_type>(__dn, __clz_r); + __m = (~__storage_type(0) << __first2.__ctz_) & (~__storage_type(0) >> (__clz_r - __ddn)); + if (__first2.__ctz_ > __first1.__ctz_) { + if ((*__first2.__seg_ & __m) != (__b << (__first2.__ctz_ - __first1.__ctz_))) + return false; + } else { + if ((*__first2.__seg_ & __m) != (__b >> (__first1.__ctz_ - __first2.__ctz_))) + return false; + } + __first2.__seg_ += (__ddn + __first2.__ctz_) / __bits_per_word; + __first2.__ctz_ = static_cast((__ddn + __first2.__ctz_) % __bits_per_word); + __dn -= __ddn; + if (__dn > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __dn); + if ((*__first2.__seg_ & __m) != (__b >> (__first1.__ctz_ + __ddn))) + return false; + __first2.__ctz_ = static_cast(__dn); + } + ++__first1.__seg_; + // __first1.__ctz_ = 0; + } + // __first1.__ctz_ == 0; + // do middle words + unsigned __clz_r = __bits_per_word - __first2.__ctz_; + __storage_type __m = ~__storage_type(0) << __first2.__ctz_; + for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first1.__seg_) { + __storage_type __b = *__first1.__seg_; + if ((*__first2.__seg_ & __m) != (__b << __first2.__ctz_)) + return false; + ++__first2.__seg_; + if ((*__first2.__seg_ & ~__m) != (__b >> __clz_r)) + return false; + } + // do last word + if (__n > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __n); + __storage_type __b = *__first1.__seg_ & __m; + __storage_type __dn = std::min(__n, static_cast(__clz_r)); + __m = (~__storage_type(0) << __first2.__ctz_) & (~__storage_type(0) >> (__clz_r - __dn)); + if ((*__first2.__seg_ & __m) != (__b << __first2.__ctz_)) + return false; + __first2.__seg_ += (__dn + __first2.__ctz_) / __bits_per_word; + __first2.__ctz_ = static_cast((__dn + __first2.__ctz_) % __bits_per_word); + __n -= __dn; + if (__n > 0) { + __m = ~__storage_type(0) >> (__bits_per_word - __n); + if ((*__first2.__seg_ & __m) != (__b >> __dn)) + return false; + } + } + } + return true; +} + +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __equal_aligned( + __bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) { + using _It = __bit_iterator<_Cp, _IC1>; + using difference_type = typename _It::difference_type; + using __storage_type = typename _It::__storage_type; + + const int __bits_per_word = _It::__bits_per_word; + difference_type __n = __last1 - __first1; + if (__n > 0) { + // do first word + if (__first1.__ctz_ != 0) { + unsigned __clz = __bits_per_word - __first1.__ctz_; + difference_type __dn = std::min(static_cast(__clz), __n); + __n -= __dn; + __storage_type __m = (~__storage_type(0) << __first1.__ctz_) & (~__storage_type(0) >> (__clz - __dn)); + if ((*__first2.__seg_ & __m) != (*__first1.__seg_ & __m)) + return false; + ++__first2.__seg_; + ++__first1.__seg_; + // __first1.__ctz_ = 0; + // __first2.__ctz_ = 0; + } + // __first1.__ctz_ == 0; + // __first2.__ctz_ == 0; + // do middle words + for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first1.__seg_, ++__first2.__seg_) + if (*__first2.__seg_ != *__first1.__seg_) + return false; + // do last word + if (__n > 0) { + __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n); + if ((*__first2.__seg_ & __m) != (*__first1.__seg_ & __m)) + return false; + } + } + return true; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +equal(__bit_iterator<_Cp, _IC1> __first1, __bit_iterator<_Cp, _IC1> __last1, __bit_iterator<_Cp, _IC2> __first2) { + if (__first1.__ctz_ == __first2.__ctz_) + return std::__equal_aligned(__first1, __last1, __first2); + return std::__equal_unaligned(__first1, __last1, __first2); +} + +template +class __bit_iterator { +public: + using difference_type = typename _Cp::difference_type; + using value_type = bool; + using pointer = __bit_iterator; +#ifndef _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL + using reference = __conditional_t<_IsConst, __bit_const_reference<_Cp>, __bit_reference<_Cp> >; +#else + using reference = __conditional_t<_IsConst, bool, __bit_reference<_Cp> >; +#endif + using iterator_category = random_access_iterator_tag; + +private: + using __storage_type = typename _Cp::__storage_type; + using __storage_pointer = + __conditional_t<_IsConst, typename _Cp::__const_storage_pointer, typename _Cp::__storage_pointer>; + + static const unsigned __bits_per_word = _Cp::__bits_per_word; + + __storage_pointer __seg_; + unsigned __ctz_; + +public: + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator() _NOEXCEPT +#if _LIBCPP_STD_VER >= 14 + : __seg_(nullptr), + __ctz_(0) +#endif + { + } + + // When _IsConst=false, this is the copy constructor. + // It is non-trivial. Making it trivial would break ABI. + // When _IsConst=true, this is a converting constructor; + // the copy and move constructors are implicitly generated + // and trivial. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator(const __bit_iterator<_Cp, false>& __it) _NOEXCEPT + : __seg_(__it.__seg_), + __ctz_(__it.__ctz_) {} + + // When _IsConst=false, we have a user-provided copy constructor, + // so we must also provide a copy assignment operator because + // the implicit generation of a defaulted one is deprecated. + // When _IsConst=true, the assignment operators are + // implicitly generated and trivial. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator& + operator=(const _If<_IsConst, struct __private_nat, __bit_iterator>& __it) { + __seg_ = __it.__seg_; + __ctz_ = __it.__ctz_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator*() const _NOEXCEPT { + return __conditional_t<_IsConst, __bit_const_reference<_Cp>, __bit_reference<_Cp> >( + __seg_, __storage_type(1) << __ctz_); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator& operator++() { + if (__ctz_ != __bits_per_word - 1) + ++__ctz_; + else { + __ctz_ = 0; + ++__seg_; + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator operator++(int) { + __bit_iterator __tmp = *this; + ++(*this); + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator& operator--() { + if (__ctz_ != 0) + --__ctz_; + else { + __ctz_ = __bits_per_word - 1; + --__seg_; + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator operator--(int) { + __bit_iterator __tmp = *this; + --(*this); + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator& operator+=(difference_type __n) { + if (__n >= 0) + __seg_ += (__n + __ctz_) / __bits_per_word; + else + __seg_ += static_cast(__n - __bits_per_word + __ctz_ + 1) / + static_cast(__bits_per_word); + __n &= (__bits_per_word - 1); + __ctz_ = static_cast((__n + __ctz_) % __bits_per_word); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator& operator-=(difference_type __n) { + return *this += -__n; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator operator+(difference_type __n) const { + __bit_iterator __t(*this); + __t += __n; + return __t; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator operator-(difference_type __n) const { + __bit_iterator __t(*this); + __t -= __n; + return __t; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator + operator+(difference_type __n, const __bit_iterator& __it) { + return __it + __n; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend difference_type + operator-(const __bit_iterator& __x, const __bit_iterator& __y) { + return (__x.__seg_ - __y.__seg_) * __bits_per_word + __x.__ctz_ - __y.__ctz_; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator[](difference_type __n) const { + return *(*this + __n); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool + operator==(const __bit_iterator& __x, const __bit_iterator& __y) { + return __x.__seg_ == __y.__seg_ && __x.__ctz_ == __y.__ctz_; + } + +#if _LIBCPP_STD_VER <= 17 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool + operator!=(const __bit_iterator& __x, const __bit_iterator& __y) { + return !(__x == __y); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool + operator<(const __bit_iterator& __x, const __bit_iterator& __y) { + return __x.__seg_ < __y.__seg_ || (__x.__seg_ == __y.__seg_ && __x.__ctz_ < __y.__ctz_); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool + operator>(const __bit_iterator& __x, const __bit_iterator& __y) { + return __y < __x; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool + operator<=(const __bit_iterator& __x, const __bit_iterator& __y) { + return !(__y < __x); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool + operator>=(const __bit_iterator& __x, const __bit_iterator& __y) { + return !(__x < __y); + } +#else // _LIBCPP_STD_VER <= 17 + _LIBCPP_HIDE_FROM_ABI constexpr friend strong_ordering + operator<=>(const __bit_iterator& __x, const __bit_iterator& __y) { + if (__x.__seg_ < __y.__seg_) + return strong_ordering::less; + + if (__x.__seg_ == __y.__seg_) + return __x.__ctz_ <=> __y.__ctz_; + + return strong_ordering::greater; + } +#endif // _LIBCPP_STD_VER <= 17 + +private: + _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit __bit_iterator(__storage_pointer __s, unsigned __ctz) _NOEXCEPT + : __seg_(__s), + __ctz_(__ctz) {} + + friend typename _Cp::__self; + + friend class __bit_reference<_Cp>; + friend class __bit_const_reference<_Cp>; + friend class __bit_iterator<_Cp, true>; + template + friend struct __bit_array; + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend void + __fill_n_bool(__bit_iterator<_Dp, false> __first, typename _Dp::size_type __n); + + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> __copy_aligned( + __bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result); + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> __copy_unaligned( + __bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result); + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> + copy(__bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result); + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> __copy_backward_aligned( + __bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result); + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> __copy_backward_unaligned( + __bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result); + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> + copy_backward(__bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result); + template + friend __bit_iterator<_Cr, false> + __swap_ranges_aligned(__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false>, __bit_iterator<_Cr, false>); + template + friend __bit_iterator<_Cr, false> + __swap_ranges_unaligned(__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false>, __bit_iterator<_Cr, false>); + template + friend __bit_iterator<_Cr, false> + swap_ranges(__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false>, __bit_iterator<_Cr, false>); + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> + rotate(__bit_iterator<_Dp, false>, __bit_iterator<_Dp, false>, __bit_iterator<_Dp, false>); + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool + __equal_aligned(__bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC2>); + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool + __equal_unaligned(__bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC2>); + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool + equal(__bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC1>, __bit_iterator<_Dp, _IC2>); + template + _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, _IC> + __find_bool(__bit_iterator<_Dp, _IC>, typename _Dp::size_type); + template + friend typename __bit_iterator<_Dp, _IC>::difference_type _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX20 __count_bool(__bit_iterator<_Dp, _IC>, typename _Dp::size_type); +}; + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___BIT_REFERENCE diff --git a/libcxx/include/__cxx03/__charconv/chars_format.h b/libcxx/include/__cxx03/__charconv/chars_format.h new file mode 100644 index 0000000000000000000000000000000000000000..c76cebd5d1847d85545536ab8033a98081ca3847 --- /dev/null +++ b/libcxx/include/__cxx03/__charconv/chars_format.h @@ -0,0 +1,61 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHARCONV_CHARS_FORMAT_H +#define _LIBCPP___CHARCONV_CHARS_FORMAT_H + +#include <__config> +#include <__utility/to_underlying.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +enum class chars_format { scientific = 0x1, fixed = 0x2, hex = 0x4, general = fixed | scientific }; + +inline _LIBCPP_HIDE_FROM_ABI constexpr chars_format operator~(chars_format __x) { + return chars_format(~std::__to_underlying(__x)); +} + +inline _LIBCPP_HIDE_FROM_ABI constexpr chars_format operator&(chars_format __x, chars_format __y) { + return chars_format(std::__to_underlying(__x) & std::__to_underlying(__y)); +} + +inline _LIBCPP_HIDE_FROM_ABI constexpr chars_format operator|(chars_format __x, chars_format __y) { + return chars_format(std::__to_underlying(__x) | std::__to_underlying(__y)); +} + +inline _LIBCPP_HIDE_FROM_ABI constexpr chars_format operator^(chars_format __x, chars_format __y) { + return chars_format(std::__to_underlying(__x) ^ std::__to_underlying(__y)); +} + +inline _LIBCPP_HIDE_FROM_ABI constexpr chars_format& operator&=(chars_format& __x, chars_format __y) { + __x = __x & __y; + return __x; +} + +inline _LIBCPP_HIDE_FROM_ABI constexpr chars_format& operator|=(chars_format& __x, chars_format __y) { + __x = __x | __y; + return __x; +} + +inline _LIBCPP_HIDE_FROM_ABI constexpr chars_format& operator^=(chars_format& __x, chars_format __y) { + __x = __x ^ __y; + return __x; +} + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CHARCONV_CHARS_FORMAT_H diff --git a/libcxx/include/__cxx03/__charconv/from_chars_integral.h b/libcxx/include/__cxx03/__charconv/from_chars_integral.h new file mode 100644 index 0000000000000000000000000000000000000000..c1f033b37b913e583e26af87f80162fec732c8ed --- /dev/null +++ b/libcxx/include/__cxx03/__charconv/from_chars_integral.h @@ -0,0 +1,240 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H +#define _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H + +#include <__algorithm/copy_n.h> +#include <__assert> +#include <__charconv/from_chars_result.h> +#include <__charconv/traits.h> +#include <__config> +#include <__memory/addressof.h> +#include <__system_error/errc.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_integral.h> +#include <__type_traits/is_unsigned.h> +#include <__type_traits/make_unsigned.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +from_chars_result from_chars(const char*, const char*, bool, int = 10) = delete; + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result +__sign_combinator(_It __first, _It __last, _Tp& __value, _Fn __f, _Ts... __args) { + using __tl = numeric_limits<_Tp>; + decltype(std::__to_unsigned_like(__value)) __x; + + bool __neg = (__first != __last && *__first == '-'); + auto __r = __f(__neg ? __first + 1 : __first, __last, __x, __args...); + switch (__r.ec) { + case errc::invalid_argument: + return {__first, __r.ec}; + case errc::result_out_of_range: + return __r; + default: + break; + } + + if (__neg) { + if (__x <= std::__complement(std::__to_unsigned_like(__tl::min()))) { + __x = std::__complement(__x); + std::copy_n(std::addressof(__x), 1, std::addressof(__value)); + return __r; + } + } else { + if (__x <= std::__to_unsigned_like(__tl::max())) { + __value = __x; + return __r; + } + } + + return {__r.ptr, errc::result_out_of_range}; +} + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool __in_pattern(_Tp __c) { + return '0' <= __c && __c <= '9'; +} + +struct _LIBCPP_HIDDEN __in_pattern_result { + bool __ok; + int __val; + + explicit _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI operator bool() const { return __ok; } +}; + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI __in_pattern_result __in_pattern(_Tp __c, int __base) { + if (__base <= 10) + return {'0' <= __c && __c < '0' + __base, __c - '0'}; + else if (std::__in_pattern(__c)) + return {true, __c - '0'}; + else if ('a' <= __c && __c < 'a' + __base - 10) + return {true, __c - 'a' + 10}; + else + return {'A' <= __c && __c < 'A' + __base - 10, __c - 'A' + 10}; +} + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result +__subject_seq_combinator(_It __first, _It __last, _Tp& __value, _Fn __f, _Ts... __args) { + auto __find_non_zero = [](_It __firstit, _It __lastit) { + for (; __firstit != __lastit; ++__firstit) + if (*__firstit != '0') + break; + return __firstit; + }; + + auto __p = __find_non_zero(__first, __last); + if (__p == __last || !std::__in_pattern(*__p, __args...)) { + if (__p == __first) + return {__first, errc::invalid_argument}; + else { + __value = 0; + return {__p, {}}; + } + } + + auto __r = __f(__p, __last, __value, __args...); + if (__r.ec == errc::result_out_of_range) { + for (; __r.ptr != __last; ++__r.ptr) { + if (!std::__in_pattern(*__r.ptr, __args...)) + break; + } + } + + return __r; +} + +template ::value, int> = 0> +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result +__from_chars_atoi(const char* __first, const char* __last, _Tp& __value) { + using __tx = __itoa::__traits<_Tp>; + using __output_type = typename __tx::type; + + return std::__subject_seq_combinator( + __first, __last, __value, [](const char* __f, const char* __l, _Tp& __val) -> from_chars_result { + __output_type __a, __b; + auto __p = __tx::__read(__f, __l, __a, __b); + if (__p == __l || !std::__in_pattern(*__p)) { + __output_type __m = numeric_limits<_Tp>::max(); + if (__m >= __a && __m - __a >= __b) { + __val = __a + __b; + return {__p, {}}; + } + } + return {__p, errc::result_out_of_range}; + }); +} + +template ::value, int> = 0> +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result +__from_chars_atoi(const char* __first, const char* __last, _Tp& __value) { + using __t = decltype(std::__to_unsigned_like(__value)); + return std::__sign_combinator(__first, __last, __value, __from_chars_atoi<__t>); +} + +/* +// Code used to generate __from_chars_log2f_lut. +#include +#include +#include + +int main() { + for (int i = 2; i <= 36; ++i) + std::cout << std::format("{},\n", log2f(i)); +} +*/ +/// log2f table for bases [2, 36]. +inline constexpr float __from_chars_log2f_lut[35] = { + 1, 1.5849625, 2, 2.321928, 2.5849626, 2.807355, 3, 3.169925, 3.321928, + 3.4594316, 3.5849626, 3.7004397, 3.807355, 3.9068906, 4, 4.087463, 4.169925, 4.2479277, + 4.321928, 4.3923173, 4.4594316, 4.523562, 4.5849624, 4.643856, 4.70044, 4.7548876, 4.807355, + 4.857981, 4.9068904, 4.9541965, 5, 5.044394, 5.087463, 5.129283, 5.169925}; + +template ::value, int> = 0> +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result +__from_chars_integral(const char* __first, const char* __last, _Tp& __value, int __base) { + if (__base == 10) + return std::__from_chars_atoi(__first, __last, __value); + + return std::__subject_seq_combinator( + __first, + __last, + __value, + [](const char* __p, const char* __lastp, _Tp& __val, int __b) -> from_chars_result { + using __tl = numeric_limits<_Tp>; + // __base is always between 2 and 36 inclusive. + auto __digits = __tl::digits / __from_chars_log2f_lut[__b - 2]; + _Tp __x = __in_pattern(*__p++, __b).__val, __y = 0; + + for (int __i = 1; __p != __lastp; ++__i, ++__p) { + if (auto __c = __in_pattern(*__p, __b)) { + if (__i < __digits - 1) + __x = __x * __b + __c.__val; + else { + if (!__itoa::__mul_overflowed(__x, __b, __x)) + ++__p; + __y = __c.__val; + break; + } + } else + break; + } + + if (__p == __lastp || !__in_pattern(*__p, __b)) { + if (__tl::max() - __x >= __y) { + __val = __x + __y; + return {__p, {}}; + } + } + return {__p, errc::result_out_of_range}; + }, + __base); +} + +template ::value, int> = 0> +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result +__from_chars_integral(const char* __first, const char* __last, _Tp& __value, int __base) { + using __t = decltype(std::__to_unsigned_like(__value)); + return std::__sign_combinator(__first, __last, __value, __from_chars_integral<__t>, __base); +} + +template ::value, int> = 0> +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result +from_chars(const char* __first, const char* __last, _Tp& __value) { + return std::__from_chars_atoi(__first, __last, __value); +} + +template ::value, int> = 0> +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result +from_chars(const char* __first, const char* __last, _Tp& __value, int __base) { + _LIBCPP_ASSERT_UNCATEGORIZED(2 <= __base && __base <= 36, "base not in [2, 36]"); + return std::__from_chars_integral(__first, __last, __value, __base); +} +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___CHARCONV_FROM_CHARS_INTEGRAL_H diff --git a/libcxx/include/__cxx03/__charconv/from_chars_result.h b/libcxx/include/__cxx03/__charconv/from_chars_result.h new file mode 100644 index 0000000000000000000000000000000000000000..a7bfd6530a8a0ef2b46220f9af1e4a669741f2e2 --- /dev/null +++ b/libcxx/include/__cxx03/__charconv/from_chars_result.h @@ -0,0 +1,39 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHARCONV_FROM_CHARS_RESULT_H +#define _LIBCPP___CHARCONV_FROM_CHARS_RESULT_H + +#include <__config> +#include <__system_error/errc.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +struct _LIBCPP_EXPORTED_FROM_ABI from_chars_result { + const char* ptr; + errc ec; +# if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI friend bool operator==(const from_chars_result&, const from_chars_result&) = default; +# endif +# if _LIBCPP_STD_VER >= 26 + _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return ec == errc{}; } +# endif +}; + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CHARCONV_FROM_CHARS_RESULT_H diff --git a/libcxx/include/__cxx03/__charconv/tables.h b/libcxx/include/__cxx03/__charconv/tables.h new file mode 100644 index 0000000000000000000000000000000000000000..6b93536b8c1bac893919787248b061b817e04efa --- /dev/null +++ b/libcxx/include/__cxx03/__charconv/tables.h @@ -0,0 +1,163 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHARCONV_TABLES +#define _LIBCPP___CHARCONV_TABLES + +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +namespace __itoa { + +inline constexpr char __base_2_lut[64] = { + '0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '1', '0', '0', '0', '1', '1', '0', '1', '0', '0', '0', '1', + '0', '1', '0', '1', '1', '0', '0', '1', '1', '1', '1', '0', '0', '0', '1', '0', '0', '1', '1', '0', '1', '0', + '1', '0', '1', '1', '1', '1', '0', '0', '1', '1', '0', '1', '1', '1', '1', '0', '1', '1', '1', '1'}; + +inline constexpr char __base_8_lut[128] = { + '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '1', '0', '1', '1', '1', '2', + '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', + '2', '6', '2', '7', '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '4', '0', + '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '5', '0', '5', '1', '5', '2', '5', '3', + '5', '4', '5', '5', '5', '6', '5', '7', '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', + '6', '7', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7'}; + +inline constexpr char __base_16_lut[512] = { + '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', '0', 'a', '0', + 'b', '0', 'c', '0', 'd', '0', 'e', '0', 'f', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', + '1', '7', '1', '8', '1', '9', '1', 'a', '1', 'b', '1', 'c', '1', 'd', '1', 'e', '1', 'f', '2', '0', '2', '1', '2', + '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '2', 'a', '2', 'b', '2', 'c', '2', 'd', + '2', 'e', '2', 'f', '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', + '9', '3', 'a', '3', 'b', '3', 'c', '3', 'd', '3', 'e', '3', 'f', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', + '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '4', 'a', '4', 'b', '4', 'c', '4', 'd', '4', 'e', '4', 'f', '5', + '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', '5', 'a', '5', 'b', + '5', 'c', '5', 'd', '5', 'e', '5', 'f', '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', + '7', '6', '8', '6', '9', '6', 'a', '6', 'b', '6', 'c', '6', 'd', '6', 'e', '6', 'f', '7', '0', '7', '1', '7', '2', + '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', '7', 'a', '7', 'b', '7', 'c', '7', 'd', '7', + 'e', '7', 'f', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', + '8', 'a', '8', 'b', '8', 'c', '8', 'd', '8', 'e', '8', 'f', '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', + '5', '9', '6', '9', '7', '9', '8', '9', '9', '9', 'a', '9', 'b', '9', 'c', '9', 'd', '9', 'e', '9', 'f', 'a', '0', + 'a', '1', 'a', '2', 'a', '3', 'a', '4', 'a', '5', 'a', '6', 'a', '7', 'a', '8', 'a', '9', 'a', 'a', 'a', 'b', 'a', + 'c', 'a', 'd', 'a', 'e', 'a', 'f', 'b', '0', 'b', '1', 'b', '2', 'b', '3', 'b', '4', 'b', '5', 'b', '6', 'b', '7', + 'b', '8', 'b', '9', 'b', 'a', 'b', 'b', 'b', 'c', 'b', 'd', 'b', 'e', 'b', 'f', 'c', '0', 'c', '1', 'c', '2', 'c', + '3', 'c', '4', 'c', '5', 'c', '6', 'c', '7', 'c', '8', 'c', '9', 'c', 'a', 'c', 'b', 'c', 'c', 'c', 'd', 'c', 'e', + 'c', 'f', 'd', '0', 'd', '1', 'd', '2', 'd', '3', 'd', '4', 'd', '5', 'd', '6', 'd', '7', 'd', '8', 'd', '9', 'd', + 'a', 'd', 'b', 'd', 'c', 'd', 'd', 'd', 'e', 'd', 'f', 'e', '0', 'e', '1', 'e', '2', 'e', '3', 'e', '4', 'e', '5', + 'e', '6', 'e', '7', 'e', '8', 'e', '9', 'e', 'a', 'e', 'b', 'e', 'c', 'e', 'd', 'e', 'e', 'e', 'f', 'f', '0', 'f', + '1', 'f', '2', 'f', '3', 'f', '4', 'f', '5', 'f', '6', 'f', '7', 'f', '8', 'f', '9', 'f', 'a', 'f', 'b', 'f', 'c', + 'f', 'd', 'f', 'e', 'f', 'f'}; + +inline constexpr uint32_t __pow10_32[10] = { + UINT32_C(0), + UINT32_C(10), + UINT32_C(100), + UINT32_C(1000), + UINT32_C(10000), + UINT32_C(100000), + UINT32_C(1000000), + UINT32_C(10000000), + UINT32_C(100000000), + UINT32_C(1000000000)}; + +inline constexpr uint64_t __pow10_64[20] = { + UINT64_C(0), + UINT64_C(10), + UINT64_C(100), + UINT64_C(1000), + UINT64_C(10000), + UINT64_C(100000), + UINT64_C(1000000), + UINT64_C(10000000), + UINT64_C(100000000), + UINT64_C(1000000000), + UINT64_C(10000000000), + UINT64_C(100000000000), + UINT64_C(1000000000000), + UINT64_C(10000000000000), + UINT64_C(100000000000000), + UINT64_C(1000000000000000), + UINT64_C(10000000000000000), + UINT64_C(100000000000000000), + UINT64_C(1000000000000000000), + UINT64_C(10000000000000000000)}; + +# ifndef _LIBCPP_HAS_NO_INT128 +inline constexpr int __pow10_128_offset = 0; +inline constexpr __uint128_t __pow10_128[40] = { + UINT64_C(0), + UINT64_C(10), + UINT64_C(100), + UINT64_C(1000), + UINT64_C(10000), + UINT64_C(100000), + UINT64_C(1000000), + UINT64_C(10000000), + UINT64_C(100000000), + UINT64_C(1000000000), + UINT64_C(10000000000), + UINT64_C(100000000000), + UINT64_C(1000000000000), + UINT64_C(10000000000000), + UINT64_C(100000000000000), + UINT64_C(1000000000000000), + UINT64_C(10000000000000000), + UINT64_C(100000000000000000), + UINT64_C(1000000000000000000), + UINT64_C(10000000000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(100), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(1000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(100000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(1000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(100000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(1000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(100000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(1000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(100000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(1000000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(100000000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(1000000000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000000000000000000), + (__uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000000000000000000)) * 10}; +# endif + +inline constexpr char __digits_base_10[200] = { + // clang-format off + '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', + '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', + '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', + '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', + '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', + '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', + '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', + '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', + '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', + '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'}; +// clang-format on + +} // namespace __itoa + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CHARCONV_TABLES diff --git a/libcxx/include/__cxx03/__charconv/to_chars.h b/libcxx/include/__cxx03/__charconv/to_chars.h new file mode 100644 index 0000000000000000000000000000000000000000..8ef09af737559fe6d1ec6a42a49451314425ac0b --- /dev/null +++ b/libcxx/include/__cxx03/__charconv/to_chars.h @@ -0,0 +1,25 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHARCONV_TO_CHARS +#define _LIBCPP___CHARCONV_TO_CHARS + +#include <__charconv/to_chars_floating_point.h> +#include <__charconv/to_chars_integral.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CHARCONV_TO_CHARS diff --git a/libcxx/include/__cxx03/__charconv/to_chars_base_10.h b/libcxx/include/__cxx03/__charconv/to_chars_base_10.h new file mode 100644 index 0000000000000000000000000000000000000000..c49f4f6797aa4373953046297bd014de7ed1cc25 --- /dev/null +++ b/libcxx/include/__cxx03/__charconv/to_chars_base_10.h @@ -0,0 +1,188 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHARCONV_TO_CHARS_BASE_10_H +#define _LIBCPP___CHARCONV_TO_CHARS_BASE_10_H + +#include <__algorithm/copy_n.h> +#include <__assert> +#include <__charconv/tables.h> +#include <__config> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +namespace __itoa { + +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append1(char* __first, uint32_t __value) noexcept { + *__first = '0' + static_cast(__value); + return __first + 1; +} + +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append2(char* __first, uint32_t __value) noexcept { + return std::copy_n(&__digits_base_10[__value * 2], 2, __first); +} + +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append3(char* __first, uint32_t __value) noexcept { + return __itoa::__append2(__itoa::__append1(__first, __value / 100), __value % 100); +} + +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append4(char* __first, uint32_t __value) noexcept { + return __itoa::__append2(__itoa::__append2(__first, __value / 100), __value % 100); +} + +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append5(char* __first, uint32_t __value) noexcept { + return __itoa::__append4(__itoa::__append1(__first, __value / 10000), __value % 10000); +} + +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append6(char* __first, uint32_t __value) noexcept { + return __itoa::__append4(__itoa::__append2(__first, __value / 10000), __value % 10000); +} + +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append7(char* __first, uint32_t __value) noexcept { + return __itoa::__append6(__itoa::__append1(__first, __value / 1000000), __value % 1000000); +} + +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append8(char* __first, uint32_t __value) noexcept { + return __itoa::__append6(__itoa::__append2(__first, __value / 1000000), __value % 1000000); +} + +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append9(char* __first, uint32_t __value) noexcept { + return __itoa::__append8(__itoa::__append1(__first, __value / 100000000), __value % 100000000); +} + +template +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI char* __append10(char* __first, _Tp __value) noexcept { + return __itoa::__append8(__itoa::__append2(__first, static_cast(__value / 100000000)), + static_cast(__value % 100000000)); +} + +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* +__base_10_u32(char* __first, uint32_t __value) noexcept { + if (__value < 1000000) { + if (__value < 10000) { + if (__value < 100) { + // 0 <= __value < 100 + if (__value < 10) + return __itoa::__append1(__first, __value); + return __itoa::__append2(__first, __value); + } + // 100 <= __value < 10'000 + if (__value < 1000) + return __itoa::__append3(__first, __value); + return __itoa::__append4(__first, __value); + } + + // 10'000 <= __value < 1'000'000 + if (__value < 100000) + return __itoa::__append5(__first, __value); + return __itoa::__append6(__first, __value); + } + + // __value => 1'000'000 + if (__value < 100000000) { + // 1'000'000 <= __value < 100'000'000 + if (__value < 10000000) + return __itoa::__append7(__first, __value); + return __itoa::__append8(__first, __value); + } + + // 100'000'000 <= __value < max + if (__value < 1000000000) + return __itoa::__append9(__first, __value); + return __itoa::__append10(__first, __value); +} + +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* +__base_10_u64(char* __buffer, uint64_t __value) noexcept { + if (__value <= UINT32_MAX) + return __itoa::__base_10_u32(__buffer, static_cast(__value)); + + // Numbers in the range UINT32_MAX <= val < 10'000'000'000 always contain 10 + // digits and are outputted after this if statement. + if (__value >= 10000000000) { + // This function properly deterimines the first non-zero leading digit. + __buffer = __itoa::__base_10_u32(__buffer, static_cast(__value / 10000000000)); + __value %= 10000000000; + } + return __itoa::__append10(__buffer, __value); +} + +# ifndef _LIBCPP_HAS_NO_INT128 +/// \returns 10^\a exp +/// +/// \pre \a exp [19, 39] +/// +/// \note The lookup table contains a partial set of exponents limiting the +/// range that can be used. However the range is sufficient for +/// \ref __base_10_u128. +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline __uint128_t __pow_10(int __exp) noexcept { + _LIBCPP_ASSERT_INTERNAL(__exp >= __pow10_128_offset, "Index out of bounds"); + return __pow10_128[__exp - __pow10_128_offset]; +} + +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* +__base_10_u128(char* __buffer, __uint128_t __value) noexcept { + _LIBCPP_ASSERT_INTERNAL( + __value > numeric_limits::max(), "The optimizations for this algorithm fails when this isn't true."); + + // Unlike the 64 to 32 bit case the 128 bit case the "upper half" can't be + // stored in the "lower half". Instead we first need to handle the top most + // digits separately. + // + // Maximum unsigned values + // 64 bit 18'446'744'073'709'551'615 (20 digits) + // 128 bit 340'282'366'920'938'463'463'374'607'431'768'211'455 (39 digits) + // step 1 ^ ([0-1] digits) + // step 2 ^^^^^^^^^^^^^^^^^^^^^^^^^ ([0-19] digits) + // step 3 ^^^^^^^^^^^^^^^^^^^^^^^^^ (19 digits) + if (__value >= __itoa::__pow_10(38)) { + // step 1 + __buffer = __itoa::__append1(__buffer, static_cast(__value / __itoa::__pow_10(38))); + __value %= __itoa::__pow_10(38); + + // step 2 always 19 digits. + // They are handled here since leading zeros need to be appended to the buffer, + __buffer = __itoa::__append9(__buffer, static_cast(__value / __itoa::__pow_10(29))); + __value %= __itoa::__pow_10(29); + __buffer = __itoa::__append10(__buffer, static_cast(__value / __itoa::__pow_10(19))); + __value %= __itoa::__pow_10(19); + } else { + // step 2 + // This version needs to determine the position of the leading non-zero digit. + __buffer = __base_10_u64(__buffer, static_cast(__value / __itoa::__pow_10(19))); + __value %= __itoa::__pow_10(19); + } + + // Step 3 + __buffer = __itoa::__append9(__buffer, static_cast(__value / 10000000000)); + __buffer = __itoa::__append10(__buffer, static_cast(__value % 10000000000)); + + return __buffer; +} +# endif +} // namespace __itoa + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___CHARCONV_TO_CHARS_BASE_10_H diff --git a/libcxx/include/__cxx03/__charconv/to_chars_floating_point.h b/libcxx/include/__cxx03/__charconv/to_chars_floating_point.h new file mode 100644 index 0000000000000000000000000000000000000000..118f316b21a10233f237dceac5727281db1545c8 --- /dev/null +++ b/libcxx/include/__cxx03/__charconv/to_chars_floating_point.h @@ -0,0 +1,55 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHARCONV_TO_CHARS_FLOATING_POINT_H +#define _LIBCPP___CHARCONV_TO_CHARS_FLOATING_POINT_H + +#include <__charconv/chars_format.h> +#include <__charconv/to_chars_result.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT _LIBCPP_EXPORTED_FROM_ABI to_chars_result +to_chars(char* __first, char* __last, float __value); + +_LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT _LIBCPP_EXPORTED_FROM_ABI to_chars_result +to_chars(char* __first, char* __last, double __value); + +_LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT _LIBCPP_EXPORTED_FROM_ABI to_chars_result +to_chars(char* __first, char* __last, long double __value); + +_LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT _LIBCPP_EXPORTED_FROM_ABI to_chars_result +to_chars(char* __first, char* __last, float __value, chars_format __fmt); + +_LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT _LIBCPP_EXPORTED_FROM_ABI to_chars_result +to_chars(char* __first, char* __last, double __value, chars_format __fmt); + +_LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT _LIBCPP_EXPORTED_FROM_ABI to_chars_result +to_chars(char* __first, char* __last, long double __value, chars_format __fmt); + +_LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT _LIBCPP_EXPORTED_FROM_ABI to_chars_result +to_chars(char* __first, char* __last, float __value, chars_format __fmt, int __precision); + +_LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT _LIBCPP_EXPORTED_FROM_ABI to_chars_result +to_chars(char* __first, char* __last, double __value, chars_format __fmt, int __precision); + +_LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT _LIBCPP_EXPORTED_FROM_ABI to_chars_result +to_chars(char* __first, char* __last, long double __value, chars_format __fmt, int __precision); +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CHARCONV_TO_CHARS_FLOATING_POINT_H diff --git a/libcxx/include/__cxx03/__charconv/to_chars_integral.h b/libcxx/include/__cxx03/__charconv/to_chars_integral.h new file mode 100644 index 0000000000000000000000000000000000000000..0369f4dfb9bda6bdcb7f86bcb6e630afee116c17 --- /dev/null +++ b/libcxx/include/__cxx03/__charconv/to_chars_integral.h @@ -0,0 +1,327 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHARCONV_TO_CHARS_INTEGRAL_H +#define _LIBCPP___CHARCONV_TO_CHARS_INTEGRAL_H + +#include <__algorithm/copy_n.h> +#include <__assert> +#include <__bit/countl.h> +#include <__charconv/tables.h> +#include <__charconv/to_chars_base_10.h> +#include <__charconv/to_chars_result.h> +#include <__charconv/traits.h> +#include <__config> +#include <__system_error/errc.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_same.h> +#include <__type_traits/make_32_64_or_128_bit.h> +#include <__type_traits/make_unsigned.h> +#include <__utility/unreachable.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +to_chars_result to_chars(char*, char*, bool, int = 10) = delete; + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result +__to_chars_itoa(char* __first, char* __last, _Tp __value, false_type); + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result +__to_chars_itoa(char* __first, char* __last, _Tp __value, true_type) { + auto __x = std::__to_unsigned_like(__value); + if (__value < 0 && __first != __last) { + *__first++ = '-'; + __x = std::__complement(__x); + } + + return std::__to_chars_itoa(__first, __last, __x, false_type()); +} + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result +__to_chars_itoa(char* __first, char* __last, _Tp __value, false_type) { + using __tx = __itoa::__traits<_Tp>; + auto __diff = __last - __first; + + if (__tx::digits <= __diff || __tx::__width(__value) <= __diff) + return {__tx::__convert(__first, __value), errc(0)}; + else + return {__last, errc::value_too_large}; +} + +# ifndef _LIBCPP_HAS_NO_INT128 +template <> +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result +__to_chars_itoa(char* __first, char* __last, __uint128_t __value, false_type) { + // When the value fits in 64-bits use the 64-bit code path. This reduces + // the number of expensive calculations on 128-bit values. + // + // NOTE the 128-bit code path requires this optimization. + if (__value <= numeric_limits::max()) + return __to_chars_itoa(__first, __last, static_cast(__value), false_type()); + + using __tx = __itoa::__traits<__uint128_t>; + auto __diff = __last - __first; + + if (__tx::digits <= __diff || __tx::__width(__value) <= __diff) + return {__tx::__convert(__first, __value), errc(0)}; + else + return {__last, errc::value_too_large}; +} +# endif + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result +__to_chars_integral(char* __first, char* __last, _Tp __value, int __base, false_type); + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result +__to_chars_integral(char* __first, char* __last, _Tp __value, int __base, true_type) { + auto __x = std::__to_unsigned_like(__value); + if (__value < 0 && __first != __last) { + *__first++ = '-'; + __x = std::__complement(__x); + } + + return std::__to_chars_integral(__first, __last, __x, __base, false_type()); +} + +namespace __itoa { + +template +struct _LIBCPP_HIDDEN __integral; + +template <> +struct _LIBCPP_HIDDEN __integral<2> { + template + _LIBCPP_HIDE_FROM_ABI static constexpr int __width(_Tp __value) noexcept { + // If value == 0 still need one digit. If the value != this has no + // effect since the code scans for the most significant bit set. (Note + // that __libcpp_clz doesn't work for 0.) + return numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1); + } + + template + _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI static to_chars_result + __to_chars(char* __first, char* __last, _Tp __value) { + ptrdiff_t __cap = __last - __first; + int __n = __width(__value); + if (__n > __cap) + return {__last, errc::value_too_large}; + + __last = __first + __n; + char* __p = __last; + const unsigned __divisor = 16; + while (__value > __divisor) { + unsigned __c = __value % __divisor; + __value /= __divisor; + __p -= 4; + std::copy_n(&__base_2_lut[4 * __c], 4, __p); + } + do { + unsigned __c = __value % 2; + __value /= 2; + *--__p = "01"[__c]; + } while (__value != 0); + return {__last, errc(0)}; + } +}; + +template <> +struct _LIBCPP_HIDDEN __integral<8> { + template + _LIBCPP_HIDE_FROM_ABI static constexpr int __width(_Tp __value) noexcept { + // If value == 0 still need one digit. If the value != this has no + // effect since the code scans for the most significat bit set. (Note + // that __libcpp_clz doesn't work for 0.) + return ((numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1)) + 2) / 3; + } + + template + _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI static to_chars_result + __to_chars(char* __first, char* __last, _Tp __value) { + ptrdiff_t __cap = __last - __first; + int __n = __width(__value); + if (__n > __cap) + return {__last, errc::value_too_large}; + + __last = __first + __n; + char* __p = __last; + unsigned __divisor = 64; + while (__value > __divisor) { + unsigned __c = __value % __divisor; + __value /= __divisor; + __p -= 2; + std::copy_n(&__base_8_lut[2 * __c], 2, __p); + } + do { + unsigned __c = __value % 8; + __value /= 8; + *--__p = "01234567"[__c]; + } while (__value != 0); + return {__last, errc(0)}; + } +}; + +template <> +struct _LIBCPP_HIDDEN __integral<16> { + template + _LIBCPP_HIDE_FROM_ABI static constexpr int __width(_Tp __value) noexcept { + // If value == 0 still need one digit. If the value != this has no + // effect since the code scans for the most significat bit set. (Note + // that __libcpp_clz doesn't work for 0.) + return (numeric_limits<_Tp>::digits - std::__libcpp_clz(__value | 1) + 3) / 4; + } + + template + _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI static to_chars_result + __to_chars(char* __first, char* __last, _Tp __value) { + ptrdiff_t __cap = __last - __first; + int __n = __width(__value); + if (__n > __cap) + return {__last, errc::value_too_large}; + + __last = __first + __n; + char* __p = __last; + unsigned __divisor = 256; + while (__value > __divisor) { + unsigned __c = __value % __divisor; + __value /= __divisor; + __p -= 2; + std::copy_n(&__base_16_lut[2 * __c], 2, __p); + } + if (__first != __last) + do { + unsigned __c = __value % 16; + __value /= 16; + *--__p = "0123456789abcdef"[__c]; + } while (__value != 0); + return {__last, errc(0)}; + } +}; + +} // namespace __itoa + +template = sizeof(unsigned)), int> = 0> +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value) { + return __itoa::__integral<_Base>::__width(__value); +} + +template = 0> +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value) { + return std::__to_chars_integral_width<_Base>(static_cast(__value)); +} + +template = sizeof(unsigned)), int> = 0> +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result +__to_chars_integral(char* __first, char* __last, _Tp __value) { + return __itoa::__integral<_Base>::__to_chars(__first, __last, __value); +} + +template = 0> +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result +__to_chars_integral(char* __first, char* __last, _Tp __value) { + return std::__to_chars_integral<_Base>(__first, __last, static_cast(__value)); +} + +template +_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value, unsigned __base) { + _LIBCPP_ASSERT_INTERNAL(__value >= 0, "The function requires a non-negative value."); + + unsigned __base_2 = __base * __base; + unsigned __base_3 = __base_2 * __base; + unsigned __base_4 = __base_2 * __base_2; + + int __r = 0; + while (true) { + if (__value < __base) + return __r + 1; + if (__value < __base_2) + return __r + 2; + if (__value < __base_3) + return __r + 3; + if (__value < __base_4) + return __r + 4; + + __value /= __base_4; + __r += 4; + } + + __libcpp_unreachable(); +} + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result +__to_chars_integral(char* __first, char* __last, _Tp __value, int __base, false_type) { + if (__base == 10) [[likely]] + return std::__to_chars_itoa(__first, __last, __value, false_type()); + + switch (__base) { + case 2: + return std::__to_chars_integral<2>(__first, __last, __value); + case 8: + return std::__to_chars_integral<8>(__first, __last, __value); + case 16: + return std::__to_chars_integral<16>(__first, __last, __value); + } + + ptrdiff_t __cap = __last - __first; + int __n = std::__to_chars_integral_width(__value, __base); + if (__n > __cap) + return {__last, errc::value_too_large}; + + __last = __first + __n; + char* __p = __last; + do { + unsigned __c = __value % __base; + __value /= __base; + *--__p = "0123456789abcdefghijklmnopqrstuvwxyz"[__c]; + } while (__value != 0); + return {__last, errc(0)}; +} + +template ::value, int> = 0> +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result +to_chars(char* __first, char* __last, _Tp __value) { + using _Type = __make_32_64_or_128_bit_t<_Tp>; + static_assert(!is_same<_Type, void>::value, "unsupported integral type used in to_chars"); + return std::__to_chars_itoa(__first, __last, static_cast<_Type>(__value), is_signed<_Tp>()); +} + +template ::value, int> = 0> +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result +to_chars(char* __first, char* __last, _Tp __value, int __base) { + _LIBCPP_ASSERT_UNCATEGORIZED(2 <= __base && __base <= 36, "base not in [2, 36]"); + + using _Type = __make_32_64_or_128_bit_t<_Tp>; + return std::__to_chars_integral(__first, __last, static_cast<_Type>(__value), __base, is_signed<_Tp>()); +} + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___CHARCONV_TO_CHARS_INTEGRAL_H diff --git a/libcxx/include/__cxx03/__charconv/to_chars_result.h b/libcxx/include/__cxx03/__charconv/to_chars_result.h new file mode 100644 index 0000000000000000000000000000000000000000..8df0897a49fbbd9c7cb180ca13a632cd86f1486b --- /dev/null +++ b/libcxx/include/__cxx03/__charconv/to_chars_result.h @@ -0,0 +1,39 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHARCONV_TO_CHARS_RESULT_H +#define _LIBCPP___CHARCONV_TO_CHARS_RESULT_H + +#include <__config> +#include <__system_error/errc.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +struct _LIBCPP_EXPORTED_FROM_ABI to_chars_result { + char* ptr; + errc ec; +# if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI friend bool operator==(const to_chars_result&, const to_chars_result&) = default; +# endif +# if _LIBCPP_STD_VER >= 26 + _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return ec == errc{}; } +# endif +}; + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CHARCONV_TO_CHARS_RESULT_H diff --git a/libcxx/include/__cxx03/__charconv/traits.h b/libcxx/include/__cxx03/__charconv/traits.h new file mode 100644 index 0000000000000000000000000000000000000000..c91c6da324797872c1217ae58a7e6c58b8bca8fc --- /dev/null +++ b/libcxx/include/__cxx03/__charconv/traits.h @@ -0,0 +1,200 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHARCONV_TRAITS +#define _LIBCPP___CHARCONV_TRAITS + +#include <__assert> +#include <__bit/countl.h> +#include <__charconv/tables.h> +#include <__charconv/to_chars_base_10.h> +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_unsigned.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +namespace __itoa { + +template +struct _LIBCPP_HIDDEN __traits_base; + +template +struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t> { + using type = uint32_t; + + /// The width estimation using a log10 algorithm. + /// + /// The algorithm is based on + /// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 + /// Instead of using IntegerLogBase2 it uses __libcpp_clz. Since that + /// function requires its input to have at least one bit set the value of + /// zero is set to one. This means the first element of the lookup table is + /// zero. + static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) { + auto __t = (32 - std::__libcpp_clz(static_cast(__v | 1))) * 1233 >> 12; + return __t - (__v < __itoa::__pow10_32[__t]) + 1; + } + + static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI char* __convert(char* __p, _Tp __v) { + return __itoa::__base_10_u32(__p, __v); + } + + static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI decltype(__pow10_32)& __pow() { + return __itoa::__pow10_32; + } +}; + +template +struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t> { + using type = uint64_t; + + /// The width estimation using a log10 algorithm. + /// + /// The algorithm is based on + /// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 + /// Instead of using IntegerLogBase2 it uses __libcpp_clz. Since that + /// function requires its input to have at least one bit set the value of + /// zero is set to one. This means the first element of the lookup table is + /// zero. + static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) { + auto __t = (64 - std::__libcpp_clz(static_cast(__v | 1))) * 1233 >> 12; + return __t - (__v < __itoa::__pow10_64[__t]) + 1; + } + + static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI char* __convert(char* __p, _Tp __v) { + return __itoa::__base_10_u64(__p, __v); + } + + static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI decltype(__pow10_64)& __pow() { + return __itoa::__pow10_64; + } +}; + +# ifndef _LIBCPP_HAS_NO_INT128 +template +struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t > { + using type = __uint128_t; + + /// The width estimation using a log10 algorithm. + /// + /// The algorithm is based on + /// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 + /// Instead of using IntegerLogBase2 it uses __libcpp_clz. Since that + /// function requires its input to have at least one bit set the value of + /// zero is set to one. This means the first element of the lookup table is + /// zero. + static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) { + _LIBCPP_ASSERT_INTERNAL( + __v > numeric_limits::max(), "The optimizations for this algorithm fail when this isn't true."); + // There's always a bit set in the upper 64-bits. + auto __t = (128 - std::__libcpp_clz(static_cast(__v >> 64))) * 1233 >> 12; + _LIBCPP_ASSERT_INTERNAL(__t >= __itoa::__pow10_128_offset, "Index out of bounds"); + // __t is adjusted since the lookup table misses the lower entries. + return __t - (__v < __itoa::__pow10_128[__t - __itoa::__pow10_128_offset]) + 1; + } + + static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI char* __convert(char* __p, _Tp __v) { + return __itoa::__base_10_u128(__p, __v); + } + + // TODO FMT This pow function should get an index. + // By moving this to its own header it can be reused by the pow function in to_chars_base_10. + static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI decltype(__pow10_128)& __pow() { + return __itoa::__pow10_128; + } +}; +# endif + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool +__mul_overflowed(unsigned char __a, _Tp __b, unsigned char& __r) { + auto __c = __a * __b; + __r = __c; + return __c > numeric_limits::max(); +} + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool +__mul_overflowed(unsigned short __a, _Tp __b, unsigned short& __r) { + auto __c = __a * __b; + __r = __c; + return __c > numeric_limits::max(); +} + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool __mul_overflowed(_Tp __a, _Tp __b, _Tp& __r) { + static_assert(is_unsigned<_Tp>::value, ""); + return __builtin_mul_overflow(__a, __b, &__r); +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool _LIBCPP_CONSTEXPR_SINCE_CXX23 __mul_overflowed(_Tp __a, _Up __b, _Tp& __r) { + return __itoa::__mul_overflowed(__a, static_cast<_Tp>(__b), __r); +} + +template +struct _LIBCPP_HIDDEN __traits : __traits_base<_Tp> { + static constexpr int digits = numeric_limits<_Tp>::digits10 + 1; + using __traits_base<_Tp>::__pow; + using typename __traits_base<_Tp>::type; + + // precondition: at least one non-zero character available + static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI char const* + __read(char const* __p, char const* __ep, type& __a, type& __b) { + type __cprod[digits]; + int __j = digits - 1; + int __i = digits; + do { + if (*__p < '0' || *__p > '9') + break; + __cprod[--__i] = *__p++ - '0'; + } while (__p != __ep && __i != 0); + + __a = __inner_product(__cprod + __i + 1, __cprod + __j, __pow() + 1, __cprod[__i]); + if (__itoa::__mul_overflowed(__cprod[__j], __pow()[__j - __i], __b)) + --__p; + return __p; + } + + template + static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _Up + __inner_product(_It1 __first1, _It1 __last1, _It2 __first2, _Up __init) { + for (; __first1 < __last1; ++__first1, ++__first2) + __init = __init + *__first1 * *__first2; + return __init; + } +}; + +} // namespace __itoa + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _Tp __complement(_Tp __x) { + static_assert(is_unsigned<_Tp>::value, "cast to unsigned first"); + return _Tp(~__x + 1); +} + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___CHARCONV_TRAITS diff --git a/libcxx/include/__cxx03/__chrono/calendar.h b/libcxx/include/__cxx03/__chrono/calendar.h new file mode 100644 index 0000000000000000000000000000000000000000..bb1c5e7ebc8d0bc794bfc18eb3f2324317ab567d --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/calendar.h @@ -0,0 +1,44 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_CALENDAR_H +#define _LIBCPP___CHRONO_CALENDAR_H + +#include <__chrono/duration.h> +#include <__chrono/time_point.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +struct local_t {}; +template +using local_time = time_point; +using local_seconds = local_time; +using local_days = local_time; + +struct last_spec { + explicit last_spec() = default; +}; +inline constexpr last_spec last{}; + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___CHRONO_CALENDAR_H diff --git a/libcxx/include/__cxx03/__chrono/concepts.h b/libcxx/include/__cxx03/__chrono/concepts.h new file mode 100644 index 0000000000000000000000000000000000000000..61ec256b23abb268da5d84017f2a3f48eb4710cd --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/concepts.h @@ -0,0 +1,36 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_CONCEPTS_H +#define _LIBCPP___CHRONO_CONCEPTS_H + +#include <__chrono/hh_mm_ss.h> +#include <__chrono/time_point.h> +#include <__config> +#include <__type_traits/is_specialization.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +concept __is_hh_mm_ss = __is_specialization_v<_Tp, chrono::hh_mm_ss>; + +template +concept __is_time_point = __is_specialization_v<_Tp, chrono::time_point>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CHRONO_CONCEPTS_H diff --git a/libcxx/include/__cxx03/__chrono/convert_to_timespec.h b/libcxx/include/__cxx03/__chrono/convert_to_timespec.h new file mode 100644 index 0000000000000000000000000000000000000000..11e0b826d05b4c95124c28d6e2f609b6f9ffad86 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/convert_to_timespec.h @@ -0,0 +1,51 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_CONVERT_TO_TIMESPEC_H +#define _LIBCPP___CHRONO_CONVERT_TO_TIMESPEC_H + +#include <__chrono/duration.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// Convert a nanoseconds duration to the given TimeSpec type, which must have +// the same properties as std::timespec. +template +_LIBCPP_HIDE_FROM_ABI inline _TimeSpec __convert_to_timespec(const chrono::nanoseconds& __ns) { + using namespace chrono; + seconds __s = duration_cast(__ns); + _TimeSpec __ts; + typedef decltype(__ts.tv_sec) __ts_sec; + const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max(); + + if (__s.count() < __ts_sec_max) { + __ts.tv_sec = static_cast<__ts_sec>(__s.count()); + __ts.tv_nsec = static_cast((__ns - __s).count()); + } else { + __ts.tv_sec = __ts_sec_max; + __ts.tv_nsec = 999999999; // (10^9 - 1) + } + + return __ts; +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___CHRONO_CONVERT_TO_TIMESPEC_H diff --git a/libcxx/include/__cxx03/__chrono/convert_to_tm.h b/libcxx/include/__cxx03/__chrono/convert_to_tm.h new file mode 100644 index 0000000000000000000000000000000000000000..3a51019b80784a76cbe88bd9c5d26bde2adcf4be --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/convert_to_tm.h @@ -0,0 +1,202 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_CONVERT_TO_TM_H +#define _LIBCPP___CHRONO_CONVERT_TO_TM_H + +#include <__chrono/calendar.h> +#include <__chrono/concepts.h> +#include <__chrono/day.h> +#include <__chrono/duration.h> +#include <__chrono/file_clock.h> +#include <__chrono/hh_mm_ss.h> +#include <__chrono/local_info.h> +#include <__chrono/month.h> +#include <__chrono/month_weekday.h> +#include <__chrono/monthday.h> +#include <__chrono/statically_widen.h> +#include <__chrono/sys_info.h> +#include <__chrono/system_clock.h> +#include <__chrono/time_point.h> +#include <__chrono/weekday.h> +#include <__chrono/year.h> +#include <__chrono/year_month.h> +#include <__chrono/year_month_day.h> +#include <__chrono/year_month_weekday.h> +#include <__chrono/zoned_time.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__format/format_error.h> +#include <__memory/addressof.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_specialization.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// Conerts a chrono date and weekday to a given _Tm type. +// +// This is an implementation detail for the function +// template +// _Tm __convert_to_tm(const _ChronoT& __value) +// +// This manually converts the two values to the proper type. It is possible to +// convert from sys_days to time_t and then to _Tm. But this leads to the Y2K +// bug when time_t is a 32-bit signed integer. Chrono considers years beyond +// the year 2038 valid, so instead do the transformation manually. +template + requires(same_as<_Date, chrono::year_month_day> || same_as<_Date, chrono::year_month_day_last>) +_LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _Date& __date, chrono::weekday __weekday) { + _Tm __result = {}; +# ifdef __GLIBC__ + __result.tm_zone = "UTC"; +# endif + __result.tm_year = static_cast(__date.year()) - 1900; + __result.tm_mon = static_cast(__date.month()) - 1; + __result.tm_mday = static_cast(__date.day()); + __result.tm_wday = static_cast(__weekday.c_encoding()); + __result.tm_yday = + (static_cast(__date) - + static_cast(chrono::year_month_day{__date.year(), chrono::January, chrono::day{1}})) + .count(); + + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const chrono::sys_time<_Duration> __tp) { + chrono::sys_days __days = chrono::floor(__tp); + chrono::year_month_day __ymd{__days}; + + _Tm __result = std::__convert_to_tm<_Tm>(chrono::year_month_day{__ymd}, chrono::weekday{__days}); + + uint64_t __sec = + chrono::duration_cast(__tp - chrono::time_point_cast(__days)).count(); + __sec %= 24 * 3600; + __result.tm_hour = __sec / 3600; + __sec %= 3600; + __result.tm_min = __sec / 60; + __result.tm_sec = __sec % 60; + + return __result; +} + +// Convert a chrono (calendar) time point, or dururation to the given _Tm type, +// which must have the same properties as std::tm. +template +_LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _ChronoT& __value) { + _Tm __result = {}; +# ifdef __GLIBC__ + __result.tm_zone = "UTC"; +# endif + + if constexpr (__is_time_point<_ChronoT>) { + if constexpr (same_as) + return std::__convert_to_tm<_Tm>(__value); + else if constexpr (same_as) + return std::__convert_to_tm<_Tm>(_ChronoT::clock::to_sys(__value)); + else if constexpr (same_as) + return std::__convert_to_tm<_Tm>(chrono::sys_time{__value.time_since_epoch()}); + else + static_assert(sizeof(_ChronoT) == 0, "TODO: Add the missing clock specialization"); + } else if constexpr (chrono::__is_duration<_ChronoT>::value) { + // [time.format]/6 + // ... However, if a flag refers to a "time of day" (e.g. %H, %I, %p, + // etc.), then a specialization of duration is interpreted as the time of + // day elapsed since midnight. + + // Not all values can be converted to hours, it may run into ratio + // conversion errors. In that case the conversion to seconds works. + if constexpr (is_convertible_v<_ChronoT, chrono::hours>) { + auto __hour = chrono::floor(__value); + auto __sec = chrono::duration_cast(__value - __hour); + __result.tm_hour = __hour.count() % 24; + __result.tm_min = __sec.count() / 60; + __result.tm_sec = __sec.count() % 60; + } else { + uint64_t __sec = chrono::duration_cast(__value).count(); + __sec %= 24 * 3600; + __result.tm_hour = __sec / 3600; + __sec %= 3600; + __result.tm_min = __sec / 60; + __result.tm_sec = __sec % 60; + } + } else if constexpr (same_as<_ChronoT, chrono::day>) + __result.tm_mday = static_cast(__value); + else if constexpr (same_as<_ChronoT, chrono::month>) + __result.tm_mon = static_cast(__value) - 1; + else if constexpr (same_as<_ChronoT, chrono::year>) + __result.tm_year = static_cast(__value) - 1900; + else if constexpr (same_as<_ChronoT, chrono::weekday>) + __result.tm_wday = __value.c_encoding(); + else if constexpr (same_as<_ChronoT, chrono::weekday_indexed> || same_as<_ChronoT, chrono::weekday_last>) + __result.tm_wday = __value.weekday().c_encoding(); + else if constexpr (same_as<_ChronoT, chrono::month_day>) { + __result.tm_mday = static_cast(__value.day()); + __result.tm_mon = static_cast(__value.month()) - 1; + } else if constexpr (same_as<_ChronoT, chrono::month_day_last>) { + __result.tm_mon = static_cast(__value.month()) - 1; + } else if constexpr (same_as<_ChronoT, chrono::month_weekday> || same_as<_ChronoT, chrono::month_weekday_last>) { + __result.tm_wday = __value.weekday_indexed().weekday().c_encoding(); + __result.tm_mon = static_cast(__value.month()) - 1; + } else if constexpr (same_as<_ChronoT, chrono::year_month>) { + __result.tm_year = static_cast(__value.year()) - 1900; + __result.tm_mon = static_cast(__value.month()) - 1; + } else if constexpr (same_as<_ChronoT, chrono::year_month_day> || same_as<_ChronoT, chrono::year_month_day_last>) { + return std::__convert_to_tm<_Tm>( + chrono::year_month_day{__value}, chrono::weekday{static_cast(__value)}); + } else if constexpr (same_as<_ChronoT, chrono::year_month_weekday> || + same_as<_ChronoT, chrono::year_month_weekday_last>) { + return std::__convert_to_tm<_Tm>(chrono::year_month_day{static_cast(__value)}, __value.weekday()); + } else if constexpr (__is_hh_mm_ss<_ChronoT>) { + __result.tm_sec = __value.seconds().count(); + __result.tm_min = __value.minutes().count(); + // In libc++ hours is stored as a long. The type in std::tm is an int. So + // the overflow can only occur when hour uses more bits than an int + // provides. + if constexpr (sizeof(std::chrono::hours::rep) > sizeof(__result.tm_hour)) + if (__value.hours().count() > std::numeric_limits::max()) + std::__throw_format_error("Formatting hh_mm_ss, encountered an hour overflow"); + __result.tm_hour = __value.hours().count(); +# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + } else if constexpr (same_as<_ChronoT, chrono::sys_info>) { + // Has no time information. + } else if constexpr (same_as<_ChronoT, chrono::local_info>) { + // Has no time information. +# if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ + !defined(_LIBCPP_HAS_NO_LOCALIZATION) + } else if constexpr (__is_specialization_v<_ChronoT, chrono::zoned_time>) { + return std::__convert_to_tm<_Tm>( + chrono::sys_time{__value.get_local_time().time_since_epoch()}); +# endif +# endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + } else + static_assert(sizeof(_ChronoT) == 0, "Add the missing type specialization"); + + return __result; +} + +#endif // if _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___CHRONO_CONVERT_TO_TM_H diff --git a/libcxx/include/__cxx03/__chrono/day.h b/libcxx/include/__cxx03/__chrono/day.h new file mode 100644 index 0000000000000000000000000000000000000000..7342084b08c8865a095e29396ad1486773b39825 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/day.h @@ -0,0 +1,99 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_DAY_H +#define _LIBCPP___CHRONO_DAY_H + +#include <__chrono/duration.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +class day { +private: + unsigned char __d_; + +public: + day() = default; + _LIBCPP_HIDE_FROM_ABI explicit inline constexpr day(unsigned __val) noexcept + : __d_(static_cast(__val)) {} + _LIBCPP_HIDE_FROM_ABI inline constexpr day& operator++() noexcept { + ++__d_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr day operator++(int) noexcept { + day __tmp = *this; + ++(*this); + return __tmp; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr day& operator--() noexcept { + --__d_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr day operator--(int) noexcept { + day __tmp = *this; + --(*this); + return __tmp; + } + _LIBCPP_HIDE_FROM_ABI constexpr day& operator+=(const days& __dd) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr day& operator-=(const days& __dd) noexcept; + _LIBCPP_HIDE_FROM_ABI explicit inline constexpr operator unsigned() const noexcept { return __d_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr bool ok() const noexcept { return __d_ >= 1 && __d_ <= 31; } +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const day& __lhs, const day& __rhs) noexcept { + return static_cast(__lhs) == static_cast(__rhs); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(const day& __lhs, const day& __rhs) noexcept { + return static_cast(__lhs) <=> static_cast(__rhs); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr day operator+(const day& __lhs, const days& __rhs) noexcept { + return day(static_cast(__lhs) + __rhs.count()); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr day operator+(const days& __lhs, const day& __rhs) noexcept { + return __rhs + __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr day operator-(const day& __lhs, const days& __rhs) noexcept { + return __lhs + -__rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr days operator-(const day& __lhs, const day& __rhs) noexcept { + return days(static_cast(static_cast(__lhs)) - static_cast(static_cast(__rhs))); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr day& day::operator+=(const days& __dd) noexcept { + *this = *this + __dd; + return *this; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr day& day::operator-=(const days& __dd) noexcept { + *this = *this - __dd; + return *this; +} + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___CHRONO_DAY_H diff --git a/libcxx/include/__cxx03/__chrono/duration.h b/libcxx/include/__cxx03/__chrono/duration.h new file mode 100644 index 0000000000000000000000000000000000000000..1e36d7342836f643c59eaee262f741576dbe6344 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/duration.h @@ -0,0 +1,550 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_DURATION_H +#define _LIBCPP___CHRONO_DURATION_H + +#include <__compare/ordering.h> +#include <__compare/three_way_comparable.h> +#include <__config> +#include <__type_traits/common_type.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_floating_point.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +template > +class _LIBCPP_TEMPLATE_VIS duration; + +template +struct __is_duration : false_type {}; + +template +struct __is_duration > : true_type {}; + +template +struct __is_duration > : true_type {}; + +template +struct __is_duration > : true_type {}; + +template +struct __is_duration > : true_type {}; + +} // namespace chrono + +template +struct _LIBCPP_TEMPLATE_VIS common_type, chrono::duration<_Rep2, _Period2> > { + typedef chrono::duration::type, typename __ratio_gcd<_Period1, _Period2>::type> + type; +}; + +namespace chrono { + +// duration_cast + +template ::type, + bool = _Period::num == 1, + bool = _Period::den == 1> +struct __duration_cast; + +template +struct __duration_cast<_FromDuration, _ToDuration, _Period, true, true> { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration operator()(const _FromDuration& __fd) const { + return _ToDuration(static_cast(__fd.count())); + } +}; + +template +struct __duration_cast<_FromDuration, _ToDuration, _Period, true, false> { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration operator()(const _FromDuration& __fd) const { + typedef typename common_type::type _Ct; + return _ToDuration( + static_cast(static_cast<_Ct>(__fd.count()) / static_cast<_Ct>(_Period::den))); + } +}; + +template +struct __duration_cast<_FromDuration, _ToDuration, _Period, false, true> { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration operator()(const _FromDuration& __fd) const { + typedef typename common_type::type _Ct; + return _ToDuration( + static_cast(static_cast<_Ct>(__fd.count()) * static_cast<_Ct>(_Period::num))); + } +}; + +template +struct __duration_cast<_FromDuration, _ToDuration, _Period, false, false> { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration operator()(const _FromDuration& __fd) const { + typedef typename common_type::type _Ct; + return _ToDuration(static_cast( + static_cast<_Ct>(__fd.count()) * static_cast<_Ct>(_Period::num) / static_cast<_Ct>(_Period::den))); + } +}; + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration duration_cast(const duration<_Rep, _Period>& __fd) { + return __duration_cast, _ToDuration>()(__fd); +} + +template +struct _LIBCPP_TEMPLATE_VIS treat_as_floating_point : is_floating_point<_Rep> {}; + +#if _LIBCPP_STD_VER >= 17 +template +inline constexpr bool treat_as_floating_point_v = treat_as_floating_point<_Rep>::value; +#endif + +template +struct _LIBCPP_TEMPLATE_VIS duration_values { +public: + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep zero() _NOEXCEPT { return _Rep(0); } + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep max() _NOEXCEPT { return numeric_limits<_Rep>::max(); } + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep min() _NOEXCEPT { return numeric_limits<_Rep>::lowest(); } +}; + +#if _LIBCPP_STD_VER >= 17 +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration floor(const duration<_Rep, _Period>& __d) { + _ToDuration __t = chrono::duration_cast<_ToDuration>(__d); + if (__t > __d) + __t = __t - _ToDuration{1}; + return __t; +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration ceil(const duration<_Rep, _Period>& __d) { + _ToDuration __t = chrono::duration_cast<_ToDuration>(__d); + if (__t < __d) + __t = __t + _ToDuration{1}; + return __t; +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration round(const duration<_Rep, _Period>& __d) { + _ToDuration __lower = chrono::floor<_ToDuration>(__d); + _ToDuration __upper = __lower + _ToDuration{1}; + auto __lower_diff = __d - __lower; + auto __upper_diff = __upper - __d; + if (__lower_diff < __upper_diff) + return __lower; + if (__lower_diff > __upper_diff) + return __upper; + return __lower.count() & 1 ? __upper : __lower; +} +#endif + +// duration + +template +class _LIBCPP_TEMPLATE_VIS duration { + static_assert(!__is_duration<_Rep>::value, "A duration representation can not be a duration"); + static_assert(__is_ratio<_Period>::value, "Second template parameter of duration must be a std::ratio"); + static_assert(_Period::num > 0, "duration period must be positive"); + + template + struct __no_overflow { + private: + static const intmax_t __gcd_n1_n2 = __static_gcd<_R1::num, _R2::num>::value; + static const intmax_t __gcd_d1_d2 = __static_gcd<_R1::den, _R2::den>::value; + static const intmax_t __n1 = _R1::num / __gcd_n1_n2; + static const intmax_t __d1 = _R1::den / __gcd_d1_d2; + static const intmax_t __n2 = _R2::num / __gcd_n1_n2; + static const intmax_t __d2 = _R2::den / __gcd_d1_d2; + static const intmax_t max = -((intmax_t(1) << (sizeof(intmax_t) * CHAR_BIT - 1)) + 1); + + template + struct __mul // __overflow == false + { + static const intmax_t value = _Xp * _Yp; + }; + + template + struct __mul<_Xp, _Yp, true> { + static const intmax_t value = 1; + }; + + public: + static const bool value = (__n1 <= max / __d2) && (__n2 <= max / __d1); + typedef ratio<__mul<__n1, __d2, !value>::value, __mul<__n2, __d1, !value>::value> type; + }; + +public: + typedef _Rep rep; + typedef typename _Period::type period; + +private: + rep __rep_; + +public: +#ifndef _LIBCPP_CXX03_LANG + constexpr duration() = default; +#else + _LIBCPP_HIDE_FROM_ABI duration() {} +#endif + + template ::value && + (treat_as_floating_point::value || !treat_as_floating_point<_Rep2>::value), + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit duration(const _Rep2& __r) : __rep_(__r) {} + + // conversions + template ::value && (treat_as_floating_point::value || + (__no_overflow<_Period2, period>::type::den == 1 && + !treat_as_floating_point<_Rep2>::value)), + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration(const duration<_Rep2, _Period2>& __d) + : __rep_(chrono::duration_cast(__d).count()) {} + + // observer + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR rep count() const { return __rep_; } + + // arithmetic + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type::type operator+() const { + return typename common_type::type(*this); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type::type operator-() const { + return typename common_type::type(-__rep_); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 duration& operator++() { + ++__rep_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 duration operator++(int) { return duration(__rep_++); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 duration& operator--() { + --__rep_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 duration operator--(int) { return duration(__rep_--); } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 duration& operator+=(const duration& __d) { + __rep_ += __d.count(); + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 duration& operator-=(const duration& __d) { + __rep_ -= __d.count(); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 duration& operator*=(const rep& __rhs) { + __rep_ *= __rhs; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 duration& operator/=(const rep& __rhs) { + __rep_ /= __rhs; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 duration& operator%=(const rep& __rhs) { + __rep_ %= __rhs; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 duration& operator%=(const duration& __rhs) { + __rep_ %= __rhs.count(); + return *this; + } + + // special values + + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration zero() _NOEXCEPT { + return duration(duration_values::zero()); + } + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration min() _NOEXCEPT { + return duration(duration_values::min()); + } + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration max() _NOEXCEPT { + return duration(duration_values::max()); + } +}; + +typedef duration nanoseconds; +typedef duration microseconds; +typedef duration milliseconds; +typedef duration seconds; +typedef duration< long, ratio< 60> > minutes; +typedef duration< long, ratio<3600> > hours; +#if _LIBCPP_STD_VER >= 20 +typedef duration< int, ratio_multiply, hours::period>> days; +typedef duration< int, ratio_multiply, days::period>> weeks; +typedef duration< int, ratio_multiply, days::period>> years; +typedef duration< int, ratio_divide>> months; +#endif +// Duration == + +template +struct __duration_eq { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator()(const _LhsDuration& __lhs, const _RhsDuration& __rhs) const { + typedef typename common_type<_LhsDuration, _RhsDuration>::type _Ct; + return _Ct(__lhs).count() == _Ct(__rhs).count(); + } +}; + +template +struct __duration_eq<_LhsDuration, _LhsDuration> { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator()(const _LhsDuration& __lhs, const _LhsDuration& __rhs) const { + return __lhs.count() == __rhs.count(); + } +}; + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator==(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { + return __duration_eq, duration<_Rep2, _Period2> >()(__lhs, __rhs); +} + +#if _LIBCPP_STD_VER <= 17 + +// Duration != + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator!=(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { + return !(__lhs == __rhs); +} + +#endif // _LIBCPP_STD_VER <= 17 + +// Duration < + +template +struct __duration_lt { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator()(const _LhsDuration& __lhs, const _RhsDuration& __rhs) const { + typedef typename common_type<_LhsDuration, _RhsDuration>::type _Ct; + return _Ct(__lhs).count() < _Ct(__rhs).count(); + } +}; + +template +struct __duration_lt<_LhsDuration, _LhsDuration> { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator()(const _LhsDuration& __lhs, const _LhsDuration& __rhs) const { + return __lhs.count() < __rhs.count(); + } +}; + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator<(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { + return __duration_lt, duration<_Rep2, _Period2> >()(__lhs, __rhs); +} + +// Duration > + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator>(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { + return __rhs < __lhs; +} + +// Duration <= + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator<=(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { + return !(__rhs < __lhs); +} + +// Duration >= + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator>=(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { + return !(__lhs < __rhs); +} + +#if _LIBCPP_STD_VER >= 20 + +template + requires three_way_comparable> +_LIBCPP_HIDE_FROM_ABI constexpr auto +operator<=>(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { + using _Ct = common_type_t, duration<_Rep2, _Period2>>; + return _Ct(__lhs).count() <=> _Ct(__rhs).count(); +} + +#endif // _LIBCPP_STD_VER >= 20 + +// Duration + + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR +typename common_type, duration<_Rep2, _Period2> >::type +operator+(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { + typedef typename common_type, duration<_Rep2, _Period2> >::type _Cd; + return _Cd(_Cd(__lhs).count() + _Cd(__rhs).count()); +} + +// Duration - + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR +typename common_type, duration<_Rep2, _Period2> >::type +operator-(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { + typedef typename common_type, duration<_Rep2, _Period2> >::type _Cd; + return _Cd(_Cd(__lhs).count() - _Cd(__rhs).count()); +} + +// Duration * + +template ::type>::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration::type, _Period> +operator*(const duration<_Rep1, _Period>& __d, const _Rep2& __s) { + typedef typename common_type<_Rep1, _Rep2>::type _Cr; + typedef duration<_Cr, _Period> _Cd; + return _Cd(_Cd(__d).count() * static_cast<_Cr>(__s)); +} + +template ::type>::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration::type, _Period> +operator*(const _Rep1& __s, const duration<_Rep2, _Period>& __d) { + return __d * __s; +} + +// Duration / + +template ::value && + is_convertible::type>::value, + int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration::type, _Period> +operator/(const duration<_Rep1, _Period>& __d, const _Rep2& __s) { + typedef typename common_type<_Rep1, _Rep2>::type _Cr; + typedef duration<_Cr, _Period> _Cd; + return _Cd(_Cd(__d).count() / static_cast<_Cr>(__s)); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<_Rep1, _Rep2>::type +operator/(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { + typedef typename common_type, duration<_Rep2, _Period2> >::type _Ct; + return _Ct(__lhs).count() / _Ct(__rhs).count(); +} + +// Duration % + +template ::value && + is_convertible::type>::value, + int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration::type, _Period> +operator%(const duration<_Rep1, _Period>& __d, const _Rep2& __s) { + typedef typename common_type<_Rep1, _Rep2>::type _Cr; + typedef duration<_Cr, _Period> _Cd; + return _Cd(_Cd(__d).count() % static_cast<_Cr>(__s)); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR +typename common_type, duration<_Rep2, _Period2> >::type +operator%(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { + typedef typename common_type<_Rep1, _Rep2>::type _Cr; + typedef typename common_type, duration<_Rep2, _Period2> >::type _Cd; + return _Cd(static_cast<_Cr>(_Cd(__lhs).count()) % static_cast<_Cr>(_Cd(__rhs).count())); +} + +} // namespace chrono + +#if _LIBCPP_STD_VER >= 14 +// Suffixes for duration literals [time.duration.literals] +inline namespace literals { +inline namespace chrono_literals { + +_LIBCPP_HIDE_FROM_ABI constexpr chrono::hours operator""h(unsigned long long __h) { + return chrono::hours(static_cast(__h)); +} + +_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration> operator""h(long double __h) { + return chrono::duration>(__h); +} + +_LIBCPP_HIDE_FROM_ABI constexpr chrono::minutes operator""min(unsigned long long __m) { + return chrono::minutes(static_cast(__m)); +} + +_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration> operator""min(long double __m) { + return chrono::duration>(__m); +} + +_LIBCPP_HIDE_FROM_ABI constexpr chrono::seconds operator""s(unsigned long long __s) { + return chrono::seconds(static_cast(__s)); +} + +_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration operator""s(long double __s) { + return chrono::duration(__s); +} + +_LIBCPP_HIDE_FROM_ABI constexpr chrono::milliseconds operator""ms(unsigned long long __ms) { + return chrono::milliseconds(static_cast(__ms)); +} + +_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration operator""ms(long double __ms) { + return chrono::duration(__ms); +} + +_LIBCPP_HIDE_FROM_ABI constexpr chrono::microseconds operator""us(unsigned long long __us) { + return chrono::microseconds(static_cast(__us)); +} + +_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration operator""us(long double __us) { + return chrono::duration(__us); +} + +_LIBCPP_HIDE_FROM_ABI constexpr chrono::nanoseconds operator""ns(unsigned long long __ns) { + return chrono::nanoseconds(static_cast(__ns)); +} + +_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration operator""ns(long double __ns) { + return chrono::duration(__ns); +} + +} // namespace chrono_literals +} // namespace literals + +namespace chrono { // hoist the literals into namespace std::chrono +using namespace literals::chrono_literals; +} // namespace chrono + +#endif // _LIBCPP_STD_VER >= 14 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 +# include +#endif + +#endif // _LIBCPP___CHRONO_DURATION_H diff --git a/libcxx/include/__cxx03/__chrono/exception.h b/libcxx/include/__cxx03/__chrono/exception.h new file mode 100644 index 0000000000000000000000000000000000000000..266f8fac441760672b982777ed5607c220b09998 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/exception.h @@ -0,0 +1,135 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#ifndef _LIBCPP___CHRONO_EXCEPTION_H +#define _LIBCPP___CHRONO_EXCEPTION_H + +#include +// Enable the contents of the header only when libc++ was built with experimental features enabled. +#if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +# include <__chrono/calendar.h> +# include <__chrono/local_info.h> +# include <__chrono/time_point.h> +# include <__config> +# include <__configuration/availability.h> +# include <__verbose_abort> +# include +# include +# include + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 20 + +namespace chrono { + +class nonexistent_local_time : public runtime_error { +public: + template + _LIBCPP_HIDE_FROM_ABI nonexistent_local_time(const local_time<_Duration>& __time, const local_info& __info) + : runtime_error{__create_message(__time, __info)} { + // [time.zone.exception.nonexist]/2 + // Preconditions: i.result == local_info::nonexistent is true. + // The value of __info.result is not used. + _LIBCPP_ASSERT_PEDANTIC(__info.result == local_info::nonexistent, + "creating an nonexistent_local_time from a local_info that is not non-existent"); + } + + _LIBCPP_HIDE_FROM_ABI nonexistent_local_time(const nonexistent_local_time&) = default; + _LIBCPP_HIDE_FROM_ABI nonexistent_local_time& operator=(const nonexistent_local_time&) = default; + + _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI ~nonexistent_local_time() override; // exported as key function + +private: + template + _LIBCPP_HIDE_FROM_ABI string __create_message(const local_time<_Duration>& __time, const local_info& __info) { + return std::format( + R"({} is in a gap between +{} {} and +{} {} which are both equivalent to +{} UTC)", + __time, + local_seconds{__info.first.end.time_since_epoch()} + __info.first.offset, + __info.first.abbrev, + local_seconds{__info.second.begin.time_since_epoch()} + __info.second.offset, + __info.second.abbrev, + __info.first.end); + } +}; + +template +_LIBCPP_NORETURN _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI void __throw_nonexistent_local_time( + [[maybe_unused]] const local_time<_Duration>& __time, [[maybe_unused]] const local_info& __info) { +# ifndef _LIBCPP_HAS_NO_EXCEPTIONS + throw nonexistent_local_time(__time, __info); +# else + _LIBCPP_VERBOSE_ABORT("nonexistent_local_time was thrown in -fno-exceptions mode"); +# endif +} + +class ambiguous_local_time : public runtime_error { +public: + template + _LIBCPP_HIDE_FROM_ABI ambiguous_local_time(const local_time<_Duration>& __time, const local_info& __info) + : runtime_error{__create_message(__time, __info)} { + // [time.zone.exception.ambig]/2 + // Preconditions: i.result == local_info::ambiguous is true. + // The value of __info.result is not used. + _LIBCPP_ASSERT_PEDANTIC(__info.result == local_info::ambiguous, + "creating an ambiguous_local_time from a local_info that is not ambiguous"); + } + + _LIBCPP_HIDE_FROM_ABI ambiguous_local_time(const ambiguous_local_time&) = default; + _LIBCPP_HIDE_FROM_ABI ambiguous_local_time& operator=(const ambiguous_local_time&) = default; + + _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI ~ambiguous_local_time() override; // exported as key function + +private: + template + _LIBCPP_HIDE_FROM_ABI string __create_message(const local_time<_Duration>& __time, const local_info& __info) { + return std::format( + // There are two spaces after the full-stop; this has been verified + // in the sources of the Standard. + R"({0} is ambiguous. It could be +{0} {1} == {2} UTC or +{0} {3} == {4} UTC)", + __time, + __info.first.abbrev, + __time - __info.first.offset, + __info.second.abbrev, + __time - __info.second.offset); + } +}; + +template +_LIBCPP_NORETURN _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI void __throw_ambiguous_local_time( + [[maybe_unused]] const local_time<_Duration>& __time, [[maybe_unused]] const local_info& __info) { +# ifndef _LIBCPP_HAS_NO_EXCEPTIONS + throw ambiguous_local_time(__time, __info); +# else + _LIBCPP_VERBOSE_ABORT("ambiguous_local_time was thrown in -fno-exceptions mode"); +# endif +} + +} // namespace chrono + +# endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +#endif // _LIBCPP___CHRONO_EXCEPTION_H diff --git a/libcxx/include/__cxx03/__chrono/file_clock.h b/libcxx/include/__cxx03/__chrono/file_clock.h new file mode 100644 index 0000000000000000000000000000000000000000..4dd3f88ce5ba4bf499316539bec89ea75b5a75a9 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/file_clock.h @@ -0,0 +1,80 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_FILE_CLOCK_H +#define _LIBCPP___CHRONO_FILE_CLOCK_H + +#include <__chrono/duration.h> +#include <__chrono/system_clock.h> +#include <__chrono/time_point.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#ifndef _LIBCPP_CXX03_LANG +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM +struct _FilesystemClock; +_LIBCPP_END_NAMESPACE_FILESYSTEM +#endif // !_LIBCPP_CXX03_LANG + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +// [time.clock.file], type file_clock +using file_clock = filesystem::_FilesystemClock; + +template +using file_time = time_point; + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#ifndef _LIBCPP_CXX03_LANG +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM +struct _FilesystemClock { +# if !defined(_LIBCPP_HAS_NO_INT128) + typedef __int128_t rep; + typedef nano period; +# else + typedef long long rep; + typedef nano period; +# endif + + typedef chrono::duration duration; + typedef chrono::time_point<_FilesystemClock> time_point; + + _LIBCPP_EXPORTED_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 const bool is_steady = false; + + _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_EXPORTED_FROM_ABI static time_point now() noexcept; + +# if _LIBCPP_STD_VER >= 20 + template + _LIBCPP_HIDE_FROM_ABI static chrono::sys_time<_Duration> to_sys(const chrono::file_time<_Duration>& __t) { + return chrono::sys_time<_Duration>(__t.time_since_epoch()); + } + + template + _LIBCPP_HIDE_FROM_ABI static chrono::file_time<_Duration> from_sys(const chrono::sys_time<_Duration>& __t) { + return chrono::file_time<_Duration>(__t.time_since_epoch()); + } +# endif // _LIBCPP_STD_VER >= 20 +}; +_LIBCPP_END_NAMESPACE_FILESYSTEM +#endif // !_LIBCPP_CXX03_LANG + +#endif // _LIBCPP___CHRONO_FILE_CLOCK_H diff --git a/libcxx/include/__cxx03/__chrono/formatter.h b/libcxx/include/__cxx03/__chrono/formatter.h new file mode 100644 index 0000000000000000000000000000000000000000..449c415e957602af0cf140b6445bb9b44fe53e20 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/formatter.h @@ -0,0 +1,990 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_FORMATTER_H +#define _LIBCPP___CHRONO_FORMATTER_H + +#include <__algorithm/ranges_copy.h> +#include <__chrono/calendar.h> +#include <__chrono/concepts.h> +#include <__chrono/convert_to_tm.h> +#include <__chrono/day.h> +#include <__chrono/duration.h> +#include <__chrono/file_clock.h> +#include <__chrono/hh_mm_ss.h> +#include <__chrono/local_info.h> +#include <__chrono/month.h> +#include <__chrono/month_weekday.h> +#include <__chrono/monthday.h> +#include <__chrono/ostream.h> +#include <__chrono/parser_std_format_spec.h> +#include <__chrono/statically_widen.h> +#include <__chrono/sys_info.h> +#include <__chrono/system_clock.h> +#include <__chrono/time_point.h> +#include <__chrono/weekday.h> +#include <__chrono/year.h> +#include <__chrono/year_month.h> +#include <__chrono/year_month_day.h> +#include <__chrono/year_month_weekday.h> +#include <__chrono/zoned_time.h> +#include <__concepts/arithmetic.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__format/concepts.h> +#include <__format/format_error.h> +#include <__format/format_functions.h> +#include <__format/format_parse_context.h> +#include <__format/formatter.h> +#include <__format/parser_std_format_spec.h> +#include <__format/write_escaped.h> +#include <__memory/addressof.h> +#include <__type_traits/is_specialization.h> +#include +#include +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __formatter { + +/// Formats a time based on a tm struct. +/// +/// This formatter passes the formatting to time_put which uses strftime. When +/// the value is outside the valid range it's unspecified what strftime will +/// output. For example weekday 8 can print 1 when the day is processed modulo +/// 7 since that handles the Sunday for 0-based weekday. It can also print 8 if +/// 7 is handled as a special case. +/// +/// The Standard doesn't specify what to do in this case so the result depends +/// on the result of the underlying code. +/// +/// \pre When the (abbreviated) weekday or month name are used, the caller +/// validates whether the value is valid. So the caller handles that +/// requirement of Table 97: Meaning of conversion specifiers +/// [tab:time.format.spec]. +/// +/// When no chrono-specs are provided it uses the stream formatter. + +// For tiny ratios it's not possible to convert a duration to a hh_mm_ss. This +// fails compile-time due to the limited precision of the ratio (64-bit is too +// small). Therefore a duration uses its own conversion. +template +_LIBCPP_HIDE_FROM_ABI void +__format_sub_seconds(basic_stringstream<_CharT>& __sstr, const chrono::duration<_Rep, _Period>& __value) { + __sstr << std::use_facet>(__sstr.getloc()).decimal_point(); + + using __duration = chrono::duration<_Rep, _Period>; + + auto __fraction = __value - chrono::duration_cast(__value); + // Converts a negative fraction to its positive value. + if (__value < chrono::seconds{0} && __fraction != __duration{0}) + __fraction += chrono::seconds{1}; + if constexpr (chrono::treat_as_floating_point_v<_Rep>) + // When the floating-point value has digits itself they are ignored based + // on the wording in [tab:time.format.spec] + // If the precision of the input cannot be exactly represented with + // seconds, then the format is a decimal floating-point number with a + // fixed format and a precision matching that of the precision of the + // input (or to a microseconds precision if the conversion to + // floating-point decimal seconds cannot be made within 18 fractional + // digits). + // + // This matches the behaviour of MSVC STL, fmtlib interprets this + // differently and uses 3 decimals. + // https://godbolt.org/z/6dsbnW8ba + std::format_to(std::ostreambuf_iterator<_CharT>{__sstr}, + _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}.0f}"), + chrono::duration_cast::precision>(__fraction).count(), + chrono::hh_mm_ss<__duration>::fractional_width); + else + std::format_to(std::ostreambuf_iterator<_CharT>{__sstr}, + _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}}"), + chrono::duration_cast::precision>(__fraction).count(), + chrono::hh_mm_ss<__duration>::fractional_width); +} + +template +_LIBCPP_HIDE_FROM_ABI void __format_sub_seconds(basic_stringstream<_CharT>& __sstr, const _Tp& __value) { + __formatter::__format_sub_seconds(__sstr, __value.time_since_epoch()); +} + +template +_LIBCPP_HIDE_FROM_ABI void +__format_sub_seconds(basic_stringstream<_CharT>& __sstr, const chrono::hh_mm_ss<_Duration>& __value) { + __sstr << std::use_facet>(__sstr.getloc()).decimal_point(); + if constexpr (chrono::treat_as_floating_point_v) + std::format_to(std::ostreambuf_iterator<_CharT>{__sstr}, + _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}.0f}"), + __value.subseconds().count(), + __value.fractional_width); + else + std::format_to(std::ostreambuf_iterator<_CharT>{__sstr}, + _LIBCPP_STATICALLY_WIDEN(_CharT, "{:0{}}"), + __value.subseconds().count(), + __value.fractional_width); +} + +# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && \ + !defined(_LIBCPP_HAS_NO_FILESYSTEM) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +template +_LIBCPP_HIDE_FROM_ABI void +__format_sub_seconds(basic_stringstream<_CharT>& __sstr, const chrono::zoned_time<_Duration, _TimeZonePtr>& __value) { + __formatter::__format_sub_seconds(__sstr, __value.get_local_time().time_since_epoch()); +} +# endif + +template +consteval bool __use_fraction() { + if constexpr (__is_time_point<_Tp>) + return chrono::hh_mm_ss::fractional_width; +# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && \ + !defined(_LIBCPP_HAS_NO_FILESYSTEM) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) + else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) + return chrono::hh_mm_ss::fractional_width; +# endif + else if constexpr (chrono::__is_duration<_Tp>::value) + return chrono::hh_mm_ss<_Tp>::fractional_width; + else if constexpr (__is_hh_mm_ss<_Tp>) + return _Tp::fractional_width; + else + return false; +} + +template +_LIBCPP_HIDE_FROM_ABI void __format_year(basic_stringstream<_CharT>& __sstr, int __year) { + if (__year < 0) { + __sstr << _CharT('-'); + __year = -__year; + } + + // TODO FMT Write an issue + // If the result has less than four digits it is zero-padded with 0 to two digits. + // is less -> has less + // left-padded -> zero-padded, otherwise the proper value would be 000-0. + + // Note according to the wording it should be left padded, which is odd. + __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:04}"), __year); +} + +template +_LIBCPP_HIDE_FROM_ABI void __format_century(basic_stringstream<_CharT>& __sstr, int __year) { + // TODO FMT Write an issue + // [tab:time.format.spec] + // %C The year divided by 100 using floored division. If the result is a + // single decimal digit, it is prefixed with 0. + + bool __negative = __year < 0; + int __century = (__year - (99 * __negative)) / 100; // floored division + __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), __century); +} + +// Implements the %z format specifier according to [tab:time.format.spec], where +// '__modifier' signals %Oz or %Ez were used. (Both modifiers behave the same, +// so there is no need to distinguish between them.) +template +_LIBCPP_HIDE_FROM_ABI void +__format_zone_offset(basic_stringstream<_CharT>& __sstr, chrono::seconds __offset, bool __modifier) { + if (__offset < 0s) { + __sstr << _CharT('-'); + __offset = -__offset; + } else { + __sstr << _CharT('+'); + } + + chrono::hh_mm_ss __hms{__offset}; + std::ostreambuf_iterator<_CharT> __out_it{__sstr}; + // Note HMS does not allow formatting hours > 23, but the offset is not limited to 24H. + std::format_to(__out_it, _LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), __hms.hours().count()); + if (__modifier) + __sstr << _CharT(':'); + std::format_to(__out_it, _LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), __hms.minutes().count()); +} + +// Helper to store the time zone information needed for formatting. +struct _LIBCPP_HIDE_FROM_ABI __time_zone { + // Typically these abbreviations are short and fit in the string's internal + // buffer. + string __abbrev; + chrono::seconds __offset; +}; + +template +_LIBCPP_HIDE_FROM_ABI __time_zone __convert_to_time_zone([[maybe_unused]] const _Tp& __value) { +# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + if constexpr (same_as<_Tp, chrono::sys_info>) + return {__value.abbrev, __value.offset}; +# if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ + !defined(_LIBCPP_HAS_NO_LOCALIZATION) + else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) + return __formatter::__convert_to_time_zone(__value.get_info()); +# endif + else +# endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + return {"UTC", chrono::seconds{0}}; +} + +template +_LIBCPP_HIDE_FROM_ABI void __format_chrono_using_chrono_specs( + basic_stringstream<_CharT>& __sstr, const _Tp& __value, basic_string_view<_CharT> __chrono_specs) { + tm __t = std::__convert_to_tm(__value); + __time_zone __z = __formatter::__convert_to_time_zone(__value); + const auto& __facet = std::use_facet>(__sstr.getloc()); + for (auto __it = __chrono_specs.begin(); __it != __chrono_specs.end(); ++__it) { + if (*__it == _CharT('%')) { + auto __s = __it; + ++__it; + // We only handle the types that can't be directly handled by time_put. + // (as an optimization n, t, and % are also handled directly.) + switch (*__it) { + case _CharT('n'): + __sstr << _CharT('\n'); + break; + case _CharT('t'): + __sstr << _CharT('\t'); + break; + case _CharT('%'): + __sstr << *__it; + break; + + case _CharT('C'): { + // strftime's output is only defined in the range [00, 99]. + int __year = __t.tm_year + 1900; + if (__year < 1000 || __year > 9999) + __formatter::__format_century(__sstr, __year); + else + __facet.put( + {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); + } break; + + case _CharT('j'): + if constexpr (chrono::__is_duration<_Tp>::value) + // Converting a duration where the period has a small ratio to days + // may fail to compile. This due to loss of precision in the + // conversion. In order to avoid that issue convert to seconds as + // an intemediate step. + __sstr << chrono::duration_cast(chrono::duration_cast(__value)).count(); + else + __facet.put( + {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); + break; + + case _CharT('q'): + if constexpr (chrono::__is_duration<_Tp>::value) { + __sstr << chrono::__units_suffix<_CharT, typename _Tp::period>(); + break; + } + __builtin_unreachable(); + + case _CharT('Q'): + // TODO FMT Determine the proper ideas + // - Should it honour the precision? + // - Shoult it honour the locale setting for the separators? + // The wording for Q doesn't use the word locale and the effect of + // precision is unspecified. + // + // MSVC STL ignores precision but uses separator + // FMT honours precision and has a bug for separator + // https://godbolt.org/z/78b7sMxns + if constexpr (chrono::__is_duration<_Tp>::value) { + __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{}"), __value.count()); + break; + } + __builtin_unreachable(); + + case _CharT('S'): + case _CharT('T'): + __facet.put( + {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); + if constexpr (__use_fraction<_Tp>()) + __formatter::__format_sub_seconds(__sstr, __value); + break; + + // Unlike time_put and strftime the formatting library requires %Y + // + // [tab:time.format.spec] + // The year as a decimal number. If the result is less than four digits + // it is left-padded with 0 to four digits. + // + // This means years in the range (-1000, 1000) need manual formatting. + // It's unclear whether %EY needs the same treatment. For example the + // Japanese EY contains the era name and year. This is zero-padded to 2 + // digits in time_put (note that older glibc versions didn't do + // padding.) However most eras won't reach 100 years, let alone 1000. + // So padding to 4 digits seems unwanted for Japanese. + // + // The same applies to %Ex since that too depends on the era. + // + // %x the locale's date representation is currently doesn't handle the + // zero-padding too. + // + // The 4 digits can be implemented better at a later time. On POSIX + // systems the required information can be extracted by nl_langinfo + // https://man7.org/linux/man-pages/man3/nl_langinfo.3.html + // + // Note since year < -1000 is expected to be rare it uses the more + // expensive year routine. + // + // TODO FMT evaluate the comment above. + +# if defined(__GLIBC__) || defined(_AIX) || defined(_WIN32) + case _CharT('y'): + // Glibc fails for negative values, AIX for positive values too. + __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), (std::abs(__t.tm_year + 1900)) % 100); + break; +# endif // defined(__GLIBC__) || defined(_AIX) || defined(_WIN32) + + case _CharT('Y'): + // Depending on the platform's libc the range of supported years is + // limited. Intead of of testing all conditions use the internal + // implementation unconditionally. + __formatter::__format_year(__sstr, __t.tm_year + 1900); + break; + + case _CharT('F'): + // Depending on the platform's libc the range of supported years is + // limited. Instead of testing all conditions use the internal + // implementation unconditionally. + __formatter::__format_year(__sstr, __t.tm_year + 1900); + __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "-{:02}-{:02}"), __t.tm_mon + 1, __t.tm_mday); + break; + + case _CharT('z'): + __formatter::__format_zone_offset(__sstr, __z.__offset, false); + break; + + case _CharT('Z'): + // __abbrev is always a char so the copy may convert. + ranges::copy(__z.__abbrev, std::ostreambuf_iterator<_CharT>{__sstr}); + break; + + case _CharT('O'): + if constexpr (__use_fraction<_Tp>()) { + // Handle OS using the normal representation for the non-fractional + // part. There seems to be no locale information regarding how the + // fractional part should be formatted. + if (*(__it + 1) == 'S') { + ++__it; + __facet.put( + {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); + __formatter::__format_sub_seconds(__sstr, __value); + break; + } + } + + // Oz produces the same output as Ez below. + [[fallthrough]]; + case _CharT('E'): + ++__it; + if (*__it == 'z') { + __formatter::__format_zone_offset(__sstr, __z.__offset, true); + break; + } + [[fallthrough]]; + default: + __facet.put( + {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1)); + break; + } + } else { + __sstr << *__it; + } + } +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_ok(const _Tp& __value) { + if constexpr (__is_time_point<_Tp>) + return true; + else if constexpr (same_as<_Tp, chrono::day>) + return true; + else if constexpr (same_as<_Tp, chrono::month>) + return __value.ok(); + else if constexpr (same_as<_Tp, chrono::year>) + return true; + else if constexpr (same_as<_Tp, chrono::weekday>) + return true; + else if constexpr (same_as<_Tp, chrono::weekday_indexed>) + return true; + else if constexpr (same_as<_Tp, chrono::weekday_last>) + return true; + else if constexpr (same_as<_Tp, chrono::month_day>) + return true; + else if constexpr (same_as<_Tp, chrono::month_day_last>) + return true; + else if constexpr (same_as<_Tp, chrono::month_weekday>) + return true; + else if constexpr (same_as<_Tp, chrono::month_weekday_last>) + return true; + else if constexpr (same_as<_Tp, chrono::year_month>) + return true; + else if constexpr (same_as<_Tp, chrono::year_month_day>) + return __value.ok(); + else if constexpr (same_as<_Tp, chrono::year_month_day_last>) + return __value.ok(); + else if constexpr (same_as<_Tp, chrono::year_month_weekday>) + return __value.weekday().ok(); + else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>) + return __value.weekday().ok(); + else if constexpr (__is_hh_mm_ss<_Tp>) + return true; +# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + else if constexpr (same_as<_Tp, chrono::sys_info>) + return true; + else if constexpr (same_as<_Tp, chrono::local_info>) + return true; +# if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ + !defined(_LIBCPP_HAS_NO_LOCALIZATION) + else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) + return true; +# endif +# endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + else + static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_name_ok(const _Tp& __value) { + if constexpr (__is_time_point<_Tp>) + return true; + else if constexpr (same_as<_Tp, chrono::day>) + return true; + else if constexpr (same_as<_Tp, chrono::month>) + return __value.ok(); + else if constexpr (same_as<_Tp, chrono::year>) + return true; + else if constexpr (same_as<_Tp, chrono::weekday>) + return __value.ok(); + else if constexpr (same_as<_Tp, chrono::weekday_indexed>) + return __value.weekday().ok(); + else if constexpr (same_as<_Tp, chrono::weekday_last>) + return __value.weekday().ok(); + else if constexpr (same_as<_Tp, chrono::month_day>) + return true; + else if constexpr (same_as<_Tp, chrono::month_day_last>) + return true; + else if constexpr (same_as<_Tp, chrono::month_weekday>) + return __value.weekday_indexed().ok(); + else if constexpr (same_as<_Tp, chrono::month_weekday_last>) + return __value.weekday_indexed().ok(); + else if constexpr (same_as<_Tp, chrono::year_month>) + return true; + else if constexpr (same_as<_Tp, chrono::year_month_day>) + return __value.ok(); + else if constexpr (same_as<_Tp, chrono::year_month_day_last>) + return __value.ok(); + else if constexpr (same_as<_Tp, chrono::year_month_weekday>) + return __value.weekday().ok(); + else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>) + return __value.weekday().ok(); + else if constexpr (__is_hh_mm_ss<_Tp>) + return true; +# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + else if constexpr (same_as<_Tp, chrono::sys_info>) + return true; + else if constexpr (same_as<_Tp, chrono::local_info>) + return true; +# if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ + !defined(_LIBCPP_HAS_NO_LOCALIZATION) + else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) + return true; +# endif +# endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + else + static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool __date_ok(const _Tp& __value) { + if constexpr (__is_time_point<_Tp>) + return true; + else if constexpr (same_as<_Tp, chrono::day>) + return true; + else if constexpr (same_as<_Tp, chrono::month>) + return __value.ok(); + else if constexpr (same_as<_Tp, chrono::year>) + return true; + else if constexpr (same_as<_Tp, chrono::weekday>) + return true; + else if constexpr (same_as<_Tp, chrono::weekday_indexed>) + return true; + else if constexpr (same_as<_Tp, chrono::weekday_last>) + return true; + else if constexpr (same_as<_Tp, chrono::month_day>) + return true; + else if constexpr (same_as<_Tp, chrono::month_day_last>) + return true; + else if constexpr (same_as<_Tp, chrono::month_weekday>) + return true; + else if constexpr (same_as<_Tp, chrono::month_weekday_last>) + return true; + else if constexpr (same_as<_Tp, chrono::year_month>) + return true; + else if constexpr (same_as<_Tp, chrono::year_month_day>) + return __value.ok(); + else if constexpr (same_as<_Tp, chrono::year_month_day_last>) + return __value.ok(); + else if constexpr (same_as<_Tp, chrono::year_month_weekday>) + return __value.ok(); + else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>) + return __value.ok(); + else if constexpr (__is_hh_mm_ss<_Tp>) + return true; +# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + else if constexpr (same_as<_Tp, chrono::sys_info>) + return true; + else if constexpr (same_as<_Tp, chrono::local_info>) + return true; +# if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ + !defined(_LIBCPP_HAS_NO_LOCALIZATION) + else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) + return true; +# endif +# endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + else + static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool __month_name_ok(const _Tp& __value) { + if constexpr (__is_time_point<_Tp>) + return true; + else if constexpr (same_as<_Tp, chrono::day>) + return true; + else if constexpr (same_as<_Tp, chrono::month>) + return __value.ok(); + else if constexpr (same_as<_Tp, chrono::year>) + return true; + else if constexpr (same_as<_Tp, chrono::weekday>) + return true; + else if constexpr (same_as<_Tp, chrono::weekday_indexed>) + return true; + else if constexpr (same_as<_Tp, chrono::weekday_last>) + return true; + else if constexpr (same_as<_Tp, chrono::month_day>) + return __value.month().ok(); + else if constexpr (same_as<_Tp, chrono::month_day_last>) + return __value.month().ok(); + else if constexpr (same_as<_Tp, chrono::month_weekday>) + return __value.month().ok(); + else if constexpr (same_as<_Tp, chrono::month_weekday_last>) + return __value.month().ok(); + else if constexpr (same_as<_Tp, chrono::year_month>) + return __value.month().ok(); + else if constexpr (same_as<_Tp, chrono::year_month_day>) + return __value.month().ok(); + else if constexpr (same_as<_Tp, chrono::year_month_day_last>) + return __value.month().ok(); + else if constexpr (same_as<_Tp, chrono::year_month_weekday>) + return __value.month().ok(); + else if constexpr (same_as<_Tp, chrono::year_month_weekday_last>) + return __value.month().ok(); + else if constexpr (__is_hh_mm_ss<_Tp>) + return true; +# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + else if constexpr (same_as<_Tp, chrono::sys_info>) + return true; + else if constexpr (same_as<_Tp, chrono::local_info>) + return true; +# if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ + !defined(_LIBCPP_HAS_NO_LOCALIZATION) + else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>) + return true; +# endif +# endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + else + static_assert(sizeof(_Tp) == 0, "Add the missing type specialization"); +} + +template +_LIBCPP_HIDE_FROM_ABI auto +__format_chrono(const _Tp& __value, + _FormatContext& __ctx, + __format_spec::__parsed_specifications<_CharT> __specs, + basic_string_view<_CharT> __chrono_specs) { + basic_stringstream<_CharT> __sstr; + // [time.format]/2 + // 2.1 - the "C" locale if the L option is not present in chrono-format-spec, otherwise + // 2.2 - the locale passed to the formatting function if any, otherwise + // 2.3 - the global locale. + // Note that the __ctx's locale() call does 2.2 and 2.3. + if (__specs.__chrono_.__locale_specific_form_) + __sstr.imbue(__ctx.locale()); + else + __sstr.imbue(locale::classic()); + + if (__chrono_specs.empty()) + __sstr << __value; + else { + if constexpr (chrono::__is_duration<_Tp>::value) { + // A duration can be a user defined arithmetic type. Users may specialize + // numeric_limits, but they may not specialize is_signed. + if constexpr (numeric_limits::is_signed) { + if (__value < __value.zero()) { + __sstr << _CharT('-'); + __formatter::__format_chrono_using_chrono_specs(__sstr, -__value, __chrono_specs); + } else + __formatter::__format_chrono_using_chrono_specs(__sstr, __value, __chrono_specs); + } else + __formatter::__format_chrono_using_chrono_specs(__sstr, __value, __chrono_specs); + // TODO FMT When keeping the precision it will truncate the string. + // Note that the behaviour what the precision does isn't specified. + __specs.__precision_ = -1; + } else { + // Test __weekday_name_ before __weekday_ to give a better error. + if (__specs.__chrono_.__weekday_name_ && !__formatter::__weekday_name_ok(__value)) + std::__throw_format_error("Formatting a weekday name needs a valid weekday"); + + if (__specs.__chrono_.__weekday_ && !__formatter::__weekday_ok(__value)) + std::__throw_format_error("Formatting a weekday needs a valid weekday"); + + if (__specs.__chrono_.__day_of_year_ && !__formatter::__date_ok(__value)) + std::__throw_format_error("Formatting a day of year needs a valid date"); + + if (__specs.__chrono_.__week_of_year_ && !__formatter::__date_ok(__value)) + std::__throw_format_error("Formatting a week of year needs a valid date"); + + if (__specs.__chrono_.__month_name_ && !__formatter::__month_name_ok(__value)) + std::__throw_format_error("Formatting a month name from an invalid month number"); + + if constexpr (__is_hh_mm_ss<_Tp>) { + // Note this is a pedantic intepretation of the Standard. A hh_mm_ss + // is no longer a time_of_day and can store an arbitrary number of + // hours. A number of hours in a 12 or 24 hour clock can't represent + // 24 hours or more. The functions std::chrono::make12 and + // std::chrono::make24 reaffirm this view point. + // + // Interestingly this will be the only output stream function that + // throws. + // + // TODO FMT The wording probably needs to be adapted to + // - The displayed hours is hh_mm_ss.hours() % 24 + // - It should probably allow %j in the same fashion as duration. + // - The stream formatter should change its output when hours >= 24 + // - Write it as not valid, + // - or write the number of days. + if (__specs.__chrono_.__hour_ && __value.hours().count() > 23) + std::__throw_format_error("Formatting a hour needs a valid value"); + + if (__value.is_negative()) + __sstr << _CharT('-'); + } + + __formatter::__format_chrono_using_chrono_specs(__sstr, __value, __chrono_specs); + } + } + + return __formatter::__write_string(__sstr.view(), __ctx.out(), __specs); +} + +} // namespace __formatter + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS __formatter_chrono { +public: + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator + __parse(_ParseContext& __ctx, __format_spec::__fields __fields, __format_spec::__flags __flags) { + return __parser_.__parse(__ctx, __fields, __flags); + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const _Tp& __value, _FormatContext& __ctx) const { + return __formatter::__format_chrono( + __value, __ctx, __parser_.__parser_.__get_parsed_chrono_specifications(__ctx), __parser_.__chrono_specs_); + } + + __format_spec::__parser_chrono<_CharT> __parser_; +}; + +template +struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); + } +}; + +template +struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); + } +}; + +template +struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + // The flags are not __clock since there is no associated time-zone. + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date_time); + } +}; + +template +struct formatter, _CharT> : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + // [time.format]/1 + // Giving a precision specification in the chrono-format-spec is valid only + // for std::chrono::duration types where the representation type Rep is a + // floating-point type. For all other Rep types, an exception of type + // format_error is thrown if the chrono-format-spec contains a precision + // specification. + // + // Note this doesn't refer to chrono::treat_as_floating_point_v<_Rep>. + if constexpr (std::floating_point<_Rep>) + return _Base::__parse(__ctx, __format_spec::__fields_chrono_fractional, __format_spec::__flags::__duration); + else + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__duration); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__day); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__weekday); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_day); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_weekday); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__month_weekday); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__year_month); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); + } +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__date); + } +}; + +template +struct formatter, _CharT> : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__time); + } +}; + +# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) +template <__fmt_char_type _CharT> +struct formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__time_zone); + } +}; + +template <__fmt_char_type _CharT> +struct formatter : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags{}); + } +}; +# if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ + !defined(_LIBCPP_HAS_NO_LOCALIZATION) +// Note due to how libc++'s formatters are implemented there is no need to add +// the exposition only local-time-format-t abstraction. +template +struct formatter, _CharT> : public __formatter_chrono<_CharT> { +public: + using _Base = __formatter_chrono<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock); + } +}; +# endif // !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && + // !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +#endif // if _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CHRONO_FORMATTER_H diff --git a/libcxx/include/__cxx03/__chrono/hh_mm_ss.h b/libcxx/include/__cxx03/__chrono/hh_mm_ss.h new file mode 100644 index 0000000000000000000000000000000000000000..57d2247fe6a3c8c214603075b2f4c759725856d7 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/hh_mm_ss.h @@ -0,0 +1,112 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_HH_MM_SS_H +#define _LIBCPP___CHRONO_HH_MM_SS_H + +#include <__chrono/duration.h> +#include <__chrono/time_point.h> +#include <__config> +#include <__type_traits/common_type.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +template +class hh_mm_ss { +private: + static_assert(__is_duration<_Duration>::value, "template parameter of hh_mm_ss must be a std::chrono::duration"); + using __CommonType = common_type_t<_Duration, chrono::seconds>; + + _LIBCPP_HIDE_FROM_ABI static constexpr uint64_t __pow10(unsigned __exp) { + uint64_t __ret = 1; + for (unsigned __i = 0; __i < __exp; ++__i) + __ret *= 10U; + return __ret; + } + + _LIBCPP_HIDE_FROM_ABI static constexpr unsigned __width(uint64_t __n, uint64_t __d = 10, unsigned __w = 0) { + if (__n >= 2 && __d != 0 && __w < 19) + return 1 + __width(__n, __d % __n * 10, __w + 1); + return 0; + } + +public: + _LIBCPP_HIDE_FROM_ABI static unsigned constexpr fractional_width = + __width(__CommonType::period::den) < 19 ? __width(__CommonType::period::den) : 6u; + using precision = duration>; + + _LIBCPP_HIDE_FROM_ABI constexpr hh_mm_ss() noexcept : hh_mm_ss{_Duration::zero()} {} + + _LIBCPP_HIDE_FROM_ABI constexpr explicit hh_mm_ss(_Duration __d) noexcept + : __is_neg_(__d < _Duration(0)), + __h_(chrono::duration_cast(chrono::abs(__d))), + __m_(chrono::duration_cast(chrono::abs(__d) - hours())), + __s_(chrono::duration_cast(chrono::abs(__d) - hours() - minutes())), + __f_(chrono::duration_cast(chrono::abs(__d) - hours() - minutes() - seconds())) {} + + _LIBCPP_HIDE_FROM_ABI constexpr bool is_negative() const noexcept { return __is_neg_; } + _LIBCPP_HIDE_FROM_ABI constexpr chrono::hours hours() const noexcept { return __h_; } + _LIBCPP_HIDE_FROM_ABI constexpr chrono::minutes minutes() const noexcept { return __m_; } + _LIBCPP_HIDE_FROM_ABI constexpr chrono::seconds seconds() const noexcept { return __s_; } + _LIBCPP_HIDE_FROM_ABI constexpr precision subseconds() const noexcept { return __f_; } + + _LIBCPP_HIDE_FROM_ABI constexpr precision to_duration() const noexcept { + auto __dur = __h_ + __m_ + __s_ + __f_; + return __is_neg_ ? -__dur : __dur; + } + + _LIBCPP_HIDE_FROM_ABI constexpr explicit operator precision() const noexcept { return to_duration(); } + +private: + bool __is_neg_; + chrono::hours __h_; + chrono::minutes __m_; + chrono::seconds __s_; + precision __f_; +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(hh_mm_ss); + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_am(const hours& __h) noexcept { + return __h >= hours(0) && __h < hours(12); +} +_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_pm(const hours& __h) noexcept { + return __h >= hours(12) && __h < hours(24); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr hours make12(const hours& __h) noexcept { + if (__h == hours(0)) + return hours(12); + else if (__h <= hours(12)) + return __h; + else + return __h - hours(12); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr hours make24(const hours& __h, bool __is_pm) noexcept { + if (__is_pm) + return __h == hours(12) ? __h : __h + hours(12); + else + return __h == hours(12) ? hours(0) : __h; +} +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___CHRONO_HH_MM_SS_H diff --git a/libcxx/include/__cxx03/__chrono/high_resolution_clock.h b/libcxx/include/__cxx03/__chrono/high_resolution_clock.h new file mode 100644 index 0000000000000000000000000000000000000000..0697fd2de9b4de413d1f5980cadb43fc09f357dd --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/high_resolution_clock.h @@ -0,0 +1,35 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_HIGH_RESOLUTION_CLOCK_H +#define _LIBCPP___CHRONO_HIGH_RESOLUTION_CLOCK_H + +#include <__chrono/steady_clock.h> +#include <__chrono/system_clock.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +#ifndef _LIBCPP_HAS_NO_MONOTONIC_CLOCK +typedef steady_clock high_resolution_clock; +#else +typedef system_clock high_resolution_clock; +#endif + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CHRONO_HIGH_RESOLUTION_CLOCK_H diff --git a/libcxx/include/__cxx03/__chrono/leap_second.h b/libcxx/include/__cxx03/__chrono/leap_second.h new file mode 100644 index 0000000000000000000000000000000000000000..1a0e7f3107de81aa8b696fb324b2525099d3684c --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/leap_second.h @@ -0,0 +1,126 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#ifndef _LIBCPP___CHRONO_LEAP_SECOND_H +#define _LIBCPP___CHRONO_LEAP_SECOND_H + +#include +// Enable the contents of the header only when libc++ was built with experimental features enabled. +#if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +# include <__chrono/duration.h> +# include <__chrono/system_clock.h> +# include <__chrono/time_point.h> +# include <__compare/ordering.h> +# include <__compare/three_way_comparable.h> +# include <__config> +# include <__utility/private_constructor_tag.h> + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 20 + +namespace chrono { + +class leap_second { +public: + [[nodiscard]] + _LIBCPP_HIDE_FROM_ABI explicit constexpr leap_second(__private_constructor_tag, sys_seconds __date, seconds __value) + : __date_(__date), __value_(__value) {} + + _LIBCPP_HIDE_FROM_ABI leap_second(const leap_second&) = default; + _LIBCPP_HIDE_FROM_ABI leap_second& operator=(const leap_second&) = default; + + _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI constexpr sys_seconds date() const noexcept { return __date_; } + + _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI constexpr seconds value() const noexcept { return __value_; } + +private: + sys_seconds __date_; + seconds __value_; +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const leap_second& __x, const leap_second& __y) { + return __x.date() == __y.date(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(const leap_second& __x, const leap_second& __y) { + return __x.date() <=> __y.date(); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const leap_second& __x, const sys_time<_Duration>& __y) { + return __x.date() == __y; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const leap_second& __x, const sys_time<_Duration>& __y) { + return __x.date() < __y; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const sys_time<_Duration>& __x, const leap_second& __y) { + return __x < __y.date(); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const leap_second& __x, const sys_time<_Duration>& __y) { + return __y < __x; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const sys_time<_Duration>& __x, const leap_second& __y) { + return __y < __x; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const leap_second& __x, const sys_time<_Duration>& __y) { + return !(__y < __x); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const sys_time<_Duration>& __x, const leap_second& __y) { + return !(__y < __x); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const leap_second& __x, const sys_time<_Duration>& __y) { + return !(__x < __y); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const sys_time<_Duration>& __x, const leap_second& __y) { + return !(__x < __y); +} + +# ifndef _LIBCPP_COMPILER_GCC +// This requirement cause a compilation loop in GCC-13 and running out of memory. +// TODO TZDB Test whether GCC-14 fixes this. +template + requires three_way_comparable_with> +_LIBCPP_HIDE_FROM_ABI constexpr auto operator<=>(const leap_second& __x, const sys_time<_Duration>& __y) { + return __x.date() <=> __y; +} +# endif + +} // namespace chrono + +# endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +#endif // _LIBCPP___CHRONO_LEAP_SECOND_H diff --git a/libcxx/include/__cxx03/__chrono/literals.h b/libcxx/include/__cxx03/__chrono/literals.h new file mode 100644 index 0000000000000000000000000000000000000000..89800440edf43522d9295c6d1754e57b4aa8c5e8 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/literals.h @@ -0,0 +1,45 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_LITERALS_H +#define _LIBCPP___CHRONO_LITERALS_H + +#include <__chrono/day.h> +#include <__chrono/year.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +inline namespace literals { +inline namespace chrono_literals { +_LIBCPP_HIDE_FROM_ABI constexpr chrono::day operator""d(unsigned long long __d) noexcept { + return chrono::day(static_cast(__d)); +} + +_LIBCPP_HIDE_FROM_ABI constexpr chrono::year operator""y(unsigned long long __y) noexcept { + return chrono::year(static_cast(__y)); +} +} // namespace chrono_literals +} // namespace literals + +namespace chrono { // hoist the literals into namespace std::chrono +using namespace literals::chrono_literals; +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___CHRONO_LITERALS_H diff --git a/libcxx/include/__cxx03/__chrono/local_info.h b/libcxx/include/__cxx03/__chrono/local_info.h new file mode 100644 index 0000000000000000000000000000000000000000..cfe1448904d3f77831340bcad50e7fa3f6347828 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/local_info.h @@ -0,0 +1,50 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#ifndef _LIBCPP___CHRONO_LOCAL_INFO_H +#define _LIBCPP___CHRONO_LOCAL_INFO_H + +#include +// Enable the contents of the header only when libc++ was built with experimental features enabled. +#if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +# include <__chrono/sys_info.h> +# include <__config> + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 20 + +namespace chrono { + +struct local_info { + static constexpr int unique = 0; + static constexpr int nonexistent = 1; + static constexpr int ambiguous = 2; + + int result; + sys_info first; + sys_info second; +}; + +} // namespace chrono + +# endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +#endif // _LIBCPP___CHRONO_LOCAL_INFO_H diff --git a/libcxx/include/__cxx03/__chrono/month.h b/libcxx/include/__cxx03/__chrono/month.h new file mode 100644 index 0000000000000000000000000000000000000000..ce5cc21aab7d1e07afcd2e34fb32678c0e532012 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/month.h @@ -0,0 +1,115 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_MONTH_H +#define _LIBCPP___CHRONO_MONTH_H + +#include <__chrono/duration.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +class month { +private: + unsigned char __m_; + +public: + month() = default; + _LIBCPP_HIDE_FROM_ABI explicit inline constexpr month(unsigned __val) noexcept + : __m_(static_cast(__val)) {} + _LIBCPP_HIDE_FROM_ABI inline constexpr month& operator++() noexcept { + *this += months{1}; + return *this; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr month operator++(int) noexcept { + month __tmp = *this; + ++(*this); + return __tmp; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr month& operator--() noexcept { + *this -= months{1}; + return *this; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr month operator--(int) noexcept { + month __tmp = *this; + --(*this); + return __tmp; + } + _LIBCPP_HIDE_FROM_ABI constexpr month& operator+=(const months& __m1) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr month& operator-=(const months& __m1) noexcept; + _LIBCPP_HIDE_FROM_ABI explicit inline constexpr operator unsigned() const noexcept { return __m_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr bool ok() const noexcept { return __m_ >= 1 && __m_ <= 12; } +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const month& __lhs, const month& __rhs) noexcept { + return static_cast(__lhs) == static_cast(__rhs); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering operator<=>(const month& __lhs, const month& __rhs) noexcept { + return static_cast(__lhs) <=> static_cast(__rhs); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month operator+(const month& __lhs, const months& __rhs) noexcept { + auto const __mu = static_cast(static_cast(__lhs)) + (__rhs.count() - 1); + auto const __yr = (__mu >= 0 ? __mu : __mu - 11) / 12; + return month{static_cast(__mu - __yr * 12 + 1)}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month operator+(const months& __lhs, const month& __rhs) noexcept { + return __rhs + __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month operator-(const month& __lhs, const months& __rhs) noexcept { + return __lhs + -__rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr months operator-(const month& __lhs, const month& __rhs) noexcept { + auto const __dm = static_cast(__lhs) - static_cast(__rhs); + return months(__dm <= 11 ? __dm : __dm + 12); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month& month::operator+=(const months& __dm) noexcept { + *this = *this + __dm; + return *this; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month& month::operator-=(const months& __dm) noexcept { + *this = *this - __dm; + return *this; +} + +inline constexpr month January{1}; +inline constexpr month February{2}; +inline constexpr month March{3}; +inline constexpr month April{4}; +inline constexpr month May{5}; +inline constexpr month June{6}; +inline constexpr month July{7}; +inline constexpr month August{8}; +inline constexpr month September{9}; +inline constexpr month October{10}; +inline constexpr month November{11}; +inline constexpr month December{12}; + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___CHRONO_MONTH_H diff --git a/libcxx/include/__cxx03/__chrono/month_weekday.h b/libcxx/include/__cxx03/__chrono/month_weekday.h new file mode 100644 index 0000000000000000000000000000000000000000..79198796552148d45ee931bbb6a81f53227d4aa3 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/month_weekday.h @@ -0,0 +1,105 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_MONTH_WEEKDAY_H +#define _LIBCPP___CHRONO_MONTH_WEEKDAY_H + +#include <__chrono/month.h> +#include <__chrono/weekday.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +class month_weekday { +private: + chrono::month __m_; + chrono::weekday_indexed __wdi_; + +public: + _LIBCPP_HIDE_FROM_ABI constexpr month_weekday(const chrono::month& __mval, + const chrono::weekday_indexed& __wdival) noexcept + : __m_{__mval}, __wdi_{__wdival} {} + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::month month() const noexcept { return __m_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::weekday_indexed weekday_indexed() const noexcept { return __wdi_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr bool ok() const noexcept { return __m_.ok() && __wdi_.ok(); } +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool +operator==(const month_weekday& __lhs, const month_weekday& __rhs) noexcept { + return __lhs.month() == __rhs.month() && __lhs.weekday_indexed() == __rhs.weekday_indexed(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_weekday +operator/(const month& __lhs, const weekday_indexed& __rhs) noexcept { + return month_weekday{__lhs, __rhs}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_weekday operator/(int __lhs, const weekday_indexed& __rhs) noexcept { + return month_weekday{month(__lhs), __rhs}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_weekday +operator/(const weekday_indexed& __lhs, const month& __rhs) noexcept { + return month_weekday{__rhs, __lhs}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_weekday operator/(const weekday_indexed& __lhs, int __rhs) noexcept { + return month_weekday{month(__rhs), __lhs}; +} + +class month_weekday_last { + chrono::month __m_; + chrono::weekday_last __wdl_; + +public: + _LIBCPP_HIDE_FROM_ABI constexpr month_weekday_last(const chrono::month& __mval, + const chrono::weekday_last& __wdlval) noexcept + : __m_{__mval}, __wdl_{__wdlval} {} + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::month month() const noexcept { return __m_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::weekday_last weekday_last() const noexcept { return __wdl_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr bool ok() const noexcept { return __m_.ok() && __wdl_.ok(); } +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool +operator==(const month_weekday_last& __lhs, const month_weekday_last& __rhs) noexcept { + return __lhs.month() == __rhs.month() && __lhs.weekday_last() == __rhs.weekday_last(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_weekday_last +operator/(const month& __lhs, const weekday_last& __rhs) noexcept { + return month_weekday_last{__lhs, __rhs}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_weekday_last operator/(int __lhs, const weekday_last& __rhs) noexcept { + return month_weekday_last{month(__lhs), __rhs}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_weekday_last +operator/(const weekday_last& __lhs, const month& __rhs) noexcept { + return month_weekday_last{__rhs, __lhs}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_weekday_last operator/(const weekday_last& __lhs, int __rhs) noexcept { + return month_weekday_last{month(__rhs), __lhs}; +} +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___CHRONO_MONTH_WEEKDAY_H diff --git a/libcxx/include/__cxx03/__chrono/monthday.h b/libcxx/include/__cxx03/__chrono/monthday.h new file mode 100644 index 0000000000000000000000000000000000000000..a89d16e518618ef50aab094a6bc9b13e0421a50c --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/monthday.h @@ -0,0 +1,133 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_MONTHDAY_H +#define _LIBCPP___CHRONO_MONTHDAY_H + +#include <__chrono/calendar.h> +#include <__chrono/day.h> +#include <__chrono/month.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +class month_day { +private: + chrono::month __m_; + chrono::day __d_; + +public: + month_day() = default; + _LIBCPP_HIDE_FROM_ABI constexpr month_day(const chrono::month& __mval, const chrono::day& __dval) noexcept + : __m_{__mval}, __d_{__dval} {} + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::month month() const noexcept { return __m_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::day day() const noexcept { return __d_; } + _LIBCPP_HIDE_FROM_ABI constexpr bool ok() const noexcept; +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool month_day::ok() const noexcept { + if (!__m_.ok()) + return false; + const unsigned __dval = static_cast(__d_); + if (__dval < 1 || __dval > 31) + return false; + if (__dval <= 29) + return true; + // Now we've got either 30 or 31 + const unsigned __mval = static_cast(__m_); + if (__mval == 2) + return false; + if (__mval == 4 || __mval == 6 || __mval == 9 || __mval == 11) + return __dval == 30; + return true; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const month_day& __lhs, const month_day& __rhs) noexcept { + return __lhs.month() == __rhs.month() && __lhs.day() == __rhs.day(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering +operator<=>(const month_day& __lhs, const month_day& __rhs) noexcept { + if (auto __c = __lhs.month() <=> __rhs.month(); __c != 0) + return __c; + return __lhs.day() <=> __rhs.day(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_day operator/(const month& __lhs, const day& __rhs) noexcept { + return month_day{__lhs, __rhs}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_day operator/(const day& __lhs, const month& __rhs) noexcept { + return __rhs / __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_day operator/(const month& __lhs, int __rhs) noexcept { + return __lhs / day(__rhs); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_day operator/(int __lhs, const day& __rhs) noexcept { + return month(__lhs) / __rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_day operator/(const day& __lhs, int __rhs) noexcept { + return month(__rhs) / __lhs; +} + +class month_day_last { +private: + chrono::month __m_; + +public: + _LIBCPP_HIDE_FROM_ABI explicit constexpr month_day_last(const chrono::month& __val) noexcept : __m_{__val} {} + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::month month() const noexcept { return __m_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr bool ok() const noexcept { return __m_.ok(); } +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool +operator==(const month_day_last& __lhs, const month_day_last& __rhs) noexcept { + return __lhs.month() == __rhs.month(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering +operator<=>(const month_day_last& __lhs, const month_day_last& __rhs) noexcept { + return __lhs.month() <=> __rhs.month(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_day_last operator/(const month& __lhs, last_spec) noexcept { + return month_day_last{__lhs}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_day_last operator/(last_spec, const month& __rhs) noexcept { + return month_day_last{__rhs}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_day_last operator/(int __lhs, last_spec) noexcept { + return month_day_last{month(__lhs)}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr month_day_last operator/(last_spec, int __rhs) noexcept { + return month_day_last{month(__rhs)}; +} + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___CHRONO_MONTHDAY_H diff --git a/libcxx/include/__cxx03/__chrono/ostream.h b/libcxx/include/__cxx03/__chrono/ostream.h new file mode 100644 index 0000000000000000000000000000000000000000..e6c43254eea15ee7272d1f4a046d1cdfca196b3f --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/ostream.h @@ -0,0 +1,322 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_OSTREAM_H +#define _LIBCPP___CHRONO_OSTREAM_H + +#include <__chrono/calendar.h> +#include <__chrono/day.h> +#include <__chrono/duration.h> +#include <__chrono/file_clock.h> +#include <__chrono/hh_mm_ss.h> +#include <__chrono/local_info.h> +#include <__chrono/month.h> +#include <__chrono/month_weekday.h> +#include <__chrono/monthday.h> +#include <__chrono/statically_widen.h> +#include <__chrono/sys_info.h> +#include <__chrono/system_clock.h> +#include <__chrono/weekday.h> +#include <__chrono/year.h> +#include <__chrono/year_month.h> +#include <__chrono/year_month_day.h> +#include <__chrono/year_month_weekday.h> +#include <__chrono/zoned_time.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__format/format_functions.h> +#include <__fwd/ostream.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace chrono { + +template + requires(!treat_as_floating_point_v && _Duration{1} < days{1}) +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_time<_Duration>& __tp) { + return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_days& __dp) { + return __os << year_month_day{__dp}; +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const file_time<_Duration> __tp) { + return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const local_time<_Duration> __tp) { + return __os << sys_time<_Duration>{__tp.time_since_epoch()}; +} + +// Depending on the type the return is a const _CharT* or a basic_string<_CharT> +template +_LIBCPP_HIDE_FROM_ABI auto __units_suffix() { + // TODO FMT LWG issue the suffixes are always char and not STATICALLY-WIDEN'ed. + if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "as"); + else if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "fs"); + else if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "ps"); + else if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "ns"); + else if constexpr (same_as) +# ifndef _LIBCPP_HAS_NO_UNICODE + return _LIBCPP_STATICALLY_WIDEN(_CharT, "\u00b5s"); +# else + return _LIBCPP_STATICALLY_WIDEN(_CharT, "us"); +# endif + else if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "ms"); + else if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "cs"); + else if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "ds"); + else if constexpr (same_as>) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "s"); + else if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "das"); + else if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "hs"); + else if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "ks"); + else if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "Ms"); + else if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "Gs"); + else if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "Ts"); + else if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "Ps"); + else if constexpr (same_as) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "Es"); + else if constexpr (same_as>) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "min"); + else if constexpr (same_as>) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "h"); + else if constexpr (same_as>) + return _LIBCPP_STATICALLY_WIDEN(_CharT, "d"); + else if constexpr (_Period::den == 1) + return std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "[{}]s"), _Period::num); + else + return std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "[{}/{}]s"), _Period::num, _Period::den); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const duration<_Rep, _Period>& __d) { + basic_ostringstream<_CharT, _Traits> __s; + __s.flags(__os.flags()); + __s.imbue(__os.getloc()); + __s.precision(__os.precision()); + __s << __d.count() << chrono::__units_suffix<_CharT, _Period>(); + return __os << __s.str(); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, const day& __d) { + return __os << (__d.ok() ? std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%d}"), __d) + // Note this error differs from the wording of the Standard. The + // Standard wording doesn't work well on AIX or Windows. There + // the formatted day seems to be either modulo 100 or completely + // omitted. Judging by the wording this is valid. + // TODO FMT Write a paper of file an LWG issue. + : std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02} is not a valid day"), + static_cast(__d))); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const month& __m) { + return __os << (__m.ok() ? std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%b}"), __m) + : std::format(__os.getloc(), + _LIBCPP_STATICALLY_WIDEN(_CharT, "{} is not a valid month"), + static_cast(__m))); // TODO FMT Standard mandated locale isn't used. +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const year& __y) { + return __os << (__y.ok() ? std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%Y}"), __y) + : std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%Y} is not a valid year"), __y)); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday& __wd) { + return __os << (__wd.ok() ? std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%a}"), __wd) + : std::format(__os.getloc(), // TODO FMT Standard mandated locale isn't used. + _LIBCPP_STATICALLY_WIDEN(_CharT, "{} is not a valid weekday"), + static_cast(__wd.c_encoding()))); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday_indexed& __wdi) { + auto __i = __wdi.index(); + return __os << (__i >= 1 && __i <= 5 + ? std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}[{}]"), __wdi.weekday(), __i) + : std::format(__os.getloc(), + _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}[{} is not a valid index]"), + __wdi.weekday(), + __i)); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday_last& __wdl) { + return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}[last]"), __wdl.weekday()); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const month_day& __md) { + // TODO FMT The Standard allows 30th of February to be printed. + // It would be nice to show an error message instead. + return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}/{}"), __md.month(), __md.day()); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const month_day_last& __mdl) { + return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}/last"), __mdl.month()); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const month_weekday& __mwd) { + return __os << std::format( + __os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}/{:L}"), __mwd.month(), __mwd.weekday_indexed()); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const month_weekday_last& __mwdl) { + return __os << std::format( + __os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}/{:L}"), __mwdl.month(), __mwdl.weekday_last()); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month& __ym) { + return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{}/{:L}"), __ym.year(), __ym.month()); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month_day& __ymd) { + return __os << (__ymd.ok() ? std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%F}"), __ymd) + : std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%F} is not a valid date"), __ymd)); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month_day_last& __ymdl) { + return __os << std::format( + __os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{}/{:L}"), __ymdl.year(), __ymdl.month_day_last()); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month_weekday& __ymwd) { + return __os << std::format( + __os.getloc(), + _LIBCPP_STATICALLY_WIDEN(_CharT, "{}/{:L}/{:L}"), + __ymwd.year(), + __ymwd.month(), + __ymwd.weekday_indexed()); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month_weekday_last& __ymwdl) { + return __os << std::format( + __os.getloc(), + _LIBCPP_STATICALLY_WIDEN(_CharT, "{}/{:L}/{:L}"), + __ymwdl.year(), + __ymwdl.month(), + __ymwdl.weekday_last()); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const hh_mm_ss<_Duration> __hms) { + return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%T}"), __hms); +} + +# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __info) { + // __info.abbrev is always std::basic_string. + // Since these strings typically are short the conversion should be cheap. + std::basic_string<_CharT> __abbrev{__info.abbrev.begin(), __info.abbrev.end()}; + return __os << std::format( + _LIBCPP_STATICALLY_WIDEN(_CharT, "[{:%F %T}, {:%F %T}) {:%T} {:%Q%q} \"{}\""), + __info.begin, + __info.end, + hh_mm_ss{__info.offset}, + __info.save, + __abbrev); +} + +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const local_info& __info) { + auto __result = [&]() -> basic_string<_CharT> { + switch (__info.result) { + case local_info::unique: + return _LIBCPP_STATICALLY_WIDEN(_CharT, "unique"); + case local_info::nonexistent: + return _LIBCPP_STATICALLY_WIDEN(_CharT, "non-existent"); + case local_info::ambiguous: + return _LIBCPP_STATICALLY_WIDEN(_CharT, "ambiguous"); + + default: + return std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "unspecified result ({})"), __info.result); + }; + }; + + return __os << std::format( + _LIBCPP_STATICALLY_WIDEN(_CharT, "{}: {{{}, {}}}"), __result(), __info.first, __info.second); +} + +# if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ + !defined(_LIBCPP_HAS_NO_LOCALIZATION) +template +_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, const zoned_time<_Duration, _TimeZonePtr>& __tp) { + return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T %Z}"), __tp); +} +# endif +# endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +} // namespace chrono + +#endif // if _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CHRONO_OSTREAM_H diff --git a/libcxx/include/__cxx03/__chrono/parser_std_format_spec.h b/libcxx/include/__cxx03/__chrono/parser_std_format_spec.h new file mode 100644 index 0000000000000000000000000000000000000000..785bbae198e46411057415471bfc3cd5f72c4152 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/parser_std_format_spec.h @@ -0,0 +1,416 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H +#define _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H + +#include <__config> +#include <__format/concepts.h> +#include <__format/format_error.h> +#include <__format/format_parse_context.h> +#include <__format/formatter_string.h> +#include <__format/parser_std_format_spec.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __format_spec { + +// By not placing this constant in the formatter class it's not duplicated for char and wchar_t +inline constexpr __fields __fields_chrono_fractional{ + .__precision_ = true, .__locale_specific_form_ = true, .__type_ = false}; +inline constexpr __fields __fields_chrono{.__locale_specific_form_ = true, .__type_ = false}; + +/// Flags available or required in a chrono type. +/// +/// The caller of the chrono formatter lists the types it has available and the +/// validation tests whether the requested type spec (e.g. %M) is available in +/// the formatter. +/// When the type in the chrono-format-spec isn't present in the data a +/// \ref format_error is thrown. +enum class __flags { + __second = 0x1, + __minute = 0x2, + __hour = 0x4, + __time = __hour | __minute | __second, + + __day = 0x8, + __month = 0x10, + __year = 0x20, + + __weekday = 0x40, + + __month_day = __day | __month, + __month_weekday = __weekday | __month, + __year_month = __month | __year, + __date = __day | __month | __year | __weekday, + + __date_time = __date | __time, + + __duration = 0x80 | __time, + + __time_zone = 0x100, + + __clock = __date_time | __time_zone +}; + +_LIBCPP_HIDE_FROM_ABI constexpr __flags operator&(__flags __lhs, __flags __rhs) { + return static_cast<__flags>(static_cast(__lhs) & static_cast(__rhs)); +} + +_LIBCPP_HIDE_FROM_ABI constexpr void __validate_second(__flags __flags) { + if ((__flags & __flags::__second) != __flags::__second) + std::__throw_format_error("The supplied date time doesn't contain a second"); +} + +_LIBCPP_HIDE_FROM_ABI constexpr void __validate_minute(__flags __flags) { + if ((__flags & __flags::__minute) != __flags::__minute) + std::__throw_format_error("The supplied date time doesn't contain a minute"); +} + +_LIBCPP_HIDE_FROM_ABI constexpr void __validate_hour(__flags __flags) { + if ((__flags & __flags::__hour) != __flags::__hour) + std::__throw_format_error("The supplied date time doesn't contain an hour"); +} + +_LIBCPP_HIDE_FROM_ABI constexpr void __validate_time(__flags __flags) { + if ((__flags & __flags::__time) != __flags::__time) + std::__throw_format_error("The supplied date time doesn't contain a time"); +} + +_LIBCPP_HIDE_FROM_ABI constexpr void __validate_day(__flags __flags) { + if ((__flags & __flags::__day) != __flags::__day) + std::__throw_format_error("The supplied date time doesn't contain a day"); +} + +_LIBCPP_HIDE_FROM_ABI constexpr void __validate_month(__flags __flags) { + if ((__flags & __flags::__month) != __flags::__month) + std::__throw_format_error("The supplied date time doesn't contain a month"); +} + +_LIBCPP_HIDE_FROM_ABI constexpr void __validate_year(__flags __flags) { + if ((__flags & __flags::__year) != __flags::__year) + std::__throw_format_error("The supplied date time doesn't contain a year"); +} + +_LIBCPP_HIDE_FROM_ABI constexpr void __validate_date(__flags __flags) { + if ((__flags & __flags::__date) != __flags::__date) + std::__throw_format_error("The supplied date time doesn't contain a date"); +} + +_LIBCPP_HIDE_FROM_ABI constexpr void __validate_date_or_duration(__flags __flags) { + if (((__flags & __flags::__date) != __flags::__date) && ((__flags & __flags::__duration) != __flags::__duration)) + std::__throw_format_error("The supplied date time doesn't contain a date or duration"); +} + +_LIBCPP_HIDE_FROM_ABI constexpr void __validate_date_time(__flags __flags) { + if ((__flags & __flags::__date_time) != __flags::__date_time) + std::__throw_format_error("The supplied date time doesn't contain a date and time"); +} + +_LIBCPP_HIDE_FROM_ABI constexpr void __validate_weekday(__flags __flags) { + if ((__flags & __flags::__weekday) != __flags::__weekday) + std::__throw_format_error("The supplied date time doesn't contain a weekday"); +} + +_LIBCPP_HIDE_FROM_ABI constexpr void __validate_duration(__flags __flags) { + if ((__flags & __flags::__duration) != __flags::__duration) + std::__throw_format_error("The supplied date time doesn't contain a duration"); +} + +_LIBCPP_HIDE_FROM_ABI constexpr void __validate_time_zone(__flags __flags) { + if ((__flags & __flags::__time_zone) != __flags::__time_zone) + std::__throw_format_error("The supplied date time doesn't contain a time zone"); +} + +template +class _LIBCPP_TEMPLATE_VIS __parser_chrono { + using _ConstIterator = typename basic_format_parse_context<_CharT>::const_iterator; + +public: + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator + __parse(_ParseContext& __ctx, __fields __fields, __flags __flags) { + _ConstIterator __begin = __parser_.__parse(__ctx, __fields); + _ConstIterator __end = __ctx.end(); + if (__begin == __end) + return __begin; + + _ConstIterator __last = __parse_chrono_specs(__begin, __end, __flags); + __chrono_specs_ = basic_string_view<_CharT>{__begin, __last}; + + return __last; + } + + __parser<_CharT> __parser_; + basic_string_view<_CharT> __chrono_specs_; + +private: + _LIBCPP_HIDE_FROM_ABI constexpr _ConstIterator + __parse_chrono_specs(_ConstIterator __begin, _ConstIterator __end, __flags __flags) { + _LIBCPP_ASSERT_INTERNAL(__begin != __end, + "When called with an empty input the function will cause " + "undefined behavior by evaluating data not in the input"); + + if (*__begin != _CharT('%') && *__begin != _CharT('}')) + std::__throw_format_error("The format specifier expects a '%' or a '}'"); + + do { + switch (*__begin) { + case _CharT('{'): + std::__throw_format_error("The chrono specifiers contain a '{'"); + + case _CharT('}'): + return __begin; + + case _CharT('%'): + __parse_conversion_spec(__begin, __end, __flags); + [[fallthrough]]; + + default: + // All other literals + ++__begin; + } + + } while (__begin != __end && *__begin != _CharT('}')); + + return __begin; + } + + /// \pre *__begin == '%' + /// \post __begin points at the end parsed conversion-spec + _LIBCPP_HIDE_FROM_ABI constexpr void + __parse_conversion_spec(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) { + ++__begin; + if (__begin == __end) + std::__throw_format_error("End of input while parsing a conversion specifier"); + + switch (*__begin) { + case _CharT('n'): + case _CharT('t'): + case _CharT('%'): + break; + + case _CharT('S'): + __format_spec::__validate_second(__flags); + break; + + case _CharT('M'): + __format_spec::__validate_minute(__flags); + break; + + case _CharT('p'): // TODO FMT does the formater require an hour or a time? + case _CharT('H'): + case _CharT('I'): + __parser_.__hour_ = true; + __validate_hour(__flags); + break; + + case _CharT('r'): + case _CharT('R'): + case _CharT('T'): + case _CharT('X'): + __parser_.__hour_ = true; + __format_spec::__validate_time(__flags); + break; + + case _CharT('d'): + case _CharT('e'): + __format_spec::__validate_day(__flags); + break; + + case _CharT('b'): + case _CharT('h'): + case _CharT('B'): + __parser_.__month_name_ = true; + [[fallthrough]]; + case _CharT('m'): + __format_spec::__validate_month(__flags); + break; + + case _CharT('y'): + case _CharT('C'): + case _CharT('Y'): + __format_spec::__validate_year(__flags); + break; + + case _CharT('j'): + __parser_.__day_of_year_ = true; + __format_spec::__validate_date_or_duration(__flags); + break; + + case _CharT('g'): + case _CharT('G'): + case _CharT('U'): + case _CharT('V'): + case _CharT('W'): + __parser_.__week_of_year_ = true; + [[fallthrough]]; + case _CharT('x'): + case _CharT('D'): + case _CharT('F'): + __format_spec::__validate_date(__flags); + break; + + case _CharT('c'): + __format_spec::__validate_date_time(__flags); + break; + + case _CharT('a'): + case _CharT('A'): + __parser_.__weekday_name_ = true; + [[fallthrough]]; + case _CharT('u'): + case _CharT('w'): + __parser_.__weekday_ = true; + __validate_weekday(__flags); + __format_spec::__validate_weekday(__flags); + break; + + case _CharT('q'): + case _CharT('Q'): + __format_spec::__validate_duration(__flags); + break; + + case _CharT('E'): + __parse_modifier_E(__begin, __end, __flags); + break; + + case _CharT('O'): + __parse_modifier_O(__begin, __end, __flags); + break; + + case _CharT('z'): + case _CharT('Z'): + // Currently there's no time zone information. However some clocks have a + // hard-coded "time zone", for these clocks the information can be used. + // TODO FMT implement time zones. + __format_spec::__validate_time_zone(__flags); + break; + + default: // unknown type; + std::__throw_format_error("The date time type specifier is invalid"); + } + } + + /// \pre *__begin == 'E' + /// \post __begin is incremented by one. + _LIBCPP_HIDE_FROM_ABI constexpr void + __parse_modifier_E(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) { + ++__begin; + if (__begin == __end) + std::__throw_format_error("End of input while parsing the modifier E"); + + switch (*__begin) { + case _CharT('X'): + __parser_.__hour_ = true; + __format_spec::__validate_time(__flags); + break; + + case _CharT('y'): + case _CharT('C'): + case _CharT('Y'): + __format_spec::__validate_year(__flags); + break; + + case _CharT('x'): + __format_spec::__validate_date(__flags); + break; + + case _CharT('c'): + __format_spec::__validate_date_time(__flags); + break; + + case _CharT('z'): + // Currently there's no time zone information. However some clocks have a + // hard-coded "time zone", for these clocks the information can be used. + // TODO FMT implement time zones. + __format_spec::__validate_time_zone(__flags); + break; + + default: + std::__throw_format_error("The date time type specifier for modifier E is invalid"); + } + } + + /// \pre *__begin == 'O' + /// \post __begin is incremented by one. + _LIBCPP_HIDE_FROM_ABI constexpr void + __parse_modifier_O(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) { + ++__begin; + if (__begin == __end) + std::__throw_format_error("End of input while parsing the modifier O"); + + switch (*__begin) { + case _CharT('S'): + __format_spec::__validate_second(__flags); + break; + + case _CharT('M'): + __format_spec::__validate_minute(__flags); + break; + + case _CharT('I'): + case _CharT('H'): + __parser_.__hour_ = true; + __format_spec::__validate_hour(__flags); + break; + + case _CharT('d'): + case _CharT('e'): + __format_spec::__validate_day(__flags); + break; + + case _CharT('m'): + __format_spec::__validate_month(__flags); + break; + + case _CharT('y'): + __format_spec::__validate_year(__flags); + break; + + case _CharT('U'): + case _CharT('V'): + case _CharT('W'): + __parser_.__week_of_year_ = true; + __format_spec::__validate_date(__flags); + break; + + case _CharT('u'): + case _CharT('w'): + __parser_.__weekday_ = true; + __format_spec::__validate_weekday(__flags); + break; + + case _CharT('z'): + // Currently there's no time zone information. However some clocks have a + // hard-coded "time zone", for these clocks the information can be used. + // TODO FMT implement time zones. + __format_spec::__validate_time_zone(__flags); + break; + + default: + std::__throw_format_error("The date time type specifier for modifier O is invalid"); + } + } +}; + +} // namespace __format_spec + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H diff --git a/libcxx/include/__cxx03/__chrono/statically_widen.h b/libcxx/include/__cxx03/__chrono/statically_widen.h new file mode 100644 index 0000000000000000000000000000000000000000..a18c46f057a819c02b2bb6ac3c5e71354640dfe8 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/statically_widen.h @@ -0,0 +1,52 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_STATICALLY_WIDEN_H +#define _LIBCPP___CHRONO_STATICALLY_WIDEN_H + +// Implements the STATICALLY-WIDEN exposition-only function. ([time.general]/2) + +#include <__concepts/same_as.h> +#include <__config> +#include <__format/concepts.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <__fmt_char_type _CharT> +_LIBCPP_HIDE_FROM_ABI constexpr const _CharT* __statically_widen(const char* __str, const wchar_t* __wstr) { + if constexpr (same_as<_CharT, char>) + return __str; + else + return __wstr; +} +# define _LIBCPP_STATICALLY_WIDEN(_CharT, __str) ::std::__statically_widen<_CharT>(__str, L##__str) +# else // _LIBCPP_HAS_NO_WIDE_CHARACTERS + +// Without this indirection the unit test test/libcxx/modules_include.sh.cpp +// fails for the CI build "No wide characters". This seems like a bug. +// TODO FMT investigate why this is needed. +template <__fmt_char_type _CharT> +_LIBCPP_HIDE_FROM_ABI constexpr const _CharT* __statically_widen(const char* __str) { + return __str; +} +# define _LIBCPP_STATICALLY_WIDEN(_CharT, __str) ::std::__statically_widen<_CharT>(__str) +# endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CHRONO_STATICALLY_WIDEN_H diff --git a/libcxx/include/__cxx03/__chrono/steady_clock.h b/libcxx/include/__cxx03/__chrono/steady_clock.h new file mode 100644 index 0000000000000000000000000000000000000000..612a7f156e6343d631c463fc76e29f5fff47bbb9 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/steady_clock.h @@ -0,0 +1,42 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_STEADY_CLOCK_H +#define _LIBCPP___CHRONO_STEADY_CLOCK_H + +#include <__chrono/duration.h> +#include <__chrono/time_point.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +#ifndef _LIBCPP_HAS_NO_MONOTONIC_CLOCK +class _LIBCPP_EXPORTED_FROM_ABI steady_clock { +public: + typedef nanoseconds duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + static _LIBCPP_CONSTEXPR_SINCE_CXX14 const bool is_steady = true; + + static time_point now() _NOEXCEPT; +}; +#endif + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CHRONO_STEADY_CLOCK_H diff --git a/libcxx/include/__cxx03/__chrono/sys_info.h b/libcxx/include/__cxx03/__chrono/sys_info.h new file mode 100644 index 0000000000000000000000000000000000000000..11536cbde3a37c481cd0fce344f040708f5503a4 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/sys_info.h @@ -0,0 +1,51 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#ifndef _LIBCPP___CHRONO_SYS_INFO_H +#define _LIBCPP___CHRONO_SYS_INFO_H + +#include +// Enable the contents of the header only when libc++ was built with experimental features enabled. +#if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +# include <__chrono/duration.h> +# include <__chrono/system_clock.h> +# include <__chrono/time_point.h> +# include <__config> +# include + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 20 + +namespace chrono { + +struct sys_info { + sys_seconds begin; + sys_seconds end; + seconds offset; + minutes save; + string abbrev; +}; + +} // namespace chrono + +# endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +#endif // _LIBCPP___CHRONO_SYS_INFO_H diff --git a/libcxx/include/__cxx03/__chrono/system_clock.h b/libcxx/include/__cxx03/__chrono/system_clock.h new file mode 100644 index 0000000000000000000000000000000000000000..5a9eb65bdae7acc424b309ecfeb6d40233871889 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/system_clock.h @@ -0,0 +1,52 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_SYSTEM_CLOCK_H +#define _LIBCPP___CHRONO_SYSTEM_CLOCK_H + +#include <__chrono/duration.h> +#include <__chrono/time_point.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +class _LIBCPP_EXPORTED_FROM_ABI system_clock { +public: + typedef microseconds duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + static _LIBCPP_CONSTEXPR_SINCE_CXX14 const bool is_steady = false; + + static time_point now() _NOEXCEPT; + static time_t to_time_t(const time_point& __t) _NOEXCEPT; + static time_point from_time_t(time_t __t) _NOEXCEPT; +}; + +#if _LIBCPP_STD_VER >= 20 + +template +using sys_time = time_point; +using sys_seconds = sys_time; +using sys_days = sys_time; + +#endif + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CHRONO_SYSTEM_CLOCK_H diff --git a/libcxx/include/__cxx03/__chrono/time_point.h b/libcxx/include/__cxx03/__chrono/time_point.h new file mode 100644 index 0000000000000000000000000000000000000000..aaf0b098f280e00243bfcb4cd9355bd67c546f18 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/time_point.h @@ -0,0 +1,220 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_TIME_POINT_H +#define _LIBCPP___CHRONO_TIME_POINT_H + +#include <__chrono/duration.h> +#include <__compare/ordering.h> +#include <__compare/three_way_comparable.h> +#include <__config> +#include <__type_traits/common_type.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_convertible.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +template +class _LIBCPP_TEMPLATE_VIS time_point { + static_assert(__is_duration<_Duration>::value, + "Second template parameter of time_point must be a std::chrono::duration"); + +public: + typedef _Clock clock; + typedef _Duration duration; + typedef typename duration::rep rep; + typedef typename duration::period period; + +private: + duration __d_; + +public: + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 time_point() : __d_(duration::zero()) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit time_point(const duration& __d) : __d_(__d) {} + + // conversions + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 time_point(const time_point& __t) + : __d_(__t.time_since_epoch()) {} + + // observer + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 duration time_since_epoch() const { return __d_; } + + // arithmetic + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 time_point& operator+=(const duration& __d) { + __d_ += __d; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 time_point& operator-=(const duration& __d) { + __d_ -= __d; + return *this; + } + + // special values + + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR time_point min() _NOEXCEPT { return time_point(duration::min()); } + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR time_point max() _NOEXCEPT { return time_point(duration::max()); } +}; + +} // namespace chrono + +template +struct _LIBCPP_TEMPLATE_VIS +common_type, chrono::time_point<_Clock, _Duration2> > { + typedef chrono::time_point<_Clock, typename common_type<_Duration1, _Duration2>::type> type; +}; + +namespace chrono { + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 time_point<_Clock, _ToDuration> +time_point_cast(const time_point<_Clock, _Duration>& __t) { + return time_point<_Clock, _ToDuration>(chrono::duration_cast<_ToDuration>(__t.time_since_epoch())); +} + +#if _LIBCPP_STD_VER >= 17 +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> floor(const time_point<_Clock, _Duration>& __t) { + return time_point<_Clock, _ToDuration>{chrono::floor<_ToDuration>(__t.time_since_epoch())}; +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> ceil(const time_point<_Clock, _Duration>& __t) { + return time_point<_Clock, _ToDuration>{chrono::ceil<_ToDuration>(__t.time_since_epoch())}; +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> round(const time_point<_Clock, _Duration>& __t) { + return time_point<_Clock, _ToDuration>{chrono::round<_ToDuration>(__t.time_since_epoch())}; +} + +template ::is_signed, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI constexpr duration<_Rep, _Period> abs(duration<_Rep, _Period> __d) { + return __d >= __d.zero() ? +__d : -__d; +} +#endif // _LIBCPP_STD_VER >= 17 + +// time_point == + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool +operator==(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs) { + return __lhs.time_since_epoch() == __rhs.time_since_epoch(); +} + +#if _LIBCPP_STD_VER <= 17 + +// time_point != + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool +operator!=(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs) { + return !(__lhs == __rhs); +} + +#endif // _LIBCPP_STD_VER <= 17 + +// time_point < + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool +operator<(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs) { + return __lhs.time_since_epoch() < __rhs.time_since_epoch(); +} + +// time_point > + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool +operator>(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs) { + return __rhs < __lhs; +} + +// time_point <= + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool +operator<=(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs) { + return !(__rhs < __lhs); +} + +// time_point >= + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool +operator>=(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs) { + return !(__lhs < __rhs); +} + +#if _LIBCPP_STD_VER >= 20 + +template _Duration2> +_LIBCPP_HIDE_FROM_ABI constexpr auto +operator<=>(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs) { + return __lhs.time_since_epoch() <=> __rhs.time_since_epoch(); +} + +#endif // _LIBCPP_STD_VER >= 20 + +// time_point operator+(time_point x, duration y); + +template +inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX14 time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type> +operator+(const time_point<_Clock, _Duration1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { + typedef time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type> _Tr; + return _Tr(__lhs.time_since_epoch() + __rhs); +} + +// time_point operator+(duration x, time_point y); + +template +inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX14 time_point<_Clock, typename common_type, _Duration2>::type> +operator+(const duration<_Rep1, _Period1>& __lhs, const time_point<_Clock, _Duration2>& __rhs) { + return __rhs + __lhs; +} + +// time_point operator-(time_point x, duration y); + +template +inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX14 time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type> +operator-(const time_point<_Clock, _Duration1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { + typedef time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type> _Ret; + return _Ret(__lhs.time_since_epoch() - __rhs); +} + +// duration operator-(time_point x, time_point y); + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename common_type<_Duration1, _Duration2>::type +operator-(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs) { + return __lhs.time_since_epoch() - __rhs.time_since_epoch(); +} + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___CHRONO_TIME_POINT_H diff --git a/libcxx/include/__cxx03/__chrono/time_zone.h b/libcxx/include/__cxx03/__chrono/time_zone.h new file mode 100644 index 0000000000000000000000000000000000000000..de11dac1eef0c2d4aaf2db87a5b21911e40acb3c --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/time_zone.h @@ -0,0 +1,182 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#ifndef _LIBCPP___CHRONO_TIME_ZONE_H +#define _LIBCPP___CHRONO_TIME_ZONE_H + +#include +// Enable the contents of the header only when libc++ was built with experimental features enabled. +#if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +# include <__chrono/calendar.h> +# include <__chrono/duration.h> +# include <__chrono/exception.h> +# include <__chrono/local_info.h> +# include <__chrono/sys_info.h> +# include <__chrono/system_clock.h> +# include <__compare/strong_order.h> +# include <__config> +# include <__memory/unique_ptr.h> +# include <__type_traits/common_type.h> +# include + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ + !defined(_LIBCPP_HAS_NO_LOCALIZATION) + +namespace chrono { + +enum class choose { earliest, latest }; + +class _LIBCPP_AVAILABILITY_TZDB time_zone { + _LIBCPP_HIDE_FROM_ABI time_zone() = default; + +public: + class __impl; // public so it can be used by make_unique. + + // The "constructor". + // + // The default constructor is private to avoid the constructor from being + // part of the ABI. Instead use an __ugly_named function as an ABI interface, + // since that gives us the ability to change it in the future. + [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI static time_zone __create(unique_ptr<__impl>&& __p); + + _LIBCPP_EXPORTED_FROM_ABI ~time_zone(); + + _LIBCPP_HIDE_FROM_ABI time_zone(time_zone&&) = default; + _LIBCPP_HIDE_FROM_ABI time_zone& operator=(time_zone&&) = default; + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_view name() const noexcept { return __name(); } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_info get_info(const sys_time<_Duration>& __time) const { + return __get_info(chrono::time_point_cast(__time)); + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI local_info get_info(const local_time<_Duration>& __time) const { + return __get_info(chrono::time_point_cast(__time)); + } + + // We don't apply nodiscard here since this function throws on many inputs, + // so it could be used as a validation. + template + _LIBCPP_HIDE_FROM_ABI sys_time> to_sys(const local_time<_Duration>& __time) const { + local_info __info = get_info(__time); + switch (__info.result) { + case local_info::unique: + return sys_time>{__time.time_since_epoch() - __info.first.offset}; + + case local_info::nonexistent: + chrono::__throw_nonexistent_local_time(__time, __info); + + case local_info::ambiguous: + chrono::__throw_ambiguous_local_time(__time, __info); + } + + // TODO TZDB The Standard does not specify anything in these cases. + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + __info.result != -1, "cannot convert the local time; it would be before the minimum system clock value"); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + __info.result != -2, "cannot convert the local time; it would be after the maximum system clock value"); + + return {}; + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_time> + to_sys(const local_time<_Duration>& __time, choose __z) const { + local_info __info = get_info(__time); + switch (__info.result) { + case local_info::unique: + case local_info::nonexistent: // first and second are the same + return sys_time>{__time.time_since_epoch() - __info.first.offset}; + + case local_info::ambiguous: + switch (__z) { + case choose::earliest: + return sys_time>{__time.time_since_epoch() - __info.first.offset}; + + case choose::latest: + return sys_time>{__time.time_since_epoch() - __info.second.offset}; + + // Note a value out of bounds is not specified. + } + } + + // TODO TZDB The standard does not specify anything in these cases. + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + __info.result != -1, "cannot convert the local time; it would be before the minimum system clock value"); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + __info.result != -2, "cannot convert the local time; it would be after the maximum system clock value"); + + return {}; + } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI local_time> + to_local(const sys_time<_Duration>& __time) const { + using _Dp = common_type_t<_Duration, seconds>; + + sys_info __info = get_info(__time); + + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + __info.offset >= chrono::seconds{0} || __time.time_since_epoch() >= _Dp::min() - __info.offset, + "cannot convert the system time; it would be before the minimum local clock value"); + + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + __info.offset <= chrono::seconds{0} || __time.time_since_epoch() <= _Dp::max() - __info.offset, + "cannot convert the system time; it would be after the maximum local clock value"); + + return local_time<_Dp>{__time.time_since_epoch() + __info.offset}; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const __impl& __implementation() const noexcept { return *__impl_; } + +private: + [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI string_view __name() const noexcept; + + [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI sys_info __get_info(sys_seconds __time) const; + [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI local_info __get_info(local_seconds __time) const; + + unique_ptr<__impl> __impl_; +}; + +[[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline bool +operator==(const time_zone& __x, const time_zone& __y) noexcept { + return __x.name() == __y.name(); +} + +[[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline strong_ordering +operator<=>(const time_zone& __x, const time_zone& __y) noexcept { + return __x.name() <=> __y.name(); +} + +} // namespace chrono + +# endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) + // && !defined(_LIBCPP_HAS_NO_LOCALIZATION) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +#endif // _LIBCPP___CHRONO_TIME_ZONE_H diff --git a/libcxx/include/__cxx03/__chrono/time_zone_link.h b/libcxx/include/__cxx03/__chrono/time_zone_link.h new file mode 100644 index 0000000000000000000000000000000000000000..b2d365c5fd0820db7076fa1f4bb0c3d0563f9d4b --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/time_zone_link.h @@ -0,0 +1,79 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#ifndef _LIBCPP___CHRONO_TIME_ZONE_LINK_H +#define _LIBCPP___CHRONO_TIME_ZONE_LINK_H + +#include +// Enable the contents of the header only when libc++ was built with experimental features enabled. +#if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +# include <__compare/strong_order.h> +# include <__config> +# include <__utility/private_constructor_tag.h> +# include +# include + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ + !defined(_LIBCPP_HAS_NO_LOCALIZATION) + +namespace chrono { + +class time_zone_link { +public: + [[nodiscard]] + _LIBCPP_HIDE_FROM_ABI explicit time_zone_link(__private_constructor_tag, string_view __name, string_view __target) + : __name_{__name}, __target_{__target} {} + + _LIBCPP_HIDE_FROM_ABI time_zone_link(time_zone_link&&) = default; + _LIBCPP_HIDE_FROM_ABI time_zone_link& operator=(time_zone_link&&) = default; + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_view name() const noexcept { return __name_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_view target() const noexcept { return __target_; } + +private: + string __name_; + // TODO TZDB instead of the name we can store the pointer to a zone. These + // pointers are immutable. This makes it possible to directly return a + // pointer in the time_zone in the 'locate_zone' function. + string __target_; +}; + +[[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline bool +operator==(const time_zone_link& __x, const time_zone_link& __y) noexcept { + return __x.name() == __y.name(); +} + +[[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline strong_ordering +operator<=>(const time_zone_link& __x, const time_zone_link& __y) noexcept { + return __x.name() <=> __y.name(); +} + +} // namespace chrono + +# endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +#endif // _LIBCPP___CHRONO_TIME_ZONE_LINK_H diff --git a/libcxx/include/__cxx03/__chrono/tzdb.h b/libcxx/include/__cxx03/__chrono/tzdb.h new file mode 100644 index 0000000000000000000000000000000000000000..f731f8c318be079ab251014963636b9eda5c4a6c --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/tzdb.h @@ -0,0 +1,94 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#ifndef _LIBCPP___CHRONO_TZDB_H +#define _LIBCPP___CHRONO_TZDB_H + +#include +// Enable the contents of the header only when libc++ was built with experimental features enabled. +#if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +# include <__algorithm/ranges_lower_bound.h> +# include <__chrono/leap_second.h> +# include <__chrono/time_zone.h> +# include <__chrono/time_zone_link.h> +# include <__config> +# include +# include + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ + !defined(_LIBCPP_HAS_NO_LOCALIZATION) + +namespace chrono { + +struct tzdb { + string version; + vector zones; + vector links; + + vector leap_seconds; + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const time_zone* __locate_zone(string_view __name) const { + if (const time_zone* __result = __find_in_zone(__name)) + return __result; + + if (auto __it = ranges::lower_bound(links, __name, {}, &time_zone_link::name); + __it != links.end() && __it->name() == __name) + if (const time_zone* __result = __find_in_zone(__it->target())) + return __result; + + return nullptr; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const time_zone* locate_zone(string_view __name) const { + if (const time_zone* __result = __locate_zone(__name)) + return __result; + + std::__throw_runtime_error("tzdb: requested time zone not found"); + } + + [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI const time_zone* current_zone() const { + return __current_zone(); + } + +private: + _LIBCPP_HIDE_FROM_ABI const time_zone* __find_in_zone(string_view __name) const noexcept { + if (auto __it = ranges::lower_bound(zones, __name, {}, &time_zone::name); + __it != zones.end() && __it->name() == __name) + return std::addressof(*__it); + + return nullptr; + } + + [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI const time_zone* __current_zone() const; +}; + +} // namespace chrono + +# endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) + // && !defined(_LIBCPP_HAS_NO_LOCALIZATION) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +#endif // _LIBCPP___CHRONO_TZDB_H diff --git a/libcxx/include/__cxx03/__chrono/tzdb_list.h b/libcxx/include/__cxx03/__chrono/tzdb_list.h new file mode 100644 index 0000000000000000000000000000000000000000..aeef4fe1aba3c1b48315fd3744679ef2e644e99e --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/tzdb_list.h @@ -0,0 +1,108 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#ifndef _LIBCPP___CHRONO_TZDB_LIST_H +#define _LIBCPP___CHRONO_TZDB_LIST_H + +#include +// Enable the contents of the header only when libc++ was built with experimental features enabled. +#if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +# include <__chrono/time_zone.h> +# include <__chrono/tzdb.h> +# include <__config> +# include <__fwd/string.h> +# include + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ + !defined(_LIBCPP_HAS_NO_LOCALIZATION) + +namespace chrono { + +// TODO TZDB +// Libc++ recently switched to only export __ugly_names from the dylib. +// Since the library is still experimental the functions in this header +// should be adapted to this new style. The other tzdb headers should be +// evaluated too. + +class _LIBCPP_AVAILABILITY_TZDB tzdb_list { +public: + class __impl; // public to allow construction in dylib + _LIBCPP_HIDE_FROM_ABI explicit tzdb_list(__impl* __p) : __impl_(__p) { + _LIBCPP_ASSERT_NON_NULL(__impl_ != nullptr, "initialized time_zone without a valid pimpl object"); + } + _LIBCPP_EXPORTED_FROM_ABI ~tzdb_list(); + + tzdb_list(const tzdb_list&) = delete; + tzdb_list& operator=(const tzdb_list&) = delete; + + using const_iterator = forward_list::const_iterator; + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const tzdb& front() const noexcept { return __front(); } + + _LIBCPP_HIDE_FROM_ABI const_iterator erase_after(const_iterator __p) { return __erase_after(__p); } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return __begin(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return __end(); } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const noexcept { return __cbegin(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const noexcept { return __cend(); } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __impl& __implementation() { return *__impl_; } + +private: + [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI const tzdb& __front() const noexcept; + + _LIBCPP_EXPORTED_FROM_ABI const_iterator __erase_after(const_iterator __p); + + [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI const_iterator __begin() const noexcept; + [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI const_iterator __end() const noexcept; + + [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI const_iterator __cbegin() const noexcept; + [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI const_iterator __cend() const noexcept; + + __impl* __impl_; +}; + +[[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI tzdb_list& get_tzdb_list(); + +[[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline const tzdb& get_tzdb() { + return get_tzdb_list().front(); +} + +[[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline const time_zone* locate_zone(string_view __name) { + return get_tzdb().locate_zone(__name); +} + +[[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline const time_zone* current_zone() { + return get_tzdb().current_zone(); +} + +_LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI const tzdb& reload_tzdb(); + +[[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI string remote_version(); + +} // namespace chrono + +# endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) + // && !defined(_LIBCPP_HAS_NO_LOCALIZATION) + +_LIBCPP_END_NAMESPACE_STD + +#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +#endif // _LIBCPP___CHRONO_TZDB_LIST_H diff --git a/libcxx/include/__cxx03/__chrono/weekday.h b/libcxx/include/__cxx03/__chrono/weekday.h new file mode 100644 index 0000000000000000000000000000000000000000..86c780cc718256ca3bf0c0662f7ba93e79cb061b --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/weekday.h @@ -0,0 +1,186 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_WEEKDAY_H +#define _LIBCPP___CHRONO_WEEKDAY_H + +#include <__chrono/calendar.h> +#include <__chrono/duration.h> +#include <__chrono/system_clock.h> +#include <__chrono/time_point.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +class weekday_indexed; +class weekday_last; + +class weekday { +private: + unsigned char __wd_; + _LIBCPP_HIDE_FROM_ABI static constexpr unsigned char __weekday_from_days(int __days) noexcept; + +public: + weekday() = default; + _LIBCPP_HIDE_FROM_ABI inline explicit constexpr weekday(unsigned __val) noexcept + : __wd_(static_cast(__val == 7 ? 0 : __val)) {} + _LIBCPP_HIDE_FROM_ABI inline constexpr weekday(const sys_days& __sysd) noexcept + : __wd_(__weekday_from_days(__sysd.time_since_epoch().count())) {} + _LIBCPP_HIDE_FROM_ABI inline explicit constexpr weekday(const local_days& __locd) noexcept + : __wd_(__weekday_from_days(__locd.time_since_epoch().count())) {} + + _LIBCPP_HIDE_FROM_ABI inline constexpr weekday& operator++() noexcept { + __wd_ = (__wd_ == 6 ? 0 : __wd_ + 1); + return *this; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr weekday operator++(int) noexcept { + weekday __tmp = *this; + ++(*this); + return __tmp; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr weekday& operator--() noexcept { + __wd_ = (__wd_ == 0 ? 6 : __wd_ - 1); + return *this; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr weekday operator--(int) noexcept { + weekday __tmp = *this; + --(*this); + return __tmp; + } + _LIBCPP_HIDE_FROM_ABI constexpr weekday& operator+=(const days& __dd) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr weekday& operator-=(const days& __dd) noexcept; + _LIBCPP_HIDE_FROM_ABI inline constexpr unsigned c_encoding() const noexcept { return __wd_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr unsigned iso_encoding() const noexcept { return __wd_ == 0u ? 7 : __wd_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr bool ok() const noexcept { return __wd_ <= 6; } + _LIBCPP_HIDE_FROM_ABI constexpr weekday_indexed operator[](unsigned __index) const noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr weekday_last operator[](last_spec) const noexcept; +}; + +// https://howardhinnant.github.io/date_algorithms.html#weekday_from_days +_LIBCPP_HIDE_FROM_ABI inline constexpr unsigned char weekday::__weekday_from_days(int __days) noexcept { + return static_cast(static_cast(__days >= -4 ? (__days + 4) % 7 : (__days + 5) % 7 + 6)); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const weekday& __lhs, const weekday& __rhs) noexcept { + return __lhs.c_encoding() == __rhs.c_encoding(); +} + +// TODO(LLVM 20): Remove the escape hatch +# ifdef _LIBCPP_ENABLE_REMOVED_WEEKDAY_RELATIONAL_OPERATORS +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator<(const weekday& __lhs, const weekday& __rhs) noexcept { + return __lhs.c_encoding() < __rhs.c_encoding(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator>(const weekday& __lhs, const weekday& __rhs) noexcept { + return __rhs < __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator<=(const weekday& __lhs, const weekday& __rhs) noexcept { + return !(__rhs < __lhs); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator>=(const weekday& __lhs, const weekday& __rhs) noexcept { + return !(__lhs < __rhs); +} +# endif // _LIBCPP_ENABLE_REMOVED_WEEKDAY_RELATIONAL_OPERATORS + +_LIBCPP_HIDE_FROM_ABI inline constexpr weekday operator+(const weekday& __lhs, const days& __rhs) noexcept { + auto const __mu = static_cast(__lhs.c_encoding()) + __rhs.count(); + auto const __yr = (__mu >= 0 ? __mu : __mu - 6) / 7; + return weekday{static_cast(__mu - __yr * 7)}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr weekday operator+(const days& __lhs, const weekday& __rhs) noexcept { + return __rhs + __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr weekday operator-(const weekday& __lhs, const days& __rhs) noexcept { + return __lhs + -__rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr days operator-(const weekday& __lhs, const weekday& __rhs) noexcept { + const int __wdu = __lhs.c_encoding() - __rhs.c_encoding(); + const int __wk = (__wdu >= 0 ? __wdu : __wdu - 6) / 7; + return days{__wdu - __wk * 7}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr weekday& weekday::operator+=(const days& __dd) noexcept { + *this = *this + __dd; + return *this; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr weekday& weekday::operator-=(const days& __dd) noexcept { + *this = *this - __dd; + return *this; +} + +class weekday_indexed { +private: + chrono::weekday __wd_; + unsigned char __idx_; + +public: + weekday_indexed() = default; + _LIBCPP_HIDE_FROM_ABI inline constexpr weekday_indexed(const chrono::weekday& __wdval, unsigned __idxval) noexcept + : __wd_{__wdval}, __idx_(__idxval) {} + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::weekday weekday() const noexcept { return __wd_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr unsigned index() const noexcept { return __idx_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr bool ok() const noexcept { return __wd_.ok() && __idx_ >= 1 && __idx_ <= 5; } +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool +operator==(const weekday_indexed& __lhs, const weekday_indexed& __rhs) noexcept { + return __lhs.weekday() == __rhs.weekday() && __lhs.index() == __rhs.index(); +} + +class weekday_last { +private: + chrono::weekday __wd_; + +public: + _LIBCPP_HIDE_FROM_ABI explicit constexpr weekday_last(const chrono::weekday& __val) noexcept : __wd_{__val} {} + _LIBCPP_HIDE_FROM_ABI constexpr chrono::weekday weekday() const noexcept { return __wd_; } + _LIBCPP_HIDE_FROM_ABI constexpr bool ok() const noexcept { return __wd_.ok(); } +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const weekday_last& __lhs, const weekday_last& __rhs) noexcept { + return __lhs.weekday() == __rhs.weekday(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr weekday_indexed weekday::operator[](unsigned __index) const noexcept { + return weekday_indexed{*this, __index}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr weekday_last weekday::operator[](last_spec) const noexcept { + return weekday_last{*this}; +} + +inline constexpr weekday Sunday{0}; +inline constexpr weekday Monday{1}; +inline constexpr weekday Tuesday{2}; +inline constexpr weekday Wednesday{3}; +inline constexpr weekday Thursday{4}; +inline constexpr weekday Friday{5}; +inline constexpr weekday Saturday{6}; + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___CHRONO_WEEKDAY_H diff --git a/libcxx/include/__cxx03/__chrono/year.h b/libcxx/include/__cxx03/__chrono/year.h new file mode 100644 index 0000000000000000000000000000000000000000..1899d09f38dbdbd78fc9e960bfffcdb5f8861fe3 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/year.h @@ -0,0 +1,118 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_YEAR_H +#define _LIBCPP___CHRONO_YEAR_H + +#include <__chrono/duration.h> +#include <__config> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +class year { +private: + short __y_; + +public: + year() = default; + _LIBCPP_HIDE_FROM_ABI explicit inline constexpr year(int __val) noexcept : __y_(static_cast(__val)) {} + + _LIBCPP_HIDE_FROM_ABI inline constexpr year& operator++() noexcept { + ++__y_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr year operator++(int) noexcept { + year __tmp = *this; + ++(*this); + return __tmp; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr year& operator--() noexcept { + --__y_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr year operator--(int) noexcept { + year __tmp = *this; + --(*this); + return __tmp; + } + _LIBCPP_HIDE_FROM_ABI constexpr year& operator+=(const years& __dy) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr year& operator-=(const years& __dy) noexcept; + _LIBCPP_HIDE_FROM_ABI inline constexpr year operator+() const noexcept { return *this; } + _LIBCPP_HIDE_FROM_ABI inline constexpr year operator-() const noexcept { return year{-__y_}; } + + _LIBCPP_HIDE_FROM_ABI inline constexpr bool is_leap() const noexcept { + return __y_ % 4 == 0 && (__y_ % 100 != 0 || __y_ % 400 == 0); + } + _LIBCPP_HIDE_FROM_ABI explicit inline constexpr operator int() const noexcept { return __y_; } + _LIBCPP_HIDE_FROM_ABI constexpr bool ok() const noexcept; + _LIBCPP_HIDE_FROM_ABI static inline constexpr year min() noexcept { return year{-32767}; } + _LIBCPP_HIDE_FROM_ABI static inline constexpr year max() noexcept { return year{32767}; } +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const year& __lhs, const year& __rhs) noexcept { + return static_cast(__lhs) == static_cast(__rhs); +} + +_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const year& __lhs, const year& __rhs) noexcept { + return static_cast(__lhs) <=> static_cast(__rhs); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year operator+(const year& __lhs, const years& __rhs) noexcept { + return year(static_cast(__lhs) + __rhs.count()); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year operator+(const years& __lhs, const year& __rhs) noexcept { + return __rhs + __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year operator-(const year& __lhs, const years& __rhs) noexcept { + return __lhs + -__rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr years operator-(const year& __lhs, const year& __rhs) noexcept { + return years{static_cast(__lhs) - static_cast(__rhs)}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year& year::operator+=(const years& __dy) noexcept { + *this = *this + __dy; + return *this; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year& year::operator-=(const years& __dy) noexcept { + *this = *this - __dy; + return *this; +} + +_LIBCPP_HIDE_FROM_ABI constexpr bool year::ok() const noexcept { + static_assert(static_cast(std::numeric_limits::max()) == static_cast(max())); + return static_cast(min()) <= __y_; +} + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___CHRONO_YEAR_H diff --git a/libcxx/include/__cxx03/__chrono/year_month.h b/libcxx/include/__cxx03/__chrono/year_month.h new file mode 100644 index 0000000000000000000000000000000000000000..369ea38f7560d9ba7f8516aca765d08fee70c786 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/year_month.h @@ -0,0 +1,123 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_YEAR_MONTH_H +#define _LIBCPP___CHRONO_YEAR_MONTH_H + +#include <__chrono/duration.h> +#include <__chrono/month.h> +#include <__chrono/year.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +class year_month { + chrono::year __y_; + chrono::month __m_; + +public: + year_month() = default; + _LIBCPP_HIDE_FROM_ABI constexpr year_month(const chrono::year& __yval, const chrono::month& __mval) noexcept + : __y_{__yval}, __m_{__mval} {} + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::year year() const noexcept { return __y_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::month month() const noexcept { return __m_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr year_month& operator+=(const months& __dm) noexcept; + _LIBCPP_HIDE_FROM_ABI inline constexpr year_month& operator-=(const months& __dm) noexcept; + _LIBCPP_HIDE_FROM_ABI inline constexpr year_month& operator+=(const years& __dy) noexcept; + _LIBCPP_HIDE_FROM_ABI inline constexpr year_month& operator-=(const years& __dy) noexcept; + _LIBCPP_HIDE_FROM_ABI inline constexpr bool ok() const noexcept { return __y_.ok() && __m_.ok(); } +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month operator/(const year& __y, const month& __m) noexcept { + return year_month{__y, __m}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month operator/(const year& __y, int __m) noexcept { + return year_month{__y, month(__m)}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool operator==(const year_month& __lhs, const year_month& __rhs) noexcept { + return __lhs.year() == __rhs.year() && __lhs.month() == __rhs.month(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering +operator<=>(const year_month& __lhs, const year_month& __rhs) noexcept { + if (auto __c = __lhs.year() <=> __rhs.year(); __c != 0) + return __c; + return __lhs.month() <=> __rhs.month(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month operator+(const year_month& __lhs, const months& __rhs) noexcept { + int __dmi = static_cast(static_cast(__lhs.month())) - 1 + __rhs.count(); + const int __dy = (__dmi >= 0 ? __dmi : __dmi - 11) / 12; + __dmi = __dmi - __dy * 12 + 1; + return (__lhs.year() + years(__dy)) / month(static_cast(__dmi)); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month operator+(const months& __lhs, const year_month& __rhs) noexcept { + return __rhs + __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month operator+(const year_month& __lhs, const years& __rhs) noexcept { + return (__lhs.year() + __rhs) / __lhs.month(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month operator+(const years& __lhs, const year_month& __rhs) noexcept { + return __rhs + __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr months operator-(const year_month& __lhs, const year_month& __rhs) noexcept { + return (__lhs.year() - __rhs.year()) + + months(static_cast(__lhs.month()) - static_cast(__rhs.month())); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month operator-(const year_month& __lhs, const months& __rhs) noexcept { + return __lhs + -__rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month operator-(const year_month& __lhs, const years& __rhs) noexcept { + return __lhs + -__rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month& year_month::operator+=(const months& __dm) noexcept { + *this = *this + __dm; + return *this; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month& year_month::operator-=(const months& __dm) noexcept { + *this = *this - __dm; + return *this; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month& year_month::operator+=(const years& __dy) noexcept { + *this = *this + __dy; + return *this; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month& year_month::operator-=(const years& __dy) noexcept { + *this = *this - __dy; + return *this; +} + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___CHRONO_YEAR_MONTH_H diff --git a/libcxx/include/__cxx03/__chrono/year_month_day.h b/libcxx/include/__cxx03/__chrono/year_month_day.h new file mode 100644 index 0000000000000000000000000000000000000000..b06c0be03e0de40d50f7885d51787744a2c68c9a --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/year_month_day.h @@ -0,0 +1,337 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_YEAR_MONTH_DAY_H +#define _LIBCPP___CHRONO_YEAR_MONTH_DAY_H + +#include <__chrono/calendar.h> +#include <__chrono/day.h> +#include <__chrono/duration.h> +#include <__chrono/month.h> +#include <__chrono/monthday.h> +#include <__chrono/system_clock.h> +#include <__chrono/time_point.h> +#include <__chrono/year.h> +#include <__chrono/year_month.h> +#include <__config> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +class year_month_day_last; + +class year_month_day { +private: + chrono::year __y_; + chrono::month __m_; + chrono::day __d_; + +public: + year_month_day() = default; + _LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day( + const chrono::year& __yval, const chrono::month& __mval, const chrono::day& __dval) noexcept + : __y_{__yval}, __m_{__mval}, __d_{__dval} {} + _LIBCPP_HIDE_FROM_ABI constexpr year_month_day(const year_month_day_last& __ymdl) noexcept; + _LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day(const sys_days& __sysd) noexcept + : year_month_day(__from_days(__sysd.time_since_epoch())) {} + _LIBCPP_HIDE_FROM_ABI inline explicit constexpr year_month_day(const local_days& __locd) noexcept + : year_month_day(__from_days(__locd.time_since_epoch())) {} + + _LIBCPP_HIDE_FROM_ABI constexpr year_month_day& operator+=(const months& __dm) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr year_month_day& operator-=(const months& __dm) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr year_month_day& operator+=(const years& __dy) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr year_month_day& operator-=(const years& __dy) noexcept; + + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::year year() const noexcept { return __y_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::month month() const noexcept { return __m_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::day day() const noexcept { return __d_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr operator sys_days() const noexcept { return sys_days{__to_days()}; } + _LIBCPP_HIDE_FROM_ABI inline explicit constexpr operator local_days() const noexcept { + return local_days{__to_days()}; + } + + _LIBCPP_HIDE_FROM_ABI constexpr bool ok() const noexcept; + + _LIBCPP_HIDE_FROM_ABI static constexpr year_month_day __from_days(days __d) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr days __to_days() const noexcept; +}; + +// https://howardhinnant.github.io/date_algorithms.html#civil_from_days +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day year_month_day::__from_days(days __d) noexcept { + static_assert(numeric_limits::digits >= 18, ""); + static_assert(numeric_limits::digits >= 20, ""); + const int __z = __d.count() + 719468; + const int __era = (__z >= 0 ? __z : __z - 146096) / 146097; + const unsigned __doe = static_cast(__z - __era * 146097); // [0, 146096] + const unsigned __yoe = (__doe - __doe / 1460 + __doe / 36524 - __doe / 146096) / 365; // [0, 399] + const int __yr = static_cast(__yoe) + __era * 400; + const unsigned __doy = __doe - (365 * __yoe + __yoe / 4 - __yoe / 100); // [0, 365] + const unsigned __mp = (5 * __doy + 2) / 153; // [0, 11] + const unsigned __dy = __doy - (153 * __mp + 2) / 5 + 1; // [1, 31] + const unsigned __mth = __mp + (__mp < 10 ? 3 : -9); // [1, 12] + return year_month_day{chrono::year{__yr + (__mth <= 2)}, chrono::month{__mth}, chrono::day{__dy}}; +} + +// https://howardhinnant.github.io/date_algorithms.html#days_from_civil +_LIBCPP_HIDE_FROM_ABI inline constexpr days year_month_day::__to_days() const noexcept { + static_assert(numeric_limits::digits >= 18, ""); + static_assert(numeric_limits::digits >= 20, ""); + + const int __yr = static_cast(__y_) - (__m_ <= February); + const unsigned __mth = static_cast(__m_); + const unsigned __dy = static_cast(__d_); + + const int __era = (__yr >= 0 ? __yr : __yr - 399) / 400; + const unsigned __yoe = static_cast(__yr - __era * 400); // [0, 399] + const unsigned __doy = (153 * (__mth + (__mth > 2 ? -3 : 9)) + 2) / 5 + __dy - 1; // [0, 365] + const unsigned __doe = __yoe * 365 + __yoe / 4 - __yoe / 100 + __doy; // [0, 146096] + return days{__era * 146097 + static_cast(__doe) - 719468}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool +operator==(const year_month_day& __lhs, const year_month_day& __rhs) noexcept { + return __lhs.year() == __rhs.year() && __lhs.month() == __rhs.month() && __lhs.day() == __rhs.day(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering +operator<=>(const year_month_day& __lhs, const year_month_day& __rhs) noexcept { + if (auto __c = __lhs.year() <=> __rhs.year(); __c != 0) + return __c; + if (auto __c = __lhs.month() <=> __rhs.month(); __c != 0) + return __c; + return __lhs.day() <=> __rhs.day(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day operator/(const year_month& __lhs, const day& __rhs) noexcept { + return year_month_day{__lhs.year(), __lhs.month(), __rhs}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day operator/(const year_month& __lhs, int __rhs) noexcept { + return __lhs / day(__rhs); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day operator/(const year& __lhs, const month_day& __rhs) noexcept { + return __lhs / __rhs.month() / __rhs.day(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day operator/(int __lhs, const month_day& __rhs) noexcept { + return year(__lhs) / __rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day operator/(const month_day& __lhs, const year& __rhs) noexcept { + return __rhs / __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day operator/(const month_day& __lhs, int __rhs) noexcept { + return year(__rhs) / __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day +operator+(const year_month_day& __lhs, const months& __rhs) noexcept { + return (__lhs.year() / __lhs.month() + __rhs) / __lhs.day(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day +operator+(const months& __lhs, const year_month_day& __rhs) noexcept { + return __rhs + __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day +operator-(const year_month_day& __lhs, const months& __rhs) noexcept { + return __lhs + -__rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day +operator+(const year_month_day& __lhs, const years& __rhs) noexcept { + return (__lhs.year() + __rhs) / __lhs.month() / __lhs.day(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day +operator+(const years& __lhs, const year_month_day& __rhs) noexcept { + return __rhs + __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day +operator-(const year_month_day& __lhs, const years& __rhs) noexcept { + return __lhs + -__rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day& year_month_day::operator+=(const months& __dm) noexcept { + *this = *this + __dm; + return *this; +} +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day& year_month_day::operator-=(const months& __dm) noexcept { + *this = *this - __dm; + return *this; +} +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day& year_month_day::operator+=(const years& __dy) noexcept { + *this = *this + __dy; + return *this; +} +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day& year_month_day::operator-=(const years& __dy) noexcept { + *this = *this - __dy; + return *this; +} + +class year_month_day_last { +private: + chrono::year __y_; + chrono::month_day_last __mdl_; + +public: + _LIBCPP_HIDE_FROM_ABI constexpr year_month_day_last(const year& __yval, const month_day_last& __mdlval) noexcept + : __y_{__yval}, __mdl_{__mdlval} {} + + _LIBCPP_HIDE_FROM_ABI constexpr year_month_day_last& operator+=(const months& __m) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr year_month_day_last& operator-=(const months& __m) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr year_month_day_last& operator+=(const years& __y) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr year_month_day_last& operator-=(const years& __y) noexcept; + + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::year year() const noexcept { return __y_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::month month() const noexcept { return __mdl_.month(); } + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::month_day_last month_day_last() const noexcept { return __mdl_; } + _LIBCPP_HIDE_FROM_ABI constexpr chrono::day day() const noexcept; + _LIBCPP_HIDE_FROM_ABI inline constexpr operator sys_days() const noexcept { + return sys_days{year() / month() / day()}; + } + _LIBCPP_HIDE_FROM_ABI inline explicit constexpr operator local_days() const noexcept { + return local_days{year() / month() / day()}; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr bool ok() const noexcept { return __y_.ok() && __mdl_.ok(); } +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr chrono::day year_month_day_last::day() const noexcept { + constexpr chrono::day __d[] = { + chrono::day(31), + chrono::day(28), + chrono::day(31), + chrono::day(30), + chrono::day(31), + chrono::day(30), + chrono::day(31), + chrono::day(31), + chrono::day(30), + chrono::day(31), + chrono::day(30), + chrono::day(31)}; + return (month() != February || !__y_.is_leap()) && month().ok() + ? __d[static_cast(month()) - 1] + : chrono::day{29}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool +operator==(const year_month_day_last& __lhs, const year_month_day_last& __rhs) noexcept { + return __lhs.year() == __rhs.year() && __lhs.month_day_last() == __rhs.month_day_last(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr strong_ordering +operator<=>(const year_month_day_last& __lhs, const year_month_day_last& __rhs) noexcept { + if (auto __c = __lhs.year() <=> __rhs.year(); __c != 0) + return __c; + return __lhs.month_day_last() <=> __rhs.month_day_last(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last operator/(const year_month& __lhs, last_spec) noexcept { + return year_month_day_last{__lhs.year(), month_day_last{__lhs.month()}}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last +operator/(const year& __lhs, const month_day_last& __rhs) noexcept { + return year_month_day_last{__lhs, __rhs}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last operator/(int __lhs, const month_day_last& __rhs) noexcept { + return year_month_day_last{year{__lhs}, __rhs}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last +operator/(const month_day_last& __lhs, const year& __rhs) noexcept { + return __rhs / __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last operator/(const month_day_last& __lhs, int __rhs) noexcept { + return year{__rhs} / __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last +operator+(const year_month_day_last& __lhs, const months& __rhs) noexcept { + return (__lhs.year() / __lhs.month() + __rhs) / last; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last +operator+(const months& __lhs, const year_month_day_last& __rhs) noexcept { + return __rhs + __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last +operator-(const year_month_day_last& __lhs, const months& __rhs) noexcept { + return __lhs + (-__rhs); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last +operator+(const year_month_day_last& __lhs, const years& __rhs) noexcept { + return year_month_day_last{__lhs.year() + __rhs, __lhs.month_day_last()}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last +operator+(const years& __lhs, const year_month_day_last& __rhs) noexcept { + return __rhs + __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last +operator-(const year_month_day_last& __lhs, const years& __rhs) noexcept { + return __lhs + (-__rhs); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last& +year_month_day_last::operator+=(const months& __dm) noexcept { + *this = *this + __dm; + return *this; +} +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last& +year_month_day_last::operator-=(const months& __dm) noexcept { + *this = *this - __dm; + return *this; +} +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last& +year_month_day_last::operator+=(const years& __dy) noexcept { + *this = *this + __dy; + return *this; +} +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day_last& +year_month_day_last::operator-=(const years& __dy) noexcept { + *this = *this - __dy; + return *this; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_day::year_month_day(const year_month_day_last& __ymdl) noexcept + : __y_{__ymdl.year()}, __m_{__ymdl.month()}, __d_{__ymdl.day()} {} + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool year_month_day::ok() const noexcept { + if (!__y_.ok() || !__m_.ok()) + return false; + return chrono::day{1} <= __d_ && __d_ <= (__y_ / __m_ / last).day(); +} + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___CHRONO_YEAR_MONTH_DAY_H diff --git a/libcxx/include/__cxx03/__chrono/year_month_weekday.h b/libcxx/include/__cxx03/__chrono/year_month_weekday.h new file mode 100644 index 0000000000000000000000000000000000000000..0c3dd494c878720cd02ab6973093057c7debebe6 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/year_month_weekday.h @@ -0,0 +1,287 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_YEAR_MONTH_WEEKDAY_H +#define _LIBCPP___CHRONO_YEAR_MONTH_WEEKDAY_H + +#include <__chrono/calendar.h> +#include <__chrono/day.h> +#include <__chrono/duration.h> +#include <__chrono/month.h> +#include <__chrono/month_weekday.h> +#include <__chrono/system_clock.h> +#include <__chrono/time_point.h> +#include <__chrono/weekday.h> +#include <__chrono/year.h> +#include <__chrono/year_month.h> +#include <__chrono/year_month_day.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +class year_month_weekday { + chrono::year __y_; + chrono::month __m_; + chrono::weekday_indexed __wdi_; + +public: + year_month_weekday() = default; + _LIBCPP_HIDE_FROM_ABI constexpr year_month_weekday( + const chrono::year& __yval, const chrono::month& __mval, const chrono::weekday_indexed& __wdival) noexcept + : __y_{__yval}, __m_{__mval}, __wdi_{__wdival} {} + _LIBCPP_HIDE_FROM_ABI constexpr year_month_weekday(const sys_days& __sysd) noexcept + : year_month_weekday(__from_days(__sysd.time_since_epoch())) {} + _LIBCPP_HIDE_FROM_ABI inline explicit constexpr year_month_weekday(const local_days& __locd) noexcept + : year_month_weekday(__from_days(__locd.time_since_epoch())) {} + _LIBCPP_HIDE_FROM_ABI constexpr year_month_weekday& operator+=(const months&) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr year_month_weekday& operator-=(const months&) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr year_month_weekday& operator+=(const years&) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr year_month_weekday& operator-=(const years&) noexcept; + + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::year year() const noexcept { return __y_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::month month() const noexcept { return __m_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::weekday weekday() const noexcept { return __wdi_.weekday(); } + _LIBCPP_HIDE_FROM_ABI inline constexpr unsigned index() const noexcept { return __wdi_.index(); } + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::weekday_indexed weekday_indexed() const noexcept { return __wdi_; } + + _LIBCPP_HIDE_FROM_ABI inline constexpr operator sys_days() const noexcept { return sys_days{__to_days()}; } + _LIBCPP_HIDE_FROM_ABI inline explicit constexpr operator local_days() const noexcept { + return local_days{__to_days()}; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr bool ok() const noexcept { + if (!__y_.ok() || !__m_.ok() || !__wdi_.ok()) + return false; + if (__wdi_.index() <= 4) + return true; + auto __nth_weekday_day = + __wdi_.weekday() - chrono::weekday{static_cast(__y_ / __m_ / 1)} + days{(__wdi_.index() - 1) * 7 + 1}; + return static_cast(__nth_weekday_day.count()) <= static_cast((__y_ / __m_ / last).day()); + } + + _LIBCPP_HIDE_FROM_ABI static constexpr year_month_weekday __from_days(days __d) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr days __to_days() const noexcept; +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday year_month_weekday::__from_days(days __d) noexcept { + const sys_days __sysd{__d}; + const chrono::weekday __wd = chrono::weekday(__sysd); + const year_month_day __ymd = year_month_day(__sysd); + return year_month_weekday{__ymd.year(), __ymd.month(), __wd[(static_cast(__ymd.day()) - 1) / 7 + 1]}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr days year_month_weekday::__to_days() const noexcept { + const sys_days __sysd = sys_days(__y_ / __m_ / 1); + return (__sysd + (__wdi_.weekday() - chrono::weekday(__sysd) + days{(__wdi_.index() - 1) * 7})).time_since_epoch(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool +operator==(const year_month_weekday& __lhs, const year_month_weekday& __rhs) noexcept { + return __lhs.year() == __rhs.year() && __lhs.month() == __rhs.month() && + __lhs.weekday_indexed() == __rhs.weekday_indexed(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday +operator/(const year_month& __lhs, const weekday_indexed& __rhs) noexcept { + return year_month_weekday{__lhs.year(), __lhs.month(), __rhs}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday +operator/(const year& __lhs, const month_weekday& __rhs) noexcept { + return year_month_weekday{__lhs, __rhs.month(), __rhs.weekday_indexed()}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday operator/(int __lhs, const month_weekday& __rhs) noexcept { + return year(__lhs) / __rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday +operator/(const month_weekday& __lhs, const year& __rhs) noexcept { + return __rhs / __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday operator/(const month_weekday& __lhs, int __rhs) noexcept { + return year(__rhs) / __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday +operator+(const year_month_weekday& __lhs, const months& __rhs) noexcept { + return (__lhs.year() / __lhs.month() + __rhs) / __lhs.weekday_indexed(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday +operator+(const months& __lhs, const year_month_weekday& __rhs) noexcept { + return __rhs + __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday +operator-(const year_month_weekday& __lhs, const months& __rhs) noexcept { + return __lhs + (-__rhs); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday +operator+(const year_month_weekday& __lhs, const years& __rhs) noexcept { + return year_month_weekday{__lhs.year() + __rhs, __lhs.month(), __lhs.weekday_indexed()}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday +operator+(const years& __lhs, const year_month_weekday& __rhs) noexcept { + return __rhs + __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday +operator-(const year_month_weekday& __lhs, const years& __rhs) noexcept { + return __lhs + (-__rhs); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday& year_month_weekday::operator+=(const months& __dm) noexcept { + *this = *this + __dm; + return *this; +} +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday& year_month_weekday::operator-=(const months& __dm) noexcept { + *this = *this - __dm; + return *this; +} +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday& year_month_weekday::operator+=(const years& __dy) noexcept { + *this = *this + __dy; + return *this; +} +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday& year_month_weekday::operator-=(const years& __dy) noexcept { + *this = *this - __dy; + return *this; +} + +class year_month_weekday_last { +private: + chrono::year __y_; + chrono::month __m_; + chrono::weekday_last __wdl_; + +public: + _LIBCPP_HIDE_FROM_ABI constexpr year_month_weekday_last( + const chrono::year& __yval, const chrono::month& __mval, const chrono::weekday_last& __wdlval) noexcept + : __y_{__yval}, __m_{__mval}, __wdl_{__wdlval} {} + _LIBCPP_HIDE_FROM_ABI constexpr year_month_weekday_last& operator+=(const months& __dm) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr year_month_weekday_last& operator-=(const months& __dm) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr year_month_weekday_last& operator+=(const years& __dy) noexcept; + _LIBCPP_HIDE_FROM_ABI constexpr year_month_weekday_last& operator-=(const years& __dy) noexcept; + + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::year year() const noexcept { return __y_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::month month() const noexcept { return __m_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::weekday weekday() const noexcept { return __wdl_.weekday(); } + _LIBCPP_HIDE_FROM_ABI inline constexpr chrono::weekday_last weekday_last() const noexcept { return __wdl_; } + _LIBCPP_HIDE_FROM_ABI inline constexpr operator sys_days() const noexcept { return sys_days{__to_days()}; } + _LIBCPP_HIDE_FROM_ABI inline explicit constexpr operator local_days() const noexcept { + return local_days{__to_days()}; + } + _LIBCPP_HIDE_FROM_ABI inline constexpr bool ok() const noexcept { return __y_.ok() && __m_.ok() && __wdl_.ok(); } + + _LIBCPP_HIDE_FROM_ABI constexpr days __to_days() const noexcept; +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr days year_month_weekday_last::__to_days() const noexcept { + const sys_days __last = sys_days{__y_ / __m_ / last}; + return (__last - (chrono::weekday{__last} - __wdl_.weekday())).time_since_epoch(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool +operator==(const year_month_weekday_last& __lhs, const year_month_weekday_last& __rhs) noexcept { + return __lhs.year() == __rhs.year() && __lhs.month() == __rhs.month() && __lhs.weekday_last() == __rhs.weekday_last(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last +operator/(const year_month& __lhs, const weekday_last& __rhs) noexcept { + return year_month_weekday_last{__lhs.year(), __lhs.month(), __rhs}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last +operator/(const year& __lhs, const month_weekday_last& __rhs) noexcept { + return year_month_weekday_last{__lhs, __rhs.month(), __rhs.weekday_last()}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last +operator/(int __lhs, const month_weekday_last& __rhs) noexcept { + return year(__lhs) / __rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last +operator/(const month_weekday_last& __lhs, const year& __rhs) noexcept { + return __rhs / __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last +operator/(const month_weekday_last& __lhs, int __rhs) noexcept { + return year(__rhs) / __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last +operator+(const year_month_weekday_last& __lhs, const months& __rhs) noexcept { + return (__lhs.year() / __lhs.month() + __rhs) / __lhs.weekday_last(); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last +operator+(const months& __lhs, const year_month_weekday_last& __rhs) noexcept { + return __rhs + __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last +operator-(const year_month_weekday_last& __lhs, const months& __rhs) noexcept { + return __lhs + (-__rhs); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last +operator+(const year_month_weekday_last& __lhs, const years& __rhs) noexcept { + return year_month_weekday_last{__lhs.year() + __rhs, __lhs.month(), __lhs.weekday_last()}; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last +operator+(const years& __lhs, const year_month_weekday_last& __rhs) noexcept { + return __rhs + __lhs; +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last +operator-(const year_month_weekday_last& __lhs, const years& __rhs) noexcept { + return __lhs + (-__rhs); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last& +year_month_weekday_last::operator+=(const months& __dm) noexcept { + *this = *this + __dm; + return *this; +} +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last& +year_month_weekday_last::operator-=(const months& __dm) noexcept { + *this = *this - __dm; + return *this; +} +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last& +year_month_weekday_last::operator+=(const years& __dy) noexcept { + *this = *this + __dy; + return *this; +} +_LIBCPP_HIDE_FROM_ABI inline constexpr year_month_weekday_last& +year_month_weekday_last::operator-=(const years& __dy) noexcept { + *this = *this - __dy; + return *this; +} + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___CHRONO_YEAR_MONTH_WEEKDAY_H diff --git a/libcxx/include/__cxx03/__chrono/zoned_time.h b/libcxx/include/__cxx03/__chrono/zoned_time.h new file mode 100644 index 0000000000000000000000000000000000000000..8cfa2122642c5e3c475be6bf0a8ee024ca296189 --- /dev/null +++ b/libcxx/include/__cxx03/__chrono/zoned_time.h @@ -0,0 +1,227 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#ifndef _LIBCPP___CHRONO_ZONED_TIME_H +#define _LIBCPP___CHRONO_ZONED_TIME_H + +#include +// Enable the contents of the header only when libc++ was built with experimental features enabled. +#if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +# include <__chrono/calendar.h> +# include <__chrono/duration.h> +# include <__chrono/sys_info.h> +# include <__chrono/system_clock.h> +# include <__chrono/time_zone.h> +# include <__chrono/tzdb_list.h> +# include <__config> +# include <__fwd/string_view.h> +# include <__type_traits/common_type.h> +# include <__type_traits/conditional.h> +# include <__type_traits/remove_cvref.h> +# include <__utility/move.h> + +# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +# endif + +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ + !defined(_LIBCPP_HAS_NO_LOCALIZATION) + +namespace chrono { + +template +struct zoned_traits {}; + +template <> +struct zoned_traits { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static const time_zone* default_zone() { return chrono::locate_zone("UTC"); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static const time_zone* locate_zone(string_view __name) { + return chrono::locate_zone(__name); + } +}; + +template +class zoned_time { + // [time.zone.zonedtime.ctor]/2 + static_assert(__is_duration<_Duration>::value, + "the program is ill-formed since _Duration is not a specialization of std::chrono::duration"); + + // The wording uses the constraints like + // constructible_from + // Using these constraints in the code causes the compiler to give an + // error that the constraint depends on itself. To avoid that issue use + // the fact it is possible to create this object from a _TimeZonePtr. + using __traits = zoned_traits<_TimeZonePtr>; + +public: + using duration = common_type_t<_Duration, seconds>; + + _LIBCPP_HIDE_FROM_ABI zoned_time() + requires requires { __traits::default_zone(); } + : __zone_{__traits::default_zone()}, __tp_{} {} + + _LIBCPP_HIDE_FROM_ABI zoned_time(const zoned_time&) = default; + _LIBCPP_HIDE_FROM_ABI zoned_time& operator=(const zoned_time&) = default; + + _LIBCPP_HIDE_FROM_ABI zoned_time(const sys_time<_Duration>& __tp) + requires requires { __traits::default_zone(); } + : __zone_{__traits::default_zone()}, __tp_{__tp} {} + + _LIBCPP_HIDE_FROM_ABI explicit zoned_time(_TimeZonePtr __zone) : __zone_{std::move(__zone)}, __tp_{} {} + + _LIBCPP_HIDE_FROM_ABI explicit zoned_time(string_view __name) + requires(requires { __traits::locate_zone(string_view{}); } && + constructible_from<_TimeZonePtr, decltype(__traits::locate_zone(string_view{}))>) + : __zone_{__traits::locate_zone(__name)}, __tp_{} {} + + template + _LIBCPP_HIDE_FROM_ABI zoned_time(const zoned_time<_Duration2, _TimeZonePtr>& __zt) + requires is_convertible_v, sys_time<_Duration>> + : __zone_{__zt.get_time_zone()}, __tp_{__zt.get_sys_time()} {} + + _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const sys_time<_Duration>& __tp) + : __zone_{std::move(__zone)}, __tp_{__tp} {} + + _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const sys_time<_Duration>& __tp) + requires requires { _TimeZonePtr{__traits::locate_zone(string_view{})}; } + : zoned_time{__traits::locate_zone(__name), __tp} {} + + _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const local_time<_Duration>& __tp) + requires(is_convertible_v() -> to_sys(local_time<_Duration>{})), + sys_time>) + : __zone_{std::move(__zone)}, __tp_{__zone_->to_sys(__tp)} {} + + _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const local_time<_Duration>& __tp) + requires(requires { + _TimeZonePtr{__traits::locate_zone(string_view{})}; + } && is_convertible_v() -> to_sys(local_time<_Duration>{})), + sys_time>) + : zoned_time{__traits::locate_zone(__name), __tp} {} + + _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const local_time<_Duration>& __tp, choose __c) + requires(is_convertible_v< + decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{}, choose::earliest)), + sys_time>) + : __zone_{std::move(__zone)}, __tp_{__zone_->to_sys(__tp, __c)} {} + + _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const local_time<_Duration>& __tp, choose __c) + requires(requires { + _TimeZonePtr{__traits::locate_zone(string_view{})}; + } && is_convertible_v() -> to_sys(local_time<_Duration>{}, choose::earliest)), + sys_time>) + : zoned_time{__traits::locate_zone(__name), __tp, __c} {} + + template + _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const zoned_time<_Duration2, _TimeZonePtr2>& __zt) + requires is_convertible_v, sys_time<_Duration>> + : __zone_{std::move(__zone)}, __tp_{__zt.get_sys_time()} {} + + // per wording choose has no effect + template + _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const zoned_time<_Duration2, _TimeZonePtr2>& __zt, choose) + requires is_convertible_v, sys_time<_Duration>> + : __zone_{std::move(__zone)}, __tp_{__zt.get_sys_time()} {} + + template + _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const zoned_time<_Duration2, _TimeZonePtr2>& __zt) + requires(requires { + _TimeZonePtr{__traits::locate_zone(string_view{})}; + } && is_convertible_v, sys_time<_Duration>>) + : zoned_time{__traits::locate_zone(__name), __zt} {} + + template + _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const zoned_time<_Duration2, _TimeZonePtr2>& __zt, choose __c) + requires(requires { + _TimeZonePtr{__traits::locate_zone(string_view{})}; + } && is_convertible_v, sys_time<_Duration>>) + : zoned_time{__traits::locate_zone(__name), __zt, __c} {} + + _LIBCPP_HIDE_FROM_ABI zoned_time& operator=(const sys_time<_Duration>& __tp) { + __tp_ = __tp; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI zoned_time& operator=(const local_time<_Duration>& __tp) { + // TODO TZDB This seems wrong. + // Assigning a non-existent or ambiguous time will throw and not satisfy + // the post condition. This seems quite odd; I constructed an object with + // choose::earliest and that choice is not respected. + // what did LEWG do with this. + // MSVC STL and libstdc++ behave the same + __tp_ = __zone_->to_sys(__tp); + return *this; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI operator sys_time() const { return get_sys_time(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit operator local_time() const { return get_local_time(); } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _TimeZonePtr get_time_zone() const { return __zone_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI local_time get_local_time() const { return __zone_->to_local(__tp_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_time get_sys_time() const { return __tp_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_info get_info() const { return __zone_->get_info(__tp_); } + +private: + _TimeZonePtr __zone_; + sys_time __tp_; +}; + +zoned_time() -> zoned_time; + +template +zoned_time(sys_time<_Duration>) -> zoned_time>; + +template +using __time_zone_representation = + conditional_t, + const time_zone*, + remove_cvref_t<_TimeZonePtrOrName>>; + +template +zoned_time(_TimeZonePtrOrName&&) -> zoned_time>; + +template +zoned_time(_TimeZonePtrOrName&&, sys_time<_Duration>) + -> zoned_time, __time_zone_representation<_TimeZonePtrOrName>>; + +template +zoned_time(_TimeZonePtrOrName&&, local_time<_Duration>, choose = choose::earliest) + -> zoned_time, __time_zone_representation<_TimeZonePtrOrName>>; + +template +zoned_time(_TimeZonePtrOrName&&, zoned_time<_Duration, TimeZonePtr2>, choose = choose::earliest) + -> zoned_time, __time_zone_representation<_TimeZonePtrOrName>>; + +using zoned_seconds = zoned_time; + +template +_LIBCPP_HIDE_FROM_ABI bool +operator==(const zoned_time<_Duration1, _TimeZonePtr>& __lhs, const zoned_time<_Duration2, _TimeZonePtr>& __rhs) { + return __lhs.get_time_zone() == __rhs.get_time_zone() && __lhs.get_sys_time() == __rhs.get_sys_time(); +} + +} // namespace chrono + +# endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) + // && !defined(_LIBCPP_HAS_NO_LOCALIZATION) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) + +#endif // _LIBCPP___CHRONO_ZONED_TIME_H diff --git a/libcxx/include/__cxx03/__compare/common_comparison_category.h b/libcxx/include/__cxx03/__compare/common_comparison_category.h new file mode 100644 index 0000000000000000000000000000000000000000..7aeb3da03a4f4a9975fa022a90ebcf63c2dc5a05 --- /dev/null +++ b/libcxx/include/__cxx03/__compare/common_comparison_category.h @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_COMMON_COMPARISON_CATEGORY_H +#define _LIBCPP___COMPARE_COMMON_COMPARISON_CATEGORY_H + +#include <__compare/ordering.h> +#include <__config> +#include <__type_traits/is_same.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __comp_detail { + +enum _ClassifyCompCategory : unsigned { _None, _PartialOrd, _WeakOrd, _StrongOrd, _CCC_Size }; + +template +_LIBCPP_HIDE_FROM_ABI constexpr _ClassifyCompCategory __type_to_enum() noexcept { + if (is_same_v<_Tp, partial_ordering>) + return _PartialOrd; + if (is_same_v<_Tp, weak_ordering>) + return _WeakOrd; + if (is_same_v<_Tp, strong_ordering>) + return _StrongOrd; + return _None; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr _ClassifyCompCategory +__compute_comp_type(const _ClassifyCompCategory (&__types)[_Size]) { + int __seen[_CCC_Size] = {}; + for (auto __type : __types) + ++__seen[__type]; + if (__seen[_None]) + return _None; + if (__seen[_PartialOrd]) + return _PartialOrd; + if (__seen[_WeakOrd]) + return _WeakOrd; + return _StrongOrd; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr auto __get_comp_type() { + using _CCC = _ClassifyCompCategory; + constexpr _CCC __type_kinds[] = {_StrongOrd, __type_to_enum<_Ts>()...}; + constexpr _CCC __cat = __comp_detail::__compute_comp_type(__type_kinds); + if constexpr (__cat == _None) + return void(); + else if constexpr (__cat == _PartialOrd) + return partial_ordering::equivalent; + else if constexpr (__cat == _WeakOrd) + return weak_ordering::equivalent; + else if constexpr (__cat == _StrongOrd) + return strong_ordering::equivalent; + else + static_assert(_False, "unhandled case"); +} +} // namespace __comp_detail + +// [cmp.common], common comparison category type +template +struct _LIBCPP_TEMPLATE_VIS common_comparison_category { + using type = decltype(__comp_detail::__get_comp_type<_Ts...>()); +}; + +template +using common_comparison_category_t = typename common_comparison_category<_Ts...>::type; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_COMMON_COMPARISON_CATEGORY_H diff --git a/libcxx/include/__cxx03/__compare/compare_partial_order_fallback.h b/libcxx/include/__cxx03/__compare/compare_partial_order_fallback.h new file mode 100644 index 0000000000000000000000000000000000000000..e0efa3ccb88db76eb4cbe18f7f5bb78a2eb05241 --- /dev/null +++ b/libcxx/include/__cxx03/__compare/compare_partial_order_fallback.h @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_COMPARE_PARTIAL_ORDER_FALLBACK +#define _LIBCPP___COMPARE_COMPARE_PARTIAL_ORDER_FALLBACK + +#include <__compare/ordering.h> +#include <__compare/partial_order.h> +#include <__config> +#include <__type_traits/decay.h> +#include <__type_traits/is_same.h> +#include <__utility/forward.h> +#include <__utility/priority_tag.h> + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [cmp.alg] +namespace __compare_partial_order_fallback { +struct __fn { + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<1>) noexcept( + noexcept(std::partial_order(std::forward<_Tp>(__t), std::forward<_Up>(__u)))) + -> decltype(std::partial_order(std::forward<_Tp>(__t), std::forward<_Up>(__u))) { + return std::partial_order(std::forward<_Tp>(__t), std::forward<_Up>(__u)); + } + + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) noexcept(noexcept( + std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? partial_ordering::equivalent + : std::forward<_Tp>(__t) < std::forward<_Up>(__u) ? partial_ordering::less + : std::forward<_Up>(__u) < std::forward<_Tp>(__t) + ? partial_ordering::greater + : partial_ordering::unordered)) + -> decltype(std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? partial_ordering::equivalent + : std::forward<_Tp>(__t) < std::forward<_Up>(__u) ? partial_ordering::less + : std::forward<_Up>(__u) < std::forward<_Tp>(__t) + ? partial_ordering::greater + : partial_ordering::unordered) { + return std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? partial_ordering::equivalent + : std::forward<_Tp>(__t) < std::forward<_Up>(__u) ? partial_ordering::less + : std::forward<_Up>(__u) < std::forward<_Tp>(__t) + ? partial_ordering::greater + : partial_ordering::unordered; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(__go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<1>()))) + -> decltype(__go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<1>())) { + return __go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<1>()); + } +}; +} // namespace __compare_partial_order_fallback + +inline namespace __cpo { +inline constexpr auto compare_partial_order_fallback = __compare_partial_order_fallback::__fn{}; +} // namespace __cpo + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_COMPARE_PARTIAL_ORDER_FALLBACK diff --git a/libcxx/include/__cxx03/__compare/compare_strong_order_fallback.h b/libcxx/include/__cxx03/__compare/compare_strong_order_fallback.h new file mode 100644 index 0000000000000000000000000000000000000000..a94d517ed30fcea591257d69a7f01f2f97b2812e --- /dev/null +++ b/libcxx/include/__cxx03/__compare/compare_strong_order_fallback.h @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_COMPARE_STRONG_ORDER_FALLBACK +#define _LIBCPP___COMPARE_COMPARE_STRONG_ORDER_FALLBACK + +#include <__compare/ordering.h> +#include <__compare/strong_order.h> +#include <__config> +#include <__type_traits/decay.h> +#include <__type_traits/is_same.h> +#include <__utility/forward.h> +#include <__utility/priority_tag.h> + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [cmp.alg] +namespace __compare_strong_order_fallback { +struct __fn { + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<1>) noexcept( + noexcept(std::strong_order(std::forward<_Tp>(__t), std::forward<_Up>(__u)))) + -> decltype(std::strong_order(std::forward<_Tp>(__t), std::forward<_Up>(__u))) { + return std::strong_order(std::forward<_Tp>(__t), std::forward<_Up>(__u)); + } + + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) noexcept(noexcept( + std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? strong_ordering::equal + : std::forward<_Tp>(__t) < std::forward<_Up>(__u) + ? strong_ordering::less + : strong_ordering::greater)) + -> decltype(std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? strong_ordering::equal + : std::forward<_Tp>(__t) < std::forward<_Up>(__u) + ? strong_ordering::less + : strong_ordering::greater) { + return std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? strong_ordering::equal + : std::forward<_Tp>(__t) < std::forward<_Up>(__u) + ? strong_ordering::less + : strong_ordering::greater; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(__go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<1>()))) + -> decltype(__go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<1>())) { + return __go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<1>()); + } +}; +} // namespace __compare_strong_order_fallback + +inline namespace __cpo { +inline constexpr auto compare_strong_order_fallback = __compare_strong_order_fallback::__fn{}; +} // namespace __cpo + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_COMPARE_STRONG_ORDER_FALLBACK diff --git a/libcxx/include/__cxx03/__compare/compare_three_way.h b/libcxx/include/__cxx03/__compare/compare_three_way.h new file mode 100644 index 0000000000000000000000000000000000000000..01c12076c0d73d021011587d169406d3c0d04f5a --- /dev/null +++ b/libcxx/include/__cxx03/__compare/compare_three_way.h @@ -0,0 +1,40 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_COMPARE_THREE_WAY_H +#define _LIBCPP___COMPARE_COMPARE_THREE_WAY_H + +#include <__compare/three_way_comparable.h> +#include <__config> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +struct _LIBCPP_TEMPLATE_VIS compare_three_way { + template + requires three_way_comparable_with<_T1, _T2> + constexpr _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) <=> std::forward<_T2>(__u))) { + return std::forward<_T1>(__t) <=> std::forward<_T2>(__u); + } + + using is_transparent = void; +}; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_COMPARE_THREE_WAY_H diff --git a/libcxx/include/__cxx03/__compare/compare_three_way_result.h b/libcxx/include/__cxx03/__compare/compare_three_way_result.h new file mode 100644 index 0000000000000000000000000000000000000000..d7508073433af465ae7d999985e65761a28f9d98 --- /dev/null +++ b/libcxx/include/__cxx03/__compare/compare_three_way_result.h @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_COMPARE_THREE_WAY_RESULT_H +#define _LIBCPP___COMPARE_COMPARE_THREE_WAY_RESULT_H + +#include <__config> +#include <__type_traits/make_const_lvalue_ref.h> +#include <__utility/declval.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +struct _LIBCPP_HIDE_FROM_ABI __compare_three_way_result {}; + +template +struct _LIBCPP_HIDE_FROM_ABI __compare_three_way_result< + _Tp, + _Up, + decltype(std::declval<__make_const_lvalue_ref<_Tp>>() <=> std::declval<__make_const_lvalue_ref<_Up>>(), void())> { + using type = decltype(std::declval<__make_const_lvalue_ref<_Tp>>() <=> std::declval<__make_const_lvalue_ref<_Up>>()); +}; + +template +struct _LIBCPP_TEMPLATE_VIS compare_three_way_result : __compare_three_way_result<_Tp, _Up, void> {}; + +template +using compare_three_way_result_t = typename compare_three_way_result<_Tp, _Up>::type; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_COMPARE_THREE_WAY_RESULT_H diff --git a/libcxx/include/__cxx03/__compare/compare_weak_order_fallback.h b/libcxx/include/__cxx03/__compare/compare_weak_order_fallback.h new file mode 100644 index 0000000000000000000000000000000000000000..062b7b582cd7ebdc427c7ccd250fe7a8bc2101dc --- /dev/null +++ b/libcxx/include/__cxx03/__compare/compare_weak_order_fallback.h @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_COMPARE_WEAK_ORDER_FALLBACK +#define _LIBCPP___COMPARE_COMPARE_WEAK_ORDER_FALLBACK + +#include <__compare/ordering.h> +#include <__compare/weak_order.h> +#include <__config> +#include <__type_traits/decay.h> +#include <__type_traits/is_same.h> +#include <__utility/forward.h> +#include <__utility/priority_tag.h> + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [cmp.alg] +namespace __compare_weak_order_fallback { +struct __fn { + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<1>) noexcept( + noexcept(std::weak_order(std::forward<_Tp>(__t), std::forward<_Up>(__u)))) + -> decltype(std::weak_order(std::forward<_Tp>(__t), std::forward<_Up>(__u))) { + return std::weak_order(std::forward<_Tp>(__t), std::forward<_Up>(__u)); + } + + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) noexcept(noexcept( + std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? weak_ordering::equivalent + : std::forward<_Tp>(__t) < std::forward<_Up>(__u) + ? weak_ordering::less + : weak_ordering::greater)) + -> decltype(std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? weak_ordering::equivalent + : std::forward<_Tp>(__t) < std::forward<_Up>(__u) + ? weak_ordering::less + : weak_ordering::greater) { + return std::forward<_Tp>(__t) == std::forward<_Up>(__u) ? weak_ordering::equivalent + : std::forward<_Tp>(__t) < std::forward<_Up>(__u) + ? weak_ordering::less + : weak_ordering::greater; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(__go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<1>()))) + -> decltype(__go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<1>())) { + return __go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<1>()); + } +}; +} // namespace __compare_weak_order_fallback + +inline namespace __cpo { +inline constexpr auto compare_weak_order_fallback = __compare_weak_order_fallback::__fn{}; +} // namespace __cpo + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_COMPARE_WEAK_ORDER_FALLBACK diff --git a/libcxx/include/__cxx03/__compare/is_eq.h b/libcxx/include/__cxx03/__compare/is_eq.h new file mode 100644 index 0000000000000000000000000000000000000000..9a82df1ebe88b7262598b3beae63f91e7342a1c8 --- /dev/null +++ b/libcxx/include/__cxx03/__compare/is_eq.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_IS_EQ_H +#define _LIBCPP___COMPARE_IS_EQ_H + +#include <__compare/ordering.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_eq(partial_ordering __c) noexcept { return __c == 0; } +_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_neq(partial_ordering __c) noexcept { return __c != 0; } +_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_lt(partial_ordering __c) noexcept { return __c < 0; } +_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_lteq(partial_ordering __c) noexcept { return __c <= 0; } +_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_gt(partial_ordering __c) noexcept { return __c > 0; } +_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_gteq(partial_ordering __c) noexcept { return __c >= 0; } + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_IS_EQ_H diff --git a/libcxx/include/__cxx03/__compare/ordering.h b/libcxx/include/__cxx03/__compare/ordering.h new file mode 100644 index 0000000000000000000000000000000000000000..2995d381304f0e4b10870aaeb184d4a21f5a2172 --- /dev/null +++ b/libcxx/include/__cxx03/__compare/ordering.h @@ -0,0 +1,278 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_ORDERING_H +#define _LIBCPP___COMPARE_ORDERING_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_same.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// exposition only +enum class _OrdResult : signed char { __less = -1, __equiv = 0, __greater = 1 }; + +enum class _NCmpResult : signed char { __unordered = -127 }; + +class partial_ordering; +class weak_ordering; +class strong_ordering; + +template +inline constexpr bool __one_of_v = (is_same_v<_Tp, _Args> || ...); + +struct _CmpUnspecifiedParam { + _LIBCPP_HIDE_FROM_ABI constexpr _CmpUnspecifiedParam(int _CmpUnspecifiedParam::*) noexcept {} + + template >> + _CmpUnspecifiedParam(_Tp) = delete; +}; + +class partial_ordering { + using _ValueT = signed char; + + _LIBCPP_HIDE_FROM_ABI explicit constexpr partial_ordering(_OrdResult __v) noexcept : __value_(_ValueT(__v)) {} + + _LIBCPP_HIDE_FROM_ABI explicit constexpr partial_ordering(_NCmpResult __v) noexcept : __value_(_ValueT(__v)) {} + + _LIBCPP_HIDE_FROM_ABI constexpr bool __is_ordered() const noexcept { + return __value_ != _ValueT(_NCmpResult::__unordered); + } + +public: + // valid values + static const partial_ordering less; + static const partial_ordering equivalent; + static const partial_ordering greater; + static const partial_ordering unordered; + + // comparisons + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(partial_ordering, partial_ordering) noexcept = default; + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(partial_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__is_ordered() && __v.__value_ == 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(partial_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__is_ordered() && __v.__value_ < 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(partial_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__is_ordered() && __v.__value_ <= 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(partial_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__is_ordered() && __v.__value_ > 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(partial_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__is_ordered() && __v.__value_ >= 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(_CmpUnspecifiedParam, partial_ordering __v) noexcept { + return __v.__is_ordered() && 0 < __v.__value_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(_CmpUnspecifiedParam, partial_ordering __v) noexcept { + return __v.__is_ordered() && 0 <= __v.__value_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(_CmpUnspecifiedParam, partial_ordering __v) noexcept { + return __v.__is_ordered() && 0 > __v.__value_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(_CmpUnspecifiedParam, partial_ordering __v) noexcept { + return __v.__is_ordered() && 0 >= __v.__value_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr partial_ordering + operator<=>(partial_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr partial_ordering + operator<=>(_CmpUnspecifiedParam, partial_ordering __v) noexcept { + return __v < 0 ? partial_ordering::greater : (__v > 0 ? partial_ordering::less : __v); + } + +private: + _ValueT __value_; +}; + +inline constexpr partial_ordering partial_ordering::less(_OrdResult::__less); +inline constexpr partial_ordering partial_ordering::equivalent(_OrdResult::__equiv); +inline constexpr partial_ordering partial_ordering::greater(_OrdResult::__greater); +inline constexpr partial_ordering partial_ordering::unordered(_NCmpResult ::__unordered); + +class weak_ordering { + using _ValueT = signed char; + + _LIBCPP_HIDE_FROM_ABI explicit constexpr weak_ordering(_OrdResult __v) noexcept : __value_(_ValueT(__v)) {} + +public: + static const weak_ordering less; + static const weak_ordering equivalent; + static const weak_ordering greater; + + _LIBCPP_HIDE_FROM_ABI constexpr operator partial_ordering() const noexcept { + return __value_ == 0 ? partial_ordering::equivalent + : (__value_ < 0 ? partial_ordering::less : partial_ordering::greater); + } + + // comparisons + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(weak_ordering, weak_ordering) noexcept = default; + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(weak_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__value_ == 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(weak_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__value_ < 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(weak_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__value_ <= 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(weak_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__value_ > 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(weak_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__value_ >= 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(_CmpUnspecifiedParam, weak_ordering __v) noexcept { + return 0 < __v.__value_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(_CmpUnspecifiedParam, weak_ordering __v) noexcept { + return 0 <= __v.__value_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(_CmpUnspecifiedParam, weak_ordering __v) noexcept { + return 0 > __v.__value_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(_CmpUnspecifiedParam, weak_ordering __v) noexcept { + return 0 >= __v.__value_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr weak_ordering operator<=>(weak_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr weak_ordering operator<=>(_CmpUnspecifiedParam, weak_ordering __v) noexcept { + return __v < 0 ? weak_ordering::greater : (__v > 0 ? weak_ordering::less : __v); + } + +private: + _ValueT __value_; +}; + +inline constexpr weak_ordering weak_ordering::less(_OrdResult::__less); +inline constexpr weak_ordering weak_ordering::equivalent(_OrdResult::__equiv); +inline constexpr weak_ordering weak_ordering::greater(_OrdResult::__greater); + +class strong_ordering { + using _ValueT = signed char; + + _LIBCPP_HIDE_FROM_ABI explicit constexpr strong_ordering(_OrdResult __v) noexcept : __value_(_ValueT(__v)) {} + +public: + static const strong_ordering less; + static const strong_ordering equal; + static const strong_ordering equivalent; + static const strong_ordering greater; + + // conversions + _LIBCPP_HIDE_FROM_ABI constexpr operator partial_ordering() const noexcept { + return __value_ == 0 ? partial_ordering::equivalent + : (__value_ < 0 ? partial_ordering::less : partial_ordering::greater); + } + + _LIBCPP_HIDE_FROM_ABI constexpr operator weak_ordering() const noexcept { + return __value_ == 0 ? weak_ordering::equivalent : (__value_ < 0 ? weak_ordering::less : weak_ordering::greater); + } + + // comparisons + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(strong_ordering, strong_ordering) noexcept = default; + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(strong_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__value_ == 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(strong_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__value_ < 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(strong_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__value_ <= 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(strong_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__value_ > 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(strong_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v.__value_ >= 0; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(_CmpUnspecifiedParam, strong_ordering __v) noexcept { + return 0 < __v.__value_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(_CmpUnspecifiedParam, strong_ordering __v) noexcept { + return 0 <= __v.__value_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(_CmpUnspecifiedParam, strong_ordering __v) noexcept { + return 0 > __v.__value_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(_CmpUnspecifiedParam, strong_ordering __v) noexcept { + return 0 >= __v.__value_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr strong_ordering + operator<=>(strong_ordering __v, _CmpUnspecifiedParam) noexcept { + return __v; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr strong_ordering + operator<=>(_CmpUnspecifiedParam, strong_ordering __v) noexcept { + return __v < 0 ? strong_ordering::greater : (__v > 0 ? strong_ordering::less : __v); + } + +private: + _ValueT __value_; +}; + +inline constexpr strong_ordering strong_ordering::less(_OrdResult::__less); +inline constexpr strong_ordering strong_ordering::equal(_OrdResult::__equiv); +inline constexpr strong_ordering strong_ordering::equivalent(_OrdResult::__equiv); +inline constexpr strong_ordering strong_ordering::greater(_OrdResult::__greater); + +/// [cmp.categories.pre]/1 +/// The types partial_ordering, weak_ordering, and strong_ordering are +/// collectively termed the comparison category types. +template +concept __comparison_category = __one_of_v<_Tp, partial_ordering, weak_ordering, strong_ordering>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_ORDERING_H diff --git a/libcxx/include/__cxx03/__compare/partial_order.h b/libcxx/include/__cxx03/__compare/partial_order.h new file mode 100644 index 0000000000000000000000000000000000000000..1d2fae63e5f248b83731ff3fd69495af0811630c --- /dev/null +++ b/libcxx/include/__cxx03/__compare/partial_order.h @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_PARTIAL_ORDER +#define _LIBCPP___COMPARE_PARTIAL_ORDER + +#include <__compare/compare_three_way.h> +#include <__compare/ordering.h> +#include <__compare/weak_order.h> +#include <__config> +#include <__type_traits/decay.h> +#include <__type_traits/is_same.h> +#include <__utility/forward.h> +#include <__utility/priority_tag.h> + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [cmp.alg] +namespace __partial_order { +void partial_order() = delete; + +struct __fn { + // NOLINTBEGIN(libcpp-robust-against-adl) partial_order should use ADL, but only here + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<2>) noexcept( + noexcept(partial_ordering(partial_order(std::forward<_Tp>(__t), std::forward<_Up>(__u))))) + -> decltype(partial_ordering(partial_order(std::forward<_Tp>(__t), std::forward<_Up>(__u)))) { + return partial_ordering(partial_order(std::forward<_Tp>(__t), std::forward<_Up>(__u))); + } + // NOLINTEND(libcpp-robust-against-adl) + + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<1>) noexcept( + noexcept(partial_ordering(compare_three_way()(std::forward<_Tp>(__t), std::forward<_Up>(__u))))) + -> decltype(partial_ordering(compare_three_way()(std::forward<_Tp>(__t), std::forward<_Up>(__u)))) { + return partial_ordering(compare_three_way()(std::forward<_Tp>(__t), std::forward<_Up>(__u))); + } + + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) noexcept( + noexcept(partial_ordering(std::weak_order(std::forward<_Tp>(__t), std::forward<_Up>(__u))))) + -> decltype(partial_ordering(std::weak_order(std::forward<_Tp>(__t), std::forward<_Up>(__u)))) { + return partial_ordering(std::weak_order(std::forward<_Tp>(__t), std::forward<_Up>(__u))); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(__go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<2>()))) + -> decltype(__go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<2>())) { + return __go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<2>()); + } +}; +} // namespace __partial_order + +inline namespace __cpo { +inline constexpr auto partial_order = __partial_order::__fn{}; +} // namespace __cpo + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_PARTIAL_ORDER diff --git a/libcxx/include/__cxx03/__compare/strong_order.h b/libcxx/include/__cxx03/__compare/strong_order.h new file mode 100644 index 0000000000000000000000000000000000000000..8c363b5638222180344e68807fe6bb5fae3f5826 --- /dev/null +++ b/libcxx/include/__cxx03/__compare/strong_order.h @@ -0,0 +1,143 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_STRONG_ORDER +#define _LIBCPP___COMPARE_STRONG_ORDER + +#include <__bit/bit_cast.h> +#include <__compare/compare_three_way.h> +#include <__compare/ordering.h> +#include <__config> +#include <__math/exponential_functions.h> +#include <__math/traits.h> +#include <__type_traits/conditional.h> +#include <__type_traits/decay.h> +#include <__type_traits/is_floating_point.h> +#include <__type_traits/is_same.h> +#include <__utility/forward.h> +#include <__utility/priority_tag.h> +#include +#include + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [cmp.alg] +namespace __strong_order { +void strong_order() = delete; + +struct __fn { + // NOLINTBEGIN(libcpp-robust-against-adl) strong_order should use ADL, but only here + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<2>) noexcept( + noexcept(strong_ordering(strong_order(std::forward<_Tp>(__t), std::forward<_Up>(__u))))) + -> decltype(strong_ordering(strong_order(std::forward<_Tp>(__t), std::forward<_Up>(__u)))) { + return strong_ordering(strong_order(std::forward<_Tp>(__t), std::forward<_Up>(__u))); + } + // NOLINTEND(libcpp-robust-against-adl) + + template > + requires is_same_v<_Dp, decay_t<_Up>> && is_floating_point_v<_Dp> + _LIBCPP_HIDE_FROM_ABI static constexpr strong_ordering __go(_Tp&& __t, _Up&& __u, __priority_tag<1>) noexcept { + if constexpr (numeric_limits<_Dp>::is_iec559 && sizeof(_Dp) == sizeof(int32_t)) { + int32_t __rx = std::bit_cast(__t); + int32_t __ry = std::bit_cast(__u); + __rx = (__rx < 0) ? (numeric_limits::min() - __rx - 1) : __rx; + __ry = (__ry < 0) ? (numeric_limits::min() - __ry - 1) : __ry; + return (__rx <=> __ry); + } else if constexpr (numeric_limits<_Dp>::is_iec559 && sizeof(_Dp) == sizeof(int64_t)) { + int64_t __rx = std::bit_cast(__t); + int64_t __ry = std::bit_cast(__u); + __rx = (__rx < 0) ? (numeric_limits::min() - __rx - 1) : __rx; + __ry = (__ry < 0) ? (numeric_limits::min() - __ry - 1) : __ry; + return (__rx <=> __ry); + } else if (__t < __u) { + return strong_ordering::less; + } else if (__t > __u) { + return strong_ordering::greater; + } else if (__t == __u) { + if constexpr (numeric_limits<_Dp>::radix == 2) { + return __math::signbit(__u) <=> __math::signbit(__t); + } else { + // This is bullet 3 of the IEEE754 algorithm, relevant + // only for decimal floating-point; + // see https://stackoverflow.com/questions/69068075/ + if (__t == 0 || __math::isinf(__t)) { + return __math::signbit(__u) <=> __math::signbit(__t); + } else { + int __texp, __uexp; + (void)__math::frexp(__t, &__texp); + (void)__math::frexp(__u, &__uexp); + return (__t < 0) ? (__texp <=> __uexp) : (__uexp <=> __texp); + } + } + } else { + // They're unordered, so one of them must be a NAN. + // The order is -QNAN, -SNAN, numbers, +SNAN, +QNAN. + bool __t_is_nan = __math::isnan(__t); + bool __u_is_nan = __math::isnan(__u); + bool __t_is_negative = __math::signbit(__t); + bool __u_is_negative = __math::signbit(__u); + using _IntType = + conditional_t< sizeof(__t) == sizeof(int32_t), + int32_t, + conditional_t< sizeof(__t) == sizeof(int64_t), int64_t, void> >; + if constexpr (is_same_v<_IntType, void>) { + static_assert(sizeof(_Dp) == 0, "std::strong_order is unimplemented for this floating-point type"); + } else if (__t_is_nan && __u_is_nan) { + // Order by sign bit, then by "payload bits" (we'll just use bit_cast). + if (__t_is_negative != __u_is_negative) { + return (__u_is_negative <=> __t_is_negative); + } else { + return std::bit_cast<_IntType>(__t) <=> std::bit_cast<_IntType>(__u); + } + } else if (__t_is_nan) { + return __t_is_negative ? strong_ordering::less : strong_ordering::greater; + } else { + return __u_is_negative ? strong_ordering::greater : strong_ordering::less; + } + } + } + + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) noexcept( + noexcept(strong_ordering(compare_three_way()(std::forward<_Tp>(__t), std::forward<_Up>(__u))))) + -> decltype(strong_ordering(compare_three_way()(std::forward<_Tp>(__t), std::forward<_Up>(__u)))) { + return strong_ordering(compare_three_way()(std::forward<_Tp>(__t), std::forward<_Up>(__u))); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(__go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<2>()))) + -> decltype(__go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<2>())) { + return __go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<2>()); + } +}; +} // namespace __strong_order + +inline namespace __cpo { +inline constexpr auto strong_order = __strong_order::__fn{}; +} // namespace __cpo + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___COMPARE_STRONG_ORDER diff --git a/libcxx/include/__cxx03/__compare/synth_three_way.h b/libcxx/include/__cxx03/__compare/synth_three_way.h new file mode 100644 index 0000000000000000000000000000000000000000..e48ce4979983685ffdebc685d02ddce0de6cf43f --- /dev/null +++ b/libcxx/include/__cxx03/__compare/synth_three_way.h @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_SYNTH_THREE_WAY_H +#define _LIBCPP___COMPARE_SYNTH_THREE_WAY_H + +#include <__compare/ordering.h> +#include <__compare/three_way_comparable.h> +#include <__concepts/boolean_testable.h> +#include <__config> +#include <__utility/declval.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [expos.only.func] + +_LIBCPP_HIDE_FROM_ABI inline constexpr auto __synth_three_way = [](const _Tp& __t, const _Up& __u) + requires requires { + { __t < __u } -> __boolean_testable; + { __u < __t } -> __boolean_testable; + } +{ + if constexpr (three_way_comparable_with<_Tp, _Up>) { + return __t <=> __u; + } else { + if (__t < __u) + return weak_ordering::less; + if (__u < __t) + return weak_ordering::greater; + return weak_ordering::equivalent; + } +}; + +template +using __synth_three_way_result = decltype(std::__synth_three_way(std::declval<_Tp&>(), std::declval<_Up&>())); + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_SYNTH_THREE_WAY_H diff --git a/libcxx/include/__cxx03/__compare/three_way_comparable.h b/libcxx/include/__cxx03/__compare/three_way_comparable.h new file mode 100644 index 0000000000000000000000000000000000000000..7a44ea9158a6f7254816439a49f7a78c86b65773 --- /dev/null +++ b/libcxx/include/__cxx03/__compare/three_way_comparable.h @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_THREE_WAY_COMPARABLE_H +#define _LIBCPP___COMPARE_THREE_WAY_COMPARABLE_H + +#include <__compare/common_comparison_category.h> +#include <__compare/ordering.h> +#include <__concepts/common_reference_with.h> +#include <__concepts/equality_comparable.h> +#include <__concepts/same_as.h> +#include <__concepts/totally_ordered.h> +#include <__config> +#include <__type_traits/common_reference.h> +#include <__type_traits/make_const_lvalue_ref.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +concept __compares_as = same_as, _Cat>; + +template +concept three_way_comparable = + __weakly_equality_comparable_with<_Tp, _Tp> && __partially_ordered_with<_Tp, _Tp> && + requires(__make_const_lvalue_ref<_Tp> __a, __make_const_lvalue_ref<_Tp> __b) { + { __a <=> __b } -> __compares_as<_Cat>; + }; + +template +concept three_way_comparable_with = + three_way_comparable<_Tp, _Cat> && three_way_comparable<_Up, _Cat> && + common_reference_with<__make_const_lvalue_ref<_Tp>, __make_const_lvalue_ref<_Up>> && + three_way_comparable, __make_const_lvalue_ref<_Up>>, _Cat> && + __weakly_equality_comparable_with<_Tp, _Up> && __partially_ordered_with<_Tp, _Up> && + requires(__make_const_lvalue_ref<_Tp> __t, __make_const_lvalue_ref<_Up> __u) { + { __t <=> __u } -> __compares_as<_Cat>; + { __u <=> __t } -> __compares_as<_Cat>; + }; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_THREE_WAY_COMPARABLE_H diff --git a/libcxx/include/__cxx03/__compare/weak_order.h b/libcxx/include/__cxx03/__compare/weak_order.h new file mode 100644 index 0000000000000000000000000000000000000000..1a3e85feb233b3330f553b9efda1fc437954e683 --- /dev/null +++ b/libcxx/include/__cxx03/__compare/weak_order.h @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_WEAK_ORDER +#define _LIBCPP___COMPARE_WEAK_ORDER + +#include <__compare/compare_three_way.h> +#include <__compare/ordering.h> +#include <__compare/strong_order.h> +#include <__config> +#include <__math/traits.h> +#include <__type_traits/decay.h> +#include <__type_traits/is_floating_point.h> +#include <__type_traits/is_same.h> +#include <__utility/forward.h> +#include <__utility/priority_tag.h> + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [cmp.alg] +namespace __weak_order { +void weak_order() = delete; + +struct __fn { + // NOLINTBEGIN(libcpp-robust-against-adl) weak_order should use ADL, but only here + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<3>) noexcept( + noexcept(weak_ordering(weak_order(std::forward<_Tp>(__t), std::forward<_Up>(__u))))) + -> decltype(weak_ordering(weak_order(std::forward<_Tp>(__t), std::forward<_Up>(__u)))) { + return weak_ordering(weak_order(std::forward<_Tp>(__t), std::forward<_Up>(__u))); + } + // NOLINTEND(libcpp-robust-against-adl) + + template > + requires is_same_v<_Dp, decay_t<_Up>> && is_floating_point_v<_Dp> + _LIBCPP_HIDE_FROM_ABI static constexpr weak_ordering __go(_Tp&& __t, _Up&& __u, __priority_tag<2>) noexcept { + partial_ordering __po = (__t <=> __u); + if (__po == partial_ordering::less) { + return weak_ordering::less; + } else if (__po == partial_ordering::equivalent) { + return weak_ordering::equivalent; + } else if (__po == partial_ordering::greater) { + return weak_ordering::greater; + } else { + // Otherwise, at least one of them is a NaN. + bool __t_is_nan = __math::isnan(__t); + bool __u_is_nan = __math::isnan(__u); + bool __t_is_negative = __math::signbit(__t); + bool __u_is_negative = __math::signbit(__u); + if (__t_is_nan && __u_is_nan) { + return (__u_is_negative <=> __t_is_negative); + } else if (__t_is_nan) { + return __t_is_negative ? weak_ordering::less : weak_ordering::greater; + } else { + return __u_is_negative ? weak_ordering::greater : weak_ordering::less; + } + } + } + + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<1>) noexcept( + noexcept(weak_ordering(compare_three_way()(std::forward<_Tp>(__t), std::forward<_Up>(__u))))) + -> decltype(weak_ordering(compare_three_way()(std::forward<_Tp>(__t), std::forward<_Up>(__u)))) { + return weak_ordering(compare_three_way()(std::forward<_Tp>(__t), std::forward<_Up>(__u))); + } + + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) noexcept( + noexcept(weak_ordering(std::strong_order(std::forward<_Tp>(__t), std::forward<_Up>(__u))))) + -> decltype(weak_ordering(std::strong_order(std::forward<_Tp>(__t), std::forward<_Up>(__u)))) { + return weak_ordering(std::strong_order(std::forward<_Tp>(__t), std::forward<_Up>(__u))); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(__go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<3>()))) + -> decltype(__go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<3>())) { + return __go(std::forward<_Tp>(__t), std::forward<_Up>(__u), __priority_tag<3>()); + } +}; +} // namespace __weak_order + +inline namespace __cpo { +inline constexpr auto weak_order = __weak_order::__fn{}; +} // namespace __cpo + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_WEAK_ORDER diff --git a/libcxx/include/__cxx03/__concepts/arithmetic.h b/libcxx/include/__cxx03/__concepts/arithmetic.h new file mode 100644 index 0000000000000000000000000000000000000000..0c44f117805f3680911bac92ed0b31e4ee4978e8 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/arithmetic.h @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_ARITHMETIC_H +#define _LIBCPP___CONCEPTS_ARITHMETIC_H + +#include <__config> +#include <__type_traits/is_floating_point.h> +#include <__type_traits/is_integral.h> +#include <__type_traits/is_signed.h> +#include <__type_traits/is_signed_integer.h> +#include <__type_traits/is_unsigned_integer.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concepts.arithmetic], arithmetic concepts + +template +concept integral = is_integral_v<_Tp>; + +template +concept signed_integral = integral<_Tp> && is_signed_v<_Tp>; + +template +concept unsigned_integral = integral<_Tp> && !signed_integral<_Tp>; + +template +concept floating_point = is_floating_point_v<_Tp>; + +// Concept helpers for the internal type traits for the fundamental types. + +template +concept __libcpp_unsigned_integer = __libcpp_is_unsigned_integer<_Tp>::value; + +template +concept __libcpp_signed_integer = __libcpp_is_signed_integer<_Tp>::value; + +template +concept __libcpp_integer = __libcpp_unsigned_integer<_Tp> || __libcpp_signed_integer<_Tp>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_ARITHMETIC_H diff --git a/libcxx/include/__cxx03/__concepts/assignable.h b/libcxx/include/__cxx03/__concepts/assignable.h new file mode 100644 index 0000000000000000000000000000000000000000..7423daabba7801b839a438d8a7986e21b6f06088 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/assignable.h @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_ASSIGNABLE_H +#define _LIBCPP___CONCEPTS_ASSIGNABLE_H + +#include <__concepts/common_reference_with.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__type_traits/is_reference.h> +#include <__type_traits/make_const_lvalue_ref.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.assignable] + +template +concept assignable_from = + is_lvalue_reference_v<_Lhs> && + common_reference_with<__make_const_lvalue_ref<_Lhs>, __make_const_lvalue_ref<_Rhs>> && + requires(_Lhs __lhs, _Rhs&& __rhs) { + { __lhs = std::forward<_Rhs>(__rhs) } -> same_as<_Lhs>; + }; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_ASSIGNABLE_H diff --git a/libcxx/include/__cxx03/__concepts/boolean_testable.h b/libcxx/include/__cxx03/__concepts/boolean_testable.h new file mode 100644 index 0000000000000000000000000000000000000000..b379fe9c5a88047935151ac954f983555274fa24 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/boolean_testable.h @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_BOOLEAN_TESTABLE_H +#define _LIBCPP___CONCEPTS_BOOLEAN_TESTABLE_H + +#include <__concepts/convertible_to.h> +#include <__config> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concepts.booleantestable] + +template +concept __boolean_testable_impl = convertible_to<_Tp, bool>; + +template +concept __boolean_testable = __boolean_testable_impl<_Tp> && requires(_Tp&& __t) { + { !std::forward<_Tp>(__t) } -> __boolean_testable_impl; +}; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_BOOLEAN_TESTABLE_H diff --git a/libcxx/include/__cxx03/__concepts/class_or_enum.h b/libcxx/include/__cxx03/__concepts/class_or_enum.h new file mode 100644 index 0000000000000000000000000000000000000000..2739e31e14ba65f2073a04274681a7dfe93e2ee1 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/class_or_enum.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_CLASS_OR_ENUM_H +#define _LIBCPP___CONCEPTS_CLASS_OR_ENUM_H + +#include <__config> +#include <__type_traits/is_class.h> +#include <__type_traits/is_enum.h> +#include <__type_traits/is_union.h> +#include <__type_traits/remove_cvref.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// Whether a type is a class type or enumeration type according to the Core wording. + +template +concept __class_or_enum = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_CLASS_OR_ENUM_H diff --git a/libcxx/include/__cxx03/__concepts/common_reference_with.h b/libcxx/include/__cxx03/__concepts/common_reference_with.h new file mode 100644 index 0000000000000000000000000000000000000000..4eb687e071bc51318be3138d0e1baf3ff2f5b6a2 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/common_reference_with.h @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_COMMON_REFERENCE_WITH_H +#define _LIBCPP___CONCEPTS_COMMON_REFERENCE_WITH_H + +#include <__concepts/convertible_to.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__type_traits/common_reference.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.commonref] + +template +concept common_reference_with = + same_as, common_reference_t<_Up, _Tp>> && + convertible_to<_Tp, common_reference_t<_Tp, _Up>> && convertible_to<_Up, common_reference_t<_Tp, _Up>>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_COMMON_REFERENCE_WITH_H diff --git a/libcxx/include/__cxx03/__concepts/common_with.h b/libcxx/include/__cxx03/__concepts/common_with.h new file mode 100644 index 0000000000000000000000000000000000000000..85abb05efbc2922510066919ed833644b2f43575 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/common_with.h @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_COMMON_WITH_H +#define _LIBCPP___CONCEPTS_COMMON_WITH_H + +#include <__concepts/common_reference_with.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__type_traits/add_lvalue_reference.h> +#include <__type_traits/common_reference.h> +#include <__type_traits/common_type.h> +#include <__utility/declval.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.common] + +// clang-format off +template +concept common_with = + same_as, common_type_t<_Up, _Tp>> && + requires { + static_cast>(std::declval<_Tp>()); + static_cast>(std::declval<_Up>()); + } && + common_reference_with< + add_lvalue_reference_t, + add_lvalue_reference_t> && + common_reference_with< + add_lvalue_reference_t>, + common_reference_t< + add_lvalue_reference_t, + add_lvalue_reference_t>>; +// clang-format on + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_COMMON_WITH_H diff --git a/libcxx/include/__cxx03/__concepts/constructible.h b/libcxx/include/__cxx03/__concepts/constructible.h new file mode 100644 index 0000000000000000000000000000000000000000..835a44429c092f9bdaaa2aa250e76ce0053f134d --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/constructible.h @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_CONSTRUCTIBLE_H +#define _LIBCPP___CONCEPTS_CONSTRUCTIBLE_H + +#include <__concepts/convertible_to.h> +#include <__concepts/destructible.h> +#include <__config> +#include <__type_traits/is_constructible.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.constructible] +template +concept constructible_from = destructible<_Tp> && is_constructible_v<_Tp, _Args...>; + +// [concept.default.init] + +template +concept __default_initializable = requires { ::new _Tp; }; + +template +concept default_initializable = constructible_from<_Tp> && requires { _Tp{}; } && __default_initializable<_Tp>; + +// [concept.moveconstructible] +template +concept move_constructible = constructible_from<_Tp, _Tp> && convertible_to<_Tp, _Tp>; + +// [concept.copyconstructible] +// clang-format off +template +concept copy_constructible = + move_constructible<_Tp> && + constructible_from<_Tp, _Tp&> && convertible_to<_Tp&, _Tp> && + constructible_from<_Tp, const _Tp&> && convertible_to && + constructible_from<_Tp, const _Tp> && convertible_to; +// clang-format on + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_CONSTRUCTIBLE_H diff --git a/libcxx/include/__cxx03/__concepts/convertible_to.h b/libcxx/include/__cxx03/__concepts/convertible_to.h new file mode 100644 index 0000000000000000000000000000000000000000..6d5b6c1268d5d2d1966de999779953f202071db9 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/convertible_to.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_CONVERTIBLE_TO_H +#define _LIBCPP___CONCEPTS_CONVERTIBLE_TO_H + +#include <__config> +#include <__type_traits/is_convertible.h> +#include <__utility/declval.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.convertible] + +template +concept convertible_to = is_convertible_v<_From, _To> && requires { static_cast<_To>(std::declval<_From>()); }; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_CONVERTIBLE_TO_H diff --git a/libcxx/include/__cxx03/__concepts/copyable.h b/libcxx/include/__cxx03/__concepts/copyable.h new file mode 100644 index 0000000000000000000000000000000000000000..2bf0ad42fc1a8393d5de87593e3b82fc2c48b730 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/copyable.h @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_COPYABLE_H +#define _LIBCPP___CONCEPTS_COPYABLE_H + +#include <__concepts/assignable.h> +#include <__concepts/constructible.h> +#include <__concepts/movable.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concepts.object] + +// clang-format off +template +concept copyable = + copy_constructible<_Tp> && + movable<_Tp> && + assignable_from<_Tp&, _Tp&> && + assignable_from<_Tp&, const _Tp&> && + assignable_from<_Tp&, const _Tp>; +// clang-format on + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_COPYABLE_H diff --git a/libcxx/include/__cxx03/__concepts/derived_from.h b/libcxx/include/__cxx03/__concepts/derived_from.h new file mode 100644 index 0000000000000000000000000000000000000000..9875faee81b90180af009403648a0fa0a5f76c98 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/derived_from.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_DERIVED_FROM_H +#define _LIBCPP___CONCEPTS_DERIVED_FROM_H + +#include <__config> +#include <__type_traits/is_base_of.h> +#include <__type_traits/is_convertible.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.derived] + +template +concept derived_from = is_base_of_v<_Bp, _Dp> && is_convertible_v; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_DERIVED_FROM_H diff --git a/libcxx/include/__cxx03/__concepts/destructible.h b/libcxx/include/__cxx03/__concepts/destructible.h new file mode 100644 index 0000000000000000000000000000000000000000..28b4b1bc24ec9f9140af3561fa3bce41de2c0932 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/destructible.h @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_DESTRUCTIBLE_H +#define _LIBCPP___CONCEPTS_DESTRUCTIBLE_H + +#include <__config> +#include <__type_traits/is_nothrow_destructible.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.destructible] + +template +concept destructible = is_nothrow_destructible_v<_Tp>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_DESTRUCTIBLE_H diff --git a/libcxx/include/__cxx03/__concepts/different_from.h b/libcxx/include/__cxx03/__concepts/different_from.h new file mode 100644 index 0000000000000000000000000000000000000000..fd31f6e25805d35c7a07320635c8ee5326923de4 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/different_from.h @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_DIFFERENT_FROM_H +#define _LIBCPP___CONCEPTS_DIFFERENT_FROM_H + +#include <__concepts/same_as.h> +#include <__config> +#include <__type_traits/remove_cvref.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +concept __different_from = !same_as, remove_cvref_t<_Up>>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_DIFFERENT_FROM_H diff --git a/libcxx/include/__cxx03/__concepts/equality_comparable.h b/libcxx/include/__cxx03/__concepts/equality_comparable.h new file mode 100644 index 0000000000000000000000000000000000000000..278fc76409289ba0e9e7ef1f0579b7ca2182ca4f --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/equality_comparable.h @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_EQUALITY_COMPARABLE_H +#define _LIBCPP___CONCEPTS_EQUALITY_COMPARABLE_H + +#include <__concepts/boolean_testable.h> +#include <__concepts/common_reference_with.h> +#include <__config> +#include <__type_traits/common_reference.h> +#include <__type_traits/make_const_lvalue_ref.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.equalitycomparable] + +template +concept __weakly_equality_comparable_with = + requires(__make_const_lvalue_ref<_Tp> __t, __make_const_lvalue_ref<_Up> __u) { + { __t == __u } -> __boolean_testable; + { __t != __u } -> __boolean_testable; + { __u == __t } -> __boolean_testable; + { __u != __t } -> __boolean_testable; + }; + +template +concept equality_comparable = __weakly_equality_comparable_with<_Tp, _Tp>; + +// clang-format off +template +concept equality_comparable_with = + equality_comparable<_Tp> && equality_comparable<_Up> && + common_reference_with<__make_const_lvalue_ref<_Tp>, __make_const_lvalue_ref<_Up>> && + equality_comparable< + common_reference_t< + __make_const_lvalue_ref<_Tp>, + __make_const_lvalue_ref<_Up>>> && + __weakly_equality_comparable_with<_Tp, _Up>; +// clang-format on + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_EQUALITY_COMPARABLE_H diff --git a/libcxx/include/__cxx03/__concepts/invocable.h b/libcxx/include/__cxx03/__concepts/invocable.h new file mode 100644 index 0000000000000000000000000000000000000000..8a29398b3a29f8ea60683e4b6f0885ac8c38917f --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/invocable.h @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_INVOCABLE_H +#define _LIBCPP___CONCEPTS_INVOCABLE_H + +#include <__config> +#include <__functional/invoke.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.invocable] + +template +concept invocable = requires(_Fn&& __fn, _Args&&... __args) { + std::invoke(std::forward<_Fn>(__fn), std::forward<_Args>(__args)...); // not required to be equality preserving +}; + +// [concept.regular.invocable] + +template +concept regular_invocable = invocable<_Fn, _Args...>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_INVOCABLE_H diff --git a/libcxx/include/__cxx03/__concepts/movable.h b/libcxx/include/__cxx03/__concepts/movable.h new file mode 100644 index 0000000000000000000000000000000000000000..bc5b9d767c6a51b309c4abeaf79b35c1ebd7aabb --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/movable.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_MOVABLE_H +#define _LIBCPP___CONCEPTS_MOVABLE_H + +#include <__concepts/assignable.h> +#include <__concepts/constructible.h> +#include <__concepts/swappable.h> +#include <__config> +#include <__type_traits/is_object.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concepts.object] + +template +concept movable = is_object_v<_Tp> && move_constructible<_Tp> && assignable_from<_Tp&, _Tp> && swappable<_Tp>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_MOVABLE_H diff --git a/libcxx/include/__cxx03/__concepts/predicate.h b/libcxx/include/__cxx03/__concepts/predicate.h new file mode 100644 index 0000000000000000000000000000000000000000..00731efc8fcd9e36bf943c76b6339dfacaa09061 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/predicate.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_PREDICATE_H +#define _LIBCPP___CONCEPTS_PREDICATE_H + +#include <__concepts/boolean_testable.h> +#include <__concepts/invocable.h> +#include <__config> +#include <__functional/invoke.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.predicate] + +template +concept predicate = regular_invocable<_Fn, _Args...> && __boolean_testable>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_PREDICATE_H diff --git a/libcxx/include/__cxx03/__concepts/regular.h b/libcxx/include/__cxx03/__concepts/regular.h new file mode 100644 index 0000000000000000000000000000000000000000..9f3d8bf30be3e0738442280218d73cc9cd3446b0 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/regular.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_REGULAR_H +#define _LIBCPP___CONCEPTS_REGULAR_H + +#include <__concepts/equality_comparable.h> +#include <__concepts/semiregular.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.object] + +template +concept regular = semiregular<_Tp> && equality_comparable<_Tp>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_REGULAR_H diff --git a/libcxx/include/__cxx03/__concepts/relation.h b/libcxx/include/__cxx03/__concepts/relation.h new file mode 100644 index 0000000000000000000000000000000000000000..7545a7db93da766029314a30df19f0df3ae1ff2d --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/relation.h @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_RELATION_H +#define _LIBCPP___CONCEPTS_RELATION_H + +#include <__concepts/predicate.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.relation] + +template +concept relation = + predicate<_Rp, _Tp, _Tp> && predicate<_Rp, _Up, _Up> && predicate<_Rp, _Tp, _Up> && predicate<_Rp, _Up, _Tp>; + +// [concept.equiv] + +template +concept equivalence_relation = relation<_Rp, _Tp, _Up>; + +// [concept.strictweakorder] + +template +concept strict_weak_order = relation<_Rp, _Tp, _Up>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_RELATION_H diff --git a/libcxx/include/__cxx03/__concepts/same_as.h b/libcxx/include/__cxx03/__concepts/same_as.h new file mode 100644 index 0000000000000000000000000000000000000000..4241131c70c1f4edd1f08dc73c9de032fd6e0776 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/same_as.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_SAME_AS_H +#define _LIBCPP___CONCEPTS_SAME_AS_H + +#include <__config> +#include <__type_traits/is_same.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.same] + +template +concept __same_as_impl = _IsSame<_Tp, _Up>::value; + +template +concept same_as = __same_as_impl<_Tp, _Up> && __same_as_impl<_Up, _Tp>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_SAME_AS_H diff --git a/libcxx/include/__cxx03/__concepts/semiregular.h b/libcxx/include/__cxx03/__concepts/semiregular.h new file mode 100644 index 0000000000000000000000000000000000000000..7a159d17dfc109c257801e29a5ff5698642d4658 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/semiregular.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_SEMIREGULAR_H +#define _LIBCPP___CONCEPTS_SEMIREGULAR_H + +#include <__concepts/constructible.h> +#include <__concepts/copyable.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.object] + +template +concept semiregular = copyable<_Tp> && default_initializable<_Tp>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_SEMIREGULAR_H diff --git a/libcxx/include/__cxx03/__concepts/swappable.h b/libcxx/include/__cxx03/__concepts/swappable.h new file mode 100644 index 0000000000000000000000000000000000000000..d339488a087a5c4157f9b338556102bde0207c27 --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/swappable.h @@ -0,0 +1,123 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_SWAPPABLE_H +#define _LIBCPP___CONCEPTS_SWAPPABLE_H + +#include <__concepts/assignable.h> +#include <__concepts/class_or_enum.h> +#include <__concepts/common_reference_with.h> +#include <__concepts/constructible.h> +#include <__config> +#include <__type_traits/extent.h> +#include <__type_traits/is_nothrow_assignable.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/exchange.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <__utility/swap.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.swappable] + +namespace ranges { +namespace __swap { + +template +void swap(_Tp&, _Tp&) = delete; + +// clang-format off +template +concept __unqualified_swappable_with = + (__class_or_enum> || __class_or_enum>) && + requires(_Tp&& __t, _Up&& __u) { + swap(std::forward<_Tp>(__t), std::forward<_Up>(__u)); + }; +// clang-format on + +struct __fn; + +// clang-format off +template +concept __swappable_arrays = + !__unqualified_swappable_with<_Tp (&)[_Size], _Up (&)[_Size]> && + extent_v<_Tp> == extent_v<_Up> && + requires(_Tp (&__t)[_Size], _Up (&__u)[_Size], const __fn& __swap) { + __swap(__t[0], __u[0]); + }; +// clang-format on + +template +concept __exchangeable = + !__unqualified_swappable_with<_Tp&, _Tp&> && move_constructible<_Tp> && assignable_from<_Tp&, _Tp>; + +struct __fn { + // 2.1 `S` is `(void)swap(E1, E2)`* if `E1` or `E2` has class or enumeration type and... + // *The name `swap` is used here unqualified. + template + requires __unqualified_swappable_with<_Tp, _Up> + _LIBCPP_HIDE_FROM_ABI constexpr void operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(swap(std::forward<_Tp>(__t), std::forward<_Up>(__u)))) { + swap(std::forward<_Tp>(__t), std::forward<_Up>(__u)); + } + + // 2.2 Otherwise, if `E1` and `E2` are lvalues of array types with equal extent and... + template + requires __swappable_arrays<_Tp, _Up, _Size> + _LIBCPP_HIDE_FROM_ABI constexpr void operator()(_Tp (&__t)[_Size], _Up (&__u)[_Size]) const + noexcept(noexcept((*this)(*__t, *__u))) { + // TODO(cjdb): replace with `ranges::swap_ranges`. + for (size_t __i = 0; __i < _Size; ++__i) { + (*this)(__t[__i], __u[__i]); + } + } + + // 2.3 Otherwise, if `E1` and `E2` are lvalues of the same type `T` that models... + template <__exchangeable _Tp> + _LIBCPP_HIDE_FROM_ABI constexpr void operator()(_Tp& __x, _Tp& __y) const + noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_move_assignable_v<_Tp>) { + __y = std::exchange(__x, std::move(__y)); + } +}; +} // namespace __swap + +inline namespace __cpo { +inline constexpr auto swap = __swap::__fn{}; +} // namespace __cpo +} // namespace ranges + +template +concept swappable = requires(_Tp& __a, _Tp& __b) { ranges::swap(__a, __b); }; + +template +concept swappable_with = common_reference_with<_Tp, _Up> && requires(_Tp&& __t, _Up&& __u) { + ranges::swap(std::forward<_Tp>(__t), std::forward<_Tp>(__t)); + ranges::swap(std::forward<_Up>(__u), std::forward<_Up>(__u)); + ranges::swap(std::forward<_Tp>(__t), std::forward<_Up>(__u)); + ranges::swap(std::forward<_Up>(__u), std::forward<_Tp>(__t)); +}; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___CONCEPTS_SWAPPABLE_H diff --git a/libcxx/include/__cxx03/__concepts/totally_ordered.h b/libcxx/include/__cxx03/__concepts/totally_ordered.h new file mode 100644 index 0000000000000000000000000000000000000000..186c3b430dd54d220a860b5a04a3c3290852418c --- /dev/null +++ b/libcxx/include/__cxx03/__concepts/totally_ordered.h @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONCEPTS_TOTALLY_ORDERED_H +#define _LIBCPP___CONCEPTS_TOTALLY_ORDERED_H + +#include <__concepts/boolean_testable.h> +#include <__concepts/equality_comparable.h> +#include <__config> +#include <__type_traits/common_reference.h> +#include <__type_traits/make_const_lvalue_ref.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [concept.totallyordered] + +template +concept __partially_ordered_with = requires(__make_const_lvalue_ref<_Tp> __t, __make_const_lvalue_ref<_Up> __u) { + { __t < __u } -> __boolean_testable; + { __t > __u } -> __boolean_testable; + { __t <= __u } -> __boolean_testable; + { __t >= __u } -> __boolean_testable; + { __u < __t } -> __boolean_testable; + { __u > __t } -> __boolean_testable; + { __u <= __t } -> __boolean_testable; + { __u >= __t } -> __boolean_testable; +}; + +template +concept totally_ordered = equality_comparable<_Tp> && __partially_ordered_with<_Tp, _Tp>; + +// clang-format off +template +concept totally_ordered_with = + totally_ordered<_Tp> && totally_ordered<_Up> && + equality_comparable_with<_Tp, _Up> && + totally_ordered< + common_reference_t< + __make_const_lvalue_ref<_Tp>, + __make_const_lvalue_ref<_Up>>> && + __partially_ordered_with<_Tp, _Up>; +// clang-format on + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_TOTALLY_ORDERED_H diff --git a/libcxx/include/__cxx03/__condition_variable/condition_variable.h b/libcxx/include/__cxx03/__condition_variable/condition_variable.h new file mode 100644 index 0000000000000000000000000000000000000000..de35aaca1070eb03354cbd8aef014425adeba331 --- /dev/null +++ b/libcxx/include/__cxx03/__condition_variable/condition_variable.h @@ -0,0 +1,244 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H +#define _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H + +#include <__chrono/duration.h> +#include <__chrono/steady_clock.h> +#include <__chrono/system_clock.h> +#include <__chrono/time_point.h> +#include <__config> +#include <__mutex/mutex.h> +#include <__mutex/unique_lock.h> +#include <__system_error/system_error.h> +#include <__thread/support.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_floating_point.h> +#include <__utility/move.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#ifndef _LIBCPP_HAS_NO_THREADS + +// enum class cv_status +_LIBCPP_DECLARE_STRONG_ENUM(cv_status){no_timeout, timeout}; +_LIBCPP_DECLARE_STRONG_ENUM_EPILOG(cv_status) + +class _LIBCPP_EXPORTED_FROM_ABI condition_variable { + __libcpp_condvar_t __cv_ = _LIBCPP_CONDVAR_INITIALIZER; + +public: + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR condition_variable() _NOEXCEPT = default; + +# ifdef _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION + ~condition_variable() = default; +# else + ~condition_variable(); +# endif + + condition_variable(const condition_variable&) = delete; + condition_variable& operator=(const condition_variable&) = delete; + + void notify_one() _NOEXCEPT; + void notify_all() _NOEXCEPT; + + void wait(unique_lock& __lk) _NOEXCEPT; + template + _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS void wait(unique_lock& __lk, _Predicate __pred); + + template + _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status + wait_until(unique_lock& __lk, const chrono::time_point<_Clock, _Duration>& __t); + + template + _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool + wait_until(unique_lock& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred); + + template + _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS cv_status + wait_for(unique_lock& __lk, const chrono::duration<_Rep, _Period>& __d); + + template + bool _LIBCPP_HIDE_FROM_ABI + wait_for(unique_lock& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred); + + typedef __libcpp_condvar_t* native_handle_type; + _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__cv_; } + +private: + void + __do_timed_wait(unique_lock& __lk, chrono::time_point) _NOEXCEPT; +# if defined(_LIBCPP_HAS_COND_CLOCKWAIT) + _LIBCPP_HIDE_FROM_ABI void + __do_timed_wait(unique_lock& __lk, chrono::time_point) _NOEXCEPT; +# endif + template + _LIBCPP_HIDE_FROM_ABI void + __do_timed_wait(unique_lock& __lk, chrono::time_point<_Clock, chrono::nanoseconds>) _NOEXCEPT; +}; +#endif // !_LIBCPP_HAS_NO_THREADS + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI chrono::nanoseconds __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) { + using namespace chrono; + using __ratio = ratio_divide<_Period, nano>; + using __ns_rep = nanoseconds::rep; + _Rep __result_float = __d.count() * __ratio::num / __ratio::den; + + _Rep __result_max = numeric_limits<__ns_rep>::max(); + if (__result_float >= __result_max) { + return nanoseconds::max(); + } + + _Rep __result_min = numeric_limits<__ns_rep>::min(); + if (__result_float <= __result_min) { + return nanoseconds::min(); + } + + return nanoseconds(static_cast<__ns_rep>(__result_float)); +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI chrono::nanoseconds __safe_nanosecond_cast(chrono::duration<_Rep, _Period> __d) { + using namespace chrono; + if (__d.count() == 0) { + return nanoseconds(0); + } + + using __ratio = ratio_divide<_Period, nano>; + using __ns_rep = nanoseconds::rep; + __ns_rep __result_max = numeric_limits<__ns_rep>::max(); + if (__d.count() > 0 && __d.count() > __result_max / __ratio::num) { + return nanoseconds::max(); + } + + __ns_rep __result_min = numeric_limits<__ns_rep>::min(); + if (__d.count() < 0 && __d.count() < __result_min / __ratio::num) { + return nanoseconds::min(); + } + + __ns_rep __result = __d.count() * __ratio::num / __ratio::den; + if (__result == 0) { + return nanoseconds(1); + } + + return nanoseconds(__result); +} + +#ifndef _LIBCPP_HAS_NO_THREADS +template +void condition_variable::wait(unique_lock& __lk, _Predicate __pred) { + while (!__pred()) + wait(__lk); +} + +template +cv_status condition_variable::wait_until(unique_lock& __lk, const chrono::time_point<_Clock, _Duration>& __t) { + using namespace chrono; + using __clock_tp_ns = time_point<_Clock, nanoseconds>; + + typename _Clock::time_point __now = _Clock::now(); + if (__t <= __now) + return cv_status::timeout; + + __clock_tp_ns __t_ns = __clock_tp_ns(std::__safe_nanosecond_cast(__t.time_since_epoch())); + + __do_timed_wait(__lk, __t_ns); + return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout; +} + +template +bool condition_variable::wait_until( + unique_lock& __lk, const chrono::time_point<_Clock, _Duration>& __t, _Predicate __pred) { + while (!__pred()) { + if (wait_until(__lk, __t) == cv_status::timeout) + return __pred(); + } + return true; +} + +template +cv_status condition_variable::wait_for(unique_lock& __lk, const chrono::duration<_Rep, _Period>& __d) { + using namespace chrono; + if (__d <= __d.zero()) + return cv_status::timeout; + using __ns_rep = nanoseconds::rep; + steady_clock::time_point __c_now = steady_clock::now(); + +# if defined(_LIBCPP_HAS_COND_CLOCKWAIT) + using __clock_tp_ns = time_point; + __ns_rep __now_count_ns = std::__safe_nanosecond_cast(__c_now.time_since_epoch()).count(); +# else + using __clock_tp_ns = time_point; + __ns_rep __now_count_ns = std::__safe_nanosecond_cast(system_clock::now().time_since_epoch()).count(); +# endif + + __ns_rep __d_ns_count = std::__safe_nanosecond_cast(__d).count(); + + if (__now_count_ns > numeric_limits<__ns_rep>::max() - __d_ns_count) { + __do_timed_wait(__lk, __clock_tp_ns::max()); + } else { + __do_timed_wait(__lk, __clock_tp_ns(nanoseconds(__now_count_ns + __d_ns_count))); + } + + return steady_clock::now() - __c_now < __d ? cv_status::no_timeout : cv_status::timeout; +} + +template +inline bool +condition_variable::wait_for(unique_lock& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred) { + return wait_until(__lk, chrono::steady_clock::now() + __d, std::move(__pred)); +} + +# if defined(_LIBCPP_HAS_COND_CLOCKWAIT) +inline void condition_variable::__do_timed_wait( + unique_lock& __lk, chrono::time_point __tp) _NOEXCEPT { + using namespace chrono; + if (!__lk.owns_lock()) + __throw_system_error(EPERM, "condition_variable::timed wait: mutex not locked"); + nanoseconds __d = __tp.time_since_epoch(); + timespec __ts; + seconds __s = duration_cast(__d); + using __ts_sec = decltype(__ts.tv_sec); + const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max(); + if (__s.count() < __ts_sec_max) { + __ts.tv_sec = static_cast<__ts_sec>(__s.count()); + __ts.tv_nsec = (__d - __s).count(); + } else { + __ts.tv_sec = __ts_sec_max; + __ts.tv_nsec = giga::num - 1; + } + int __ec = pthread_cond_clockwait(&__cv_, __lk.mutex()->native_handle(), CLOCK_MONOTONIC, &__ts); + if (__ec != 0 && __ec != ETIMEDOUT) + __throw_system_error(__ec, "condition_variable timed_wait failed"); +} +# endif // _LIBCPP_HAS_COND_CLOCKWAIT + +template +inline void condition_variable::__do_timed_wait(unique_lock& __lk, + chrono::time_point<_Clock, chrono::nanoseconds> __tp) _NOEXCEPT { + wait_for(__lk, __tp - _Clock::now()); +} + +#endif // _LIBCPP_HAS_NO_THREADS + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___CONDITION_VARIABLE_CONDITION_VARIABLE_H diff --git a/libcxx/include/__cxx03/__config b/libcxx/include/__cxx03/__config new file mode 100644 index 0000000000000000000000000000000000000000..661af5be3c225e44b91a1cc7c842668e7bd656eb --- /dev/null +++ b/libcxx/include/__cxx03/__config @@ -0,0 +1,1228 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONFIG +#define _LIBCPP___CONFIG + +#include <__config_site> +#include <__configuration/abi.h> +#include <__configuration/availability.h> +#include <__configuration/compiler.h> +#include <__configuration/platform.h> + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +# pragma GCC system_header +#endif + +#ifdef __cplusplus + +// The attributes supported by clang are documented at https://clang.llvm.org/docs/AttributeReference.html + +// _LIBCPP_VERSION represents the version of libc++, which matches the version of LLVM. +// Given a LLVM release LLVM XX.YY.ZZ (e.g. LLVM 17.0.1 == 17.00.01), _LIBCPP_VERSION is +// defined to XXYYZZ. +# define _LIBCPP_VERSION 190100 + +# define _LIBCPP_CONCAT_IMPL(_X, _Y) _X##_Y +# define _LIBCPP_CONCAT(_X, _Y) _LIBCPP_CONCAT_IMPL(_X, _Y) + +# if __STDC_HOSTED__ == 0 +# define _LIBCPP_FREESTANDING +# endif + +// HARDENING { + +// This is for backward compatibility -- make enabling `_LIBCPP_ENABLE_ASSERTIONS` (which predates hardening modes) +// equivalent to setting the extensive mode. This is deprecated and will be removed in LLVM 20. +# ifdef _LIBCPP_ENABLE_ASSERTIONS +# warning "_LIBCPP_ENABLE_ASSERTIONS is deprecated, please use _LIBCPP_HARDENING_MODE instead" +# if _LIBCPP_ENABLE_ASSERTIONS != 0 && _LIBCPP_ENABLE_ASSERTIONS != 1 +# error "_LIBCPP_ENABLE_ASSERTIONS must be set to 0 or 1" +# endif +# if _LIBCPP_ENABLE_ASSERTIONS +# define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_EXTENSIVE +# endif +# endif + +// The library provides the macro `_LIBCPP_HARDENING_MODE` which can be set to one of the following values: +// +// - `_LIBCPP_HARDENING_MODE_NONE`; +// - `_LIBCPP_HARDENING_MODE_FAST`; +// - `_LIBCPP_HARDENING_MODE_EXTENSIVE`; +// - `_LIBCPP_HARDENING_MODE_DEBUG`. +// +// These values have the following effects: +// +// - `_LIBCPP_HARDENING_MODE_NONE` -- sets the hardening mode to "none" which disables all runtime hardening checks; +// +// - `_LIBCPP_HARDENING_MODE_FAST` -- sets that hardening mode to "fast". The fast mode enables security-critical checks +// that can be done with relatively little runtime overhead in constant time; +// +// - `_LIBCPP_HARDENING_MODE_EXTENSIVE` -- sets the hardening mode to "extensive". The extensive mode is a superset of +// the fast mode that additionally enables checks that are relatively cheap and prevent common types of logic errors +// but are not necessarily security-critical; +// +// - `_LIBCPP_HARDENING_MODE_DEBUG` -- sets the hardening mode to "debug". The debug mode is a superset of the extensive +// mode and enables all checks available in the library, including internal assertions. Checks that are part of the +// debug mode can be very expensive and thus the debug mode is intended to be used for testing, not in production. + +// Inside the library, assertions are categorized so they can be cherry-picked based on the chosen hardening mode. These +// macros are only for internal use -- users should only pick one of the high-level hardening modes described above. +// +// - `_LIBCPP_ASSERT_VALID_INPUT_RANGE` -- checks that ranges (whether expressed as an iterator pair, an iterator and +// a sentinel, an iterator and a count, or a `std::range`) given as input to library functions are valid: +// - the sentinel is reachable from the begin iterator; +// - TODO(hardening): both iterators refer to the same container. +// +// - `_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS` -- checks that any attempts to access a container element, whether through +// the container object or through an iterator, are valid and do not attempt to go out of bounds or otherwise access +// a non-existent element. For iterator checks to work, bounded iterators must be enabled in the ABI. Types like +// `optional` and `function` are considered one-element containers for the purposes of this check. +// +// - `_LIBCPP_ASSERT_NON_NULL` -- checks that the pointer being dereferenced is not null. On most modern platforms zero +// address does not refer to an actual location in memory, so a null pointer dereference would not compromize the +// memory security of a program (however, it is still undefined behavior that can result in strange errors due to +// compiler optimizations). +// +// - `_LIBCPP_ASSERT_NON_OVERLAPPING_RANGES` -- for functions that take several ranges as arguments, checks that the +// given ranges do not overlap. +// +// - `_LIBCPP_ASSERT_VALID_DEALLOCATION` -- checks that an attempt to deallocate memory is valid (e.g. the given object +// was allocated by the given allocator). Violating this category typically results in a memory leak. +// +// - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL` -- checks that a call to an external API doesn't fail in +// an unexpected manner. This includes triggering documented cases of undefined behavior in an external library (like +// attempting to unlock an unlocked mutex in pthreads). Any API external to the library falls under this category +// (from system calls to compiler intrinsics). We generally don't expect these failures to compromize memory safety or +// otherwise create an immediate security issue. +// +// - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure +// the containers have compatible allocators. +// +// - `_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN` -- checks that the given argument is within the domain of valid arguments +// for the function. Violating this typically produces an incorrect result (e.g. the clamp algorithm returns the +// original value without clamping it due to incorrect functors) or puts an object into an invalid state (e.g. +// a string view where only a subset of elements is possible to access). This category is for assertions violating +// which doesn't cause any immediate issues in the library -- whatever the consequences are, they will happen in the +// user code. +// +// - `_LIBCPP_ASSERT_PEDANTIC` -- checks prerequisites which are imposed by the Standard, but violating which happens to +// be benign in our implementation. +// +// - `_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT` -- checks that the given argument satisfies the semantic requirements imposed +// by the Standard. Typically, there is no simple way to completely prove that a semantic requirement is satisfied; +// thus, this would often be a heuristic check and it might be quite expensive. +// +// - `_LIBCPP_ASSERT_INTERNAL` -- checks that internal invariants of the library hold. These assertions don't depend on +// user input. +// +// - `_LIBCPP_ASSERT_UNCATEGORIZED` -- for assertions that haven't been properly classified yet. + +// clang-format off +# define _LIBCPP_HARDENING_MODE_NONE (1 << 1) +# define _LIBCPP_HARDENING_MODE_FAST (1 << 2) +# define _LIBCPP_HARDENING_MODE_EXTENSIVE (1 << 4) // Deliberately not ordered. +# define _LIBCPP_HARDENING_MODE_DEBUG (1 << 3) +// clang-format on + +# ifndef _LIBCPP_HARDENING_MODE + +# ifndef _LIBCPP_HARDENING_MODE_DEFAULT +# error _LIBCPP_HARDENING_MODE_DEFAULT is not defined. This definition should be set at configuration time in the \ +`__config_site` header, please make sure your installation of libc++ is not broken. +# endif + +# define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEFAULT +# endif + +# if _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_NONE && \ + _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_FAST && \ + _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_EXTENSIVE && \ + _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG +# error _LIBCPP_HARDENING_MODE must be set to one of the following values: \ +_LIBCPP_HARDENING_MODE_NONE, \ +_LIBCPP_HARDENING_MODE_FAST, \ +_LIBCPP_HARDENING_MODE_EXTENSIVE, \ +_LIBCPP_HARDENING_MODE_DEBUG +# endif + +// } HARDENING + +# define _LIBCPP_TOSTRING2(x) #x +# define _LIBCPP_TOSTRING(x) _LIBCPP_TOSTRING2(x) + +// NOLINTNEXTLINE(libcpp-cpp-version-check) +# if __cplusplus < 201103L +# define _LIBCPP_CXX03_LANG +# endif + +# ifndef __has_constexpr_builtin +# define __has_constexpr_builtin(x) 0 +# endif + +// This checks wheter a Clang module is built +# ifndef __building_module +# define __building_module(...) 0 +# endif + +// '__is_identifier' returns '0' if '__x' is a reserved identifier provided by +// the compiler and '1' otherwise. +# ifndef __is_identifier +# define __is_identifier(__x) 1 +# endif + +# ifndef __has_declspec_attribute +# define __has_declspec_attribute(__x) 0 +# endif + +# define __has_keyword(__x) !(__is_identifier(__x)) + +# ifndef __has_warning +# define __has_warning(...) 0 +# endif + +# if !defined(_LIBCPP_COMPILER_CLANG_BASED) && __cplusplus < 201103L +# error "libc++ only supports C++03 with Clang-based compilers. Please enable C++11" +# endif + +// FIXME: ABI detection should be done via compiler builtin macros. This +// is just a placeholder until Clang implements such macros. For now assume +// that Windows compilers pretending to be MSVC++ target the Microsoft ABI, +// and allow the user to explicitly specify the ABI to handle cases where this +// heuristic falls short. +# if defined(_LIBCPP_ABI_FORCE_ITANIUM) && defined(_LIBCPP_ABI_FORCE_MICROSOFT) +# error "Only one of _LIBCPP_ABI_FORCE_ITANIUM and _LIBCPP_ABI_FORCE_MICROSOFT can be defined" +# elif defined(_LIBCPP_ABI_FORCE_ITANIUM) +# define _LIBCPP_ABI_ITANIUM +# elif defined(_LIBCPP_ABI_FORCE_MICROSOFT) +# define _LIBCPP_ABI_MICROSOFT +# else +# if defined(_WIN32) && defined(_MSC_VER) +# define _LIBCPP_ABI_MICROSOFT +# else +# define _LIBCPP_ABI_ITANIUM +# endif +# endif + +# if defined(_LIBCPP_ABI_MICROSOFT) && !defined(_LIBCPP_NO_VCRUNTIME) +# define _LIBCPP_ABI_VCRUNTIME +# endif + +# if __has_feature(experimental_library) +# ifndef _LIBCPP_ENABLE_EXPERIMENTAL +# define _LIBCPP_ENABLE_EXPERIMENTAL +# endif +# endif + +// Incomplete features get their own specific disabling flags. This makes it +// easier to grep for target specific flags once the feature is complete. +# if !defined(_LIBCPP_ENABLE_EXPERIMENTAL) && !defined(_LIBCPP_BUILDING_LIBRARY) +# define _LIBCPP_HAS_NO_INCOMPLETE_PSTL +# define _LIBCPP_HAS_NO_EXPERIMENTAL_STOP_TOKEN +# define _LIBCPP_HAS_NO_EXPERIMENTAL_TZDB +# define _LIBCPP_HAS_NO_EXPERIMENTAL_SYNCSTREAM +# endif + +# if defined(__MVS__) +# include // for __NATIVE_ASCII_F +# endif + +# if defined(_WIN32) +# define _LIBCPP_WIN32API +# define _LIBCPP_SHORT_WCHAR 1 +// Both MinGW and native MSVC provide a "MSVC"-like environment +# define _LIBCPP_MSVCRT_LIKE +// If mingw not explicitly detected, assume using MS C runtime only if +// a MS compatibility version is specified. +# if defined(_MSC_VER) && !defined(__MINGW32__) +# define _LIBCPP_MSVCRT // Using Microsoft's C Runtime library +# endif +# if (defined(_M_AMD64) || defined(__x86_64__)) || (defined(_M_ARM) || defined(__arm__)) +# define _LIBCPP_HAS_BITSCAN64 +# endif +# define _LIBCPP_HAS_OPEN_WITH_WCHAR +# endif // defined(_WIN32) + +# if defined(_AIX) && !defined(__64BIT__) +// The size of wchar is 2 byte on 32-bit mode on AIX. +# define _LIBCPP_SHORT_WCHAR 1 +# endif + +// Libc++ supports various implementations of std::random_device. +// +// _LIBCPP_USING_DEV_RANDOM +// Read entropy from the given file, by default `/dev/urandom`. +// If a token is provided, it is assumed to be the path to a file +// to read entropy from. This is the default behavior if nothing +// else is specified. This implementation requires storing state +// inside `std::random_device`. +// +// _LIBCPP_USING_ARC4_RANDOM +// Use arc4random(). This allows obtaining random data even when +// using sandboxing mechanisms. On some platforms like Apple, this +// is the recommended source of entropy for user-space programs. +// When this option is used, the token passed to `std::random_device`'s +// constructor *must* be "/dev/urandom" -- anything else is an error. +// +// _LIBCPP_USING_GETENTROPY +// Use getentropy(). +// When this option is used, the token passed to `std::random_device`'s +// constructor *must* be "/dev/urandom" -- anything else is an error. +// +// _LIBCPP_USING_FUCHSIA_CPRNG +// Use Fuchsia's zx_cprng_draw() system call, which is specified to +// deliver high-quality entropy and cannot fail. +// When this option is used, the token passed to `std::random_device`'s +// constructor *must* be "/dev/urandom" -- anything else is an error. +// +// _LIBCPP_USING_NACL_RANDOM +// NaCl's sandbox (which PNaCl also runs in) doesn't allow filesystem access, +// including accesses to the special files under `/dev`. This implementation +// uses the NaCL syscall `nacl_secure_random_init()` to get entropy. +// When this option is used, the token passed to `std::random_device`'s +// constructor *must* be "/dev/urandom" -- anything else is an error. +// +// _LIBCPP_USING_WIN32_RANDOM +// Use rand_s(), for use on Windows. +// When this option is used, the token passed to `std::random_device`'s +// constructor *must* be "/dev/urandom" -- anything else is an error. +# if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ + defined(__DragonFly__) +# define _LIBCPP_USING_ARC4_RANDOM +# elif defined(__wasi__) || defined(__EMSCRIPTEN__) +# define _LIBCPP_USING_GETENTROPY +# elif defined(__Fuchsia__) +# define _LIBCPP_USING_FUCHSIA_CPRNG +# elif defined(__native_client__) +# define _LIBCPP_USING_NACL_RANDOM +# elif defined(_LIBCPP_WIN32API) +# define _LIBCPP_USING_WIN32_RANDOM +# else +# define _LIBCPP_USING_DEV_RANDOM +# endif + +# ifndef _LIBCPP_CXX03_LANG + +# define _LIBCPP_ALIGNOF(_Tp) alignof(_Tp) +# define _ALIGNAS_TYPE(x) alignas(x) +# define _ALIGNAS(x) alignas(x) +# define _LIBCPP_NORETURN [[noreturn]] +# define _NOEXCEPT noexcept +# define _NOEXCEPT_(...) noexcept(__VA_ARGS__) +# define _LIBCPP_CONSTEXPR constexpr + +# else + +# define _LIBCPP_ALIGNOF(_Tp) _Alignof(_Tp) +# define _ALIGNAS_TYPE(x) __attribute__((__aligned__(_LIBCPP_ALIGNOF(x)))) +# define _ALIGNAS(x) __attribute__((__aligned__(x))) +# define _LIBCPP_NORETURN __attribute__((__noreturn__)) +# define _LIBCPP_HAS_NO_NOEXCEPT +# define nullptr __nullptr +# define _NOEXCEPT throw() +# define _NOEXCEPT_(...) +# define static_assert(...) _Static_assert(__VA_ARGS__) +# define decltype(...) __decltype(__VA_ARGS__) +# define _LIBCPP_CONSTEXPR + +typedef __char16_t char16_t; +typedef __char32_t char32_t; + +# endif + +# define _LIBCPP_PREFERRED_ALIGNOF(_Tp) __alignof(_Tp) + +// Objective-C++ features (opt-in) +# if __has_feature(objc_arc) +# define _LIBCPP_HAS_OBJC_ARC +# endif + +# if __has_feature(objc_arc_weak) +# define _LIBCPP_HAS_OBJC_ARC_WEAK +# endif + +# if __has_extension(blocks) +# define _LIBCPP_HAS_EXTENSION_BLOCKS +# endif + +# if defined(_LIBCPP_HAS_EXTENSION_BLOCKS) && defined(__APPLE__) +# define _LIBCPP_HAS_BLOCKS_RUNTIME +# endif + +# if !__has_feature(address_sanitizer) +# define _LIBCPP_HAS_NO_ASAN +# endif + +# define _LIBCPP_ALWAYS_INLINE __attribute__((__always_inline__)) + +# define _LIBCPP_DISABLE_EXTENSION_WARNING __extension__ + +# if defined(_LIBCPP_OBJECT_FORMAT_COFF) + +# ifdef _DLL +# define _LIBCPP_CRT_FUNC __declspec(dllimport) +# else +# define _LIBCPP_CRT_FUNC +# endif + +# if defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) || (defined(__MINGW32__) && !defined(_LIBCPP_BUILDING_LIBRARY)) +# define _LIBCPP_DLL_VIS +# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS +# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS +# define _LIBCPP_OVERRIDABLE_FUNC_VIS +# define _LIBCPP_EXPORTED_FROM_ABI +# elif defined(_LIBCPP_BUILDING_LIBRARY) +# define _LIBCPP_DLL_VIS __declspec(dllexport) +# if defined(__MINGW32__) +# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS _LIBCPP_DLL_VIS +# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS +# else +# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS +# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS _LIBCPP_DLL_VIS +# endif +# define _LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_DLL_VIS +# define _LIBCPP_EXPORTED_FROM_ABI __declspec(dllexport) +# else +# define _LIBCPP_DLL_VIS __declspec(dllimport) +# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS _LIBCPP_DLL_VIS +# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS +# define _LIBCPP_OVERRIDABLE_FUNC_VIS +# define _LIBCPP_EXPORTED_FROM_ABI __declspec(dllimport) +# endif + +# define _LIBCPP_HIDDEN +# define _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS +# define _LIBCPP_TEMPLATE_VIS +# define _LIBCPP_TEMPLATE_DATA_VIS +# define _LIBCPP_TYPE_VISIBILITY_DEFAULT + +# else + +# if !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) +# define _LIBCPP_VISIBILITY(vis) __attribute__((__visibility__(vis))) +# else +# define _LIBCPP_VISIBILITY(vis) +# endif + +# define _LIBCPP_HIDDEN _LIBCPP_VISIBILITY("hidden") +# define _LIBCPP_TEMPLATE_DATA_VIS _LIBCPP_VISIBILITY("default") +# define _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_VISIBILITY("default") +# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS _LIBCPP_VISIBILITY("default") +# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS + +// TODO: Make this a proper customization point or remove the option to override it. +# ifndef _LIBCPP_OVERRIDABLE_FUNC_VIS +# define _LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_VISIBILITY("default") +# endif + +# if !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) +// The inline should be removed once PR32114 is resolved +# define _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS inline _LIBCPP_HIDDEN +# else +# define _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS +# endif + +// GCC doesn't support the type_visibility attribute, so we have to keep the visibility attribute on templates +# if !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) && !__has_attribute(__type_visibility__) +# define _LIBCPP_TEMPLATE_VIS __attribute__((__visibility__("default"))) +# else +# define _LIBCPP_TEMPLATE_VIS +# endif + +# if !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) && __has_attribute(__type_visibility__) +# define _LIBCPP_TYPE_VISIBILITY_DEFAULT __attribute__((__type_visibility__("default"))) +# else +# define _LIBCPP_TYPE_VISIBILITY_DEFAULT +# endif + +# endif // defined(_LIBCPP_OBJECT_FORMAT_COFF) + +# if __has_attribute(exclude_from_explicit_instantiation) +# define _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((__exclude_from_explicit_instantiation__)) +# else +// Try to approximate the effect of exclude_from_explicit_instantiation +// (which is that entities are not assumed to be provided by explicit +// template instantiations in the dylib) by always inlining those entities. +# define _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION _LIBCPP_ALWAYS_INLINE +# endif + +# ifdef _LIBCPP_COMPILER_CLANG_BASED +# define _LIBCPP_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") +# define _LIBCPP_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +# define _LIBCPP_CLANG_DIAGNOSTIC_IGNORED(str) _Pragma(_LIBCPP_TOSTRING(clang diagnostic ignored str)) +# define _LIBCPP_GCC_DIAGNOSTIC_IGNORED(str) +# elif defined(_LIBCPP_COMPILER_GCC) +# define _LIBCPP_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") +# define _LIBCPP_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +# define _LIBCPP_CLANG_DIAGNOSTIC_IGNORED(str) +# define _LIBCPP_GCC_DIAGNOSTIC_IGNORED(str) _Pragma(_LIBCPP_TOSTRING(GCC diagnostic ignored str)) +# else +# define _LIBCPP_DIAGNOSTIC_PUSH +# define _LIBCPP_DIAGNOSTIC_POP +# define _LIBCPP_CLANG_DIAGNOSTIC_IGNORED(str) +# define _LIBCPP_GCC_DIAGNOSTIC_IGNORED(str) +# endif + +# if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_FAST +# define _LIBCPP_HARDENING_SIG f +# elif _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_EXTENSIVE +# define _LIBCPP_HARDENING_SIG s +# elif _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG +# define _LIBCPP_HARDENING_SIG d +# else +# define _LIBCPP_HARDENING_SIG n // "none" +# endif + +# ifdef _LIBCPP_HAS_NO_EXCEPTIONS +# define _LIBCPP_EXCEPTIONS_SIG n +# else +# define _LIBCPP_EXCEPTIONS_SIG e +# endif + +# define _LIBCPP_ODR_SIGNATURE \ + _LIBCPP_CONCAT(_LIBCPP_CONCAT(_LIBCPP_HARDENING_SIG, _LIBCPP_EXCEPTIONS_SIG), _LIBCPP_VERSION) + +// This macro marks a symbol as being hidden from libc++'s ABI. This is achieved +// on two levels: +// 1. The symbol is given hidden visibility, which ensures that users won't start exporting +// symbols from their dynamic library by means of using the libc++ headers. This ensures +// that those symbols stay private to the dynamic library in which it is defined. +// +// 2. The symbol is given an ABI tag that encodes the ODR-relevant properties of the library. +// This ensures that no ODR violation can arise from mixing two TUs compiled with different +// versions or configurations of libc++ (such as exceptions vs no-exceptions). Indeed, if the +// program contains two definitions of a function, the ODR requires them to be token-by-token +// equivalent, and the linker is allowed to pick either definition and discard the other one. +// +// For example, if a program contains a copy of `vector::at()` compiled with exceptions enabled +// *and* a copy of `vector::at()` compiled with exceptions disabled (by means of having two TUs +// compiled with different settings), the two definitions are both visible by the linker and they +// have the same name, but they have a meaningfully different implementation (one throws an exception +// and the other aborts the program). This violates the ODR and makes the program ill-formed, and in +// practice what will happen is that the linker will pick one of the definitions at random and will +// discard the other one. This can quite clearly lead to incorrect program behavior. +// +// A similar reasoning holds for many other properties that are ODR-affecting. Essentially any +// property that causes the code of a function to differ from the code in another configuration +// can be considered ODR-affecting. In practice, we don't encode all such properties in the ABI +// tag, but we encode the ones that we think are most important: library version, exceptions, and +// hardening mode. +// +// Note that historically, solving this problem has been achieved in various ways, including +// force-inlining all functions or giving internal linkage to all functions. Both these previous +// solutions suffer from drawbacks that lead notably to code bloat. +// +// Note that we use _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION to ensure that we don't depend +// on _LIBCPP_HIDE_FROM_ABI methods of classes explicitly instantiated in the dynamic library. +// +// Also note that the _LIBCPP_HIDE_FROM_ABI_VIRTUAL macro should be used on virtual functions +// instead of _LIBCPP_HIDE_FROM_ABI. That macro does not use an ABI tag. Indeed, the mangled +// name of a virtual function is part of its ABI, since some architectures like arm64e can sign +// the virtual function pointer in the vtable based on the mangled name of the function. Since +// we use an ABI tag that changes with each released version, the mangled name of the virtual +// function would change, which is incorrect. Note that it doesn't make much sense to change +// the implementation of a virtual function in an ABI-incompatible way in the first place, +// since that would be an ABI break anyway. Hence, the lack of ABI tag should not be noticeable. +// +// The macro can be applied to record and enum types. When the tagged type is nested in +// a record this "parent" record needs to have the macro too. Another use case for applying +// this macro to records and unions is to apply an ABI tag to inline constexpr variables. +// This can be useful for inline variables that are implementation details which are expected +// to change in the future. +// +// TODO: We provide a escape hatch with _LIBCPP_NO_ABI_TAG for folks who want to avoid increasing +// the length of symbols with an ABI tag. In practice, we should remove the escape hatch and +// use compression mangling instead, see https://github.com/itanium-cxx-abi/cxx-abi/issues/70. +# ifndef _LIBCPP_NO_ABI_TAG +# define _LIBCPP_HIDE_FROM_ABI \ + _LIBCPP_HIDDEN _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION \ + __attribute__((__abi_tag__(_LIBCPP_TOSTRING(_LIBCPP_ODR_SIGNATURE)))) +# else +# define _LIBCPP_HIDE_FROM_ABI _LIBCPP_HIDDEN _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION +# endif +# define _LIBCPP_HIDE_FROM_ABI_VIRTUAL _LIBCPP_HIDDEN _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION + +# ifdef _LIBCPP_BUILDING_LIBRARY +# if _LIBCPP_ABI_VERSION > 1 +# define _LIBCPP_HIDE_FROM_ABI_AFTER_V1 _LIBCPP_HIDE_FROM_ABI +# else +# define _LIBCPP_HIDE_FROM_ABI_AFTER_V1 +# endif +# else +# define _LIBCPP_HIDE_FROM_ABI_AFTER_V1 _LIBCPP_HIDE_FROM_ABI +# endif + +// TODO: Remove this workaround once we drop support for Clang 16 +# if __has_warning("-Wc++23-extensions") +# define _LIBCPP_CLANG_DIAGNOSTIC_IGNORED_CXX23_EXTENSION _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++23-extensions") +# else +# define _LIBCPP_CLANG_DIAGNOSTIC_IGNORED_CXX23_EXTENSION _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++2b-extensions") +# endif + +// Clang modules take a significant compile time hit when pushing and popping diagnostics. +// Since all the headers are marked as system headers in the modulemap, we can simply disable this +// pushing and popping when building with clang modules. +# if !__has_feature(modules) +# define _LIBCPP_PUSH_EXTENSION_DIAGNOSTICS \ + _LIBCPP_DIAGNOSTIC_PUSH \ + _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++11-extensions") \ + _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++14-extensions") \ + _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++17-extensions") \ + _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wc++20-extensions") \ + _LIBCPP_CLANG_DIAGNOSTIC_IGNORED_CXX23_EXTENSION \ + _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++14-extensions") \ + _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++17-extensions") \ + _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++20-extensions") \ + _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wc++23-extensions") +# define _LIBCPP_POP_EXTENSION_DIAGNOSTICS _LIBCPP_DIAGNOSTIC_POP +# else +# define _LIBCPP_PUSH_EXTENSION_DIAGNOSTICS +# define _LIBCPP_POP_EXTENSION_DIAGNOSTICS +# endif + +// Inline namespaces are available in Clang/GCC/MSVC regardless of C++ dialect. +// clang-format off +# define _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_PUSH_EXTENSION_DIAGNOSTICS \ + namespace _LIBCPP_TYPE_VISIBILITY_DEFAULT std { \ + inline namespace _LIBCPP_ABI_NAMESPACE { +# define _LIBCPP_END_NAMESPACE_STD }} _LIBCPP_POP_EXTENSION_DIAGNOSTICS + +#ifdef _LIBCPP_ABI_NO_FILESYSTEM_INLINE_NAMESPACE +# define _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM _LIBCPP_BEGIN_NAMESPACE_STD namespace filesystem { +# define _LIBCPP_END_NAMESPACE_FILESYSTEM } _LIBCPP_END_NAMESPACE_STD +#else +# define _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM _LIBCPP_BEGIN_NAMESPACE_STD \ + inline namespace __fs { namespace filesystem { + +# define _LIBCPP_END_NAMESPACE_FILESYSTEM }} _LIBCPP_END_NAMESPACE_STD +#endif + +// clang-format on + +# if __has_attribute(__enable_if__) +# define _LIBCPP_PREFERRED_OVERLOAD __attribute__((__enable_if__(true, ""))) +# endif + +# if !defined(__SIZEOF_INT128__) || defined(_MSC_VER) +# define _LIBCPP_HAS_NO_INT128 +# endif + +# ifdef _LIBCPP_CXX03_LANG +# define _LIBCPP_DECLARE_STRONG_ENUM(x) \ + struct _LIBCPP_EXPORTED_FROM_ABI x { \ + enum __lx +// clang-format off +# define _LIBCPP_DECLARE_STRONG_ENUM_EPILOG(x) \ + __lx __v_; \ + _LIBCPP_HIDE_FROM_ABI x(__lx __v) : __v_(__v) {} \ + _LIBCPP_HIDE_FROM_ABI explicit x(int __v) : __v_(static_cast<__lx>(__v)) {} \ + _LIBCPP_HIDE_FROM_ABI operator int() const { return __v_; } \ + }; +// clang-format on + +# else // _LIBCPP_CXX03_LANG +# define _LIBCPP_DECLARE_STRONG_ENUM(x) enum class x +# define _LIBCPP_DECLARE_STRONG_ENUM_EPILOG(x) +# endif // _LIBCPP_CXX03_LANG + +# if defined(__APPLE__) || defined(__FreeBSD__) || defined(_LIBCPP_MSVCRT_LIKE) || defined(__NetBSD__) +# define _LIBCPP_LOCALE__L_EXTENSIONS 1 +# endif + +# ifdef __FreeBSD__ +# define _DECLARE_C99_LDBL_MATH 1 +# endif + +// If we are getting operator new from the MSVC CRT, then allocation overloads +// for align_val_t were added in 19.12, aka VS 2017 version 15.3. +# if defined(_LIBCPP_MSVCRT) && defined(_MSC_VER) && _MSC_VER < 1912 +# define _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION +# elif defined(_LIBCPP_ABI_VCRUNTIME) && !defined(__cpp_aligned_new) +// We're deferring to Microsoft's STL to provide aligned new et al. We don't +// have it unless the language feature test macro is defined. +# define _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION +# elif defined(__MVS__) +# define _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION +# endif + +# if defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) || (!defined(__cpp_aligned_new) || __cpp_aligned_new < 201606) +# define _LIBCPP_HAS_NO_ALIGNED_ALLOCATION +# endif + +// It is not yet possible to use aligned_alloc() on all Apple platforms since +// 10.15 was the first version to ship an implementation of aligned_alloc(). +# if defined(__APPLE__) +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101500) +# define _LIBCPP_HAS_NO_C11_ALIGNED_ALLOC +# endif +# elif defined(__ANDROID__) && __ANDROID_API__ < 28 +// Android only provides aligned_alloc when targeting API 28 or higher. +# define _LIBCPP_HAS_NO_C11_ALIGNED_ALLOC +# endif + +# if defined(__APPLE__) || defined(__FreeBSD__) +# define _LIBCPP_HAS_DEFAULTRUNELOCALE +# endif + +# if defined(__APPLE__) || defined(__FreeBSD__) +# define _LIBCPP_WCTYPE_IS_MASK +# endif + +# if _LIBCPP_STD_VER <= 17 || !defined(__cpp_char8_t) +# define _LIBCPP_HAS_NO_CHAR8_T +# endif + +// Deprecation macros. +// +// Deprecations warnings are always enabled, except when users explicitly opt-out +// by defining _LIBCPP_DISABLE_DEPRECATION_WARNINGS. +# if !defined(_LIBCPP_DISABLE_DEPRECATION_WARNINGS) +# if __has_attribute(__deprecated__) +# define _LIBCPP_DEPRECATED __attribute__((__deprecated__)) +# define _LIBCPP_DEPRECATED_(m) __attribute__((__deprecated__(m))) +# elif _LIBCPP_STD_VER >= 14 +# define _LIBCPP_DEPRECATED [[deprecated]] +# define _LIBCPP_DEPRECATED_(m) [[deprecated(m)]] +# else +# define _LIBCPP_DEPRECATED +# define _LIBCPP_DEPRECATED_(m) +# endif +# else +# define _LIBCPP_DEPRECATED +# define _LIBCPP_DEPRECATED_(m) +# endif + +# if _LIBCPP_STD_VER < 20 +# define _LIBCPP_DEPRECATED_ATOMIC_SYNC \ + _LIBCPP_DEPRECATED_("The C++20 synchronization library has been deprecated prior to C++20. Please update to " \ + "using -std=c++20 if you need to use these facilities.") +# else +# define _LIBCPP_DEPRECATED_ATOMIC_SYNC /* nothing */ +# endif + +# if !defined(_LIBCPP_CXX03_LANG) +# define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED +# else +# define _LIBCPP_DEPRECATED_IN_CXX11 +# endif + +# if _LIBCPP_STD_VER >= 14 +# define _LIBCPP_DEPRECATED_IN_CXX14 _LIBCPP_DEPRECATED +# else +# define _LIBCPP_DEPRECATED_IN_CXX14 +# endif + +# if _LIBCPP_STD_VER >= 17 +# define _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_DEPRECATED +# else +# define _LIBCPP_DEPRECATED_IN_CXX17 +# endif + +# if _LIBCPP_STD_VER >= 20 +# define _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_DEPRECATED +# else +# define _LIBCPP_DEPRECATED_IN_CXX20 +# endif + +# if _LIBCPP_STD_VER >= 23 +# define _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_DEPRECATED +# else +# define _LIBCPP_DEPRECATED_IN_CXX23 +# endif + +# if _LIBCPP_STD_VER >= 26 +# define _LIBCPP_DEPRECATED_IN_CXX26 _LIBCPP_DEPRECATED +# else +# define _LIBCPP_DEPRECATED_IN_CXX26 +# endif + +# if !defined(_LIBCPP_HAS_NO_CHAR8_T) +# define _LIBCPP_DEPRECATED_WITH_CHAR8_T _LIBCPP_DEPRECATED +# else +# define _LIBCPP_DEPRECATED_WITH_CHAR8_T +# endif + +// Macros to enter and leave a state where deprecation warnings are suppressed. +# if defined(_LIBCPP_COMPILER_CLANG_BASED) || defined(_LIBCPP_COMPILER_GCC) +# define _LIBCPP_SUPPRESS_DEPRECATED_PUSH \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wdeprecated\"") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define _LIBCPP_SUPPRESS_DEPRECATED_POP _Pragma("GCC diagnostic pop") +# else +# define _LIBCPP_SUPPRESS_DEPRECATED_PUSH +# define _LIBCPP_SUPPRESS_DEPRECATED_POP +# endif + +# if _LIBCPP_STD_VER <= 11 +# define _LIBCPP_EXPLICIT_SINCE_CXX14 +# else +# define _LIBCPP_EXPLICIT_SINCE_CXX14 explicit +# endif + +# if _LIBCPP_STD_VER >= 23 +# define _LIBCPP_EXPLICIT_SINCE_CXX23 explicit +# else +# define _LIBCPP_EXPLICIT_SINCE_CXX23 +# endif + +# if _LIBCPP_STD_VER >= 14 +# define _LIBCPP_CONSTEXPR_SINCE_CXX14 constexpr +# else +# define _LIBCPP_CONSTEXPR_SINCE_CXX14 +# endif + +# if _LIBCPP_STD_VER >= 17 +# define _LIBCPP_CONSTEXPR_SINCE_CXX17 constexpr +# else +# define _LIBCPP_CONSTEXPR_SINCE_CXX17 +# endif + +# if _LIBCPP_STD_VER >= 20 +# define _LIBCPP_CONSTEXPR_SINCE_CXX20 constexpr +# else +# define _LIBCPP_CONSTEXPR_SINCE_CXX20 +# endif + +# if _LIBCPP_STD_VER >= 23 +# define _LIBCPP_CONSTEXPR_SINCE_CXX23 constexpr +# else +# define _LIBCPP_CONSTEXPR_SINCE_CXX23 +# endif + +# ifndef _LIBCPP_WEAK +# define _LIBCPP_WEAK __attribute__((__weak__)) +# endif + +// Thread API +// clang-format off +# if !defined(_LIBCPP_HAS_NO_THREADS) && \ + !defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && \ + !defined(_LIBCPP_HAS_THREAD_API_WIN32) && \ + !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) + +# if defined(__FreeBSD__) || \ + defined(__wasi__) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NuttX__) || \ + defined(__linux__) || \ + defined(__GNU__) || \ + defined(__APPLE__) || \ + defined(__MVS__) || \ + defined(_AIX) || \ + defined(__EMSCRIPTEN__) +// clang-format on +# define _LIBCPP_HAS_THREAD_API_PTHREAD +# elif defined(__Fuchsia__) +// TODO(44575): Switch to C11 thread API when possible. +# define _LIBCPP_HAS_THREAD_API_PTHREAD +# elif defined(_LIBCPP_WIN32API) +# define _LIBCPP_HAS_THREAD_API_WIN32 +# else +# error "No thread API" +# endif // _LIBCPP_HAS_THREAD_API +# endif // _LIBCPP_HAS_NO_THREADS + +# if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) +# if defined(__ANDROID__) && __ANDROID_API__ >= 30 +# define _LIBCPP_HAS_COND_CLOCKWAIT +# elif defined(_LIBCPP_GLIBC_PREREQ) +# if _LIBCPP_GLIBC_PREREQ(2, 30) +# define _LIBCPP_HAS_COND_CLOCKWAIT +# endif +# endif +# endif + +# if defined(_LIBCPP_HAS_NO_THREADS) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD) +# error _LIBCPP_HAS_THREAD_API_PTHREAD may only be defined when \ + _LIBCPP_HAS_NO_THREADS is not defined. +# endif + +# if defined(_LIBCPP_HAS_NO_THREADS) && defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) +# error _LIBCPP_HAS_THREAD_API_EXTERNAL may not be defined when \ + _LIBCPP_HAS_NO_THREADS is defined. +# endif + +# if defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK) && !defined(_LIBCPP_HAS_NO_THREADS) +# error _LIBCPP_HAS_NO_MONOTONIC_CLOCK may only be defined when \ + _LIBCPP_HAS_NO_THREADS is defined. +# endif + +# if !defined(_LIBCPP_HAS_NO_THREADS) && !defined(__STDCPP_THREADS__) +# define __STDCPP_THREADS__ 1 +# endif + +// The glibc and Bionic implementation of pthreads implements +// pthread_mutex_destroy as nop for regular mutexes. Additionally, Win32 +// mutexes have no destroy mechanism. +// +// This optimization can't be performed on Apple platforms, where +// pthread_mutex_destroy can allow the kernel to release resources. +// See https://llvm.org/D64298 for details. +// +// TODO(EricWF): Enable this optimization on Bionic after speaking to their +// respective stakeholders. +// clang-format off +# if (defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && defined(__GLIBC__)) || \ + (defined(_LIBCPP_HAS_THREAD_API_C11) && defined(__Fuchsia__)) || \ + defined(_LIBCPP_HAS_THREAD_API_WIN32) +// clang-format on +# define _LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION +# endif + +// Destroying a condvar is a nop on Windows. +// +// This optimization can't be performed on Apple platforms, where +// pthread_cond_destroy can allow the kernel to release resources. +// See https://llvm.org/D64298 for details. +// +// TODO(EricWF): This is potentially true for some pthread implementations +// as well. +# if (defined(_LIBCPP_HAS_THREAD_API_C11) && defined(__Fuchsia__)) || defined(_LIBCPP_HAS_THREAD_API_WIN32) +# define _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION +# endif + +# if defined(__BIONIC__) || defined(__NuttX__) || defined(__Fuchsia__) || defined(__wasi__) || \ + defined(_LIBCPP_HAS_MUSL_LIBC) || defined(__OpenBSD__) +# define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE +# endif + +# if __has_feature(cxx_atomic) || __has_extension(c_atomic) || __has_keyword(_Atomic) +# define _LIBCPP_HAS_C_ATOMIC_IMP +# elif defined(_LIBCPP_COMPILER_GCC) +# define _LIBCPP_HAS_GCC_ATOMIC_IMP +# endif + +# if !defined(_LIBCPP_HAS_C_ATOMIC_IMP) && !defined(_LIBCPP_HAS_GCC_ATOMIC_IMP) && \ + !defined(_LIBCPP_HAS_EXTERNAL_ATOMIC_IMP) +# define _LIBCPP_HAS_NO_ATOMIC_HEADER +# else +# ifndef _LIBCPP_ATOMIC_FLAG_TYPE +# define _LIBCPP_ATOMIC_FLAG_TYPE bool +# endif +# endif + +# if defined(__FreeBSD__) && defined(__clang__) && __has_attribute(__no_thread_safety_analysis__) +# define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS __attribute__((__no_thread_safety_analysis__)) +# else +# define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS +# endif + +# if defined(_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS) +# if defined(__clang__) && __has_attribute(acquire_capability) +// Work around the attribute handling in clang. When both __declspec and +// __attribute__ are present, the processing goes awry preventing the definition +// of the types. In MinGW mode, __declspec evaluates to __attribute__, and thus +// combining the two does work. +# if !defined(_MSC_VER) +# define _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS +# endif +# endif +# endif + +# ifdef _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS +# define _LIBCPP_THREAD_SAFETY_ANNOTATION(x) __attribute__((x)) +# else +# define _LIBCPP_THREAD_SAFETY_ANNOTATION(x) +# endif + +# if _LIBCPP_STD_VER >= 20 +# define _LIBCPP_CONSTINIT constinit +# elif __has_attribute(__require_constant_initialization__) +# define _LIBCPP_CONSTINIT __attribute__((__require_constant_initialization__)) +# else +# define _LIBCPP_CONSTINIT +# endif + +# if defined(__CUDACC__) || defined(__CUDA_ARCH__) || defined(__CUDA_LIBDEVICE__) +// The CUDA SDK contains an unfortunate definition for the __noinline__ macro, +// which breaks the regular __attribute__((__noinline__)) syntax. Therefore, +// when compiling for CUDA we use the non-underscored version of the noinline +// attribute. +// +// This is a temporary workaround and we still expect the CUDA SDK team to solve +// this issue properly in the SDK headers. +// +// See https://github.com/llvm/llvm-project/pull/73838 for more details. +# define _LIBCPP_NOINLINE __attribute__((noinline)) +# elif __has_attribute(__noinline__) +# define _LIBCPP_NOINLINE __attribute__((__noinline__)) +# else +# define _LIBCPP_NOINLINE +# endif + +// We often repeat things just for handling wide characters in the library. +// When wide characters are disabled, it can be useful to have a quick way of +// disabling it without having to resort to #if-#endif, which has a larger +// impact on readability. +# if defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) +# define _LIBCPP_IF_WIDE_CHARACTERS(...) +# else +# define _LIBCPP_IF_WIDE_CHARACTERS(...) __VA_ARGS__ +# endif + +// clang-format off +# define _LIBCPP_PUSH_MACROS _Pragma("push_macro(\"min\")") _Pragma("push_macro(\"max\")") _Pragma("push_macro(\"refresh\")") _Pragma("push_macro(\"move\")") _Pragma("push_macro(\"erase\")") +# define _LIBCPP_POP_MACROS _Pragma("pop_macro(\"min\")") _Pragma("pop_macro(\"max\")") _Pragma("pop_macro(\"refresh\")") _Pragma("pop_macro(\"move\")") _Pragma("pop_macro(\"erase\")") +// clang-format on + +# ifndef _LIBCPP_NO_AUTO_LINK +# if defined(_LIBCPP_ABI_MICROSOFT) && !defined(_LIBCPP_BUILDING_LIBRARY) +# if !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) +# pragma comment(lib, "c++.lib") +# else +# pragma comment(lib, "libc++.lib") +# endif +# endif // defined(_LIBCPP_ABI_MICROSOFT) && !defined(_LIBCPP_BUILDING_LIBRARY) +# endif // _LIBCPP_NO_AUTO_LINK + +// Configures the fopen close-on-exec mode character, if any. This string will +// be appended to any mode string used by fstream for fopen/fdopen. +// +// Not all platforms support this, but it helps avoid fd-leaks on platforms that +// do. +# if defined(__BIONIC__) +# define _LIBCPP_FOPEN_CLOEXEC_MODE "e" +# else +# define _LIBCPP_FOPEN_CLOEXEC_MODE +# endif + +# if __has_cpp_attribute(msvc::no_unique_address) +// MSVC implements [[no_unique_address]] as a silent no-op currently. +// (If/when MSVC breaks its C++ ABI, it will be changed to work as intended.) +// However, MSVC implements [[msvc::no_unique_address]] which does what +// [[no_unique_address]] is supposed to do, in general. + +// Clang-cl does not yet (14.0) implement either [[no_unique_address]] or +// [[msvc::no_unique_address]] though. If/when it does implement +// [[msvc::no_unique_address]], this should be preferred though. +# define _LIBCPP_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] +# elif __has_cpp_attribute(no_unique_address) +# define _LIBCPP_NO_UNIQUE_ADDRESS [[__no_unique_address__]] +# else +# define _LIBCPP_NO_UNIQUE_ADDRESS /* nothing */ +// Note that this can be replaced by #error as soon as clang-cl +// implements msvc::no_unique_address, since there should be no C++20 +// compiler that doesn't support one of the two attributes at that point. +// We generally don't want to use this macro outside of C++20-only code, +// because using it conditionally in one language version only would make +// the ABI inconsistent. +# endif + +// c8rtomb() and mbrtoc8() were added in C++20 and C23. Support for these +// functions is gradually being added to existing C libraries. The conditions +// below check for known C library versions and conditions under which these +// functions are declared by the C library. +# define _LIBCPP_HAS_NO_C8RTOMB_MBRTOC8 +// GNU libc 2.36 and newer declare c8rtomb() and mbrtoc8() in C++ modes if +// __cpp_char8_t is defined or if C2X extensions are enabled. Determining +// the latter depends on internal GNU libc details that are not appropriate +// to depend on here, so any declarations present when __cpp_char8_t is not +// defined are ignored. +# if defined(_LIBCPP_GLIBC_PREREQ) +# if _LIBCPP_GLIBC_PREREQ(2, 36) && defined(__cpp_char8_t) +# undef _LIBCPP_HAS_NO_C8RTOMB_MBRTOC8 +# endif +# endif + +// There are a handful of public standard library types that are intended to +// support CTAD but don't need any explicit deduction guides to do so. This +// macro is used to mark them as such, which suppresses the +// '-Wctad-maybe-unsupported' compiler warning when CTAD is used in user code +// with these classes. +# if _LIBCPP_STD_VER >= 17 +# ifdef _LIBCPP_COMPILER_CLANG_BASED +# define _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(_ClassName) \ + template \ + [[maybe_unused]] _ClassName(typename _Tag::__allow_ctad...)->_ClassName<_Tag...> +# else +# define _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(ClassName) \ + template \ + ClassName(typename _Tag::__allow_ctad...)->ClassName<_Tag...> +# endif +# else +# define _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(_ClassName) static_assert(true, "") +# endif + +// TODO(varconst): currently, there are bugs in Clang's intrinsics when handling Objective-C++ `id`, so don't use +// compiler intrinsics in the Objective-C++ mode. +# ifdef __OBJC__ +# define _LIBCPP_WORKAROUND_OBJCXX_COMPILER_INTRINSICS +# endif + +# define _PSTL_PRAGMA(x) _Pragma(#x) + +// Enable SIMD for compilers that support OpenMP 4.0 +# if (defined(_OPENMP) && _OPENMP >= 201307) + +# define _PSTL_UDR_PRESENT +# define _PSTL_PRAGMA_SIMD _PSTL_PRAGMA(omp simd) +# define _PSTL_PRAGMA_DECLARE_SIMD _PSTL_PRAGMA(omp declare simd) +# define _PSTL_PRAGMA_SIMD_REDUCTION(PRM) _PSTL_PRAGMA(omp simd reduction(PRM)) +# define _PSTL_PRAGMA_SIMD_SCAN(PRM) _PSTL_PRAGMA(omp simd reduction(inscan, PRM)) +# define _PSTL_PRAGMA_SIMD_INCLUSIVE_SCAN(PRM) _PSTL_PRAGMA(omp scan inclusive(PRM)) +# define _PSTL_PRAGMA_SIMD_EXCLUSIVE_SCAN(PRM) _PSTL_PRAGMA(omp scan exclusive(PRM)) + +// Declaration of reduction functor, where +// NAME - the name of the functor +// OP - type of the callable object with the reduction operation +// omp_in - refers to the local partial result +// omp_out - refers to the final value of the combiner operator +// omp_priv - refers to the private copy of the initial value +// omp_orig - refers to the original variable to be reduced +# define _PSTL_PRAGMA_DECLARE_REDUCTION(NAME, OP) \ + _PSTL_PRAGMA(omp declare reduction(NAME:OP : omp_out(omp_in)) initializer(omp_priv = omp_orig)) + +# elif defined(_LIBCPP_COMPILER_CLANG_BASED) + +# define _PSTL_PRAGMA_SIMD _Pragma("clang loop vectorize(enable) interleave(enable)") +# define _PSTL_PRAGMA_DECLARE_SIMD +# define _PSTL_PRAGMA_SIMD_REDUCTION(PRM) _Pragma("clang loop vectorize(enable) interleave(enable)") +# define _PSTL_PRAGMA_SIMD_SCAN(PRM) _Pragma("clang loop vectorize(enable) interleave(enable)") +# define _PSTL_PRAGMA_SIMD_INCLUSIVE_SCAN(PRM) +# define _PSTL_PRAGMA_SIMD_EXCLUSIVE_SCAN(PRM) +# define _PSTL_PRAGMA_DECLARE_REDUCTION(NAME, OP) + +# else // (defined(_OPENMP) && _OPENMP >= 201307) + +# define _PSTL_PRAGMA_SIMD +# define _PSTL_PRAGMA_DECLARE_SIMD +# define _PSTL_PRAGMA_SIMD_REDUCTION(PRM) +# define _PSTL_PRAGMA_SIMD_SCAN(PRM) +# define _PSTL_PRAGMA_SIMD_INCLUSIVE_SCAN(PRM) +# define _PSTL_PRAGMA_SIMD_EXCLUSIVE_SCAN(PRM) +# define _PSTL_PRAGMA_DECLARE_REDUCTION(NAME, OP) + +# endif // (defined(_OPENMP) && _OPENMP >= 201307) + +# define _PSTL_USE_NONTEMPORAL_STORES_IF_ALLOWED + +// Optional attributes - these are useful for a better QoI, but not required to be available + +# if __has_attribute(__no_sanitize__) && !defined(_LIBCPP_COMPILER_GCC) +# define _LIBCPP_NO_CFI __attribute__((__no_sanitize__("cfi"))) +# else +# define _LIBCPP_NO_CFI +# endif + +# if __has_attribute(__malloc__) +# define _LIBCPP_NOALIAS __attribute__((__malloc__)) +# else +# define _LIBCPP_NOALIAS +# endif + +# if __has_attribute(__using_if_exists__) +# define _LIBCPP_USING_IF_EXISTS __attribute__((__using_if_exists__)) +# else +# define _LIBCPP_USING_IF_EXISTS +# endif + +# if __has_cpp_attribute(__nodiscard__) +# define _LIBCPP_NODISCARD [[__nodiscard__]] +# else +// We can't use GCC's [[gnu::warn_unused_result]] and +// __attribute__((warn_unused_result)), because GCC does not silence them via +// (void) cast. +# define _LIBCPP_NODISCARD +# endif + +# if __has_attribute(__no_destroy__) +# define _LIBCPP_NO_DESTROY __attribute__((__no_destroy__)) +# else +# define _LIBCPP_NO_DESTROY +# endif + +# if __has_attribute(__diagnose_if__) +# define _LIBCPP_DIAGNOSE_WARNING(...) __attribute__((__diagnose_if__(__VA_ARGS__, "warning"))) +# else +# define _LIBCPP_DIAGNOSE_WARNING(...) +# endif + +// Use a function like macro to imply that it must be followed by a semicolon +# if __has_cpp_attribute(fallthrough) +# define _LIBCPP_FALLTHROUGH() [[fallthrough]] +# elif __has_attribute(__fallthrough__) +# define _LIBCPP_FALLTHROUGH() __attribute__((__fallthrough__)) +# else +# define _LIBCPP_FALLTHROUGH() ((void)0) +# endif + +# if __has_cpp_attribute(_Clang::__lifetimebound__) +# define _LIBCPP_LIFETIMEBOUND [[_Clang::__lifetimebound__]] +# else +# define _LIBCPP_LIFETIMEBOUND +# endif + +# if __has_attribute(__nodebug__) +# define _LIBCPP_NODEBUG __attribute__((__nodebug__)) +# else +# define _LIBCPP_NODEBUG +# endif + +# if __has_attribute(__standalone_debug__) +# define _LIBCPP_STANDALONE_DEBUG __attribute__((__standalone_debug__)) +# else +# define _LIBCPP_STANDALONE_DEBUG +# endif + +# if __has_attribute(__preferred_name__) +# define _LIBCPP_PREFERRED_NAME(x) __attribute__((__preferred_name__(x))) +# else +# define _LIBCPP_PREFERRED_NAME(x) +# endif + +# if __has_attribute(__no_sanitize__) +# define _LIBCPP_NO_SANITIZE(...) __attribute__((__no_sanitize__(__VA_ARGS__))) +# else +# define _LIBCPP_NO_SANITIZE(...) +# endif + +# if __has_attribute(__init_priority__) +# define _LIBCPP_INIT_PRIORITY_MAX __attribute__((__init_priority__(100))) +# else +# define _LIBCPP_INIT_PRIORITY_MAX +# endif + +# if __has_attribute(__format__) +// The attribute uses 1-based indices for ordinary and static member functions. +// The attribute uses 2-based indices for non-static member functions. +# define _LIBCPP_ATTRIBUTE_FORMAT(archetype, format_string_index, first_format_arg_index) \ + __attribute__((__format__(archetype, format_string_index, first_format_arg_index))) +# else +# define _LIBCPP_ATTRIBUTE_FORMAT(archetype, format_string_index, first_format_arg_index) /* nothing */ +# endif + +# if __has_attribute(__packed__) +# define _LIBCPP_PACKED __attribute__((__packed__)) +# else +# define _LIBCPP_PACKED +# endif + +# if defined(_LIBCPP_ABI_MICROSOFT) && __has_declspec_attribute(empty_bases) +# define _LIBCPP_DECLSPEC_EMPTY_BASES __declspec(empty_bases) +# else +# define _LIBCPP_DECLSPEC_EMPTY_BASES +# endif + +// Allow for build-time disabling of unsigned integer sanitization +# if __has_attribute(no_sanitize) && !defined(_LIBCPP_COMPILER_GCC) +# define _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK __attribute__((__no_sanitize__("unsigned-integer-overflow"))) +# else +# define _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK +# endif + +// Clang-18 has support for deducing this, but it does not set the FTM. +# if defined(__cpp_explicit_this_parameter) || (defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 1800) +# define _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER +# endif + +#endif // __cplusplus + +#endif // _LIBCPP___CONFIG diff --git a/libcxx/include/__cxx03/__config_site.in b/libcxx/include/__cxx03/__config_site.in new file mode 100644 index 0000000000000000000000000000000000000000..67022146c9082bd30d3bdec4a55d3381ca17b33a --- /dev/null +++ b/libcxx/include/__cxx03/__config_site.in @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONFIG_SITE +#define _LIBCPP___CONFIG_SITE + +#cmakedefine _LIBCPP_ABI_VERSION @_LIBCPP_ABI_VERSION@ +#cmakedefine _LIBCPP_ABI_NAMESPACE @_LIBCPP_ABI_NAMESPACE@ +#cmakedefine _LIBCPP_ABI_FORCE_ITANIUM +#cmakedefine _LIBCPP_ABI_FORCE_MICROSOFT +#cmakedefine _LIBCPP_HAS_NO_THREADS +#cmakedefine _LIBCPP_HAS_NO_MONOTONIC_CLOCK +#cmakedefine _LIBCPP_HAS_MUSL_LIBC +#cmakedefine _LIBCPP_HAS_THREAD_API_PTHREAD +#cmakedefine _LIBCPP_HAS_THREAD_API_EXTERNAL +#cmakedefine _LIBCPP_HAS_THREAD_API_WIN32 +#cmakedefine _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS +#cmakedefine _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS +#cmakedefine _LIBCPP_NO_VCRUNTIME +#cmakedefine _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION @_LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION@ +#cmakedefine _LIBCPP_HAS_NO_FILESYSTEM +#cmakedefine _LIBCPP_HAS_NO_RANDOM_DEVICE +#cmakedefine _LIBCPP_HAS_NO_LOCALIZATION +#cmakedefine _LIBCPP_HAS_NO_UNICODE +#cmakedefine _LIBCPP_HAS_NO_WIDE_CHARACTERS +#cmakedefine _LIBCPP_HAS_NO_STD_MODULES +#cmakedefine _LIBCPP_HAS_NO_TIME_ZONE_DATABASE +#cmakedefine _LIBCPP_INSTRUMENTED_WITH_ASAN + +// PSTL backends +#cmakedefine _LIBCPP_PSTL_BACKEND_SERIAL +#cmakedefine _LIBCPP_PSTL_BACKEND_STD_THREAD +#cmakedefine _LIBCPP_PSTL_BACKEND_LIBDISPATCH + +// Hardening. +#cmakedefine _LIBCPP_HARDENING_MODE_DEFAULT @_LIBCPP_HARDENING_MODE_DEFAULT@ + +// __USE_MINGW_ANSI_STDIO gets redefined on MinGW +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wmacro-redefined" +#endif + +@_LIBCPP_ABI_DEFINES@ +@_LIBCPP_EXTRA_SITE_DEFINES@ + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + +#endif // _LIBCPP___CONFIG_SITE diff --git a/libcxx/include/__cxx03/__configuration/abi.h b/libcxx/include/__cxx03/__configuration/abi.h new file mode 100644 index 0000000000000000000000000000000000000000..0422b645727d8a8d41a7c7932bc9c09cda92c2b1 --- /dev/null +++ b/libcxx/include/__cxx03/__configuration/abi.h @@ -0,0 +1,172 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONFIGURATION_ABI_H +#define _LIBCPP___CONFIGURATION_ABI_H + +#include <__config_site> +#include <__configuration/compiler.h> +#include <__configuration/platform.h> + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +# pragma GCC system_header +#endif + +#if _LIBCPP_ABI_VERSION >= 2 +// Change short string representation so that string data starts at offset 0, +// improving its alignment in some cases. +# define _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT +// Fix deque iterator type in order to support incomplete types. +# define _LIBCPP_ABI_INCOMPLETE_TYPES_IN_DEQUE +// Fix undefined behavior in how std::list stores its linked nodes. +# define _LIBCPP_ABI_LIST_REMOVE_NODE_POINTER_UB +// Fix undefined behavior in how __tree stores its end and parent nodes. +# define _LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB +// Fix undefined behavior in how __hash_table stores its pointer types. +# define _LIBCPP_ABI_FIX_UNORDERED_NODE_POINTER_UB +# define _LIBCPP_ABI_FORWARD_LIST_REMOVE_NODE_POINTER_UB +# define _LIBCPP_ABI_FIX_UNORDERED_CONTAINER_SIZE_TYPE +// Override the default return value of exception::what() for bad_function_call::what() +// with a string that is specific to bad_function_call (see http://wg21.link/LWG2233). +// This is an ABI break on platforms that sign and authenticate vtable function pointers +// because it changes the mangling of the virtual function located in the vtable, which +// changes how it gets signed. +# define _LIBCPP_ABI_BAD_FUNCTION_CALL_GOOD_WHAT_MESSAGE +// Enable optimized version of __do_get_(un)signed which avoids redundant copies. +# define _LIBCPP_ABI_OPTIMIZED_LOCALE_NUM_GET +// Give reverse_iterator one data member of type T, not two. +// Also, in C++17 and later, don't derive iterator types from std::iterator. +# define _LIBCPP_ABI_NO_ITERATOR_BASES +// Use the smallest possible integer type to represent the index of the variant. +// Previously libc++ used "unsigned int" exclusively. +# define _LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION +// Unstable attempt to provide a more optimized std::function +# define _LIBCPP_ABI_OPTIMIZED_FUNCTION +// All the regex constants must be distinct and nonzero. +# define _LIBCPP_ABI_REGEX_CONSTANTS_NONZERO +// Re-worked external template instantiations for std::string with a focus on +// performance and fast-path inlining. +# define _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION +// Enable clang::trivial_abi on std::unique_ptr. +# define _LIBCPP_ABI_ENABLE_UNIQUE_PTR_TRIVIAL_ABI +// Enable clang::trivial_abi on std::shared_ptr and std::weak_ptr +# define _LIBCPP_ABI_ENABLE_SHARED_PTR_TRIVIAL_ABI +// std::random_device holds some state when it uses an implementation that gets +// entropy from a file (see _LIBCPP_USING_DEV_RANDOM). When switching from this +// implementation to another one on a platform that has already shipped +// std::random_device, one needs to retain the same object layout to remain ABI +// compatible. This switch removes these workarounds for platforms that don't care +// about ABI compatibility. +# define _LIBCPP_ABI_NO_RANDOM_DEVICE_COMPATIBILITY_LAYOUT +// Don't export the legacy __basic_string_common class and its methods from the built library. +# define _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON +// Don't export the legacy __vector_base_common class and its methods from the built library. +# define _LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON +// According to the Standard, `bitset::operator[] const` returns bool +# define _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL +// Fix the implementation of CityHash used for std::hash. +// This is an ABI break because `std::hash` will return a different result, +// which means that hashing the same object in translation units built against +// different versions of libc++ can return inconsistent results. This is especially +// tricky since std::hash is used in the implementation of unordered containers. +// +// The incorrect implementation of CityHash has the problem that it drops some +// bits on the floor. +# define _LIBCPP_ABI_FIX_CITYHASH_IMPLEMENTATION +// Remove the base 10 implementation of std::to_chars from the dylib. +// The implementation moved to the header, but we still export the symbols from +// the dylib for backwards compatibility. +# define _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10 +// Define std::array/std::string_view iterators to be __wrap_iters instead of raw +// pointers, which prevents people from relying on a non-portable implementation +// detail. This is especially useful because enabling bounded iterators hardening +// requires code not to make these assumptions. +# define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY +# define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW +// Dont' add an inline namespace for `std::filesystem` +# define _LIBCPP_ABI_NO_FILESYSTEM_INLINE_NAMESPACE +// std::basic_ios uses WEOF to indicate that the fill value is +// uninitialized. However, on platforms where the size of char_type is +// equal to or greater than the size of int_type and char_type is unsigned, +// std::char_traits::eq_int_type() cannot distinguish between WEOF +// and WCHAR_MAX. This ABI setting determines whether we should instead track whether the fill +// value has been initialized using a separate boolean, which changes the ABI. +# define _LIBCPP_ABI_IOS_ALLOW_ARBITRARY_FILL_VALUE +// Make a std::pair of trivially copyable types trivially copyable. +// While this technically doesn't change the layout of pair itself, other types may decide to programatically change +// their representation based on whether something is trivially copyable. +# define _LIBCPP_ABI_TRIVIALLY_COPYABLE_PAIR +#elif _LIBCPP_ABI_VERSION == 1 +# if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF)) +// Enable compiling copies of now inline methods into the dylib to support +// applications compiled against older libraries. This is unnecessary with +// COFF dllexport semantics, since dllexport forces a non-inline definition +// of inline functions to be emitted anyway. Our own non-inline copy would +// conflict with the dllexport-emitted copy, so we disable it. For XCOFF, +// the linker will take issue with the symbols in the shared object if the +// weak inline methods get visibility (such as from -fvisibility-inlines-hidden), +// so disable it. +# define _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS +# endif +// Feature macros for disabling pre ABI v1 features. All of these options +// are deprecated. +# if defined(__FreeBSD__) && __FreeBSD__ < 14 +# define _LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR +# endif +#endif + +// We had some bugs where we use [[no_unique_address]] together with construct_at, +// which causes UB as the call on construct_at could write to overlapping subobjects +// +// https://github.com/llvm/llvm-project/issues/70506 +// https://github.com/llvm/llvm-project/issues/70494 +// +// To fix the bug we had to change the ABI of some classes to remove [[no_unique_address]] under certain conditions. +// The macro below is used for all classes whose ABI have changed as part of fixing these bugs. +#define _LIBCPP_ABI_LLVM18_NO_UNIQUE_ADDRESS __attribute__((__abi_tag__("llvm18_nua"))) + +// Changes the iterator type of select containers (see below) to a bounded iterator that keeps track of whether it's +// within the bounds of the original container and asserts it on every dereference. +// +// ABI impact: changes the iterator type of the relevant containers. +// +// Supported containers: +// - `span`; +// - `string_view`. +// #define _LIBCPP_ABI_BOUNDED_ITERATORS + +// Changes the iterator type of `basic_string` to a bounded iterator that keeps track of whether it's within the bounds +// of the original container and asserts it on every dereference and when performing iterator arithmetics. +// +// ABI impact: changes the iterator type of `basic_string` and its specializations, such as `string` and `wstring`. +// #define _LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING + +// Changes the iterator type of `vector` to a bounded iterator that keeps track of whether it's within the bounds of the +// original container and asserts it on every dereference and when performing iterator arithmetics. Note: this doesn't +// yet affect `vector`. +// +// ABI impact: changes the iterator type of `vector` (except `vector`). +// #define _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR + +#if defined(_LIBCPP_COMPILER_CLANG_BASED) +# if defined(__APPLE__) +# if defined(__i386__) || defined(__x86_64__) +// use old string layout on x86_64 and i386 +# elif defined(__arm__) +// use old string layout on arm (which does not include aarch64/arm64), except on watch ABIs +# if defined(__ARM_ARCH_7K__) && __ARM_ARCH_7K__ >= 2 +# define _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT +# endif +# else +# define _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT +# endif +# endif +#endif + +#endif // _LIBCPP___CONFIGURATION_ABI_H diff --git a/libcxx/include/__cxx03/__configuration/availability.h b/libcxx/include/__cxx03/__configuration/availability.h new file mode 100644 index 0000000000000000000000000000000000000000..ab483a07c9c13774185775457f82929301706eb5 --- /dev/null +++ b/libcxx/include/__cxx03/__configuration/availability.h @@ -0,0 +1,400 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONFIGURATION_AVAILABILITY_H +#define _LIBCPP___CONFIGURATION_AVAILABILITY_H + +#include <__configuration/compiler.h> +#include <__configuration/language.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +// Libc++ is shipped by various vendors. In particular, it is used as a system +// library on macOS, iOS and other Apple platforms. In order for users to be +// able to compile a binary that is intended to be deployed to an older version +// of a platform, Clang provides availability attributes [1]. These attributes +// can be placed on declarations and are used to describe the life cycle of a +// symbol in the library. +// +// The main goal is to ensure a compile-time error if a symbol that hasn't been +// introduced in a previously released library is used in a program that targets +// that previously released library. Normally, this would be a load-time error +// when one tries to launch the program against the older library. +// +// For example, the filesystem library was introduced in the dylib in LLVM 9. +// On Apple platforms, this corresponds to macOS 10.15. If a user compiles on +// a macOS 10.15 host but targets macOS 10.13 with their program, the compiler +// would normally not complain (because the required declarations are in the +// headers), but the dynamic loader would fail to find the symbols when actually +// trying to launch the program on macOS 10.13. To turn this into a compile-time +// issue instead, declarations are annotated with when they were introduced, and +// the compiler can produce a diagnostic if the program references something that +// isn't available on the deployment target. +// +// This mechanism is general in nature, and any vendor can add their markup to +// the library (see below). Whenever a new feature is added that requires support +// in the shared library, two macros are added below to allow marking the feature +// as unavailable: +// 1. A macro named `_LIBCPP_AVAILABILITY_HAS_` which must be defined +// to `_LIBCPP_INTRODUCED_IN_` for the appropriate LLVM version. +// 2. A macro named `_LIBCPP_AVAILABILITY_`, which must be defined to +// `_LIBCPP_INTRODUCED_IN__MARKUP` for the appropriate LLVM version. +// +// When vendors decide to ship the feature as part of their shared library, they +// can update the `_LIBCPP_INTRODUCED_IN_` macro (and the markup counterpart) +// based on the platform version they shipped that version of LLVM in. The library +// will then use this markup to provide an optimal user experience on these platforms. +// +// Furthermore, many features in the standard library have corresponding +// feature-test macros. The `_LIBCPP_AVAILABILITY_HAS_` macros +// are checked by the corresponding feature-test macros generated by +// generate_feature_test_macro_components.py to ensure that the library +// doesn't announce a feature as being implemented if it is unavailable on +// the deployment target. +// +// Note that this mechanism is disabled by default in the "upstream" libc++. +// Availability annotations are only meaningful when shipping libc++ inside +// a platform (i.e. as a system library), and so vendors that want them should +// turn those annotations on at CMake configuration time. +// +// [1]: https://clang.llvm.org/docs/AttributeReference.html#availability + +// For backwards compatibility, allow users to define _LIBCPP_DISABLE_AVAILABILITY +// for a while. +#if defined(_LIBCPP_DISABLE_AVAILABILITY) +# if !defined(_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS) +# define _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS +# endif +#endif + +// Availability markup is disabled when building the library, or when a non-Clang +// compiler is used because only Clang supports the necessary attributes. +#if defined(_LIBCPP_BUILDING_LIBRARY) || defined(_LIBCXXABI_BUILDING_LIBRARY) || !defined(_LIBCPP_COMPILER_CLANG_BASED) +# if !defined(_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS) +# define _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS +# endif +#endif + +// When availability annotations are disabled, we take for granted that features introduced +// in all versions of the library are available. +#if defined(_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS) + +# define _LIBCPP_INTRODUCED_IN_LLVM_19 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_18 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_18_ATTRIBUTE /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_17 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_17_ATTRIBUTE /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_16 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_16_ATTRIBUTE /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_15 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_15_ATTRIBUTE /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_14 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_14_ATTRIBUTE /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_13 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_13_ATTRIBUTE /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_12 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_12_ATTRIBUTE /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_11 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_11_ATTRIBUTE /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_10 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_10_ATTRIBUTE /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_9 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_PUSH /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_POP /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_8 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_8_ATTRIBUTE /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_4 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_4_ATTRIBUTE /* nothing */ + +#elif defined(__APPLE__) + +// clang-format off + +// LLVM 19 +// TODO: Fill this in +# define _LIBCPP_INTRODUCED_IN_LLVM_19 0 +# define _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE __attribute__((unavailable)) + +// LLVM 18 +// TODO: Fill this in +# define _LIBCPP_INTRODUCED_IN_LLVM_18 0 +# define _LIBCPP_INTRODUCED_IN_LLVM_18_ATTRIBUTE __attribute__((unavailable)) + +// LLVM 17 +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 140400) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 170400) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 170400) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 100400) +# define _LIBCPP_INTRODUCED_IN_LLVM_17 0 +# else +# define _LIBCPP_INTRODUCED_IN_LLVM_17 1 +# endif +# define _LIBCPP_INTRODUCED_IN_LLVM_17_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 14.4))) \ + __attribute__((availability(ios, strict, introduced = 17.4))) \ + __attribute__((availability(tvos, strict, introduced = 17.4))) \ + __attribute__((availability(watchos, strict, introduced = 10.4))) + +// LLVM 16 +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 140000) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 170000) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 170000) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 100000) +# define _LIBCPP_INTRODUCED_IN_LLVM_16 0 +# else +# define _LIBCPP_INTRODUCED_IN_LLVM_16 1 +# endif +# define _LIBCPP_INTRODUCED_IN_LLVM_16_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 14.0))) \ + __attribute__((availability(ios, strict, introduced = 17.0))) \ + __attribute__((availability(tvos, strict, introduced = 17.0))) \ + __attribute__((availability(watchos, strict, introduced = 10.0))) + +// LLVM 15 +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 130400) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 160500) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 160500) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 90500) +# define _LIBCPP_INTRODUCED_IN_LLVM_15 0 +# else +# define _LIBCPP_INTRODUCED_IN_LLVM_15 1 +# endif +# define _LIBCPP_INTRODUCED_IN_LLVM_15_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 13.4))) \ + __attribute__((availability(ios, strict, introduced = 16.5))) \ + __attribute__((availability(tvos, strict, introduced = 16.5))) \ + __attribute__((availability(watchos, strict, introduced = 9.5))) + +// LLVM 14 +# define _LIBCPP_INTRODUCED_IN_LLVM_14 _LIBCPP_INTRODUCED_IN_LLVM_15 +# define _LIBCPP_INTRODUCED_IN_LLVM_14_ATTRIBUTE _LIBCPP_INTRODUCED_IN_LLVM_15_ATTRIBUTE + +// LLVM 13 +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 130000) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 160000) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 160000) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 90000) +# define _LIBCPP_INTRODUCED_IN_LLVM_13 0 +# else +# define _LIBCPP_INTRODUCED_IN_LLVM_13 1 +# endif +# define _LIBCPP_INTRODUCED_IN_LLVM_13_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 13.0))) \ + __attribute__((availability(ios, strict, introduced = 16.0))) \ + __attribute__((availability(tvos, strict, introduced = 16.0))) \ + __attribute__((availability(watchos, strict, introduced = 9.0))) + +// LLVM 12 +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 120300) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 150300) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 150300) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 80300) +# define _LIBCPP_INTRODUCED_IN_LLVM_12 0 +# else +# define _LIBCPP_INTRODUCED_IN_LLVM_12 1 +# endif +# define _LIBCPP_INTRODUCED_IN_LLVM_12_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 12.3))) \ + __attribute__((availability(ios, strict, introduced = 15.3))) \ + __attribute__((availability(tvos, strict, introduced = 15.3))) \ + __attribute__((availability(watchos, strict, introduced = 8.3))) + +// LLVM 11 +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 110000) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 140000) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 140000) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 70000) +# define _LIBCPP_INTRODUCED_IN_LLVM_11 0 +# else +# define _LIBCPP_INTRODUCED_IN_LLVM_11 1 +# endif +# define _LIBCPP_INTRODUCED_IN_LLVM_11_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 11.0))) \ + __attribute__((availability(ios, strict, introduced = 14.0))) \ + __attribute__((availability(tvos, strict, introduced = 14.0))) \ + __attribute__((availability(watchos, strict, introduced = 7.0))) + +// LLVM 10 +# define _LIBCPP_INTRODUCED_IN_LLVM_10 _LIBCPP_INTRODUCED_IN_LLVM_11 +# define _LIBCPP_INTRODUCED_IN_LLVM_10_ATTRIBUTE _LIBCPP_INTRODUCED_IN_LLVM_11_ATTRIBUTE + +// LLVM 9 +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101500) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 130000) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 130000) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 60000) +# define _LIBCPP_INTRODUCED_IN_LLVM_9 0 +# else +# define _LIBCPP_INTRODUCED_IN_LLVM_9 1 +# endif +# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 10.15))) \ + __attribute__((availability(ios, strict, introduced = 13.0))) \ + __attribute__((availability(tvos, strict, introduced = 13.0))) \ + __attribute__((availability(watchos, strict, introduced = 6.0))) +# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_PUSH \ + _Pragma("clang attribute push(__attribute__((availability(macos,strict,introduced=10.15))), apply_to=any(function,record))") \ + _Pragma("clang attribute push(__attribute__((availability(ios,strict,introduced=13.0))), apply_to=any(function,record))") \ + _Pragma("clang attribute push(__attribute__((availability(tvos,strict,introduced=13.0))), apply_to=any(function,record))") \ + _Pragma("clang attribute push(__attribute__((availability(watchos,strict,introduced=6.0))), apply_to=any(function,record))") +# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_POP \ + _Pragma("clang attribute pop") \ + _Pragma("clang attribute pop") \ + _Pragma("clang attribute pop") \ + _Pragma("clang attribute pop") + +// LLVM 4 +# if defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000 +# define _LIBCPP_INTRODUCED_IN_LLVM_4 0 +# else +# define _LIBCPP_INTRODUCED_IN_LLVM_4 1 +# endif +# define _LIBCPP_INTRODUCED_IN_LLVM_4_ATTRIBUTE __attribute__((availability(watchos, strict, introduced = 5.0))) + +// clang-format on + +#else + +// ...New vendors can add availability markup here... + +# error \ + "It looks like you're trying to enable vendor availability markup, but you haven't defined the corresponding macros yet!" + +#endif + +// These macros control the availability of std::bad_optional_access and +// other exception types. These were put in the shared library to prevent +// code bloat from every user program defining the vtable for these exception +// types. +// +// Note that when exceptions are disabled, the methods that normally throw +// these exceptions can be used even on older deployment targets, but those +// methods will abort instead of throwing. +#define _LIBCPP_AVAILABILITY_HAS_BAD_OPTIONAL_ACCESS _LIBCPP_INTRODUCED_IN_LLVM_4 +#define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS _LIBCPP_INTRODUCED_IN_LLVM_4_ATTRIBUTE + +#define _LIBCPP_AVAILABILITY_HAS_BAD_VARIANT_ACCESS _LIBCPP_INTRODUCED_IN_LLVM_4 +#define _LIBCPP_AVAILABILITY_BAD_VARIANT_ACCESS _LIBCPP_INTRODUCED_IN_LLVM_4_ATTRIBUTE + +#define _LIBCPP_AVAILABILITY_HAS_BAD_ANY_CAST _LIBCPP_INTRODUCED_IN_LLVM_4 +#define _LIBCPP_AVAILABILITY_BAD_ANY_CAST _LIBCPP_INTRODUCED_IN_LLVM_4_ATTRIBUTE + +// These macros control the availability of all parts of that +// depend on something in the dylib. +#define _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY _LIBCPP_INTRODUCED_IN_LLVM_9 +#define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE +#define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_PUSH +#define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_POP + +// This controls the availability of the C++20 synchronization library, +// which requires shared library support for various operations +// (see libcxx/src/atomic.cpp). This includes , , +// , and notification functions on std::atomic. +#define _LIBCPP_AVAILABILITY_HAS_SYNC _LIBCPP_INTRODUCED_IN_LLVM_11 +#define _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INTRODUCED_IN_LLVM_11_ATTRIBUTE + +// Enable additional explicit instantiations of iostreams components. This +// reduces the number of weak definitions generated in programs that use +// iostreams by providing a single strong definition in the shared library. +// +// TODO: Enable additional explicit instantiations on GCC once it supports exclude_from_explicit_instantiation, +// or once libc++ doesn't use the attribute anymore. +// TODO: Enable them on Windows once https://llvm.org/PR41018 has been fixed. +#if !defined(_LIBCPP_COMPILER_GCC) && !defined(_WIN32) +# define _LIBCPP_AVAILABILITY_HAS_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 _LIBCPP_INTRODUCED_IN_LLVM_12 +#else +# define _LIBCPP_AVAILABILITY_HAS_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1 0 +#endif + +// This controls the availability of floating-point std::to_chars functions. +// These overloads were added later than the integer overloads. +#define _LIBCPP_AVAILABILITY_HAS_TO_CHARS_FLOATING_POINT _LIBCPP_INTRODUCED_IN_LLVM_14 +#define _LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT _LIBCPP_INTRODUCED_IN_LLVM_14_ATTRIBUTE + +// This controls whether the library claims to provide a default verbose +// termination function, and consequently whether the headers will try +// to use it when the mechanism isn't overriden at compile-time. +#define _LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT _LIBCPP_INTRODUCED_IN_LLVM_15 +#define _LIBCPP_AVAILABILITY_VERBOSE_ABORT _LIBCPP_INTRODUCED_IN_LLVM_15_ATTRIBUTE + +// This controls the availability of the C++17 std::pmr library, +// which is implemented in large part in the built library. +// +// TODO: Enable std::pmr markup once https://github.com/llvm/llvm-project/issues/40340 has been fixed +// Until then, it is possible for folks to try to use `std::pmr` when back-deploying to targets that don't support +// it and it'll be a load-time error, but we don't have a good alternative because the library won't compile if we +// use availability annotations until that bug has been fixed. +#define _LIBCPP_AVAILABILITY_HAS_PMR _LIBCPP_INTRODUCED_IN_LLVM_16 +#define _LIBCPP_AVAILABILITY_PMR + +// These macros controls the availability of __cxa_init_primary_exception +// in the built library, which std::make_exception_ptr might use +// (see libcxx/include/__exception/exception_ptr.h). +#define _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION _LIBCPP_INTRODUCED_IN_LLVM_18 +#define _LIBCPP_AVAILABILITY_INIT_PRIMARY_EXCEPTION _LIBCPP_INTRODUCED_IN_LLVM_18_ATTRIBUTE + +// This controls the availability of C++23 , which +// has a dependency on the built library (it needs access to +// the underlying buffer types of std::cout, std::cerr, and std::clog. +#define _LIBCPP_AVAILABILITY_HAS_PRINT _LIBCPP_INTRODUCED_IN_LLVM_18 +#define _LIBCPP_AVAILABILITY_PRINT _LIBCPP_INTRODUCED_IN_LLVM_18_ATTRIBUTE + +// This controls the availability of the C++20 time zone database. +// The parser code is built in the library. +#define _LIBCPP_AVAILABILITY_HAS_TZDB _LIBCPP_INTRODUCED_IN_LLVM_19 +#define _LIBCPP_AVAILABILITY_TZDB _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE + +// These macros determine whether we assume that std::bad_function_call and +// std::bad_expected_access provide a key function in the dylib. This allows +// centralizing their vtable and typeinfo instead of having all TUs provide +// a weak definition that then gets deduplicated. +#define _LIBCPP_AVAILABILITY_HAS_BAD_FUNCTION_CALL_KEY_FUNCTION _LIBCPP_INTRODUCED_IN_LLVM_19 +#define _LIBCPP_AVAILABILITY_BAD_FUNCTION_CALL_KEY_FUNCTION _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE +#define _LIBCPP_AVAILABILITY_HAS_BAD_EXPECTED_ACCESS_KEY_FUNCTION _LIBCPP_INTRODUCED_IN_LLVM_19 +#define _LIBCPP_AVAILABILITY_BAD_EXPECTED_ACCESS_KEY_FUNCTION _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE + +// Define availability attributes that depend on _LIBCPP_HAS_NO_EXCEPTIONS. +// Those are defined in terms of the availability attributes above, and +// should not be vendor-specific. +#if defined(_LIBCPP_HAS_NO_EXCEPTIONS) +# define _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST +# define _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS +# define _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS +#else +# define _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST _LIBCPP_AVAILABILITY_BAD_ANY_CAST +# define _LIBCPP_AVAILABILITY_THROW_BAD_OPTIONAL_ACCESS _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS +# define _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_BAD_VARIANT_ACCESS +#endif + +// Define availability attributes that depend on both +// _LIBCPP_HAS_NO_EXCEPTIONS and _LIBCPP_HAS_NO_RTTI. +#if defined(_LIBCPP_HAS_NO_EXCEPTIONS) || defined(_LIBCPP_HAS_NO_RTTI) +# undef _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION +# undef _LIBCPP_AVAILABILITY_INIT_PRIMARY_EXCEPTION +# define _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION 0 +# define _LIBCPP_AVAILABILITY_INIT_PRIMARY_EXCEPTION +#endif + +#endif // _LIBCPP___CONFIGURATION_AVAILABILITY_H diff --git a/libcxx/include/__cxx03/__configuration/compiler.h b/libcxx/include/__cxx03/__configuration/compiler.h new file mode 100644 index 0000000000000000000000000000000000000000..80ece22bb50bd6e738a907e6e9b1b16a18886144 --- /dev/null +++ b/libcxx/include/__cxx03/__configuration/compiler.h @@ -0,0 +1,51 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONFIGURATION_COMPILER_H +#define _LIBCPP___CONFIGURATION_COMPILER_H + +#include <__config_site> + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +# pragma GCC system_header +#endif + +#if defined(__apple_build_version__) +// Given AppleClang XX.Y.Z, _LIBCPP_APPLE_CLANG_VER is XXYZ (e.g. AppleClang 14.0.3 => 1403) +# define _LIBCPP_COMPILER_CLANG_BASED +# define _LIBCPP_APPLE_CLANG_VER (__apple_build_version__ / 10000) +#elif defined(__clang__) +# define _LIBCPP_COMPILER_CLANG_BASED +# define _LIBCPP_CLANG_VER (__clang_major__ * 100 + __clang_minor__) +#elif defined(__GNUC__) +# define _LIBCPP_COMPILER_GCC +# define _LIBCPP_GCC_VER (__GNUC__ * 100 + __GNUC_MINOR__) +#endif + +#ifdef __cplusplus + +// Warn if a compiler version is used that is not supported anymore +// LLVM RELEASE Update the minimum compiler versions +# if defined(_LIBCPP_CLANG_VER) +# if _LIBCPP_CLANG_VER < 1700 +# warning "Libc++ only supports Clang 17 and later" +# endif +# elif defined(_LIBCPP_APPLE_CLANG_VER) +# if _LIBCPP_APPLE_CLANG_VER < 1500 +# warning "Libc++ only supports AppleClang 15 and later" +# endif +# elif defined(_LIBCPP_GCC_VER) +# if _LIBCPP_GCC_VER < 1400 +# warning "Libc++ only supports GCC 14 and later" +# endif +# endif + +#endif + +#endif // _LIBCPP___CONFIGURATION_COMPILER_H diff --git a/libcxx/include/__cxx03/__configuration/language.h b/libcxx/include/__cxx03/__configuration/language.h new file mode 100644 index 0000000000000000000000000000000000000000..fa62a7b6f5c2a1f2cad2e8f1098ac9456700d0a3 --- /dev/null +++ b/libcxx/include/__cxx03/__configuration/language.h @@ -0,0 +1,46 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONFIGURATION_LANGUAGE_H +#define _LIBCPP___CONFIGURATION_LANGUAGE_H + +#include <__config_site> + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +# pragma GCC system_header +#endif + +// NOLINTBEGIN(libcpp-cpp-version-check) +#ifdef __cplusplus +# if __cplusplus <= 201103L +# define _LIBCPP_STD_VER 11 +# elif __cplusplus <= 201402L +# define _LIBCPP_STD_VER 14 +# elif __cplusplus <= 201703L +# define _LIBCPP_STD_VER 17 +# elif __cplusplus <= 202002L +# define _LIBCPP_STD_VER 20 +# elif __cplusplus <= 202302L +# define _LIBCPP_STD_VER 23 +# else +// Expected release year of the next C++ standard +# define _LIBCPP_STD_VER 26 +# endif +#endif // __cplusplus +// NOLINTEND(libcpp-cpp-version-check) + +#if !defined(__cpp_rtti) || __cpp_rtti < 199711L +# define _LIBCPP_HAS_NO_RTTI +#endif + +#if !defined(__cpp_exceptions) || __cpp_exceptions < 199711L +# define _LIBCPP_HAS_NO_EXCEPTIONS +#endif + +#endif // _LIBCPP___CONFIGURATION_LANGUAGE_H diff --git a/libcxx/include/__cxx03/__configuration/platform.h b/libcxx/include/__cxx03/__configuration/platform.h new file mode 100644 index 0000000000000000000000000000000000000000..27f68d04e8a8d9c843d700cb23974aa4b1e5ae37 --- /dev/null +++ b/libcxx/include/__cxx03/__configuration/platform.h @@ -0,0 +1,54 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CONFIGURATION_PLATFORM_H +#define _LIBCPP___CONFIGURATION_PLATFORM_H + +#include <__config_site> + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +# pragma GCC system_header +#endif + +#if defined(__ELF__) +# define _LIBCPP_OBJECT_FORMAT_ELF 1 +#elif defined(__MACH__) +# define _LIBCPP_OBJECT_FORMAT_MACHO 1 +#elif defined(_WIN32) +# define _LIBCPP_OBJECT_FORMAT_COFF 1 +#elif defined(__wasm__) +# define _LIBCPP_OBJECT_FORMAT_WASM 1 +#elif defined(_AIX) +# define _LIBCPP_OBJECT_FORMAT_XCOFF 1 +#else +// ... add new file formats here ... +#endif + +// Need to detect which libc we're using if we're on Linux. +#if defined(__linux__) +# include +# if defined(__GLIBC_PREREQ) +# define _LIBCPP_GLIBC_PREREQ(a, b) __GLIBC_PREREQ(a, b) +# else +# define _LIBCPP_GLIBC_PREREQ(a, b) 0 +# endif // defined(__GLIBC_PREREQ) +#endif // defined(__linux__) + +#ifndef __BYTE_ORDER__ +# error \ + "Your compiler doesn't seem to define __BYTE_ORDER__, which is required by libc++ to know the endianness of your target platform" +#endif + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define _LIBCPP_LITTLE_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define _LIBCPP_BIG_ENDIAN +#endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + +#endif // _LIBCPP___CONFIGURATION_PLATFORM_H diff --git a/libcxx/include/__cxx03/__coroutine/coroutine_handle.h b/libcxx/include/__cxx03/__coroutine/coroutine_handle.h new file mode 100644 index 0000000000000000000000000000000000000000..4557a6643c2393b844b42c9a1060349b9a2cffc2 --- /dev/null +++ b/libcxx/include/__cxx03/__coroutine/coroutine_handle.h @@ -0,0 +1,176 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COROUTINE_COROUTINE_HANDLE_H +#define _LIBCPP___COROUTINE_COROUTINE_HANDLE_H + +#include <__assert> +#include <__config> +#include <__functional/hash.h> +#include <__memory/addressof.h> +#include <__type_traits/remove_cv.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +// [coroutine.handle] +template +struct _LIBCPP_TEMPLATE_VIS coroutine_handle; + +template <> +struct _LIBCPP_TEMPLATE_VIS coroutine_handle { +public: + // [coroutine.handle.con], construct/reset + constexpr coroutine_handle() noexcept = default; + + _LIBCPP_HIDE_FROM_ABI constexpr coroutine_handle(nullptr_t) noexcept {} + + _LIBCPP_HIDE_FROM_ABI coroutine_handle& operator=(nullptr_t) noexcept { + __handle_ = nullptr; + return *this; + } + + // [coroutine.handle.export.import], export/import + _LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; } + + _LIBCPP_HIDE_FROM_ABI static constexpr coroutine_handle from_address(void* __addr) noexcept { + coroutine_handle __tmp; + __tmp.__handle_ = __addr; + return __tmp; + } + + // [coroutine.handle.observers], observers + _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __handle_ != nullptr; } + + _LIBCPP_HIDE_FROM_ABI bool done() const { + _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(__is_suspended(), "done() can be called only on suspended coroutines"); + return __builtin_coro_done(__handle_); + } + + // [coroutine.handle.resumption], resumption + _LIBCPP_HIDE_FROM_ABI void operator()() const { resume(); } + + _LIBCPP_HIDE_FROM_ABI void resume() const { + _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(__is_suspended(), "resume() can be called only on suspended coroutines"); + _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(!done(), "resume() has undefined behavior when the coroutine is done"); + __builtin_coro_resume(__handle_); + } + + _LIBCPP_HIDE_FROM_ABI void destroy() const { + _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(__is_suspended(), "destroy() can be called only on suspended coroutines"); + __builtin_coro_destroy(__handle_); + } + +private: + _LIBCPP_HIDE_FROM_ABI bool __is_suspended() const { + // FIXME actually implement a check for if the coro is suspended. + return __handle_ != nullptr; + } + + void* __handle_ = nullptr; +}; + +// [coroutine.handle.compare] +inline _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { + return __x.address() == __y.address(); +} +inline _LIBCPP_HIDE_FROM_ABI constexpr strong_ordering +operator<=>(coroutine_handle<> __x, coroutine_handle<> __y) noexcept { + return compare_three_way()(__x.address(), __y.address()); +} + +template +struct _LIBCPP_TEMPLATE_VIS coroutine_handle { +public: + // [coroutine.handle.con], construct/reset + constexpr coroutine_handle() noexcept = default; + + _LIBCPP_HIDE_FROM_ABI constexpr coroutine_handle(nullptr_t) noexcept {} + + _LIBCPP_HIDE_FROM_ABI static coroutine_handle from_promise(_Promise& __promise) { + using _RawPromise = __remove_cv_t<_Promise>; + coroutine_handle __tmp; + __tmp.__handle_ = + __builtin_coro_promise(std::addressof(const_cast<_RawPromise&>(__promise)), alignof(_Promise), true); + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI coroutine_handle& operator=(nullptr_t) noexcept { + __handle_ = nullptr; + return *this; + } + + // [coroutine.handle.export.import], export/import + _LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; } + + _LIBCPP_HIDE_FROM_ABI static constexpr coroutine_handle from_address(void* __addr) noexcept { + coroutine_handle __tmp; + __tmp.__handle_ = __addr; + return __tmp; + } + + // [coroutine.handle.conv], conversion + _LIBCPP_HIDE_FROM_ABI constexpr operator coroutine_handle<>() const noexcept { + return coroutine_handle<>::from_address(address()); + } + + // [coroutine.handle.observers], observers + _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __handle_ != nullptr; } + + _LIBCPP_HIDE_FROM_ABI bool done() const { + _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(__is_suspended(), "done() can be called only on suspended coroutines"); + return __builtin_coro_done(__handle_); + } + + // [coroutine.handle.resumption], resumption + _LIBCPP_HIDE_FROM_ABI void operator()() const { resume(); } + + _LIBCPP_HIDE_FROM_ABI void resume() const { + _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(__is_suspended(), "resume() can be called only on suspended coroutines"); + _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(!done(), "resume() has undefined behavior when the coroutine is done"); + __builtin_coro_resume(__handle_); + } + + _LIBCPP_HIDE_FROM_ABI void destroy() const { + _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(__is_suspended(), "destroy() can be called only on suspended coroutines"); + __builtin_coro_destroy(__handle_); + } + + // [coroutine.handle.promise], promise access + _LIBCPP_HIDE_FROM_ABI _Promise& promise() const { + return *static_cast<_Promise*>(__builtin_coro_promise(this->__handle_, alignof(_Promise), false)); + } + +private: + _LIBCPP_HIDE_FROM_ABI bool __is_suspended() const { + // FIXME actually implement a check for if the coro is suspended. + return __handle_ != nullptr; + } + void* __handle_ = nullptr; +}; + +// [coroutine.handle.hash] +template +struct hash> { + _LIBCPP_HIDE_FROM_ABI size_t operator()(const coroutine_handle<_Tp>& __v) const noexcept { + return hash()(__v.address()); + } +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // __LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___COROUTINE_COROUTINE_HANDLE_H diff --git a/libcxx/include/__cxx03/__coroutine/coroutine_traits.h b/libcxx/include/__cxx03/__coroutine/coroutine_traits.h new file mode 100644 index 0000000000000000000000000000000000000000..78f05341f7486af5b7aa911b52e517033ba37359 --- /dev/null +++ b/libcxx/include/__cxx03/__coroutine/coroutine_traits.h @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COROUTINE_COROUTINE_TRAITS_H +#define _LIBCPP___COROUTINE_COROUTINE_TRAITS_H + +#include <__config> +#include <__type_traits/void_t.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +// [coroutine.traits] +// [coroutine.traits.primary] +// The header defined the primary template coroutine_traits such that +// if ArgTypes is a parameter pack of types and if the qualified-id R::promise_type +// is valid and denotes a type ([temp.deduct]), then coroutine_traits +// has the following publicly accessible memebr: +// +// using promise_type = typename R::promise_type; +// +// Otherwise, coroutine_traits has no members. +template +struct __coroutine_traits_sfinae {}; + +template +struct __coroutine_traits_sfinae< _Tp, __void_t > { + using promise_type = typename _Tp::promise_type; +}; + +template +struct coroutine_traits : public __coroutine_traits_sfinae<_Ret> {}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // __LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___COROUTINE_COROUTINE_TRAITS_H diff --git a/libcxx/include/__cxx03/__coroutine/noop_coroutine_handle.h b/libcxx/include/__cxx03/__coroutine/noop_coroutine_handle.h new file mode 100644 index 0000000000000000000000000000000000000000..da13d579604b55ca33d040617adfb09cab863681 --- /dev/null +++ b/libcxx/include/__cxx03/__coroutine/noop_coroutine_handle.h @@ -0,0 +1,99 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COROUTINE_NOOP_COROUTINE_HANDLE_H +#define _LIBCPP___COROUTINE_NOOP_COROUTINE_HANDLE_H + +#include <__config> +#include <__coroutine/coroutine_handle.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +# if __has_builtin(__builtin_coro_noop) || defined(_LIBCPP_COMPILER_GCC) + +// [coroutine.noop] +// [coroutine.promise.noop] +struct noop_coroutine_promise {}; + +// [coroutine.handle.noop] +template <> +struct _LIBCPP_TEMPLATE_VIS coroutine_handle { +public: + // [coroutine.handle.noop.conv], conversion + _LIBCPP_HIDE_FROM_ABI constexpr operator coroutine_handle<>() const noexcept { + return coroutine_handle<>::from_address(address()); + } + + // [coroutine.handle.noop.observers], observers + _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI constexpr bool done() const noexcept { return false; } + + // [coroutine.handle.noop.resumption], resumption + _LIBCPP_HIDE_FROM_ABI constexpr void operator()() const noexcept {} + _LIBCPP_HIDE_FROM_ABI constexpr void resume() const noexcept {} + _LIBCPP_HIDE_FROM_ABI constexpr void destroy() const noexcept {} + + // [coroutine.handle.noop.promise], promise access + _LIBCPP_HIDE_FROM_ABI noop_coroutine_promise& promise() const noexcept { + return *static_cast( + __builtin_coro_promise(this->__handle_, alignof(noop_coroutine_promise), false)); + } + + // [coroutine.handle.noop.address], address + _LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; } + +private: + _LIBCPP_HIDE_FROM_ABI friend coroutine_handle noop_coroutine() noexcept; + +# if __has_builtin(__builtin_coro_noop) + _LIBCPP_HIDE_FROM_ABI coroutine_handle() noexcept { this->__handle_ = __builtin_coro_noop(); } + + void* __handle_ = nullptr; + +# elif defined(_LIBCPP_COMPILER_GCC) + // GCC doesn't implement __builtin_coro_noop(). + // Construct the coroutine frame manually instead. + struct __noop_coroutine_frame_ty_ { + static void __dummy_resume_destroy_func() {} + + void (*__resume_)() = __dummy_resume_destroy_func; + void (*__destroy_)() = __dummy_resume_destroy_func; + struct noop_coroutine_promise __promise_; + }; + + static __noop_coroutine_frame_ty_ __noop_coroutine_frame_; + + void* __handle_ = &__noop_coroutine_frame_; + + _LIBCPP_HIDE_FROM_ABI coroutine_handle() noexcept = default; + +# endif // __has_builtin(__builtin_coro_noop) +}; + +using noop_coroutine_handle = coroutine_handle; + +# if defined(_LIBCPP_COMPILER_GCC) +inline noop_coroutine_handle::__noop_coroutine_frame_ty_ noop_coroutine_handle::__noop_coroutine_frame_{}; +# endif + +// [coroutine.noop.coroutine] +inline _LIBCPP_HIDE_FROM_ABI noop_coroutine_handle noop_coroutine() noexcept { return noop_coroutine_handle(); } + +# endif // __has_builtin(__builtin_coro_noop) || defined(_LIBCPP_COMPILER_GCC) + +_LIBCPP_END_NAMESPACE_STD + +#endif // __LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___COROUTINE_NOOP_COROUTINE_HANDLE_H diff --git a/libcxx/include/__cxx03/__coroutine/trivial_awaitables.h b/libcxx/include/__cxx03/__coroutine/trivial_awaitables.h new file mode 100644 index 0000000000000000000000000000000000000000..b604bd3c2d8ad2bc38fc8a76fc12d2b08379dc37 --- /dev/null +++ b/libcxx/include/__cxx03/__coroutine/trivial_awaitables.h @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef __LIBCPP___COROUTINE_TRIVIAL_AWAITABLES_H +#define __LIBCPP___COROUTINE_TRIVIAL_AWAITABLES_H + +#include <__config> +#include <__coroutine/coroutine_handle.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +// [coroutine.trivial.awaitables] +struct suspend_never { + _LIBCPP_HIDE_FROM_ABI constexpr bool await_ready() const noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI constexpr void await_suspend(coroutine_handle<>) const noexcept {} + _LIBCPP_HIDE_FROM_ABI constexpr void await_resume() const noexcept {} +}; + +struct suspend_always { + _LIBCPP_HIDE_FROM_ABI constexpr bool await_ready() const noexcept { return false; } + _LIBCPP_HIDE_FROM_ABI constexpr void await_suspend(coroutine_handle<>) const noexcept {} + _LIBCPP_HIDE_FROM_ABI constexpr void await_resume() const noexcept {} +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // __LIBCPP_STD_VER >= 20 + +#endif // __LIBCPP___COROUTINE_TRIVIAL_AWAITABLES_H diff --git a/libcxx/include/__cxx03/__debug_utils/randomize_range.h b/libcxx/include/__cxx03/__debug_utils/randomize_range.h new file mode 100644 index 0000000000000000000000000000000000000000..7eb77d81ab2a3db2866c4916c39c3eb1e95c7b5f --- /dev/null +++ b/libcxx/include/__cxx03/__debug_utils/randomize_range.h @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___LIBCXX_DEBUG_RANDOMIZE_RANGE_H +#define _LIBCPP___LIBCXX_DEBUG_RANDOMIZE_RANGE_H + +#include <__config> + +#ifdef _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY +# include <__algorithm/shuffle.h> +# include <__type_traits/is_constant_evaluated.h> +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __debug_randomize_range(_Iterator __first, _Sentinel __last) { +#ifdef _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY +# ifdef _LIBCPP_CXX03_LANG +# error Support for unspecified stability is only for C++11 and higher +# endif + + if (!__libcpp_is_constant_evaluated()) + std::__shuffle<_AlgPolicy>(__first, __last, __libcpp_debug_randomizer()); +#else + (void)__first; + (void)__last; +#endif +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___LIBCXX_DEBUG_RANDOMIZE_RANGE_H diff --git a/libcxx/include/__cxx03/__debug_utils/sanitizers.h b/libcxx/include/__cxx03/__debug_utils/sanitizers.h new file mode 100644 index 0000000000000000000000000000000000000000..d8547e32493303accd703d90aafbf2d1c8cce0dd --- /dev/null +++ b/libcxx/include/__cxx03/__debug_utils/sanitizers.h @@ -0,0 +1,104 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___LIBCXX_DEBUG_UTILS_SANITIZERS_H +#define _LIBCPP___LIBCXX_DEBUG_UTILS_SANITIZERS_H + +#include <__config> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_constant_evaluated.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#ifndef _LIBCPP_HAS_NO_ASAN + +extern "C" { +_LIBCPP_EXPORTED_FROM_ABI void +__sanitizer_annotate_contiguous_container(const void*, const void*, const void*, const void*); +_LIBCPP_EXPORTED_FROM_ABI void __sanitizer_annotate_double_ended_contiguous_container( + const void*, const void*, const void*, const void*, const void*, const void*); +_LIBCPP_EXPORTED_FROM_ABI int +__sanitizer_verify_double_ended_contiguous_container(const void*, const void*, const void*, const void*); +} + +#endif // _LIBCPP_HAS_NO_ASAN + +_LIBCPP_BEGIN_NAMESPACE_STD + +// ASan choices +#ifndef _LIBCPP_HAS_NO_ASAN +# define _LIBCPP_HAS_ASAN_CONTAINER_ANNOTATIONS_FOR_ALL_ALLOCATORS 1 +#endif + +#ifdef _LIBCPP_HAS_ASAN_CONTAINER_ANNOTATIONS_FOR_ALL_ALLOCATORS +// __asan_annotate_container_with_allocator determines whether containers with custom allocators are annotated. This is +// a public customization point to disable annotations if the custom allocator assumes that the memory isn't poisoned. +// See the https://libcxx.llvm.org/UsingLibcxx.html#turning-off-asan-annotation-in-containers for more information. +template +struct __asan_annotate_container_with_allocator : true_type {}; +#endif + +// Annotate a double-ended contiguous range. +// - [__first_storage, __last_storage) is the allocated memory region, +// - [__first_old_contained, __last_old_contained) is the previously allowed (unpoisoned) range, and +// - [__first_new_contained, __last_new_contained) is the new allowed (unpoisoned) range. +template +_LIBCPP_HIDE_FROM_ABI void __annotate_double_ended_contiguous_container( + const void* __first_storage, + const void* __last_storage, + const void* __first_old_contained, + const void* __last_old_contained, + const void* __first_new_contained, + const void* __last_new_contained) { +#ifdef _LIBCPP_HAS_NO_ASAN + (void)__first_storage; + (void)__last_storage; + (void)__first_old_contained; + (void)__last_old_contained; + (void)__first_new_contained; + (void)__last_new_contained; +#else + if (__asan_annotate_container_with_allocator<_Allocator>::value && __first_storage != nullptr) + __sanitizer_annotate_double_ended_contiguous_container( + __first_storage, + __last_storage, + __first_old_contained, + __last_old_contained, + __first_new_contained, + __last_new_contained); +#endif +} + +// Annotate a contiguous range. +// [__first_storage, __last_storage) is the allocated memory region, +// __old_last_contained is the previously last allowed (unpoisoned) element, and +// __new_last_contained is the new last allowed (unpoisoned) element. +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __annotate_contiguous_container( + const void* __first_storage, + const void* __last_storage, + const void* __old_last_contained, + const void* __new_last_contained) { +#ifdef _LIBCPP_HAS_NO_ASAN + (void)__first_storage; + (void)__last_storage; + (void)__old_last_contained; + (void)__new_last_contained; +#else + if (!__libcpp_is_constant_evaluated() && __asan_annotate_container_with_allocator<_Allocator>::value && + __first_storage != nullptr) + __sanitizer_annotate_contiguous_container( + __first_storage, __last_storage, __old_last_contained, __new_last_contained); +#endif +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___LIBCXX_DEBUG_UTILS_SANITIZERS_H diff --git a/libcxx/include/__cxx03/__debug_utils/strict_weak_ordering_check.h b/libcxx/include/__cxx03/__debug_utils/strict_weak_ordering_check.h new file mode 100644 index 0000000000000000000000000000000000000000..3a9d887284164d9bb7a55424844a00fd2a43a6ba --- /dev/null +++ b/libcxx/include/__cxx03/__debug_utils/strict_weak_ordering_check.h @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___LIBCXX_DEBUG_STRICT_WEAK_ORDERING_CHECK +#define _LIBCPP___LIBCXX_DEBUG_STRICT_WEAK_ORDERING_CHECK + +#include <__config> + +#include <__algorithm/comp_ref_type.h> +#include <__algorithm/is_sorted.h> +#include <__assert> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_constant_evaluated.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void +__check_strict_weak_ordering_sorted(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp& __comp) { +#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG + using __diff_t = __iter_diff_t<_RandomAccessIterator>; + using _Comp_ref = __comp_ref_type<_Comp>; + if (!__libcpp_is_constant_evaluated()) { + // Check if the range is actually sorted. + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + (std::is_sorted<_RandomAccessIterator, _Comp_ref>(__first, __last, _Comp_ref(__comp))), + "The range is not sorted after the sort, your comparator is not a valid strict-weak ordering"); + // Limit the number of elements we need to check. + __diff_t __size = __last - __first > __diff_t(100) ? __diff_t(100) : __last - __first; + __diff_t __p = 0; + while (__p < __size) { + __diff_t __q = __p + __diff_t(1); + // Find first element that is greater than *(__first+__p). + while (__q < __size && !__comp(*(__first + __p), *(__first + __q))) { + ++__q; + } + // Check that the elements from __p to __q are equal between each other. + for (__diff_t __b = __p; __b < __q; ++__b) { + for (__diff_t __a = __p; __a <= __b; ++__a) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + !__comp(*(__first + __a), *(__first + __b)), "Your comparator is not a valid strict-weak ordering"); + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + !__comp(*(__first + __b), *(__first + __a)), "Your comparator is not a valid strict-weak ordering"); + } + } + // Check that elements between __p and __q are less than between __q and __size. + for (__diff_t __a = __p; __a < __q; ++__a) { + for (__diff_t __b = __q; __b < __size; ++__b) { + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + __comp(*(__first + __a), *(__first + __b)), "Your comparator is not a valid strict-weak ordering"); + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( + !__comp(*(__first + __b), *(__first + __a)), "Your comparator is not a valid strict-weak ordering"); + } + } + // Skip these equal elements. + __p = __q; + } + } +#else + (void)__first; + (void)__last; + (void)__comp; +#endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___LIBCXX_DEBUG_STRICT_WEAK_ORDERING_CHECK diff --git a/libcxx/include/__cxx03/__exception/exception.h b/libcxx/include/__cxx03/__exception/exception.h new file mode 100644 index 0000000000000000000000000000000000000000..e724e1b99bd14e72440fe36db40b5c523bf1ee27 --- /dev/null +++ b/libcxx/include/__cxx03/__exception/exception.h @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___EXCEPTION_EXCEPTION_H +#define _LIBCPP___EXCEPTION_EXCEPTION_H + +#include <__config> + +// defines its own std::exception and std::bad_exception types, +// which we use in order to be ABI-compatible with other STLs on Windows. +#if defined(_LIBCPP_ABI_VCRUNTIME) +# include +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +namespace std { // purposefully not using versioning namespace + +#if defined(_LIBCPP_ABI_VCRUNTIME) && (!defined(_HAS_EXCEPTIONS) || _HAS_EXCEPTIONS != 0) +// The std::exception class was already included above, but we're explicit about this condition here for clarity. + +#elif defined(_LIBCPP_ABI_VCRUNTIME) && _HAS_EXCEPTIONS == 0 +// However, does not define std::exception and std::bad_exception +// when _HAS_EXCEPTIONS == 0. +// +// Since libc++ still wants to provide the std::exception hierarchy even when _HAS_EXCEPTIONS == 0 +// (after all those are simply types like any other), we define an ABI-compatible version +// of the VCRuntime std::exception and std::bad_exception types in that mode. + +struct __std_exception_data { + char const* _What; + bool _DoFree; +}; + +class exception { // base of all library exceptions +public: + exception() _NOEXCEPT : __data_() {} + + explicit exception(char const* __message) _NOEXCEPT : __data_() { + __data_._What = __message; + __data_._DoFree = true; + } + + exception(exception const&) _NOEXCEPT {} + + exception& operator=(exception const&) _NOEXCEPT { return *this; } + + virtual ~exception() _NOEXCEPT {} + + virtual char const* what() const _NOEXCEPT { return __data_._What ? __data_._What : "Unknown exception"; } + +private: + __std_exception_data __data_; +}; + +class bad_exception : public exception { +public: + bad_exception() _NOEXCEPT : exception("bad exception") {} +}; + +#else // !defined(_LIBCPP_ABI_VCRUNTIME) +// On all other platforms, we define our own std::exception and std::bad_exception types +// regardless of whether exceptions are turned on as a language feature. + +class _LIBCPP_EXPORTED_FROM_ABI exception { +public: + _LIBCPP_HIDE_FROM_ABI exception() _NOEXCEPT {} + _LIBCPP_HIDE_FROM_ABI exception(const exception&) _NOEXCEPT = default; + _LIBCPP_HIDE_FROM_ABI exception& operator=(const exception&) _NOEXCEPT = default; + + virtual ~exception() _NOEXCEPT; + virtual const char* what() const _NOEXCEPT; +}; + +class _LIBCPP_EXPORTED_FROM_ABI bad_exception : public exception { +public: + _LIBCPP_HIDE_FROM_ABI bad_exception() _NOEXCEPT {} + _LIBCPP_HIDE_FROM_ABI bad_exception(const bad_exception&) _NOEXCEPT = default; + _LIBCPP_HIDE_FROM_ABI bad_exception& operator=(const bad_exception&) _NOEXCEPT = default; + ~bad_exception() _NOEXCEPT override; + const char* what() const _NOEXCEPT override; +}; +#endif // !_LIBCPP_ABI_VCRUNTIME + +} // namespace std + +#endif // _LIBCPP___EXCEPTION_EXCEPTION_H diff --git a/libcxx/include/__cxx03/__exception/exception_ptr.h b/libcxx/include/__cxx03/__exception/exception_ptr.h new file mode 100644 index 0000000000000000000000000000000000000000..beadd9212abd10890b234d915732edabe88581f8 --- /dev/null +++ b/libcxx/include/__cxx03/__exception/exception_ptr.h @@ -0,0 +1,177 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___EXCEPTION_EXCEPTION_PTR_H +#define _LIBCPP___EXCEPTION_EXCEPTION_PTR_H + +#include <__config> +#include <__exception/operations.h> +#include <__memory/addressof.h> +#include <__memory/construct_at.h> +#include <__type_traits/decay.h> +#include +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#ifndef _LIBCPP_ABI_MICROSOFT + +# if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION + +namespace __cxxabiv1 { + +extern "C" { +_LIBCPP_OVERRIDABLE_FUNC_VIS void* __cxa_allocate_exception(size_t) throw(); +_LIBCPP_OVERRIDABLE_FUNC_VIS void __cxa_free_exception(void*) throw(); + +struct __cxa_exception; +_LIBCPP_OVERRIDABLE_FUNC_VIS __cxa_exception* __cxa_init_primary_exception( + void*, + std::type_info*, +# if defined(_WIN32) + void(__thiscall*)(void*)) throw(); +# elif defined(__wasm__) + // In Wasm, a destructor returns its argument + void* (*)(void*)) throw(); +# else + void (*)(void*)) throw(); +# endif +} + +} // namespace __cxxabiv1 + +# endif + +#endif + +namespace std { // purposefully not using versioning namespace + +#ifndef _LIBCPP_ABI_MICROSOFT + +class _LIBCPP_EXPORTED_FROM_ABI exception_ptr { + void* __ptr_; + + static exception_ptr __from_native_exception_pointer(void*) _NOEXCEPT; + + template + friend _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep) _NOEXCEPT; + +public: + // exception_ptr is basically a COW string. + using __trivially_relocatable = exception_ptr; + + _LIBCPP_HIDE_FROM_ABI exception_ptr() _NOEXCEPT : __ptr_() {} + _LIBCPP_HIDE_FROM_ABI exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {} + + exception_ptr(const exception_ptr&) _NOEXCEPT; + exception_ptr& operator=(const exception_ptr&) _NOEXCEPT; + ~exception_ptr() _NOEXCEPT; + + _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __ptr_ != nullptr; } + + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT { + return __x.__ptr_ == __y.__ptr_; + } + + friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT { + return !(__x == __y); + } + + friend _LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT; + friend _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr); +}; + +template +_LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT { +# ifndef _LIBCPP_HAS_NO_EXCEPTIONS +# if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION && __cplusplus >= 201103L + using _Ep2 = __decay_t<_Ep>; + + void* __ex = __cxxabiv1::__cxa_allocate_exception(sizeof(_Ep)); +# ifdef __wasm__ + // In Wasm, a destructor returns its argument + (void)__cxxabiv1::__cxa_init_primary_exception( + __ex, const_cast(&typeid(_Ep)), [](void* __p) -> void* { +# else + (void)__cxxabiv1::__cxa_init_primary_exception(__ex, const_cast(&typeid(_Ep)), [](void* __p) { +# endif + std::__destroy_at(static_cast<_Ep2*>(__p)); +# ifdef __wasm__ + return __p; +# endif + }); + + try { + ::new (__ex) _Ep2(__e); + return exception_ptr::__from_native_exception_pointer(__ex); + } catch (...) { + __cxxabiv1::__cxa_free_exception(__ex); + return current_exception(); + } +# else + try { + throw __e; + } catch (...) { + return current_exception(); + } +# endif +# else + ((void)__e); + std::abort(); +# endif +} + +#else // _LIBCPP_ABI_MICROSOFT + +class _LIBCPP_EXPORTED_FROM_ABI exception_ptr { + _LIBCPP_DIAGNOSTIC_PUSH + _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-private-field") + void* __ptr1_; + void* __ptr2_; + _LIBCPP_DIAGNOSTIC_POP + +public: + exception_ptr() _NOEXCEPT; + exception_ptr(nullptr_t) _NOEXCEPT; + exception_ptr(const exception_ptr& __other) _NOEXCEPT; + exception_ptr& operator=(const exception_ptr& __other) _NOEXCEPT; + exception_ptr& operator=(nullptr_t) _NOEXCEPT; + ~exception_ptr() _NOEXCEPT; + explicit operator bool() const _NOEXCEPT; +}; + +_LIBCPP_EXPORTED_FROM_ABI bool operator==(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT; + +inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const exception_ptr& __x, const exception_ptr& __y) _NOEXCEPT { + return !(__x == __y); +} + +_LIBCPP_EXPORTED_FROM_ABI void swap(exception_ptr&, exception_ptr&) _NOEXCEPT; + +_LIBCPP_EXPORTED_FROM_ABI exception_ptr __copy_exception_ptr(void* __except, const void* __ptr); +_LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT; +_LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr); + +// This is a built-in template function which automagically extracts the required +// information. +template +void* __GetExceptionInfo(_E); + +template +_LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT { + return __copy_exception_ptr(std::addressof(__e), __GetExceptionInfo(__e)); +} + +#endif // _LIBCPP_ABI_MICROSOFT +} // namespace std + +#endif // _LIBCPP___EXCEPTION_EXCEPTION_PTR_H diff --git a/libcxx/include/__cxx03/__exception/nested_exception.h b/libcxx/include/__cxx03/__exception/nested_exception.h new file mode 100644 index 0000000000000000000000000000000000000000..feb489f87f62f54dc842d03b9edbb1ad566b9e3a --- /dev/null +++ b/libcxx/include/__cxx03/__exception/nested_exception.h @@ -0,0 +1,99 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___EXCEPTION_NESTED_EXCEPTION_H +#define _LIBCPP___EXCEPTION_NESTED_EXCEPTION_H + +#include <__config> +#include <__exception/exception_ptr.h> +#include <__memory/addressof.h> +#include <__type_traits/decay.h> +#include <__type_traits/is_base_of.h> +#include <__type_traits/is_class.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_final.h> +#include <__type_traits/is_polymorphic.h> +#include <__utility/forward.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +namespace std { // purposefully not using versioning namespace + +class _LIBCPP_EXPORTED_FROM_ABI nested_exception { + exception_ptr __ptr_; + +public: + nested_exception() _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI nested_exception(const nested_exception&) _NOEXCEPT = default; + _LIBCPP_HIDE_FROM_ABI nested_exception& operator=(const nested_exception&) _NOEXCEPT = default; + virtual ~nested_exception() _NOEXCEPT; + + // access functions + _LIBCPP_NORETURN void rethrow_nested() const; + _LIBCPP_HIDE_FROM_ABI exception_ptr nested_ptr() const _NOEXCEPT { return __ptr_; } +}; + +template +struct __nested : public _Tp, public nested_exception { + _LIBCPP_HIDE_FROM_ABI explicit __nested(const _Tp& __t) : _Tp(__t) {} +}; + +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS +template +struct __throw_with_nested; + +template +struct __throw_with_nested<_Tp, _Up, true> { + _LIBCPP_NORETURN static inline _LIBCPP_HIDE_FROM_ABI void __do_throw(_Tp&& __t) { + throw __nested<_Up>(std::forward<_Tp>(__t)); + } +}; + +template +struct __throw_with_nested<_Tp, _Up, false> { + _LIBCPP_NORETURN static inline _LIBCPP_HIDE_FROM_ABI void __do_throw(_Tp&& __t) { throw std::forward<_Tp>(__t); } +}; +#endif + +template +_LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI void throw_with_nested(_Tp&& __t) { +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + using _Up = __decay_t<_Tp>; + static_assert(is_copy_constructible<_Up>::value, "type thrown must be CopyConstructible"); + __throw_with_nested<_Tp, + _Up, + is_class<_Up>::value && !is_base_of::value && + !__libcpp_is_final<_Up>::value>::__do_throw(std::forward<_Tp>(__t)); +#else + ((void)__t); + // FIXME: Make this abort +#endif +} + +template +struct __can_dynamic_cast + : _BoolConstant< is_polymorphic<_From>::value && + (!is_base_of<_To, _From>::value || is_convertible::value)> {}; + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI void rethrow_if_nested(const _Ep& __e) { + const nested_exception* __nep = dynamic_cast(std::addressof(__e)); + if (__nep) + __nep->rethrow_nested(); +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI void rethrow_if_nested(const _Ep&) {} + +} // namespace std + +#endif // _LIBCPP___EXCEPTION_NESTED_EXCEPTION_H diff --git a/libcxx/include/__cxx03/__exception/operations.h b/libcxx/include/__cxx03/__exception/operations.h new file mode 100644 index 0000000000000000000000000000000000000000..0a9c7a7c7f0d88784b7b414683c4b68fbb3a986d --- /dev/null +++ b/libcxx/include/__cxx03/__exception/operations.h @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___EXCEPTION_OPERATIONS_H +#define _LIBCPP___EXCEPTION_OPERATIONS_H + +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +namespace std { // purposefully not using versioning namespace +#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS) || \ + defined(_LIBCPP_BUILDING_LIBRARY) +using unexpected_handler = void (*)(); +_LIBCPP_EXPORTED_FROM_ABI unexpected_handler set_unexpected(unexpected_handler) _NOEXCEPT; +_LIBCPP_EXPORTED_FROM_ABI unexpected_handler get_unexpected() _NOEXCEPT; +_LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void unexpected(); +#endif + +using terminate_handler = void (*)(); +_LIBCPP_EXPORTED_FROM_ABI terminate_handler set_terminate(terminate_handler) _NOEXCEPT; +_LIBCPP_EXPORTED_FROM_ABI terminate_handler get_terminate() _NOEXCEPT; + +_LIBCPP_EXPORTED_FROM_ABI bool uncaught_exception() _NOEXCEPT; +_LIBCPP_EXPORTED_FROM_ABI int uncaught_exceptions() _NOEXCEPT; + +class _LIBCPP_EXPORTED_FROM_ABI exception_ptr; + +_LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT; +_LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr); +} // namespace std + +#endif // _LIBCPP___EXCEPTION_OPERATIONS_H diff --git a/libcxx/include/__cxx03/__exception/terminate.h b/libcxx/include/__cxx03/__exception/terminate.h new file mode 100644 index 0000000000000000000000000000000000000000..e672471dc52631698d082b3abcce29f60d699158 --- /dev/null +++ b/libcxx/include/__cxx03/__exception/terminate.h @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___EXCEPTION_TERMINATE_H +#define _LIBCPP___EXCEPTION_TERMINATE_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +namespace std { // purposefully not using versioning namespace +_LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void terminate() _NOEXCEPT; +} // namespace std + +#endif // _LIBCPP___EXCEPTION_TERMINATE_H diff --git a/libcxx/include/__cxx03/__expected/bad_expected_access.h b/libcxx/include/__cxx03/__expected/bad_expected_access.h new file mode 100644 index 0000000000000000000000000000000000000000..1b734389e8311f37bb7ea59b92b945c0e6beae49 --- /dev/null +++ b/libcxx/include/__cxx03/__expected/bad_expected_access.h @@ -0,0 +1,73 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef _LIBCPP___EXPECTED_BAD_EXPECTED_ACCESS_H +#define _LIBCPP___EXPECTED_BAD_EXPECTED_ACCESS_H + +#include <__config> +#include <__exception/exception.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class bad_expected_access; + +_LIBCPP_DIAGNOSTIC_PUSH +# if !_LIBCPP_AVAILABILITY_HAS_BAD_EXPECTED_ACCESS_KEY_FUNCTION +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wweak-vtables") +# endif +template <> +class _LIBCPP_EXPORTED_FROM_ABI bad_expected_access : public exception { +protected: + _LIBCPP_HIDE_FROM_ABI bad_expected_access() noexcept = default; + _LIBCPP_HIDE_FROM_ABI bad_expected_access(const bad_expected_access&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI bad_expected_access(bad_expected_access&&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI bad_expected_access& operator=(const bad_expected_access&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI bad_expected_access& operator=(bad_expected_access&&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~bad_expected_access() override = default; + +public: +# if _LIBCPP_AVAILABILITY_HAS_BAD_EXPECTED_ACCESS_KEY_FUNCTION + const char* what() const noexcept override; +# else + _LIBCPP_HIDE_FROM_ABI_VIRTUAL const char* what() const noexcept override { return "bad access to std::expected"; } +# endif +}; +_LIBCPP_DIAGNOSTIC_POP + +template +class bad_expected_access : public bad_expected_access { +public: + _LIBCPP_HIDE_FROM_ABI explicit bad_expected_access(_Err __e) : __unex_(std::move(__e)) {} + + _LIBCPP_HIDE_FROM_ABI _Err& error() & noexcept { return __unex_; } + _LIBCPP_HIDE_FROM_ABI const _Err& error() const& noexcept { return __unex_; } + _LIBCPP_HIDE_FROM_ABI _Err&& error() && noexcept { return std::move(__unex_); } + _LIBCPP_HIDE_FROM_ABI const _Err&& error() const&& noexcept { return std::move(__unex_); } + +private: + _Err __unex_; +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___EXPECTED_BAD_EXPECTED_ACCESS_H diff --git a/libcxx/include/__cxx03/__expected/expected.h b/libcxx/include/__cxx03/__expected/expected.h new file mode 100644 index 0000000000000000000000000000000000000000..7a6f04c50dabf26f59cab3de37462bbde8ad86b5 --- /dev/null +++ b/libcxx/include/__cxx03/__expected/expected.h @@ -0,0 +1,1874 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef _LIBCPP___EXPECTED_EXPECTED_H +#define _LIBCPP___EXPECTED_EXPECTED_H + +#include <__assert> +#include <__config> +#include <__expected/bad_expected_access.h> +#include <__expected/unexpect.h> +#include <__expected/unexpected.h> +#include <__functional/invoke.h> +#include <__memory/addressof.h> +#include <__memory/construct_at.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/disjunction.h> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_assignable.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_function.h> +#include <__type_traits/is_nothrow_assignable.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/is_same.h> +#include <__type_traits/is_swappable.h> +#include <__type_traits/is_trivially_constructible.h> +#include <__type_traits/is_trivially_destructible.h> +#include <__type_traits/is_trivially_relocatable.h> +#include <__type_traits/is_void.h> +#include <__type_traits/lazy.h> +#include <__type_traits/negation.h> +#include <__type_traits/remove_cv.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/as_const.h> +#include <__utility/exception_guard.h> +#include <__utility/forward.h> +#include <__utility/in_place.h> +#include <__utility/move.h> +#include <__utility/swap.h> +#include <__verbose_abort> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class expected; + +template +struct __is_std_expected : false_type {}; + +template +struct __is_std_expected> : true_type {}; + +struct __expected_construct_in_place_from_invoke_tag {}; +struct __expected_construct_unexpected_from_invoke_tag {}; + +template +_LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) { +# ifndef _LIBCPP_HAS_NO_EXCEPTIONS + throw bad_expected_access<_Err>(std::forward<_Arg>(__arg)); +# else + (void)__arg; + _LIBCPP_VERBOSE_ABORT("bad_expected_access was thrown in -fno-exceptions mode"); +# endif +} + +// If parameter type `_Tp` of `__conditional_no_unique_address` is neither +// copyable nor movable, a constructor with this tag is provided. For that +// constructor, the user has to provide a function and arguments. The function +// must return an object of type `_Tp`. When the function is invoked by the +// constructor, guaranteed copy elision kicks in and the `_Tp` is constructed +// in place. +struct __conditional_no_unique_address_invoke_tag {}; + +// This class implements an object with `[[no_unique_address]]` conditionally applied to it, +// based on the value of `_NoUnique`. +// +// A member of this class must always have `[[no_unique_address]]` applied to +// it. Otherwise, the `[[no_unique_address]]` in the "`_NoUnique == true`" case +// would not have any effect. In the `false` case, the `__v` is not +// `[[no_unique_address]]`, so nullifies the effects of the "outer" +// `[[no_unique_address]]` regarding data layout. +// +// If we had a language feature, this class would basically be replaced by `[[no_unique_address(condition)]]`. +template +struct __conditional_no_unique_address; + +template +struct __conditional_no_unique_address { + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(in_place_t, _Args&&... __args) + : __v(std::forward<_Args>(__args)...) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address( + __conditional_no_unique_address_invoke_tag, _Func&& __f, _Args&&... __args) + : __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {} + + _LIBCPP_NO_UNIQUE_ADDRESS _Tp __v; +}; + +template +struct __conditional_no_unique_address { + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(in_place_t, _Args&&... __args) + : __v(std::forward<_Args>(__args)...) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address( + __conditional_no_unique_address_invoke_tag, _Func&& __f, _Args&&... __args) + : __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {} + + _Tp __v; +}; + +// This function returns whether the type `_Second` can be stuffed into the tail padding +// of the `_First` type if both of them are given `[[no_unique_address]]`. +template +inline constexpr bool __fits_in_tail_padding = []() { + struct __x { + _LIBCPP_NO_UNIQUE_ADDRESS _First __first; + _LIBCPP_NO_UNIQUE_ADDRESS _Second __second; + }; + return sizeof(__x) == sizeof(_First); +}(); + +// This class implements the storage used by `std::expected`. We have a few +// goals for this storage: +// 1. Whenever the underlying {_Tp | _Unex} combination has free bytes in its +// tail padding, we should reuse it to store the bool discriminator of the +// expected, so as to save space. +// 2. Whenever the `expected<_Tp, _Unex>` as a whole has free bytes in its tail +// padding, we should allow an object following the expected to be stored in +// its tail padding. +// 3. However, we never want a user object (say `X`) that would follow an +// `expected<_Tp, _Unex>` to be stored in the padding bytes of the +// underlying {_Tp | _Unex} union, if any. That is because we use +// `construct_at` on that union, which would end up overwriting the `X` +// member if it is stored in the tail padding of the union. +// +// To achieve this, `__expected_base`'s logic is implemented in an inner +// `__repr` class. `__expected_base` holds one `__repr` member which is +// conditionally `[[no_unique_address]]`. The `__repr` class holds the +// underlying {_Tp | _Unex} union and a boolean "has value" flag. +// +// Which one of the `__repr_`/`__union_` members is `[[no_unique_address]]` +// depends on whether the "has value" boolean fits into the tail padding of +// the underlying {_Tp | _Unex} union: +// +// - In case the "has value" bool fits into the tail padding of the union, the +// whole `__repr_` member is _not_ `[[no_unique_address]]` as it needs to be +// transparently replaced on `emplace()`/`swap()` etc. +// - In case the "has value" bool does not fit into the tail padding of the +// union, only the union member must be transparently replaced (therefore is +// _not_ `[[no_unique_address]]`) and the "has value" flag must be adjusted +// manually. +// +// This way, the member that is transparently replaced on mutating operations +// is never `[[no_unique_address]]`, satisfying the requirements from +// "[basic.life]" in the standard. +// +// Stripped away of all superfluous elements, the layout of `__expected_base` +// then looks like this: +// +// template +// class expected_base { +// union union_t { +// [[no_unique_address]] Tp val; +// [[no_unique_address]] Err unex; +// }; +// +// static constexpr bool put_flag_in_tail = fits_in_tail_padding; +// static constexpr bool allow_reusing_expected_tail_padding = !put_flag_in_tail; +// +// struct repr { +// private: +// // If "has value" fits into the tail, this should be +// // `[[no_unique_address]]`, otherwise not. +// [[no_unique_address]] conditional_no_unique_address< +// put_flag_in_tail, +// union_t>::type union_; +// [[no_unique_address]] bool has_val_; +// }; +// +// protected: +// // If "has value" fits into the tail, this must _not_ be +// // `[[no_unique_address]]` so that we fill out the +// // complete `expected` object. +// [[no_unique_address]] conditional_no_unique_address< +// allow_reusing_expected_tail_padding, +// repr>::type repr_; +// }; +// +template +class __expected_base { + // use named union because [[no_unique_address]] cannot be applied to an unnamed union, + // also guaranteed elision into a potentially-overlapping subobject is unsettled (and + // it's not clear that it's implementable, given that the function is allowed to clobber + // the tail padding) - see https://github.com/itanium-cxx-abi/cxx-abi/issues/107. + union __union_t { + _LIBCPP_HIDE_FROM_ABI constexpr __union_t(const __union_t&) = delete; + _LIBCPP_HIDE_FROM_ABI constexpr __union_t(const __union_t&) + requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> && + is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>) + = default; + _LIBCPP_HIDE_FROM_ABI constexpr __union_t(__union_t&&) = delete; + _LIBCPP_HIDE_FROM_ABI constexpr __union_t(__union_t&&) + requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> && + is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>) + = default; + _LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(const __union_t&) = delete; + _LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(__union_t&&) = delete; + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(in_place_t, _Args&&... __args) + : __val_(std::forward<_Args>(__args)...) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(unexpect_t, _Args&&... __args) + : __unex_(std::forward<_Args>(__args)...) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t( + std::__expected_construct_in_place_from_invoke_tag, _Func&& __f, _Args&&... __args) + : __val_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t( + std::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args) + : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {} + + _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() + requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>) + = default; + + // __repr's destructor handles this + _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() {} + + _LIBCPP_NO_UNIQUE_ADDRESS _Tp __val_; + _LIBCPP_NO_UNIQUE_ADDRESS _Err __unex_; + }; + + static constexpr bool __put_flag_in_tail = __fits_in_tail_padding<__union_t, bool>; + static constexpr bool __allow_reusing_expected_tail_padding = !__put_flag_in_tail; + + struct __repr { + _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr() = delete; + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(in_place_t __tag, _Args&&... __args) + : __union_(in_place, __tag, std::forward<_Args>(__args)...), __has_val_(true) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(unexpect_t __tag, _Args&&... __args) + : __union_(in_place, __tag, std::forward<_Args>(__args)...), __has_val_(false) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(std::__expected_construct_in_place_from_invoke_tag __tag, + _Args&&... __args) + : __union_(in_place, __tag, std::forward<_Args>(__args)...), __has_val_(true) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(std::__expected_construct_unexpected_from_invoke_tag __tag, + _Args&&... __args) + : __union_(in_place, __tag, std::forward<_Args>(__args)...), __has_val_(false) {} + + // The return value of `__make_union` must be constructed in place in the + // `__v` member of `__union_`, relying on guaranteed copy elision. To do + // this, the `__conditional_no_unique_address_invoke_tag` constructor is + // called with a lambda that is immediately called inside + // `__conditional_no_unique_address`'s constructor. + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other) + requires(__allow_reusing_expected_tail_padding) + : __union_(__conditional_no_unique_address_invoke_tag{}, + [&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }), + __has_val_(__has_val) {} + + _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&) = delete; + _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&) + requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> && + is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>) + = default; + _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&) = delete; + _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&) + requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> && + is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>) + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(const __repr&) = delete; + _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(__repr&&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr ~__repr() + requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>) + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr ~__repr() + requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>) + { + __destroy_union_member(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union() + requires(__allow_reusing_expected_tail_padding && + (is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)) + { + // Note: Since the destructor of the union is trivial, this does nothing + // except to end the lifetime of the union. + std::destroy_at(&__union_.__v); + } + + _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union() + requires(__allow_reusing_expected_tail_padding && + (!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)) + { + __destroy_union_member(); + std::destroy_at(&__union_.__v); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(in_place_t, _Args&&... __args) + requires(__allow_reusing_expected_tail_padding) + { + std::construct_at(&__union_.__v, in_place, std::forward<_Args>(__args)...); + __has_val_ = true; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(unexpect_t, _Args&&... __args) + requires(__allow_reusing_expected_tail_padding) + { + std::construct_at(&__union_.__v, unexpect, std::forward<_Args>(__args)...); + __has_val_ = false; + } + + private: + template + friend class __expected_base; + + _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union_member() + requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>) + { + if (__has_val_) { + std::destroy_at(std::addressof(__union_.__v.__val_)); + } else { + std::destroy_at(std::addressof(__union_.__v.__unex_)); + } + } + + template + _LIBCPP_HIDE_FROM_ABI static constexpr __union_t __make_union(bool __has_val, _OtherUnion&& __other) + requires(__allow_reusing_expected_tail_padding) + { + if (__has_val) + return __union_t(in_place, std::forward<_OtherUnion>(__other).__val_); + else + return __union_t(unexpect, std::forward<_OtherUnion>(__other).__unex_); + } + + _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<__put_flag_in_tail, __union_t> __union_; + _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_; + }; + + template + _LIBCPP_HIDE_FROM_ABI static constexpr __repr __make_repr(bool __has_val, _OtherUnion&& __other) + requires(__put_flag_in_tail) + { + if (__has_val) + return __repr(in_place, std::forward<_OtherUnion>(__other).__val_); + else + return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_); + } + +protected: + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(_Args&&... __args) + : __repr_(in_place, std::forward<_Args>(__args)...) {} + + // In case we copy/move construct from another `expected` we need to create + // our `expected` so that it either has a value or not, depending on the "has + // value" flag of the other `expected`. To do this without falling back on + // `std::construct_at` we rely on guaranteed copy elision using two helper + // functions `__make_repr` and `__make_union`. There have to be two since + // there are two data layouts with different members being + // `[[no_unique_address]]`. GCC (as of version 13) does not do guaranteed + // copy elision when initializing `[[no_unique_address]]` members. The two + // cases are: + // + // - `__make_repr`: This is used when the "has value" flag lives in the tail + // of the union. In this case, the `__repr` member is _not_ + // `[[no_unique_address]]`. + // - `__make_union`: When the "has value" flag does _not_ fit in the tail of + // the union, the `__repr` member is `[[no_unique_address]]` and the union + // is not. + // + // This constructor "catches" the first case and leaves the second case to + // `__union_t`, its constructors and `__make_union`. + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(bool __has_val, _OtherUnion&& __other) + requires(__put_flag_in_tail) + : __repr_(__conditional_no_unique_address_invoke_tag{}, + [&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {} + + _LIBCPP_HIDE_FROM_ABI constexpr void __destroy() { + if constexpr (__put_flag_in_tail) + std::destroy_at(&__repr_.__v); + else + __repr_.__v.__destroy_union(); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args) { + if constexpr (__put_flag_in_tail) + std::construct_at(&__repr_.__v, __tag, std::forward<_Args>(__args)...); + else + __repr_.__v.__construct_union(__tag, std::forward<_Args>(__args)...); + } + + _LIBCPP_HIDE_FROM_ABI constexpr bool __has_val() const { return __repr_.__v.__has_val_; } + _LIBCPP_HIDE_FROM_ABI constexpr __union_t& __union() { return __repr_.__v.__union_.__v; } + _LIBCPP_HIDE_FROM_ABI constexpr const __union_t& __union() const { return __repr_.__v.__union_.__v; } + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& __val() { return __repr_.__v.__union_.__v.__val_; } + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& __val() const { return __repr_.__v.__union_.__v.__val_; } + _LIBCPP_HIDE_FROM_ABI constexpr _Err& __unex() { return __repr_.__v.__union_.__v.__unex_; } + _LIBCPP_HIDE_FROM_ABI constexpr const _Err& __unex() const { return __repr_.__v.__union_.__v.__unex_; } + +private: + _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<__allow_reusing_expected_tail_padding, __repr> __repr_; +}; + +template +class expected : private __expected_base<_Tp, _Err> { + static_assert(!is_reference_v<_Tp> && !is_function_v<_Tp> && !is_same_v, in_place_t> && + !is_same_v, unexpect_t> && !__is_std_unexpected>::value && + __valid_std_unexpected<_Err>::value, + "[expected.object.general] A program that instantiates the definition of template expected for a " + "reference type, a function type, or for possibly cv-qualified types in_place_t, unexpect_t, or a " + "specialization of unexpected for the T parameter is ill-formed. A program that instantiates the " + "definition of the template expected with a type for the E parameter that is not a valid " + "template argument for unexpected is ill-formed."); + + template + friend class expected; + + using __base = __expected_base<_Tp, _Err>; + +public: + using value_type = _Tp; + using error_type = _Err; + using unexpected_type = unexpected<_Err>; + + using __trivially_relocatable = + __conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value && __libcpp_is_trivially_relocatable<_Err>::value, + expected, + void>; + + template + using rebind = expected<_Up, error_type>; + + // [expected.object.ctor], constructors + _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept(is_nothrow_default_constructible_v<_Tp>) // strengthened + requires is_default_constructible_v<_Tp> + : __base(in_place) {} + + _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) + requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Tp> && + is_trivially_copy_constructible_v<_Err>) + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __other) noexcept( + is_nothrow_copy_constructible_v<_Tp> && is_nothrow_copy_constructible_v<_Err>) // strengthened + requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> && + !(is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>)) + : __base(__other.__has_val(), __other.__union()) {} + + _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&) + requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Tp> && + is_trivially_move_constructible_v<_Err>) + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __other) noexcept( + is_nothrow_move_constructible_v<_Tp> && is_nothrow_move_constructible_v<_Err>) + requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> && + !(is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>)) + : __base(__other.__has_val(), std::move(__other.__union())) {} + +private: + template + using __can_convert = _And< + is_constructible<_Tp, _UfQual>, + is_constructible<_Err, _OtherErrQual>, + _If<_Not, bool>>::value, + _And< _Not<_And, is_same<_Err, _OtherErr>>>, // use the copy constructor instead, see #92676 + _Not&>>, + _Not>>, + _Not&>>, + _Not>>, + _Not&, _Tp>>, + _Not&&, _Tp>>, + _Not&, _Tp>>, + _Not&&, _Tp>>>, + true_type>, + _Not, expected<_Up, _OtherErr>&>>, + _Not, expected<_Up, _OtherErr>>>, + _Not, const expected<_Up, _OtherErr>&>>, + _Not, const expected<_Up, _OtherErr>>> >; + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected( + std::__expected_construct_in_place_from_invoke_tag __tag, _Func&& __f, _Args&&... __args) + : __base(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected( + std::__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args) + : __base(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {} + +public: + template + requires __can_convert<_Up, _OtherErr, const _Up&, const _OtherErr&>::value + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v || + !is_convertible_v) + expected(const expected<_Up, _OtherErr>& __other) noexcept( + is_nothrow_constructible_v<_Tp, const _Up&> && + is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened + : __base(__other.__has_val(), __other.__union()) {} + + template + requires __can_convert<_Up, _OtherErr, _Up, _OtherErr>::value + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp> || !is_convertible_v<_OtherErr, _Err>) + expected(expected<_Up, _OtherErr>&& __other) noexcept( + is_nothrow_constructible_v<_Tp, _Up> && is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened + : __base(__other.__has_val(), std::move(__other.__union())) {} + + template + requires(!is_same_v, in_place_t> && !is_same_v> && + is_constructible_v<_Tp, _Up> && !__is_std_unexpected>::value && + (!is_same_v, bool> || !__is_std_expected>::value)) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp>) + expected(_Up&& __u) noexcept(is_nothrow_constructible_v<_Tp, _Up>) // strengthened + : __base(in_place, std::forward<_Up>(__u)) {} + + template + requires is_constructible_v<_Err, const _OtherErr&> + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v) expected( + const unexpected<_OtherErr>& __unex) noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened + : __base(unexpect, __unex.error()) {} + + template + requires is_constructible_v<_Err, _OtherErr> + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>) + expected(unexpected<_OtherErr>&& __unex) noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened + : __base(unexpect, std::move(__unex.error())) {} + + template + requires is_constructible_v<_Tp, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t, _Args&&... __args) noexcept( + is_nothrow_constructible_v<_Tp, _Args...>) // strengthened + : __base(in_place, std::forward<_Args>(__args)...) {} + + template + requires is_constructible_v< _Tp, initializer_list<_Up>&, _Args... > + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t, initializer_list<_Up> __il, _Args&&... __args) noexcept( + is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...>) // strengthened + : __base(in_place, __il, std::forward<_Args>(__args)...) {} + + template + requires is_constructible_v<_Err, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args) noexcept( + is_nothrow_constructible_v<_Err, _Args...>) // strengthened + : __base(unexpect, std::forward<_Args>(__args)...) {} + + template + requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... > + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args) noexcept( + is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened + : __base(unexpect, __il, std::forward<_Args>(__args)...) {} + + // [expected.object.dtor], destructor + + _LIBCPP_HIDE_FROM_ABI constexpr ~expected() = default; + +private: + template + _LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(_T2& __oldval, _Args&&... __args) { + if constexpr (is_nothrow_constructible_v<_T1, _Args...>) { + this->__destroy(); + this->__construct(_Tag{}, std::forward<_Args>(__args)...); + } else if constexpr (is_nothrow_move_constructible_v<_T1>) { + _T1 __tmp(std::forward<_Args>(__args)...); + this->__destroy(); + this->__construct(_Tag{}, std::move(__tmp)); + } else { + static_assert( + is_nothrow_move_constructible_v<_T2>, + "To provide strong exception guarantee, T2 has to satisfy `is_nothrow_move_constructible_v` so that it can " + "be reverted to the previous state in case an exception is thrown during the assignment."); + _T2 __tmp(std::move(__oldval)); + this->__destroy(); + auto __trans = std::__make_exception_guard([&] { this->__construct(_OtherTag{}, std::move(__tmp)); }); + this->__construct(_Tag{}, std::forward<_Args>(__args)...); + __trans.__complete(); + } + } + +public: + // [expected.object.assign], assignment + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs) noexcept( + is_nothrow_copy_assignable_v<_Tp> && is_nothrow_copy_constructible_v<_Tp> && is_nothrow_copy_assignable_v<_Err> && + is_nothrow_copy_constructible_v<_Err>) // strengthened + requires(is_copy_assignable_v<_Tp> && is_copy_constructible_v<_Tp> && is_copy_assignable_v<_Err> && + is_copy_constructible_v<_Err> && + (is_nothrow_move_constructible_v<_Tp> || is_nothrow_move_constructible_v<_Err>)) + { + if (this->__has_val() && __rhs.__has_val()) { + this->__val() = __rhs.__val(); + } else if (this->__has_val()) { + __reinit_expected(this->__val(), __rhs.__unex()); + } else if (__rhs.__has_val()) { + __reinit_expected(this->__unex(), __rhs.__val()); + } else { + this->__unex() = __rhs.__unex(); + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr expected& + operator=(expected&& __rhs) noexcept(is_nothrow_move_assignable_v<_Tp> && is_nothrow_move_constructible_v<_Tp> && + is_nothrow_move_assignable_v<_Err> && is_nothrow_move_constructible_v<_Err>) + requires(is_move_constructible_v<_Tp> && is_move_assignable_v<_Tp> && is_move_constructible_v<_Err> && + is_move_assignable_v<_Err> && + (is_nothrow_move_constructible_v<_Tp> || is_nothrow_move_constructible_v<_Err>)) + { + if (this->__has_val() && __rhs.__has_val()) { + this->__val() = std::move(__rhs.__val()); + } else if (this->__has_val()) { + __reinit_expected(this->__val(), std::move(__rhs.__unex())); + } else if (__rhs.__has_val()) { + __reinit_expected(this->__unex(), std::move(__rhs.__val())); + } else { + this->__unex() = std::move(__rhs.__unex()); + } + return *this; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(_Up&& __v) + requires(!is_same_v> && !__is_std_unexpected>::value && + is_constructible_v<_Tp, _Up> && is_assignable_v<_Tp&, _Up> && + (is_nothrow_constructible_v<_Tp, _Up> || is_nothrow_move_constructible_v<_Tp> || + is_nothrow_move_constructible_v<_Err>)) + { + if (this->__has_val()) { + this->__val() = std::forward<_Up>(__v); + } else { + __reinit_expected(this->__unex(), std::forward<_Up>(__v)); + } + return *this; + } + +private: + template + static constexpr bool __can_assign_from_unexpected = + _And< is_constructible<_Err, _OtherErrQual>, + is_assignable<_Err&, _OtherErrQual>, + _Lazy<_Or, + is_nothrow_constructible<_Err, _OtherErrQual>, + is_nothrow_move_constructible<_Tp>, + is_nothrow_move_constructible<_Err>> >::value; + +public: + template + requires(__can_assign_from_unexpected) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) { + if (this->__has_val()) { + __reinit_expected(this->__val(), __un.error()); + } else { + this->__unex() = __un.error(); + } + return *this; + } + + template + requires(__can_assign_from_unexpected<_OtherErr>) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) { + if (this->__has_val()) { + __reinit_expected(this->__val(), std::move(__un.error())); + } else { + this->__unex() = std::move(__un.error()); + } + return *this; + } + + template + requires is_nothrow_constructible_v<_Tp, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(_Args&&... __args) noexcept { + this->__destroy(); + this->__construct(in_place, std::forward<_Args>(__args)...); + return this->__val(); + } + + template + requires is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) noexcept { + this->__destroy(); + this->__construct(in_place, __il, std::forward<_Args>(__args)...); + return this->__val(); + } + +public: + // [expected.object.swap], swap + _LIBCPP_HIDE_FROM_ABI constexpr void + swap(expected& __rhs) noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp> && + is_nothrow_move_constructible_v<_Err> && is_nothrow_swappable_v<_Err>) + requires(is_swappable_v<_Tp> && is_swappable_v<_Err> && is_move_constructible_v<_Tp> && + is_move_constructible_v<_Err> && + (is_nothrow_move_constructible_v<_Tp> || is_nothrow_move_constructible_v<_Err>)) + { + auto __swap_val_unex_impl = [](expected& __with_val, expected& __with_err) { + if constexpr (is_nothrow_move_constructible_v<_Err>) { + _Err __tmp(std::move(__with_err.__unex())); + __with_err.__destroy(); + auto __trans = std::__make_exception_guard([&] { __with_err.__construct(unexpect, std::move(__tmp)); }); + __with_err.__construct(in_place, std::move(__with_val.__val())); + __trans.__complete(); + __with_val.__destroy(); + __with_val.__construct(unexpect, std::move(__tmp)); + } else { + static_assert(is_nothrow_move_constructible_v<_Tp>, + "To provide strong exception guarantee, Tp has to satisfy `is_nothrow_move_constructible_v` so " + "that it can be reverted to the previous state in case an exception is thrown during swap."); + _Tp __tmp(std::move(__with_val.__val())); + __with_val.__destroy(); + auto __trans = std::__make_exception_guard([&] { __with_val.__construct(in_place, std::move(__tmp)); }); + __with_val.__construct(unexpect, std::move(__with_err.__unex())); + __trans.__complete(); + __with_err.__destroy(); + __with_err.__construct(in_place, std::move(__tmp)); + } + }; + + if (this->__has_val()) { + if (__rhs.__has_val()) { + using std::swap; + swap(this->__val(), __rhs.__val()); + } else { + __swap_val_unex_impl(*this, __rhs); + } + } else { + if (__rhs.__has_val()) { + __swap_val_unex_impl(__rhs, *this); + } else { + using std::swap; + swap(this->__unex(), __rhs.__unex()); + } + } + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(expected& __x, expected& __y) noexcept(noexcept(__x.swap(__y))) + requires requires { __x.swap(__y); } + { + __x.swap(__y); + } + + // [expected.object.obs], observers + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* operator->() const noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + this->__has_val(), "expected::operator-> requires the expected to contain a value"); + return std::addressof(this->__val()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Tp* operator->() noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + this->__has_val(), "expected::operator-> requires the expected to contain a value"); + return std::addressof(this->__val()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + this->__has_val(), "expected::operator* requires the expected to contain a value"); + return this->__val(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + this->__has_val(), "expected::operator* requires the expected to contain a value"); + return this->__val(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + this->__has_val(), "expected::operator* requires the expected to contain a value"); + return std::move(this->__val()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + this->__has_val(), "expected::operator* requires the expected to contain a value"); + return std::move(this->__val()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return this->__has_val(); } + + _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& value() const& { + static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible"); + if (!this->__has_val()) { + std::__throw_bad_expected_access<_Err>(std::as_const(error())); + } + return this->__val(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & { + static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible"); + if (!this->__has_val()) { + std::__throw_bad_expected_access<_Err>(std::as_const(error())); + } + return this->__val(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& value() const&& { + static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>, + "error_type has to be both copy constructible and constructible from decltype(std::move(error()))"); + if (!this->__has_val()) { + std::__throw_bad_expected_access<_Err>(std::move(error())); + } + return std::move(this->__val()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && { + static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>, + "error_type has to be both copy constructible and constructible from decltype(std::move(error()))"); + if (!this->__has_val()) { + std::__throw_bad_expected_access<_Err>(std::move(error())); + } + return std::move(this->__val()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !this->__has_val(), "expected::error requires the expected to contain an error"); + return this->__unex(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !this->__has_val(), "expected::error requires the expected to contain an error"); + return this->__unex(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !this->__has_val(), "expected::error requires the expected to contain an error"); + return std::move(this->__unex()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !this->__has_val(), "expected::error requires the expected to contain an error"); + return std::move(this->__unex()); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& { + static_assert(is_copy_constructible_v<_Tp>, "value_type has to be copy constructible"); + static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type"); + return this->__has_val() ? this->__val() : static_cast<_Tp>(std::forward<_Up>(__v)); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && { + static_assert(is_move_constructible_v<_Tp>, "value_type has to be move constructible"); + static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type"); + return this->__has_val() ? std::move(this->__val()) : static_cast<_Tp>(std::forward<_Up>(__v)); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& { + static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible"); + static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); + if (has_value()) + return std::forward<_Up>(__error); + return error(); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) && { + static_assert(is_move_constructible_v<_Err>, "error_type has to be move constructible"); + static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); + if (has_value()) + return std::forward<_Up>(__error); + return std::move(error()); + } + + // [expected.void.monadic], monadic + template + requires is_constructible_v<_Err, _Err&> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { + using _Up = remove_cvref_t>; + static_assert(__is_std_expected<_Up>::value, "The result of f(**this) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(**this) must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f), this->__val()); + } + return _Up(unexpect, error()); + } + + template + requires is_constructible_v<_Err, const _Err&> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& { + using _Up = remove_cvref_t>; + static_assert(__is_std_expected<_Up>::value, "The result of f(**this) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(**this) must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f), this->__val()); + } + return _Up(unexpect, error()); + } + + template + requires is_constructible_v<_Err, _Err&&> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && { + using _Up = remove_cvref_t>; + static_assert( + __is_std_expected<_Up>::value, "The result of f(std::move(**this)) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(std::move(**this)) must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f), std::move(this->__val())); + } + return _Up(unexpect, std::move(error())); + } + + template + requires is_constructible_v<_Err, const _Err&&> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& { + using _Up = remove_cvref_t>; + static_assert( + __is_std_expected<_Up>::value, "The result of f(std::move(**this)) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(std::move(**this)) must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f), std::move(this->__val())); + } + return _Up(unexpect, std::move(error())); + } + + template + requires is_constructible_v<_Tp, _Tp&> + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & { + using _Gp = remove_cvref_t>; + static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(error()) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(in_place, this->__val()); + } + return std::invoke(std::forward<_Func>(__f), error()); + } + + template + requires is_constructible_v<_Tp, const _Tp&> + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& { + using _Gp = remove_cvref_t>; + static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(error()) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(in_place, this->__val()); + } + return std::invoke(std::forward<_Func>(__f), error()); + } + + template + requires is_constructible_v<_Tp, _Tp&&> + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && { + using _Gp = remove_cvref_t>; + static_assert( + __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(std::move(error())) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(in_place, std::move(this->__val())); + } + return std::invoke(std::forward<_Func>(__f), std::move(error())); + } + + template + requires is_constructible_v<_Tp, const _Tp&&> + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& { + using _Gp = remove_cvref_t>; + static_assert( + __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(std::move(error())) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(in_place, std::move(this->__val())); + } + return std::invoke(std::forward<_Func>(__f), std::move(error())); + } + + template + requires is_constructible_v<_Err, _Err&> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, error()); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), this->__val()); + } else { + std::invoke(std::forward<_Func>(__f), this->__val()); + return expected<_Up, _Err>(); + } + } + + template + requires is_constructible_v<_Err, const _Err&> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, error()); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), this->__val()); + } else { + std::invoke(std::forward<_Func>(__f), this->__val()); + return expected<_Up, _Err>(); + } + } + + template + requires is_constructible_v<_Err, _Err&&> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, std::move(error())); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(this->__val())); + } else { + std::invoke(std::forward<_Func>(__f), std::move(this->__val())); + return expected<_Up, _Err>(); + } + } + + template + requires is_constructible_v<_Err, const _Err&&> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, std::move(error())); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(this->__val())); + } else { + std::invoke(std::forward<_Func>(__f), std::move(this->__val())); + return expected<_Up, _Err>(); + } + } + + template + requires is_constructible_v<_Tp, _Tp&> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & { + using _Gp = remove_cv_t>; + static_assert(__valid_std_unexpected<_Gp>::value, + "The result of f(error()) must be a valid template argument for unexpected"); + if (has_value()) { + return expected<_Tp, _Gp>(in_place, this->__val()); + } + return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error()); + } + + template + requires is_constructible_v<_Tp, const _Tp&> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& { + using _Gp = remove_cv_t>; + static_assert(__valid_std_unexpected<_Gp>::value, + "The result of f(error()) must be a valid template argument for unexpected"); + if (has_value()) { + return expected<_Tp, _Gp>(in_place, this->__val()); + } + return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error()); + } + + template + requires is_constructible_v<_Tp, _Tp&&> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && { + using _Gp = remove_cv_t>; + static_assert(__valid_std_unexpected<_Gp>::value, + "The result of f(std::move(error())) must be a valid template argument for unexpected"); + if (has_value()) { + return expected<_Tp, _Gp>(in_place, std::move(this->__val())); + } + return expected<_Tp, _Gp>( + __expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error())); + } + + template + requires is_constructible_v<_Tp, const _Tp&&> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& { + using _Gp = remove_cv_t>; + static_assert(__valid_std_unexpected<_Gp>::value, + "The result of f(std::move(error())) must be a valid template argument for unexpected"); + if (has_value()) { + return expected<_Tp, _Gp>(in_place, std::move(this->__val())); + } + return expected<_Tp, _Gp>( + __expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error())); + } + + // [expected.object.eq], equality operators + template + requires(!is_void_v<_T2>) + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) { + if (__x.__has_val() != __y.__has_val()) { + return false; + } else { + if (__x.__has_val()) { + return __x.__val() == __y.__val(); + } else { + return __x.__unex() == __y.__unex(); + } + } + } + + template + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const _T2& __v) { + return __x.__has_val() && static_cast(__x.__val() == __v); + } + + template + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __e) { + return !__x.__has_val() && static_cast(__x.__unex() == __e.error()); + } +}; + +template +class __expected_void_base { + struct __empty_t {}; + // use named union because [[no_unique_address]] cannot be applied to an unnamed union, + // also guaranteed elision into a potentially-overlapping subobject is unsettled (and + // it's not clear that it's implementable, given that the function is allowed to clobber + // the tail padding) - see https://github.com/itanium-cxx-abi/cxx-abi/issues/107. + union __union_t { + _LIBCPP_HIDE_FROM_ABI constexpr __union_t(const __union_t&) = delete; + _LIBCPP_HIDE_FROM_ABI constexpr __union_t(const __union_t&) + requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>) + = default; + _LIBCPP_HIDE_FROM_ABI constexpr __union_t(__union_t&&) = delete; + _LIBCPP_HIDE_FROM_ABI constexpr __union_t(__union_t&&) + requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>) + = default; + _LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(const __union_t&) = delete; + _LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(__union_t&&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(in_place_t) : __empty_() {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(unexpect_t, _Args&&... __args) + : __unex_(std::forward<_Args>(__args)...) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t( + __expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args) + : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {} + + _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() + requires(is_trivially_destructible_v<_Err>) + = default; + + // __repr's destructor handles this + _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() + requires(!is_trivially_destructible_v<_Err>) + {} + + _LIBCPP_NO_UNIQUE_ADDRESS __empty_t __empty_; + _LIBCPP_NO_UNIQUE_ADDRESS _Err __unex_; + }; + + static constexpr bool __put_flag_in_tail = __fits_in_tail_padding<__union_t, bool>; + static constexpr bool __allow_reusing_expected_tail_padding = !__put_flag_in_tail; + + struct __repr { + _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr() = delete; + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(in_place_t __tag) : __union_(in_place, __tag), __has_val_(true) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(unexpect_t __tag, _Args&&... __args) + : __union_(in_place, __tag, std::forward<_Args>(__args)...), __has_val_(false) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(std::__expected_construct_unexpected_from_invoke_tag __tag, + _Args&&... __args) + : __union_(in_place, __tag, std::forward<_Args>(__args)...), __has_val_(false) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other) + requires(__allow_reusing_expected_tail_padding) + : __union_(__conditional_no_unique_address_invoke_tag{}, + [&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }), + __has_val_(__has_val) {} + + _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&) = delete; + _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&) + requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>) + = default; + _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&) = delete; + _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&) + requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>) + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(const __repr&) = delete; + _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(__repr&&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr ~__repr() + requires(is_trivially_destructible_v<_Err>) + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr ~__repr() + requires(!is_trivially_destructible_v<_Err>) + { + __destroy_union_member(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union() + requires(__allow_reusing_expected_tail_padding && is_trivially_destructible_v<_Err>) + { + std::destroy_at(&__union_.__v); + } + + _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union() + requires(__allow_reusing_expected_tail_padding && !is_trivially_destructible_v<_Err>) + { + __destroy_union_member(); + std::destroy_at(&__union_.__v); + } + + _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(in_place_t) + requires(__allow_reusing_expected_tail_padding) + { + std::construct_at(&__union_.__v, in_place); + __has_val_ = true; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(unexpect_t, _Args&&... __args) + requires(__allow_reusing_expected_tail_padding) + { + std::construct_at(&__union_.__v, unexpect, std::forward<_Args>(__args)...); + __has_val_ = false; + } + + private: + template + friend class __expected_void_base; + + _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union_member() + requires(!is_trivially_destructible_v<_Err>) + { + if (!__has_val_) + std::destroy_at(std::addressof(__union_.__v.__unex_)); + } + + template + _LIBCPP_HIDE_FROM_ABI static constexpr __union_t __make_union(bool __has_val, _OtherUnion&& __other) + requires(__allow_reusing_expected_tail_padding) + { + if (__has_val) + return __union_t(in_place); + else + return __union_t(unexpect, std::forward<_OtherUnion>(__other).__unex_); + } + + _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<__put_flag_in_tail, __union_t> __union_; + _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_; + }; + + template + _LIBCPP_HIDE_FROM_ABI static constexpr __repr __make_repr(bool __has_val, _OtherUnion&& __other) + requires(__put_flag_in_tail) + { + if (__has_val) + return __repr(in_place); + else + return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_); + } + +protected: + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_base(_Args&&... __args) + : __repr_(in_place, std::forward<_Args>(__args)...) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_base(bool __has_val, _OtherUnion&& __other) + requires(__put_flag_in_tail) + : __repr_(__conditional_no_unique_address_invoke_tag{}, + [&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {} + + _LIBCPP_HIDE_FROM_ABI constexpr void __destroy() { + if constexpr (__put_flag_in_tail) + std::destroy_at(&__repr_.__v); + else + __repr_.__v.__destroy_union(); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args) { + if constexpr (__put_flag_in_tail) + std::construct_at(&__repr_.__v, __tag, std::forward<_Args>(__args)...); + else + __repr_.__v.__construct_union(__tag, std::forward<_Args>(__args)...); + } + + _LIBCPP_HIDE_FROM_ABI constexpr bool __has_val() const { return __repr_.__v.__has_val_; } + _LIBCPP_HIDE_FROM_ABI constexpr __union_t& __union() { return __repr_.__v.__union_.__v; } + _LIBCPP_HIDE_FROM_ABI constexpr const __union_t& __union() const { return __repr_.__v.__union_.__v; } + _LIBCPP_HIDE_FROM_ABI constexpr _Err& __unex() { return __repr_.__v.__union_.__v.__unex_; } + _LIBCPP_HIDE_FROM_ABI constexpr const _Err& __unex() const { return __repr_.__v.__union_.__v.__unex_; } + +private: + _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<__allow_reusing_expected_tail_padding, __repr> __repr_; +}; + +template + requires is_void_v<_Tp> +class expected<_Tp, _Err> : private __expected_void_base<_Err> { + static_assert(__valid_std_unexpected<_Err>::value, + "[expected.void.general] A program that instantiates expected with a E that is not a " + "valid argument for unexpected is ill-formed"); + + template + friend class expected; + + template + using __can_convert = + _And< is_void<_Up>, + is_constructible<_Err, _OtherErrQual>, + _Not, expected<_Up, _OtherErr>&>>, + _Not, expected<_Up, _OtherErr>>>, + _Not, const expected<_Up, _OtherErr>&>>, + _Not, const expected<_Up, _OtherErr>>>>; + + using __base = __expected_void_base<_Err>; + +public: + using value_type = _Tp; + using error_type = _Err; + using unexpected_type = unexpected<_Err>; + + template + using rebind = expected<_Up, error_type>; + + // [expected.void.ctor], constructors + _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept : __base(in_place) {} + + _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) + requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>) + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __rhs) noexcept( + is_nothrow_copy_constructible_v<_Err>) // strengthened + requires(is_copy_constructible_v<_Err> && !is_trivially_copy_constructible_v<_Err>) + : __base(__rhs.__has_val(), __rhs.__union()) {} + + _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&) + requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>) + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __rhs) noexcept(is_nothrow_move_constructible_v<_Err>) + requires(is_move_constructible_v<_Err> && !is_trivially_move_constructible_v<_Err>) + : __base(__rhs.__has_val(), std::move(__rhs.__union())) {} + + template + requires __can_convert<_Up, _OtherErr, const _OtherErr&>::value + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v) + expected(const expected<_Up, _OtherErr>& __rhs) noexcept( + is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened + : __base(__rhs.__has_val(), __rhs.__union()) {} + + template + requires __can_convert<_Up, _OtherErr, _OtherErr>::value + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>) + expected(expected<_Up, _OtherErr>&& __rhs) noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened + : __base(__rhs.__has_val(), std::move(__rhs.__union())) {} + + template + requires is_constructible_v<_Err, const _OtherErr&> + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v) expected( + const unexpected<_OtherErr>& __unex) noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened + : __base(unexpect, __unex.error()) {} + + template + requires is_constructible_v<_Err, _OtherErr> + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>) + expected(unexpected<_OtherErr>&& __unex) noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened + : __base(unexpect, std::move(__unex.error())) {} + + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t) noexcept : __base(in_place) {} + + template + requires is_constructible_v<_Err, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args) noexcept( + is_nothrow_constructible_v<_Err, _Args...>) // strengthened + : __base(unexpect, std::forward<_Args>(__args)...) {} + + template + requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... > + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args) noexcept( + is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened + : __base(unexpect, __il, std::forward<_Args>(__args)...) {} + +private: + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected( + __expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args) + : __base(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {} + +public: + // [expected.void.dtor], destructor + + _LIBCPP_HIDE_FROM_ABI constexpr ~expected() = default; + +private: + template + _LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(unexpect_t, _Args&&... __args) { + _LIBCPP_ASSERT_INTERNAL(this->__has_val(), "__reinit_expected(unexpect_t, ...) needs value to be set"); + + this->__destroy(); + auto __trans = std::__make_exception_guard([&] { this->__construct(in_place); }); + this->__construct(unexpect, std::forward<_Args>(__args)...); + __trans.__complete(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(in_place_t) { + _LIBCPP_ASSERT_INTERNAL(!this->__has_val(), "__reinit_expected(in_place_t, ...) needs value to be unset"); + + this->__destroy(); + this->__construct(in_place); + } + +public: + // [expected.void.assign], assignment + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs) noexcept( + is_nothrow_copy_assignable_v<_Err> && is_nothrow_copy_constructible_v<_Err>) // strengthened + requires(is_copy_assignable_v<_Err> && is_copy_constructible_v<_Err>) + { + if (this->__has_val()) { + if (!__rhs.__has_val()) { + __reinit_expected(unexpect, __rhs.__unex()); + } + } else { + if (__rhs.__has_val()) { + __reinit_expected(in_place); + } else { + this->__unex() = __rhs.__unex(); + } + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr expected& + operator=(expected&& __rhs) noexcept(is_nothrow_move_assignable_v<_Err> && is_nothrow_move_constructible_v<_Err>) + requires(is_move_assignable_v<_Err> && is_move_constructible_v<_Err>) + { + if (this->__has_val()) { + if (!__rhs.__has_val()) { + __reinit_expected(unexpect, std::move(__rhs.__unex())); + } + } else { + if (__rhs.__has_val()) { + __reinit_expected(in_place); + } else { + this->__unex() = std::move(__rhs.__unex()); + } + } + return *this; + } + + template + requires(is_constructible_v<_Err, const _OtherErr&> && is_assignable_v<_Err&, const _OtherErr&>) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) { + if (this->__has_val()) { + __reinit_expected(unexpect, __un.error()); + } else { + this->__unex() = __un.error(); + } + return *this; + } + + template + requires(is_constructible_v<_Err, _OtherErr> && is_assignable_v<_Err&, _OtherErr>) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) { + if (this->__has_val()) { + __reinit_expected(unexpect, std::move(__un.error())); + } else { + this->__unex() = std::move(__un.error()); + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr void emplace() noexcept { + if (!this->__has_val()) { + __reinit_expected(in_place); + } + } + + // [expected.void.swap], swap + _LIBCPP_HIDE_FROM_ABI constexpr void + swap(expected& __rhs) noexcept(is_nothrow_move_constructible_v<_Err> && is_nothrow_swappable_v<_Err>) + requires(is_swappable_v<_Err> && is_move_constructible_v<_Err>) + { + auto __swap_val_unex_impl = [](expected& __with_val, expected& __with_err) { + // May throw, but will re-engage `__with_val` in that case. + __with_val.__reinit_expected(unexpect, std::move(__with_err.__unex())); + // Will not throw. + __with_err.__reinit_expected(in_place); + }; + + if (this->__has_val()) { + if (!__rhs.__has_val()) { + __swap_val_unex_impl(*this, __rhs); + } + } else { + if (__rhs.__has_val()) { + __swap_val_unex_impl(__rhs, *this); + } else { + using std::swap; + swap(this->__unex(), __rhs.__unex()); + } + } + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(expected& __x, expected& __y) noexcept(noexcept(__x.swap(__y))) + requires requires { __x.swap(__y); } + { + __x.swap(__y); + } + + // [expected.void.obs], observers + _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return this->__has_val(); } + + _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); } + + _LIBCPP_HIDE_FROM_ABI constexpr void operator*() const noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + this->__has_val(), "expected::operator* requires the expected to contain a value"); + } + + _LIBCPP_HIDE_FROM_ABI constexpr void value() const& { + static_assert(is_copy_constructible_v<_Err>); + if (!this->__has_val()) { + std::__throw_bad_expected_access<_Err>(this->__unex()); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr void value() && { + static_assert(is_copy_constructible_v<_Err> && is_move_constructible_v<_Err>); + if (!this->__has_val()) { + std::__throw_bad_expected_access<_Err>(std::move(this->__unex())); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !this->__has_val(), "expected::error requires the expected to contain an error"); + return this->__unex(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !this->__has_val(), "expected::error requires the expected to contain an error"); + return this->__unex(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !this->__has_val(), "expected::error requires the expected to contain an error"); + return std::move(this->__unex()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !this->__has_val(), "expected::error requires the expected to contain an error"); + return std::move(this->__unex()); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& { + static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible"); + static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); + if (has_value()) { + return std::forward<_Up>(__error); + } + return error(); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) && { + static_assert(is_move_constructible_v<_Err>, "error_type has to be move constructible"); + static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); + if (has_value()) { + return std::forward<_Up>(__error); + } + return std::move(error()); + } + + // [expected.void.monadic], monadic + template + requires is_constructible_v<_Err, _Err&> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { + using _Up = remove_cvref_t>; + static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected"); + static_assert( + is_same_v, "The result of f() must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f)); + } + return _Up(unexpect, error()); + } + + template + requires is_constructible_v<_Err, const _Err&> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& { + using _Up = remove_cvref_t>; + static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected"); + static_assert( + is_same_v, "The result of f() must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f)); + } + return _Up(unexpect, error()); + } + + template + requires is_constructible_v<_Err, _Err&&> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && { + using _Up = remove_cvref_t>; + static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected"); + static_assert( + is_same_v, "The result of f() must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f)); + } + return _Up(unexpect, std::move(error())); + } + + template + requires is_constructible_v<_Err, const _Err&&> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& { + using _Up = remove_cvref_t>; + static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected"); + static_assert( + is_same_v, "The result of f() must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f)); + } + return _Up(unexpect, std::move(error())); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & { + using _Gp = remove_cvref_t>; + static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(error()) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(); + } + return std::invoke(std::forward<_Func>(__f), error()); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& { + using _Gp = remove_cvref_t>; + static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(error()) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(); + } + return std::invoke(std::forward<_Func>(__f), error()); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && { + using _Gp = remove_cvref_t>; + static_assert( + __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(std::move(error())) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(); + } + return std::invoke(std::forward<_Func>(__f), std::move(error())); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& { + using _Gp = remove_cvref_t>; + static_assert( + __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(std::move(error())) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(); + } + return std::invoke(std::forward<_Func>(__f), std::move(error())); + } + + template + requires is_constructible_v<_Err, _Err&> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, error()); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f)); + } else { + std::invoke(std::forward<_Func>(__f)); + return expected<_Up, _Err>(); + } + } + + template + requires is_constructible_v<_Err, const _Err&> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, error()); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f)); + } else { + std::invoke(std::forward<_Func>(__f)); + return expected<_Up, _Err>(); + } + } + + template + requires is_constructible_v<_Err, _Err&&> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, std::move(error())); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f)); + } else { + std::invoke(std::forward<_Func>(__f)); + return expected<_Up, _Err>(); + } + } + + template + requires is_constructible_v<_Err, const _Err&&> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, std::move(error())); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f)); + } else { + std::invoke(std::forward<_Func>(__f)); + return expected<_Up, _Err>(); + } + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & { + using _Gp = remove_cv_t>; + static_assert(__valid_std_unexpected<_Gp>::value, + "The result of f(error()) must be a valid template argument for unexpected"); + if (has_value()) { + return expected<_Tp, _Gp>(); + } + return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error()); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& { + using _Gp = remove_cv_t>; + static_assert(__valid_std_unexpected<_Gp>::value, + "The result of f(error()) must be a valid template argument for unexpected"); + if (has_value()) { + return expected<_Tp, _Gp>(); + } + return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error()); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && { + using _Gp = remove_cv_t>; + static_assert(__valid_std_unexpected<_Gp>::value, + "The result of f(std::move(error())) must be a valid template argument for unexpected"); + if (has_value()) { + return expected<_Tp, _Gp>(); + } + return expected<_Tp, _Gp>( + __expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error())); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& { + using _Gp = remove_cv_t>; + static_assert(__valid_std_unexpected<_Gp>::value, + "The result of f(std::move(error())) must be a valid template argument for unexpected"); + if (has_value()) { + return expected<_Tp, _Gp>(); + } + return expected<_Tp, _Gp>( + __expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error())); + } + + // [expected.void.eq], equality operators + template + requires is_void_v<_T2> + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) { + if (__x.__has_val() != __y.__has_val()) { + return false; + } else { + return __x.__has_val() || static_cast(__x.__unex() == __y.__unex()); + } + } + + template + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __y) { + return !__x.__has_val() && static_cast(__x.__unex() == __y.error()); + } +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___EXPECTED_EXPECTED_H diff --git a/libcxx/include/__cxx03/__expected/unexpect.h b/libcxx/include/__cxx03/__expected/unexpect.h new file mode 100644 index 0000000000000000000000000000000000000000..df52787d36faff64e44488b0b9825157aaa0fea0 --- /dev/null +++ b/libcxx/include/__cxx03/__expected/unexpect.h @@ -0,0 +1,32 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef _LIBCPP___EXPECTED_UNEXPECT_H +#define _LIBCPP___EXPECTED_UNEXPECT_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +struct unexpect_t { + explicit unexpect_t() = default; +}; + +inline constexpr unexpect_t unexpect{}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +#endif // _LIBCPP___EXPECTED_UNEXPECT_H diff --git a/libcxx/include/__cxx03/__expected/unexpected.h b/libcxx/include/__cxx03/__expected/unexpected.h new file mode 100644 index 0000000000000000000000000000000000000000..c7fe3c52e431142795b66d393d29769cd59d37fc --- /dev/null +++ b/libcxx/include/__cxx03/__expected/unexpected.h @@ -0,0 +1,127 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef _LIBCPP___EXPECTED_UNEXPECTED_H +#define _LIBCPP___EXPECTED_UNEXPECTED_H + +#include <__config> +#include <__type_traits/conjunction.h> +#include <__type_traits/is_array.h> +#include <__type_traits/is_const.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_object.h> +#include <__type_traits/is_same.h> +#include <__type_traits/is_swappable.h> +#include <__type_traits/is_volatile.h> +#include <__type_traits/negation.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/forward.h> +#include <__utility/in_place.h> +#include <__utility/move.h> +#include <__utility/swap.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class unexpected; + +template +struct __is_std_unexpected : false_type {}; + +template +struct __is_std_unexpected> : true_type {}; + +template +using __valid_std_unexpected = _BoolConstant< // + is_object_v<_Tp> && // + !is_array_v<_Tp> && // + !__is_std_unexpected<_Tp>::value && // + !is_const_v<_Tp> && // + !is_volatile_v<_Tp> // + >; + +template +class unexpected { + static_assert(__valid_std_unexpected<_Err>::value, + "[expected.un.general] states a program that instantiates std::unexpected for a non-object type, an " + "array type, a specialization of unexpected, or a cv-qualified type is ill-formed."); + +public: + _LIBCPP_HIDE_FROM_ABI constexpr unexpected(const unexpected&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr unexpected(unexpected&&) = default; + + template + requires(!is_same_v, unexpected> && // + !is_same_v, in_place_t> && // + is_constructible_v<_Err, _Error>) + _LIBCPP_HIDE_FROM_ABI constexpr explicit unexpected(_Error&& __error) // + noexcept(is_nothrow_constructible_v<_Err, _Error>) // strengthened + : __unex_(std::forward<_Error>(__error)) {} + + template + requires is_constructible_v<_Err, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr explicit unexpected(in_place_t, _Args&&... __args) // + noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened + : __unex_(std::forward<_Args>(__args)...) {} + + template + requires is_constructible_v<_Err, initializer_list<_Up>&, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr explicit unexpected(in_place_t, initializer_list<_Up> __il, _Args&&... __args) // + noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened + : __unex_(__il, std::forward<_Args>(__args)...) {} + + _LIBCPP_HIDE_FROM_ABI constexpr unexpected& operator=(const unexpected&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr unexpected& operator=(unexpected&&) = default; + + _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { return __unex_; } + _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { return __unex_; } + _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { return std::move(__unex_); } + _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { return std::move(__unex_); } + + _LIBCPP_HIDE_FROM_ABI constexpr void swap(unexpected& __other) noexcept(is_nothrow_swappable_v<_Err>) { + static_assert(is_swappable_v<_Err>, "unexpected::swap requires is_swappable_v to be true"); + using std::swap; + swap(__unex_, __other.__unex_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(unexpected& __x, unexpected& __y) noexcept(noexcept(__x.swap(__y))) + requires is_swappable_v<_Err> + { + __x.swap(__y); + } + + template + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const unexpected& __x, const unexpected<_Err2>& __y) { + return __x.__unex_ == __y.__unex_; + } + +private: + _Err __unex_; +}; + +template +unexpected(_Err) -> unexpected<_Err>; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___EXPECTED_UNEXPECTED_H diff --git a/libcxx/include/__cxx03/__filesystem/copy_options.h b/libcxx/include/__cxx03/__filesystem/copy_options.h new file mode 100644 index 0000000000000000000000000000000000000000..097eebe61137d7826ae3291ab11a31eb3115ca65 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/copy_options.h @@ -0,0 +1,69 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_COPY_OPTIONS_H +#define _LIBCPP___FILESYSTEM_COPY_OPTIONS_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +enum class copy_options : unsigned short { + none = 0, + skip_existing = 1, + overwrite_existing = 2, + update_existing = 4, + recursive = 8, + copy_symlinks = 16, + skip_symlinks = 32, + directories_only = 64, + create_symlinks = 128, + create_hard_links = 256, + __in_recursive_copy = 512, +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr copy_options operator&(copy_options __lhs, copy_options __rhs) { + return static_cast(static_cast(__lhs) & static_cast(__rhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr copy_options operator|(copy_options __lhs, copy_options __rhs) { + return static_cast(static_cast(__lhs) | static_cast(__rhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr copy_options operator^(copy_options __lhs, copy_options __rhs) { + return static_cast(static_cast(__lhs) ^ static_cast(__rhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr copy_options operator~(copy_options __lhs) { + return static_cast(~static_cast(__lhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline copy_options& operator&=(copy_options& __lhs, copy_options __rhs) { + return __lhs = __lhs & __rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline copy_options& operator|=(copy_options& __lhs, copy_options __rhs) { + return __lhs = __lhs | __rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline copy_options& operator^=(copy_options& __lhs, copy_options __rhs) { + return __lhs = __lhs ^ __rhs; +} + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +#endif // _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___FILESYSTEM_COPY_OPTIONS_H diff --git a/libcxx/include/__cxx03/__filesystem/directory_entry.h b/libcxx/include/__cxx03/__filesystem/directory_entry.h new file mode 100644 index 0000000000000000000000000000000000000000..96d88dcd90b4c02c352370d37e9c860bd2d58ea5 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/directory_entry.h @@ -0,0 +1,435 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H +#define _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H + +#include <__chrono/time_point.h> +#include <__compare/ordering.h> +#include <__config> +#include <__filesystem/file_status.h> +#include <__filesystem/file_time_type.h> +#include <__filesystem/file_type.h> +#include <__filesystem/filesystem_error.h> +#include <__filesystem/operations.h> +#include <__filesystem/path.h> +#include <__filesystem/perms.h> +#include <__system_error/errc.h> +#include <__system_error/error_code.h> +#include <__utility/move.h> +#include <__utility/unreachable.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_FILESYSTEM) + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH + +class directory_entry { + typedef filesystem::path _Path; + +public: + // constructors and destructors + _LIBCPP_HIDE_FROM_ABI directory_entry() noexcept = default; + _LIBCPP_HIDE_FROM_ABI directory_entry(directory_entry const&) = default; + _LIBCPP_HIDE_FROM_ABI directory_entry(directory_entry&&) noexcept = default; + + _LIBCPP_HIDE_FROM_ABI explicit directory_entry(_Path const& __p) : __p_(__p) { + error_code __ec; + __refresh(&__ec); + } + + _LIBCPP_HIDE_FROM_ABI directory_entry(_Path const& __p, error_code& __ec) : __p_(__p) { __refresh(&__ec); } + + _LIBCPP_HIDE_FROM_ABI ~directory_entry() {} + + _LIBCPP_HIDE_FROM_ABI directory_entry& operator=(directory_entry const&) = default; + _LIBCPP_HIDE_FROM_ABI directory_entry& operator=(directory_entry&&) noexcept = default; + + _LIBCPP_HIDE_FROM_ABI void assign(_Path const& __p) { + __p_ = __p; + error_code __ec; + __refresh(&__ec); + } + + _LIBCPP_HIDE_FROM_ABI void assign(_Path const& __p, error_code& __ec) { + __p_ = __p; + __refresh(&__ec); + } + + _LIBCPP_HIDE_FROM_ABI void replace_filename(_Path const& __p) { + __p_.replace_filename(__p); + error_code __ec; + __refresh(&__ec); + } + + _LIBCPP_HIDE_FROM_ABI void replace_filename(_Path const& __p, error_code& __ec) { + __p_ = __p_.parent_path() / __p; + __refresh(&__ec); + } + + _LIBCPP_HIDE_FROM_ABI void refresh() { __refresh(); } + + _LIBCPP_HIDE_FROM_ABI void refresh(error_code& __ec) noexcept { __refresh(&__ec); } + + _LIBCPP_HIDE_FROM_ABI _Path const& path() const noexcept { return __p_; } + + _LIBCPP_HIDE_FROM_ABI operator const _Path&() const noexcept { return __p_; } + + _LIBCPP_HIDE_FROM_ABI bool exists() const { return filesystem::exists(file_status{__get_ft()}); } + + _LIBCPP_HIDE_FROM_ABI bool exists(error_code& __ec) const noexcept { + return filesystem::exists(file_status{__get_ft(&__ec)}); + } + + _LIBCPP_HIDE_FROM_ABI bool is_block_file() const { return __get_ft() == file_type::block; } + + _LIBCPP_HIDE_FROM_ABI bool is_block_file(error_code& __ec) const noexcept { + return __get_ft(&__ec) == file_type::block; + } + + _LIBCPP_HIDE_FROM_ABI bool is_character_file() const { return __get_ft() == file_type::character; } + + _LIBCPP_HIDE_FROM_ABI bool is_character_file(error_code& __ec) const noexcept { + return __get_ft(&__ec) == file_type::character; + } + + _LIBCPP_HIDE_FROM_ABI bool is_directory() const { return __get_ft() == file_type::directory; } + + _LIBCPP_HIDE_FROM_ABI bool is_directory(error_code& __ec) const noexcept { + return __get_ft(&__ec) == file_type::directory; + } + + _LIBCPP_HIDE_FROM_ABI bool is_fifo() const { return __get_ft() == file_type::fifo; } + + _LIBCPP_HIDE_FROM_ABI bool is_fifo(error_code& __ec) const noexcept { return __get_ft(&__ec) == file_type::fifo; } + + _LIBCPP_HIDE_FROM_ABI bool is_other() const { return filesystem::is_other(file_status{__get_ft()}); } + + _LIBCPP_HIDE_FROM_ABI bool is_other(error_code& __ec) const noexcept { + return filesystem::is_other(file_status{__get_ft(&__ec)}); + } + + _LIBCPP_HIDE_FROM_ABI bool is_regular_file() const { return __get_ft() == file_type::regular; } + + _LIBCPP_HIDE_FROM_ABI bool is_regular_file(error_code& __ec) const noexcept { + return __get_ft(&__ec) == file_type::regular; + } + + _LIBCPP_HIDE_FROM_ABI bool is_socket() const { return __get_ft() == file_type::socket; } + + _LIBCPP_HIDE_FROM_ABI bool is_socket(error_code& __ec) const noexcept { return __get_ft(&__ec) == file_type::socket; } + + _LIBCPP_HIDE_FROM_ABI bool is_symlink() const { return __get_sym_ft() == file_type::symlink; } + + _LIBCPP_HIDE_FROM_ABI bool is_symlink(error_code& __ec) const noexcept { + return __get_sym_ft(&__ec) == file_type::symlink; + } + _LIBCPP_HIDE_FROM_ABI uintmax_t file_size() const { return __get_size(); } + + _LIBCPP_HIDE_FROM_ABI uintmax_t file_size(error_code& __ec) const noexcept { return __get_size(&__ec); } + + _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count() const { return __get_nlink(); } + + _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count(error_code& __ec) const noexcept { return __get_nlink(&__ec); } + + _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time() const { return __get_write_time(); } + + _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time(error_code& __ec) const noexcept { + return __get_write_time(&__ec); + } + + _LIBCPP_HIDE_FROM_ABI file_status status() const { return __get_status(); } + + _LIBCPP_HIDE_FROM_ABI file_status status(error_code& __ec) const noexcept { return __get_status(&__ec); } + + _LIBCPP_HIDE_FROM_ABI file_status symlink_status() const { return __get_symlink_status(); } + + _LIBCPP_HIDE_FROM_ABI file_status symlink_status(error_code& __ec) const noexcept { + return __get_symlink_status(&__ec); + } + + _LIBCPP_HIDE_FROM_ABI bool operator==(directory_entry const& __rhs) const noexcept { return __p_ == __rhs.__p_; } + +# if _LIBCPP_STD_VER <= 17 + _LIBCPP_HIDE_FROM_ABI bool operator!=(directory_entry const& __rhs) const noexcept { return __p_ != __rhs.__p_; } + + _LIBCPP_HIDE_FROM_ABI bool operator<(directory_entry const& __rhs) const noexcept { return __p_ < __rhs.__p_; } + + _LIBCPP_HIDE_FROM_ABI bool operator<=(directory_entry const& __rhs) const noexcept { return __p_ <= __rhs.__p_; } + + _LIBCPP_HIDE_FROM_ABI bool operator>(directory_entry const& __rhs) const noexcept { return __p_ > __rhs.__p_; } + + _LIBCPP_HIDE_FROM_ABI bool operator>=(directory_entry const& __rhs) const noexcept { return __p_ >= __rhs.__p_; } + +# else // _LIBCPP_STD_VER <= 17 + + _LIBCPP_HIDE_FROM_ABI strong_ordering operator<=>(const directory_entry& __rhs) const noexcept { + return __p_ <=> __rhs.__p_; + } + +# endif // _LIBCPP_STD_VER <= 17 + + template + _LIBCPP_HIDE_FROM_ABI friend basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, const directory_entry& __d) { + return __os << __d.path(); + } + +private: + friend class directory_iterator; + friend class recursive_directory_iterator; + friend class _LIBCPP_HIDDEN __dir_stream; + + enum _CacheType : unsigned char { + _Empty, + _IterSymlink, + _IterNonSymlink, + _RefreshSymlink, + _RefreshSymlinkUnresolved, + _RefreshNonSymlink + }; + + struct __cached_data { + uintmax_t __size_; + uintmax_t __nlink_; + file_time_type __write_time_; + perms __sym_perms_; + perms __non_sym_perms_; + file_type __type_; + _CacheType __cache_type_; + + _LIBCPP_HIDE_FROM_ABI __cached_data() noexcept { __reset(); } + + _LIBCPP_HIDE_FROM_ABI void __reset() { + __cache_type_ = _Empty; + __type_ = file_type::none; + __sym_perms_ = __non_sym_perms_ = perms::unknown; + __size_ = __nlink_ = uintmax_t(-1); + __write_time_ = file_time_type::min(); + } + }; + + _LIBCPP_HIDE_FROM_ABI static __cached_data __create_iter_result(file_type __ft) { + __cached_data __data; + __data.__type_ = __ft; + __data.__cache_type_ = [&]() { + switch (__ft) { + case file_type::none: + return _Empty; + case file_type::symlink: + return _IterSymlink; + default: + return _IterNonSymlink; + } + }(); + return __data; + } + + _LIBCPP_HIDE_FROM_ABI void __assign_iter_entry(_Path&& __p, __cached_data __dt) { + __p_ = std::move(__p); + __data_ = __dt; + } + + _LIBCPP_EXPORTED_FROM_ABI error_code __do_refresh() noexcept; + + _LIBCPP_HIDE_FROM_ABI static bool __is_dne_error(error_code const& __ec) { + if (!__ec) + return true; + switch (static_cast(__ec.value())) { + case errc::no_such_file_or_directory: + case errc::not_a_directory: + return true; + default: + return false; + } + } + + _LIBCPP_HIDE_FROM_ABI void + __handle_error(const char* __msg, error_code* __dest_ec, error_code const& __ec, bool __allow_dne = false) const { + if (__dest_ec) { + *__dest_ec = __ec; + return; + } + if (__ec && (!__allow_dne || !__is_dne_error(__ec))) + __throw_filesystem_error(__msg, __p_, __ec); + } + + _LIBCPP_HIDE_FROM_ABI void __refresh(error_code* __ec = nullptr) { + __handle_error("in directory_entry::refresh", + __ec, + __do_refresh(), + /*allow_dne*/ true); + } + + _LIBCPP_HIDE_FROM_ABI file_type __get_sym_ft(error_code* __ec = nullptr) const { + switch (__data_.__cache_type_) { + case _Empty: + return __symlink_status(__p_, __ec).type(); + case _IterSymlink: + case _RefreshSymlink: + case _RefreshSymlinkUnresolved: + if (__ec) + __ec->clear(); + return file_type::symlink; + case _IterNonSymlink: + case _RefreshNonSymlink: + file_status __st(__data_.__type_); + if (__ec && !filesystem::exists(__st)) + *__ec = make_error_code(errc::no_such_file_or_directory); + else if (__ec) + __ec->clear(); + return __data_.__type_; + } + __libcpp_unreachable(); + } + + _LIBCPP_HIDE_FROM_ABI file_type __get_ft(error_code* __ec = nullptr) const { + switch (__data_.__cache_type_) { + case _Empty: + case _IterSymlink: + case _RefreshSymlinkUnresolved: + return __status(__p_, __ec).type(); + case _IterNonSymlink: + case _RefreshNonSymlink: + case _RefreshSymlink: { + file_status __st(__data_.__type_); + if (__ec && !filesystem::exists(__st)) + *__ec = make_error_code(errc::no_such_file_or_directory); + else if (__ec) + __ec->clear(); + return __data_.__type_; + } + } + __libcpp_unreachable(); + } + + _LIBCPP_HIDE_FROM_ABI file_status __get_status(error_code* __ec = nullptr) const { + switch (__data_.__cache_type_) { + case _Empty: + case _IterNonSymlink: + case _IterSymlink: + case _RefreshSymlinkUnresolved: + return __status(__p_, __ec); + case _RefreshNonSymlink: + case _RefreshSymlink: + return file_status(__get_ft(__ec), __data_.__non_sym_perms_); + } + __libcpp_unreachable(); + } + + _LIBCPP_HIDE_FROM_ABI file_status __get_symlink_status(error_code* __ec = nullptr) const { + switch (__data_.__cache_type_) { + case _Empty: + case _IterNonSymlink: + case _IterSymlink: + return __symlink_status(__p_, __ec); + case _RefreshNonSymlink: + return file_status(__get_sym_ft(__ec), __data_.__non_sym_perms_); + case _RefreshSymlink: + case _RefreshSymlinkUnresolved: + return file_status(__get_sym_ft(__ec), __data_.__sym_perms_); + } + __libcpp_unreachable(); + } + + _LIBCPP_HIDE_FROM_ABI uintmax_t __get_size(error_code* __ec = nullptr) const { + switch (__data_.__cache_type_) { + case _Empty: + case _IterNonSymlink: + case _IterSymlink: + case _RefreshSymlinkUnresolved: + return filesystem::__file_size(__p_, __ec); + case _RefreshSymlink: + case _RefreshNonSymlink: { + error_code __m_ec; + file_status __st(__get_ft(&__m_ec)); + __handle_error("in directory_entry::file_size", __ec, __m_ec); + if (filesystem::exists(__st) && !filesystem::is_regular_file(__st)) { + errc __err_kind = filesystem::is_directory(__st) ? errc::is_a_directory : errc::not_supported; + __handle_error("in directory_entry::file_size", __ec, make_error_code(__err_kind)); + } + return __data_.__size_; + } + } + __libcpp_unreachable(); + } + + _LIBCPP_HIDE_FROM_ABI uintmax_t __get_nlink(error_code* __ec = nullptr) const { + switch (__data_.__cache_type_) { + case _Empty: + case _IterNonSymlink: + case _IterSymlink: + case _RefreshSymlinkUnresolved: + return filesystem::__hard_link_count(__p_, __ec); + case _RefreshSymlink: + case _RefreshNonSymlink: { + error_code __m_ec; + (void)__get_ft(&__m_ec); + __handle_error("in directory_entry::hard_link_count", __ec, __m_ec); + return __data_.__nlink_; + } + } + __libcpp_unreachable(); + } + + _LIBCPP_HIDE_FROM_ABI file_time_type __get_write_time(error_code* __ec = nullptr) const { + switch (__data_.__cache_type_) { + case _Empty: + case _IterNonSymlink: + case _IterSymlink: + case _RefreshSymlinkUnresolved: + return filesystem::__last_write_time(__p_, __ec); + case _RefreshSymlink: + case _RefreshNonSymlink: { + error_code __m_ec; + file_status __st(__get_ft(&__m_ec)); + __handle_error("in directory_entry::last_write_time", __ec, __m_ec); + if (filesystem::exists(__st) && __data_.__write_time_ == file_time_type::min()) + __handle_error("in directory_entry::last_write_time", __ec, make_error_code(errc::value_too_large)); + return __data_.__write_time_; + } + } + __libcpp_unreachable(); + } + +private: + _Path __p_; + __cached_data __data_; +}; + +class __dir_element_proxy { +public: + inline _LIBCPP_HIDE_FROM_ABI directory_entry operator*() { return std::move(__elem_); } + +private: + friend class directory_iterator; + friend class recursive_directory_iterator; + _LIBCPP_HIDE_FROM_ABI explicit __dir_element_proxy(directory_entry const& __e) : __elem_(__e) {} + _LIBCPP_HIDE_FROM_ABI __dir_element_proxy(__dir_element_proxy&& __o) : __elem_(std::move(__o.__elem_)) {} + directory_entry __elem_; +}; + +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +#endif // _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_FILESYSTEM) + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FILESYSTEM_DIRECTORY_ENTRY_H diff --git a/libcxx/include/__cxx03/__filesystem/directory_iterator.h b/libcxx/include/__cxx03/__filesystem/directory_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..e0246d8001e1952bef0d20835aa9c7032194ffd2 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/directory_iterator.h @@ -0,0 +1,151 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_DIRECTORY_ITERATOR_H +#define _LIBCPP___FILESYSTEM_DIRECTORY_ITERATOR_H + +#include <__assert> +#include <__config> +#include <__filesystem/directory_entry.h> +#include <__filesystem/directory_options.h> +#include <__filesystem/path.h> +#include <__iterator/default_sentinel.h> +#include <__iterator/iterator_traits.h> +#include <__memory/shared_ptr.h> +#include <__ranges/enable_borrowed_range.h> +#include <__ranges/enable_view.h> +#include <__system_error/error_code.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_FILESYSTEM) + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH + +class _LIBCPP_HIDDEN __dir_stream; +class directory_iterator { +public: + typedef directory_entry value_type; + typedef ptrdiff_t difference_type; + typedef value_type const* pointer; + typedef value_type const& reference; + typedef input_iterator_tag iterator_category; + +public: + // ctor & dtor + _LIBCPP_HIDE_FROM_ABI directory_iterator() noexcept {} + + _LIBCPP_HIDE_FROM_ABI explicit directory_iterator(const path& __p) : directory_iterator(__p, nullptr) {} + + _LIBCPP_HIDE_FROM_ABI directory_iterator(const path& __p, directory_options __opts) + : directory_iterator(__p, nullptr, __opts) {} + + _LIBCPP_HIDE_FROM_ABI directory_iterator(const path& __p, error_code& __ec) : directory_iterator(__p, &__ec) {} + + _LIBCPP_HIDE_FROM_ABI directory_iterator(const path& __p, directory_options __opts, error_code& __ec) + : directory_iterator(__p, &__ec, __opts) {} + + _LIBCPP_HIDE_FROM_ABI directory_iterator(const directory_iterator&) = default; + _LIBCPP_HIDE_FROM_ABI directory_iterator(directory_iterator&&) = default; + _LIBCPP_HIDE_FROM_ABI directory_iterator& operator=(const directory_iterator&) = default; + + _LIBCPP_HIDE_FROM_ABI directory_iterator& operator=(directory_iterator&& __o) noexcept { + // non-default implementation provided to support self-move assign. + if (this != &__o) { + __imp_ = std::move(__o.__imp_); + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI ~directory_iterator() = default; + + _LIBCPP_HIDE_FROM_ABI const directory_entry& operator*() const { + // Note: this check duplicates a check in `__dereference()`. + _LIBCPP_ASSERT_NON_NULL(__imp_, "The end iterator cannot be dereferenced"); + return __dereference(); + } + + _LIBCPP_HIDE_FROM_ABI const directory_entry* operator->() const { return &**this; } + + _LIBCPP_HIDE_FROM_ABI directory_iterator& operator++() { return __increment(); } + + _LIBCPP_HIDE_FROM_ABI __dir_element_proxy operator++(int) { + __dir_element_proxy __p(**this); + __increment(); + return __p; + } + + _LIBCPP_HIDE_FROM_ABI directory_iterator& increment(error_code& __ec) { return __increment(&__ec); } + +# if _LIBCPP_STD_VER >= 20 + + _LIBCPP_HIDE_FROM_ABI bool operator==(default_sentinel_t) const noexcept { return *this == directory_iterator(); } + +# endif + +private: + inline _LIBCPP_HIDE_FROM_ABI friend bool + operator==(const directory_iterator& __lhs, const directory_iterator& __rhs) noexcept; + + // construct the dir_stream + _LIBCPP_EXPORTED_FROM_ABI directory_iterator(const path&, error_code*, directory_options = directory_options::none); + + _LIBCPP_EXPORTED_FROM_ABI directory_iterator& __increment(error_code* __ec = nullptr); + + _LIBCPP_EXPORTED_FROM_ABI const directory_entry& __dereference() const; + +private: + shared_ptr<__dir_stream> __imp_; +}; + +inline _LIBCPP_HIDE_FROM_ABI bool +operator==(const directory_iterator& __lhs, const directory_iterator& __rhs) noexcept { + return __lhs.__imp_ == __rhs.__imp_; +} + +inline _LIBCPP_HIDE_FROM_ABI bool +operator!=(const directory_iterator& __lhs, const directory_iterator& __rhs) noexcept { + return !(__lhs == __rhs); +} + +// enable directory_iterator range-based for statements +inline _LIBCPP_HIDE_FROM_ABI directory_iterator begin(directory_iterator __iter) noexcept { return __iter; } + +inline _LIBCPP_HIDE_FROM_ABI directory_iterator end(directory_iterator) noexcept { return directory_iterator(); } + +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +# if _LIBCPP_STD_VER >= 20 + +template <> +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY inline constexpr bool + std::ranges::enable_borrowed_range = true; + +template <> +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY inline constexpr bool + std::ranges::enable_view = true; + +# endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_FILESYSTEM) + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FILESYSTEM_DIRECTORY_ITERATOR_H diff --git a/libcxx/include/__cxx03/__filesystem/directory_options.h b/libcxx/include/__cxx03/__filesystem/directory_options.h new file mode 100644 index 0000000000000000000000000000000000000000..d0cd3ebfdaa7ee798a123867142a89738a12a114 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/directory_options.h @@ -0,0 +1,57 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_DIRECTORY_OPTIONS_H +#define _LIBCPP___FILESYSTEM_DIRECTORY_OPTIONS_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +enum class directory_options : unsigned char { none = 0, follow_directory_symlink = 1, skip_permission_denied = 2 }; + +_LIBCPP_HIDE_FROM_ABI inline constexpr directory_options operator&(directory_options __lhs, directory_options __rhs) { + return static_cast(static_cast(__lhs) & static_cast(__rhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr directory_options operator|(directory_options __lhs, directory_options __rhs) { + return static_cast(static_cast(__lhs) | static_cast(__rhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr directory_options operator^(directory_options __lhs, directory_options __rhs) { + return static_cast(static_cast(__lhs) ^ static_cast(__rhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr directory_options operator~(directory_options __lhs) { + return static_cast(~static_cast(__lhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline directory_options& operator&=(directory_options& __lhs, directory_options __rhs) { + return __lhs = __lhs & __rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline directory_options& operator|=(directory_options& __lhs, directory_options __rhs) { + return __lhs = __lhs | __rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline directory_options& operator^=(directory_options& __lhs, directory_options __rhs) { + return __lhs = __lhs ^ __rhs; +} + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +#endif // _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___FILESYSTEM_DIRECTORY_OPTIONS_H diff --git a/libcxx/include/__cxx03/__filesystem/file_status.h b/libcxx/include/__cxx03/__filesystem/file_status.h new file mode 100644 index 0000000000000000000000000000000000000000..da316c8b027464f086d5d31b2272106c5fb59c69 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/file_status.h @@ -0,0 +1,67 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_FILE_STATUS_H +#define _LIBCPP___FILESYSTEM_FILE_STATUS_H + +#include <__config> +#include <__filesystem/file_type.h> +#include <__filesystem/perms.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +class _LIBCPP_EXPORTED_FROM_ABI file_status { +public: + // constructors + _LIBCPP_HIDE_FROM_ABI file_status() noexcept : file_status(file_type::none) {} + _LIBCPP_HIDE_FROM_ABI explicit file_status(file_type __ft, perms __prms = perms::unknown) noexcept + : __ft_(__ft), __prms_(__prms) {} + + _LIBCPP_HIDE_FROM_ABI file_status(const file_status&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI file_status(file_status&&) noexcept = default; + + _LIBCPP_HIDE_FROM_ABI ~file_status() {} + + _LIBCPP_HIDE_FROM_ABI file_status& operator=(const file_status&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI file_status& operator=(file_status&&) noexcept = default; + + // observers + _LIBCPP_HIDE_FROM_ABI file_type type() const noexcept { return __ft_; } + + _LIBCPP_HIDE_FROM_ABI perms permissions() const noexcept { return __prms_; } + + // modifiers + _LIBCPP_HIDE_FROM_ABI void type(file_type __ft) noexcept { __ft_ = __ft; } + + _LIBCPP_HIDE_FROM_ABI void permissions(perms __p) noexcept { __prms_ = __p; } + +# if _LIBCPP_STD_VER >= 20 + + _LIBCPP_HIDE_FROM_ABI friend bool operator==(const file_status& __lhs, const file_status& __rhs) noexcept { + return __lhs.type() == __rhs.type() && __lhs.permissions() == __rhs.permissions(); + } + +# endif + +private: + file_type __ft_; + perms __prms_; +}; + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +#endif // _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___FILESYSTEM_FILE_STATUS_H diff --git a/libcxx/include/__cxx03/__filesystem/file_time_type.h b/libcxx/include/__cxx03/__filesystem/file_time_type.h new file mode 100644 index 0000000000000000000000000000000000000000..63e4ae1578cfd9f8fbf88be261c22f27f712d5d3 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/file_time_type.h @@ -0,0 +1,31 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_FILE_TIME_TYPE_H +#define _LIBCPP___FILESYSTEM_FILE_TIME_TYPE_H + +#include <__chrono/file_clock.h> +#include <__chrono/time_point.h> +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +typedef chrono::time_point<_FilesystemClock> file_time_type; + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +#endif // _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___FILESYSTEM_FILE_TIME_TYPE_H diff --git a/libcxx/include/__cxx03/__filesystem/file_type.h b/libcxx/include/__cxx03/__filesystem/file_type.h new file mode 100644 index 0000000000000000000000000000000000000000..e4ac1dfee9ed9b6d8fb7a9c871885db4457a7340 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/file_type.h @@ -0,0 +1,42 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_FILE_TYPE_H +#define _LIBCPP___FILESYSTEM_FILE_TYPE_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +// On Windows, the library never identifies files as block, character, fifo +// or socket. +enum class file_type : signed char { + none = 0, + not_found = -1, + regular = 1, + directory = 2, + symlink = 3, + block = 4, + character = 5, + fifo = 6, + socket = 7, + unknown = 8 +}; + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +#endif // _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___FILESYSTEM_FILE_TYPE_H diff --git a/libcxx/include/__cxx03/__filesystem/filesystem_error.h b/libcxx/include/__cxx03/__filesystem/filesystem_error.h new file mode 100644 index 0000000000000000000000000000000000000000..80a11e3b1932c785abc26316b388a05d22f699f7 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/filesystem_error.h @@ -0,0 +1,88 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_FILESYSTEM_ERROR_H +#define _LIBCPP___FILESYSTEM_FILESYSTEM_ERROR_H + +#include <__config> +#include <__filesystem/path.h> +#include <__memory/shared_ptr.h> +#include <__system_error/error_code.h> +#include <__system_error/system_error.h> +#include <__utility/forward.h> +#include <__verbose_abort> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +class _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_EXPORTED_FROM_ABI filesystem_error : public system_error { +public: + _LIBCPP_HIDE_FROM_ABI filesystem_error(const string& __what, error_code __ec) + : system_error(__ec, __what), __storage_(make_shared<_Storage>(path(), path())) { + __create_what(0); + } + + _LIBCPP_HIDE_FROM_ABI filesystem_error(const string& __what, const path& __p1, error_code __ec) + : system_error(__ec, __what), __storage_(make_shared<_Storage>(__p1, path())) { + __create_what(1); + } + + _LIBCPP_HIDE_FROM_ABI filesystem_error(const string& __what, const path& __p1, const path& __p2, error_code __ec) + : system_error(__ec, __what), __storage_(make_shared<_Storage>(__p1, __p2)) { + __create_what(2); + } + + _LIBCPP_HIDE_FROM_ABI const path& path1() const noexcept { return __storage_->__p1_; } + + _LIBCPP_HIDE_FROM_ABI const path& path2() const noexcept { return __storage_->__p2_; } + + _LIBCPP_HIDE_FROM_ABI filesystem_error(const filesystem_error&) = default; + ~filesystem_error() override; // key function + + _LIBCPP_HIDE_FROM_ABI_VIRTUAL + const char* what() const noexcept override { return __storage_->__what_.c_str(); } + + void __create_what(int __num_paths); + +private: + struct _LIBCPP_HIDDEN _Storage { + _LIBCPP_HIDE_FROM_ABI _Storage(const path& __p1, const path& __p2) : __p1_(__p1), __p2_(__p2) {} + + path __p1_; + path __p2_; + string __what_; + }; + shared_ptr<_Storage> __storage_; +}; + +# ifndef _LIBCPP_HAS_NO_EXCEPTIONS +template +_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY void +__throw_filesystem_error(_Args&&... __args) { + throw filesystem_error(std::forward<_Args>(__args)...); +} +# else +template +_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY void +__throw_filesystem_error(_Args&&...) { + _LIBCPP_VERBOSE_ABORT("filesystem_error was thrown in -fno-exceptions mode"); +} +# endif + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +#endif // _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___FILESYSTEM_FILESYSTEM_ERROR_H diff --git a/libcxx/include/__cxx03/__filesystem/operations.h b/libcxx/include/__cxx03/__filesystem/operations.h new file mode 100644 index 0000000000000000000000000000000000000000..f588189ed1d9de33e9956af08a6bdb9425b37edd --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/operations.h @@ -0,0 +1,310 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_OPERATIONS_H +#define _LIBCPP___FILESYSTEM_OPERATIONS_H + +#include <__chrono/time_point.h> +#include <__config> +#include <__filesystem/copy_options.h> +#include <__filesystem/file_status.h> +#include <__filesystem/file_time_type.h> +#include <__filesystem/file_type.h> +#include <__filesystem/path.h> +#include <__filesystem/perm_options.h> +#include <__filesystem/perms.h> +#include <__filesystem/space_info.h> +#include <__system_error/error_code.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_FILESYSTEM) + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH + +_LIBCPP_EXPORTED_FROM_ABI path __absolute(const path&, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI path __canonical(const path&, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI bool +__copy_file(const path& __from, const path& __to, copy_options __opt, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI void +__copy_symlink(const path& __existing_symlink, const path& __new_symlink, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI void +__copy(const path& __from, const path& __to, copy_options __opt, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI bool __create_directories(const path&, error_code* = nullptr); +_LIBCPP_EXPORTED_FROM_ABI void +__create_directory_symlink(const path& __to, const path& __new_symlink, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI bool __create_directory(const path&, error_code* = nullptr); +_LIBCPP_EXPORTED_FROM_ABI bool __create_directory(const path&, const path& __attributes, error_code* = nullptr); +_LIBCPP_EXPORTED_FROM_ABI void +__create_hard_link(const path& __to, const path& __new_hard_link, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI void +__create_symlink(const path& __to, const path& __new_symlink, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI path __current_path(error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI void __current_path(const path&, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI bool __equivalent(const path&, const path&, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI file_status __status(const path&, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI uintmax_t __file_size(const path&, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI uintmax_t __hard_link_count(const path&, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI file_status __symlink_status(const path&, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI file_time_type __last_write_time(const path&, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI void __last_write_time(const path&, file_time_type __new_time, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI path __weakly_canonical(path const& __p, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI path __read_symlink(const path&, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI uintmax_t __remove_all(const path&, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI bool __remove(const path&, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI void __rename(const path& __from, const path& __to, error_code* __ec = nullptr); +_LIBCPP_EXPORTED_FROM_ABI void __resize_file(const path&, uintmax_t __size, error_code* = nullptr); +_LIBCPP_EXPORTED_FROM_ABI path __temp_directory_path(error_code* __ec = nullptr); + +inline _LIBCPP_HIDE_FROM_ABI path absolute(const path& __p) { return __absolute(__p); } +inline _LIBCPP_HIDE_FROM_ABI path absolute(const path& __p, error_code& __ec) { return __absolute(__p, &__ec); } +inline _LIBCPP_HIDE_FROM_ABI path canonical(const path& __p) { return __canonical(__p); } +inline _LIBCPP_HIDE_FROM_ABI path canonical(const path& __p, error_code& __ec) { return __canonical(__p, &__ec); } +inline _LIBCPP_HIDE_FROM_ABI bool copy_file(const path& __from, const path& __to) { + return __copy_file(__from, __to, copy_options::none); +} +inline _LIBCPP_HIDE_FROM_ABI bool copy_file(const path& __from, const path& __to, error_code& __ec) { + return __copy_file(__from, __to, copy_options::none, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI bool copy_file(const path& __from, const path& __to, copy_options __opt) { + return __copy_file(__from, __to, __opt); +} +inline _LIBCPP_HIDE_FROM_ABI bool +copy_file(const path& __from, const path& __to, copy_options __opt, error_code& __ec) { + return __copy_file(__from, __to, __opt, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI void copy_symlink(const path& __from, const path& __to) { __copy_symlink(__from, __to); } +inline _LIBCPP_HIDE_FROM_ABI void copy_symlink(const path& __from, const path& __to, error_code& __ec) noexcept { + __copy_symlink(__from, __to, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI void copy(const path& __from, const path& __to) { + __copy(__from, __to, copy_options::none); +} +inline _LIBCPP_HIDE_FROM_ABI void copy(const path& __from, const path& __to, error_code& __ec) { + __copy(__from, __to, copy_options::none, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI void copy(const path& __from, const path& __to, copy_options __opt) { + __copy(__from, __to, __opt); +} +inline _LIBCPP_HIDE_FROM_ABI void copy(const path& __from, const path& __to, copy_options __opt, error_code& __ec) { + __copy(__from, __to, __opt, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI bool create_directories(const path& __p) { return __create_directories(__p); } +inline _LIBCPP_HIDE_FROM_ABI bool create_directories(const path& __p, error_code& __ec) { + return __create_directories(__p, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI void create_directory_symlink(const path& __target, const path& __link) { + __create_directory_symlink(__target, __link); +} +inline _LIBCPP_HIDE_FROM_ABI void +create_directory_symlink(const path& __target, const path& __link, error_code& __ec) noexcept { + __create_directory_symlink(__target, __link, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI bool create_directory(const path& __p) { return __create_directory(__p); } +inline _LIBCPP_HIDE_FROM_ABI bool create_directory(const path& __p, error_code& __ec) noexcept { + return __create_directory(__p, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI bool create_directory(const path& __p, const path& __attrs) { + return __create_directory(__p, __attrs); +} +inline _LIBCPP_HIDE_FROM_ABI bool create_directory(const path& __p, const path& __attrs, error_code& __ec) noexcept { + return __create_directory(__p, __attrs, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI void create_hard_link(const path& __target, const path& __link) { + __create_hard_link(__target, __link); +} +inline _LIBCPP_HIDE_FROM_ABI void +create_hard_link(const path& __target, const path& __link, error_code& __ec) noexcept { + __create_hard_link(__target, __link, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI void create_symlink(const path& __target, const path& __link) { + __create_symlink(__target, __link); +} +inline _LIBCPP_HIDE_FROM_ABI void create_symlink(const path& __target, const path& __link, error_code& __ec) noexcept { + return __create_symlink(__target, __link, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI path current_path() { return __current_path(); } +inline _LIBCPP_HIDE_FROM_ABI path current_path(error_code& __ec) { return __current_path(&__ec); } +inline _LIBCPP_HIDE_FROM_ABI void current_path(const path& __p) { __current_path(__p); } +inline _LIBCPP_HIDE_FROM_ABI void current_path(const path& __p, error_code& __ec) noexcept { + __current_path(__p, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI bool equivalent(const path& __p1, const path& __p2) { return __equivalent(__p1, __p2); } +inline _LIBCPP_HIDE_FROM_ABI bool equivalent(const path& __p1, const path& __p2, error_code& __ec) noexcept { + return __equivalent(__p1, __p2, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI bool status_known(file_status __s) noexcept { return __s.type() != file_type::none; } +inline _LIBCPP_HIDE_FROM_ABI bool exists(file_status __s) noexcept { + return status_known(__s) && __s.type() != file_type::not_found; +} +inline _LIBCPP_HIDE_FROM_ABI bool exists(const path& __p) { return exists(__status(__p)); } + +inline _LIBCPP_HIDE_FROM_ABI bool exists(const path& __p, error_code& __ec) noexcept { + auto __s = __status(__p, &__ec); + if (status_known(__s)) + __ec.clear(); + return exists(__s); +} + +inline _LIBCPP_HIDE_FROM_ABI uintmax_t file_size(const path& __p) { return __file_size(__p); } +inline _LIBCPP_HIDE_FROM_ABI uintmax_t file_size(const path& __p, error_code& __ec) noexcept { + return __file_size(__p, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count(const path& __p) { return __hard_link_count(__p); } +inline _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count(const path& __p, error_code& __ec) noexcept { + return __hard_link_count(__p, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI bool is_block_file(file_status __s) noexcept { return __s.type() == file_type::block; } +inline _LIBCPP_HIDE_FROM_ABI bool is_block_file(const path& __p) { return is_block_file(__status(__p)); } +inline _LIBCPP_HIDE_FROM_ABI bool is_block_file(const path& __p, error_code& __ec) noexcept { + return is_block_file(__status(__p, &__ec)); +} +inline _LIBCPP_HIDE_FROM_ABI bool is_character_file(file_status __s) noexcept { + return __s.type() == file_type::character; +} +inline _LIBCPP_HIDE_FROM_ABI bool is_character_file(const path& __p) { return is_character_file(__status(__p)); } +inline _LIBCPP_HIDE_FROM_ABI bool is_character_file(const path& __p, error_code& __ec) noexcept { + return is_character_file(__status(__p, &__ec)); +} +inline _LIBCPP_HIDE_FROM_ABI bool is_directory(file_status __s) noexcept { return __s.type() == file_type::directory; } +inline _LIBCPP_HIDE_FROM_ABI bool is_directory(const path& __p) { return is_directory(__status(__p)); } +inline _LIBCPP_HIDE_FROM_ABI bool is_directory(const path& __p, error_code& __ec) noexcept { + return is_directory(__status(__p, &__ec)); +} +_LIBCPP_EXPORTED_FROM_ABI bool __fs_is_empty(const path& __p, error_code* __ec = nullptr); +inline _LIBCPP_HIDE_FROM_ABI bool is_empty(const path& __p) { return __fs_is_empty(__p); } +inline _LIBCPP_HIDE_FROM_ABI bool is_empty(const path& __p, error_code& __ec) { return __fs_is_empty(__p, &__ec); } +inline _LIBCPP_HIDE_FROM_ABI bool is_fifo(file_status __s) noexcept { return __s.type() == file_type::fifo; } +inline _LIBCPP_HIDE_FROM_ABI bool is_fifo(const path& __p) { return is_fifo(__status(__p)); } +inline _LIBCPP_HIDE_FROM_ABI bool is_fifo(const path& __p, error_code& __ec) noexcept { + return is_fifo(__status(__p, &__ec)); +} +inline _LIBCPP_HIDE_FROM_ABI bool is_regular_file(file_status __s) noexcept { return __s.type() == file_type::regular; } +inline _LIBCPP_HIDE_FROM_ABI bool is_regular_file(const path& __p) { return is_regular_file(__status(__p)); } +inline _LIBCPP_HIDE_FROM_ABI bool is_regular_file(const path& __p, error_code& __ec) noexcept { + return is_regular_file(__status(__p, &__ec)); +} +inline _LIBCPP_HIDE_FROM_ABI bool is_symlink(file_status __s) noexcept { return __s.type() == file_type::symlink; } +inline _LIBCPP_HIDE_FROM_ABI bool is_symlink(const path& __p) { return is_symlink(__symlink_status(__p)); } +inline _LIBCPP_HIDE_FROM_ABI bool is_symlink(const path& __p, error_code& __ec) noexcept { + return is_symlink(__symlink_status(__p, &__ec)); +} +inline _LIBCPP_HIDE_FROM_ABI bool is_other(file_status __s) noexcept { + return exists(__s) && !is_regular_file(__s) && !is_directory(__s) && !is_symlink(__s); +} +inline _LIBCPP_HIDE_FROM_ABI bool is_other(const path& __p) { return is_other(__status(__p)); } +inline _LIBCPP_HIDE_FROM_ABI bool is_other(const path& __p, error_code& __ec) noexcept { + return is_other(__status(__p, &__ec)); +} +inline _LIBCPP_HIDE_FROM_ABI bool is_socket(file_status __s) noexcept { return __s.type() == file_type::socket; } +inline _LIBCPP_HIDE_FROM_ABI bool is_socket(const path& __p) { return is_socket(__status(__p)); } +inline _LIBCPP_HIDE_FROM_ABI bool is_socket(const path& __p, error_code& __ec) noexcept { + return is_socket(__status(__p, &__ec)); +} +inline _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time(const path& __p) { return __last_write_time(__p); } +inline _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time(const path& __p, error_code& __ec) noexcept { + return __last_write_time(__p, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI void last_write_time(const path& __p, file_time_type __t) { __last_write_time(__p, __t); } +inline _LIBCPP_HIDE_FROM_ABI void last_write_time(const path& __p, file_time_type __t, error_code& __ec) noexcept { + __last_write_time(__p, __t, &__ec); +} +_LIBCPP_EXPORTED_FROM_ABI void __permissions(const path&, perms, perm_options, error_code* = nullptr); +inline _LIBCPP_HIDE_FROM_ABI void +permissions(const path& __p, perms __prms, perm_options __opts = perm_options::replace) { + __permissions(__p, __prms, __opts); +} +inline _LIBCPP_HIDE_FROM_ABI void permissions(const path& __p, perms __prms, error_code& __ec) noexcept { + __permissions(__p, __prms, perm_options::replace, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI void permissions(const path& __p, perms __prms, perm_options __opts, error_code& __ec) { + __permissions(__p, __prms, __opts, &__ec); +} + +inline _LIBCPP_HIDE_FROM_ABI path proximate(const path& __p, const path& __base, error_code& __ec) { + path __tmp = __weakly_canonical(__p, &__ec); + if (__ec) + return {}; + path __tmp_base = __weakly_canonical(__base, &__ec); + if (__ec) + return {}; + return __tmp.lexically_proximate(__tmp_base); +} + +inline _LIBCPP_HIDE_FROM_ABI path proximate(const path& __p, error_code& __ec) { + return proximate(__p, current_path(), __ec); +} +inline _LIBCPP_HIDE_FROM_ABI path proximate(const path& __p, const path& __base = current_path()) { + return __weakly_canonical(__p).lexically_proximate(__weakly_canonical(__base)); +} +inline _LIBCPP_HIDE_FROM_ABI path read_symlink(const path& __p) { return __read_symlink(__p); } +inline _LIBCPP_HIDE_FROM_ABI path read_symlink(const path& __p, error_code& __ec) { return __read_symlink(__p, &__ec); } + +inline _LIBCPP_HIDE_FROM_ABI path relative(const path& __p, const path& __base, error_code& __ec) { + path __tmp = __weakly_canonical(__p, &__ec); + if (__ec) + return path(); + path __tmpbase = __weakly_canonical(__base, &__ec); + if (__ec) + return path(); + return __tmp.lexically_relative(__tmpbase); +} + +inline _LIBCPP_HIDE_FROM_ABI path relative(const path& __p, error_code& __ec) { + return relative(__p, current_path(), __ec); +} +inline _LIBCPP_HIDE_FROM_ABI path relative(const path& __p, const path& __base = current_path()) { + return __weakly_canonical(__p).lexically_relative(__weakly_canonical(__base)); +} +inline _LIBCPP_HIDE_FROM_ABI uintmax_t remove_all(const path& __p) { return __remove_all(__p); } +inline _LIBCPP_HIDE_FROM_ABI uintmax_t remove_all(const path& __p, error_code& __ec) { + return __remove_all(__p, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI bool remove(const path& __p) { return __remove(__p); } +inline _LIBCPP_HIDE_FROM_ABI bool remove(const path& __p, error_code& __ec) noexcept { return __remove(__p, &__ec); } +inline _LIBCPP_HIDE_FROM_ABI void rename(const path& __from, const path& __to) { return __rename(__from, __to); } +inline _LIBCPP_HIDE_FROM_ABI void rename(const path& __from, const path& __to, error_code& __ec) noexcept { + return __rename(__from, __to, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI void resize_file(const path& __p, uintmax_t __ns) { return __resize_file(__p, __ns); } +inline _LIBCPP_HIDE_FROM_ABI void resize_file(const path& __p, uintmax_t __ns, error_code& __ec) noexcept { + return __resize_file(__p, __ns, &__ec); +} +_LIBCPP_EXPORTED_FROM_ABI space_info __space(const path&, error_code* __ec = nullptr); +inline _LIBCPP_HIDE_FROM_ABI space_info space(const path& __p) { return __space(__p); } +inline _LIBCPP_HIDE_FROM_ABI space_info space(const path& __p, error_code& __ec) noexcept { + return __space(__p, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI file_status status(const path& __p) { return __status(__p); } +inline _LIBCPP_HIDE_FROM_ABI file_status status(const path& __p, error_code& __ec) noexcept { + return __status(__p, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI file_status symlink_status(const path& __p) { return __symlink_status(__p); } +inline _LIBCPP_HIDE_FROM_ABI file_status symlink_status(const path& __p, error_code& __ec) noexcept { + return __symlink_status(__p, &__ec); +} +inline _LIBCPP_HIDE_FROM_ABI path temp_directory_path() { return __temp_directory_path(); } +inline _LIBCPP_HIDE_FROM_ABI path temp_directory_path(error_code& __ec) { return __temp_directory_path(&__ec); } +inline _LIBCPP_HIDE_FROM_ABI path weakly_canonical(path const& __p) { return __weakly_canonical(__p); } +inline _LIBCPP_HIDE_FROM_ABI path weakly_canonical(path const& __p, error_code& __ec) { + return __weakly_canonical(__p, &__ec); +} + +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +#endif // _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_FILESYSTEM) + +#endif // _LIBCPP___FILESYSTEM_OPERATIONS_H diff --git a/libcxx/include/__cxx03/__filesystem/path.h b/libcxx/include/__cxx03/__filesystem/path.h new file mode 100644 index 0000000000000000000000000000000000000000..ff468d517722fe9d129993ade505a7cb40371361 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/path.h @@ -0,0 +1,931 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_PATH_H +#define _LIBCPP___FILESYSTEM_PATH_H + +#include <__algorithm/replace.h> +#include <__algorithm/replace_copy.h> +#include <__config> +#include <__functional/unary_function.h> +#include <__fwd/functional.h> +#include <__iterator/back_insert_iterator.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/decay.h> +#include <__type_traits/is_pointer.h> +#include <__type_traits/remove_const.h> +#include <__type_traits/remove_pointer.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include // for quoted +# include +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH + +template +struct __can_convert_char { + static const bool value = false; +}; +template +struct __can_convert_char : public __can_convert_char<_Tp> {}; +template <> +struct __can_convert_char { + static const bool value = true; + using __char_type = char; +}; +template <> +struct __can_convert_char { + static const bool value = true; + using __char_type = wchar_t; +}; +# ifndef _LIBCPP_HAS_NO_CHAR8_T +template <> +struct __can_convert_char { + static const bool value = true; + using __char_type = char8_t; +}; +# endif +template <> +struct __can_convert_char { + static const bool value = true; + using __char_type = char16_t; +}; +template <> +struct __can_convert_char { + static const bool value = true; + using __char_type = char32_t; +}; + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI bool __is_separator(_ECharT __e) { +# if defined(_LIBCPP_WIN32API) + return __e == _ECharT('/') || __e == _ECharT('\\'); +# else + return __e == _ECharT('/'); +# endif +} + +# ifndef _LIBCPP_HAS_NO_CHAR8_T +typedef u8string __u8_string; +# else +typedef string __u8_string; +# endif + +struct _NullSentinel {}; + +template +using _Void = void; + +template +struct __is_pathable_string : public false_type {}; + +template +struct __is_pathable_string< basic_string<_ECharT, _Traits, _Alloc>, + _Void::__char_type> > + : public __can_convert_char<_ECharT> { + using _Str = basic_string<_ECharT, _Traits, _Alloc>; + + _LIBCPP_HIDE_FROM_ABI static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); } + + _LIBCPP_HIDE_FROM_ABI static _ECharT const* __range_end(_Str const& __s) { return __s.data() + __s.length(); } + + _LIBCPP_HIDE_FROM_ABI static _ECharT __first_or_null(_Str const& __s) { return __s.empty() ? _ECharT{} : __s[0]; } +}; + +template +struct __is_pathable_string< basic_string_view<_ECharT, _Traits>, + _Void::__char_type> > + : public __can_convert_char<_ECharT> { + using _Str = basic_string_view<_ECharT, _Traits>; + + _LIBCPP_HIDE_FROM_ABI static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); } + + _LIBCPP_HIDE_FROM_ABI static _ECharT const* __range_end(_Str const& __s) { return __s.data() + __s.length(); } + + _LIBCPP_HIDE_FROM_ABI static _ECharT __first_or_null(_Str const& __s) { return __s.empty() ? _ECharT{} : __s[0]; } +}; + +template , + class _UnqualPtrType = __remove_const_t<__remove_pointer_t<_DS> >, + bool _IsCharPtr = is_pointer<_DS>::value && __can_convert_char<_UnqualPtrType>::value> +struct __is_pathable_char_array : false_type {}; + +template +struct __is_pathable_char_array<_Source, _ECharT*, _UPtr, true> : __can_convert_char<__remove_const_t<_ECharT> > { + _LIBCPP_HIDE_FROM_ABI static _ECharT const* __range_begin(const _ECharT* __b) { return __b; } + + _LIBCPP_HIDE_FROM_ABI static _ECharT const* __range_end(const _ECharT* __b) { + using _Iter = const _ECharT*; + const _ECharT __sentinel = _ECharT{}; + _Iter __e = __b; + for (; *__e != __sentinel; ++__e) + ; + return __e; + } + + _LIBCPP_HIDE_FROM_ABI static _ECharT __first_or_null(const _ECharT* __b) { return *__b; } +}; + +template ::value, class = void> +struct __is_pathable_iter : false_type {}; + +template +struct __is_pathable_iter< + _Iter, + true, + _Void::value_type>::__char_type> > + : __can_convert_char::value_type> { + using _ECharT = typename iterator_traits<_Iter>::value_type; + + _LIBCPP_HIDE_FROM_ABI static _Iter __range_begin(_Iter __b) { return __b; } + + _LIBCPP_HIDE_FROM_ABI static _NullSentinel __range_end(_Iter) { return _NullSentinel{}; } + + _LIBCPP_HIDE_FROM_ABI static _ECharT __first_or_null(_Iter __b) { return *__b; } +}; + +template ::value, + bool _IsCharIterT = __is_pathable_char_array<_Tp>::value, + bool _IsIterT = !_IsCharIterT && __is_pathable_iter<_Tp>::value> +struct __is_pathable : false_type { + static_assert(!_IsStringT && !_IsCharIterT && !_IsIterT, "Must all be false"); +}; + +template +struct __is_pathable<_Tp, true, false, false> : __is_pathable_string<_Tp> {}; + +template +struct __is_pathable<_Tp, false, true, false> : __is_pathable_char_array<_Tp> {}; + +template +struct __is_pathable<_Tp, false, false, true> : __is_pathable_iter<_Tp> {}; + +# if defined(_LIBCPP_WIN32API) +typedef wstring __path_string; +typedef wchar_t __path_value; +# else +typedef string __path_string; +typedef char __path_value; +# endif + +# if defined(_LIBCPP_WIN32API) +_LIBCPP_EXPORTED_FROM_ABI size_t __wide_to_char(const wstring&, char*, size_t); +_LIBCPP_EXPORTED_FROM_ABI size_t __char_to_wide(const string&, wchar_t*, size_t); +# endif + +template +struct _PathCVT; + +# if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +template +struct _PathCVT { + static_assert(__can_convert_char<_ECharT>::value, "Char type not convertible"); + + typedef __narrow_to_utf8 _Narrower; +# if defined(_LIBCPP_WIN32API) + typedef __widen_from_utf8 _Widener; +# endif + + _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _ECharT const* __b, _ECharT const* __e) { +# if defined(_LIBCPP_WIN32API) + string __utf8; + _Narrower()(back_inserter(__utf8), __b, __e); + _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size()); +# else + _Narrower()(back_inserter(__dest), __b, __e); +# endif + } + + template + _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _Iter __e) { + static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload"); + if (__b == __e) + return; + basic_string<_ECharT> __tmp(__b, __e); +# if defined(_LIBCPP_WIN32API) + string __utf8; + _Narrower()(back_inserter(__utf8), __tmp.data(), __tmp.data() + __tmp.length()); + _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size()); +# else + _Narrower()(back_inserter(__dest), __tmp.data(), __tmp.data() + __tmp.length()); +# endif + } + + template + _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) { + static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload"); + const _ECharT __sentinel = _ECharT{}; + if (*__b == __sentinel) + return; + basic_string<_ECharT> __tmp; + for (; *__b != __sentinel; ++__b) + __tmp.push_back(*__b); +# if defined(_LIBCPP_WIN32API) + string __utf8; + _Narrower()(back_inserter(__utf8), __tmp.data(), __tmp.data() + __tmp.length()); + _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size()); +# else + _Narrower()(back_inserter(__dest), __tmp.data(), __tmp.data() + __tmp.length()); +# endif + } + + template + _LIBCPP_HIDE_FROM_ABI static void __append_source(__path_string& __dest, _Source const& __s) { + using _Traits = __is_pathable<_Source>; + __append_range(__dest, _Traits::__range_begin(__s), _Traits::__range_end(__s)); + } +}; +# endif // !_LIBCPP_HAS_NO_LOCALIZATION + +template <> +struct _PathCVT<__path_value> { + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _Iter __e) { + for (; __b != __e; ++__b) + __dest.push_back(*__b); + } + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _Iter __e) { + __dest.append(__b, __e); + } + + template + _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) { + const char __sentinel = char{}; + for (; *__b != __sentinel; ++__b) + __dest.push_back(*__b); + } + + template + _LIBCPP_HIDE_FROM_ABI static void __append_source(__path_string& __dest, _Source const& __s) { + using _Traits = __is_pathable<_Source>; + __append_range(__dest, _Traits::__range_begin(__s), _Traits::__range_end(__s)); + } +}; + +# if defined(_LIBCPP_WIN32API) +template <> +struct _PathCVT { + _LIBCPP_HIDE_FROM_ABI static void __append_string(__path_string& __dest, const basic_string& __str) { + size_t __size = __char_to_wide(__str, nullptr, 0); + size_t __pos = __dest.size(); + __dest.resize(__pos + __size); + __char_to_wide(__str, const_cast<__path_value*>(__dest.data()) + __pos, __size); + } + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _Iter __e) { + basic_string __tmp(__b, __e); + __append_string(__dest, __tmp); + } + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _Iter __e) { + basic_string __tmp(__b, __e); + __append_string(__dest, __tmp); + } + + template + _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) { + const char __sentinel = char{}; + basic_string __tmp; + for (; *__b != __sentinel; ++__b) + __tmp.push_back(*__b); + __append_string(__dest, __tmp); + } + + template + _LIBCPP_HIDE_FROM_ABI static void __append_source(__path_string& __dest, _Source const& __s) { + using _Traits = __is_pathable<_Source>; + __append_range(__dest, _Traits::__range_begin(__s), _Traits::__range_end(__s)); + } +}; + +template +struct _PathExport { + typedef __narrow_to_utf8 _Narrower; + typedef __widen_from_utf8 _Widener; + + template + _LIBCPP_HIDE_FROM_ABI static void __append(_Str& __dest, const __path_string& __src) { + string __utf8; + _Narrower()(back_inserter(__utf8), __src.data(), __src.data() + __src.size()); + _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size()); + } +}; + +template <> +struct _PathExport { + template + _LIBCPP_HIDE_FROM_ABI static void __append(_Str& __dest, const __path_string& __src) { + size_t __size = __wide_to_char(__src, nullptr, 0); + size_t __pos = __dest.size(); + __dest.resize(__size); + __wide_to_char(__src, const_cast(__dest.data()) + __pos, __size); + } +}; + +template <> +struct _PathExport { + template + _LIBCPP_HIDE_FROM_ABI static void __append(_Str& __dest, const __path_string& __src) { + __dest.append(__src.begin(), __src.end()); + } +}; + +template <> +struct _PathExport { + template + _LIBCPP_HIDE_FROM_ABI static void __append(_Str& __dest, const __path_string& __src) { + __dest.append(__src.begin(), __src.end()); + } +}; + +# ifndef _LIBCPP_HAS_NO_CHAR8_T +template <> +struct _PathExport { + typedef __narrow_to_utf8 _Narrower; + + template + _LIBCPP_HIDE_FROM_ABI static void __append(_Str& __dest, const __path_string& __src) { + _Narrower()(back_inserter(__dest), __src.data(), __src.data() + __src.size()); + } +}; +# endif /* !_LIBCPP_HAS_NO_CHAR8_T */ +# endif /* _LIBCPP_WIN32API */ + +class _LIBCPP_EXPORTED_FROM_ABI path { + template + using _EnableIfPathable = __enable_if_t<__is_pathable<_SourceOrIter>::value, _Tp>; + + template + using _SourceChar = typename __is_pathable<_Tp>::__char_type; + + template + using _SourceCVT = _PathCVT<_SourceChar<_Tp> >; + +public: +# if defined(_LIBCPP_WIN32API) + typedef wchar_t value_type; + static constexpr value_type preferred_separator = L'\\'; +# else + typedef char value_type; + static constexpr value_type preferred_separator = '/'; +# endif + typedef basic_string string_type; + typedef basic_string_view __string_view; + + enum format : unsigned char { auto_format, native_format, generic_format }; + + // constructors and destructor + _LIBCPP_HIDE_FROM_ABI path() noexcept {} + _LIBCPP_HIDE_FROM_ABI path(const path& __p) : __pn_(__p.__pn_) {} + _LIBCPP_HIDE_FROM_ABI path(path&& __p) noexcept : __pn_(std::move(__p.__pn_)) {} + + _LIBCPP_HIDE_FROM_ABI path(string_type&& __s, format = format::auto_format) noexcept : __pn_(std::move(__s)) {} + + template > + _LIBCPP_HIDE_FROM_ABI path(const _Source& __src, format = format::auto_format) { + _SourceCVT<_Source>::__append_source(__pn_, __src); + } + + template + _LIBCPP_HIDE_FROM_ABI path(_InputIt __first, _InputIt __last, format = format::auto_format) { + typedef typename iterator_traits<_InputIt>::value_type _ItVal; + _PathCVT<_ItVal>::__append_range(__pn_, __first, __last); + } + + /* + #if !defined(_LIBCPP_HAS_NO_LOCALIZATION) + // TODO Implement locale conversions. + template > + path(const _Source& __src, const locale& __loc, format = format::auto_format); + template + path(_InputIt __first, _InputIt _last, const locale& __loc, + format = format::auto_format); + #endif + */ + + _LIBCPP_HIDE_FROM_ABI ~path() = default; + + // assignments + _LIBCPP_HIDE_FROM_ABI path& operator=(const path& __p) { + __pn_ = __p.__pn_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI path& operator=(path&& __p) noexcept { + __pn_ = std::move(__p.__pn_); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI path& operator=(string_type&& __s) noexcept { + __pn_ = std::move(__s); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI path& assign(string_type&& __s) noexcept { + __pn_ = std::move(__s); + return *this; + } + + template + _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> operator=(const _Source& __src) { + return this->assign(__src); + } + + template + _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> assign(const _Source& __src) { + __pn_.clear(); + _SourceCVT<_Source>::__append_source(__pn_, __src); + return *this; + } + + template + _LIBCPP_HIDE_FROM_ABI path& assign(_InputIt __first, _InputIt __last) { + typedef typename iterator_traits<_InputIt>::value_type _ItVal; + __pn_.clear(); + _PathCVT<_ItVal>::__append_range(__pn_, __first, __last); + return *this; + } + +public: + // appends +# if defined(_LIBCPP_WIN32API) + _LIBCPP_HIDE_FROM_ABI path& operator/=(const path& __p) { + auto __p_root_name = __p.__root_name(); + auto __p_root_name_size = __p_root_name.size(); + if (__p.is_absolute() || (!__p_root_name.empty() && __p_root_name != __string_view(root_name().__pn_))) { + __pn_ = __p.__pn_; + return *this; + } + if (__p.has_root_directory()) { + path __root_name_str = root_name(); + __pn_ = __root_name_str.native(); + __pn_ += __string_view(__p.__pn_).substr(__p_root_name_size); + return *this; + } + if (has_filename() || (!has_root_directory() && is_absolute())) + __pn_ += preferred_separator; + __pn_ += __string_view(__p.__pn_).substr(__p_root_name_size); + return *this; + } + template + _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> operator/=(const _Source& __src) { + return operator/=(path(__src)); + } + + template + _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> append(const _Source& __src) { + return operator/=(path(__src)); + } + + template + _LIBCPP_HIDE_FROM_ABI path& append(_InputIt __first, _InputIt __last) { + return operator/=(path(__first, __last)); + } +# else + _LIBCPP_HIDE_FROM_ABI path& operator/=(const path& __p) { + if (__p.is_absolute()) { + __pn_ = __p.__pn_; + return *this; + } + if (has_filename()) + __pn_ += preferred_separator; + __pn_ += __p.native(); + return *this; + } + + // FIXME: Use _LIBCPP_DIAGNOSE_WARNING to produce a diagnostic when __src + // is known at compile time to be "/' since the user almost certainly intended + // to append a separator instead of overwriting the path with "/" + template + _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> operator/=(const _Source& __src) { + return this->append(__src); + } + + template + _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> append(const _Source& __src) { + using _Traits = __is_pathable<_Source>; + using _CVT = _PathCVT<_SourceChar<_Source> >; + bool __source_is_absolute = filesystem::__is_separator(_Traits::__first_or_null(__src)); + if (__source_is_absolute) + __pn_.clear(); + else if (has_filename()) + __pn_ += preferred_separator; + _CVT::__append_source(__pn_, __src); + return *this; + } + + template + _LIBCPP_HIDE_FROM_ABI path& append(_InputIt __first, _InputIt __last) { + typedef typename iterator_traits<_InputIt>::value_type _ItVal; + static_assert(__can_convert_char<_ItVal>::value, "Must convertible"); + using _CVT = _PathCVT<_ItVal>; + if (__first != __last && filesystem::__is_separator(*__first)) + __pn_.clear(); + else if (has_filename()) + __pn_ += preferred_separator; + _CVT::__append_range(__pn_, __first, __last); + return *this; + } +# endif + + // concatenation + _LIBCPP_HIDE_FROM_ABI path& operator+=(const path& __x) { + __pn_ += __x.__pn_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI path& operator+=(const string_type& __x) { + __pn_ += __x; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI path& operator+=(__string_view __x) { + __pn_ += __x; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI path& operator+=(const value_type* __x) { + __pn_ += __x; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI path& operator+=(value_type __x) { + __pn_ += __x; + return *this; + } + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI path& operator+=(_ECharT __x) { + _PathCVT<_ECharT>::__append_source(__pn_, basic_string_view<_ECharT>(&__x, 1)); + return *this; + } + + template + _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> operator+=(const _Source& __x) { + return this->concat(__x); + } + + template + _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> concat(const _Source& __x) { + _SourceCVT<_Source>::__append_source(__pn_, __x); + return *this; + } + + template + _LIBCPP_HIDE_FROM_ABI path& concat(_InputIt __first, _InputIt __last) { + typedef typename iterator_traits<_InputIt>::value_type _ItVal; + _PathCVT<_ItVal>::__append_range(__pn_, __first, __last); + return *this; + } + + // modifiers + _LIBCPP_HIDE_FROM_ABI void clear() noexcept { __pn_.clear(); } + + _LIBCPP_HIDE_FROM_ABI path& make_preferred() { +# if defined(_LIBCPP_WIN32API) + std::replace(__pn_.begin(), __pn_.end(), L'/', L'\\'); +# endif + return *this; + } + + _LIBCPP_HIDE_FROM_ABI path& remove_filename() { + auto __fname = __filename(); + if (!__fname.empty()) + __pn_.erase(__fname.data() - __pn_.data()); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI path& replace_filename(const path& __replacement) { + remove_filename(); + return (*this /= __replacement); + } + + path& replace_extension(const path& __replacement = path()); + + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const path& __lhs, const path& __rhs) noexcept { + return __lhs.__compare(__rhs.__pn_) == 0; + } +# if _LIBCPP_STD_VER <= 17 + friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const path& __lhs, const path& __rhs) noexcept { + return __lhs.__compare(__rhs.__pn_) != 0; + } + friend _LIBCPP_HIDE_FROM_ABI bool operator<(const path& __lhs, const path& __rhs) noexcept { + return __lhs.__compare(__rhs.__pn_) < 0; + } + friend _LIBCPP_HIDE_FROM_ABI bool operator<=(const path& __lhs, const path& __rhs) noexcept { + return __lhs.__compare(__rhs.__pn_) <= 0; + } + friend _LIBCPP_HIDE_FROM_ABI bool operator>(const path& __lhs, const path& __rhs) noexcept { + return __lhs.__compare(__rhs.__pn_) > 0; + } + friend _LIBCPP_HIDE_FROM_ABI bool operator>=(const path& __lhs, const path& __rhs) noexcept { + return __lhs.__compare(__rhs.__pn_) >= 0; + } +# else // _LIBCPP_STD_VER <= 17 + friend _LIBCPP_HIDE_FROM_ABI strong_ordering operator<=>(const path& __lhs, const path& __rhs) noexcept { + return __lhs.__compare(__rhs.__pn_) <=> 0; + } +# endif // _LIBCPP_STD_VER <= 17 + + friend _LIBCPP_HIDE_FROM_ABI path operator/(const path& __lhs, const path& __rhs) { + path __result(__lhs); + __result /= __rhs; + return __result; + } + + _LIBCPP_HIDE_FROM_ABI void swap(path& __rhs) noexcept { __pn_.swap(__rhs.__pn_); } + + // private helper to allow reserving memory in the path + _LIBCPP_HIDE_FROM_ABI void __reserve(size_t __s) { __pn_.reserve(__s); } + + // native format observers + _LIBCPP_HIDE_FROM_ABI const string_type& native() const noexcept { return __pn_; } + + _LIBCPP_HIDE_FROM_ABI const value_type* c_str() const noexcept { return __pn_.c_str(); } + + _LIBCPP_HIDE_FROM_ABI operator string_type() const { return __pn_; } + +# if defined(_LIBCPP_WIN32API) + _LIBCPP_HIDE_FROM_ABI std::wstring wstring() const { return __pn_; } + + _LIBCPP_HIDE_FROM_ABI std::wstring generic_wstring() const { + std::wstring __s; + __s.resize(__pn_.size()); + std::replace_copy(__pn_.begin(), __pn_.end(), __s.begin(), '\\', '/'); + return __s; + } + +# if !defined(_LIBCPP_HAS_NO_LOCALIZATION) + template , class _Allocator = allocator<_ECharT> > + _LIBCPP_HIDE_FROM_ABI basic_string<_ECharT, _Traits, _Allocator> string(const _Allocator& __a = _Allocator()) const { + using _Str = basic_string<_ECharT, _Traits, _Allocator>; + _Str __s(__a); + __s.reserve(__pn_.size()); + _PathExport<_ECharT>::__append(__s, __pn_); + return __s; + } + + _LIBCPP_HIDE_FROM_ABI std::string string() const { return string(); } + _LIBCPP_HIDE_FROM_ABI __u8_string u8string() const { + using _CVT = __narrow_to_utf8; + __u8_string __s; + __s.reserve(__pn_.size()); + _CVT()(back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size()); + return __s; + } + + _LIBCPP_HIDE_FROM_ABI std::u16string u16string() const { return string(); } + _LIBCPP_HIDE_FROM_ABI std::u32string u32string() const { return string(); } + + // generic format observers + template , class _Allocator = allocator<_ECharT> > + _LIBCPP_HIDE_FROM_ABI basic_string<_ECharT, _Traits, _Allocator> + generic_string(const _Allocator& __a = _Allocator()) const { + using _Str = basic_string<_ECharT, _Traits, _Allocator>; + _Str __s = string<_ECharT, _Traits, _Allocator>(__a); + // Note: This (and generic_u8string below) is slightly suboptimal as + // it iterates twice over the string; once to convert it to the right + // character type, and once to replace path delimiters. + std::replace(__s.begin(), __s.end(), static_cast<_ECharT>('\\'), static_cast<_ECharT>('/')); + return __s; + } + + _LIBCPP_HIDE_FROM_ABI std::string generic_string() const { return generic_string(); } + _LIBCPP_HIDE_FROM_ABI std::u16string generic_u16string() const { return generic_string(); } + _LIBCPP_HIDE_FROM_ABI std::u32string generic_u32string() const { return generic_string(); } + _LIBCPP_HIDE_FROM_ABI __u8_string generic_u8string() const { + __u8_string __s = u8string(); + std::replace(__s.begin(), __s.end(), '\\', '/'); + return __s; + } +# endif /* !_LIBCPP_HAS_NO_LOCALIZATION */ +# else /* _LIBCPP_WIN32API */ + + _LIBCPP_HIDE_FROM_ABI std::string string() const { return __pn_; } +# ifndef _LIBCPP_HAS_NO_CHAR8_T + _LIBCPP_HIDE_FROM_ABI std::u8string u8string() const { return std::u8string(__pn_.begin(), __pn_.end()); } +# else + _LIBCPP_HIDE_FROM_ABI std::string u8string() const { return __pn_; } +# endif + +# if !defined(_LIBCPP_HAS_NO_LOCALIZATION) + template , class _Allocator = allocator<_ECharT> > + _LIBCPP_HIDE_FROM_ABI basic_string<_ECharT, _Traits, _Allocator> string(const _Allocator& __a = _Allocator()) const { + using _CVT = __widen_from_utf8; + using _Str = basic_string<_ECharT, _Traits, _Allocator>; + _Str __s(__a); + __s.reserve(__pn_.size()); + _CVT()(std::back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size()); + return __s; + } + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS + _LIBCPP_HIDE_FROM_ABI std::wstring wstring() const { return string(); } +# endif + _LIBCPP_HIDE_FROM_ABI std::u16string u16string() const { return string(); } + _LIBCPP_HIDE_FROM_ABI std::u32string u32string() const { return string(); } +# endif /* !_LIBCPP_HAS_NO_LOCALIZATION */ + + // generic format observers + _LIBCPP_HIDE_FROM_ABI std::string generic_string() const { return __pn_; } +# ifndef _LIBCPP_HAS_NO_CHAR8_T + _LIBCPP_HIDE_FROM_ABI std::u8string generic_u8string() const { return std::u8string(__pn_.begin(), __pn_.end()); } +# else + _LIBCPP_HIDE_FROM_ABI std::string generic_u8string() const { return __pn_; } +# endif + +# if !defined(_LIBCPP_HAS_NO_LOCALIZATION) + template , class _Allocator = allocator<_ECharT> > + _LIBCPP_HIDE_FROM_ABI basic_string<_ECharT, _Traits, _Allocator> + generic_string(const _Allocator& __a = _Allocator()) const { + return string<_ECharT, _Traits, _Allocator>(__a); + } + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS + _LIBCPP_HIDE_FROM_ABI std::wstring generic_wstring() const { return string(); } +# endif + _LIBCPP_HIDE_FROM_ABI std::u16string generic_u16string() const { return string(); } + _LIBCPP_HIDE_FROM_ABI std::u32string generic_u32string() const { return string(); } +# endif /* !_LIBCPP_HAS_NO_LOCALIZATION */ +# endif /* !_LIBCPP_WIN32API */ + +private: + int __compare(__string_view) const; + __string_view __root_name() const; + __string_view __root_directory() const; + __string_view __root_path_raw() const; + __string_view __relative_path() const; + __string_view __parent_path() const; + __string_view __filename() const; + __string_view __stem() const; + __string_view __extension() const; + +public: + // compare + _LIBCPP_HIDE_FROM_ABI int compare(const path& __p) const noexcept { return __compare(__p.__pn_); } + _LIBCPP_HIDE_FROM_ABI int compare(const string_type& __s) const { return __compare(__s); } + _LIBCPP_HIDE_FROM_ABI int compare(__string_view __s) const { return __compare(__s); } + _LIBCPP_HIDE_FROM_ABI int compare(const value_type* __s) const { return __compare(__s); } + + // decomposition + _LIBCPP_HIDE_FROM_ABI path root_name() const { return string_type(__root_name()); } + _LIBCPP_HIDE_FROM_ABI path root_directory() const { return string_type(__root_directory()); } + _LIBCPP_HIDE_FROM_ABI path root_path() const { +# if defined(_LIBCPP_WIN32API) + return string_type(__root_path_raw()); +# else + return root_name().append(string_type(__root_directory())); +# endif + } + _LIBCPP_HIDE_FROM_ABI path relative_path() const { return string_type(__relative_path()); } + _LIBCPP_HIDE_FROM_ABI path parent_path() const { return string_type(__parent_path()); } + _LIBCPP_HIDE_FROM_ABI path filename() const { return string_type(__filename()); } + _LIBCPP_HIDE_FROM_ABI path stem() const { return string_type(__stem()); } + _LIBCPP_HIDE_FROM_ABI path extension() const { return string_type(__extension()); } + + // query + _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept { return __pn_.empty(); } + + _LIBCPP_HIDE_FROM_ABI bool has_root_name() const { return !__root_name().empty(); } + _LIBCPP_HIDE_FROM_ABI bool has_root_directory() const { return !__root_directory().empty(); } + _LIBCPP_HIDE_FROM_ABI bool has_root_path() const { return !__root_path_raw().empty(); } + _LIBCPP_HIDE_FROM_ABI bool has_relative_path() const { return !__relative_path().empty(); } + _LIBCPP_HIDE_FROM_ABI bool has_parent_path() const { return !__parent_path().empty(); } + _LIBCPP_HIDE_FROM_ABI bool has_filename() const { return !__filename().empty(); } + _LIBCPP_HIDE_FROM_ABI bool has_stem() const { return !__stem().empty(); } + _LIBCPP_HIDE_FROM_ABI bool has_extension() const { return !__extension().empty(); } + + _LIBCPP_HIDE_FROM_ABI bool is_absolute() const { +# if defined(_LIBCPP_WIN32API) + __string_view __root_name_str = __root_name(); + __string_view __root_dir = __root_directory(); + if (__root_name_str.size() == 2 && __root_name_str[1] == ':') { + // A drive letter with no root directory is relative, e.g. x:example. + return !__root_dir.empty(); + } + // If no root name, it's relative, e.g. \example is relative to the current drive + if (__root_name_str.empty()) + return false; + if (__root_name_str.size() < 3) + return false; + // A server root name, like \\server, is always absolute + if (__root_name_str[0] != '/' && __root_name_str[0] != '\\') + return false; + if (__root_name_str[1] != '/' && __root_name_str[1] != '\\') + return false; + // Seems to be a server root name + return true; +# else + return has_root_directory(); +# endif + } + _LIBCPP_HIDE_FROM_ABI bool is_relative() const { return !is_absolute(); } + + // relative paths + path lexically_normal() const; + path lexically_relative(const path& __base) const; + + _LIBCPP_HIDE_FROM_ABI path lexically_proximate(const path& __base) const { + path __result = this->lexically_relative(__base); + if (__result.native().empty()) + return *this; + return __result; + } + + // iterators + class _LIBCPP_EXPORTED_FROM_ABI iterator; + typedef iterator const_iterator; + + iterator begin() const; + iterator end() const; + +# if !defined(_LIBCPP_HAS_NO_LOCALIZATION) + template < + class _CharT, + class _Traits, + __enable_if_t::value && is_same<_Traits, char_traits >::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI friend basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) { + __os << std::__quoted(__p.native()); + return __os; + } + + template < + class _CharT, + class _Traits, + __enable_if_t::value || !is_same<_Traits, char_traits >::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI friend basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) { + __os << std::__quoted(__p.string<_CharT, _Traits>()); + return __os; + } + + template + _LIBCPP_HIDE_FROM_ABI friend basic_istream<_CharT, _Traits>& + operator>>(basic_istream<_CharT, _Traits>& __is, path& __p) { + basic_string<_CharT, _Traits> __tmp; + __is >> std::__quoted(__tmp); + __p = __tmp; + return __is; + } +# endif // !_LIBCPP_HAS_NO_LOCALIZATION + +private: + inline _LIBCPP_HIDE_FROM_ABI path& __assign_view(__string_view const& __s) { + __pn_ = string_type(__s); + return *this; + } + string_type __pn_; +}; + +inline _LIBCPP_HIDE_FROM_ABI void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); } + +_LIBCPP_EXPORTED_FROM_ABI size_t hash_value(const path& __p) noexcept; + +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +_LIBCPP_BEGIN_NAMESPACE_STD + +template <> +struct _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY hash : __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(filesystem::path const& __p) const noexcept { + return filesystem::hash_value(__p); + } +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FILESYSTEM_PATH_H diff --git a/libcxx/include/__cxx03/__filesystem/path_iterator.h b/libcxx/include/__cxx03/__filesystem/path_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..f4d486d86cf380911af385b0f28459862acb6ae2 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/path_iterator.h @@ -0,0 +1,115 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_PATH_ITERATOR_H +#define _LIBCPP___FILESYSTEM_PATH_ITERATOR_H + +#include <__assert> +#include <__config> +#include <__filesystem/path.h> +#include <__iterator/iterator_traits.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +class _LIBCPP_EXPORTED_FROM_ABI path::iterator { +public: + enum _ParserState : unsigned char { + _Singular, + _BeforeBegin, + _InRootName, + _InRootDir, + _InFilenames, + _InTrailingSep, + _AtEnd + }; + +public: + typedef input_iterator_tag iterator_category; + typedef bidirectional_iterator_tag iterator_concept; + + typedef path value_type; + typedef ptrdiff_t difference_type; + typedef const path* pointer; + typedef path reference; + +public: + _LIBCPP_HIDE_FROM_ABI iterator() : __stashed_elem_(), __path_ptr_(nullptr), __entry_(), __state_(_Singular) {} + + _LIBCPP_HIDE_FROM_ABI iterator(const iterator&) = default; + _LIBCPP_HIDE_FROM_ABI ~iterator() = default; + + _LIBCPP_HIDE_FROM_ABI iterator& operator=(const iterator&) = default; + + _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __stashed_elem_; } + + _LIBCPP_HIDE_FROM_ABI pointer operator->() const { return &__stashed_elem_; } + + _LIBCPP_HIDE_FROM_ABI iterator& operator++() { + _LIBCPP_ASSERT_NON_NULL(__state_ != _Singular, "attempting to increment a singular iterator"); + _LIBCPP_ASSERT_UNCATEGORIZED(__state_ != _AtEnd, "attempting to increment the end iterator"); + return __increment(); + } + + _LIBCPP_HIDE_FROM_ABI iterator operator++(int) { + iterator __it(*this); + this->operator++(); + return __it; + } + + _LIBCPP_HIDE_FROM_ABI iterator& operator--() { + _LIBCPP_ASSERT_NON_NULL(__state_ != _Singular, "attempting to decrement a singular iterator"); + _LIBCPP_ASSERT_UNCATEGORIZED( + __entry_.data() != __path_ptr_->native().data(), "attempting to decrement the begin iterator"); + return __decrement(); + } + + _LIBCPP_HIDE_FROM_ABI iterator operator--(int) { + iterator __it(*this); + this->operator--(); + return __it; + } + +private: + friend class path; + + inline _LIBCPP_HIDE_FROM_ABI friend bool operator==(const iterator&, const iterator&); + + iterator& __increment(); + iterator& __decrement(); + + path __stashed_elem_; + const path* __path_ptr_; + path::__string_view __entry_; + _ParserState __state_; +}; + +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY +inline _LIBCPP_HIDE_FROM_ABI bool operator==(const path::iterator& __lhs, const path::iterator& __rhs) { + return __lhs.__path_ptr_ == __rhs.__path_ptr_ && __lhs.__entry_.data() == __rhs.__entry_.data(); +} + +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY +inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const path::iterator& __lhs, const path::iterator& __rhs) { + return !(__lhs == __rhs); +} + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +#endif // _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___FILESYSTEM_PATH_ITERATOR_H diff --git a/libcxx/include/__cxx03/__filesystem/perm_options.h b/libcxx/include/__cxx03/__filesystem/perm_options.h new file mode 100644 index 0000000000000000000000000000000000000000..64c16ee60a17d0856388de91c067fb61ae3f7116 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/perm_options.h @@ -0,0 +1,57 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_PERM_OPTIONS_H +#define _LIBCPP___FILESYSTEM_PERM_OPTIONS_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +enum class perm_options : unsigned char { replace = 1, add = 2, remove = 4, nofollow = 8 }; + +_LIBCPP_HIDE_FROM_ABI inline constexpr perm_options operator&(perm_options __lhs, perm_options __rhs) { + return static_cast(static_cast(__lhs) & static_cast(__rhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr perm_options operator|(perm_options __lhs, perm_options __rhs) { + return static_cast(static_cast(__lhs) | static_cast(__rhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr perm_options operator^(perm_options __lhs, perm_options __rhs) { + return static_cast(static_cast(__lhs) ^ static_cast(__rhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr perm_options operator~(perm_options __lhs) { + return static_cast(~static_cast(__lhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline perm_options& operator&=(perm_options& __lhs, perm_options __rhs) { + return __lhs = __lhs & __rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline perm_options& operator|=(perm_options& __lhs, perm_options __rhs) { + return __lhs = __lhs | __rhs; +} + +_LIBCPP_HIDE_FROM_ABI inline perm_options& operator^=(perm_options& __lhs, perm_options __rhs) { + return __lhs = __lhs ^ __rhs; +} + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +#endif // _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___FILESYSTEM_PERM_OPTIONS_H diff --git a/libcxx/include/__cxx03/__filesystem/perms.h b/libcxx/include/__cxx03/__filesystem/perms.h new file mode 100644 index 0000000000000000000000000000000000000000..458f1e6e5348339ec0007f764458924669cdfe30 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/perms.h @@ -0,0 +1,80 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_PERMS_H +#define _LIBCPP___FILESYSTEM_PERMS_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +// On Windows, these permission bits map to one single readonly flag per +// file, and the executable bit is always returned as set. When setting +// permissions, as long as the write bit is set for either owner, group or +// others, the readonly flag is cleared. +enum class perms : unsigned { + none = 0, + + owner_read = 0400, + owner_write = 0200, + owner_exec = 0100, + owner_all = 0700, + + group_read = 040, + group_write = 020, + group_exec = 010, + group_all = 070, + + others_read = 04, + others_write = 02, + others_exec = 01, + others_all = 07, + + all = 0777, + + set_uid = 04000, + set_gid = 02000, + sticky_bit = 01000, + mask = 07777, + unknown = 0xFFFF, +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr perms operator&(perms __lhs, perms __rhs) { + return static_cast(static_cast(__lhs) & static_cast(__rhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr perms operator|(perms __lhs, perms __rhs) { + return static_cast(static_cast(__lhs) | static_cast(__rhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr perms operator^(perms __lhs, perms __rhs) { + return static_cast(static_cast(__lhs) ^ static_cast(__rhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline constexpr perms operator~(perms __lhs) { + return static_cast(~static_cast(__lhs)); +} + +_LIBCPP_HIDE_FROM_ABI inline perms& operator&=(perms& __lhs, perms __rhs) { return __lhs = __lhs & __rhs; } + +_LIBCPP_HIDE_FROM_ABI inline perms& operator|=(perms& __lhs, perms __rhs) { return __lhs = __lhs | __rhs; } + +_LIBCPP_HIDE_FROM_ABI inline perms& operator^=(perms& __lhs, perms __rhs) { return __lhs = __lhs ^ __rhs; } + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +#endif // _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___FILESYSTEM_PERMS_H diff --git a/libcxx/include/__cxx03/__filesystem/recursive_directory_iterator.h b/libcxx/include/__cxx03/__filesystem/recursive_directory_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..caa1396eb301fc96427f3e1be1febfc506888f78 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/recursive_directory_iterator.h @@ -0,0 +1,164 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_RECURSIVE_DIRECTORY_ITERATOR_H +#define _LIBCPP___FILESYSTEM_RECURSIVE_DIRECTORY_ITERATOR_H + +#include <__config> +#include <__filesystem/directory_entry.h> +#include <__filesystem/directory_options.h> +#include <__filesystem/path.h> +#include <__iterator/default_sentinel.h> +#include <__iterator/iterator_traits.h> +#include <__memory/shared_ptr.h> +#include <__ranges/enable_borrowed_range.h> +#include <__ranges/enable_view.h> +#include <__system_error/error_code.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_FILESYSTEM) + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH + +class recursive_directory_iterator { +public: + using value_type = directory_entry; + using difference_type = ptrdiff_t; + using pointer = directory_entry const*; + using reference = directory_entry const&; + using iterator_category = input_iterator_tag; + +public: + // constructors and destructor + _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator() noexcept : __rec_(false) {} + + _LIBCPP_HIDE_FROM_ABI explicit recursive_directory_iterator( + const path& __p, directory_options __xoptions = directory_options::none) + : recursive_directory_iterator(__p, __xoptions, nullptr) {} + + _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator(const path& __p, directory_options __xoptions, error_code& __ec) + : recursive_directory_iterator(__p, __xoptions, &__ec) {} + + _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator(const path& __p, error_code& __ec) + : recursive_directory_iterator(__p, directory_options::none, &__ec) {} + + _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator(const recursive_directory_iterator&) = default; + _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator(recursive_directory_iterator&&) = default; + + _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator& operator=(const recursive_directory_iterator&) = default; + + _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator& operator=(recursive_directory_iterator&& __o) noexcept { + // non-default implementation provided to support self-move assign. + if (this != &__o) { + __imp_ = std::move(__o.__imp_); + __rec_ = __o.__rec_; + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI ~recursive_directory_iterator() = default; + + _LIBCPP_HIDE_FROM_ABI const directory_entry& operator*() const { return __dereference(); } + + _LIBCPP_HIDE_FROM_ABI const directory_entry* operator->() const { return &__dereference(); } + + _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator& operator++() { return __increment(); } + + _LIBCPP_HIDE_FROM_ABI __dir_element_proxy operator++(int) { + __dir_element_proxy __p(**this); + __increment(); + return __p; + } + + _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator& increment(error_code& __ec) { return __increment(&__ec); } + + _LIBCPP_EXPORTED_FROM_ABI directory_options options() const; + _LIBCPP_EXPORTED_FROM_ABI int depth() const; + + _LIBCPP_HIDE_FROM_ABI void pop() { __pop(); } + + _LIBCPP_HIDE_FROM_ABI void pop(error_code& __ec) { __pop(&__ec); } + + _LIBCPP_HIDE_FROM_ABI bool recursion_pending() const { return __rec_; } + + _LIBCPP_HIDE_FROM_ABI void disable_recursion_pending() { __rec_ = false; } + +# if _LIBCPP_STD_VER >= 20 + + _LIBCPP_HIDE_FROM_ABI bool operator==(default_sentinel_t) const noexcept { + return *this == recursive_directory_iterator(); + } + +# endif + +private: + _LIBCPP_EXPORTED_FROM_ABI recursive_directory_iterator(const path& __p, directory_options __opt, error_code* __ec); + _LIBCPP_EXPORTED_FROM_ABI const directory_entry& __dereference() const; + _LIBCPP_EXPORTED_FROM_ABI bool __try_recursion(error_code* __ec); + _LIBCPP_EXPORTED_FROM_ABI void __advance(error_code* __ec = nullptr); + _LIBCPP_EXPORTED_FROM_ABI recursive_directory_iterator& __increment(error_code* __ec = nullptr); + _LIBCPP_EXPORTED_FROM_ABI void __pop(error_code* __ec = nullptr); + + inline _LIBCPP_HIDE_FROM_ABI friend bool + operator==(const recursive_directory_iterator&, const recursive_directory_iterator&) noexcept; + + struct _LIBCPP_HIDDEN __shared_imp; + shared_ptr<__shared_imp> __imp_; + bool __rec_; +}; // class recursive_directory_iterator + +inline _LIBCPP_HIDE_FROM_ABI bool +operator==(const recursive_directory_iterator& __lhs, const recursive_directory_iterator& __rhs) noexcept { + return __lhs.__imp_ == __rhs.__imp_; +} + +_LIBCPP_HIDE_FROM_ABI inline bool +operator!=(const recursive_directory_iterator& __lhs, const recursive_directory_iterator& __rhs) noexcept { + return !(__lhs == __rhs); +} +// enable recursive_directory_iterator range-based for statements +inline _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator begin(recursive_directory_iterator __iter) noexcept { + return __iter; +} + +inline _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator end(recursive_directory_iterator) noexcept { + return recursive_directory_iterator(); +} + +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +# if _LIBCPP_STD_VER >= 20 + +template <> +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY inline constexpr bool + std::ranges::enable_borrowed_range = true; + +template <> +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY inline constexpr bool + std::ranges::enable_view = true; + +# endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_FILESYSTEM) + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FILESYSTEM_RECURSIVE_DIRECTORY_ITERATOR_H diff --git a/libcxx/include/__cxx03/__filesystem/space_info.h b/libcxx/include/__cxx03/__filesystem/space_info.h new file mode 100644 index 0000000000000000000000000000000000000000..3fa57d33096fc89daf95bd2f460c5be348a45fc7 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/space_info.h @@ -0,0 +1,38 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_SPACE_INFO_H +#define _LIBCPP___FILESYSTEM_SPACE_INFO_H + +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +struct _LIBCPP_EXPORTED_FROM_ABI space_info { + uintmax_t capacity; + uintmax_t free; + uintmax_t available; + +# if _LIBCPP_STD_VER >= 20 + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const space_info&, const space_info&) = default; +# endif +}; + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +#endif // _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___FILESYSTEM_SPACE_INFO_H diff --git a/libcxx/include/__cxx03/__filesystem/u8path.h b/libcxx/include/__cxx03/__filesystem/u8path.h new file mode 100644 index 0000000000000000000000000000000000000000..dae5823128f028a0fa3828a93b11d80d4413fa56 --- /dev/null +++ b/libcxx/include/__cxx03/__filesystem/u8path.h @@ -0,0 +1,100 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FILESYSTEM_U8PATH_H +#define _LIBCPP___FILESYSTEM_U8PATH_H + +#include <__algorithm/unwrap_iter.h> +#include <__config> +#include <__filesystem/path.h> +#include + +// Only required on Windows for __widen_from_utf8, and included conservatively +// because it requires support for localization. +#if defined(_LIBCPP_WIN32API) +# include +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_WITH_CHAR8_T path u8path(_InputIt __f, _InputIt __l) { + static_assert( +# ifndef _LIBCPP_HAS_NO_CHAR8_T + is_same::__char_type, char8_t>::value || +# endif + is_same::__char_type, char>::value, + "u8path(Iter, Iter) requires Iter have a value_type of type 'char'" + " or 'char8_t'"); +# if defined(_LIBCPP_WIN32API) + string __tmp(__f, __l); + using _CVT = __widen_from_utf8; + std::wstring __w; + __w.reserve(__tmp.size()); + _CVT()(back_inserter(__w), __tmp.data(), __tmp.data() + __tmp.size()); + return path(__w); +# else + return path(__f, __l); +# endif /* !_LIBCPP_WIN32API */ +} + +# if defined(_LIBCPP_WIN32API) +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_WITH_CHAR8_T path u8path(_InputIt __f, _NullSentinel) { + static_assert( +# ifndef _LIBCPP_HAS_NO_CHAR8_T + is_same::__char_type, char8_t>::value || +# endif + is_same::__char_type, char>::value, + "u8path(Iter, Iter) requires Iter have a value_type of type 'char'" + " or 'char8_t'"); + string __tmp; + const char __sentinel = char{}; + for (; *__f != __sentinel; ++__f) + __tmp.push_back(*__f); + using _CVT = __widen_from_utf8; + std::wstring __w; + __w.reserve(__tmp.size()); + _CVT()(back_inserter(__w), __tmp.data(), __tmp.data() + __tmp.size()); + return path(__w); +} +# endif /* _LIBCPP_WIN32API */ + +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_WITH_CHAR8_T path u8path(const _Source& __s) { + static_assert( +# ifndef _LIBCPP_HAS_NO_CHAR8_T + is_same::__char_type, char8_t>::value || +# endif + is_same::__char_type, char>::value, + "u8path(Source const&) requires Source have a character type of type " + "'char' or 'char8_t'"); +# if defined(_LIBCPP_WIN32API) + using _Traits = __is_pathable<_Source>; + return u8path(std::__unwrap_iter(_Traits::__range_begin(__s)), std::__unwrap_iter(_Traits::__range_end(__s))); +# else + return path(__s); +# endif +} + +_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +#endif // _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___FILESYSTEM_U8PATH_H diff --git a/libcxx/include/__cxx03/__format/buffer.h b/libcxx/include/__cxx03/__format/buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..8598f0a1c0395765a3076ebf79738ade0308acb0 --- /dev/null +++ b/libcxx/include/__cxx03/__format/buffer.h @@ -0,0 +1,655 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_BUFFER_H +#define _LIBCPP___FORMAT_BUFFER_H + +#include <__algorithm/copy_n.h> +#include <__algorithm/fill_n.h> +#include <__algorithm/max.h> +#include <__algorithm/min.h> +#include <__algorithm/ranges_copy_n.h> +#include <__algorithm/transform.h> +#include <__algorithm/unwrap_iter.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__format/concepts.h> +#include <__format/enable_insertable.h> +#include <__format/format_to_n_result.h> +#include <__iterator/back_insert_iterator.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/wrap_iter.h> +#include <__memory/addressof.h> +#include <__memory/allocate_at_least.h> +#include <__memory/allocator_traits.h> +#include <__memory/construct_at.h> +#include <__memory/ranges_construct_at.h> +#include <__memory/uninitialized_algorithms.h> +#include <__type_traits/add_pointer.h> +#include <__type_traits/conditional.h> +#include <__utility/exception_guard.h> +#include <__utility/move.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __format { + +/// A "buffer" that handles writing to the proper iterator. +/// +/// This helper is used together with the @ref back_insert_iterator to offer +/// type-erasure for the formatting functions. This reduces the number to +/// template instantiations. +template <__fmt_char_type _CharT> +class _LIBCPP_TEMPLATE_VIS __output_buffer { +public: + using value_type = _CharT; + + template + _LIBCPP_HIDE_FROM_ABI explicit __output_buffer(_CharT* __ptr, size_t __capacity, _Tp* __obj) + : __ptr_(__ptr), + __capacity_(__capacity), + __flush_([](_CharT* __p, size_t __n, void* __o) { static_cast<_Tp*>(__o)->__flush(__p, __n); }), + __obj_(__obj) {} + + _LIBCPP_HIDE_FROM_ABI void __reset(_CharT* __ptr, size_t __capacity) { + __ptr_ = __ptr; + __capacity_ = __capacity; + } + + _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return std::back_insert_iterator{*this}; } + + // Used in std::back_insert_iterator. + _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) { + __ptr_[__size_++] = __c; + + // Profiling showed flushing after adding is more efficient than flushing + // when entering the function. + if (__size_ == __capacity_) + __flush(); + } + + /// Copies the input __str to the buffer. + /// + /// Since some of the input is generated by std::to_chars, there needs to be a + /// conversion when _CharT is wchar_t. + template <__fmt_char_type _InCharT> + _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) { + // When the underlying iterator is a simple iterator the __capacity_ is + // infinite. For a string or container back_inserter it isn't. This means + // that adding a large string to the buffer can cause some overhead. In that + // case a better approach could be: + // - flush the buffer + // - container.append(__str.begin(), __str.end()); + // The same holds true for the fill. + // For transform it might be slightly harder, however the use case for + // transform is slightly less common; it converts hexadecimal values to + // upper case. For integral these strings are short. + // TODO FMT Look at the improvements above. + size_t __n = __str.size(); + + __flush_on_overflow(__n); + if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <). + std::copy_n(__str.data(), __n, std::addressof(__ptr_[__size_])); + __size_ += __n; + return; + } + + // The output doesn't fit in the internal buffer. + // Copy the data in "__capacity_" sized chunks. + _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); + const _InCharT* __first = __str.data(); + do { + size_t __chunk = std::min(__n, __capacity_); + std::copy_n(__first, __chunk, std::addressof(__ptr_[__size_])); + __size_ = __chunk; + __first += __chunk; + __n -= __chunk; + __flush(); + } while (__n); + } + + /// A std::transform wrapper. + /// + /// Like @ref __copy it may need to do type conversion. + template ::value_type> + _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) { + _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range"); + + size_t __n = static_cast(__last - __first); + __flush_on_overflow(__n); + if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <). + std::transform(__first, __last, std::addressof(__ptr_[__size_]), std::move(__operation)); + __size_ += __n; + return; + } + + // The output doesn't fit in the internal buffer. + // Transform the data in "__capacity_" sized chunks. + _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); + do { + size_t __chunk = std::min(__n, __capacity_); + std::transform(__first, __first + __chunk, std::addressof(__ptr_[__size_]), __operation); + __size_ = __chunk; + __first += __chunk; + __n -= __chunk; + __flush(); + } while (__n); + } + + /// A \c fill_n wrapper. + _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) { + __flush_on_overflow(__n); + if (__n < __capacity_) { // push_back requires the buffer to have room for at least one character (so use <). + std::fill_n(std::addressof(__ptr_[__size_]), __n, __value); + __size_ += __n; + return; + } + + // The output doesn't fit in the internal buffer. + // Fill the buffer in "__capacity_" sized chunks. + _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); + do { + size_t __chunk = std::min(__n, __capacity_); + std::fill_n(std::addressof(__ptr_[__size_]), __chunk, __value); + __size_ = __chunk; + __n -= __chunk; + __flush(); + } while (__n); + } + + _LIBCPP_HIDE_FROM_ABI void __flush() { + __flush_(__ptr_, __size_, __obj_); + __size_ = 0; + } + +private: + _CharT* __ptr_; + size_t __capacity_; + size_t __size_{0}; + void (*__flush_)(_CharT*, size_t, void*); + void* __obj_; + + /// Flushes the buffer when the output operation would overflow the buffer. + /// + /// A simple approach for the overflow detection would be something along the + /// lines: + /// \code + /// // The internal buffer is large enough. + /// if (__n <= __capacity_) { + /// // Flush when we really would overflow. + /// if (__size_ + __n >= __capacity_) + /// __flush(); + /// ... + /// } + /// \endcode + /// + /// This approach works for all cases but one: + /// A __format_to_n_buffer_base where \ref __enable_direct_output is true. + /// In that case the \ref __capacity_ of the buffer changes during the first + /// \ref __flush. During that operation the output buffer switches from its + /// __writer_ to its __storage_. The \ref __capacity_ of the former depends + /// on the value of n, of the latter is a fixed size. For example: + /// - a format_to_n call with a 10'000 char buffer, + /// - the buffer is filled with 9'500 chars, + /// - adding 1'000 elements would overflow the buffer so the buffer gets + /// changed and the \ref __capacity_ decreases from 10'000 to + /// __buffer_size (256 at the time of writing). + /// + /// This means that the \ref __flush for this class may need to copy a part of + /// the internal buffer to the proper output. In this example there will be + /// 500 characters that need this copy operation. + /// + /// Note it would be more efficient to write 500 chars directly and then swap + /// the buffers. This would make the code more complex and \ref format_to_n is + /// not the most common use case. Therefore the optimization isn't done. + _LIBCPP_HIDE_FROM_ABI void __flush_on_overflow(size_t __n) { + if (__size_ + __n >= __capacity_) + __flush(); + } +}; + +/// A storage using an internal buffer. +/// +/// This storage is used when writing a single element to the output iterator +/// is expensive. +template <__fmt_char_type _CharT> +class _LIBCPP_TEMPLATE_VIS __internal_storage { +public: + _LIBCPP_HIDE_FROM_ABI _CharT* __begin() { return __buffer_; } + + static constexpr size_t __buffer_size = 256 / sizeof(_CharT); + +private: + _CharT __buffer_[__buffer_size]; +}; + +/// A storage writing directly to the storage. +/// +/// This requires the storage to be a contiguous buffer of \a _CharT. +/// Since the output is directly written to the underlying storage this class +/// is just an empty class. +template <__fmt_char_type _CharT> +class _LIBCPP_TEMPLATE_VIS __direct_storage {}; + +template +concept __enable_direct_output = + __fmt_char_type<_CharT> && + (same_as<_OutIt, _CharT*> + // TODO(hardening): the following check might not apply to hardened iterators and might need to be wrapped in an + // `#ifdef`. + || same_as<_OutIt, __wrap_iter<_CharT*>>); + +/// Write policy for directly writing to the underlying output. +template +class _LIBCPP_TEMPLATE_VIS __writer_direct { +public: + _LIBCPP_HIDE_FROM_ABI explicit __writer_direct(_OutIt __out_it) : __out_it_(__out_it) {} + + _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() { return __out_it_; } + + _LIBCPP_HIDE_FROM_ABI void __flush(_CharT*, size_t __n) { + // _OutIt can be a __wrap_iter. Therefore the original iterator + // is adjusted. + __out_it_ += __n; + } + +private: + _OutIt __out_it_; +}; + +/// Write policy for copying the buffer to the output. +template +class _LIBCPP_TEMPLATE_VIS __writer_iterator { +public: + _LIBCPP_HIDE_FROM_ABI explicit __writer_iterator(_OutIt __out_it) : __out_it_{std::move(__out_it)} {} + + _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { return std::move(__out_it_); } + + _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { + __out_it_ = std::ranges::copy_n(__ptr, __n, std::move(__out_it_)).out; + } + +private: + _OutIt __out_it_; +}; + +/// Concept to see whether a \a _Container is insertable. +/// +/// The concept is used to validate whether multiple calls to a +/// \ref back_insert_iterator can be replace by a call to \c _Container::insert. +/// +/// \note a \a _Container needs to opt-in to the concept by specializing +/// \ref __enable_insertable. +template +concept __insertable = + __enable_insertable<_Container> && __fmt_char_type && + requires(_Container& __t, + add_pointer_t __first, + add_pointer_t __last) { __t.insert(__t.end(), __first, __last); }; + +/// Extract the container type of a \ref back_insert_iterator. +template +struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container { + using type = void; +}; + +template <__insertable _Container> +struct _LIBCPP_TEMPLATE_VIS __back_insert_iterator_container> { + using type = _Container; +}; + +/// Write policy for inserting the buffer in a container. +template +class _LIBCPP_TEMPLATE_VIS __writer_container { +public: + using _CharT = typename _Container::value_type; + + _LIBCPP_HIDE_FROM_ABI explicit __writer_container(back_insert_iterator<_Container> __out_it) + : __container_{__out_it.__get_container()} {} + + _LIBCPP_HIDE_FROM_ABI auto __out_it() { return std::back_inserter(*__container_); } + + _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { + __container_->insert(__container_->end(), __ptr, __ptr + __n); + } + +private: + _Container* __container_; +}; + +/// Selects the type of the writer used for the output iterator. +template +class _LIBCPP_TEMPLATE_VIS __writer_selector { + using _Container = typename __back_insert_iterator_container<_OutIt>::type; + +public: + using type = + conditional_t, + __writer_container<_Container>, + conditional_t<__enable_direct_output<_OutIt, _CharT>, + __writer_direct<_OutIt, _CharT>, + __writer_iterator<_OutIt, _CharT>>>; +}; + +/// The generic formatting buffer. +template + requires(output_iterator<_OutIt, const _CharT&>) +class _LIBCPP_TEMPLATE_VIS __format_buffer { + using _Storage = + conditional_t<__enable_direct_output<_OutIt, _CharT>, __direct_storage<_CharT>, __internal_storage<_CharT>>; + +public: + _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it) + requires(same_as<_Storage, __internal_storage<_CharT>>) + : __output_(__storage_.__begin(), __storage_.__buffer_size, this), __writer_(std::move(__out_it)) {} + + _LIBCPP_HIDE_FROM_ABI explicit __format_buffer(_OutIt __out_it) + requires(same_as<_Storage, __direct_storage<_CharT>>) + : __output_(std::__unwrap_iter(__out_it), size_t(-1), this), __writer_(std::move(__out_it)) {} + + _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); } + + _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { __writer_.__flush(__ptr, __n); } + + _LIBCPP_HIDE_FROM_ABI _OutIt __out_it() && { + __output_.__flush(); + return std::move(__writer_).__out_it(); + } + +private: + _LIBCPP_NO_UNIQUE_ADDRESS _Storage __storage_; + __output_buffer<_CharT> __output_; + typename __writer_selector<_OutIt, _CharT>::type __writer_; +}; + +/// A buffer that counts the number of insertions. +/// +/// Since \ref formatted_size only needs to know the size, the output itself is +/// discarded. +template <__fmt_char_type _CharT> +class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer { +public: + _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return __output_.__make_output_iterator(); } + + _LIBCPP_HIDE_FROM_ABI void __flush(const _CharT*, size_t __n) { __size_ += __n; } + + _LIBCPP_HIDE_FROM_ABI size_t __result() && { + __output_.__flush(); + return __size_; + } + +private: + __internal_storage<_CharT> __storage_; + __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this}; + size_t __size_{0}; +}; + +/// The base of a buffer that counts and limits the number of insertions. +template + requires(output_iterator<_OutIt, const _CharT&>) +struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base { + using _Size = iter_difference_t<_OutIt>; + +public: + _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size) + : __writer_(std::move(__out_it)), __max_size_(std::max(_Size(0), __max_size)) {} + + _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { + if (_Size(__size_) <= __max_size_) + __writer_.__flush(__ptr, std::min(_Size(__n), __max_size_ - __size_)); + __size_ += __n; + } + +protected: + __internal_storage<_CharT> __storage_; + __output_buffer<_CharT> __output_{__storage_.__begin(), __storage_.__buffer_size, this}; + typename __writer_selector<_OutIt, _CharT>::type __writer_; + + _Size __max_size_; + _Size __size_{0}; +}; + +/// The base of a buffer that counts and limits the number of insertions. +/// +/// This version is used when \c __enable_direct_output<_OutIt, _CharT> == true. +/// +/// This class limits the size available to the direct writer so it will not +/// exceed the maximum number of code units. +template + requires(output_iterator<_OutIt, const _CharT&>) +class _LIBCPP_TEMPLATE_VIS __format_to_n_buffer_base<_OutIt, _CharT, true> { + using _Size = iter_difference_t<_OutIt>; + +public: + _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer_base(_OutIt __out_it, _Size __max_size) + : __output_(std::__unwrap_iter(__out_it), __max_size, this), + __writer_(std::move(__out_it)), + __max_size_(__max_size) { + if (__max_size <= 0) [[unlikely]] + __output_.__reset(__storage_.__begin(), __storage_.__buffer_size); + } + + _LIBCPP_HIDE_FROM_ABI void __flush(_CharT* __ptr, size_t __n) { + // A __flush to the direct writer happens in the following occasions: + // - The format function has written the maximum number of allowed code + // units. At this point it's no longer valid to write to this writer. So + // switch to the internal storage. This internal storage doesn't need to + // be written anywhere so the __flush for that storage writes no output. + // - Like above, but the next "mass write" operation would overflow the + // buffer. In that case the buffer is pre-emptively switched. The still + // valid code units will be written separately. + // - The format_to_n function is finished. In this case there's no need to + // switch the buffer, but for simplicity the buffers are still switched. + // When the __max_size <= 0 the constructor already switched the buffers. + if (__size_ == 0 && __ptr != __storage_.__begin()) { + __writer_.__flush(__ptr, __n); + __output_.__reset(__storage_.__begin(), __storage_.__buffer_size); + } else if (__size_ < __max_size_) { + // Copies a part of the internal buffer to the output up to n characters. + // See __output_buffer<_CharT>::__flush_on_overflow for more information. + _Size __s = std::min(_Size(__n), __max_size_ - __size_); + std::copy_n(__ptr, __s, __writer_.__out_it()); + __writer_.__flush(__ptr, __s); + } + + __size_ += __n; + } + +protected: + __internal_storage<_CharT> __storage_; + __output_buffer<_CharT> __output_; + __writer_direct<_OutIt, _CharT> __writer_; + + _Size __max_size_; + _Size __size_{0}; +}; + +/// The buffer that counts and limits the number of insertions. +template + requires(output_iterator<_OutIt, const _CharT&>) +struct _LIBCPP_TEMPLATE_VIS __format_to_n_buffer final + : public __format_to_n_buffer_base< _OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>> { + using _Base = __format_to_n_buffer_base<_OutIt, _CharT, __enable_direct_output<_OutIt, _CharT>>; + using _Size = iter_difference_t<_OutIt>; + +public: + _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer(_OutIt __out_it, _Size __max_size) + : _Base(std::move(__out_it), __max_size) {} + _LIBCPP_HIDE_FROM_ABI auto __make_output_iterator() { return this->__output_.__make_output_iterator(); } + + _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __result() && { + this->__output_.__flush(); + return {std::move(this->__writer_).__out_it(), this->__size_}; + } +}; + +// A dynamically growing buffer intended to be used for retargeting a context. +// +// P2286 Formatting ranges adds range formatting support. It allows the user to +// specify the minimum width for the entire formatted range. The width of the +// range is not known until the range is formatted. Formatting is done to an +// output_iterator so there's no guarantee it would be possible to add the fill +// to the front of the output. Instead the range is formatted to a temporary +// buffer and that buffer is formatted as a string. +// +// There is an issue with that approach, the format context used in +// std::formatter::format contains the output iterator used as part of its +// type. So using this output iterator means there needs to be a new format +// context and the format arguments need to be retargeted to the new context. +// This retargeting is done by a basic_format_context specialized for the +// __iterator of this container. +// +// This class uses its own buffer management, since using vector +// would lead to a circular include with formatter for vector. +template <__fmt_char_type _CharT> +class _LIBCPP_TEMPLATE_VIS __retarget_buffer { + using _Alloc = allocator<_CharT>; + +public: + using value_type = _CharT; + + struct __iterator { + using difference_type = ptrdiff_t; + using value_type = _CharT; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(__retarget_buffer& __buffer) + : __buffer_(std::addressof(__buffer)) {} + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(const _CharT& __c) { + __buffer_->push_back(__c); + return *this; + } + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator=(_CharT&& __c) { + __buffer_->push_back(__c); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator*() { return *this; } + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { return *this; } + _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { return *this; } + __retarget_buffer* __buffer_; + }; + + __retarget_buffer(const __retarget_buffer&) = delete; + __retarget_buffer& operator=(const __retarget_buffer&) = delete; + + _LIBCPP_HIDE_FROM_ABI explicit __retarget_buffer(size_t __size_hint) { + // When the initial size is very small a lot of resizes happen + // when elements added. So use a hard-coded minimum size. + // + // Note a size < 2 will not work + // - 0 there is no buffer, while push_back requires 1 empty element. + // - 1 multiplied by the grow factor is 1 and thus the buffer never + // grows. + auto __result = std::__allocate_at_least(__alloc_, std::max(__size_hint, 256 / sizeof(_CharT))); + __ptr_ = __result.ptr; + __capacity_ = __result.count; + } + + _LIBCPP_HIDE_FROM_ABI ~__retarget_buffer() { + ranges::destroy_n(__ptr_, __size_); + allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_); + } + + _LIBCPP_HIDE_FROM_ABI __iterator __make_output_iterator() { return __iterator{*this}; } + + _LIBCPP_HIDE_FROM_ABI void push_back(_CharT __c) { + std::construct_at(__ptr_ + __size_, __c); + ++__size_; + + if (__size_ == __capacity_) + __grow_buffer(); + } + + template <__fmt_char_type _InCharT> + _LIBCPP_HIDE_FROM_ABI void __copy(basic_string_view<_InCharT> __str) { + size_t __n = __str.size(); + if (__size_ + __n >= __capacity_) + // Push_back requires the buffer to have room for at least one character. + __grow_buffer(__size_ + __n + 1); + + std::uninitialized_copy_n(__str.data(), __n, __ptr_ + __size_); + __size_ += __n; + } + + template ::value_type> + _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) { + _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range"); + + size_t __n = static_cast(__last - __first); + if (__size_ + __n >= __capacity_) + // Push_back requires the buffer to have room for at least one character. + __grow_buffer(__size_ + __n + 1); + + std::uninitialized_default_construct_n(__ptr_ + __size_, __n); + std::transform(__first, __last, __ptr_ + __size_, std::move(__operation)); + __size_ += __n; + } + + _LIBCPP_HIDE_FROM_ABI void __fill(size_t __n, _CharT __value) { + if (__size_ + __n >= __capacity_) + // Push_back requires the buffer to have room for at least one character. + __grow_buffer(__size_ + __n + 1); + + std::uninitialized_fill_n(__ptr_ + __size_, __n, __value); + __size_ += __n; + } + + _LIBCPP_HIDE_FROM_ABI basic_string_view<_CharT> __view() { return {__ptr_, __size_}; } + +private: + _LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); } + + _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) { + _LIBCPP_ASSERT_INTERNAL(__capacity > __capacity_, "the buffer must grow"); + auto __result = std::__allocate_at_least(__alloc_, __capacity); + auto __guard = std::__make_exception_guard([&] { + allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count); + }); + // This shouldn't throw, but just to be safe. Note that at -O1 this + // guard is optimized away so there is no runtime overhead. + std::uninitialized_move_n(__ptr_, __size_, __result.ptr); + __guard.__complete(); + ranges::destroy_n(__ptr_, __size_); + allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_); + + __ptr_ = __result.ptr; + __capacity_ = __result.count; + } + _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_; + _CharT* __ptr_; + size_t __capacity_; + size_t __size_{0}; +}; + +} // namespace __format + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_BUFFER_H diff --git a/libcxx/include/__cxx03/__format/concepts.h b/libcxx/include/__cxx03/__format/concepts.h new file mode 100644 index 0000000000000000000000000000000000000000..13380e9b91aff85862d874607ee96f86fd0569f6 --- /dev/null +++ b/libcxx/include/__cxx03/__format/concepts.h @@ -0,0 +1,83 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_CONCEPTS_H +#define _LIBCPP___FORMAT_CONCEPTS_H + +#include <__concepts/same_as.h> +#include <__concepts/semiregular.h> +#include <__config> +#include <__format/format_parse_context.h> +#include <__fwd/format.h> +#include <__fwd/tuple.h> +#include <__tuple/tuple_size.h> +#include <__type_traits/is_specialization.h> +#include <__type_traits/remove_const.h> +#include <__type_traits/remove_reference.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +/// The character type specializations of \ref formatter. +template +concept __fmt_char_type = + same_as<_CharT, char> +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS + || same_as<_CharT, wchar_t> +# endif + ; + +// The output iterator isn't specified. A formatter should accept any +// output_iterator. This iterator is a minimal iterator to test the concept. +// (Note testing for (w)format_context would be a valid choice, but requires +// selecting the proper one depending on the type of _CharT.) +template +using __fmt_iter_for = _CharT*; + +template >> +concept __formattable_with = + semiregular<_Formatter> && + requires(_Formatter& __f, + const _Formatter& __cf, + _Tp&& __t, + _Context __fc, + basic_format_parse_context __pc) { + { __f.parse(__pc) } -> same_as; + { __cf.format(__t, __fc) } -> same_as; + }; + +template +concept __formattable = + __formattable_with, basic_format_context<__fmt_iter_for<_CharT>, _CharT>>; + +# if _LIBCPP_STD_VER >= 23 +template +concept formattable = __formattable<_Tp, _CharT>; + +// [tuple.like] defines a tuple-like exposition only concept. This concept is +// not related to that. Therefore it uses a different name for the concept. +// +// TODO FMT Add a test to validate we fail when using that concept after P2165 +// has been implemented. +template +concept __fmt_pair_like = + __is_specialization_v<_Tp, pair> || (__is_specialization_v<_Tp, tuple> && tuple_size_v<_Tp> == 2); + +# endif //_LIBCPP_STD_VER >= 23 +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_CONCEPTS_H diff --git a/libcxx/include/__cxx03/__format/container_adaptor.h b/libcxx/include/__cxx03/__format/container_adaptor.h new file mode 100644 index 0000000000000000000000000000000000000000..9f49ca03bf4f50c332262bb257e52ed3f4ac3385 --- /dev/null +++ b/libcxx/include/__cxx03/__format/container_adaptor.h @@ -0,0 +1,73 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_CONTAINER_ADAPTOR_H +#define _LIBCPP___FORMAT_CONTAINER_ADAPTOR_H + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#include <__config> +#include <__format/concepts.h> +#include <__format/formatter.h> +#include <__format/range_default_formatter.h> +#include <__fwd/queue.h> +#include <__fwd/stack.h> +#include <__ranges/ref_view.h> +#include <__type_traits/is_const.h> +#include <__type_traits/maybe_const.h> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +// [container.adaptors.format] only specifies the library should provide the +// formatter specializations, not which header should provide them. +// Since includes a lot of headers, add these headers here instead of +// adding more dependencies like, locale, optinal, string, tuple, etc. to the +// adaptor headers. To use the format functions users already include . + +template +struct _LIBCPP_TEMPLATE_VIS __formatter_container_adaptor { +private: + using __maybe_const_container = __fmt_maybe_const; + using __maybe_const_adaptor = __maybe_const, _Adaptor>; + formatter, _CharT> __underlying_; + +public: + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return __underlying_.parse(__ctx); + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator + format(__maybe_const_adaptor& __adaptor, _FormatContext& __ctx) const { + return __underlying_.format(__adaptor.__get_container(), __ctx); + } +}; + +template _Container> +struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> + : public __formatter_container_adaptor, _CharT> {}; + +template +struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> + : public __formatter_container_adaptor, _CharT> {}; + +template _Container> +struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> + : public __formatter_container_adaptor, _CharT> {}; + +#endif //_LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_CONTAINER_ADAPTOR_H diff --git a/libcxx/include/__cxx03/__format/enable_insertable.h b/libcxx/include/__cxx03/__format/enable_insertable.h new file mode 100644 index 0000000000000000000000000000000000000000..86ef94a325b1924a27458ed3874013e15f41cd0d --- /dev/null +++ b/libcxx/include/__cxx03/__format/enable_insertable.h @@ -0,0 +1,35 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_ENABLE_INSERTABLE_H +#define _LIBCPP___FORMAT_ENABLE_INSERTABLE_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __format { + +/// Opt-in to enable \ref __insertable for a \a _Container. +template +inline constexpr bool __enable_insertable = false; + +} // namespace __format + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_ENABLE_INSERTABLE_H diff --git a/libcxx/include/__cxx03/__format/escaped_output_table.h b/libcxx/include/__cxx03/__format/escaped_output_table.h new file mode 100644 index 0000000000000000000000000000000000000000..f7be2dc61f21a35102fb48a873bdd30be2b24397 --- /dev/null +++ b/libcxx/include/__cxx03/__format/escaped_output_table.h @@ -0,0 +1,863 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// WARNING, this entire header is generated by +// utils/generate_escaped_output_table.py +// DO NOT MODIFY! + +// UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE +// +// See Terms of Use +// for definitions of Unicode Inc.'s Data Files and Software. +// +// NOTICE TO USER: Carefully read the following legal agreement. +// BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +// DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +// YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +// TERMS AND CONDITIONS OF THIS AGREEMENT. +// IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +// THE DATA FILES OR SOFTWARE. +// +// COPYRIGHT AND PERMISSION NOTICE +// +// Copyright (c) 1991-2022 Unicode, Inc. All rights reserved. +// Distributed under the Terms of Use in https://www.unicode.org/copyright.html. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of the Unicode data files and any associated documentation +// (the "Data Files") or Unicode software and any associated documentation +// (the "Software") to deal in the Data Files or Software +// without restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, and/or sell copies of +// the Data Files or Software, and to permit persons to whom the Data Files +// or Software are furnished to do so, provided that either +// (a) this copyright and permission notice appear with all copies +// of the Data Files or Software, or +// (b) this copyright and permission notice appear in associated +// Documentation. +// +// THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS. +// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +// NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +// DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THE DATA FILES OR SOFTWARE. +// +// Except as contained in this notice, the name of a copyright holder +// shall not be used in advertising or otherwise to promote the sale, +// use or other dealings in these Data Files or Software without prior +// written authorization of the copyright holder. + +#ifndef _LIBCPP___FORMAT_ESCAPED_OUTPUT_TABLE_H +#define _LIBCPP___FORMAT_ESCAPED_OUTPUT_TABLE_H + +#include <__algorithm/ranges_upper_bound.h> +#include <__config> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +namespace __escaped_output_table { +// clang-format off + +/// The entries of the characters to escape in format's debug string. +/// +/// Contains the entries for [format.string.escaped]/2.2.1.2.1 +/// CE is a Unicode encoding and C corresponds to a UCS scalar value whose +/// Unicode property General_Category has a value in the groups Separator (Z) +/// or Other (C), as described by table 12 of UAX #44 +/// +/// Separator (Z) consists of General_Category +/// - Space_Separator, +/// - Line_Separator, +/// - Paragraph_Separator. +/// +/// Other (C) consists of General_Category +/// - Control, +/// - Format, +/// - Surrogate, +/// - Private_Use, +/// - Unassigned. +/// +/// The data is generated from +/// - https://www.unicode.org/Public/UCD/latest/ucd/extracted/DerivedGeneralCategory.txt +/// +/// The table is similar to the table +/// __extended_grapheme_custer_property_boundary::__entries +/// which explains the details of these classes. The only difference is this +/// table lacks a property, thus having more bits available for the size. +/// +/// The data has 2 values: +/// - bits [0, 13] The size of the range, allowing 16384 elements. +/// - bits [14, 31] The lower bound code point of the range. The upper bound of +/// the range is lower bound + size. Note the code expects code units the fit +/// into 18 bits, instead of the 21 bits needed for the full Unicode range. +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[711] = { + 0x00000020 /* 00000000 - 00000020 [ 33] */, + 0x001fc021 /* 0000007f - 000000a0 [ 34] */, + 0x002b4000 /* 000000ad - 000000ad [ 1] */, + 0x00de0001 /* 00000378 - 00000379 [ 2] */, + 0x00e00003 /* 00000380 - 00000383 [ 4] */, + 0x00e2c000 /* 0000038b - 0000038b [ 1] */, + 0x00e34000 /* 0000038d - 0000038d [ 1] */, + 0x00e88000 /* 000003a2 - 000003a2 [ 1] */, + 0x014c0000 /* 00000530 - 00000530 [ 1] */, + 0x0155c001 /* 00000557 - 00000558 [ 2] */, + 0x0162c001 /* 0000058b - 0000058c [ 2] */, + 0x01640000 /* 00000590 - 00000590 [ 1] */, + 0x01720007 /* 000005c8 - 000005cf [ 8] */, + 0x017ac003 /* 000005eb - 000005ee [ 4] */, + 0x017d4010 /* 000005f5 - 00000605 [ 17] */, + 0x01870000 /* 0000061c - 0000061c [ 1] */, + 0x01b74000 /* 000006dd - 000006dd [ 1] */, + 0x01c38001 /* 0000070e - 0000070f [ 2] */, + 0x01d2c001 /* 0000074b - 0000074c [ 2] */, + 0x01ec800d /* 000007b2 - 000007bf [ 14] */, + 0x01fec001 /* 000007fb - 000007fc [ 2] */, + 0x020b8001 /* 0000082e - 0000082f [ 2] */, + 0x020fc000 /* 0000083f - 0000083f [ 1] */, + 0x02170001 /* 0000085c - 0000085d [ 2] */, + 0x0217c000 /* 0000085f - 0000085f [ 1] */, + 0x021ac004 /* 0000086b - 0000086f [ 5] */, + 0x0223c008 /* 0000088f - 00000897 [ 9] */, + 0x02388000 /* 000008e2 - 000008e2 [ 1] */, + 0x02610000 /* 00000984 - 00000984 [ 1] */, + 0x02634001 /* 0000098d - 0000098e [ 2] */, + 0x02644001 /* 00000991 - 00000992 [ 2] */, + 0x026a4000 /* 000009a9 - 000009a9 [ 1] */, + 0x026c4000 /* 000009b1 - 000009b1 [ 1] */, + 0x026cc002 /* 000009b3 - 000009b5 [ 3] */, + 0x026e8001 /* 000009ba - 000009bb [ 2] */, + 0x02714001 /* 000009c5 - 000009c6 [ 2] */, + 0x02724001 /* 000009c9 - 000009ca [ 2] */, + 0x0273c007 /* 000009cf - 000009d6 [ 8] */, + 0x02760003 /* 000009d8 - 000009db [ 4] */, + 0x02778000 /* 000009de - 000009de [ 1] */, + 0x02790001 /* 000009e4 - 000009e5 [ 2] */, + 0x027fc001 /* 000009ff - 00000a00 [ 2] */, + 0x02810000 /* 00000a04 - 00000a04 [ 1] */, + 0x0282c003 /* 00000a0b - 00000a0e [ 4] */, + 0x02844001 /* 00000a11 - 00000a12 [ 2] */, + 0x028a4000 /* 00000a29 - 00000a29 [ 1] */, + 0x028c4000 /* 00000a31 - 00000a31 [ 1] */, + 0x028d0000 /* 00000a34 - 00000a34 [ 1] */, + 0x028dc000 /* 00000a37 - 00000a37 [ 1] */, + 0x028e8001 /* 00000a3a - 00000a3b [ 2] */, + 0x028f4000 /* 00000a3d - 00000a3d [ 1] */, + 0x0290c003 /* 00000a43 - 00000a46 [ 4] */, + 0x02924001 /* 00000a49 - 00000a4a [ 2] */, + 0x02938002 /* 00000a4e - 00000a50 [ 3] */, + 0x02948006 /* 00000a52 - 00000a58 [ 7] */, + 0x02974000 /* 00000a5d - 00000a5d [ 1] */, + 0x0297c006 /* 00000a5f - 00000a65 [ 7] */, + 0x029dc009 /* 00000a77 - 00000a80 [ 10] */, + 0x02a10000 /* 00000a84 - 00000a84 [ 1] */, + 0x02a38000 /* 00000a8e - 00000a8e [ 1] */, + 0x02a48000 /* 00000a92 - 00000a92 [ 1] */, + 0x02aa4000 /* 00000aa9 - 00000aa9 [ 1] */, + 0x02ac4000 /* 00000ab1 - 00000ab1 [ 1] */, + 0x02ad0000 /* 00000ab4 - 00000ab4 [ 1] */, + 0x02ae8001 /* 00000aba - 00000abb [ 2] */, + 0x02b18000 /* 00000ac6 - 00000ac6 [ 1] */, + 0x02b28000 /* 00000aca - 00000aca [ 1] */, + 0x02b38001 /* 00000ace - 00000acf [ 2] */, + 0x02b4400e /* 00000ad1 - 00000adf [ 15] */, + 0x02b90001 /* 00000ae4 - 00000ae5 [ 2] */, + 0x02bc8006 /* 00000af2 - 00000af8 [ 7] */, + 0x02c00000 /* 00000b00 - 00000b00 [ 1] */, + 0x02c10000 /* 00000b04 - 00000b04 [ 1] */, + 0x02c34001 /* 00000b0d - 00000b0e [ 2] */, + 0x02c44001 /* 00000b11 - 00000b12 [ 2] */, + 0x02ca4000 /* 00000b29 - 00000b29 [ 1] */, + 0x02cc4000 /* 00000b31 - 00000b31 [ 1] */, + 0x02cd0000 /* 00000b34 - 00000b34 [ 1] */, + 0x02ce8001 /* 00000b3a - 00000b3b [ 2] */, + 0x02d14001 /* 00000b45 - 00000b46 [ 2] */, + 0x02d24001 /* 00000b49 - 00000b4a [ 2] */, + 0x02d38006 /* 00000b4e - 00000b54 [ 7] */, + 0x02d60003 /* 00000b58 - 00000b5b [ 4] */, + 0x02d78000 /* 00000b5e - 00000b5e [ 1] */, + 0x02d90001 /* 00000b64 - 00000b65 [ 2] */, + 0x02de0009 /* 00000b78 - 00000b81 [ 10] */, + 0x02e10000 /* 00000b84 - 00000b84 [ 1] */, + 0x02e2c002 /* 00000b8b - 00000b8d [ 3] */, + 0x02e44000 /* 00000b91 - 00000b91 [ 1] */, + 0x02e58002 /* 00000b96 - 00000b98 [ 3] */, + 0x02e6c000 /* 00000b9b - 00000b9b [ 1] */, + 0x02e74000 /* 00000b9d - 00000b9d [ 1] */, + 0x02e80002 /* 00000ba0 - 00000ba2 [ 3] */, + 0x02e94002 /* 00000ba5 - 00000ba7 [ 3] */, + 0x02eac002 /* 00000bab - 00000bad [ 3] */, + 0x02ee8003 /* 00000bba - 00000bbd [ 4] */, + 0x02f0c002 /* 00000bc3 - 00000bc5 [ 3] */, + 0x02f24000 /* 00000bc9 - 00000bc9 [ 1] */, + 0x02f38001 /* 00000bce - 00000bcf [ 2] */, + 0x02f44005 /* 00000bd1 - 00000bd6 [ 6] */, + 0x02f6000d /* 00000bd8 - 00000be5 [ 14] */, + 0x02fec004 /* 00000bfb - 00000bff [ 5] */, + 0x03034000 /* 00000c0d - 00000c0d [ 1] */, + 0x03044000 /* 00000c11 - 00000c11 [ 1] */, + 0x030a4000 /* 00000c29 - 00000c29 [ 1] */, + 0x030e8001 /* 00000c3a - 00000c3b [ 2] */, + 0x03114000 /* 00000c45 - 00000c45 [ 1] */, + 0x03124000 /* 00000c49 - 00000c49 [ 1] */, + 0x03138006 /* 00000c4e - 00000c54 [ 7] */, + 0x0315c000 /* 00000c57 - 00000c57 [ 1] */, + 0x0316c001 /* 00000c5b - 00000c5c [ 2] */, + 0x03178001 /* 00000c5e - 00000c5f [ 2] */, + 0x03190001 /* 00000c64 - 00000c65 [ 2] */, + 0x031c0006 /* 00000c70 - 00000c76 [ 7] */, + 0x03234000 /* 00000c8d - 00000c8d [ 1] */, + 0x03244000 /* 00000c91 - 00000c91 [ 1] */, + 0x032a4000 /* 00000ca9 - 00000ca9 [ 1] */, + 0x032d0000 /* 00000cb4 - 00000cb4 [ 1] */, + 0x032e8001 /* 00000cba - 00000cbb [ 2] */, + 0x03314000 /* 00000cc5 - 00000cc5 [ 1] */, + 0x03324000 /* 00000cc9 - 00000cc9 [ 1] */, + 0x03338006 /* 00000cce - 00000cd4 [ 7] */, + 0x0335c005 /* 00000cd7 - 00000cdc [ 6] */, + 0x0337c000 /* 00000cdf - 00000cdf [ 1] */, + 0x03390001 /* 00000ce4 - 00000ce5 [ 2] */, + 0x033c0000 /* 00000cf0 - 00000cf0 [ 1] */, + 0x033d000b /* 00000cf4 - 00000cff [ 12] */, + 0x03434000 /* 00000d0d - 00000d0d [ 1] */, + 0x03444000 /* 00000d11 - 00000d11 [ 1] */, + 0x03514000 /* 00000d45 - 00000d45 [ 1] */, + 0x03524000 /* 00000d49 - 00000d49 [ 1] */, + 0x03540003 /* 00000d50 - 00000d53 [ 4] */, + 0x03590001 /* 00000d64 - 00000d65 [ 2] */, + 0x03600000 /* 00000d80 - 00000d80 [ 1] */, + 0x03610000 /* 00000d84 - 00000d84 [ 1] */, + 0x0365c002 /* 00000d97 - 00000d99 [ 3] */, + 0x036c8000 /* 00000db2 - 00000db2 [ 1] */, + 0x036f0000 /* 00000dbc - 00000dbc [ 1] */, + 0x036f8001 /* 00000dbe - 00000dbf [ 2] */, + 0x0371c002 /* 00000dc7 - 00000dc9 [ 3] */, + 0x0372c003 /* 00000dcb - 00000dce [ 4] */, + 0x03754000 /* 00000dd5 - 00000dd5 [ 1] */, + 0x0375c000 /* 00000dd7 - 00000dd7 [ 1] */, + 0x03780005 /* 00000de0 - 00000de5 [ 6] */, + 0x037c0001 /* 00000df0 - 00000df1 [ 2] */, + 0x037d400b /* 00000df5 - 00000e00 [ 12] */, + 0x038ec003 /* 00000e3b - 00000e3e [ 4] */, + 0x03970024 /* 00000e5c - 00000e80 [ 37] */, + 0x03a0c000 /* 00000e83 - 00000e83 [ 1] */, + 0x03a14000 /* 00000e85 - 00000e85 [ 1] */, + 0x03a2c000 /* 00000e8b - 00000e8b [ 1] */, + 0x03a90000 /* 00000ea4 - 00000ea4 [ 1] */, + 0x03a98000 /* 00000ea6 - 00000ea6 [ 1] */, + 0x03af8001 /* 00000ebe - 00000ebf [ 2] */, + 0x03b14000 /* 00000ec5 - 00000ec5 [ 1] */, + 0x03b1c000 /* 00000ec7 - 00000ec7 [ 1] */, + 0x03b3c000 /* 00000ecf - 00000ecf [ 1] */, + 0x03b68001 /* 00000eda - 00000edb [ 2] */, + 0x03b8001f /* 00000ee0 - 00000eff [ 32] */, + 0x03d20000 /* 00000f48 - 00000f48 [ 1] */, + 0x03db4003 /* 00000f6d - 00000f70 [ 4] */, + 0x03e60000 /* 00000f98 - 00000f98 [ 1] */, + 0x03ef4000 /* 00000fbd - 00000fbd [ 1] */, + 0x03f34000 /* 00000fcd - 00000fcd [ 1] */, + 0x03f6c024 /* 00000fdb - 00000fff [ 37] */, + 0x04318000 /* 000010c6 - 000010c6 [ 1] */, + 0x04320004 /* 000010c8 - 000010cc [ 5] */, + 0x04338001 /* 000010ce - 000010cf [ 2] */, + 0x04924000 /* 00001249 - 00001249 [ 1] */, + 0x04938001 /* 0000124e - 0000124f [ 2] */, + 0x0495c000 /* 00001257 - 00001257 [ 1] */, + 0x04964000 /* 00001259 - 00001259 [ 1] */, + 0x04978001 /* 0000125e - 0000125f [ 2] */, + 0x04a24000 /* 00001289 - 00001289 [ 1] */, + 0x04a38001 /* 0000128e - 0000128f [ 2] */, + 0x04ac4000 /* 000012b1 - 000012b1 [ 1] */, + 0x04ad8001 /* 000012b6 - 000012b7 [ 2] */, + 0x04afc000 /* 000012bf - 000012bf [ 1] */, + 0x04b04000 /* 000012c1 - 000012c1 [ 1] */, + 0x04b18001 /* 000012c6 - 000012c7 [ 2] */, + 0x04b5c000 /* 000012d7 - 000012d7 [ 1] */, + 0x04c44000 /* 00001311 - 00001311 [ 1] */, + 0x04c58001 /* 00001316 - 00001317 [ 2] */, + 0x04d6c001 /* 0000135b - 0000135c [ 2] */, + 0x04df4002 /* 0000137d - 0000137f [ 3] */, + 0x04e68005 /* 0000139a - 0000139f [ 6] */, + 0x04fd8001 /* 000013f6 - 000013f7 [ 2] */, + 0x04ff8001 /* 000013fe - 000013ff [ 2] */, + 0x05a00000 /* 00001680 - 00001680 [ 1] */, + 0x05a74002 /* 0000169d - 0000169f [ 3] */, + 0x05be4006 /* 000016f9 - 000016ff [ 7] */, + 0x05c58008 /* 00001716 - 0000171e [ 9] */, + 0x05cdc008 /* 00001737 - 0000173f [ 9] */, + 0x05d5000b /* 00001754 - 0000175f [ 12] */, + 0x05db4000 /* 0000176d - 0000176d [ 1] */, + 0x05dc4000 /* 00001771 - 00001771 [ 1] */, + 0x05dd000b /* 00001774 - 0000177f [ 12] */, + 0x05f78001 /* 000017de - 000017df [ 2] */, + 0x05fa8005 /* 000017ea - 000017ef [ 6] */, + 0x05fe8005 /* 000017fa - 000017ff [ 6] */, + 0x06038000 /* 0000180e - 0000180e [ 1] */, + 0x06068005 /* 0000181a - 0000181f [ 6] */, + 0x061e4006 /* 00001879 - 0000187f [ 7] */, + 0x062ac004 /* 000018ab - 000018af [ 5] */, + 0x063d8009 /* 000018f6 - 000018ff [ 10] */, + 0x0647c000 /* 0000191f - 0000191f [ 1] */, + 0x064b0003 /* 0000192c - 0000192f [ 4] */, + 0x064f0003 /* 0000193c - 0000193f [ 4] */, + 0x06504002 /* 00001941 - 00001943 [ 3] */, + 0x065b8001 /* 0000196e - 0000196f [ 2] */, + 0x065d400a /* 00001975 - 0000197f [ 11] */, + 0x066b0003 /* 000019ac - 000019af [ 4] */, + 0x06728005 /* 000019ca - 000019cf [ 6] */, + 0x0676c002 /* 000019db - 000019dd [ 3] */, + 0x06870001 /* 00001a1c - 00001a1d [ 2] */, + 0x0697c000 /* 00001a5f - 00001a5f [ 1] */, + 0x069f4001 /* 00001a7d - 00001a7e [ 2] */, + 0x06a28005 /* 00001a8a - 00001a8f [ 6] */, + 0x06a68005 /* 00001a9a - 00001a9f [ 6] */, + 0x06ab8001 /* 00001aae - 00001aaf [ 2] */, + 0x06b3c030 /* 00001acf - 00001aff [ 49] */, + 0x06d34002 /* 00001b4d - 00001b4f [ 3] */, + 0x06dfc000 /* 00001b7f - 00001b7f [ 1] */, + 0x06fd0007 /* 00001bf4 - 00001bfb [ 8] */, + 0x070e0002 /* 00001c38 - 00001c3a [ 3] */, + 0x07128002 /* 00001c4a - 00001c4c [ 3] */, + 0x07224006 /* 00001c89 - 00001c8f [ 7] */, + 0x072ec001 /* 00001cbb - 00001cbc [ 2] */, + 0x07320007 /* 00001cc8 - 00001ccf [ 8] */, + 0x073ec004 /* 00001cfb - 00001cff [ 5] */, + 0x07c58001 /* 00001f16 - 00001f17 [ 2] */, + 0x07c78001 /* 00001f1e - 00001f1f [ 2] */, + 0x07d18001 /* 00001f46 - 00001f47 [ 2] */, + 0x07d38001 /* 00001f4e - 00001f4f [ 2] */, + 0x07d60000 /* 00001f58 - 00001f58 [ 1] */, + 0x07d68000 /* 00001f5a - 00001f5a [ 1] */, + 0x07d70000 /* 00001f5c - 00001f5c [ 1] */, + 0x07d78000 /* 00001f5e - 00001f5e [ 1] */, + 0x07df8001 /* 00001f7e - 00001f7f [ 2] */, + 0x07ed4000 /* 00001fb5 - 00001fb5 [ 1] */, + 0x07f14000 /* 00001fc5 - 00001fc5 [ 1] */, + 0x07f50001 /* 00001fd4 - 00001fd5 [ 2] */, + 0x07f70000 /* 00001fdc - 00001fdc [ 1] */, + 0x07fc0001 /* 00001ff0 - 00001ff1 [ 2] */, + 0x07fd4000 /* 00001ff5 - 00001ff5 [ 1] */, + 0x07ffc010 /* 00001fff - 0000200f [ 17] */, + 0x080a0007 /* 00002028 - 0000202f [ 8] */, + 0x0817c010 /* 0000205f - 0000206f [ 17] */, + 0x081c8001 /* 00002072 - 00002073 [ 2] */, + 0x0823c000 /* 0000208f - 0000208f [ 1] */, + 0x08274002 /* 0000209d - 0000209f [ 3] */, + 0x0830400e /* 000020c1 - 000020cf [ 15] */, + 0x083c400e /* 000020f1 - 000020ff [ 15] */, + 0x08630003 /* 0000218c - 0000218f [ 4] */, + 0x0909c018 /* 00002427 - 0000243f [ 25] */, + 0x0912c014 /* 0000244b - 0000245f [ 21] */, + 0x0add0001 /* 00002b74 - 00002b75 [ 2] */, + 0x0ae58000 /* 00002b96 - 00002b96 [ 1] */, + 0x0b3d0004 /* 00002cf4 - 00002cf8 [ 5] */, + 0x0b498000 /* 00002d26 - 00002d26 [ 1] */, + 0x0b4a0004 /* 00002d28 - 00002d2c [ 5] */, + 0x0b4b8001 /* 00002d2e - 00002d2f [ 2] */, + 0x0b5a0006 /* 00002d68 - 00002d6e [ 7] */, + 0x0b5c400d /* 00002d71 - 00002d7e [ 14] */, + 0x0b65c008 /* 00002d97 - 00002d9f [ 9] */, + 0x0b69c000 /* 00002da7 - 00002da7 [ 1] */, + 0x0b6bc000 /* 00002daf - 00002daf [ 1] */, + 0x0b6dc000 /* 00002db7 - 00002db7 [ 1] */, + 0x0b6fc000 /* 00002dbf - 00002dbf [ 1] */, + 0x0b71c000 /* 00002dc7 - 00002dc7 [ 1] */, + 0x0b73c000 /* 00002dcf - 00002dcf [ 1] */, + 0x0b75c000 /* 00002dd7 - 00002dd7 [ 1] */, + 0x0b77c000 /* 00002ddf - 00002ddf [ 1] */, + 0x0b978021 /* 00002e5e - 00002e7f [ 34] */, + 0x0ba68000 /* 00002e9a - 00002e9a [ 1] */, + 0x0bbd000b /* 00002ef4 - 00002eff [ 12] */, + 0x0bf58019 /* 00002fd6 - 00002fef [ 26] */, + 0x0c000000 /* 00003000 - 00003000 [ 1] */, + 0x0c100000 /* 00003040 - 00003040 [ 1] */, + 0x0c25c001 /* 00003097 - 00003098 [ 2] */, + 0x0c400004 /* 00003100 - 00003104 [ 5] */, + 0x0c4c0000 /* 00003130 - 00003130 [ 1] */, + 0x0c63c000 /* 0000318f - 0000318f [ 1] */, + 0x0c79000a /* 000031e4 - 000031ee [ 11] */, + 0x0c87c000 /* 0000321f - 0000321f [ 1] */, + 0x29234002 /* 0000a48d - 0000a48f [ 3] */, + 0x2931c008 /* 0000a4c7 - 0000a4cf [ 9] */, + 0x298b0013 /* 0000a62c - 0000a63f [ 20] */, + 0x29be0007 /* 0000a6f8 - 0000a6ff [ 8] */, + 0x29f2c004 /* 0000a7cb - 0000a7cf [ 5] */, + 0x29f48000 /* 0000a7d2 - 0000a7d2 [ 1] */, + 0x29f50000 /* 0000a7d4 - 0000a7d4 [ 1] */, + 0x29f68017 /* 0000a7da - 0000a7f1 [ 24] */, + 0x2a0b4002 /* 0000a82d - 0000a82f [ 3] */, + 0x2a0e8005 /* 0000a83a - 0000a83f [ 6] */, + 0x2a1e0007 /* 0000a878 - 0000a87f [ 8] */, + 0x2a318007 /* 0000a8c6 - 0000a8cd [ 8] */, + 0x2a368005 /* 0000a8da - 0000a8df [ 6] */, + 0x2a55000a /* 0000a954 - 0000a95e [ 11] */, + 0x2a5f4002 /* 0000a97d - 0000a97f [ 3] */, + 0x2a738000 /* 0000a9ce - 0000a9ce [ 1] */, + 0x2a768003 /* 0000a9da - 0000a9dd [ 4] */, + 0x2a7fc000 /* 0000a9ff - 0000a9ff [ 1] */, + 0x2a8dc008 /* 0000aa37 - 0000aa3f [ 9] */, + 0x2a938001 /* 0000aa4e - 0000aa4f [ 2] */, + 0x2a968001 /* 0000aa5a - 0000aa5b [ 2] */, + 0x2ab0c017 /* 0000aac3 - 0000aada [ 24] */, + 0x2abdc009 /* 0000aaf7 - 0000ab00 [ 10] */, + 0x2ac1c001 /* 0000ab07 - 0000ab08 [ 2] */, + 0x2ac3c001 /* 0000ab0f - 0000ab10 [ 2] */, + 0x2ac5c008 /* 0000ab17 - 0000ab1f [ 9] */, + 0x2ac9c000 /* 0000ab27 - 0000ab27 [ 1] */, + 0x2acbc000 /* 0000ab2f - 0000ab2f [ 1] */, + 0x2adb0003 /* 0000ab6c - 0000ab6f [ 4] */, + 0x2afb8001 /* 0000abee - 0000abef [ 2] */, + 0x2afe8005 /* 0000abfa - 0000abff [ 6] */, + 0x35e9000b /* 0000d7a4 - 0000d7af [ 12] */, + 0x35f1c003 /* 0000d7c7 - 0000d7ca [ 4] */, + 0x35ff2103 /* 0000d7fc - 0000f8ff [ 8452] */, + 0x3e9b8001 /* 0000fa6e - 0000fa6f [ 2] */, + 0x3eb68025 /* 0000fada - 0000faff [ 38] */, + 0x3ec1c00b /* 0000fb07 - 0000fb12 [ 12] */, + 0x3ec60004 /* 0000fb18 - 0000fb1c [ 5] */, + 0x3ecdc000 /* 0000fb37 - 0000fb37 [ 1] */, + 0x3ecf4000 /* 0000fb3d - 0000fb3d [ 1] */, + 0x3ecfc000 /* 0000fb3f - 0000fb3f [ 1] */, + 0x3ed08000 /* 0000fb42 - 0000fb42 [ 1] */, + 0x3ed14000 /* 0000fb45 - 0000fb45 [ 1] */, + 0x3ef0c00f /* 0000fbc3 - 0000fbd2 [ 16] */, + 0x3f640001 /* 0000fd90 - 0000fd91 [ 2] */, + 0x3f720006 /* 0000fdc8 - 0000fdce [ 7] */, + 0x3f74001f /* 0000fdd0 - 0000fdef [ 32] */, + 0x3f868005 /* 0000fe1a - 0000fe1f [ 6] */, + 0x3f94c000 /* 0000fe53 - 0000fe53 [ 1] */, + 0x3f99c000 /* 0000fe67 - 0000fe67 [ 1] */, + 0x3f9b0003 /* 0000fe6c - 0000fe6f [ 4] */, + 0x3f9d4000 /* 0000fe75 - 0000fe75 [ 1] */, + 0x3fbf4003 /* 0000fefd - 0000ff00 [ 4] */, + 0x3fefc002 /* 0000ffbf - 0000ffc1 [ 3] */, + 0x3ff20001 /* 0000ffc8 - 0000ffc9 [ 2] */, + 0x3ff40001 /* 0000ffd0 - 0000ffd1 [ 2] */, + 0x3ff60001 /* 0000ffd8 - 0000ffd9 [ 2] */, + 0x3ff74002 /* 0000ffdd - 0000ffdf [ 3] */, + 0x3ff9c000 /* 0000ffe7 - 0000ffe7 [ 1] */, + 0x3ffbc00c /* 0000ffef - 0000fffb [ 13] */, + 0x3fff8001 /* 0000fffe - 0000ffff [ 2] */, + 0x40030000 /* 0001000c - 0001000c [ 1] */, + 0x4009c000 /* 00010027 - 00010027 [ 1] */, + 0x400ec000 /* 0001003b - 0001003b [ 1] */, + 0x400f8000 /* 0001003e - 0001003e [ 1] */, + 0x40138001 /* 0001004e - 0001004f [ 2] */, + 0x40178021 /* 0001005e - 0001007f [ 34] */, + 0x403ec004 /* 000100fb - 000100ff [ 5] */, + 0x4040c003 /* 00010103 - 00010106 [ 4] */, + 0x404d0002 /* 00010134 - 00010136 [ 3] */, + 0x4063c000 /* 0001018f - 0001018f [ 1] */, + 0x40674002 /* 0001019d - 0001019f [ 3] */, + 0x4068402e /* 000101a1 - 000101cf [ 47] */, + 0x407f8081 /* 000101fe - 0001027f [ 130] */, + 0x40a74002 /* 0001029d - 0001029f [ 3] */, + 0x40b4400e /* 000102d1 - 000102df [ 15] */, + 0x40bf0003 /* 000102fc - 000102ff [ 4] */, + 0x40c90008 /* 00010324 - 0001032c [ 9] */, + 0x40d2c004 /* 0001034b - 0001034f [ 5] */, + 0x40dec004 /* 0001037b - 0001037f [ 5] */, + 0x40e78000 /* 0001039e - 0001039e [ 1] */, + 0x40f10003 /* 000103c4 - 000103c7 [ 4] */, + 0x40f58029 /* 000103d6 - 000103ff [ 42] */, + 0x41278001 /* 0001049e - 0001049f [ 2] */, + 0x412a8005 /* 000104aa - 000104af [ 6] */, + 0x41350003 /* 000104d4 - 000104d7 [ 4] */, + 0x413f0003 /* 000104fc - 000104ff [ 4] */, + 0x414a0007 /* 00010528 - 0001052f [ 8] */, + 0x4159000a /* 00010564 - 0001056e [ 11] */, + 0x415ec000 /* 0001057b - 0001057b [ 1] */, + 0x4162c000 /* 0001058b - 0001058b [ 1] */, + 0x4164c000 /* 00010593 - 00010593 [ 1] */, + 0x41658000 /* 00010596 - 00010596 [ 1] */, + 0x41688000 /* 000105a2 - 000105a2 [ 1] */, + 0x416c8000 /* 000105b2 - 000105b2 [ 1] */, + 0x416e8000 /* 000105ba - 000105ba [ 1] */, + 0x416f4042 /* 000105bd - 000105ff [ 67] */, + 0x41cdc008 /* 00010737 - 0001073f [ 9] */, + 0x41d58009 /* 00010756 - 0001075f [ 10] */, + 0x41da0017 /* 00010768 - 0001077f [ 24] */, + 0x41e18000 /* 00010786 - 00010786 [ 1] */, + 0x41ec4000 /* 000107b1 - 000107b1 [ 1] */, + 0x41eec044 /* 000107bb - 000107ff [ 69] */, + 0x42018001 /* 00010806 - 00010807 [ 2] */, + 0x42024000 /* 00010809 - 00010809 [ 1] */, + 0x420d8000 /* 00010836 - 00010836 [ 1] */, + 0x420e4002 /* 00010839 - 0001083b [ 3] */, + 0x420f4001 /* 0001083d - 0001083e [ 2] */, + 0x42158000 /* 00010856 - 00010856 [ 1] */, + 0x4227c007 /* 0001089f - 000108a6 [ 8] */, + 0x422c002f /* 000108b0 - 000108df [ 48] */, + 0x423cc000 /* 000108f3 - 000108f3 [ 1] */, + 0x423d8004 /* 000108f6 - 000108fa [ 5] */, + 0x42470002 /* 0001091c - 0001091e [ 3] */, + 0x424e8004 /* 0001093a - 0001093e [ 5] */, + 0x4250003f /* 00010940 - 0001097f [ 64] */, + 0x426e0003 /* 000109b8 - 000109bb [ 4] */, + 0x42740001 /* 000109d0 - 000109d1 [ 2] */, + 0x42810000 /* 00010a04 - 00010a04 [ 1] */, + 0x4281c004 /* 00010a07 - 00010a0b [ 5] */, + 0x42850000 /* 00010a14 - 00010a14 [ 1] */, + 0x42860000 /* 00010a18 - 00010a18 [ 1] */, + 0x428d8001 /* 00010a36 - 00010a37 [ 2] */, + 0x428ec003 /* 00010a3b - 00010a3e [ 4] */, + 0x42924006 /* 00010a49 - 00010a4f [ 7] */, + 0x42964006 /* 00010a59 - 00010a5f [ 7] */, + 0x42a8001f /* 00010aa0 - 00010abf [ 32] */, + 0x42b9c003 /* 00010ae7 - 00010aea [ 4] */, + 0x42bdc008 /* 00010af7 - 00010aff [ 9] */, + 0x42cd8002 /* 00010b36 - 00010b38 [ 3] */, + 0x42d58001 /* 00010b56 - 00010b57 [ 2] */, + 0x42dcc004 /* 00010b73 - 00010b77 [ 5] */, + 0x42e48006 /* 00010b92 - 00010b98 [ 7] */, + 0x42e7400b /* 00010b9d - 00010ba8 [ 12] */, + 0x42ec004f /* 00010bb0 - 00010bff [ 80] */, + 0x43124036 /* 00010c49 - 00010c7f [ 55] */, + 0x432cc00c /* 00010cb3 - 00010cbf [ 13] */, + 0x433cc006 /* 00010cf3 - 00010cf9 [ 7] */, + 0x434a0007 /* 00010d28 - 00010d2f [ 8] */, + 0x434e8125 /* 00010d3a - 00010e5f [ 294] */, + 0x439fc000 /* 00010e7f - 00010e7f [ 1] */, + 0x43aa8000 /* 00010eaa - 00010eaa [ 1] */, + 0x43ab8001 /* 00010eae - 00010eaf [ 2] */, + 0x43ac804a /* 00010eb2 - 00010efc [ 75] */, + 0x43ca0007 /* 00010f28 - 00010f2f [ 8] */, + 0x43d68015 /* 00010f5a - 00010f6f [ 22] */, + 0x43e28025 /* 00010f8a - 00010faf [ 38] */, + 0x43f30013 /* 00010fcc - 00010fdf [ 20] */, + 0x43fdc008 /* 00010ff7 - 00010fff [ 9] */, + 0x44138003 /* 0001104e - 00011051 [ 4] */, + 0x441d8008 /* 00011076 - 0001107e [ 9] */, + 0x442f4000 /* 000110bd - 000110bd [ 1] */, + 0x4430c00c /* 000110c3 - 000110cf [ 13] */, + 0x443a4006 /* 000110e9 - 000110ef [ 7] */, + 0x443e8005 /* 000110fa - 000110ff [ 6] */, + 0x444d4000 /* 00011135 - 00011135 [ 1] */, + 0x44520007 /* 00011148 - 0001114f [ 8] */, + 0x445dc008 /* 00011177 - 0001117f [ 9] */, + 0x44780000 /* 000111e0 - 000111e0 [ 1] */, + 0x447d400a /* 000111f5 - 000111ff [ 11] */, + 0x44848000 /* 00011212 - 00011212 [ 1] */, + 0x4490803d /* 00011242 - 0001127f [ 62] */, + 0x44a1c000 /* 00011287 - 00011287 [ 1] */, + 0x44a24000 /* 00011289 - 00011289 [ 1] */, + 0x44a38000 /* 0001128e - 0001128e [ 1] */, + 0x44a78000 /* 0001129e - 0001129e [ 1] */, + 0x44aa8005 /* 000112aa - 000112af [ 6] */, + 0x44bac004 /* 000112eb - 000112ef [ 5] */, + 0x44be8005 /* 000112fa - 000112ff [ 6] */, + 0x44c10000 /* 00011304 - 00011304 [ 1] */, + 0x44c34001 /* 0001130d - 0001130e [ 2] */, + 0x44c44001 /* 00011311 - 00011312 [ 2] */, + 0x44ca4000 /* 00011329 - 00011329 [ 1] */, + 0x44cc4000 /* 00011331 - 00011331 [ 1] */, + 0x44cd0000 /* 00011334 - 00011334 [ 1] */, + 0x44ce8000 /* 0001133a - 0001133a [ 1] */, + 0x44d14001 /* 00011345 - 00011346 [ 2] */, + 0x44d24001 /* 00011349 - 0001134a [ 2] */, + 0x44d38001 /* 0001134e - 0001134f [ 2] */, + 0x44d44005 /* 00011351 - 00011356 [ 6] */, + 0x44d60004 /* 00011358 - 0001135c [ 5] */, + 0x44d90001 /* 00011364 - 00011365 [ 2] */, + 0x44db4002 /* 0001136d - 0001136f [ 3] */, + 0x44dd408a /* 00011375 - 000113ff [ 139] */, + 0x45170000 /* 0001145c - 0001145c [ 1] */, + 0x4518801d /* 00011462 - 0001147f [ 30] */, + 0x45320007 /* 000114c8 - 000114cf [ 8] */, + 0x453680a5 /* 000114da - 0001157f [ 166] */, + 0x456d8001 /* 000115b6 - 000115b7 [ 2] */, + 0x45778021 /* 000115de - 000115ff [ 34] */, + 0x4591400a /* 00011645 - 0001164f [ 11] */, + 0x45968005 /* 0001165a - 0001165f [ 6] */, + 0x459b4012 /* 0001166d - 0001167f [ 19] */, + 0x45ae8005 /* 000116ba - 000116bf [ 6] */, + 0x45b28035 /* 000116ca - 000116ff [ 54] */, + 0x45c6c001 /* 0001171b - 0001171c [ 2] */, + 0x45cb0003 /* 0001172c - 0001172f [ 4] */, + 0x45d1c0b8 /* 00011747 - 000117ff [ 185] */, + 0x460f0063 /* 0001183c - 0001189f [ 100] */, + 0x463cc00b /* 000118f3 - 000118fe [ 12] */, + 0x4641c001 /* 00011907 - 00011908 [ 2] */, + 0x46428001 /* 0001190a - 0001190b [ 2] */, + 0x46450000 /* 00011914 - 00011914 [ 1] */, + 0x4645c000 /* 00011917 - 00011917 [ 1] */, + 0x464d8000 /* 00011936 - 00011936 [ 1] */, + 0x464e4001 /* 00011939 - 0001193a [ 2] */, + 0x4651c008 /* 00011947 - 0001194f [ 9] */, + 0x46568045 /* 0001195a - 0001199f [ 70] */, + 0x466a0001 /* 000119a8 - 000119a9 [ 2] */, + 0x46760001 /* 000119d8 - 000119d9 [ 2] */, + 0x4679401a /* 000119e5 - 000119ff [ 27] */, + 0x46920007 /* 00011a48 - 00011a4f [ 8] */, + 0x46a8c00c /* 00011aa3 - 00011aaf [ 13] */, + 0x46be4006 /* 00011af9 - 00011aff [ 7] */, + 0x46c280f5 /* 00011b0a - 00011bff [ 246] */, + 0x47024000 /* 00011c09 - 00011c09 [ 1] */, + 0x470dc000 /* 00011c37 - 00011c37 [ 1] */, + 0x47118009 /* 00011c46 - 00011c4f [ 10] */, + 0x471b4002 /* 00011c6d - 00011c6f [ 3] */, + 0x47240001 /* 00011c90 - 00011c91 [ 2] */, + 0x472a0000 /* 00011ca8 - 00011ca8 [ 1] */, + 0x472dc048 /* 00011cb7 - 00011cff [ 73] */, + 0x4741c000 /* 00011d07 - 00011d07 [ 1] */, + 0x47428000 /* 00011d0a - 00011d0a [ 1] */, + 0x474dc002 /* 00011d37 - 00011d39 [ 3] */, + 0x474ec000 /* 00011d3b - 00011d3b [ 1] */, + 0x474f8000 /* 00011d3e - 00011d3e [ 1] */, + 0x47520007 /* 00011d48 - 00011d4f [ 8] */, + 0x47568005 /* 00011d5a - 00011d5f [ 6] */, + 0x47598000 /* 00011d66 - 00011d66 [ 1] */, + 0x475a4000 /* 00011d69 - 00011d69 [ 1] */, + 0x4763c000 /* 00011d8f - 00011d8f [ 1] */, + 0x47648000 /* 00011d92 - 00011d92 [ 1] */, + 0x47664006 /* 00011d99 - 00011d9f [ 7] */, + 0x476a8135 /* 00011daa - 00011edf [ 310] */, + 0x47be4006 /* 00011ef9 - 00011eff [ 7] */, + 0x47c44000 /* 00011f11 - 00011f11 [ 1] */, + 0x47cec002 /* 00011f3b - 00011f3d [ 3] */, + 0x47d68055 /* 00011f5a - 00011faf [ 86] */, + 0x47ec400e /* 00011fb1 - 00011fbf [ 15] */, + 0x47fc800c /* 00011ff2 - 00011ffe [ 13] */, + 0x48e68065 /* 0001239a - 000123ff [ 102] */, + 0x491bc000 /* 0001246f - 0001246f [ 1] */, + 0x491d400a /* 00012475 - 0001247f [ 11] */, + 0x49510a4b /* 00012544 - 00012f8f [ 2636] */, + 0x4bfcc00c /* 00012ff3 - 00012fff [ 13] */, + 0x4d0c000f /* 00013430 - 0001343f [ 16] */, + 0x4d158fa9 /* 00013456 - 000143ff [ 4010] */, + 0x5191e1b8 /* 00014647 - 000167ff [ 8633] */, + 0x5a8e4006 /* 00016a39 - 00016a3f [ 7] */, + 0x5a97c000 /* 00016a5f - 00016a5f [ 1] */, + 0x5a9a8003 /* 00016a6a - 00016a6d [ 4] */, + 0x5aafc000 /* 00016abf - 00016abf [ 1] */, + 0x5ab28005 /* 00016aca - 00016acf [ 6] */, + 0x5abb8001 /* 00016aee - 00016aef [ 2] */, + 0x5abd8009 /* 00016af6 - 00016aff [ 10] */, + 0x5ad18009 /* 00016b46 - 00016b4f [ 10] */, + 0x5ad68000 /* 00016b5a - 00016b5a [ 1] */, + 0x5ad88000 /* 00016b62 - 00016b62 [ 1] */, + 0x5ade0004 /* 00016b78 - 00016b7c [ 5] */, + 0x5ae402af /* 00016b90 - 00016e3f [ 688] */, + 0x5ba6c064 /* 00016e9b - 00016eff [ 101] */, + 0x5bd2c003 /* 00016f4b - 00016f4e [ 4] */, + 0x5be20006 /* 00016f88 - 00016f8e [ 7] */, + 0x5be8003f /* 00016fa0 - 00016fdf [ 64] */, + 0x5bf9400a /* 00016fe5 - 00016fef [ 11] */, + 0x5bfc800d /* 00016ff2 - 00016fff [ 14] */, + 0x61fe0007 /* 000187f8 - 000187ff [ 8] */, + 0x63358029 /* 00018cd6 - 00018cff [ 42] */, + 0x634262e6 /* 00018d09 - 0001afef [ 8935] */, + 0x6bfd0000 /* 0001aff4 - 0001aff4 [ 1] */, + 0x6bff0000 /* 0001affc - 0001affc [ 1] */, + 0x6bffc000 /* 0001afff - 0001afff [ 1] */, + 0x6c48c00e /* 0001b123 - 0001b131 [ 15] */, + 0x6c4cc01c /* 0001b133 - 0001b14f [ 29] */, + 0x6c54c001 /* 0001b153 - 0001b154 [ 2] */, + 0x6c55800d /* 0001b156 - 0001b163 [ 14] */, + 0x6c5a0007 /* 0001b168 - 0001b16f [ 8] */, + 0x6cbf0903 /* 0001b2fc - 0001bbff [ 2308] */, + 0x6f1ac004 /* 0001bc6b - 0001bc6f [ 5] */, + 0x6f1f4002 /* 0001bc7d - 0001bc7f [ 3] */, + 0x6f224006 /* 0001bc89 - 0001bc8f [ 7] */, + 0x6f268001 /* 0001bc9a - 0001bc9b [ 2] */, + 0x6f28125f /* 0001bca0 - 0001ceff [ 4704] */, + 0x73cb8001 /* 0001cf2e - 0001cf2f [ 2] */, + 0x73d1c008 /* 0001cf47 - 0001cf4f [ 9] */, + 0x73f1003b /* 0001cfc4 - 0001cfff [ 60] */, + 0x743d8009 /* 0001d0f6 - 0001d0ff [ 10] */, + 0x7449c001 /* 0001d127 - 0001d128 [ 2] */, + 0x745cc007 /* 0001d173 - 0001d17a [ 8] */, + 0x747ac014 /* 0001d1eb - 0001d1ff [ 21] */, + 0x74918079 /* 0001d246 - 0001d2bf [ 122] */, + 0x74b5000b /* 0001d2d4 - 0001d2df [ 12] */, + 0x74bd000b /* 0001d2f4 - 0001d2ff [ 12] */, + 0x74d5c008 /* 0001d357 - 0001d35f [ 9] */, + 0x74de4086 /* 0001d379 - 0001d3ff [ 135] */, + 0x75154000 /* 0001d455 - 0001d455 [ 1] */, + 0x75274000 /* 0001d49d - 0001d49d [ 1] */, + 0x75280001 /* 0001d4a0 - 0001d4a1 [ 2] */, + 0x7528c001 /* 0001d4a3 - 0001d4a4 [ 2] */, + 0x7529c001 /* 0001d4a7 - 0001d4a8 [ 2] */, + 0x752b4000 /* 0001d4ad - 0001d4ad [ 1] */, + 0x752e8000 /* 0001d4ba - 0001d4ba [ 1] */, + 0x752f0000 /* 0001d4bc - 0001d4bc [ 1] */, + 0x75310000 /* 0001d4c4 - 0001d4c4 [ 1] */, + 0x75418000 /* 0001d506 - 0001d506 [ 1] */, + 0x7542c001 /* 0001d50b - 0001d50c [ 2] */, + 0x75454000 /* 0001d515 - 0001d515 [ 1] */, + 0x75474000 /* 0001d51d - 0001d51d [ 1] */, + 0x754e8000 /* 0001d53a - 0001d53a [ 1] */, + 0x754fc000 /* 0001d53f - 0001d53f [ 1] */, + 0x75514000 /* 0001d545 - 0001d545 [ 1] */, + 0x7551c002 /* 0001d547 - 0001d549 [ 3] */, + 0x75544000 /* 0001d551 - 0001d551 [ 1] */, + 0x75a98001 /* 0001d6a6 - 0001d6a7 [ 2] */, + 0x75f30001 /* 0001d7cc - 0001d7cd [ 2] */, + 0x76a3000e /* 0001da8c - 0001da9a [ 15] */, + 0x76a80000 /* 0001daa0 - 0001daa0 [ 1] */, + 0x76ac044f /* 0001dab0 - 0001deff [ 1104] */, + 0x77c7c005 /* 0001df1f - 0001df24 [ 6] */, + 0x77cac0d4 /* 0001df2b - 0001dfff [ 213] */, + 0x7801c000 /* 0001e007 - 0001e007 [ 1] */, + 0x78064001 /* 0001e019 - 0001e01a [ 2] */, + 0x78088000 /* 0001e022 - 0001e022 [ 1] */, + 0x78094000 /* 0001e025 - 0001e025 [ 1] */, + 0x780ac004 /* 0001e02b - 0001e02f [ 5] */, + 0x781b8020 /* 0001e06e - 0001e08e [ 33] */, + 0x7824006f /* 0001e090 - 0001e0ff [ 112] */, + 0x784b4002 /* 0001e12d - 0001e12f [ 3] */, + 0x784f8001 /* 0001e13e - 0001e13f [ 2] */, + 0x78528003 /* 0001e14a - 0001e14d [ 4] */, + 0x7854013f /* 0001e150 - 0001e28f [ 320] */, + 0x78abc010 /* 0001e2af - 0001e2bf [ 17] */, + 0x78be8004 /* 0001e2fa - 0001e2fe [ 5] */, + 0x78c001cf /* 0001e300 - 0001e4cf [ 464] */, + 0x793e82e5 /* 0001e4fa - 0001e7df [ 742] */, + 0x79f9c000 /* 0001e7e7 - 0001e7e7 [ 1] */, + 0x79fb0000 /* 0001e7ec - 0001e7ec [ 1] */, + 0x79fbc000 /* 0001e7ef - 0001e7ef [ 1] */, + 0x79ffc000 /* 0001e7ff - 0001e7ff [ 1] */, + 0x7a314001 /* 0001e8c5 - 0001e8c6 [ 2] */, + 0x7a35c028 /* 0001e8d7 - 0001e8ff [ 41] */, + 0x7a530003 /* 0001e94c - 0001e94f [ 4] */, + 0x7a568003 /* 0001e95a - 0001e95d [ 4] */, + 0x7a580310 /* 0001e960 - 0001ec70 [ 785] */, + 0x7b2d404b /* 0001ecb5 - 0001ed00 [ 76] */, + 0x7b4f80c1 /* 0001ed3e - 0001edff [ 194] */, + 0x7b810000 /* 0001ee04 - 0001ee04 [ 1] */, + 0x7b880000 /* 0001ee20 - 0001ee20 [ 1] */, + 0x7b88c000 /* 0001ee23 - 0001ee23 [ 1] */, + 0x7b894001 /* 0001ee25 - 0001ee26 [ 2] */, + 0x7b8a0000 /* 0001ee28 - 0001ee28 [ 1] */, + 0x7b8cc000 /* 0001ee33 - 0001ee33 [ 1] */, + 0x7b8e0000 /* 0001ee38 - 0001ee38 [ 1] */, + 0x7b8e8000 /* 0001ee3a - 0001ee3a [ 1] */, + 0x7b8f0005 /* 0001ee3c - 0001ee41 [ 6] */, + 0x7b90c003 /* 0001ee43 - 0001ee46 [ 4] */, + 0x7b920000 /* 0001ee48 - 0001ee48 [ 1] */, + 0x7b928000 /* 0001ee4a - 0001ee4a [ 1] */, + 0x7b930000 /* 0001ee4c - 0001ee4c [ 1] */, + 0x7b940000 /* 0001ee50 - 0001ee50 [ 1] */, + 0x7b94c000 /* 0001ee53 - 0001ee53 [ 1] */, + 0x7b954001 /* 0001ee55 - 0001ee56 [ 2] */, + 0x7b960000 /* 0001ee58 - 0001ee58 [ 1] */, + 0x7b968000 /* 0001ee5a - 0001ee5a [ 1] */, + 0x7b970000 /* 0001ee5c - 0001ee5c [ 1] */, + 0x7b978000 /* 0001ee5e - 0001ee5e [ 1] */, + 0x7b980000 /* 0001ee60 - 0001ee60 [ 1] */, + 0x7b98c000 /* 0001ee63 - 0001ee63 [ 1] */, + 0x7b994001 /* 0001ee65 - 0001ee66 [ 2] */, + 0x7b9ac000 /* 0001ee6b - 0001ee6b [ 1] */, + 0x7b9cc000 /* 0001ee73 - 0001ee73 [ 1] */, + 0x7b9e0000 /* 0001ee78 - 0001ee78 [ 1] */, + 0x7b9f4000 /* 0001ee7d - 0001ee7d [ 1] */, + 0x7b9fc000 /* 0001ee7f - 0001ee7f [ 1] */, + 0x7ba28000 /* 0001ee8a - 0001ee8a [ 1] */, + 0x7ba70004 /* 0001ee9c - 0001eea0 [ 5] */, + 0x7ba90000 /* 0001eea4 - 0001eea4 [ 1] */, + 0x7baa8000 /* 0001eeaa - 0001eeaa [ 1] */, + 0x7baf0033 /* 0001eebc - 0001eeef [ 52] */, + 0x7bbc810d /* 0001eef2 - 0001efff [ 270] */, + 0x7c0b0003 /* 0001f02c - 0001f02f [ 4] */, + 0x7c25000b /* 0001f094 - 0001f09f [ 12] */, + 0x7c2bc001 /* 0001f0af - 0001f0b0 [ 2] */, + 0x7c300000 /* 0001f0c0 - 0001f0c0 [ 1] */, + 0x7c340000 /* 0001f0d0 - 0001f0d0 [ 1] */, + 0x7c3d8009 /* 0001f0f6 - 0001f0ff [ 10] */, + 0x7c6b8037 /* 0001f1ae - 0001f1e5 [ 56] */, + 0x7c80c00c /* 0001f203 - 0001f20f [ 13] */, + 0x7c8f0003 /* 0001f23c - 0001f23f [ 4] */, + 0x7c924006 /* 0001f249 - 0001f24f [ 7] */, + 0x7c94800d /* 0001f252 - 0001f25f [ 14] */, + 0x7c998099 /* 0001f266 - 0001f2ff [ 154] */, + 0x7db60003 /* 0001f6d8 - 0001f6db [ 4] */, + 0x7dbb4002 /* 0001f6ed - 0001f6ef [ 3] */, + 0x7dbf4002 /* 0001f6fd - 0001f6ff [ 3] */, + 0x7dddc003 /* 0001f777 - 0001f77a [ 4] */, + 0x7df68005 /* 0001f7da - 0001f7df [ 6] */, + 0x7dfb0003 /* 0001f7ec - 0001f7ef [ 4] */, + 0x7dfc400e /* 0001f7f1 - 0001f7ff [ 15] */, + 0x7e030003 /* 0001f80c - 0001f80f [ 4] */, + 0x7e120007 /* 0001f848 - 0001f84f [ 8] */, + 0x7e168005 /* 0001f85a - 0001f85f [ 6] */, + 0x7e220007 /* 0001f888 - 0001f88f [ 8] */, + 0x7e2b8001 /* 0001f8ae - 0001f8af [ 2] */, + 0x7e2c804d /* 0001f8b2 - 0001f8ff [ 78] */, + 0x7e95000b /* 0001fa54 - 0001fa5f [ 12] */, + 0x7e9b8001 /* 0001fa6e - 0001fa6f [ 2] */, + 0x7e9f4002 /* 0001fa7d - 0001fa7f [ 3] */, + 0x7ea24006 /* 0001fa89 - 0001fa8f [ 7] */, + 0x7eaf8000 /* 0001fabe - 0001fabe [ 1] */, + 0x7eb18007 /* 0001fac6 - 0001facd [ 8] */, + 0x7eb70003 /* 0001fadc - 0001fadf [ 4] */, + 0x7eba4006 /* 0001fae9 - 0001faef [ 7] */, + 0x7ebe4006 /* 0001faf9 - 0001faff [ 7] */, + 0x7ee4c000 /* 0001fb93 - 0001fb93 [ 1] */, + 0x7ef2c024 /* 0001fbcb - 0001fbef [ 37] */, + 0x7efe8405 /* 0001fbfa - 0001ffff [ 1030] */, + 0xa9b8001f /* 0002a6e0 - 0002a6ff [ 32] */, + 0xadce8005 /* 0002b73a - 0002b73f [ 6] */, + 0xae078001 /* 0002b81e - 0002b81f [ 2] */, + 0xb3a8800d /* 0002cea2 - 0002ceaf [ 14] */, + 0xbaf8400e /* 0002ebe1 - 0002ebef [ 15] */, + 0xbb9789a1 /* 0002ee5e - 0002f7ff [ 2466] */, + 0xbe8785e1 /* 0002fa1e - 0002ffff [ 1506] */, + 0xc4d2c004 /* 0003134b - 0003134f [ 5] */}; + +/// Returns whether the code unit needs to be escaped. +/// +/// At the end of the valid Unicode code points space a lot of code points are +/// either reserved or a noncharacter. Adding all these entries to the +/// lookup table would greatly increase the size of the table. Instead these +/// entries are manually processed. In this large area of reserved code points, +/// there is a small area of extended graphemes that should not be escaped +/// unconditionally. This is also manually coded. See the generation script for +/// more details. + +/// +/// \\pre The code point is a valid Unicode code point. +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool __needs_escape(const char32_t __code_point) noexcept { + + // The entries in the gap at the end. + if(__code_point >= 0x000e0100 && __code_point <= 0x000e01ef) + return false; + + // The entries at the end. + if (__code_point >= 0x000323b0) + return true; + + ptrdiff_t __i = std::ranges::upper_bound(__entries, (__code_point << 14) | 0x3fffu) - __entries; + if (__i == 0) + return false; + + --__i; + uint32_t __upper_bound = (__entries[__i] >> 14) + (__entries[__i] & 0x3fffu); + return __code_point <= __upper_bound; +} + +// clang-format on +} // namespace __escaped_output_table + +#endif //_LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_ESCAPED_OUTPUT_TABLE_H diff --git a/libcxx/include/__cxx03/__format/extended_grapheme_cluster_table.h b/libcxx/include/__cxx03/__format/extended_grapheme_cluster_table.h new file mode 100644 index 0000000000000000000000000000000000000000..48581d8a5dde3df96a5cf25610e4d5bef9413dd5 --- /dev/null +++ b/libcxx/include/__cxx03/__format/extended_grapheme_cluster_table.h @@ -0,0 +1,1663 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// WARNING, this entire header is generated by +// utils/generate_extended_grapheme_cluster_table.py +// DO NOT MODIFY! + +// UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE +// +// See Terms of Use +// for definitions of Unicode Inc.'s Data Files and Software. +// +// NOTICE TO USER: Carefully read the following legal agreement. +// BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +// DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +// YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +// TERMS AND CONDITIONS OF THIS AGREEMENT. +// IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +// THE DATA FILES OR SOFTWARE. +// +// COPYRIGHT AND PERMISSION NOTICE +// +// Copyright (c) 1991-2022 Unicode, Inc. All rights reserved. +// Distributed under the Terms of Use in https://www.unicode.org/copyright.html. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of the Unicode data files and any associated documentation +// (the "Data Files") or Unicode software and any associated documentation +// (the "Software") to deal in the Data Files or Software +// without restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, and/or sell copies of +// the Data Files or Software, and to permit persons to whom the Data Files +// or Software are furnished to do so, provided that either +// (a) this copyright and permission notice appear with all copies +// of the Data Files or Software, or +// (b) this copyright and permission notice appear in associated +// Documentation. +// +// THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS. +// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +// NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +// DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THE DATA FILES OR SOFTWARE. +// +// Except as contained in this notice, the name of a copyright holder +// shall not be used in advertising or otherwise to promote the sale, +// use or other dealings in these Data Files or Software without prior +// written authorization of the copyright holder. + +#ifndef _LIBCPP___FORMAT_EXTENDED_GRAPHEME_CLUSTER_TABLE_H +#define _LIBCPP___FORMAT_EXTENDED_GRAPHEME_CLUSTER_TABLE_H + +#include <__algorithm/ranges_upper_bound.h> +#include <__config> +#include <__iterator/access.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __extended_grapheme_custer_property_boundary { + +enum class __property : uint8_t { + // Values generated from the data files. + __CR, + __Control, + __Extend, + __Extended_Pictographic, + __L, + __LF, + __LV, + __LVT, + __Prepend, + __Regional_Indicator, + __SpacingMark, + __T, + __V, + __ZWJ, + + // The properies below aren't stored in the "database". + + // Text position properties. + __sot, + __eot, + + // The code unit has none of above properties. + __none +}; + +/// The entries of the extended grapheme cluster bondary property table. +/// +/// The data is generated from +/// - https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakProperty.txt +/// - https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt +/// +/// The data has 3 values +/// - bits [0, 3] The property. One of the values generated from the datafiles +/// of \ref __property +/// - bits [4, 10] The size of the range. +/// - bits [11, 31] The lower bound code point of the range. The upper bound of +/// the range is lower bound + size. +/// +/// The 7 bits for the size allow a maximum range of 128 elements. Some ranges +/// in the Unicode tables are larger. They are stored in multiple consecutive +/// ranges in the data table. An alternative would be to store the sizes in a +/// separate 16-bit value. The original MSVC STL code had such an approach, but +/// this approach uses less space for the data and is about 4% faster in the +/// following benchmark. +/// libcxx/benchmarks/std_format_spec_string_unicode.bench.cpp +// clang-format off +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1496] = { + 0x00000091, + 0x00005005, + 0x00005811, + 0x00006800, + 0x00007111, + 0x0003fa01, + 0x00054803, + 0x00056801, + 0x00057003, + 0x001806f2, + 0x00241862, + 0x002c8ac2, + 0x002df802, + 0x002e0812, + 0x002e2012, + 0x002e3802, + 0x00300058, + 0x003080a2, + 0x0030e001, + 0x00325942, + 0x00338002, + 0x0036b062, + 0x0036e808, + 0x0036f852, + 0x00373812, + 0x00375032, + 0x00387808, + 0x00388802, + 0x003981a2, + 0x003d30a2, + 0x003f5882, + 0x003fe802, + 0x0040b032, + 0x0040d882, + 0x00412822, + 0x00414842, + 0x0042c822, + 0x00448018, + 0x0044c072, + 0x00465172, + 0x00471008, + 0x004719f2, + 0x0048180a, + 0x0049d002, + 0x0049d80a, + 0x0049e002, + 0x0049f02a, + 0x004a0872, + 0x004a483a, + 0x004a6802, + 0x004a701a, + 0x004a8862, + 0x004b1012, + 0x004c0802, + 0x004c101a, + 0x004de002, + 0x004df002, + 0x004df81a, + 0x004e0832, + 0x004e381a, + 0x004e581a, + 0x004e6802, + 0x004eb802, + 0x004f1012, + 0x004ff002, + 0x00500812, + 0x0050180a, + 0x0051e002, + 0x0051f02a, + 0x00520812, + 0x00523812, + 0x00525822, + 0x00528802, + 0x00538012, + 0x0053a802, + 0x00540812, + 0x0054180a, + 0x0055e002, + 0x0055f02a, + 0x00560842, + 0x00563812, + 0x0056480a, + 0x0056581a, + 0x00566802, + 0x00571012, + 0x0057d052, + 0x00580802, + 0x0058101a, + 0x0059e002, + 0x0059f012, + 0x005a000a, + 0x005a0832, + 0x005a381a, + 0x005a581a, + 0x005a6802, + 0x005aa822, + 0x005b1012, + 0x005c1002, + 0x005df002, + 0x005df80a, + 0x005e0002, + 0x005e081a, + 0x005e302a, + 0x005e502a, + 0x005e6802, + 0x005eb802, + 0x00600002, + 0x0060082a, + 0x00602002, + 0x0061e002, + 0x0061f022, + 0x0062083a, + 0x00623022, + 0x00625032, + 0x0062a812, + 0x00631012, + 0x00640802, + 0x0064101a, + 0x0065e002, + 0x0065f00a, + 0x0065f802, + 0x0066001a, + 0x00661002, + 0x0066181a, + 0x00663002, + 0x0066381a, + 0x0066501a, + 0x00666012, + 0x0066a812, + 0x00671012, + 0x0067980a, + 0x00680012, + 0x0068101a, + 0x0069d812, + 0x0069f002, + 0x0069f81a, + 0x006a0832, + 0x006a302a, + 0x006a502a, + 0x006a6802, + 0x006a7008, + 0x006ab802, + 0x006b1012, + 0x006c0802, + 0x006c101a, + 0x006e5002, + 0x006e7802, + 0x006e801a, + 0x006e9022, + 0x006eb002, + 0x006ec06a, + 0x006ef802, + 0x006f901a, + 0x00718802, + 0x0071980a, + 0x0071a062, + 0x00723872, + 0x00758802, + 0x0075980a, + 0x0075a082, + 0x00764062, + 0x0078c012, + 0x0079a802, + 0x0079b802, + 0x0079c802, + 0x0079f01a, + 0x007b88d2, + 0x007bf80a, + 0x007c0042, + 0x007c3012, + 0x007c68a2, + 0x007cca32, + 0x007e3002, + 0x00816832, + 0x0081880a, + 0x00819052, + 0x0081c812, + 0x0081d81a, + 0x0081e812, + 0x0082b01a, + 0x0082c012, + 0x0082f022, + 0x00838832, + 0x00841002, + 0x0084200a, + 0x00842812, + 0x00846802, + 0x0084e802, + 0x008805f4, + 0x008b047c, + 0x008d457b, + 0x009ae822, + 0x00b89022, + 0x00b8a80a, + 0x00b99012, + 0x00b9a00a, + 0x00ba9012, + 0x00bb9012, + 0x00bda012, + 0x00bdb00a, + 0x00bdb862, + 0x00bdf07a, + 0x00be3002, + 0x00be381a, + 0x00be48a2, + 0x00bee802, + 0x00c05822, + 0x00c07001, + 0x00c07802, + 0x00c42812, + 0x00c54802, + 0x00c90022, + 0x00c9183a, + 0x00c93812, + 0x00c9482a, + 0x00c9801a, + 0x00c99002, + 0x00c9985a, + 0x00c9c822, + 0x00d0b812, + 0x00d0c81a, + 0x00d0d802, + 0x00d2a80a, + 0x00d2b002, + 0x00d2b80a, + 0x00d2c062, + 0x00d30002, + 0x00d31002, + 0x00d32872, + 0x00d3685a, + 0x00d39892, + 0x00d3f802, + 0x00d581e2, + 0x00d80032, + 0x00d8200a, + 0x00d9a062, + 0x00d9d80a, + 0x00d9e002, + 0x00d9e84a, + 0x00da1002, + 0x00da181a, + 0x00db5882, + 0x00dc0012, + 0x00dc100a, + 0x00dd080a, + 0x00dd1032, + 0x00dd301a, + 0x00dd4012, + 0x00dd500a, + 0x00dd5822, + 0x00df3002, + 0x00df380a, + 0x00df4012, + 0x00df502a, + 0x00df6802, + 0x00df700a, + 0x00df7822, + 0x00df901a, + 0x00e1207a, + 0x00e16072, + 0x00e1a01a, + 0x00e1b012, + 0x00e68022, + 0x00e6a0c2, + 0x00e7080a, + 0x00e71062, + 0x00e76802, + 0x00e7a002, + 0x00e7b80a, + 0x00e7c012, + 0x00ee03f2, + 0x01005801, + 0x01006002, + 0x0100680d, + 0x01007011, + 0x01014061, + 0x0101e003, + 0x01024803, + 0x010300f1, + 0x01068202, + 0x01091003, + 0x0109c803, + 0x010ca053, + 0x010d4813, + 0x0118d013, + 0x01194003, + 0x011c4003, + 0x011e7803, + 0x011f48a3, + 0x011fc023, + 0x01261003, + 0x012d5013, + 0x012db003, + 0x012e0003, + 0x012fd833, + 0x01300053, + 0x013038b3, + 0x0130a713, + 0x01348753, + 0x013840a3, + 0x0138a003, + 0x0138b003, + 0x0138e803, + 0x01390803, + 0x01394003, + 0x01399813, + 0x013a2003, + 0x013a3803, + 0x013a6003, + 0x013a7003, + 0x013a9823, + 0x013ab803, + 0x013b1843, + 0x013ca823, + 0x013d0803, + 0x013d8003, + 0x013df803, + 0x0149a013, + 0x01582823, + 0x0158d813, + 0x015a8003, + 0x015aa803, + 0x01677822, + 0x016bf802, + 0x016f01f2, + 0x01815052, + 0x01818003, + 0x0181e803, + 0x0184c812, + 0x0194b803, + 0x0194c803, + 0x05337832, + 0x0533a092, + 0x0534f012, + 0x05378012, + 0x05401002, + 0x05403002, + 0x05405802, + 0x0541181a, + 0x05412812, + 0x0541380a, + 0x05416002, + 0x0544001a, + 0x0545a0fa, + 0x05462012, + 0x05470112, + 0x0547f802, + 0x05493072, + 0x054a38a2, + 0x054a901a, + 0x054b01c4, + 0x054c0022, + 0x054c180a, + 0x054d9802, + 0x054da01a, + 0x054db032, + 0x054dd01a, + 0x054de012, + 0x054df02a, + 0x054f2802, + 0x05514852, + 0x0551781a, + 0x05518812, + 0x0551981a, + 0x0551a812, + 0x05521802, + 0x05526002, + 0x0552680a, + 0x0553e002, + 0x05558002, + 0x05559022, + 0x0555b812, + 0x0555f012, + 0x05560802, + 0x0557580a, + 0x05576012, + 0x0557701a, + 0x0557a80a, + 0x0557b002, + 0x055f181a, + 0x055f2802, + 0x055f301a, + 0x055f4002, + 0x055f481a, + 0x055f600a, + 0x055f6802, + 0x05600006, + 0x056009a7, + 0x0560e006, + 0x0560e9a7, + 0x0561c006, + 0x0561c9a7, + 0x0562a006, + 0x0562a9a7, + 0x05638006, + 0x056389a7, + 0x05646006, + 0x056469a7, + 0x05654006, + 0x056549a7, + 0x05662006, + 0x056629a7, + 0x05670006, + 0x056709a7, + 0x0567e006, + 0x0567e9a7, + 0x0568c006, + 0x0568c9a7, + 0x0569a006, + 0x0569a9a7, + 0x056a8006, + 0x056a89a7, + 0x056b6006, + 0x056b69a7, + 0x056c4006, + 0x056c49a7, + 0x056d2006, + 0x056d29a7, + 0x056e0006, + 0x056e09a7, + 0x056ee006, + 0x056ee9a7, + 0x056fc006, + 0x056fc9a7, + 0x0570a006, + 0x0570a9a7, + 0x05718006, + 0x057189a7, + 0x05726006, + 0x057269a7, + 0x05734006, + 0x057349a7, + 0x05742006, + 0x057429a7, + 0x05750006, + 0x057509a7, + 0x0575e006, + 0x0575e9a7, + 0x0576c006, + 0x0576c9a7, + 0x0577a006, + 0x0577a9a7, + 0x05788006, + 0x057889a7, + 0x05796006, + 0x057969a7, + 0x057a4006, + 0x057a49a7, + 0x057b2006, + 0x057b29a7, + 0x057c0006, + 0x057c09a7, + 0x057ce006, + 0x057ce9a7, + 0x057dc006, + 0x057dc9a7, + 0x057ea006, + 0x057ea9a7, + 0x057f8006, + 0x057f89a7, + 0x05806006, + 0x058069a7, + 0x05814006, + 0x058149a7, + 0x05822006, + 0x058229a7, + 0x05830006, + 0x058309a7, + 0x0583e006, + 0x0583e9a7, + 0x0584c006, + 0x0584c9a7, + 0x0585a006, + 0x0585a9a7, + 0x05868006, + 0x058689a7, + 0x05876006, + 0x058769a7, + 0x05884006, + 0x058849a7, + 0x05892006, + 0x058929a7, + 0x058a0006, + 0x058a09a7, + 0x058ae006, + 0x058ae9a7, + 0x058bc006, + 0x058bc9a7, + 0x058ca006, + 0x058ca9a7, + 0x058d8006, + 0x058d89a7, + 0x058e6006, + 0x058e69a7, + 0x058f4006, + 0x058f49a7, + 0x05902006, + 0x059029a7, + 0x05910006, + 0x059109a7, + 0x0591e006, + 0x0591e9a7, + 0x0592c006, + 0x0592c9a7, + 0x0593a006, + 0x0593a9a7, + 0x05948006, + 0x059489a7, + 0x05956006, + 0x059569a7, + 0x05964006, + 0x059649a7, + 0x05972006, + 0x059729a7, + 0x05980006, + 0x059809a7, + 0x0598e006, + 0x0598e9a7, + 0x0599c006, + 0x0599c9a7, + 0x059aa006, + 0x059aa9a7, + 0x059b8006, + 0x059b89a7, + 0x059c6006, + 0x059c69a7, + 0x059d4006, + 0x059d49a7, + 0x059e2006, + 0x059e29a7, + 0x059f0006, + 0x059f09a7, + 0x059fe006, + 0x059fe9a7, + 0x05a0c006, + 0x05a0c9a7, + 0x05a1a006, + 0x05a1a9a7, + 0x05a28006, + 0x05a289a7, + 0x05a36006, + 0x05a369a7, + 0x05a44006, + 0x05a449a7, + 0x05a52006, + 0x05a529a7, + 0x05a60006, + 0x05a609a7, + 0x05a6e006, + 0x05a6e9a7, + 0x05a7c006, + 0x05a7c9a7, + 0x05a8a006, + 0x05a8a9a7, + 0x05a98006, + 0x05a989a7, + 0x05aa6006, + 0x05aa69a7, + 0x05ab4006, + 0x05ab49a7, + 0x05ac2006, + 0x05ac29a7, + 0x05ad0006, + 0x05ad09a7, + 0x05ade006, + 0x05ade9a7, + 0x05aec006, + 0x05aec9a7, + 0x05afa006, + 0x05afa9a7, + 0x05b08006, + 0x05b089a7, + 0x05b16006, + 0x05b169a7, + 0x05b24006, + 0x05b249a7, + 0x05b32006, + 0x05b329a7, + 0x05b40006, + 0x05b409a7, + 0x05b4e006, + 0x05b4e9a7, + 0x05b5c006, + 0x05b5c9a7, + 0x05b6a006, + 0x05b6a9a7, + 0x05b78006, + 0x05b789a7, + 0x05b86006, + 0x05b869a7, + 0x05b94006, + 0x05b949a7, + 0x05ba2006, + 0x05ba29a7, + 0x05bb0006, + 0x05bb09a7, + 0x05bbe006, + 0x05bbe9a7, + 0x05bcc006, + 0x05bcc9a7, + 0x05bda006, + 0x05bda9a7, + 0x05be8006, + 0x05be89a7, + 0x05bf6006, + 0x05bf69a7, + 0x05c04006, + 0x05c049a7, + 0x05c12006, + 0x05c129a7, + 0x05c20006, + 0x05c209a7, + 0x05c2e006, + 0x05c2e9a7, + 0x05c3c006, + 0x05c3c9a7, + 0x05c4a006, + 0x05c4a9a7, + 0x05c58006, + 0x05c589a7, + 0x05c66006, + 0x05c669a7, + 0x05c74006, + 0x05c749a7, + 0x05c82006, + 0x05c829a7, + 0x05c90006, + 0x05c909a7, + 0x05c9e006, + 0x05c9e9a7, + 0x05cac006, + 0x05cac9a7, + 0x05cba006, + 0x05cba9a7, + 0x05cc8006, + 0x05cc89a7, + 0x05cd6006, + 0x05cd69a7, + 0x05ce4006, + 0x05ce49a7, + 0x05cf2006, + 0x05cf29a7, + 0x05d00006, + 0x05d009a7, + 0x05d0e006, + 0x05d0e9a7, + 0x05d1c006, + 0x05d1c9a7, + 0x05d2a006, + 0x05d2a9a7, + 0x05d38006, + 0x05d389a7, + 0x05d46006, + 0x05d469a7, + 0x05d54006, + 0x05d549a7, + 0x05d62006, + 0x05d629a7, + 0x05d70006, + 0x05d709a7, + 0x05d7e006, + 0x05d7e9a7, + 0x05d8c006, + 0x05d8c9a7, + 0x05d9a006, + 0x05d9a9a7, + 0x05da8006, + 0x05da89a7, + 0x05db6006, + 0x05db69a7, + 0x05dc4006, + 0x05dc49a7, + 0x05dd2006, + 0x05dd29a7, + 0x05de0006, + 0x05de09a7, + 0x05dee006, + 0x05dee9a7, + 0x05dfc006, + 0x05dfc9a7, + 0x05e0a006, + 0x05e0a9a7, + 0x05e18006, + 0x05e189a7, + 0x05e26006, + 0x05e269a7, + 0x05e34006, + 0x05e349a7, + 0x05e42006, + 0x05e429a7, + 0x05e50006, + 0x05e509a7, + 0x05e5e006, + 0x05e5e9a7, + 0x05e6c006, + 0x05e6c9a7, + 0x05e7a006, + 0x05e7a9a7, + 0x05e88006, + 0x05e889a7, + 0x05e96006, + 0x05e969a7, + 0x05ea4006, + 0x05ea49a7, + 0x05eb2006, + 0x05eb29a7, + 0x05ec0006, + 0x05ec09a7, + 0x05ece006, + 0x05ece9a7, + 0x05edc006, + 0x05edc9a7, + 0x05eea006, + 0x05eea9a7, + 0x05ef8006, + 0x05ef89a7, + 0x05f06006, + 0x05f069a7, + 0x05f14006, + 0x05f149a7, + 0x05f22006, + 0x05f229a7, + 0x05f30006, + 0x05f309a7, + 0x05f3e006, + 0x05f3e9a7, + 0x05f4c006, + 0x05f4c9a7, + 0x05f5a006, + 0x05f5a9a7, + 0x05f68006, + 0x05f689a7, + 0x05f76006, + 0x05f769a7, + 0x05f84006, + 0x05f849a7, + 0x05f92006, + 0x05f929a7, + 0x05fa0006, + 0x05fa09a7, + 0x05fae006, + 0x05fae9a7, + 0x05fbc006, + 0x05fbc9a7, + 0x05fca006, + 0x05fca9a7, + 0x05fd8006, + 0x05fd89a7, + 0x05fe6006, + 0x05fe69a7, + 0x05ff4006, + 0x05ff49a7, + 0x06002006, + 0x060029a7, + 0x06010006, + 0x060109a7, + 0x0601e006, + 0x0601e9a7, + 0x0602c006, + 0x0602c9a7, + 0x0603a006, + 0x0603a9a7, + 0x06048006, + 0x060489a7, + 0x06056006, + 0x060569a7, + 0x06064006, + 0x060649a7, + 0x06072006, + 0x060729a7, + 0x06080006, + 0x060809a7, + 0x0608e006, + 0x0608e9a7, + 0x0609c006, + 0x0609c9a7, + 0x060aa006, + 0x060aa9a7, + 0x060b8006, + 0x060b89a7, + 0x060c6006, + 0x060c69a7, + 0x060d4006, + 0x060d49a7, + 0x060e2006, + 0x060e29a7, + 0x060f0006, + 0x060f09a7, + 0x060fe006, + 0x060fe9a7, + 0x0610c006, + 0x0610c9a7, + 0x0611a006, + 0x0611a9a7, + 0x06128006, + 0x061289a7, + 0x06136006, + 0x061369a7, + 0x06144006, + 0x061449a7, + 0x06152006, + 0x061529a7, + 0x06160006, + 0x061609a7, + 0x0616e006, + 0x0616e9a7, + 0x0617c006, + 0x0617c9a7, + 0x0618a006, + 0x0618a9a7, + 0x06198006, + 0x061989a7, + 0x061a6006, + 0x061a69a7, + 0x061b4006, + 0x061b49a7, + 0x061c2006, + 0x061c29a7, + 0x061d0006, + 0x061d09a7, + 0x061de006, + 0x061de9a7, + 0x061ec006, + 0x061ec9a7, + 0x061fa006, + 0x061fa9a7, + 0x06208006, + 0x062089a7, + 0x06216006, + 0x062169a7, + 0x06224006, + 0x062249a7, + 0x06232006, + 0x062329a7, + 0x06240006, + 0x062409a7, + 0x0624e006, + 0x0624e9a7, + 0x0625c006, + 0x0625c9a7, + 0x0626a006, + 0x0626a9a7, + 0x06278006, + 0x062789a7, + 0x06286006, + 0x062869a7, + 0x06294006, + 0x062949a7, + 0x062a2006, + 0x062a29a7, + 0x062b0006, + 0x062b09a7, + 0x062be006, + 0x062be9a7, + 0x062cc006, + 0x062cc9a7, + 0x062da006, + 0x062da9a7, + 0x062e8006, + 0x062e89a7, + 0x062f6006, + 0x062f69a7, + 0x06304006, + 0x063049a7, + 0x06312006, + 0x063129a7, + 0x06320006, + 0x063209a7, + 0x0632e006, + 0x0632e9a7, + 0x0633c006, + 0x0633c9a7, + 0x0634a006, + 0x0634a9a7, + 0x06358006, + 0x063589a7, + 0x06366006, + 0x063669a7, + 0x06374006, + 0x063749a7, + 0x06382006, + 0x063829a7, + 0x06390006, + 0x063909a7, + 0x0639e006, + 0x0639e9a7, + 0x063ac006, + 0x063ac9a7, + 0x063ba006, + 0x063ba9a7, + 0x063c8006, + 0x063c89a7, + 0x063d6006, + 0x063d69a7, + 0x063e4006, + 0x063e49a7, + 0x063f2006, + 0x063f29a7, + 0x06400006, + 0x064009a7, + 0x0640e006, + 0x0640e9a7, + 0x0641c006, + 0x0641c9a7, + 0x0642a006, + 0x0642a9a7, + 0x06438006, + 0x064389a7, + 0x06446006, + 0x064469a7, + 0x06454006, + 0x064549a7, + 0x06462006, + 0x064629a7, + 0x06470006, + 0x064709a7, + 0x0647e006, + 0x0647e9a7, + 0x0648c006, + 0x0648c9a7, + 0x0649a006, + 0x0649a9a7, + 0x064a8006, + 0x064a89a7, + 0x064b6006, + 0x064b69a7, + 0x064c4006, + 0x064c49a7, + 0x064d2006, + 0x064d29a7, + 0x064e0006, + 0x064e09a7, + 0x064ee006, + 0x064ee9a7, + 0x064fc006, + 0x064fc9a7, + 0x0650a006, + 0x0650a9a7, + 0x06518006, + 0x065189a7, + 0x06526006, + 0x065269a7, + 0x06534006, + 0x065349a7, + 0x06542006, + 0x065429a7, + 0x06550006, + 0x065509a7, + 0x0655e006, + 0x0655e9a7, + 0x0656c006, + 0x0656c9a7, + 0x0657a006, + 0x0657a9a7, + 0x06588006, + 0x065889a7, + 0x06596006, + 0x065969a7, + 0x065a4006, + 0x065a49a7, + 0x065b2006, + 0x065b29a7, + 0x065c0006, + 0x065c09a7, + 0x065ce006, + 0x065ce9a7, + 0x065dc006, + 0x065dc9a7, + 0x065ea006, + 0x065ea9a7, + 0x065f8006, + 0x065f89a7, + 0x06606006, + 0x066069a7, + 0x06614006, + 0x066149a7, + 0x06622006, + 0x066229a7, + 0x06630006, + 0x066309a7, + 0x0663e006, + 0x0663e9a7, + 0x0664c006, + 0x0664c9a7, + 0x0665a006, + 0x0665a9a7, + 0x06668006, + 0x066689a7, + 0x06676006, + 0x066769a7, + 0x06684006, + 0x066849a7, + 0x06692006, + 0x066929a7, + 0x066a0006, + 0x066a09a7, + 0x066ae006, + 0x066ae9a7, + 0x066bc006, + 0x066bc9a7, + 0x066ca006, + 0x066ca9a7, + 0x066d8006, + 0x066d89a7, + 0x066e6006, + 0x066e69a7, + 0x066f4006, + 0x066f49a7, + 0x06702006, + 0x067029a7, + 0x06710006, + 0x067109a7, + 0x0671e006, + 0x0671e9a7, + 0x0672c006, + 0x0672c9a7, + 0x0673a006, + 0x0673a9a7, + 0x06748006, + 0x067489a7, + 0x06756006, + 0x067569a7, + 0x06764006, + 0x067649a7, + 0x06772006, + 0x067729a7, + 0x06780006, + 0x067809a7, + 0x0678e006, + 0x0678e9a7, + 0x0679c006, + 0x0679c9a7, + 0x067aa006, + 0x067aa9a7, + 0x067b8006, + 0x067b89a7, + 0x067c6006, + 0x067c69a7, + 0x067d4006, + 0x067d49a7, + 0x067e2006, + 0x067e29a7, + 0x067f0006, + 0x067f09a7, + 0x067fe006, + 0x067fe9a7, + 0x0680c006, + 0x0680c9a7, + 0x0681a006, + 0x0681a9a7, + 0x06828006, + 0x068289a7, + 0x06836006, + 0x068369a7, + 0x06844006, + 0x068449a7, + 0x06852006, + 0x068529a7, + 0x06860006, + 0x068609a7, + 0x0686e006, + 0x0686e9a7, + 0x0687c006, + 0x0687c9a7, + 0x0688a006, + 0x0688a9a7, + 0x06898006, + 0x068989a7, + 0x068a6006, + 0x068a69a7, + 0x068b4006, + 0x068b49a7, + 0x068c2006, + 0x068c29a7, + 0x068d0006, + 0x068d09a7, + 0x068de006, + 0x068de9a7, + 0x068ec006, + 0x068ec9a7, + 0x068fa006, + 0x068fa9a7, + 0x06908006, + 0x069089a7, + 0x06916006, + 0x069169a7, + 0x06924006, + 0x069249a7, + 0x06932006, + 0x069329a7, + 0x06940006, + 0x069409a7, + 0x0694e006, + 0x0694e9a7, + 0x0695c006, + 0x0695c9a7, + 0x0696a006, + 0x0696a9a7, + 0x06978006, + 0x069789a7, + 0x06986006, + 0x069869a7, + 0x06994006, + 0x069949a7, + 0x069a2006, + 0x069a29a7, + 0x069b0006, + 0x069b09a7, + 0x069be006, + 0x069be9a7, + 0x069cc006, + 0x069cc9a7, + 0x069da006, + 0x069da9a7, + 0x069e8006, + 0x069e89a7, + 0x069f6006, + 0x069f69a7, + 0x06a04006, + 0x06a049a7, + 0x06a12006, + 0x06a129a7, + 0x06a20006, + 0x06a209a7, + 0x06a2e006, + 0x06a2e9a7, + 0x06a3c006, + 0x06a3c9a7, + 0x06a4a006, + 0x06a4a9a7, + 0x06a58006, + 0x06a589a7, + 0x06a66006, + 0x06a669a7, + 0x06a74006, + 0x06a749a7, + 0x06a82006, + 0x06a829a7, + 0x06a90006, + 0x06a909a7, + 0x06a9e006, + 0x06a9e9a7, + 0x06aac006, + 0x06aac9a7, + 0x06aba006, + 0x06aba9a7, + 0x06ac8006, + 0x06ac89a7, + 0x06ad6006, + 0x06ad69a7, + 0x06ae4006, + 0x06ae49a7, + 0x06af2006, + 0x06af29a7, + 0x06b00006, + 0x06b009a7, + 0x06b0e006, + 0x06b0e9a7, + 0x06b1c006, + 0x06b1c9a7, + 0x06b2a006, + 0x06b2a9a7, + 0x06b38006, + 0x06b389a7, + 0x06b46006, + 0x06b469a7, + 0x06b54006, + 0x06b549a7, + 0x06b62006, + 0x06b629a7, + 0x06b70006, + 0x06b709a7, + 0x06b7e006, + 0x06b7e9a7, + 0x06b8c006, + 0x06b8c9a7, + 0x06b9a006, + 0x06b9a9a7, + 0x06ba8006, + 0x06ba89a7, + 0x06bb6006, + 0x06bb69a7, + 0x06bc4006, + 0x06bc49a7, + 0x06bd816c, + 0x06be5b0b, + 0x07d8f002, + 0x07f000f2, + 0x07f100f2, + 0x07f7f801, + 0x07fcf012, + 0x07ff80b1, + 0x080fe802, + 0x08170002, + 0x081bb042, + 0x08500822, + 0x08502812, + 0x08506032, + 0x0851c022, + 0x0851f802, + 0x08572812, + 0x08692032, + 0x08755812, + 0x0877e822, + 0x087a30a2, + 0x087c1032, + 0x0880000a, + 0x08800802, + 0x0880100a, + 0x0881c0e2, + 0x08838002, + 0x08839812, + 0x0883f822, + 0x0884100a, + 0x0885802a, + 0x08859832, + 0x0885b81a, + 0x0885c812, + 0x0885e808, + 0x08861002, + 0x08866808, + 0x08880022, + 0x08893842, + 0x0889600a, + 0x08896872, + 0x088a281a, + 0x088b9802, + 0x088c0012, + 0x088c100a, + 0x088d982a, + 0x088db082, + 0x088df81a, + 0x088e1018, + 0x088e4832, + 0x088e700a, + 0x088e7802, + 0x0891602a, + 0x08917822, + 0x0891901a, + 0x0891a002, + 0x0891a80a, + 0x0891b012, + 0x0891f002, + 0x08920802, + 0x0896f802, + 0x0897002a, + 0x08971872, + 0x08980012, + 0x0898101a, + 0x0899d812, + 0x0899f002, + 0x0899f80a, + 0x089a0002, + 0x089a083a, + 0x089a381a, + 0x089a582a, + 0x089ab802, + 0x089b101a, + 0x089b3062, + 0x089b8042, + 0x08a1a82a, + 0x08a1c072, + 0x08a2001a, + 0x08a21022, + 0x08a2280a, + 0x08a23002, + 0x08a2f002, + 0x08a58002, + 0x08a5881a, + 0x08a59852, + 0x08a5c80a, + 0x08a5d002, + 0x08a5d81a, + 0x08a5e802, + 0x08a5f00a, + 0x08a5f812, + 0x08a6080a, + 0x08a61012, + 0x08ad7802, + 0x08ad801a, + 0x08ad9032, + 0x08adc03a, + 0x08ade012, + 0x08adf00a, + 0x08adf812, + 0x08aee012, + 0x08b1802a, + 0x08b19872, + 0x08b1d81a, + 0x08b1e802, + 0x08b1f00a, + 0x08b1f812, + 0x08b55802, + 0x08b5600a, + 0x08b56802, + 0x08b5701a, + 0x08b58052, + 0x08b5b00a, + 0x08b5b802, + 0x08b8e822, + 0x08b91032, + 0x08b9300a, + 0x08b93842, + 0x08c1602a, + 0x08c17882, + 0x08c1c00a, + 0x08c1c812, + 0x08c98002, + 0x08c9884a, + 0x08c9b81a, + 0x08c9d812, + 0x08c9e80a, + 0x08c9f002, + 0x08c9f808, + 0x08ca000a, + 0x08ca0808, + 0x08ca100a, + 0x08ca1802, + 0x08ce882a, + 0x08cea032, + 0x08ced012, + 0x08cee03a, + 0x08cf0002, + 0x08cf200a, + 0x08d00892, + 0x08d19852, + 0x08d1c80a, + 0x08d1d008, + 0x08d1d832, + 0x08d23802, + 0x08d28852, + 0x08d2b81a, + 0x08d2c822, + 0x08d42058, + 0x08d450c2, + 0x08d4b80a, + 0x08d4c012, + 0x08e1780a, + 0x08e18062, + 0x08e1c052, + 0x08e1f00a, + 0x08e1f802, + 0x08e49152, + 0x08e5480a, + 0x08e55062, + 0x08e5880a, + 0x08e59012, + 0x08e5a00a, + 0x08e5a812, + 0x08e98852, + 0x08e9d002, + 0x08e9e012, + 0x08e9f862, + 0x08ea3008, + 0x08ea3802, + 0x08ec504a, + 0x08ec8012, + 0x08ec981a, + 0x08eca802, + 0x08ecb00a, + 0x08ecb802, + 0x08f79812, + 0x08f7a81a, + 0x08f80012, + 0x08f81008, + 0x08f8180a, + 0x08f9a01a, + 0x08f9b042, + 0x08f9f01a, + 0x08fa0002, + 0x08fa080a, + 0x08fa1002, + 0x09a180f1, + 0x09a20002, + 0x09a238e2, + 0x0b578042, + 0x0b598062, + 0x0b7a7802, + 0x0b7a8b6a, + 0x0b7c7832, + 0x0b7f2002, + 0x0b7f801a, + 0x0de4e812, + 0x0de50031, + 0x0e7802d2, + 0x0e798162, + 0x0e8b2802, + 0x0e8b300a, + 0x0e8b3822, + 0x0e8b680a, + 0x0e8b7042, + 0x0e8b9871, + 0x0e8bd872, + 0x0e8c2862, + 0x0e8d5032, + 0x0e921022, + 0x0ed00362, + 0x0ed1db12, + 0x0ed3a802, + 0x0ed42002, + 0x0ed4d842, + 0x0ed508e2, + 0x0f000062, + 0x0f004102, + 0x0f00d862, + 0x0f011812, + 0x0f013042, + 0x0f047802, + 0x0f098062, + 0x0f157002, + 0x0f176032, + 0x0f276032, + 0x0f468062, + 0x0f4a2062, + 0x0f8007f3, + 0x0f8407f3, + 0x0f886823, + 0x0f897803, + 0x0f8b6053, + 0x0f8bf013, + 0x0f8c7003, + 0x0f8c8893, + 0x0f8d6b83, + 0x0f8f3199, + 0x0f9008e3, + 0x0f90d003, + 0x0f917803, + 0x0f919083, + 0x0f91e033, + 0x0f924ff3, + 0x0f964ff3, + 0x0f9a4ff3, + 0x0f9e4b13, + 0x0f9fd842, + 0x0fa007f3, + 0x0fa407f3, + 0x0fa803d3, + 0x0faa37f3, + 0x0fae37f3, + 0x0fb23093, + 0x0fb407f3, + 0x0fbba0b3, + 0x0fbeaaa3, + 0x0fc06033, + 0x0fc24073, + 0x0fc2d053, + 0x0fc44073, + 0x0fc57513, + 0x0fc862e3, + 0x0fc9e093, + 0x0fca3ff3, + 0x0fce3ff3, + 0x0fd23ff3, + 0x0fd63b83, + 0x0fe007f3, + 0x0fe407f3, + 0x0fe807f3, + 0x0fec07f3, + 0x0ff007f3, + 0x0ff407f3, + 0x0ff807f3, + 0x0ffc07d3, + 0x700001f1, + 0x700105f2, + 0x700407f1, + 0x700807f2, + 0x700c06f2, + 0x700f87f1, + 0x701387f1, + 0x701787f1, + 0x701b87f1, + 0x701f87f1, + 0x702387f1, + 0x702787f1, + 0x702b87f1, + 0x702f87f1, + 0x703387f1, + 0x703787f1, + 0x703b87f1, + 0x703f87f1, + 0x704387f1, + 0x704787f1, + 0x704b87f1, + 0x704f87f1, + 0x705387f1, + 0x705787f1, + 0x705b87f1, + 0x705f87f1, + 0x706387f1, + 0x706787f1, + 0x706b87f1, + 0x706f87f1, + 0x707387f1, + 0x707787f1, + 0x707b87f1, + 0x707f80f1}; +// clang-format on + +/// Returns the extended grapheme cluster bondary property of a code point. +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __property __get_property(const char32_t __code_point) noexcept { + // The algorithm searches for the upper bound of the range and, when found, + // steps back one entry. This algorithm is used since the code point can be + // anywhere in the range. After a lower bound is found the next step is to + // compare whether the code unit is indeed in the range. + // + // Since the entry contains a code unit, size, and property the code point + // being sought needs to be adjusted. Just shifting the code point to the + // proper position doesn't work; suppose an entry has property 0, size 1, + // and lower bound 3. This results in the entry 0x1810. + // When searching for code point 3 it will search for 0x1800, find 0x1810 + // and moves to the previous entry. Thus the lower bound value will never + // be found. + // The simple solution is to set the bits belonging to the property and + // size. Then the upper bound for code point 3 will return the entry after + // 0x1810. After moving to the previous entry the algorithm arrives at the + // correct entry. + ptrdiff_t __i = std::ranges::upper_bound(__entries, (__code_point << 11) | 0x7ffu) - __entries; + if (__i == 0) + return __property::__none; + + --__i; + uint32_t __upper_bound = (__entries[__i] >> 11) + ((__entries[__i] >> 4) & 0x7f); + if (__code_point <= __upper_bound) + return static_cast<__property>(__entries[__i] & 0xf); + + return __property::__none; +} + +} // namespace __extended_grapheme_custer_property_boundary + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_EXTENDED_GRAPHEME_CLUSTER_TABLE_H diff --git a/libcxx/include/__cxx03/__format/format_arg.h b/libcxx/include/__cxx03/__format/format_arg.h new file mode 100644 index 0000000000000000000000000000000000000000..aa02f81dc40e2d8eb283047038448c6d68990946 --- /dev/null +++ b/libcxx/include/__cxx03/__format/format_arg.h @@ -0,0 +1,401 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMAT_ARG_H +#define _LIBCPP___FORMAT_FORMAT_ARG_H + +#include <__assert> +#include <__concepts/arithmetic.h> +#include <__config> +#include <__format/concepts.h> +#include <__format/format_parse_context.h> +#include <__functional/invoke.h> +#include <__fwd/format.h> +#include <__memory/addressof.h> +#include <__type_traits/conditional.h> +#include <__type_traits/remove_const.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <__utility/unreachable.h> +#include <__variant/monostate.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __format { +/// The type stored in @ref basic_format_arg. +/// +/// @note The 128-bit types are unconditionally in the list to avoid the values +/// of the enums to depend on the availability of 128-bit integers. +/// +/// @note The value is stored as a 5-bit value in the __packed_arg_t_bits. This +/// limits the maximum number of elements to 32. +/// When modifying update the test +/// test/libcxx/utilities/format/format.arguments/format.arg/arg_t.compile.pass.cpp +/// It could be packed in 4-bits but that means a new type directly becomes an +/// ABI break. The packed type is 64-bit so this reduces the maximum number of +/// packed elements from 16 to 12. +/// +/// @note Some members of this enum are an extension. These extensions need +/// special behaviour in visit_format_arg. There they need to be wrapped in a +/// handle to satisfy the user observable behaviour. The internal function +/// __visit_format_arg doesn't do this wrapping. So in the format functions +/// this function is used to avoid unneeded overhead. +enum class __arg_t : uint8_t { + __none, + __boolean, + __char_type, + __int, + __long_long, + __i128, // extension + __unsigned, + __unsigned_long_long, + __u128, // extension + __float, + __double, + __long_double, + __const_char_type_ptr, + __string_view, + __ptr, + __handle +}; + +inline constexpr unsigned __packed_arg_t_bits = 5; +inline constexpr uint8_t __packed_arg_t_mask = 0x1f; + +inline constexpr unsigned __packed_types_storage_bits = 64; +inline constexpr unsigned __packed_types_max = __packed_types_storage_bits / __packed_arg_t_bits; + +_LIBCPP_HIDE_FROM_ABI constexpr bool __use_packed_format_arg_store(size_t __size) { + return __size <= __packed_types_max; +} + +_LIBCPP_HIDE_FROM_ABI constexpr __arg_t __get_packed_type(uint64_t __types, size_t __id) { + _LIBCPP_ASSERT_INTERNAL(__id <= __packed_types_max, ""); + + if (__id > 0) + __types >>= __id * __packed_arg_t_bits; + + return static_cast<__format::__arg_t>(__types & __packed_arg_t_mask); +} + +} // namespace __format + +// This function is not user observable, so it can directly use the non-standard +// types of the "variant". See __arg_t for more details. +template +_LIBCPP_HIDE_FROM_ABI decltype(auto) __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) { + switch (__arg.__type_) { + case __format::__arg_t::__none: + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__monostate_); + case __format::__arg_t::__boolean: + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__boolean_); + case __format::__arg_t::__char_type: + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__char_type_); + case __format::__arg_t::__int: + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__int_); + case __format::__arg_t::__long_long: + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__long_long_); + case __format::__arg_t::__i128: +# ifndef _LIBCPP_HAS_NO_INT128 + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__i128_); +# else + __libcpp_unreachable(); +# endif + case __format::__arg_t::__unsigned: + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_); + case __format::__arg_t::__unsigned_long_long: + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_long_long_); + case __format::__arg_t::__u128: +# ifndef _LIBCPP_HAS_NO_INT128 + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__u128_); +# else + __libcpp_unreachable(); +# endif + case __format::__arg_t::__float: + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__float_); + case __format::__arg_t::__double: + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__double_); + case __format::__arg_t::__long_double: + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__long_double_); + case __format::__arg_t::__const_char_type_ptr: + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__const_char_type_ptr_); + case __format::__arg_t::__string_view: + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__string_view_); + case __format::__arg_t::__ptr: + return std::invoke(std::forward<_Visitor>(__vis), __arg.__value_.__ptr_); + case __format::__arg_t::__handle: + return std::invoke( + std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__arg.__value_.__handle_}); + } + + __libcpp_unreachable(); +} + +# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) + +template +_LIBCPP_HIDE_FROM_ABI _Rp __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) { + switch (__arg.__type_) { + case __format::__arg_t::__none: + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__monostate_); + case __format::__arg_t::__boolean: + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__boolean_); + case __format::__arg_t::__char_type: + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__char_type_); + case __format::__arg_t::__int: + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__int_); + case __format::__arg_t::__long_long: + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__long_long_); + case __format::__arg_t::__i128: +# ifndef _LIBCPP_HAS_NO_INT128 + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__i128_); +# else + __libcpp_unreachable(); +# endif + case __format::__arg_t::__unsigned: + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_); + case __format::__arg_t::__unsigned_long_long: + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_long_long_); + case __format::__arg_t::__u128: +# ifndef _LIBCPP_HAS_NO_INT128 + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__u128_); +# else + __libcpp_unreachable(); +# endif + case __format::__arg_t::__float: + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__float_); + case __format::__arg_t::__double: + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__double_); + case __format::__arg_t::__long_double: + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__long_double_); + case __format::__arg_t::__const_char_type_ptr: + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__const_char_type_ptr_); + case __format::__arg_t::__string_view: + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__string_view_); + case __format::__arg_t::__ptr: + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__ptr_); + case __format::__arg_t::__handle: + return std::invoke_r<_Rp>( + std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__arg.__value_.__handle_}); + } + + __libcpp_unreachable(); +} + +# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) + +/// Contains the values used in basic_format_arg. +/// +/// This is a separate type so it's possible to store the values and types in +/// separate arrays. +template +class __basic_format_arg_value { + using _CharT = typename _Context::char_type; + +public: + /// Contains the implementation for basic_format_arg::handle. + struct __handle { + template + _LIBCPP_HIDE_FROM_ABI explicit __handle(_Tp& __v) noexcept + : __ptr_(std::addressof(__v)), + __format_([](basic_format_parse_context<_CharT>& __parse_ctx, _Context& __ctx, const void* __ptr) { + using _Dp = remove_const_t<_Tp>; + using _Qp = conditional_t<__formattable_with, const _Dp, _Dp>; + static_assert(__formattable_with<_Qp, _Context>, "Mandated by [format.arg]/10"); + + typename _Context::template formatter_type<_Dp> __f; + __parse_ctx.advance_to(__f.parse(__parse_ctx)); + __ctx.advance_to(__f.format(*const_cast<_Qp*>(static_cast(__ptr)), __ctx)); + }) {} + + const void* __ptr_; + void (*__format_)(basic_format_parse_context<_CharT>&, _Context&, const void*); + }; + + union { + monostate __monostate_; + bool __boolean_; + _CharT __char_type_; + int __int_; + unsigned __unsigned_; + long long __long_long_; + unsigned long long __unsigned_long_long_; +# ifndef _LIBCPP_HAS_NO_INT128 + __int128_t __i128_; + __uint128_t __u128_; +# endif + float __float_; + double __double_; + long double __long_double_; + const _CharT* __const_char_type_ptr_; + basic_string_view<_CharT> __string_view_; + const void* __ptr_; + __handle __handle_; + }; + + // These constructors contain the exact storage type used. If adjustments are + // required, these will be done in __create_format_arg. + + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value() noexcept : __monostate_() {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(bool __value) noexcept : __boolean_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(_CharT __value) noexcept : __char_type_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(int __value) noexcept : __int_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(unsigned __value) noexcept : __unsigned_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(long long __value) noexcept : __long_long_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(unsigned long long __value) noexcept + : __unsigned_long_long_(__value) {} +# ifndef _LIBCPP_HAS_NO_INT128 + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__int128_t __value) noexcept : __i128_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__uint128_t __value) noexcept : __u128_(__value) {} +# endif + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(float __value) noexcept : __float_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(double __value) noexcept : __double_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(long double __value) noexcept : __long_double_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(const _CharT* __value) noexcept : __const_char_type_ptr_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(basic_string_view<_CharT> __value) noexcept + : __string_view_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(const void* __value) noexcept : __ptr_(__value) {} + _LIBCPP_HIDE_FROM_ABI __basic_format_arg_value(__handle&& __value) noexcept : __handle_(std::move(__value)) {} +}; + +template +class _LIBCPP_TEMPLATE_VIS basic_format_arg { +public: + class _LIBCPP_TEMPLATE_VIS handle; + + _LIBCPP_HIDE_FROM_ABI basic_format_arg() noexcept : __type_{__format::__arg_t::__none} {} + + _LIBCPP_HIDE_FROM_ABI explicit operator bool() const noexcept { return __type_ != __format::__arg_t::__none; } + +# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) + + // This function is user facing, so it must wrap the non-standard types of + // the "variant" in a handle to stay conforming. See __arg_t for more details. + template + _LIBCPP_HIDE_FROM_ABI decltype(auto) visit(this basic_format_arg __arg, _Visitor&& __vis) { + switch (__arg.__type_) { +# ifndef _LIBCPP_HAS_NO_INT128 + case __format::__arg_t::__i128: { + typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__i128_}; + return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h}); + } + + case __format::__arg_t::__u128: { + typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_}; + return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h}); + } +# endif + default: + return std::__visit_format_arg(std::forward<_Visitor>(__vis), __arg); + } + } + + // This function is user facing, so it must wrap the non-standard types of + // the "variant" in a handle to stay conforming. See __arg_t for more details. + template + _LIBCPP_HIDE_FROM_ABI _Rp visit(this basic_format_arg __arg, _Visitor&& __vis) { + switch (__arg.__type_) { +# ifndef _LIBCPP_HAS_NO_INT128 + case __format::__arg_t::__i128: { + typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__i128_}; + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h}); + } + + case __format::__arg_t::__u128: { + typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_}; + return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h}); + } +# endif + default: + return std::__visit_format_arg<_Rp>(std::forward<_Visitor>(__vis), __arg); + } + } + +# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) + +private: + using char_type = typename _Context::char_type; + + // TODO FMT Implement constrain [format.arg]/4 + // Constraints: The template specialization + // typename Context::template formatter_type + // meets the Formatter requirements ([formatter.requirements]). The extent + // to which an implementation determines that the specialization meets the + // Formatter requirements is unspecified, except that as a minimum the + // expression + // typename Context::template formatter_type() + // .format(declval(), declval()) + // shall be well-formed when treated as an unevaluated operand. + +public: + __basic_format_arg_value<_Context> __value_; + __format::__arg_t __type_; + + _LIBCPP_HIDE_FROM_ABI explicit basic_format_arg(__format::__arg_t __type, + __basic_format_arg_value<_Context> __value) noexcept + : __value_(__value), __type_(__type) {} +}; + +template +class _LIBCPP_TEMPLATE_VIS basic_format_arg<_Context>::handle { +public: + _LIBCPP_HIDE_FROM_ABI void format(basic_format_parse_context& __parse_ctx, _Context& __ctx) const { + __handle_.__format_(__parse_ctx, __ctx, __handle_.__ptr_); + } + + _LIBCPP_HIDE_FROM_ABI explicit handle(typename __basic_format_arg_value<_Context>::__handle& __handle) noexcept + : __handle_(__handle) {} + +private: + typename __basic_format_arg_value<_Context>::__handle& __handle_; +}; + +// This function is user facing, so it must wrap the non-standard types of +// the "variant" in a handle to stay conforming. See __arg_t for more details. +template +# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) +_LIBCPP_DEPRECATED_IN_CXX26 +# endif + _LIBCPP_HIDE_FROM_ABI decltype(auto) + visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) { + switch (__arg.__type_) { +# ifndef _LIBCPP_HAS_NO_INT128 + case __format::__arg_t::__i128: { + typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__i128_}; + return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h}); + } + + case __format::__arg_t::__u128: { + typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_}; + return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h}); + } +# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) + default: + return std::__visit_format_arg(std::forward<_Visitor>(__vis), __arg); + } +} + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_FORMAT_ARG_H diff --git a/libcxx/include/__cxx03/__format/format_arg_store.h b/libcxx/include/__cxx03/__format/format_arg_store.h new file mode 100644 index 0000000000000000000000000000000000000000..23a599e99575999dbed5a6a0f548d047f9f415f5 --- /dev/null +++ b/libcxx/include/__cxx03/__format/format_arg_store.h @@ -0,0 +1,266 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMAT_ARG_STORE_H +#define _LIBCPP___FORMAT_FORMAT_ARG_STORE_H + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#include <__concepts/arithmetic.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__format/concepts.h> +#include <__format/format_arg.h> +#include <__type_traits/conditional.h> +#include <__type_traits/extent.h> +#include <__type_traits/remove_const.h> +#include +#include + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __format { + +/// \returns The @c __arg_t based on the type of the formatting argument. +/// +/// \pre \c __formattable<_Tp, typename _Context::char_type> +template +consteval __arg_t __determine_arg_t(); + +// Boolean +template _Tp> +consteval __arg_t __determine_arg_t() { + return __arg_t::__boolean; +} + +// Char +template _Tp> +consteval __arg_t __determine_arg_t() { + return __arg_t::__char_type; +} +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template + requires(same_as && same_as<_CharT, char>) +consteval __arg_t __determine_arg_t() { + return __arg_t::__char_type; +} +# endif + +// Signed integers +template +consteval __arg_t __determine_arg_t() { + if constexpr (sizeof(_Tp) <= sizeof(int)) + return __arg_t::__int; + else if constexpr (sizeof(_Tp) <= sizeof(long long)) + return __arg_t::__long_long; +# ifndef _LIBCPP_HAS_NO_INT128 + else if constexpr (sizeof(_Tp) == sizeof(__int128_t)) + return __arg_t::__i128; +# endif + else + static_assert(sizeof(_Tp) == 0, "an unsupported signed integer was used"); +} + +// Unsigned integers +template +consteval __arg_t __determine_arg_t() { + if constexpr (sizeof(_Tp) <= sizeof(unsigned)) + return __arg_t::__unsigned; + else if constexpr (sizeof(_Tp) <= sizeof(unsigned long long)) + return __arg_t::__unsigned_long_long; +# ifndef _LIBCPP_HAS_NO_INT128 + else if constexpr (sizeof(_Tp) == sizeof(__uint128_t)) + return __arg_t::__u128; +# endif + else + static_assert(sizeof(_Tp) == 0, "an unsupported unsigned integer was used"); +} + +// Floating-point +template _Tp> +consteval __arg_t __determine_arg_t() { + return __arg_t::__float; +} +template _Tp> +consteval __arg_t __determine_arg_t() { + return __arg_t::__double; +} +template _Tp> +consteval __arg_t __determine_arg_t() { + return __arg_t::__long_double; +} + +// Char pointer +template + requires(same_as || same_as) +consteval __arg_t __determine_arg_t() { + return __arg_t::__const_char_type_ptr; +} + +// Char array +template + requires(is_array_v<_Tp> && same_as<_Tp, typename _Context::char_type[extent_v<_Tp>]>) +consteval __arg_t __determine_arg_t() { + return __arg_t::__string_view; +} + +// String view +template + requires(same_as && + same_as<_Tp, basic_string_view>) +consteval __arg_t __determine_arg_t() { + return __arg_t::__string_view; +} + +// String +template + requires( + same_as && + same_as<_Tp, basic_string>) +consteval __arg_t __determine_arg_t() { + return __arg_t::__string_view; +} + +// Pointers +template + requires(same_as<_Ptr, void*> || same_as<_Ptr, const void*> || same_as<_Ptr, nullptr_t>) +consteval __arg_t __determine_arg_t() { + return __arg_t::__ptr; +} + +// Handle +// +// Note this version can't be constrained avoiding ambiguous overloads. +// That means it can be instantiated by disabled formatters. To solve this, a +// constrained version for not formattable formatters is added. +template +consteval __arg_t __determine_arg_t() { + return __arg_t::__handle; +} + +// The overload for not formattable types allows triggering the static +// assertion below. +template + requires(!__formattable_with<_Tp, _Context>) +consteval __arg_t __determine_arg_t() { + return __arg_t::__none; +} + +// Pseudo constuctor for basic_format_arg +// +// Modeled after template explicit basic_format_arg(T& v) noexcept; +// [format.arg]/4-6 +template +_LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp& __value) noexcept { + using _Dp = remove_const_t<_Tp>; + constexpr __arg_t __arg = __determine_arg_t<_Context, _Dp>(); + static_assert(__arg != __arg_t::__none, "the supplied type is not formattable"); + static_assert(__formattable_with<_Tp, _Context>); + + // Not all types can be used to directly initialize the + // __basic_format_arg_value. First handle all types needing adjustment, the + // final else requires no adjustment. + if constexpr (__arg == __arg_t::__char_type) + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS + if constexpr (same_as && same_as<_Dp, char>) + return basic_format_arg<_Context>{__arg, static_cast(static_cast(__value))}; + else +# endif + return basic_format_arg<_Context>{__arg, __value}; + else if constexpr (__arg == __arg_t::__int) + return basic_format_arg<_Context>{__arg, static_cast(__value)}; + else if constexpr (__arg == __arg_t::__long_long) + return basic_format_arg<_Context>{__arg, static_cast(__value)}; + else if constexpr (__arg == __arg_t::__unsigned) + return basic_format_arg<_Context>{__arg, static_cast(__value)}; + else if constexpr (__arg == __arg_t::__unsigned_long_long) + return basic_format_arg<_Context>{__arg, static_cast(__value)}; + else if constexpr (__arg == __arg_t::__string_view) + // Using std::size on a character array will add the NUL-terminator to the size. + if constexpr (is_array_v<_Dp>) + return basic_format_arg<_Context>{ + __arg, basic_string_view{__value, extent_v<_Dp> - 1}}; + else + // When the _Traits or _Allocator are different an implicit conversion will + // fail. + return basic_format_arg<_Context>{ + __arg, basic_string_view{__value.data(), __value.size()}}; + else if constexpr (__arg == __arg_t::__ptr) + return basic_format_arg<_Context>{__arg, static_cast(__value)}; + else if constexpr (__arg == __arg_t::__handle) + return basic_format_arg<_Context>{__arg, typename __basic_format_arg_value<_Context>::__handle{__value}}; + else + return basic_format_arg<_Context>{__arg, __value}; +} + +template +_LIBCPP_HIDE_FROM_ABI void +__create_packed_storage(uint64_t& __types, __basic_format_arg_value<_Context>* __values, _Args&... __args) noexcept { + int __shift = 0; + ( + [&] { + basic_format_arg<_Context> __arg = __format::__create_format_arg<_Context>(__args); + if (__shift != 0) + __types |= static_cast(__arg.__type_) << __shift; + else + // Assigns the initial value. + __types = static_cast(__arg.__type_); + __shift += __packed_arg_t_bits; + *__values++ = __arg.__value_; + }(), + ...); +} + +template +_LIBCPP_HIDE_FROM_ABI void __store_basic_format_arg(basic_format_arg<_Context>* __data, _Args&... __args) noexcept { + ([&] { *__data++ = __format::__create_format_arg<_Context>(__args); }(), ...); +} + +template +struct __packed_format_arg_store { + __basic_format_arg_value<_Context> __values_[_Np]; + uint64_t __types_ = 0; +}; + +template +struct __unpacked_format_arg_store { + basic_format_arg<_Context> __args_[_Np]; +}; + +} // namespace __format + +template +struct _LIBCPP_TEMPLATE_VIS __format_arg_store { + _LIBCPP_HIDE_FROM_ABI __format_arg_store(_Args&... __args) noexcept { + if constexpr (sizeof...(_Args) != 0) { + if constexpr (__format::__use_packed_format_arg_store(sizeof...(_Args))) + __format::__create_packed_storage(__storage.__types_, __storage.__values_, __args...); + else + __format::__store_basic_format_arg<_Context>(__storage.__args_, __args...); + } + } + + using _Storage = + conditional_t<__format::__use_packed_format_arg_store(sizeof...(_Args)), + __format::__packed_format_arg_store<_Context, sizeof...(_Args)>, + __format::__unpacked_format_arg_store<_Context, sizeof...(_Args)>>; + + _Storage __storage; +}; + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMAT_ARG_STORE_H diff --git a/libcxx/include/__cxx03/__format/format_args.h b/libcxx/include/__cxx03/__format/format_args.h new file mode 100644 index 0000000000000000000000000000000000000000..07923570f38930fa80ef8ab695656deec9669a17 --- /dev/null +++ b/libcxx/include/__cxx03/__format/format_args.h @@ -0,0 +1,78 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMAT_ARGS_H +#define _LIBCPP___FORMAT_FORMAT_ARGS_H + +#include <__config> +#include <__format/format_arg.h> +#include <__format/format_arg_store.h> +#include <__fwd/format.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +class _LIBCPP_TEMPLATE_VIS basic_format_args { +public: + template + _LIBCPP_HIDE_FROM_ABI basic_format_args(const __format_arg_store<_Context, _Args...>& __store) noexcept + : __size_(sizeof...(_Args)) { + if constexpr (sizeof...(_Args) != 0) { + if constexpr (__format::__use_packed_format_arg_store(sizeof...(_Args))) { + __values_ = __store.__storage.__values_; + __types_ = __store.__storage.__types_; + } else + __args_ = __store.__storage.__args_; + } + } + + _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> get(size_t __id) const noexcept { + if (__id >= __size_) + return basic_format_arg<_Context>{}; + + if (__format::__use_packed_format_arg_store(__size_)) + return basic_format_arg<_Context>{__format::__get_packed_type(__types_, __id), __values_[__id]}; + + return __args_[__id]; + } + + _LIBCPP_HIDE_FROM_ABI size_t __size() const noexcept { return __size_; } + +private: + size_t __size_{0}; + // [format.args]/5 + // [Note 1: Implementations are encouraged to optimize the representation of + // basic_format_args for small number of formatting arguments by storing + // indices of type alternatives separately from values and packing the + // former. - end note] + union { + struct { + const __basic_format_arg_value<_Context>* __values_; + uint64_t __types_; + }; + const basic_format_arg<_Context>* __args_; + }; +}; + +template +basic_format_args(__format_arg_store<_Context, _Args...>) -> basic_format_args<_Context>; + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMAT_ARGS_H diff --git a/libcxx/include/__cxx03/__format/format_context.h b/libcxx/include/__cxx03/__format/format_context.h new file mode 100644 index 0000000000000000000000000000000000000000..20c07559eae448d7a21ca4e87cb14615076d0aac --- /dev/null +++ b/libcxx/include/__cxx03/__format/format_context.h @@ -0,0 +1,220 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMAT_CONTEXT_H +#define _LIBCPP___FORMAT_FORMAT_CONTEXT_H + +#include <__concepts/same_as.h> +#include <__config> +#include <__format/buffer.h> +#include <__format/format_arg.h> +#include <__format/format_arg_store.h> +#include <__format/format_args.h> +#include <__format/format_error.h> +#include <__fwd/format.h> +#include <__iterator/back_insert_iterator.h> +#include <__iterator/concepts.h> +#include <__memory/addressof.h> +#include <__utility/move.h> +#include <__variant/monostate.h> +#include + +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include <__locale> +# include +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template + requires output_iterator<_OutIt, const _CharT&> +class _LIBCPP_TEMPLATE_VIS basic_format_context; + +# ifndef _LIBCPP_HAS_NO_LOCALIZATION +/** + * Helper to create a basic_format_context. + * + * This is needed since the constructor is private. + */ +template +_LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT> +__format_context_create(_OutIt __out_it, + basic_format_args> __args, + optional&& __loc = nullopt) { + return std::basic_format_context(std::move(__out_it), __args, std::move(__loc)); +} +# else +template +_LIBCPP_HIDE_FROM_ABI basic_format_context<_OutIt, _CharT> +__format_context_create(_OutIt __out_it, basic_format_args> __args) { + return std::basic_format_context(std::move(__out_it), __args); +} +# endif + +using format_context = basic_format_context>, char>; +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +using wformat_context = basic_format_context< back_insert_iterator<__format::__output_buffer>, wchar_t>; +# endif + +template + requires output_iterator<_OutIt, const _CharT&> +class + // clang-format off + _LIBCPP_TEMPLATE_VIS + _LIBCPP_PREFERRED_NAME(format_context) + _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wformat_context)) + // clang-format on + basic_format_context { +public: + using iterator = _OutIt; + using char_type = _CharT; + template + using formatter_type = formatter<_Tp, _CharT>; + + _LIBCPP_HIDE_FROM_ABI basic_format_arg arg(size_t __id) const noexcept { + return __args_.get(__id); + } +# ifndef _LIBCPP_HAS_NO_LOCALIZATION + _LIBCPP_HIDE_FROM_ABI std::locale locale() { + if (!__loc_) + __loc_ = std::locale{}; + return *__loc_; + } +# endif + _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); } + _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); } + +private: + iterator __out_it_; + basic_format_args __args_; +# ifndef _LIBCPP_HAS_NO_LOCALIZATION + + // The Standard doesn't specify how the locale is stored. + // [format.context]/6 + // std::locale locale(); + // Returns: The locale passed to the formatting function if the latter + // takes one, and std::locale() otherwise. + // This is done by storing the locale of the constructor in this optional. If + // locale() is called and the optional has no value the value will be created. + // This allows the implementation to lazily create the locale. + // TODO FMT Validate whether lazy creation is the best solution. + optional __loc_; + + template + friend _LIBCPP_HIDE_FROM_ABI basic_format_context<_OtherOutIt, _OtherCharT> __format_context_create( + _OtherOutIt, basic_format_args>, optional&&); + + // Note: the Standard doesn't specify the required constructors. + _LIBCPP_HIDE_FROM_ABI explicit basic_format_context( + _OutIt __out_it, basic_format_args __args, optional&& __loc) + : __out_it_(std::move(__out_it)), __args_(__args), __loc_(std::move(__loc)) {} +# else + template + friend _LIBCPP_HIDE_FROM_ABI basic_format_context<_OtherOutIt, _OtherCharT> + __format_context_create(_OtherOutIt, basic_format_args>); + + _LIBCPP_HIDE_FROM_ABI explicit basic_format_context(_OutIt __out_it, basic_format_args __args) + : __out_it_(std::move(__out_it)), __args_(__args) {} +# endif + + basic_format_context(const basic_format_context&) = delete; + basic_format_context& operator=(const basic_format_context&) = delete; +}; + +// A specialization for __retarget_buffer +// +// See __retarget_buffer for the motivation for this specialization. +// +// This context holds a reference to the instance of the basic_format_context +// that is retargeted. It converts a formatting argument when it is requested +// during formatting. It is expected that the usage of the arguments is rare so +// the lookups are not expected to be used often. An alternative would be to +// convert all elements during construction. +// +// The elements of the retargets context are only used when an underlying +// formatter uses a locale specific formatting or an formatting argument is +// part for the format spec. For example +// format("{:256:{}}", input, 8); +// Here the width of an element in input is determined dynamically. +// Note when the top-level element has no width the retargeting is not needed. +template +class _LIBCPP_TEMPLATE_VIS basic_format_context::__iterator, _CharT> { +public: + using iterator = typename __format::__retarget_buffer<_CharT>::__iterator; + using char_type = _CharT; + template + using formatter_type = formatter<_Tp, _CharT>; + + template + _LIBCPP_HIDE_FROM_ABI explicit basic_format_context(iterator __out_it, _Context& __ctx) + : __out_it_(std::move(__out_it)), +# ifndef _LIBCPP_HAS_NO_LOCALIZATION + __loc_([](void* __c) { return static_cast<_Context*>(__c)->locale(); }), +# endif + __ctx_(std::addressof(__ctx)), + __arg_([](void* __c, size_t __id) { + auto __visitor = [&](auto __arg) -> basic_format_arg { + if constexpr (same_as) + return {}; + else if constexpr (same_as::handle>) + // At the moment it's not possible for formatting to use a re-targeted handle. + // TODO FMT add this when support is needed. + std::__throw_format_error("Re-targeting handle not supported"); + else + return basic_format_arg{ + __format::__determine_arg_t(), + __basic_format_arg_value(__arg)}; + }; +# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) + return static_cast<_Context*>(__c)->arg(__id).visit(std::move(__visitor)); +# else + _LIBCPP_SUPPRESS_DEPRECATED_PUSH + return std::visit_format_arg(std::move(__visitor), static_cast<_Context*>(__c)->arg(__id)); + _LIBCPP_SUPPRESS_DEPRECATED_POP +# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER) + }) { + } + + _LIBCPP_HIDE_FROM_ABI basic_format_arg arg(size_t __id) const noexcept { + return __arg_(__ctx_, __id); + } +# ifndef _LIBCPP_HAS_NO_LOCALIZATION + _LIBCPP_HIDE_FROM_ABI std::locale locale() { return __loc_(__ctx_); } +# endif + _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); } + _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); } + +private: + iterator __out_it_; + +# ifndef _LIBCPP_HAS_NO_LOCALIZATION + std::locale (*__loc_)(void* __ctx); +# endif + + void* __ctx_; + basic_format_arg (*__arg_)(void* __ctx, size_t __id); +}; + +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_context); +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_FORMAT_CONTEXT_H diff --git a/libcxx/include/__cxx03/__format/format_error.h b/libcxx/include/__cxx03/__format/format_error.h new file mode 100644 index 0000000000000000000000000000000000000000..ed40e395d6af7255cba96d81bc951ba1c0bc9710 --- /dev/null +++ b/libcxx/include/__cxx03/__format/format_error.h @@ -0,0 +1,50 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMAT_ERROR_H +#define _LIBCPP___FORMAT_FORMAT_ERROR_H + +#include <__config> +#include <__verbose_abort> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wweak-vtables") +class _LIBCPP_EXPORTED_FROM_ABI format_error : public runtime_error { +public: + _LIBCPP_HIDE_FROM_ABI explicit format_error(const string& __s) : runtime_error(__s) {} + _LIBCPP_HIDE_FROM_ABI explicit format_error(const char* __s) : runtime_error(__s) {} + _LIBCPP_HIDE_FROM_ABI format_error(const format_error&) = default; + _LIBCPP_HIDE_FROM_ABI format_error& operator=(const format_error&) = default; + _LIBCPP_HIDE_FROM_ABI_VIRTUAL + ~format_error() noexcept override = default; +}; +_LIBCPP_DIAGNOSTIC_POP + +_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void __throw_format_error(const char* __s) { +# ifndef _LIBCPP_HAS_NO_EXCEPTIONS + throw format_error(__s); +# else + _LIBCPP_VERBOSE_ABORT("format_error was thrown in -fno-exceptions mode with message \"%s\"", __s); +# endif +} + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMAT_ERROR_H diff --git a/libcxx/include/__cxx03/__format/format_functions.h b/libcxx/include/__cxx03/__format/format_functions.h new file mode 100644 index 0000000000000000000000000000000000000000..d14b49aff149573e85cdff3ac2b7cbd5bcd5341d --- /dev/null +++ b/libcxx/include/__cxx03/__format/format_functions.h @@ -0,0 +1,680 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMAT_FUNCTIONS +#define _LIBCPP___FORMAT_FORMAT_FUNCTIONS + +#include <__algorithm/clamp.h> +#include <__concepts/convertible_to.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__format/buffer.h> +#include <__format/format_arg.h> +#include <__format/format_arg_store.h> +#include <__format/format_args.h> +#include <__format/format_context.h> +#include <__format/format_error.h> +#include <__format/format_parse_context.h> +#include <__format/format_string.h> +#include <__format/format_to_n_result.h> +#include <__format/formatter.h> +#include <__format/formatter_bool.h> +#include <__format/formatter_char.h> +#include <__format/formatter_floating_point.h> +#include <__format/formatter_integer.h> +#include <__format/formatter_pointer.h> +#include <__format/formatter_string.h> +#include <__format/parser_std_format_spec.h> +#include <__iterator/back_insert_iterator.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iterator_traits.h> // iter_value_t +#include <__variant/monostate.h> +#include +#include +#include + +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include <__locale> +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// TODO FMT Evaluate which templates should be external templates. This +// improves the efficiency of the header. However since the header is still +// under heavy development and not all classes are stable it makes no sense +// to do this optimization now. + +using format_args = basic_format_args; +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +using wformat_args = basic_format_args; +# endif + +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...> make_format_args(_Args&... __args) { + return std::__format_arg_store<_Context, _Args...>(__args...); +} + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI __format_arg_store make_wformat_args(_Args&... __args) { + return std::__format_arg_store(__args...); +} +# endif + +namespace __format { + +/// Helper class parse and handle argument. +/// +/// When parsing a handle which is not enabled the code is ill-formed. +/// This helper uses the parser of the appropriate formatter for the stored type. +template +class _LIBCPP_TEMPLATE_VIS __compile_time_handle { +public: + template + _LIBCPP_HIDE_FROM_ABI constexpr void __parse(_ParseContext& __ctx) const { + __parse_(__ctx); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr void __enable() { + __parse_ = [](basic_format_parse_context<_CharT>& __ctx) { + formatter<_Tp, _CharT> __f; + __ctx.advance_to(__f.parse(__ctx)); + }; + } + + // Before calling __parse the proper handler needs to be set with __enable. + // The default handler isn't a core constant expression. + _LIBCPP_HIDE_FROM_ABI constexpr __compile_time_handle() + : __parse_([](basic_format_parse_context<_CharT>&) { std::__throw_format_error("Not a handle"); }) {} + +private: + void (*__parse_)(basic_format_parse_context<_CharT>&); +}; + +// Dummy format_context only providing the parts used during constant +// validation of the basic_format_string. +template +struct _LIBCPP_TEMPLATE_VIS __compile_time_basic_format_context { +public: + using char_type = _CharT; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __compile_time_basic_format_context( + const __arg_t* __args, const __compile_time_handle<_CharT>* __handles, size_t __size) + : __args_(__args), __handles_(__handles), __size_(__size) {} + + // During the compile-time validation nothing needs to be written. + // Therefore all operations of this iterator are a NOP. + struct iterator { + _LIBCPP_HIDE_FROM_ABI constexpr iterator& operator=(_CharT) { return *this; } + _LIBCPP_HIDE_FROM_ABI constexpr iterator& operator*() { return *this; } + _LIBCPP_HIDE_FROM_ABI constexpr iterator operator++(int) { return *this; } + }; + + _LIBCPP_HIDE_FROM_ABI constexpr __arg_t arg(size_t __id) const { + if (__id >= __size_) + std::__throw_format_error("The argument index value is too large for the number of arguments supplied"); + return __args_[__id]; + } + + _LIBCPP_HIDE_FROM_ABI constexpr const __compile_time_handle<_CharT>& __handle(size_t __id) const { + if (__id >= __size_) + std::__throw_format_error("The argument index value is too large for the number of arguments supplied"); + return __handles_[__id]; + } + + _LIBCPP_HIDE_FROM_ABI constexpr iterator out() { return {}; } + _LIBCPP_HIDE_FROM_ABI constexpr void advance_to(iterator) {} + +private: + const __arg_t* __args_; + const __compile_time_handle<_CharT>* __handles_; + size_t __size_; +}; + +// [format.string.std]/8 +// If { arg-idopt } is used in a width or precision, the value of the +// corresponding formatting argument is used in its place. If the +// corresponding formatting argument is not of standard signed or unsigned +// integer type, or its value is negative for precision or non-positive for +// width, an exception of type format_error is thrown. +// +// _HasPrecision does the formatter have a precision? +template +_LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_validate_argument( + basic_format_parse_context<_CharT>& __parse_ctx, __compile_time_basic_format_context<_CharT>& __ctx) { + auto __validate_type = [](__arg_t __type) { + // LWG3720 originally allowed "signed or unsigned integer types", however + // the final version explicitly changed it to "*standard* signed or unsigned + // integer types". It's trivial to use 128-bit integrals in libc++'s + // implementation, but other implementations may not implement it. + // (Using a width or precision, that does not fit in 64-bits, sounds very + // unlikely in real world code.) + switch (__type) { + case __arg_t::__int: + case __arg_t::__long_long: + case __arg_t::__unsigned: + case __arg_t::__unsigned_long_long: + return; + + default: + std::__throw_format_error("Replacement argument isn't a standard signed or unsigned integer type"); + } + }; + + formatter<_Tp, _CharT> __formatter; + __parse_ctx.advance_to(__formatter.parse(__parse_ctx)); + if (__formatter.__parser_.__width_as_arg_) + __validate_type(__ctx.arg(__formatter.__parser_.__width_)); + + if constexpr (_HasPrecision) + if (__formatter.__parser_.__precision_as_arg_) + __validate_type(__ctx.arg(__formatter.__parser_.__precision_)); +} + +// This function is not user facing, so it can directly use the non-standard types of the "variant". +template +_LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_visit_format_arg( + basic_format_parse_context<_CharT>& __parse_ctx, + __compile_time_basic_format_context<_CharT>& __ctx, + __arg_t __type) { + switch (__type) { + case __arg_t::__none: + std::__throw_format_error("Invalid argument"); + case __arg_t::__boolean: + return __format::__compile_time_validate_argument<_CharT, bool>(__parse_ctx, __ctx); + case __arg_t::__char_type: + return __format::__compile_time_validate_argument<_CharT, _CharT>(__parse_ctx, __ctx); + case __arg_t::__int: + return __format::__compile_time_validate_argument<_CharT, int>(__parse_ctx, __ctx); + case __arg_t::__long_long: + return __format::__compile_time_validate_argument<_CharT, long long>(__parse_ctx, __ctx); + case __arg_t::__i128: +# ifndef _LIBCPP_HAS_NO_INT128 + return __format::__compile_time_validate_argument<_CharT, __int128_t>(__parse_ctx, __ctx); +# else + std::__throw_format_error("Invalid argument"); +# endif + return; + case __arg_t::__unsigned: + return __format::__compile_time_validate_argument<_CharT, unsigned>(__parse_ctx, __ctx); + case __arg_t::__unsigned_long_long: + return __format::__compile_time_validate_argument<_CharT, unsigned long long>(__parse_ctx, __ctx); + case __arg_t::__u128: +# ifndef _LIBCPP_HAS_NO_INT128 + return __format::__compile_time_validate_argument<_CharT, __uint128_t>(__parse_ctx, __ctx); +# else + std::__throw_format_error("Invalid argument"); +# endif + return; + case __arg_t::__float: + return __format::__compile_time_validate_argument<_CharT, float, true>(__parse_ctx, __ctx); + case __arg_t::__double: + return __format::__compile_time_validate_argument<_CharT, double, true>(__parse_ctx, __ctx); + case __arg_t::__long_double: + return __format::__compile_time_validate_argument<_CharT, long double, true>(__parse_ctx, __ctx); + case __arg_t::__const_char_type_ptr: + return __format::__compile_time_validate_argument<_CharT, const _CharT*, true>(__parse_ctx, __ctx); + case __arg_t::__string_view: + return __format::__compile_time_validate_argument<_CharT, basic_string_view<_CharT>, true>(__parse_ctx, __ctx); + case __arg_t::__ptr: + return __format::__compile_time_validate_argument<_CharT, const void*>(__parse_ctx, __ctx); + case __arg_t::__handle: + std::__throw_format_error("Handle should use __compile_time_validate_handle_argument"); + } + std::__throw_format_error("Invalid argument"); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr _Iterator +__handle_replacement_field(_Iterator __begin, _Iterator __end, _ParseCtx& __parse_ctx, _Ctx& __ctx) { + using _CharT = iter_value_t<_Iterator>; + __format::__parse_number_result __r = __format::__parse_arg_id(__begin, __end, __parse_ctx); + + if (__r.__last == __end) + std::__throw_format_error("The argument index should end with a ':' or a '}'"); + + bool __parse = *__r.__last == _CharT(':'); + switch (*__r.__last) { + case _CharT(':'): + // The arg-id has a format-specifier, advance the input to the format-spec. + __parse_ctx.advance_to(__r.__last + 1); + break; + case _CharT('}'): + // The arg-id has no format-specifier. + __parse_ctx.advance_to(__r.__last); + break; + default: + std::__throw_format_error("The argument index should end with a ':' or a '}'"); + } + + if constexpr (same_as<_Ctx, __compile_time_basic_format_context<_CharT>>) { + __arg_t __type = __ctx.arg(__r.__value); + if (__type == __arg_t::__none) + std::__throw_format_error("The argument index value is too large for the number of arguments supplied"); + else if (__type == __arg_t::__handle) + __ctx.__handle(__r.__value).__parse(__parse_ctx); + else if (__parse) + __format::__compile_time_visit_format_arg(__parse_ctx, __ctx, __type); + } else + std::__visit_format_arg( + [&](auto __arg) { + if constexpr (same_as) + std::__throw_format_error("The argument index value is too large for the number of arguments supplied"); + else if constexpr (same_as::handle>) + __arg.format(__parse_ctx, __ctx); + else { + formatter __formatter; + if (__parse) + __parse_ctx.advance_to(__formatter.parse(__parse_ctx)); + __ctx.advance_to(__formatter.format(__arg, __ctx)); + } + }, + __ctx.arg(__r.__value)); + + __begin = __parse_ctx.begin(); + if (__begin == __end || *__begin != _CharT('}')) + std::__throw_format_error("The replacement field misses a terminating '}'"); + + return ++__begin; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr typename _Ctx::iterator __vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) { + using _CharT = typename _ParseCtx::char_type; + static_assert(same_as); + + auto __begin = __parse_ctx.begin(); + auto __end = __parse_ctx.end(); + typename _Ctx::iterator __out_it = __ctx.out(); + while (__begin != __end) { + switch (*__begin) { + case _CharT('{'): + ++__begin; + if (__begin == __end) + std::__throw_format_error("The format string terminates at a '{'"); + + if (*__begin != _CharT('{')) [[likely]] { + __ctx.advance_to(std::move(__out_it)); + __begin = __format::__handle_replacement_field(__begin, __end, __parse_ctx, __ctx); + __out_it = __ctx.out(); + + // The output is written and __begin points to the next character. So + // start the next iteration. + continue; + } + // The string is an escape character. + break; + + case _CharT('}'): + ++__begin; + if (__begin == __end || *__begin != _CharT('}')) + std::__throw_format_error("The format string contains an invalid escape sequence"); + + break; + } + + // Copy the character to the output verbatim. + *__out_it++ = *__begin++; + } + return __out_it; +} + +} // namespace __format + +# if _LIBCPP_STD_VER >= 26 +template +struct _LIBCPP_TEMPLATE_VIS __runtime_format_string { +private: + basic_string_view<_CharT> __str_; + + template + friend struct _LIBCPP_TEMPLATE_VIS basic_format_string; + +public: + _LIBCPP_HIDE_FROM_ABI __runtime_format_string(basic_string_view<_CharT> __s) noexcept : __str_(__s) {} + + __runtime_format_string(const __runtime_format_string&) = delete; + __runtime_format_string& operator=(const __runtime_format_string&) = delete; +}; + +_LIBCPP_HIDE_FROM_ABI inline __runtime_format_string runtime_format(string_view __fmt) noexcept { return __fmt; } +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +_LIBCPP_HIDE_FROM_ABI inline __runtime_format_string runtime_format(wstring_view __fmt) noexcept { + return __fmt; +} +# endif +# endif //_LIBCPP_STD_VER >= 26 + +template +struct _LIBCPP_TEMPLATE_VIS basic_format_string { + template + requires convertible_to> + consteval basic_format_string(const _Tp& __str) : __str_{__str} { + __format::__vformat_to(basic_format_parse_context<_CharT>{__str_, sizeof...(_Args)}, + _Context{__types_.data(), __handles_.data(), sizeof...(_Args)}); + } + + _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<_CharT> get() const noexcept { return __str_; } +# if _LIBCPP_STD_VER >= 26 + _LIBCPP_HIDE_FROM_ABI basic_format_string(__runtime_format_string<_CharT> __s) noexcept : __str_(__s.__str_) {} +# endif + +private: + basic_string_view<_CharT> __str_; + + using _Context = __format::__compile_time_basic_format_context<_CharT>; + + static constexpr array<__format::__arg_t, sizeof...(_Args)> __types_{ + __format::__determine_arg_t<_Context, remove_cvref_t<_Args>>()...}; + + static constexpr array<__format::__compile_time_handle<_CharT>, sizeof...(_Args)> __handles_{[] { + using _Tp = remove_cvref_t<_Args>; + __format::__compile_time_handle<_CharT> __handle; + if (__format::__determine_arg_t<_Context, _Tp>() == __format::__arg_t::__handle) + __handle.template __enable<_Tp>(); + + return __handle; + }()...}; +}; + +template +using format_string = basic_format_string...>; + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template +using wformat_string = basic_format_string...>; +# endif + +template + requires(output_iterator<_OutIt, const _CharT&>) +_LIBCPP_HIDE_FROM_ABI _OutIt __vformat_to(_OutIt __out_it, + basic_string_view<_CharT> __fmt, + basic_format_args> __args) { + if constexpr (same_as<_OutIt, _FormatOutIt>) + return std::__format::__vformat_to( + basic_format_parse_context{__fmt, __args.__size()}, std::__format_context_create(std::move(__out_it), __args)); + else { + __format::__format_buffer<_OutIt, _CharT> __buffer{std::move(__out_it)}; + std::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()}, + std::__format_context_create(__buffer.__make_output_iterator(), __args)); + return std::move(__buffer).__out_it(); + } +} + +// The function is _LIBCPP_ALWAYS_INLINE since the compiler is bad at inlining +// https://reviews.llvm.org/D110499#inline-1180704 +// TODO FMT Evaluate whether we want to file a Clang bug report regarding this. +template _OutIt> +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt vformat_to(_OutIt __out_it, string_view __fmt, format_args __args) { + return std::__vformat_to(std::move(__out_it), __fmt, __args); +} + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template _OutIt> +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt +vformat_to(_OutIt __out_it, wstring_view __fmt, wformat_args __args) { + return std::__vformat_to(std::move(__out_it), __fmt, __args); +} +# endif + +template _OutIt, class... _Args> +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt +format_to(_OutIt __out_it, format_string<_Args...> __fmt, _Args&&... __args) { + return std::vformat_to(std::move(__out_it), __fmt.get(), std::make_format_args(__args...)); +} + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template _OutIt, class... _Args> +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt +format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) { + return std::vformat_to(std::move(__out_it), __fmt.get(), std::make_wformat_args(__args...)); +} +# endif + +// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup +// fires too eagerly, see http://llvm.org/PR61563. +template +[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string vformat(string_view __fmt, format_args __args) { + string __res; + std::vformat_to(std::back_inserter(__res), __fmt, __args); + return __res; +} + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup +// fires too eagerly, see http://llvm.org/PR61563. +template +[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring +vformat(wstring_view __fmt, wformat_args __args) { + wstring __res; + std::vformat_to(std::back_inserter(__res), __fmt, __args); + return __res; +} +# endif + +template +[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string +format(format_string<_Args...> __fmt, _Args&&... __args) { + return std::vformat(__fmt.get(), std::make_format_args(__args...)); +} + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template +[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring +format(wformat_string<_Args...> __fmt, _Args&&... __args) { + return std::vformat(__fmt.get(), std::make_wformat_args(__args...)); +} +# endif + +template +_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> +__vformat_to_n(_OutIt __out_it, + iter_difference_t<_OutIt> __n, + basic_string_view<_CharT> __fmt, + basic_format_args<_Context> __args) { + __format::__format_to_n_buffer<_OutIt, _CharT> __buffer{std::move(__out_it), __n}; + std::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()}, + std::__format_context_create(__buffer.__make_output_iterator(), __args)); + return std::move(__buffer).__result(); +} + +template _OutIt, class... _Args> +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> +format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, format_string<_Args...> __fmt, _Args&&... __args) { + return std::__vformat_to_n(std::move(__out_it), __n, __fmt.get(), std::make_format_args(__args...)); +} + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template _OutIt, class... _Args> +_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> +format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, wformat_string<_Args...> __fmt, _Args&&... __args) { + return std::__vformat_to_n(std::move(__out_it), __n, __fmt.get(), std::make_wformat_args(__args...)); +} +# endif + +template +_LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(basic_string_view<_CharT> __fmt, auto __args) { + __format::__formatted_size_buffer<_CharT> __buffer; + std::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()}, + std::__format_context_create(__buffer.__make_output_iterator(), __args)); + return std::move(__buffer).__result(); +} + +template +[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t +formatted_size(format_string<_Args...> __fmt, _Args&&... __args) { + return std::__vformatted_size(__fmt.get(), basic_format_args{std::make_format_args(__args...)}); +} + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template +[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t +formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args) { + return std::__vformatted_size(__fmt.get(), basic_format_args{std::make_wformat_args(__args...)}); +} +# endif + +# ifndef _LIBCPP_HAS_NO_LOCALIZATION + +template + requires(output_iterator<_OutIt, const _CharT&>) +_LIBCPP_HIDE_FROM_ABI _OutIt __vformat_to( + _OutIt __out_it, + locale __loc, + basic_string_view<_CharT> __fmt, + basic_format_args> __args) { + if constexpr (same_as<_OutIt, _FormatOutIt>) + return std::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()}, + std::__format_context_create(std::move(__out_it), __args, std::move(__loc))); + else { + __format::__format_buffer<_OutIt, _CharT> __buffer{std::move(__out_it)}; + std::__format::__vformat_to( + basic_format_parse_context{__fmt, __args.__size()}, + std::__format_context_create(__buffer.__make_output_iterator(), __args, std::move(__loc))); + return std::move(__buffer).__out_it(); + } +} + +template _OutIt> +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt +vformat_to(_OutIt __out_it, locale __loc, string_view __fmt, format_args __args) { + return std::__vformat_to(std::move(__out_it), std::move(__loc), __fmt, __args); +} + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template _OutIt> +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt +vformat_to(_OutIt __out_it, locale __loc, wstring_view __fmt, wformat_args __args) { + return std::__vformat_to(std::move(__out_it), std::move(__loc), __fmt, __args); +} +# endif + +template _OutIt, class... _Args> +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt +format_to(_OutIt __out_it, locale __loc, format_string<_Args...> __fmt, _Args&&... __args) { + return std::vformat_to(std::move(__out_it), std::move(__loc), __fmt.get(), std::make_format_args(__args...)); +} + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template _OutIt, class... _Args> +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt +format_to(_OutIt __out_it, locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) { + return std::vformat_to(std::move(__out_it), std::move(__loc), __fmt.get(), std::make_wformat_args(__args...)); +} +# endif + +// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup +// fires too eagerly, see http://llvm.org/PR61563. +template +[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string +vformat(locale __loc, string_view __fmt, format_args __args) { + string __res; + std::vformat_to(std::back_inserter(__res), std::move(__loc), __fmt, __args); + return __res; +} + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup +// fires too eagerly, see http://llvm.org/PR61563. +template +[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring +vformat(locale __loc, wstring_view __fmt, wformat_args __args) { + wstring __res; + std::vformat_to(std::back_inserter(__res), std::move(__loc), __fmt, __args); + return __res; +} +# endif + +template +[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string +format(locale __loc, format_string<_Args...> __fmt, _Args&&... __args) { + return std::vformat(std::move(__loc), __fmt.get(), std::make_format_args(__args...)); +} + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template +[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring +format(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) { + return std::vformat(std::move(__loc), __fmt.get(), std::make_wformat_args(__args...)); +} +# endif + +template +_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n( + _OutIt __out_it, + iter_difference_t<_OutIt> __n, + locale __loc, + basic_string_view<_CharT> __fmt, + basic_format_args<_Context> __args) { + __format::__format_to_n_buffer<_OutIt, _CharT> __buffer{std::move(__out_it), __n}; + std::__format::__vformat_to( + basic_format_parse_context{__fmt, __args.__size()}, + std::__format_context_create(__buffer.__make_output_iterator(), __args, std::move(__loc))); + return std::move(__buffer).__result(); +} + +template _OutIt, class... _Args> +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> format_to_n( + _OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, format_string<_Args...> __fmt, _Args&&... __args) { + return std::__vformat_to_n( + std::move(__out_it), __n, std::move(__loc), __fmt.get(), std::make_format_args(__args...)); +} + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template _OutIt, class... _Args> +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> format_to_n( + _OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) { + return std::__vformat_to_n( + std::move(__out_it), __n, std::move(__loc), __fmt.get(), std::make_wformat_args(__args...)); +} +# endif + +template +_LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(locale __loc, basic_string_view<_CharT> __fmt, auto __args) { + __format::__formatted_size_buffer<_CharT> __buffer; + std::__format::__vformat_to( + basic_format_parse_context{__fmt, __args.__size()}, + std::__format_context_create(__buffer.__make_output_iterator(), __args, std::move(__loc))); + return std::move(__buffer).__result(); +} + +template +[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t +formatted_size(locale __loc, format_string<_Args...> __fmt, _Args&&... __args) { + return std::__vformatted_size(std::move(__loc), __fmt.get(), basic_format_args{std::make_format_args(__args...)}); +} + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template +[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t +formatted_size(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) { + return std::__vformatted_size(std::move(__loc), __fmt.get(), basic_format_args{std::make_wformat_args(__args...)}); +} +# endif + +# endif // _LIBCPP_HAS_NO_LOCALIZATION + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_FORMAT_FUNCTIONS diff --git a/libcxx/include/__cxx03/__format/format_parse_context.h b/libcxx/include/__cxx03/__format/format_parse_context.h new file mode 100644 index 0000000000000000000000000000000000000000..aefcd5497f3b9b04ca1bdb7739be1462adf0b455 --- /dev/null +++ b/libcxx/include/__cxx03/__format/format_parse_context.h @@ -0,0 +1,105 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMAT_PARSE_CONTEXT_H +#define _LIBCPP___FORMAT_FORMAT_PARSE_CONTEXT_H + +#include <__config> +#include <__format/format_error.h> +#include <__type_traits/is_constant_evaluated.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +class _LIBCPP_TEMPLATE_VIS basic_format_parse_context { +public: + using char_type = _CharT; + using const_iterator = typename basic_string_view<_CharT>::const_iterator; + using iterator = const_iterator; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit basic_format_parse_context( + basic_string_view<_CharT> __fmt, size_t __num_args = 0) noexcept + : __begin_(__fmt.begin()), + __end_(__fmt.end()), + __indexing_(__unknown), + __next_arg_id_(0), + __num_args_(__num_args) {} + + basic_format_parse_context(const basic_format_parse_context&) = delete; + basic_format_parse_context& operator=(const basic_format_parse_context&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept { return __begin_; } + _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept { return __end_; } + _LIBCPP_HIDE_FROM_ABI constexpr void advance_to(const_iterator __it) { __begin_ = __it; } + + _LIBCPP_HIDE_FROM_ABI constexpr size_t next_arg_id() { + if (__indexing_ == __manual) + std::__throw_format_error("Using automatic argument numbering in manual argument numbering mode"); + + if (__indexing_ == __unknown) + __indexing_ = __automatic; + + // Throws an exception to make the expression a non core constant + // expression as required by: + // [format.parse.ctx]/8 + // Remarks: Let cur-arg-id be the value of next_arg_id_ prior to this + // call. Call expressions where cur-arg-id >= num_args_ is true are not + // core constant expressions (7.7 [expr.const]). + // Note: the Throws clause [format.parse.ctx]/9 doesn't specify the + // behavior when id >= num_args_. + if (is_constant_evaluated() && __next_arg_id_ >= __num_args_) + std::__throw_format_error("Argument index outside the valid range"); + + return __next_arg_id_++; + } + _LIBCPP_HIDE_FROM_ABI constexpr void check_arg_id(size_t __id) { + if (__indexing_ == __automatic) + std::__throw_format_error("Using manual argument numbering in automatic argument numbering mode"); + + if (__indexing_ == __unknown) + __indexing_ = __manual; + + // Throws an exception to make the expression a non core constant + // expression as required by: + // [format.parse.ctx]/11 + // Remarks: Call expressions where id >= num_args_ are not core constant + // expressions ([expr.const]). + // Note: the Throws clause [format.parse.ctx]/10 doesn't specify the + // behavior when id >= num_args_. + if (is_constant_evaluated() && __id >= __num_args_) + std::__throw_format_error("Argument index outside the valid range"); + } + +private: + iterator __begin_; + iterator __end_; + enum _Indexing { __unknown, __manual, __automatic }; + _Indexing __indexing_; + size_t __next_arg_id_; + size_t __num_args_; +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_format_parse_context); + +using format_parse_context = basic_format_parse_context; +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +using wformat_parse_context = basic_format_parse_context; +# endif + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMAT_PARSE_CONTEXT_H diff --git a/libcxx/include/__cxx03/__format/format_string.h b/libcxx/include/__cxx03/__format/format_string.h new file mode 100644 index 0000000000000000000000000000000000000000..bdf3cff7f49b1824fb2ce68711f296cf1241bf68 --- /dev/null +++ b/libcxx/include/__cxx03/__format/format_string.h @@ -0,0 +1,160 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMAT_STRING_H +#define _LIBCPP___FORMAT_FORMAT_STRING_H + +#include <__assert> +#include <__config> +#include <__format/format_error.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> // iter_value_t +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __format { + +template +struct _LIBCPP_TEMPLATE_VIS __parse_number_result { + _Iterator __last; + uint32_t __value; +}; + +template +__parse_number_result(_Iterator, uint32_t) -> __parse_number_result<_Iterator>; + +template +_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> __parse_number(_Iterator __begin, _Iterator __end); + +/** + * The maximum value of a numeric argument. + * + * This is used for: + * * arg-id + * * width as value or arg-id. + * * precision as value or arg-id. + * + * The value is compatible with the maximum formatting width and precision + * using the `%*` syntax on a 32-bit system. + */ +inline constexpr uint32_t __number_max = INT32_MAX; + +namespace __detail { +template +_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> +__parse_zero(_Iterator __begin, _Iterator, auto& __parse_ctx) { + __parse_ctx.check_arg_id(0); + return {++__begin, 0}; // can never be larger than the maximum. +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> +__parse_automatic(_Iterator __begin, _Iterator, auto& __parse_ctx) { + size_t __value = __parse_ctx.next_arg_id(); + _LIBCPP_ASSERT_UNCATEGORIZED(__value <= __number_max, "Compilers don't support this number of arguments"); + + return {__begin, uint32_t(__value)}; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> +__parse_manual(_Iterator __begin, _Iterator __end, auto& __parse_ctx) { + __parse_number_result<_Iterator> __r = __format::__parse_number(__begin, __end); + __parse_ctx.check_arg_id(__r.__value); + return __r; +} + +} // namespace __detail + +/** + * Parses a number. + * + * The number is used for the 31-bit values @em width and @em precision. This + * allows a maximum value of 2147483647. + */ +template +_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> +__parse_number(_Iterator __begin, _Iterator __end_input) { + using _CharT = iter_value_t<_Iterator>; + static_assert(__format::__number_max == INT32_MAX, "The algorithm is implemented based on this value."); + /* + * Limit the input to 9 digits, otherwise we need two checks during every + * iteration: + * - Are we at the end of the input? + * - Does the value exceed width of an uint32_t? (Switching to uint64_t would + * have the same issue, but with a higher maximum.) + */ + _Iterator __end = __end_input - __begin > 9 ? __begin + 9 : __end_input; + uint32_t __value = *__begin - _CharT('0'); + while (++__begin != __end) { + if (*__begin < _CharT('0') || *__begin > _CharT('9')) + return {__begin, __value}; + + __value = __value * 10 + *__begin - _CharT('0'); + } + + if (__begin != __end_input && *__begin >= _CharT('0') && *__begin <= _CharT('9')) { + /* + * There are more than 9 digits, do additional validations: + * - Does the 10th digit exceed the maximum allowed value? + * - Are there more than 10 digits? + * (More than 10 digits always overflows the maximum.) + */ + uint64_t __v = uint64_t(__value) * 10 + *__begin++ - _CharT('0'); + if (__v > __number_max || (__begin != __end_input && *__begin >= _CharT('0') && *__begin <= _CharT('9'))) + std::__throw_format_error("The numeric value of the format specifier is too large"); + + __value = __v; + } + + return {__begin, __value}; +} + +/** + * Multiplexer for all parse functions. + * + * The parser will return a pointer beyond the last consumed character. This + * should be the closing '}' of the arg-id. + */ +template +_LIBCPP_HIDE_FROM_ABI constexpr __parse_number_result<_Iterator> +__parse_arg_id(_Iterator __begin, _Iterator __end, auto& __parse_ctx) { + using _CharT = iter_value_t<_Iterator>; + switch (*__begin) { + case _CharT('0'): + return __detail::__parse_zero(__begin, __end, __parse_ctx); + + case _CharT(':'): + // This case is conditionally valid. It's allowed in an arg-id in the + // replacement-field, but not in the std-format-spec. The caller can + // provide a better diagnostic, so accept it here unconditionally. + case _CharT('}'): + return __detail::__parse_automatic(__begin, __end, __parse_ctx); + } + if (*__begin < _CharT('0') || *__begin > _CharT('9')) + std::__throw_format_error("The argument index starts with an invalid character"); + + return __detail::__parse_manual(__begin, __end, __parse_ctx); +} + +} // namespace __format + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMAT_STRING_H diff --git a/libcxx/include/__cxx03/__format/format_to_n_result.h b/libcxx/include/__cxx03/__format/format_to_n_result.h new file mode 100644 index 0000000000000000000000000000000000000000..6f30546dec081cb66927851a8ccc5831c5b37ae8 --- /dev/null +++ b/libcxx/include/__cxx03/__format/format_to_n_result.h @@ -0,0 +1,35 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMAT_TO_N_RESULT_H +#define _LIBCPP___FORMAT_FORMAT_TO_N_RESULT_H + +#include <__config> +#include <__iterator/incrementable_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +struct _LIBCPP_TEMPLATE_VIS format_to_n_result { + _OutIt out; + iter_difference_t<_OutIt> size; +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(format_to_n_result); + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMAT_TO_N_RESULT_H diff --git a/libcxx/include/__cxx03/__format/formatter.h b/libcxx/include/__cxx03/__format/formatter.h new file mode 100644 index 0000000000000000000000000000000000000000..e2f418f936ee10e401d9c879729d1722fa1b1b34 --- /dev/null +++ b/libcxx/include/__cxx03/__format/formatter.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMATTER_H +#define _LIBCPP___FORMAT_FORMATTER_H + +#include <__config> +#include <__fwd/format.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +/// The default formatter template. +/// +/// [format.formatter.spec]/5 +/// If F is a disabled specialization of formatter, these values are false: +/// - is_default_constructible_v, +/// - is_copy_constructible_v, +/// - is_move_constructible_v, +/// - is_copy_assignable, and +/// - is_move_assignable. +template +struct _LIBCPP_TEMPLATE_VIS formatter { + formatter() = delete; + formatter(const formatter&) = delete; + formatter& operator=(const formatter&) = delete; +}; + +# if _LIBCPP_STD_VER >= 23 + +template +_LIBCPP_HIDE_FROM_ABI constexpr void __set_debug_format(_Tp& __formatter) { + if constexpr (requires { __formatter.set_debug_format(); }) + __formatter.set_debug_format(); +} + +# endif // _LIBCPP_STD_VER >= 23 +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMATTER_H diff --git a/libcxx/include/__cxx03/__format/formatter_bool.h b/libcxx/include/__cxx03/__format/formatter_bool.h new file mode 100644 index 0000000000000000000000000000000000000000..17dc69541e8fe1b1c6ebee117fdbed78873b00b6 --- /dev/null +++ b/libcxx/include/__cxx03/__format/formatter_bool.h @@ -0,0 +1,76 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMATTER_BOOL_H +#define _LIBCPP___FORMAT_FORMATTER_BOOL_H + +#include <__algorithm/copy.h> +#include <__assert> +#include <__config> +#include <__format/concepts.h> +#include <__format/format_parse_context.h> +#include <__format/formatter.h> +#include <__format/formatter_integral.h> +#include <__format/parser_std_format_spec.h> +#include <__utility/unreachable.h> + +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include <__locale> +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter { +public: + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_integral); + __format_spec::__process_parsed_bool(__parser_, "a bool"); + return __result; + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(bool __value, _FormatContext& __ctx) const { + switch (__parser_.__type_) { + case __format_spec::__type::__default: + case __format_spec::__type::__string: + return __formatter::__format_bool(__value, __ctx, __parser_.__get_parsed_std_specifications(__ctx)); + + case __format_spec::__type::__binary_lower_case: + case __format_spec::__type::__binary_upper_case: + case __format_spec::__type::__octal: + case __format_spec::__type::__decimal: + case __format_spec::__type::__hexadecimal_lower_case: + case __format_spec::__type::__hexadecimal_upper_case: + // Promotes bool to an integral type. This reduces the number of + // instantiations of __format_integer reducing code size. + return __formatter::__format_integer( + static_cast(__value), __ctx, __parser_.__get_parsed_std_specifications(__ctx)); + + default: + _LIBCPP_ASSERT_INTERNAL(false, "The parse function should have validated the type"); + __libcpp_unreachable(); + } + } + + __format_spec::__parser<_CharT> __parser_; +}; + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMATTER_BOOL_H diff --git a/libcxx/include/__cxx03/__format/formatter_char.h b/libcxx/include/__cxx03/__format/formatter_char.h new file mode 100644 index 0000000000000000000000000000000000000000..d33e84368a7650d3c498b1af89bf6554175ddc01 --- /dev/null +++ b/libcxx/include/__cxx03/__format/formatter_char.h @@ -0,0 +1,93 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMATTER_CHAR_H +#define _LIBCPP___FORMAT_FORMATTER_CHAR_H + +#include <__concepts/same_as.h> +#include <__config> +#include <__format/concepts.h> +#include <__format/format_parse_context.h> +#include <__format/formatter.h> +#include <__format/formatter_integral.h> +#include <__format/formatter_output.h> +#include <__format/parser_std_format_spec.h> +#include <__format/write_escaped.h> +#include <__type_traits/conditional.h> +#include <__type_traits/make_unsigned.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS __formatter_char { +public: + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_integral); + __format_spec::__process_parsed_char(__parser_, "a character"); + return __result; + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_CharT __value, _FormatContext& __ctx) const { + if (__parser_.__type_ == __format_spec::__type::__default || __parser_.__type_ == __format_spec::__type::__char) + return __formatter::__format_char(__value, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx)); + +# if _LIBCPP_STD_VER >= 23 + if (__parser_.__type_ == __format_spec::__type::__debug) + return __formatter::__format_escaped_char(__value, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx)); +# endif + + if constexpr (sizeof(_CharT) <= sizeof(unsigned)) + return __formatter::__format_integer( + static_cast(static_cast>(__value)), + __ctx, + __parser_.__get_parsed_std_specifications(__ctx)); + else + return __formatter::__format_integer( + static_cast>(__value), __ctx, __parser_.__get_parsed_std_specifications(__ctx)); + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(char __value, _FormatContext& __ctx) const + requires(same_as<_CharT, wchar_t>) + { + return format(static_cast(static_cast(__value)), __ctx); + } + +# if _LIBCPP_STD_VER >= 23 + _LIBCPP_HIDE_FROM_ABI constexpr void set_debug_format() { __parser_.__type_ = __format_spec::__type::__debug; } +# endif + + __format_spec::__parser<_CharT> __parser_; +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_char {}; + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_char {}; + +template <> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_char {}; + +# endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMATTER_CHAR_H diff --git a/libcxx/include/__cxx03/__format/formatter_floating_point.h b/libcxx/include/__cxx03/__format/formatter_floating_point.h new file mode 100644 index 0000000000000000000000000000000000000000..fa42ba203b0b5e2bc9516a96a6e570c1e32ba532 --- /dev/null +++ b/libcxx/include/__cxx03/__format/formatter_floating_point.h @@ -0,0 +1,783 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMATTER_FLOATING_POINT_H +#define _LIBCPP___FORMAT_FORMATTER_FLOATING_POINT_H + +#include <__algorithm/copy_n.h> +#include <__algorithm/find.h> +#include <__algorithm/max.h> +#include <__algorithm/min.h> +#include <__algorithm/rotate.h> +#include <__algorithm/transform.h> +#include <__assert> +#include <__charconv/chars_format.h> +#include <__charconv/to_chars_floating_point.h> +#include <__charconv/to_chars_result.h> +#include <__concepts/arithmetic.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__format/concepts.h> +#include <__format/format_parse_context.h> +#include <__format/formatter.h> +#include <__format/formatter_integral.h> +#include <__format/formatter_output.h> +#include <__format/parser_std_format_spec.h> +#include <__iterator/concepts.h> +#include <__memory/allocator.h> +#include <__system_error/errc.h> +#include <__type_traits/conditional.h> +#include <__utility/move.h> +#include <__utility/unreachable.h> +#include +#include + +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include <__locale> +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __formatter { + +template +_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value) { + to_chars_result __r = std::to_chars(__first, __last, __value); + _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small"); + return __r.ptr; +} + +template +_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, chars_format __fmt) { + to_chars_result __r = std::to_chars(__first, __last, __value, __fmt); + _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small"); + return __r.ptr; +} + +template +_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, chars_format __fmt, int __precision) { + to_chars_result __r = std::to_chars(__first, __last, __value, __fmt, __precision); + _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small"); + return __r.ptr; +} + +// https://en.cppreference.com/w/cpp/language/types#cite_note-1 +// float min subnormal: +/-0x1p-149 max: +/- 3.402,823,4 10^38 +// double min subnormal: +/-0x1p-1074 max +/- 1.797,693,134,862,315,7 10^308 +// long double (x86) min subnormal: +/-0x1p-16446 max: +/- 1.189,731,495,357,231,765,021 10^4932 +// +// The maximum number of digits required for the integral part is based on the +// maximum's value power of 10. Every power of 10 requires one additional +// decimal digit. +// The maximum number of digits required for the fractional part is based on +// the minimal subnormal hexadecimal output's power of 10. Every division of a +// fraction's binary 1 by 2, requires one additional decimal digit. +// +// The maximum size of a formatted value depends on the selected output format. +// Ignoring the fact the format string can request a precision larger than the +// values maximum required, these values are: +// +// sign 1 code unit +// __max_integral +// radix point 1 code unit +// __max_fractional +// exponent character 1 code unit +// sign 1 code unit +// __max_fractional_value +// ----------------------------------- +// total 4 code units extra required. +// +// TODO FMT Optimize the storage to avoid storing digits that are known to be zero. +// https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/ + +// TODO FMT Add long double specialization when to_chars has proper long double support. +template +struct __traits; + +template +_LIBCPP_HIDE_FROM_ABI constexpr size_t __float_buffer_size(int __precision) { + using _Traits = __traits<_Fp>; + return 4 + _Traits::__max_integral + __precision + _Traits::__max_fractional_value; +} + +template <> +struct __traits { + static constexpr int __max_integral = 38; + static constexpr int __max_fractional = 149; + static constexpr int __max_fractional_value = 3; + static constexpr size_t __stack_buffer_size = 256; + + static constexpr int __hex_precision_digits = 3; +}; + +template <> +struct __traits { + static constexpr int __max_integral = 308; + static constexpr int __max_fractional = 1074; + static constexpr int __max_fractional_value = 4; + static constexpr size_t __stack_buffer_size = 1024; + + static constexpr int __hex_precision_digits = 4; +}; + +/// Helper class to store the conversion buffer. +/// +/// Depending on the maximum size required for a value, the buffer is allocated +/// on the stack or the heap. +template +class _LIBCPP_TEMPLATE_VIS __float_buffer { + using _Traits = __traits<_Fp>; + +public: + // TODO FMT Improve this constructor to do a better estimate. + // When using a scientific formatting with a precision of 6 a stack buffer + // will always suffice. At the moment that isn't important since floats and + // doubles use a stack buffer, unless the precision used in the format string + // is large. + // When supporting long doubles the __max_integral part becomes 4932 which + // may be too much for some platforms. For these cases a better estimate is + // required. + explicit _LIBCPP_HIDE_FROM_ABI __float_buffer(int __precision) + : __precision_(__precision != -1 ? __precision : _Traits::__max_fractional) { + // When the precision is larger than _Traits::__max_fractional the digits in + // the range (_Traits::__max_fractional, precision] will contain the value + // zero. There's no need to request to_chars to write these zeros: + // - When the value is large a temporary heap buffer needs to be allocated. + // - When to_chars writes the values they need to be "copied" to the output: + // - char: std::fill on the output iterator is faster than std::copy. + // - wchar_t: same argument as char, but additional std::copy won't work. + // The input is always a char buffer, so every char in the buffer needs + // to be converted from a char to a wchar_t. + if (__precision_ > _Traits::__max_fractional) { + __num_trailing_zeros_ = __precision_ - _Traits::__max_fractional; + __precision_ = _Traits::__max_fractional; + } + + __size_ = __formatter::__float_buffer_size<_Fp>(__precision_); + if (__size_ > _Traits::__stack_buffer_size) + // The allocated buffer's contents don't need initialization. + __begin_ = allocator{}.allocate(__size_); + else + __begin_ = __buffer_; + } + + _LIBCPP_HIDE_FROM_ABI ~__float_buffer() { + if (__size_ > _Traits::__stack_buffer_size) + allocator{}.deallocate(__begin_, __size_); + } + _LIBCPP_HIDE_FROM_ABI __float_buffer(const __float_buffer&) = delete; + _LIBCPP_HIDE_FROM_ABI __float_buffer& operator=(const __float_buffer&) = delete; + + _LIBCPP_HIDE_FROM_ABI char* begin() const { return __begin_; } + _LIBCPP_HIDE_FROM_ABI char* end() const { return __begin_ + __size_; } + + _LIBCPP_HIDE_FROM_ABI int __precision() const { return __precision_; } + _LIBCPP_HIDE_FROM_ABI int __num_trailing_zeros() const { return __num_trailing_zeros_; } + _LIBCPP_HIDE_FROM_ABI void __remove_trailing_zeros() { __num_trailing_zeros_ = 0; } + _LIBCPP_HIDE_FROM_ABI void __add_trailing_zeros(int __zeros) { __num_trailing_zeros_ += __zeros; } + +private: + int __precision_; + int __num_trailing_zeros_{0}; + size_t __size_; + char* __begin_; + char __buffer_[_Traits::__stack_buffer_size]; +}; + +struct __float_result { + /// Points at the beginning of the integral part in the buffer. + /// + /// When there's no sign character this points at the start of the buffer. + char* __integral; + + /// Points at the radix point, when not present it's the same as \ref __last. + char* __radix_point; + + /// Points at the exponent character, when not present it's the same as \ref __last. + char* __exponent; + + /// Points beyond the last written element in the buffer. + char* __last; +}; + +/// Finds the position of the exponent character 'e' at the end of the buffer. +/// +/// Assuming there is an exponent the input will terminate with +/// eSdd and eSdddd (S = sign, d = digit) +/// +/// \returns a pointer to the exponent or __last when not found. +constexpr inline _LIBCPP_HIDE_FROM_ABI char* __find_exponent(char* __first, char* __last) { + ptrdiff_t __size = __last - __first; + if (__size >= 4) { + __first = __last - std::min(__size, ptrdiff_t(6)); + for (; __first != __last - 3; ++__first) { + if (*__first == 'e') + return __first; + } + } + return __last; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result +__format_buffer_default(const __float_buffer<_Fp>& __buffer, _Tp __value, char* __integral) { + __float_result __result; + __result.__integral = __integral; + __result.__last = __formatter::__to_buffer(__integral, __buffer.end(), __value); + + __result.__exponent = __formatter::__find_exponent(__result.__integral, __result.__last); + + // Constrains: + // - There's at least one decimal digit before the radix point. + // - The radix point, when present, is placed before the exponent. + __result.__radix_point = std::find(__result.__integral + 1, __result.__exponent, '.'); + + // When the radix point isn't found its position is the exponent instead of + // __result.__last. + if (__result.__radix_point == __result.__exponent) + __result.__radix_point = __result.__last; + + // clang-format off + _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent == __result.__last || *__result.__exponent == 'e'), + "Post-condition failure."); + // clang-format on + + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_lower_case( + const __float_buffer<_Fp>& __buffer, _Tp __value, int __precision, char* __integral) { + __float_result __result; + __result.__integral = __integral; + if (__precision == -1) + __result.__last = __formatter::__to_buffer(__integral, __buffer.end(), __value, chars_format::hex); + else + __result.__last = __formatter::__to_buffer(__integral, __buffer.end(), __value, chars_format::hex, __precision); + + // H = one or more hex-digits + // S = sign + // D = one or more decimal-digits + // When the fractional part is zero and no precision the output is 0p+0 + // else the output is 0.HpSD + // So testing the second position can differentiate between these two cases. + char* __first = __integral + 1; + if (*__first == '.') { + __result.__radix_point = __first; + // One digit is the minimum + // 0.hpSd + // ^-- last + // ^---- integral = end of search + // ^-------- start of search + // 0123456 + // + // Four digits is the maximum + // 0.hpSdddd + // ^-- last + // ^---- integral = end of search + // ^-------- start of search + // 0123456789 + static_assert(__traits<_Fp>::__hex_precision_digits <= 4, "Guard against possible underflow."); + + char* __last = __result.__last - 2; + __first = __last - __traits<_Fp>::__hex_precision_digits; + __result.__exponent = std::find(__first, __last, 'p'); + } else { + __result.__radix_point = __result.__last; + __result.__exponent = __first; + } + + // clang-format off + _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent != __result.__last && *__result.__exponent == 'p'), + "Post-condition failure."); + // clang-format on + + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_upper_case( + const __float_buffer<_Fp>& __buffer, _Tp __value, int __precision, char* __integral) { + __float_result __result = + __formatter::__format_buffer_hexadecimal_lower_case(__buffer, __value, __precision, __integral); + std::transform(__result.__integral, __result.__exponent, __result.__integral, __hex_to_upper); + *__result.__exponent = 'P'; + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_lower_case( + const __float_buffer<_Fp>& __buffer, _Tp __value, int __precision, char* __integral) { + __float_result __result; + __result.__integral = __integral; + __result.__last = + __formatter::__to_buffer(__integral, __buffer.end(), __value, chars_format::scientific, __precision); + + char* __first = __integral + 1; + _LIBCPP_ASSERT_INTERNAL(__first != __result.__last, "No exponent present"); + if (*__first == '.') { + __result.__radix_point = __first; + __result.__exponent = __formatter::__find_exponent(__first + 1, __result.__last); + } else { + __result.__radix_point = __result.__last; + __result.__exponent = __first; + } + + // clang-format off + _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent != __result.__last && *__result.__exponent == 'e'), + "Post-condition failure."); + // clang-format on + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_upper_case( + const __float_buffer<_Fp>& __buffer, _Tp __value, int __precision, char* __integral) { + __float_result __result = + __formatter::__format_buffer_scientific_lower_case(__buffer, __value, __precision, __integral); + *__result.__exponent = 'E'; + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result +__format_buffer_fixed(const __float_buffer<_Fp>& __buffer, _Tp __value, int __precision, char* __integral) { + __float_result __result; + __result.__integral = __integral; + __result.__last = __formatter::__to_buffer(__integral, __buffer.end(), __value, chars_format::fixed, __precision); + + // When there's no precision there's no radix point. + // Else the radix point is placed at __precision + 1 from the end. + // By converting __precision to a bool the subtraction can be done + // unconditionally. + __result.__radix_point = __result.__last - (__precision + bool(__precision)); + __result.__exponent = __result.__last; + + // clang-format off + _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent == __result.__last), + "Post-condition failure."); + // clang-format on + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result +__format_buffer_general_lower_case(__float_buffer<_Fp>& __buffer, _Tp __value, int __precision, char* __integral) { + __buffer.__remove_trailing_zeros(); + + __float_result __result; + __result.__integral = __integral; + __result.__last = __formatter::__to_buffer(__integral, __buffer.end(), __value, chars_format::general, __precision); + + char* __first = __integral + 1; + if (__first == __result.__last) { + __result.__radix_point = __result.__last; + __result.__exponent = __result.__last; + } else { + __result.__exponent = __formatter::__find_exponent(__first, __result.__last); + if (__result.__exponent != __result.__last) + // In scientific mode if there's a radix point it will always be after + // the first digit. (This is the position __first points at). + __result.__radix_point = *__first == '.' ? __first : __result.__last; + else { + // In fixed mode the algorithm truncates trailing spaces and possibly the + // radix point. There's no good guess for the position of the radix point + // therefore scan the output after the first digit. + __result.__radix_point = std::find(__first, __result.__last, '.'); + } + } + + // clang-format off + _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent == __result.__last || *__result.__exponent == 'e'), + "Post-condition failure."); + // clang-format on + + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result +__format_buffer_general_upper_case(__float_buffer<_Fp>& __buffer, _Tp __value, int __precision, char* __integral) { + __float_result __result = __formatter::__format_buffer_general_lower_case(__buffer, __value, __precision, __integral); + if (__result.__exponent != __result.__last) + *__result.__exponent = 'E'; + return __result; +} + +/// Fills the buffer with the data based on the requested formatting. +/// +/// This function, when needed, turns the characters to upper case and +/// determines the "interesting" locations which are returned to the caller. +/// +/// This means the caller never has to convert the contents of the buffer to +/// upper case or search for radix points and the location of the exponent. +/// This gives a bit of overhead. The original code didn't do that, but due +/// to the number of possible additional work needed to turn this number to +/// the proper output the code was littered with tests for upper cases and +/// searches for radix points and exponents. +/// - When a precision larger than the type's precision is selected +/// additional zero characters need to be written before the exponent. +/// - alternate form needs to add a radix point when not present. +/// - localization needs to do grouping in the integral part. +template +// TODO FMT _Fp should just be _Tp when to_chars has proper long double support. +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer( + __float_buffer<_Fp>& __buffer, + _Tp __value, + bool __negative, + bool __has_precision, + __format_spec::__sign __sign, + __format_spec::__type __type) { + char* __first = __formatter::__insert_sign(__buffer.begin(), __negative, __sign); + switch (__type) { + case __format_spec::__type::__default: + if (__has_precision) + return __formatter::__format_buffer_general_lower_case(__buffer, __value, __buffer.__precision(), __first); + else + return __formatter::__format_buffer_default(__buffer, __value, __first); + + case __format_spec::__type::__hexfloat_lower_case: + return __formatter::__format_buffer_hexadecimal_lower_case( + __buffer, __value, __has_precision ? __buffer.__precision() : -1, __first); + + case __format_spec::__type::__hexfloat_upper_case: + return __formatter::__format_buffer_hexadecimal_upper_case( + __buffer, __value, __has_precision ? __buffer.__precision() : -1, __first); + + case __format_spec::__type::__scientific_lower_case: + return __formatter::__format_buffer_scientific_lower_case(__buffer, __value, __buffer.__precision(), __first); + + case __format_spec::__type::__scientific_upper_case: + return __formatter::__format_buffer_scientific_upper_case(__buffer, __value, __buffer.__precision(), __first); + + case __format_spec::__type::__fixed_lower_case: + case __format_spec::__type::__fixed_upper_case: + return __formatter::__format_buffer_fixed(__buffer, __value, __buffer.__precision(), __first); + + case __format_spec::__type::__general_lower_case: + return __formatter::__format_buffer_general_lower_case(__buffer, __value, __buffer.__precision(), __first); + + case __format_spec::__type::__general_upper_case: + return __formatter::__format_buffer_general_upper_case(__buffer, __value, __buffer.__precision(), __first); + + default: + _LIBCPP_ASSERT_INTERNAL(false, "The parser should have validated the type"); + __libcpp_unreachable(); + } +} + +# ifndef _LIBCPP_HAS_NO_LOCALIZATION +template +_LIBCPP_HIDE_FROM_ABI _OutIt __format_locale_specific_form( + _OutIt __out_it, + const __float_buffer<_Fp>& __buffer, + const __float_result& __result, + std::locale __loc, + __format_spec::__parsed_specifications<_CharT> __specs) { + const auto& __np = std::use_facet>(__loc); + string __grouping = __np.grouping(); + char* __first = __result.__integral; + // When no radix point or exponent are present __last will be __result.__last. + char* __last = std::min(__result.__radix_point, __result.__exponent); + + ptrdiff_t __digits = __last - __first; + if (!__grouping.empty()) { + if (__digits <= __grouping[0]) + __grouping.clear(); + else + __grouping = __formatter::__determine_grouping(__digits, __grouping); + } + + ptrdiff_t __size = + __result.__last - __buffer.begin() + // Formatted string + __buffer.__num_trailing_zeros() + // Not yet rendered zeros + __grouping.size() - // Grouping contains one + !__grouping.empty(); // additional character + + __formatter::__padding_size_result __padding = {0, 0}; + bool __zero_padding = __specs.__alignment_ == __format_spec::__alignment::__zero_padding; + if (__size < __specs.__width_) { + if (__zero_padding) { + __specs.__alignment_ = __format_spec::__alignment::__right; + __specs.__fill_.__data[0] = _CharT('0'); + } + + __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_); + } + + // sign and (zero padding or alignment) + if (__zero_padding && __first != __buffer.begin()) + *__out_it++ = *__buffer.begin(); + __out_it = __formatter::__fill(std::move(__out_it), __padding.__before_, __specs.__fill_); + if (!__zero_padding && __first != __buffer.begin()) + *__out_it++ = *__buffer.begin(); + + // integral part + if (__grouping.empty()) { + __out_it = __formatter::__copy(__first, __digits, std::move(__out_it)); + } else { + auto __r = __grouping.rbegin(); + auto __e = __grouping.rend() - 1; + _CharT __sep = __np.thousands_sep(); + // The output is divided in small groups of numbers to write: + // - A group before the first separator. + // - A separator and a group, repeated for the number of separators. + // - A group after the last separator. + // This loop achieves that process by testing the termination condition + // midway in the loop. + while (true) { + __out_it = __formatter::__copy(__first, *__r, std::move(__out_it)); + __first += *__r; + + if (__r == __e) + break; + + ++__r; + *__out_it++ = __sep; + } + } + + // fractional part + if (__result.__radix_point != __result.__last) { + *__out_it++ = __np.decimal_point(); + __out_it = __formatter::__copy(__result.__radix_point + 1, __result.__exponent, std::move(__out_it)); + __out_it = __formatter::__fill(std::move(__out_it), __buffer.__num_trailing_zeros(), _CharT('0')); + } + + // exponent + if (__result.__exponent != __result.__last) + __out_it = __formatter::__copy(__result.__exponent, __result.__last, std::move(__out_it)); + + // alignment + return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_); +} +# endif // _LIBCPP_HAS_NO_LOCALIZATION + +template +_LIBCPP_HIDE_FROM_ABI _OutIt __format_floating_point_non_finite( + _OutIt __out_it, __format_spec::__parsed_specifications<_CharT> __specs, bool __negative, bool __isnan) { + char __buffer[4]; + char* __last = __formatter::__insert_sign(__buffer, __negative, __specs.__std_.__sign_); + + // to_chars can return inf, infinity, nan, and nan(n-char-sequence). + // The format library requires inf and nan. + // All in one expression to avoid dangling references. + bool __upper_case = + __specs.__std_.__type_ == __format_spec::__type::__hexfloat_upper_case || + __specs.__std_.__type_ == __format_spec::__type::__scientific_upper_case || + __specs.__std_.__type_ == __format_spec::__type::__fixed_upper_case || + __specs.__std_.__type_ == __format_spec::__type::__general_upper_case; + __last = std::copy_n(&("infnanINFNAN"[6 * __upper_case + 3 * __isnan]), 3, __last); + + // [format.string.std]/13 + // A zero (0) character preceding the width field pads the field with + // leading zeros (following any indication of sign or base) to the field + // width, except when applied to an infinity or NaN. + if (__specs.__alignment_ == __format_spec::__alignment::__zero_padding) + __specs.__alignment_ = __format_spec::__alignment::__right; + + return __formatter::__write(__buffer, __last, std::move(__out_it), __specs); +} + +/// Writes additional zero's for the precision before the exponent. +/// This is used when the precision requested in the format string is larger +/// than the maximum precision of the floating-point type. These precision +/// digits are always 0. +/// +/// \param __exponent The location of the exponent character. +/// \param __num_trailing_zeros The number of 0's to write before the exponent +/// character. +template +_LIBCPP_HIDE_FROM_ABI auto __write_using_trailing_zeros( + const _CharT* __first, + const _CharT* __last, + output_iterator auto __out_it, + __format_spec::__parsed_specifications<_ParserCharT> __specs, + size_t __size, + const _CharT* __exponent, + size_t __num_trailing_zeros) -> decltype(__out_it) { + _LIBCPP_ASSERT_INTERNAL(__first <= __last, "Not a valid range"); + _LIBCPP_ASSERT_INTERNAL(__num_trailing_zeros > 0, "The overload not writing trailing zeros should have been used"); + + __padding_size_result __padding = + __formatter::__padding_size(__size + __num_trailing_zeros, __specs.__width_, __specs.__alignment_); + __out_it = __formatter::__fill(std::move(__out_it), __padding.__before_, __specs.__fill_); + __out_it = __formatter::__copy(__first, __exponent, std::move(__out_it)); + __out_it = __formatter::__fill(std::move(__out_it), __num_trailing_zeros, _CharT('0')); + __out_it = __formatter::__copy(__exponent, __last, std::move(__out_it)); + return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_); +} + +template +_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator +__format_floating_point(_Tp __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) { + bool __negative = std::signbit(__value); + + if (!std::isfinite(__value)) [[unlikely]] + return __formatter::__format_floating_point_non_finite(__ctx.out(), __specs, __negative, std::isnan(__value)); + + // Depending on the std-format-spec string the sign and the value + // might not be outputted together: + // - zero-padding may insert additional '0' characters. + // Therefore the value is processed as a non negative value. + // The function @ref __insert_sign will insert a '-' when the value was + // negative. + + if (__negative) + __value = -__value; + + // TODO FMT _Fp should just be _Tp when to_chars has proper long double support. + using _Fp = conditional_t, double, _Tp>; + // Force the type of the precision to avoid -1 to become an unsigned value. + __float_buffer<_Fp> __buffer(__specs.__precision_); + __float_result __result = __formatter::__format_buffer( + __buffer, __value, __negative, (__specs.__has_precision()), __specs.__std_.__sign_, __specs.__std_.__type_); + + if (__specs.__std_.__alternate_form_) { + if (__result.__radix_point == __result.__last) { + *__result.__last++ = '.'; + + // When there is an exponent the point needs to be moved before the + // exponent. When there's no exponent the rotate does nothing. Since + // rotate tests whether the operation is a nop, call it unconditionally. + std::rotate(__result.__exponent, __result.__last - 1, __result.__last); + __result.__radix_point = __result.__exponent; + + // The radix point is always placed before the exponent. + // - No exponent needs to point to the new last. + // - An exponent needs to move one position to the right. + // So it's safe to increment the value unconditionally. + ++__result.__exponent; + } + + // [format.string.std]/6 + // In addition, for g and G conversions, trailing zeros are not removed + // from the result. + // + // If the type option for a floating-point type is none it may use the + // general formatting, but it's not a g or G conversion. So in that case + // the formatting should not append trailing zeros. + bool __is_general = __specs.__std_.__type_ == __format_spec::__type::__general_lower_case || + __specs.__std_.__type_ == __format_spec::__type::__general_upper_case; + + if (__is_general) { + // https://en.cppreference.com/w/c/io/fprintf + // Let P equal the precision if nonzero, 6 if the precision is not + // specified, or 1 if the precision is 0. Then, if a conversion with + // style E would have an exponent of X: + int __p = std::max(1, (__specs.__has_precision() ? __specs.__precision_ : 6)); + if (__result.__exponent == __result.__last) + // if P > X >= -4, the conversion is with style f or F and precision P - 1 - X. + // By including the radix point it calculates P - (1 + X) + __p -= __result.__radix_point - __result.__integral; + else + // otherwise, the conversion is with style e or E and precision P - 1. + --__p; + + ptrdiff_t __precision = (__result.__exponent - __result.__radix_point) - 1; + if (__precision < __p) + __buffer.__add_trailing_zeros(__p - __precision); + } + } + +# ifndef _LIBCPP_HAS_NO_LOCALIZATION + if (__specs.__std_.__locale_specific_form_) + return __formatter::__format_locale_specific_form(__ctx.out(), __buffer, __result, __ctx.locale(), __specs); +# endif + + ptrdiff_t __size = __result.__last - __buffer.begin(); + int __num_trailing_zeros = __buffer.__num_trailing_zeros(); + if (__size + __num_trailing_zeros >= __specs.__width_) { + if (__num_trailing_zeros && __result.__exponent != __result.__last) + // Insert trailing zeros before exponent character. + return __formatter::__copy( + __result.__exponent, + __result.__last, + __formatter::__fill(__formatter::__copy(__buffer.begin(), __result.__exponent, __ctx.out()), + __num_trailing_zeros, + _CharT('0'))); + + return __formatter::__fill( + __formatter::__copy(__buffer.begin(), __result.__last, __ctx.out()), __num_trailing_zeros, _CharT('0')); + } + + auto __out_it = __ctx.out(); + char* __first = __buffer.begin(); + if (__specs.__alignment_ == __format_spec::__alignment ::__zero_padding) { + // When there is a sign output it before the padding. Note the __size + // doesn't need any adjustment, regardless whether the sign is written + // here or in __formatter::__write. + if (__first != __result.__integral) + *__out_it++ = *__first++; + // After the sign is written, zero padding is the same a right alignment + // with '0'. + __specs.__alignment_ = __format_spec::__alignment::__right; + __specs.__fill_.__data[0] = _CharT('0'); + } + + if (__num_trailing_zeros) + return __formatter::__write_using_trailing_zeros( + __first, __result.__last, std::move(__out_it), __specs, __size, __result.__exponent, __num_trailing_zeros); + + return __formatter::__write(__first, __result.__last, std::move(__out_it), __specs, __size); +} + +} // namespace __formatter + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS __formatter_floating_point { +public: + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_floating_point); + __format_spec::__process_parsed_floating_point(__parser_, "a floating-point"); + return __result; + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_Tp __value, _FormatContext& __ctx) const { + return __formatter::__format_floating_point(__value, __ctx, __parser_.__get_parsed_std_specifications(__ctx)); + } + + __format_spec::__parser<_CharT> __parser_; +}; + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_floating_point<_CharT> {}; +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_floating_point<_CharT> {}; +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_floating_point<_CharT> {}; + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_FORMATTER_FLOATING_POINT_H diff --git a/libcxx/include/__cxx03/__format/formatter_integer.h b/libcxx/include/__cxx03/__format/formatter_integer.h new file mode 100644 index 0000000000000000000000000000000000000000..41400f00478eb474a31105a7e0a0c7301fbc7e11 --- /dev/null +++ b/libcxx/include/__cxx03/__format/formatter_integer.h @@ -0,0 +1,95 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMATTER_INTEGER_H +#define _LIBCPP___FORMAT_FORMATTER_INTEGER_H + +#include <__concepts/arithmetic.h> +#include <__config> +#include <__format/concepts.h> +#include <__format/format_parse_context.h> +#include <__format/formatter.h> +#include <__format/formatter_integral.h> +#include <__format/formatter_output.h> +#include <__format/parser_std_format_spec.h> +#include <__type_traits/is_void.h> +#include <__type_traits/make_32_64_or_128_bit.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS __formatter_integer { +public: + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_integral); + __format_spec::__process_parsed_integer(__parser_, "an integer"); + return __result; + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_Tp __value, _FormatContext& __ctx) const { + __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx); + + if (__specs.__std_.__type_ == __format_spec::__type::__char) + return __formatter::__format_char(__value, __ctx.out(), __specs); + + using _Type = __make_32_64_or_128_bit_t<_Tp>; + static_assert(!is_void<_Type>::value, "unsupported integral type used in __formatter_integer::__format"); + + // Reduce the number of instantiation of the integer formatter + return __formatter::__format_integer(static_cast<_Type>(__value), __ctx, __specs); + } + + __format_spec::__parser<_CharT> __parser_; +}; + +// Signed integral types. +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_integer<_CharT> {}; +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_integer<_CharT> {}; +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_integer<_CharT> {}; +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_integer<_CharT> {}; +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_integer<_CharT> {}; +# ifndef _LIBCPP_HAS_NO_INT128 +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter<__int128_t, _CharT> : public __formatter_integer<_CharT> {}; +# endif + +// Unsigned integral types. +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_integer<_CharT> {}; +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_integer<_CharT> {}; +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_integer<_CharT> {}; +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_integer<_CharT> {}; +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_integer<_CharT> {}; +# ifndef _LIBCPP_HAS_NO_INT128 +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter<__uint128_t, _CharT> : public __formatter_integer<_CharT> {}; +# endif + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMATTER_INTEGER_H diff --git a/libcxx/include/__cxx03/__format/formatter_integral.h b/libcxx/include/__cxx03/__format/formatter_integral.h new file mode 100644 index 0000000000000000000000000000000000000000..eca966f8886f8405a0a95197e73074d50c61075d --- /dev/null +++ b/libcxx/include/__cxx03/__format/formatter_integral.h @@ -0,0 +1,445 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMATTER_INTEGRAL_H +#define _LIBCPP___FORMAT_FORMATTER_INTEGRAL_H + +#include <__charconv/to_chars_integral.h> +#include <__charconv/to_chars_result.h> +#include <__charconv/traits.h> +#include <__concepts/arithmetic.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__format/concepts.h> +#include <__format/format_error.h> +#include <__format/formatter_output.h> +#include <__format/parser_std_format_spec.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__memory/pointer_traits.h> +#include <__system_error/errc.h> +#include <__type_traits/make_unsigned.h> +#include <__utility/unreachable.h> +#include +#include +#include +#include + +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include <__locale> +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __formatter { + +// +// Generic +// + +template + requires same_as> +_LIBCPP_HIDE_FROM_ABI inline _Iterator __insert_sign(_Iterator __buf, bool __negative, __format_spec::__sign __sign) { + if (__negative) + *__buf++ = '-'; + else + switch (__sign) { + case __format_spec::__sign::__default: + case __format_spec::__sign::__minus: + // No sign added. + break; + case __format_spec::__sign::__plus: + *__buf++ = '+'; + break; + case __format_spec::__sign::__space: + *__buf++ = ' '; + break; + } + + return __buf; +} + +/** + * Determines the required grouping based on the size of the input. + * + * The grouping's last element will be repeated. For simplicity this repeating + * is unwrapped based on the length of the input. (When the input is short some + * groups are not processed.) + * + * @returns The size of the groups to write. This means the number of + * separator characters written is size() - 1. + * + * @note Since zero-sized groups cause issues they are silently ignored. + * + * @note The grouping field of the locale is always a @c std::string, + * regardless whether the @c std::numpunct's type is @c char or @c wchar_t. + */ +_LIBCPP_HIDE_FROM_ABI inline string __determine_grouping(ptrdiff_t __size, const string& __grouping) { + _LIBCPP_ASSERT_INTERNAL(!__grouping.empty() && __size > __grouping[0], + "The slow grouping formatting is used while there will be no separators written"); + string __r; + auto __end = __grouping.end() - 1; + auto __ptr = __grouping.begin(); + + while (true) { + __size -= *__ptr; + if (__size > 0) + __r.push_back(*__ptr); + else { + // __size <= 0 so the value pushed will be <= *__ptr. + __r.push_back(*__ptr + __size); + return __r; + } + + // Proceed to the next group. + if (__ptr != __end) { + do { + ++__ptr; + // Skip grouping with a width of 0. + } while (*__ptr == 0 && __ptr != __end); + } + } + + __libcpp_unreachable(); +} + +// +// Char +// + +template <__fmt_char_type _CharT> +_LIBCPP_HIDE_FROM_ABI auto +__format_char(integral auto __value, + output_iterator auto __out_it, + __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { + using _Tp = decltype(__value); + if constexpr (!same_as<_CharT, _Tp>) { + // cmp_less and cmp_greater can't be used for character types. + if constexpr (signed_integral<_CharT> == signed_integral<_Tp>) { + if (__value < numeric_limits<_CharT>::min() || __value > numeric_limits<_CharT>::max()) + std::__throw_format_error("Integral value outside the range of the char type"); + } else if constexpr (signed_integral<_CharT>) { + // _CharT is signed _Tp is unsigned + if (__value > static_cast>(numeric_limits<_CharT>::max())) + std::__throw_format_error("Integral value outside the range of the char type"); + } else { + // _CharT is unsigned _Tp is signed + if (__value < 0 || static_cast>(__value) > numeric_limits<_CharT>::max()) + std::__throw_format_error("Integral value outside the range of the char type"); + } + } + + const auto __c = static_cast<_CharT>(__value); + return __formatter::__write(std::addressof(__c), std::addressof(__c) + 1, std::move(__out_it), __specs); +} + +// +// Integer +// + +/** Wrapper around @ref to_chars, returning the output iterator. */ +template + requires same_as> +_LIBCPP_HIDE_FROM_ABI _Iterator __to_buffer(_Iterator __first, _Iterator __last, _Tp __value, int __base) { + // TODO FMT Evaluate code overhead due to not calling the internal function + // directly. (Should be zero overhead.) + to_chars_result __r = std::to_chars(std::to_address(__first), std::to_address(__last), __value, __base); + _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small"); + auto __diff = __r.ptr - std::to_address(__first); + return __first + __diff; +} + +/** + * Helper to determine the buffer size to output a integer in Base @em x. + * + * There are several overloads for the supported bases. The function uses the + * base as template argument so it can be used in a constant expression. + */ +template +consteval size_t __buffer_size() noexcept + requires(_Base == 2) +{ + return numeric_limits<_Tp>::digits // The number of binary digits. + + 2 // Reserve space for the '0[Bb]' prefix. + + 1; // Reserve space for the sign. +} + +template +consteval size_t __buffer_size() noexcept + requires(_Base == 8) +{ + return numeric_limits<_Tp>::digits // The number of binary digits. + / 3 // Adjust to octal. + + 1 // Turn floor to ceil. + + 1 // Reserve space for the '0' prefix. + + 1; // Reserve space for the sign. +} + +template +consteval size_t __buffer_size() noexcept + requires(_Base == 10) +{ + return numeric_limits<_Tp>::digits10 // The floored value. + + 1 // Turn floor to ceil. + + 1; // Reserve space for the sign. +} + +template +consteval size_t __buffer_size() noexcept + requires(_Base == 16) +{ + return numeric_limits<_Tp>::digits // The number of binary digits. + / 4 // Adjust to hexadecimal. + + 2 // Reserve space for the '0[Xx]' prefix. + + 1; // Reserve space for the sign. +} + +template + requires same_as> +_LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators( + _OutIt __out_it, + _Iterator __begin, + _Iterator __first, + _Iterator __last, + string&& __grouping, + _CharT __sep, + __format_spec::__parsed_specifications<_CharT> __specs) { + int __size = (__first - __begin) + // [sign][prefix] + (__last - __first) + // data + (__grouping.size() - 1); // number of separator characters + + __padding_size_result __padding = {0, 0}; + if (__specs.__alignment_ == __format_spec::__alignment::__zero_padding) { + // Write [sign][prefix]. + __out_it = __formatter::__copy(__begin, __first, std::move(__out_it)); + + if (__specs.__width_ > __size) { + // Write zero padding. + __padding.__before_ = __specs.__width_ - __size; + __out_it = __formatter::__fill(std::move(__out_it), __specs.__width_ - __size, _CharT('0')); + } + } else { + if (__specs.__width_ > __size) { + // Determine padding and write padding. + __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_); + + __out_it = __formatter::__fill(std::move(__out_it), __padding.__before_, __specs.__fill_); + } + // Write [sign][prefix]. + __out_it = __formatter::__copy(__begin, __first, std::move(__out_it)); + } + + auto __r = __grouping.rbegin(); + auto __e = __grouping.rend() - 1; + _LIBCPP_ASSERT_INTERNAL( + __r != __e, "The slow grouping formatting is used while there will be no separators written."); + // The output is divided in small groups of numbers to write: + // - A group before the first separator. + // - A separator and a group, repeated for the number of separators. + // - A group after the last separator. + // This loop achieves that process by testing the termination condition + // midway in the loop. + // + // TODO FMT This loop evaluates the loop invariant `__parser.__type != + // _Flags::_Type::__hexadecimal_upper_case` for every iteration. (This test + // happens in the __write call.) Benchmark whether making two loops and + // hoisting the invariant is worth the effort. + while (true) { + if (__specs.__std_.__type_ == __format_spec::__type::__hexadecimal_upper_case) { + __last = __first + *__r; + __out_it = __formatter::__transform(__first, __last, std::move(__out_it), __hex_to_upper); + __first = __last; + } else { + __out_it = __formatter::__copy(__first, *__r, std::move(__out_it)); + __first += *__r; + } + + if (__r == __e) + break; + + ++__r; + *__out_it++ = __sep; + } + + return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_); +} + +template + requires same_as> +_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator __format_integer( + _Tp __value, + _FormatContext& __ctx, + __format_spec::__parsed_specifications<_CharT> __specs, + bool __negative, + _Iterator __begin, + _Iterator __end, + const char* __prefix, + int __base) { + _Iterator __first = __formatter::__insert_sign(__begin, __negative, __specs.__std_.__sign_); + if (__specs.__std_.__alternate_form_ && __prefix) + while (*__prefix) + *__first++ = *__prefix++; + + _Iterator __last = __formatter::__to_buffer(__first, __end, __value, __base); + +# ifndef _LIBCPP_HAS_NO_LOCALIZATION + if (__specs.__std_.__locale_specific_form_) { + const auto& __np = std::use_facet>(__ctx.locale()); + string __grouping = __np.grouping(); + ptrdiff_t __size = __last - __first; + // Writing the grouped form has more overhead than the normal output + // routines. If there will be no separators written the locale-specific + // form is identical to the normal routine. Test whether to grouped form + // is required. + if (!__grouping.empty() && __size > __grouping[0]) + return __formatter::__write_using_decimal_separators( + __ctx.out(), + __begin, + __first, + __last, + __formatter::__determine_grouping(__size, __grouping), + __np.thousands_sep(), + __specs); + } +# endif + auto __out_it = __ctx.out(); + if (__specs.__alignment_ != __format_spec::__alignment::__zero_padding) + __first = __begin; + else { + // __buf contains [sign][prefix]data + // ^ location of __first + // The zero padding is done like: + // - Write [sign][prefix] + // - Write data right aligned with '0' as fill character. + __out_it = __formatter::__copy(__begin, __first, std::move(__out_it)); + __specs.__alignment_ = __format_spec::__alignment::__right; + __specs.__fill_.__data[0] = _CharT('0'); + int32_t __size = __first - __begin; + + __specs.__width_ -= std::min(__size, __specs.__width_); + } + + if (__specs.__std_.__type_ != __format_spec::__type::__hexadecimal_upper_case) [[likely]] + return __formatter::__write(__first, __last, __ctx.out(), __specs); + + return __formatter::__write_transformed(__first, __last, __ctx.out(), __specs, __formatter::__hex_to_upper); +} + +template +_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator +__format_integer(_Tp __value, + _FormatContext& __ctx, + __format_spec::__parsed_specifications<_CharT> __specs, + bool __negative = false) { + switch (__specs.__std_.__type_) { + case __format_spec::__type::__binary_lower_case: { + array()> __array; + return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0b", 2); + } + case __format_spec::__type::__binary_upper_case: { + array()> __array; + return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0B", 2); + } + case __format_spec::__type::__octal: { + // Octal is special; if __value == 0 there's no prefix. + array()> __array; + return __formatter::__format_integer( + __value, __ctx, __specs, __negative, __array.begin(), __array.end(), __value != 0 ? "0" : nullptr, 8); + } + case __format_spec::__type::__default: + case __format_spec::__type::__decimal: { + array()> __array; + return __formatter::__format_integer( + __value, __ctx, __specs, __negative, __array.begin(), __array.end(), nullptr, 10); + } + case __format_spec::__type::__hexadecimal_lower_case: { + array()> __array; + return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0x", 16); + } + case __format_spec::__type::__hexadecimal_upper_case: { + array()> __array; + return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0X", 16); + } + default: + _LIBCPP_ASSERT_INTERNAL(false, "The parse function should have validated the type"); + __libcpp_unreachable(); + } +} + +template +_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator +__format_integer(_Tp __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) { + // Depending on the std-format-spec string the sign and the value + // might not be outputted together: + // - alternate form may insert a prefix string. + // - zero-padding may insert additional '0' characters. + // Therefore the value is processed as a positive unsigned value. + // The function @ref __insert_sign will a '-' when the value was negative. + auto __r = std::__to_unsigned_like(__value); + bool __negative = __value < 0; + if (__negative) + __r = std::__complement(__r); + + return __formatter::__format_integer(__r, __ctx, __specs, __negative); +} + +// +// Formatter arithmetic (bool) +// + +template +struct _LIBCPP_TEMPLATE_VIS __bool_strings; + +template <> +struct _LIBCPP_TEMPLATE_VIS __bool_strings { + static constexpr string_view __true{"true"}; + static constexpr string_view __false{"false"}; +}; + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <> +struct _LIBCPP_TEMPLATE_VIS __bool_strings { + static constexpr wstring_view __true{L"true"}; + static constexpr wstring_view __false{L"false"}; +}; +# endif + +template +_LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator +__format_bool(bool __value, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) { +# ifndef _LIBCPP_HAS_NO_LOCALIZATION + if (__specs.__std_.__locale_specific_form_) { + const auto& __np = std::use_facet>(__ctx.locale()); + basic_string<_CharT> __str = __value ? __np.truename() : __np.falsename(); + return __formatter::__write_string_no_precision(basic_string_view<_CharT>{__str}, __ctx.out(), __specs); + } +# endif + basic_string_view<_CharT> __str = + __value ? __formatter::__bool_strings<_CharT>::__true : __formatter::__bool_strings<_CharT>::__false; + return __formatter::__write(__str.begin(), __str.end(), __ctx.out(), __specs); +} + +} // namespace __formatter + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_FORMATTER_INTEGRAL_H diff --git a/libcxx/include/__cxx03/__format/formatter_output.h b/libcxx/include/__cxx03/__format/formatter_output.h new file mode 100644 index 0000000000000000000000000000000000000000..1498f64c4aeff7dda70f84d5386e5cb31a3391d4 --- /dev/null +++ b/libcxx/include/__cxx03/__format/formatter_output.h @@ -0,0 +1,335 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMATTER_OUTPUT_H +#define _LIBCPP___FORMAT_FORMATTER_OUTPUT_H + +#include <__algorithm/ranges_copy.h> +#include <__algorithm/ranges_fill_n.h> +#include <__algorithm/ranges_transform.h> +#include <__bit/countl.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__format/buffer.h> +#include <__format/concepts.h> +#include <__format/formatter.h> +#include <__format/parser_std_format_spec.h> +#include <__format/unicode.h> +#include <__iterator/back_insert_iterator.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__memory/addressof.h> +#include <__memory/pointer_traits.h> +#include <__utility/move.h> +#include <__utility/unreachable.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __formatter { + +_LIBCPP_HIDE_FROM_ABI constexpr char __hex_to_upper(char __c) { + switch (__c) { + case 'a': + return 'A'; + case 'b': + return 'B'; + case 'c': + return 'C'; + case 'd': + return 'D'; + case 'e': + return 'E'; + case 'f': + return 'F'; + } + return __c; +} + +struct _LIBCPP_EXPORTED_FROM_ABI __padding_size_result { + size_t __before_; + size_t __after_; +}; + +_LIBCPP_HIDE_FROM_ABI constexpr __padding_size_result +__padding_size(size_t __size, size_t __width, __format_spec::__alignment __align) { + _LIBCPP_ASSERT_INTERNAL(__width > __size, "don't call this function when no padding is required"); + _LIBCPP_ASSERT_INTERNAL( + __align != __format_spec::__alignment::__zero_padding, "the caller should have handled the zero-padding"); + + size_t __fill = __width - __size; + switch (__align) { + case __format_spec::__alignment::__zero_padding: + __libcpp_unreachable(); + + case __format_spec::__alignment::__left: + return {0, __fill}; + + case __format_spec::__alignment::__center: { + // The extra padding is divided per [format.string.std]/3 + // __before = floor(__fill, 2); + // __after = ceil(__fill, 2); + size_t __before = __fill / 2; + size_t __after = __fill - __before; + return {__before, __after}; + } + case __format_spec::__alignment::__default: + case __format_spec::__alignment::__right: + return {__fill, 0}; + } + __libcpp_unreachable(); +} + +/// Copy wrapper. +/// +/// This uses a "mass output function" of __format::__output_buffer when possible. +template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT> +_LIBCPP_HIDE_FROM_ABI auto +__copy(basic_string_view<_CharT> __str, output_iterator auto __out_it) -> decltype(__out_it) { + if constexpr (std::same_as>>) { + __out_it.__get_container()->__copy(__str); + return __out_it; + } else if constexpr (std::same_as::__iterator>) { + __out_it.__buffer_->__copy(__str); + return __out_it; + } else { + return std::ranges::copy(__str, std::move(__out_it)).out; + } +} + +template ::value_type, + __fmt_char_type _OutCharT = _CharT> +_LIBCPP_HIDE_FROM_ABI auto +__copy(_Iterator __first, _Iterator __last, output_iterator auto __out_it) -> decltype(__out_it) { + return __formatter::__copy(basic_string_view{__first, __last}, std::move(__out_it)); +} + +template ::value_type, + __fmt_char_type _OutCharT = _CharT> +_LIBCPP_HIDE_FROM_ABI auto +__copy(_Iterator __first, size_t __n, output_iterator auto __out_it) -> decltype(__out_it) { + return __formatter::__copy(basic_string_view{std::to_address(__first), __n}, std::move(__out_it)); +} + +/// Transform wrapper. +/// +/// This uses a "mass output function" of __format::__output_buffer when possible. +template ::value_type, + __fmt_char_type _OutCharT = _CharT, + class _UnaryOperation> +_LIBCPP_HIDE_FROM_ABI auto +__transform(_Iterator __first, + _Iterator __last, + output_iterator auto __out_it, + _UnaryOperation __operation) -> decltype(__out_it) { + if constexpr (std::same_as>>) { + __out_it.__get_container()->__transform(__first, __last, std::move(__operation)); + return __out_it; + } else if constexpr (std::same_as::__iterator>) { + __out_it.__buffer_->__transform(__first, __last, std::move(__operation)); + return __out_it; + } else { + return std::ranges::transform(__first, __last, std::move(__out_it), __operation).out; + } +} + +/// Fill wrapper. +/// +/// This uses a "mass output function" of __format::__output_buffer when possible. +template <__fmt_char_type _CharT, output_iterator _OutIt> +_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, _CharT __value) { + if constexpr (std::same_as>>) { + __out_it.__get_container()->__fill(__n, __value); + return __out_it; + } else if constexpr (std::same_as::__iterator>) { + __out_it.__buffer_->__fill(__n, __value); + return __out_it; + } else { + return std::ranges::fill_n(std::move(__out_it), __n, __value); + } +} + +# ifndef _LIBCPP_HAS_NO_UNICODE +template <__fmt_char_type _CharT, output_iterator _OutIt> + requires(same_as<_CharT, char>) +_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { + std::size_t __bytes = std::countl_one(static_cast(__value.__data[0])); + if (__bytes == 0) + return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); + + for (size_t __i = 0; __i < __n; ++__i) + __out_it = __formatter::__copy( + std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + __bytes, std::move(__out_it)); + return __out_it; +} + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <__fmt_char_type _CharT, output_iterator _OutIt> + requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 2) +_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { + if (!__unicode::__is_high_surrogate(__value.__data[0])) + return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); + + for (size_t __i = 0; __i < __n; ++__i) + __out_it = __formatter::__copy( + std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + 2, std::move(__out_it)); + return __out_it; +} + +template <__fmt_char_type _CharT, output_iterator _OutIt> + requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 4) +_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { + return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); +} +# endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS +# else // _LIBCPP_HAS_NO_UNICODE +template <__fmt_char_type _CharT, output_iterator _OutIt> +_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { + return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); +} +# endif // _LIBCPP_HAS_NO_UNICODE + +/// Writes the input to the output with the required padding. +/// +/// Since the output column width is specified the function can be used for +/// ASCII and Unicode output. +/// +/// \pre \a __size <= \a __width. Using this function when this pre-condition +/// doesn't hold incurs an unwanted overhead. +/// +/// \param __str The string to write. +/// \param __out_it The output iterator to write to. +/// \param __specs The parsed formatting specifications. +/// \param __size The (estimated) output column width. When the elements +/// to be written are ASCII the following condition holds +/// \a __size == \a __last - \a __first. +/// +/// \returns An iterator pointing beyond the last element written. +/// +/// \note The type of the elements in range [\a __first, \a __last) can differ +/// from the type of \a __specs. Integer output uses \c std::to_chars for its +/// conversion, which means the [\a __first, \a __last) always contains elements +/// of the type \c char. +template +_LIBCPP_HIDE_FROM_ABI auto +__write(basic_string_view<_CharT> __str, + output_iterator auto __out_it, + __format_spec::__parsed_specifications<_ParserCharT> __specs, + ptrdiff_t __size) -> decltype(__out_it) { + if (__size >= __specs.__width_) + return __formatter::__copy(__str, std::move(__out_it)); + + __padding_size_result __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__std_.__alignment_); + __out_it = __formatter::__fill(std::move(__out_it), __padding.__before_, __specs.__fill_); + __out_it = __formatter::__copy(__str, std::move(__out_it)); + return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_); +} + +template +_LIBCPP_HIDE_FROM_ABI auto +__write(_Iterator __first, + _Iterator __last, + output_iterator&> auto __out_it, + __format_spec::__parsed_specifications<_ParserCharT> __specs, + ptrdiff_t __size) -> decltype(__out_it) { + _LIBCPP_ASSERT_VALID_INPUT_RANGE(__first <= __last, "Not a valid range"); + return __formatter::__write(basic_string_view{__first, __last}, std::move(__out_it), __specs, __size); +} + +/// \overload +/// +/// Calls the function above where \a __size = \a __last - \a __first. +template +_LIBCPP_HIDE_FROM_ABI auto +__write(_Iterator __first, + _Iterator __last, + output_iterator&> auto __out_it, + __format_spec::__parsed_specifications<_ParserCharT> __specs) -> decltype(__out_it) { + _LIBCPP_ASSERT_VALID_INPUT_RANGE(__first <= __last, "Not a valid range"); + return __formatter::__write(__first, __last, std::move(__out_it), __specs, __last - __first); +} + +template ::value_type, + class _ParserCharT, + class _UnaryOperation> +_LIBCPP_HIDE_FROM_ABI auto __write_transformed( + _Iterator __first, + _Iterator __last, + output_iterator auto __out_it, + __format_spec::__parsed_specifications<_ParserCharT> __specs, + _UnaryOperation __op) -> decltype(__out_it) { + _LIBCPP_ASSERT_VALID_INPUT_RANGE(__first <= __last, "Not a valid range"); + + ptrdiff_t __size = __last - __first; + if (__size >= __specs.__width_) + return __formatter::__transform(__first, __last, std::move(__out_it), __op); + + __padding_size_result __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_); + __out_it = __formatter::__fill(std::move(__out_it), __padding.__before_, __specs.__fill_); + __out_it = __formatter::__transform(__first, __last, std::move(__out_it), __op); + return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_); +} + +/// Writes a string using format's width estimation algorithm. +/// +/// \pre !__specs.__has_precision() +/// +/// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the +/// input is ASCII. +template +_LIBCPP_HIDE_FROM_ABI auto __write_string_no_precision( + basic_string_view<_CharT> __str, + output_iterator auto __out_it, + __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { + _LIBCPP_ASSERT_INTERNAL(!__specs.__has_precision(), "use __write_string"); + + // No padding -> copy the string + if (!__specs.__has_width()) + return __formatter::__copy(__str, std::move(__out_it)); + + // Note when the estimated width is larger than size there's no padding. So + // there's no reason to get the real size when the estimate is larger than or + // equal to the minimum field width. + size_t __size = + __format_spec::__estimate_column_width(__str, __specs.__width_, __format_spec::__column_width_rounding::__up) + .__width_; + return __formatter::__write(__str, std::move(__out_it), __specs, __size); +} + +template +_LIBCPP_HIDE_FROM_ABI int __truncate(basic_string_view<_CharT>& __str, int __precision) { + __format_spec::__column_width_result __result = + __format_spec::__estimate_column_width(__str, __precision, __format_spec::__column_width_rounding::__down); + __str = basic_string_view<_CharT>{__str.begin(), __result.__last_}; + return __result.__width_; +} + +} // namespace __formatter + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_FORMATTER_OUTPUT_H diff --git a/libcxx/include/__cxx03/__format/formatter_pointer.h b/libcxx/include/__cxx03/__format/formatter_pointer.h new file mode 100644 index 0000000000000000000000000000000000000000..6941343efd91f99b87338159e1bbeed89082f5e1 --- /dev/null +++ b/libcxx/include/__cxx03/__format/formatter_pointer.h @@ -0,0 +1,72 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMATTER_POINTER_H +#define _LIBCPP___FORMAT_FORMATTER_POINTER_H + +#include <__config> +#include <__format/concepts.h> +#include <__format/format_parse_context.h> +#include <__format/formatter.h> +#include <__format/formatter_integral.h> +#include <__format/formatter_output.h> +#include <__format/parser_std_format_spec.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS __formatter_pointer { +public: + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_pointer); + __format_spec::__process_display_type_pointer(__parser_.__type_, "a pointer"); + return __result; + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const void* __ptr, _FormatContext& __ctx) const { + __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx); + __specs.__std_.__alternate_form_ = true; + __specs.__std_.__type_ = + __specs.__std_.__type_ == __format_spec::__type::__pointer_upper_case + ? __format_spec::__type::__hexadecimal_upper_case + : __format_spec::__type::__hexadecimal_lower_case; + + return __formatter::__format_integer(reinterpret_cast(__ptr), __ctx, __specs); + } + + __format_spec::__parser<_CharT> __parser_; +}; + +// [format.formatter.spec]/2.4 +// For each charT, the pointer type specializations template<> +// - struct formatter; +// - template<> struct formatter; +// - template<> struct formatter; +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_pointer<_CharT> {}; +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_pointer<_CharT> {}; +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_pointer<_CharT> {}; + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMATTER_POINTER_H diff --git a/libcxx/include/__cxx03/__format/formatter_string.h b/libcxx/include/__cxx03/__format/formatter_string.h new file mode 100644 index 0000000000000000000000000000000000000000..347439fc8dff13253f0b6adbab741b6b5e416209 --- /dev/null +++ b/libcxx/include/__cxx03/__format/formatter_string.h @@ -0,0 +1,150 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMATTER_STRING_H +#define _LIBCPP___FORMAT_FORMATTER_STRING_H + +#include <__config> +#include <__format/concepts.h> +#include <__format/format_parse_context.h> +#include <__format/formatter.h> +#include <__format/formatter_output.h> +#include <__format/parser_std_format_spec.h> +#include <__format/write_escaped.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS __formatter_string { +public: + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_string); + __format_spec::__process_display_type_string(__parser_.__type_); + return __result; + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator + format(basic_string_view<_CharT> __str, _FormatContext& __ctx) const { +# if _LIBCPP_STD_VER >= 23 + if (__parser_.__type_ == __format_spec::__type::__debug) + return __formatter::__format_escaped_string(__str, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx)); +# endif + + return __formatter::__write_string(__str, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx)); + } + +# if _LIBCPP_STD_VER >= 23 + _LIBCPP_HIDE_FROM_ABI constexpr void set_debug_format() { __parser_.__type_ = __format_spec::__type::__debug; } +# endif + + __format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__left}; +}; + +// Formatter const char*. +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_string<_CharT> { + using _Base = __formatter_string<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const _CharT* __str, _FormatContext& __ctx) const { + _LIBCPP_ASSERT_INTERNAL(__str, "The basic_format_arg constructor should have prevented an invalid pointer."); + + __format_spec::__parsed_specifications<_CharT> __specs = _Base::__parser_.__get_parsed_std_specifications(__ctx); +# if _LIBCPP_STD_VER >= 23 + if (_Base::__parser_.__type_ == __format_spec::__type::__debug) + return __formatter::__format_escaped_string(basic_string_view<_CharT>{__str}, __ctx.out(), __specs); +# endif + + // When using a center or right alignment and the width option the length + // of __str must be known to add the padding upfront. This case is handled + // by the base class by converting the argument to a basic_string_view. + // + // When using left alignment and the width option the padding is added + // after outputting __str so the length can be determined while outputting + // __str. The same holds true for the precision, during outputting __str it + // can be validated whether the precision threshold has been reached. For + // now these optimizations aren't implemented. Instead the base class + // handles these options. + // TODO FMT Implement these improvements. + if (__specs.__has_width() || __specs.__has_precision()) + return __formatter::__write_string(basic_string_view<_CharT>{__str}, __ctx.out(), __specs); + + // No formatting required, copy the string to the output. + auto __out_it = __ctx.out(); + while (*__str) + *__out_it++ = *__str++; + return __out_it; + } +}; + +// Formatter char*. +template <__fmt_char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS formatter<_CharT*, _CharT> : public formatter { + using _Base = formatter; + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_CharT* __str, _FormatContext& __ctx) const { + return _Base::format(__str, __ctx); + } +}; + +// Formatter char[]. +template <__fmt_char_type _CharT, size_t _Size> +struct _LIBCPP_TEMPLATE_VIS formatter<_CharT[_Size], _CharT> : public __formatter_string<_CharT> { + using _Base = __formatter_string<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator + format(const _CharT (&__str)[_Size], _FormatContext& __ctx) const { + return _Base::format(basic_string_view<_CharT>(__str, _Size), __ctx); + } +}; + +// Formatter std::string. +template <__fmt_char_type _CharT, class _Traits, class _Allocator> +struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> + : public __formatter_string<_CharT> { + using _Base = __formatter_string<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator + format(const basic_string<_CharT, _Traits, _Allocator>& __str, _FormatContext& __ctx) const { + // Drop _Traits and _Allocator to have one std::basic_string formatter. + return _Base::format(basic_string_view<_CharT>(__str.data(), __str.size()), __ctx); + } +}; + +// Formatter std::string_view. +template <__fmt_char_type _CharT, class _Traits> +struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> : public __formatter_string<_CharT> { + using _Base = __formatter_string<_CharT>; + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator + format(basic_string_view<_CharT, _Traits> __str, _FormatContext& __ctx) const { + // Drop _Traits to have one std::basic_string_view formatter. + return _Base::format(basic_string_view<_CharT>(__str.data(), __str.size()), __ctx); + } +}; + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMATTER_STRING_H diff --git a/libcxx/include/__cxx03/__format/formatter_tuple.h b/libcxx/include/__cxx03/__format/formatter_tuple.h new file mode 100644 index 0000000000000000000000000000000000000000..030097a8797daeb49a4b58457f83a1c0679f46d3 --- /dev/null +++ b/libcxx/include/__cxx03/__format/formatter_tuple.h @@ -0,0 +1,150 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_FORMATTER_TUPLE_H +#define _LIBCPP___FORMAT_FORMATTER_TUPLE_H + +#include <__algorithm/ranges_copy.h> +#include <__chrono/statically_widen.h> +#include <__config> +#include <__format/buffer.h> +#include <__format/concepts.h> +#include <__format/format_context.h> +#include <__format/format_error.h> +#include <__format/format_parse_context.h> +#include <__format/formatter.h> +#include <__format/formatter_output.h> +#include <__format/parser_std_format_spec.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/integer_sequence.h> +#include <__utility/pair.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template <__fmt_char_type _CharT, class _Tuple, formattable<_CharT>... _Args> +struct _LIBCPP_TEMPLATE_VIS __formatter_tuple { + _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept { + __separator_ = __separator; + } + _LIBCPP_HIDE_FROM_ABI constexpr void + set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept { + __opening_bracket_ = __opening_bracket; + __closing_bracket_ = __closing_bracket; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + auto __begin = __parser_.__parse(__ctx, __format_spec::__fields_tuple); + + auto __end = __ctx.end(); + // Note 'n' is part of the type here + if (__parser_.__clear_brackets_) + set_brackets({}, {}); + else if (__begin != __end && *__begin == _CharT('m')) { + if constexpr (sizeof...(_Args) == 2) { + set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": ")); + set_brackets({}, {}); + ++__begin; + } else + std::__throw_format_error("Type m requires a pair or a tuple with two elements"); + } + + if (__begin != __end && *__begin != _CharT('}')) + std::__throw_format_error("The format specifier should consume the input or end with a '}'"); + + __ctx.advance_to(__begin); + + // [format.tuple]/7 + // ... For each element e in underlying_, if e.set_debug_format() + // is a valid expression, calls e.set_debug_format(). + std::__for_each_index_sequence(make_index_sequence(), [&] { + auto& __formatter = std::get<_Index>(__underlying_); + __formatter.parse(__ctx); + // Unlike the range_formatter we don't guard against evil parsers. Since + // this format-spec never has a format-spec for the underlying type + // adding the test would give additional overhead. + std::__set_debug_format(__formatter); + }); + + return __begin; + } + + template + typename _FormatContext::iterator _LIBCPP_HIDE_FROM_ABI + format(conditional_t<(formattable && ...), const _Tuple&, _Tuple&> __tuple, + _FormatContext& __ctx) const { + __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx); + + if (!__specs.__has_width()) + return __format_tuple(__tuple, __ctx); + + // The size of the buffer needed is: + // - open bracket characters + // - close bracket character + // - n elements where every element may have a different size + // - (n -1) separators + // The size of the element is hard to predict, knowing the type helps but + // it depends on the format-spec. As an initial estimate we guess 6 + // characters. + // Typically both brackets are 1 character and the separator is 2 + // characters. Which means there will be + // (n - 1) * 2 + 1 + 1 = n * 2 character + // So estimate 8 times the range size as buffer. + __format::__retarget_buffer<_CharT> __buffer{8 * tuple_size_v<_Tuple>}; + basic_format_context::__iterator, _CharT> __c{ + __buffer.__make_output_iterator(), __ctx}; + + __format_tuple(__tuple, __c); + + return __formatter::__write_string_no_precision(basic_string_view{__buffer.__view()}, __ctx.out(), __specs); + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator __format_tuple(auto&& __tuple, _FormatContext& __ctx) const { + __ctx.advance_to(std::ranges::copy(__opening_bracket_, __ctx.out()).out); + + std::__for_each_index_sequence(make_index_sequence(), [&] { + if constexpr (_Index) + __ctx.advance_to(std::ranges::copy(__separator_, __ctx.out()).out); + __ctx.advance_to(std::get<_Index>(__underlying_).format(std::get<_Index>(__tuple), __ctx)); + }); + + return std::ranges::copy(__closing_bracket_, __ctx.out()).out; + } + + __format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__left}; + +private: + tuple, _CharT>...> __underlying_; + basic_string_view<_CharT> __separator_ = _LIBCPP_STATICALLY_WIDEN(_CharT, ", "); + basic_string_view<_CharT> __opening_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, "("); + basic_string_view<_CharT> __closing_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, ")"); +}; + +template <__fmt_char_type _CharT, formattable<_CharT>... _Args> +struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> + : public __formatter_tuple<_CharT, pair<_Args...>, _Args...> {}; + +template <__fmt_char_type _CharT, formattable<_CharT>... _Args> +struct _LIBCPP_TEMPLATE_VIS formatter, _CharT> + : public __formatter_tuple<_CharT, tuple<_Args...>, _Args...> {}; + +#endif //_LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_FORMATTER_TUPLE_H diff --git a/libcxx/include/__cxx03/__format/indic_conjunct_break_table.h b/libcxx/include/__cxx03/__format/indic_conjunct_break_table.h new file mode 100644 index 0000000000000000000000000000000000000000..44521d27498c3c368ecc2c29f93487577a07778c --- /dev/null +++ b/libcxx/include/__cxx03/__format/indic_conjunct_break_table.h @@ -0,0 +1,350 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// WARNING, this entire header is generated by +// utils/generate_indic_conjunct_break_table.py +// DO NOT MODIFY! + +// UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE +// +// See Terms of Use +// for definitions of Unicode Inc.'s Data Files and Software. +// +// NOTICE TO USER: Carefully read the following legal agreement. +// BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +// DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +// YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +// TERMS AND CONDITIONS OF THIS AGREEMENT. +// IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +// THE DATA FILES OR SOFTWARE. +// +// COPYRIGHT AND PERMISSION NOTICE +// +// Copyright (c) 1991-2022 Unicode, Inc. All rights reserved. +// Distributed under the Terms of Use in https://www.unicode.org/copyright.html. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of the Unicode data files and any associated documentation +// (the "Data Files") or Unicode software and any associated documentation +// (the "Software") to deal in the Data Files or Software +// without restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, and/or sell copies of +// the Data Files or Software, and to permit persons to whom the Data Files +// or Software are furnished to do so, provided that either +// (a) this copyright and permission notice appear with all copies +// of the Data Files or Software, or +// (b) this copyright and permission notice appear in associated +// Documentation. +// +// THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS. +// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +// NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +// DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THE DATA FILES OR SOFTWARE. +// +// Except as contained in this notice, the name of a copyright holder +// shall not be used in advertising or otherwise to promote the sale, +// use or other dealings in these Data Files or Software without prior +// written authorization of the copyright holder. + +#ifndef _LIBCPP___FORMAT_INDIC_CONJUNCT_BREAK_TABLE_H +#define _LIBCPP___FORMAT_INDIC_CONJUNCT_BREAK_TABLE_H + +#include <__algorithm/ranges_upper_bound.h> +#include <__config> +#include <__iterator/access.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __indic_conjunct_break { + +enum class __property : uint8_t { + // Values generated from the data files. + __Consonant, + __Extend, + __Linker, + + // The code unit has none of above properties. + __none +}; + +/// The entries of the indic conjunct break property table. +/// +/// The data is generated from +/// - https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt +/// +/// The data has 3 values +/// - bits [0, 1] The property. One of the values generated from the datafiles +/// of \ref __property +/// - bits [2, 10] The size of the range. +/// - bits [11, 31] The lower bound code point of the range. The upper bound of +/// the range is lower bound + size. +/// +/// The 9 bits for the size allow a maximum range of 512 elements. Some ranges +/// in the Unicode tables are larger. They are stored in multiple consecutive +/// ranges in the data table. An alternative would be to store the sizes in a +/// separate 16-bit value. The original MSVC STL code had such an approach, but +/// this approach uses less space for the data and is about 4% faster in the +/// following benchmark. +/// libcxx/benchmarks/std_format_spec_string_unicode.bench.cpp +// clang-format off +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[201] = { + 0x00180139, + 0x001a807d, + 0x00241811, + 0x002c88b1, + 0x002df801, + 0x002e0805, + 0x002e2005, + 0x002e3801, + 0x00308029, + 0x00325851, + 0x00338001, + 0x0036b019, + 0x0036f815, + 0x00373805, + 0x0037500d, + 0x00388801, + 0x00398069, + 0x003f5821, + 0x003fe801, + 0x0040b00d, + 0x0040d821, + 0x00412809, + 0x00414811, + 0x0042c809, + 0x0044c01d, + 0x0046505d, + 0x00471871, + 0x0048a890, + 0x0049e001, + 0x004a6802, + 0x004a880d, + 0x004ac01c, + 0x004bc01c, + 0x004ca84c, + 0x004d5018, + 0x004d9000, + 0x004db00c, + 0x004de001, + 0x004e6802, + 0x004ee004, + 0x004ef800, + 0x004f8004, + 0x004ff001, + 0x0051e001, + 0x0054a84c, + 0x00555018, + 0x00559004, + 0x0055a810, + 0x0055e001, + 0x00566802, + 0x0057c800, + 0x0058a84c, + 0x00595018, + 0x00599004, + 0x0059a810, + 0x0059e001, + 0x005a6802, + 0x005ae004, + 0x005af800, + 0x005b8800, + 0x0060a84c, + 0x0061503c, + 0x0061e001, + 0x00626802, + 0x0062a805, + 0x0062c008, + 0x0065e001, + 0x0068a894, + 0x0069d805, + 0x006a6802, + 0x0071c009, + 0x0072400d, + 0x0075c009, + 0x0076400d, + 0x0078c005, + 0x0079a801, + 0x0079b801, + 0x0079c801, + 0x007b8805, + 0x007ba001, + 0x007bd00d, + 0x007c0001, + 0x007c1009, + 0x007c3005, + 0x007e3001, + 0x0081b801, + 0x0081c805, + 0x00846801, + 0x009ae809, + 0x00b8a001, + 0x00be9001, + 0x00bee801, + 0x00c54801, + 0x00c9c809, + 0x00d0b805, + 0x00d30001, + 0x00d3a81d, + 0x00d3f801, + 0x00d58035, + 0x00d5f83d, + 0x00d9a001, + 0x00db5821, + 0x00dd5801, + 0x00df3001, + 0x00e1b801, + 0x00e68009, + 0x00e6a031, + 0x00e71019, + 0x00e76801, + 0x00e7a001, + 0x00e7c005, + 0x00ee00fd, + 0x01006801, + 0x01068031, + 0x01070801, + 0x0107282d, + 0x01677809, + 0x016bf801, + 0x016f007d, + 0x01815015, + 0x0184c805, + 0x05337801, + 0x0533a025, + 0x0534f005, + 0x05378005, + 0x05416001, + 0x05470045, + 0x05495809, + 0x054d9801, + 0x05558001, + 0x05559009, + 0x0555b805, + 0x0555f005, + 0x05560801, + 0x0557b001, + 0x055f6801, + 0x07d8f001, + 0x07f1003d, + 0x080fe801, + 0x08170001, + 0x081bb011, + 0x08506801, + 0x08507801, + 0x0851c009, + 0x0851f801, + 0x08572805, + 0x0869200d, + 0x08755805, + 0x0877e809, + 0x087a3029, + 0x087c100d, + 0x08838001, + 0x0883f801, + 0x0885d001, + 0x08880009, + 0x08899805, + 0x088b9801, + 0x088e5001, + 0x0891b001, + 0x08974805, + 0x0899d805, + 0x089b3019, + 0x089b8011, + 0x08a23001, + 0x08a2f001, + 0x08a61801, + 0x08ae0001, + 0x08b5b801, + 0x08b95801, + 0x08c1d001, + 0x08c9f001, + 0x08ca1801, + 0x08d1a001, + 0x08d23801, + 0x08d4c801, + 0x08ea1001, + 0x08ea2005, + 0x08ecb801, + 0x08fa1001, + 0x0b578011, + 0x0b598019, + 0x0de4f001, + 0x0e8b2801, + 0x0e8b3809, + 0x0e8b7011, + 0x0e8bd81d, + 0x0e8c2819, + 0x0e8d500d, + 0x0e921009, + 0x0f000019, + 0x0f004041, + 0x0f00d819, + 0x0f011805, + 0x0f013011, + 0x0f047801, + 0x0f098019, + 0x0f157001, + 0x0f17600d, + 0x0f27600d, + 0x0f468019, + 0x0f4a2019}; +// clang-format on + +/// Returns the indic conjuct break property of a code point. +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __property __get_property(const char32_t __code_point) noexcept { + // The algorithm searches for the upper bound of the range and, when found, + // steps back one entry. This algorithm is used since the code point can be + // anywhere in the range. After a lower bound is found the next step is to + // compare whether the code unit is indeed in the range. + // + // Since the entry contains a code unit, size, and property the code point + // being sought needs to be adjusted. Just shifting the code point to the + // proper position doesn't work; suppose an entry has property 0, size 1, + // and lower bound 3. This results in the entry 0x1810. + // When searching for code point 3 it will search for 0x1800, find 0x1810 + // and moves to the previous entry. Thus the lower bound value will never + // be found. + // The simple solution is to set the bits belonging to the property and + // size. Then the upper bound for code point 3 will return the entry after + // 0x1810. After moving to the previous entry the algorithm arrives at the + // correct entry. + ptrdiff_t __i = std::ranges::upper_bound(__entries, (__code_point << 11) | 0x7ffu) - __entries; + if (__i == 0) + return __property::__none; + + --__i; + uint32_t __upper_bound = (__entries[__i] >> 11) + ((__entries[__i] >> 2) & 0b1'1111'1111); + if (__code_point <= __upper_bound) + return static_cast<__property>(__entries[__i] & 0b11); + + return __property::__none; +} + +} // namespace __indic_conjunct_break + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_INDIC_CONJUNCT_BREAK_TABLE_H diff --git a/libcxx/include/__cxx03/__format/parser_std_format_spec.h b/libcxx/include/__cxx03/__format/parser_std_format_spec.h new file mode 100644 index 0000000000000000000000000000000000000000..150bdde89f3b396f9d3de463d32878f859d41a80 --- /dev/null +++ b/libcxx/include/__cxx03/__format/parser_std_format_spec.h @@ -0,0 +1,1172 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_PARSER_STD_FORMAT_SPEC_H +#define _LIBCPP___FORMAT_PARSER_STD_FORMAT_SPEC_H + +/// \file Contains the std-format-spec parser. +/// +/// Most of the code can be reused in the chrono-format-spec. +/// This header has some support for the chrono-format-spec since it doesn't +/// affect the std-format-spec. + +#include <__algorithm/copy_n.h> +#include <__algorithm/min.h> +#include <__assert> +#include <__concepts/arithmetic.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__format/format_arg.h> +#include <__format/format_error.h> +#include <__format/format_parse_context.h> +#include <__format/format_string.h> +#include <__format/unicode.h> +#include <__format/width_estimation_table.h> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> // iter_value_t +#include <__memory/addressof.h> +#include <__type_traits/common_type.h> +#include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_trivially_copyable.h> +#include <__variant/monostate.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __format_spec { + +_LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI inline void +__throw_invalid_option_format_error(const char* __id, const char* __option) { + std::__throw_format_error( + (string("The format specifier for ") + __id + " does not allow the " + __option + " option").c_str()); +} + +_LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI inline void __throw_invalid_type_format_error(const char* __id) { + std::__throw_format_error( + (string("The type option contains an invalid value for ") + __id + " formatting argument").c_str()); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr __format::__parse_number_result<_Iterator> +__parse_arg_id(_Iterator __begin, _Iterator __end, _ParseContext& __ctx) { + using _CharT = iter_value_t<_Iterator>; + // This function is a wrapper to call the real parser. But it does the + // validation for the pre-conditions and post-conditions. + if (__begin == __end) + std::__throw_format_error("End of input while parsing an argument index"); + + __format::__parse_number_result __r = __format::__parse_arg_id(__begin, __end, __ctx); + + if (__r.__last == __end || *__r.__last != _CharT('}')) + std::__throw_format_error("The argument index is invalid"); + + ++__r.__last; + return __r; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr uint32_t __substitute_arg_id(basic_format_arg<_Context> __format_arg) { + // [format.string.std]/8 + // If the corresponding formatting argument is not of integral type... + // This wording allows char and bool too. LWG-3720 changes the wording to + // If the corresponding formatting argument is not of standard signed or + // unsigned integer type, + // This means the 128-bit will not be valid anymore. + // TODO FMT Verify this resolution is accepted and add a test to verify + // 128-bit integrals fail and switch to visit_format_arg. + return std::__visit_format_arg( + [](auto __arg) -> uint32_t { + using _Type = decltype(__arg); + if constexpr (same_as<_Type, monostate>) + std::__throw_format_error("The argument index value is too large for the number of arguments supplied"); + + // [format.string.std]/8 + // If { arg-idopt } is used in a width or precision, the value of the + // corresponding formatting argument is used in its place. If the + // corresponding formatting argument is not of standard signed or unsigned + // integer type, or its value is negative for precision or non-positive for + // width, an exception of type format_error is thrown. + // + // When an integral is used in a format function, it is stored as one of + // the types checked below. Other integral types are promoted. For example, + // a signed char is stored as an int. + if constexpr (same_as<_Type, int> || same_as<_Type, unsigned int> || // + same_as<_Type, long long> || same_as<_Type, unsigned long long>) { + if constexpr (signed_integral<_Type>) { + if (__arg < 0) + std::__throw_format_error("An argument index may not have a negative value"); + } + + using _CT = common_type_t<_Type, decltype(__format::__number_max)>; + if (static_cast<_CT>(__arg) > static_cast<_CT>(__format::__number_max)) + std::__throw_format_error("The value of the argument index exceeds its maximum value"); + + return __arg; + } else + std::__throw_format_error("Replacement argument isn't a standard signed or unsigned integer type"); + }, + __format_arg); +} + +/// These fields are a filter for which elements to parse. +/// +/// They default to false so when a new field is added it needs to be opted in +/// explicitly. +struct _LIBCPP_HIDE_FROM_ABI __fields { + uint16_t __sign_ : 1 {false}; + uint16_t __alternate_form_ : 1 {false}; + uint16_t __zero_padding_ : 1 {false}; + uint16_t __precision_ : 1 {false}; + uint16_t __locale_specific_form_ : 1 {false}; + uint16_t __type_ : 1 {false}; + // Determines the valid values for fill. + // + // Originally the fill could be any character except { and }. Range-based + // formatters use the colon to mark the beginning of the + // underlying-format-spec. To avoid parsing ambiguities these formatter + // specializations prohibit the use of the colon as a fill character. + uint16_t __use_range_fill_ : 1 {false}; + uint16_t __clear_brackets_ : 1 {false}; + uint16_t __consume_all_ : 1 {false}; +}; + +// By not placing this constant in the formatter class it's not duplicated for +// char and wchar_t. +inline constexpr __fields __fields_bool{.__locale_specific_form_ = true, .__type_ = true, .__consume_all_ = true}; +inline constexpr __fields __fields_integral{ + .__sign_ = true, + .__alternate_form_ = true, + .__zero_padding_ = true, + .__locale_specific_form_ = true, + .__type_ = true, + .__consume_all_ = true}; +inline constexpr __fields __fields_floating_point{ + .__sign_ = true, + .__alternate_form_ = true, + .__zero_padding_ = true, + .__precision_ = true, + .__locale_specific_form_ = true, + .__type_ = true, + .__consume_all_ = true}; +inline constexpr __fields __fields_string{.__precision_ = true, .__type_ = true, .__consume_all_ = true}; +inline constexpr __fields __fields_pointer{.__zero_padding_ = true, .__type_ = true, .__consume_all_ = true}; + +# if _LIBCPP_STD_VER >= 23 +inline constexpr __fields __fields_tuple{.__use_range_fill_ = true, .__clear_brackets_ = true}; +inline constexpr __fields __fields_range{.__use_range_fill_ = true, .__clear_brackets_ = true}; +inline constexpr __fields __fields_fill_align_width{}; +# endif + +enum class __alignment : uint8_t { + /// No alignment is set in the format string. + __default, + __left, + __center, + __right, + __zero_padding +}; + +enum class __sign : uint8_t { + /// No sign is set in the format string. + /// + /// The sign isn't allowed for certain format-types. By using this value + /// it's possible to detect whether or not the user explicitly set the sign + /// flag. For formatting purposes it behaves the same as \ref __minus. + __default, + __minus, + __plus, + __space +}; + +enum class __type : uint8_t { + __default = 0, + __string, + __binary_lower_case, + __binary_upper_case, + __octal, + __decimal, + __hexadecimal_lower_case, + __hexadecimal_upper_case, + __pointer_lower_case, + __pointer_upper_case, + __char, + __hexfloat_lower_case, + __hexfloat_upper_case, + __scientific_lower_case, + __scientific_upper_case, + __fixed_lower_case, + __fixed_upper_case, + __general_lower_case, + __general_upper_case, + __debug +}; + +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __create_type_mask(__type __t) { + uint32_t __shift = static_cast(__t); + if (__shift == 0) + return 1; + + if (__shift > 31) + std::__throw_format_error("The type does not fit in the mask"); + + return 1 << __shift; +} + +inline constexpr uint32_t __type_mask_integer = + __create_type_mask(__type::__binary_lower_case) | // + __create_type_mask(__type::__binary_upper_case) | // + __create_type_mask(__type::__decimal) | // + __create_type_mask(__type::__octal) | // + __create_type_mask(__type::__hexadecimal_lower_case) | // + __create_type_mask(__type::__hexadecimal_upper_case); + +struct __std { + __alignment __alignment_ : 3; + __sign __sign_ : 2; + bool __alternate_form_ : 1; + bool __locale_specific_form_ : 1; + __type __type_; +}; + +struct __chrono { + __alignment __alignment_ : 3; + bool __locale_specific_form_ : 1; + bool __hour_ : 1; + bool __weekday_name_ : 1; + bool __weekday_ : 1; + bool __day_of_year_ : 1; + bool __week_of_year_ : 1; + bool __month_name_ : 1; +}; + +// The fill UCS scalar value. +// +// This is always an array, with 1, 2, or 4 elements. +// The size of the data structure is always 32-bits. +template +struct __code_point; + +template <> +struct __code_point { + char __data[4] = {' '}; +}; + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <> +struct __code_point { + wchar_t __data[4 / sizeof(wchar_t)] = {L' '}; +}; +# endif + +/// Contains the parsed formatting specifications. +/// +/// This contains information for both the std-format-spec and the +/// chrono-format-spec. This results in some unused members for both +/// specifications. However these unused members don't increase the size +/// of the structure. +/// +/// This struct doesn't cross ABI boundaries so its layout doesn't need to be +/// kept stable. +template +struct __parsed_specifications { + union { + // The field __alignment_ is the first element in __std_ and __chrono_. + // This allows the code to always inspect this value regards which member + // of the union is the active member [class.union.general]/2. + // + // This is needed since the generic output routines handle the alignment of + // the output. + __alignment __alignment_ : 3; + __std __std_; + __chrono __chrono_; + }; + + /// The requested width. + /// + /// When the format-spec used an arg-id for this field it has already been + /// replaced with the value of that arg-id. + int32_t __width_; + + /// The requested precision. + /// + /// When the format-spec used an arg-id for this field it has already been + /// replaced with the value of that arg-id. + int32_t __precision_; + + __code_point<_CharT> __fill_; + + _LIBCPP_HIDE_FROM_ABI constexpr bool __has_width() const { return __width_ > 0; } + + _LIBCPP_HIDE_FROM_ABI constexpr bool __has_precision() const { return __precision_ >= 0; } +}; + +// Validate the struct is small and cheap to copy since the struct is passed by +// value in formatting functions. +static_assert(sizeof(__parsed_specifications) == 16); +static_assert(is_trivially_copyable_v<__parsed_specifications>); +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +static_assert(sizeof(__parsed_specifications) == 16); +static_assert(is_trivially_copyable_v<__parsed_specifications>); +# endif + +/// The parser for the std-format-spec. +/// +/// Note this class is a member of std::formatter specializations. It's +/// expected developers will create their own formatter specializations that +/// inherit from the std::formatter specializations. This means this class +/// must be ABI stable. To aid the stability the unused bits in the class are +/// set to zero. That way they can be repurposed if a future revision of the +/// Standards adds new fields to std-format-spec. +template +class _LIBCPP_TEMPLATE_VIS __parser { +public: + // Parses the format specification. + // + // Depending on whether the parsing is done compile-time or run-time + // the method slightly differs. + // - Only parses a field when it is in the __fields. Accepting all + // fields and then validating the valid ones has a performance impact. + // This is faster but gives slighly worse error messages. + // - At compile-time when a field is not accepted the parser will still + // parse it and give an error when it's present. This gives a more + // accurate error. + // The idea is that most times the format instead of the vformat + // functions are used. In that case the error will be detected during + // compilation and there is no need to pay for the run-time overhead. + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator __parse(_ParseContext& __ctx, __fields __fields) { + auto __begin = __ctx.begin(); + auto __end = __ctx.end(); + if (__begin == __end || *__begin == _CharT('}') || (__fields.__use_range_fill_ && *__begin == _CharT(':'))) + return __begin; + + if (__parse_fill_align(__begin, __end) && __begin == __end) + return __begin; + + if (__fields.__sign_) { + if (__parse_sign(__begin) && __begin == __end) + return __begin; + } else if (std::is_constant_evaluated() && __parse_sign(__begin)) { + std::__throw_format_error("The format specification does not allow the sign option"); + } + + if (__fields.__alternate_form_) { + if (__parse_alternate_form(__begin) && __begin == __end) + return __begin; + } else if (std::is_constant_evaluated() && __parse_alternate_form(__begin)) { + std::__throw_format_error("The format specifier does not allow the alternate form option"); + } + + if (__fields.__zero_padding_) { + if (__parse_zero_padding(__begin) && __begin == __end) + return __begin; + } else if (std::is_constant_evaluated() && __parse_zero_padding(__begin)) { + std::__throw_format_error("The format specifier does not allow the zero-padding option"); + } + + if (__parse_width(__begin, __end, __ctx) && __begin == __end) + return __begin; + + if (__fields.__precision_) { + if (__parse_precision(__begin, __end, __ctx) && __begin == __end) + return __begin; + } else if (std::is_constant_evaluated() && __parse_precision(__begin, __end, __ctx)) { + std::__throw_format_error("The format specifier does not allow the precision option"); + } + + if (__fields.__locale_specific_form_) { + if (__parse_locale_specific_form(__begin) && __begin == __end) + return __begin; + } else if (std::is_constant_evaluated() && __parse_locale_specific_form(__begin)) { + std::__throw_format_error("The format specifier does not allow the locale-specific form option"); + } + + if (__fields.__clear_brackets_) { + if (__parse_clear_brackets(__begin) && __begin == __end) + return __begin; + } else if (std::is_constant_evaluated() && __parse_clear_brackets(__begin)) { + std::__throw_format_error("The format specifier does not allow the n option"); + } + + if (__fields.__type_) + __parse_type(__begin); + + if (!__fields.__consume_all_) + return __begin; + + if (__begin != __end && *__begin != _CharT('}')) + std::__throw_format_error("The format specifier should consume the input or end with a '}'"); + + return __begin; + } + + // Validates the selected the parsed data. + // + // The valid fields in the parser may depend on the display type + // selected. But the type is the last optional field, so by the time + // it's known an option can't be used, it already has been parsed. + // This does the validation again. + // + // For example an integral may have a sign, zero-padding, or alternate + // form when the type option is not 'c'. So the generic approach is: + // + // typename _ParseContext::iterator __result = __parser_.__parse(__ctx, __format_spec::__fields_integral); + // if (__parser.__type_ == __format_spec::__type::__char) { + // __parser.__validate((__format_spec::__fields_bool, "an integer"); + // ... // more char adjustments + // } else { + // ... // validate an integral type. + // } + // + // For some types all valid options need a second validation run, like + // boolean types. + // + // Depending on whether the validation is done at compile-time or + // run-time the error differs + // - run-time the exception is thrown and contains the type of field + // being validated. + // - at compile-time the line with `std::__throw_format_error` is shown + // in the output. In that case it's important for the error to be on one + // line. + // Note future versions of C++ may allow better compile-time error + // reporting. + _LIBCPP_HIDE_FROM_ABI constexpr void + __validate(__fields __fields, const char* __id, uint32_t __type_mask = -1) const { + if (!__fields.__sign_ && __sign_ != __sign::__default) { + if (std::is_constant_evaluated()) + std::__throw_format_error("The format specifier does not allow the sign option"); + else + __format_spec::__throw_invalid_option_format_error(__id, "sign"); + } + + if (!__fields.__alternate_form_ && __alternate_form_) { + if (std::is_constant_evaluated()) + std::__throw_format_error("The format specifier does not allow the alternate form option"); + else + __format_spec::__throw_invalid_option_format_error(__id, "alternate form"); + } + + if (!__fields.__zero_padding_ && __alignment_ == __alignment::__zero_padding) { + if (std::is_constant_evaluated()) + std::__throw_format_error("The format specifier does not allow the zero-padding option"); + else + __format_spec::__throw_invalid_option_format_error(__id, "zero-padding"); + } + + if (!__fields.__precision_ && __precision_ != -1) { // Works both when the precision has a value or an arg-id. + if (std::is_constant_evaluated()) + std::__throw_format_error("The format specifier does not allow the precision option"); + else + __format_spec::__throw_invalid_option_format_error(__id, "precision"); + } + + if (!__fields.__locale_specific_form_ && __locale_specific_form_) { + if (std::is_constant_evaluated()) + std::__throw_format_error("The format specifier does not allow the locale-specific form option"); + else + __format_spec::__throw_invalid_option_format_error(__id, "locale-specific form"); + } + + if ((__create_type_mask(__type_) & __type_mask) == 0) { + if (std::is_constant_evaluated()) + std::__throw_format_error("The format specifier uses an invalid value for the type option"); + else + __format_spec::__throw_invalid_type_format_error(__id); + } + } + + /// \returns the `__parsed_specifications` with the resolved dynamic sizes.. + _LIBCPP_HIDE_FROM_ABI __parsed_specifications<_CharT> __get_parsed_std_specifications(auto& __ctx) const { + return __parsed_specifications<_CharT>{ + .__std_ = __std{.__alignment_ = __alignment_, + .__sign_ = __sign_, + .__alternate_form_ = __alternate_form_, + .__locale_specific_form_ = __locale_specific_form_, + .__type_ = __type_}, + .__width_{__get_width(__ctx)}, + .__precision_{__get_precision(__ctx)}, + .__fill_{__fill_}}; + } + + _LIBCPP_HIDE_FROM_ABI __parsed_specifications<_CharT> __get_parsed_chrono_specifications(auto& __ctx) const { + return __parsed_specifications<_CharT>{ + .__chrono_ = + __chrono{.__alignment_ = __alignment_, + .__locale_specific_form_ = __locale_specific_form_, + .__hour_ = __hour_, + .__weekday_name_ = __weekday_name_, + .__weekday_ = __weekday_, + .__day_of_year_ = __day_of_year_, + .__week_of_year_ = __week_of_year_, + .__month_name_ = __month_name_}, + .__width_{__get_width(__ctx)}, + .__precision_{__get_precision(__ctx)}, + .__fill_{__fill_}}; + } + + __alignment __alignment_ : 3 {__alignment::__default}; + __sign __sign_ : 2 {__sign::__default}; + bool __alternate_form_ : 1 {false}; + bool __locale_specific_form_ : 1 {false}; + bool __clear_brackets_ : 1 {false}; + __type __type_{__type::__default}; + + // These flags are only used for formatting chrono. Since the struct has + // padding space left it's added to this structure. + bool __hour_ : 1 {false}; + + bool __weekday_name_ : 1 {false}; + bool __weekday_ : 1 {false}; + + bool __day_of_year_ : 1 {false}; + bool __week_of_year_ : 1 {false}; + + bool __month_name_ : 1 {false}; + + uint8_t __reserved_0_ : 2 {0}; + uint8_t __reserved_1_ : 6 {0}; + // These two flags are only used internally and not part of the + // __parsed_specifications. Therefore put them at the end. + bool __width_as_arg_ : 1 {false}; + bool __precision_as_arg_ : 1 {false}; + + /// The requested width, either the value or the arg-id. + int32_t __width_{0}; + + /// The requested precision, either the value or the arg-id. + int32_t __precision_{-1}; + + __code_point<_CharT> __fill_{}; + +private: + _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_alignment(_CharT __c) { + switch (__c) { + case _CharT('<'): + __alignment_ = __alignment::__left; + return true; + + case _CharT('^'): + __alignment_ = __alignment::__center; + return true; + + case _CharT('>'): + __alignment_ = __alignment::__right; + return true; + } + return false; + } + + _LIBCPP_HIDE_FROM_ABI constexpr void __validate_fill_character(_CharT __fill) { + // The forbidden fill characters all code points formed from a single code unit, thus the + // check can be omitted when more code units are used. + if (__fill == _CharT('{')) + std::__throw_format_error("The fill option contains an invalid value"); + } + +# ifndef _LIBCPP_HAS_NO_UNICODE + // range-fill and tuple-fill are identical + template + requires same_as<_CharT, char> +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS + || (same_as<_CharT, wchar_t> && sizeof(wchar_t) == 2) +# endif + _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __begin != __end, + "when called with an empty input the function will cause " + "undefined behavior by evaluating data not in the input"); + __unicode::__code_point_view<_CharT> __view{__begin, __end}; + __unicode::__consume_result __consumed = __view.__consume(); + if (__consumed.__status != __unicode::__consume_result::__ok) + std::__throw_format_error("The format specifier contains malformed Unicode characters"); + + if (__view.__position() < __end && __parse_alignment(*__view.__position())) { + ptrdiff_t __code_units = __view.__position() - __begin; + if (__code_units == 1) + // The forbidden fill characters all are code points encoded + // in one code unit, thus the check can be omitted when more + // code units are used. + __validate_fill_character(*__begin); + + std::copy_n(__begin, __code_units, std::addressof(__fill_.__data[0])); + __begin += __code_units + 1; + return true; + } + + if (!__parse_alignment(*__begin)) + return false; + + ++__begin; + return true; + } + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS + template + requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 4) + _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __begin != __end, + "when called with an empty input the function will cause " + "undefined behavior by evaluating data not in the input"); + if (__begin + 1 != __end && __parse_alignment(*(__begin + 1))) { + if (!__unicode::__is_scalar_value(*__begin)) + std::__throw_format_error("The fill option contains an invalid value"); + + __validate_fill_character(*__begin); + + __fill_.__data[0] = *__begin; + __begin += 2; + return true; + } + + if (!__parse_alignment(*__begin)) + return false; + + ++__begin; + return true; + } + +# endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS + +# else // _LIBCPP_HAS_NO_UNICODE + // range-fill and tuple-fill are identical + template + _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_fill_align(_Iterator& __begin, _Iterator __end) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __begin != __end, + "when called with an empty input the function will cause " + "undefined behavior by evaluating data not in the input"); + if (__begin + 1 != __end) { + if (__parse_alignment(*(__begin + 1))) { + __validate_fill_character(*__begin); + + __fill_.__data[0] = *__begin; + __begin += 2; + return true; + } + } + + if (!__parse_alignment(*__begin)) + return false; + + ++__begin; + return true; + } + +# endif // _LIBCPP_HAS_NO_UNICODE + + template + _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_sign(_Iterator& __begin) { + switch (*__begin) { + case _CharT('-'): + __sign_ = __sign::__minus; + break; + case _CharT('+'): + __sign_ = __sign::__plus; + break; + case _CharT(' '): + __sign_ = __sign::__space; + break; + default: + return false; + } + ++__begin; + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_alternate_form(_Iterator& __begin) { + if (*__begin != _CharT('#')) + return false; + + __alternate_form_ = true; + ++__begin; + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_zero_padding(_Iterator& __begin) { + if (*__begin != _CharT('0')) + return false; + + if (__alignment_ == __alignment::__default) + __alignment_ = __alignment::__zero_padding; + ++__begin; + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_width(_Iterator& __begin, _Iterator __end, auto& __ctx) { + if (*__begin == _CharT('0')) + std::__throw_format_error("The width option should not have a leading zero"); + + if (*__begin == _CharT('{')) { + __format::__parse_number_result __r = __format_spec::__parse_arg_id(++__begin, __end, __ctx); + __width_as_arg_ = true; + __width_ = __r.__value; + __begin = __r.__last; + return true; + } + + if (*__begin < _CharT('0') || *__begin > _CharT('9')) + return false; + + __format::__parse_number_result __r = __format::__parse_number(__begin, __end); + __width_ = __r.__value; + _LIBCPP_ASSERT_INTERNAL(__width_ != 0, + "A zero value isn't allowed and should be impossible, " + "due to validations in this function"); + __begin = __r.__last; + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_precision(_Iterator& __begin, _Iterator __end, auto& __ctx) { + if (*__begin != _CharT('.')) + return false; + + ++__begin; + if (__begin == __end) + std::__throw_format_error("End of input while parsing format specifier precision"); + + if (*__begin == _CharT('{')) { + __format::__parse_number_result __arg_id = __format_spec::__parse_arg_id(++__begin, __end, __ctx); + __precision_as_arg_ = true; + __precision_ = __arg_id.__value; + __begin = __arg_id.__last; + return true; + } + + if (*__begin < _CharT('0') || *__begin > _CharT('9')) + std::__throw_format_error("The precision option does not contain a value or an argument index"); + + __format::__parse_number_result __r = __format::__parse_number(__begin, __end); + __precision_ = __r.__value; + __precision_as_arg_ = false; + __begin = __r.__last; + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_locale_specific_form(_Iterator& __begin) { + if (*__begin != _CharT('L')) + return false; + + __locale_specific_form_ = true; + ++__begin; + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr bool __parse_clear_brackets(_Iterator& __begin) { + if (*__begin != _CharT('n')) + return false; + + __clear_brackets_ = true; + ++__begin; + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr void __parse_type(_Iterator& __begin) { + // Determines the type. It does not validate whether the selected type is + // valid. Most formatters have optional fields that are only allowed for + // certain types. These parsers need to do validation after the type has + // been parsed. So its easier to implement the validation for all types in + // the specific parse function. + switch (*__begin) { + case 'A': + __type_ = __type::__hexfloat_upper_case; + break; + case 'B': + __type_ = __type::__binary_upper_case; + break; + case 'E': + __type_ = __type::__scientific_upper_case; + break; + case 'F': + __type_ = __type::__fixed_upper_case; + break; + case 'G': + __type_ = __type::__general_upper_case; + break; + case 'X': + __type_ = __type::__hexadecimal_upper_case; + break; + case 'a': + __type_ = __type::__hexfloat_lower_case; + break; + case 'b': + __type_ = __type::__binary_lower_case; + break; + case 'c': + __type_ = __type::__char; + break; + case 'd': + __type_ = __type::__decimal; + break; + case 'e': + __type_ = __type::__scientific_lower_case; + break; + case 'f': + __type_ = __type::__fixed_lower_case; + break; + case 'g': + __type_ = __type::__general_lower_case; + break; + case 'o': + __type_ = __type::__octal; + break; + case 'p': + __type_ = __type::__pointer_lower_case; + break; + case 'P': + __type_ = __type::__pointer_upper_case; + break; + case 's': + __type_ = __type::__string; + break; + case 'x': + __type_ = __type::__hexadecimal_lower_case; + break; +# if _LIBCPP_STD_VER >= 23 + case '?': + __type_ = __type::__debug; + break; +# endif + default: + return; + } + ++__begin; + } + + _LIBCPP_HIDE_FROM_ABI int32_t __get_width(auto& __ctx) const { + if (!__width_as_arg_) + return __width_; + + return __format_spec::__substitute_arg_id(__ctx.arg(__width_)); + } + + _LIBCPP_HIDE_FROM_ABI int32_t __get_precision(auto& __ctx) const { + if (!__precision_as_arg_) + return __precision_; + + return __format_spec::__substitute_arg_id(__ctx.arg(__precision_)); + } +}; + +// Validates whether the reserved bitfields don't change the size. +static_assert(sizeof(__parser) == 16); +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +static_assert(sizeof(__parser) == 16); +# endif + +_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_string(__format_spec::__type __type) { + switch (__type) { + case __format_spec::__type::__default: + case __format_spec::__type::__string: + case __format_spec::__type::__debug: + break; + + default: + std::__throw_format_error("The type option contains an invalid value for a string formatting argument"); + } +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_bool_string(__parser<_CharT>& __parser, const char* __id) { + __parser.__validate(__format_spec::__fields_bool, __id); + if (__parser.__alignment_ == __alignment::__default) + __parser.__alignment_ = __alignment::__left; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_char(__parser<_CharT>& __parser, const char* __id) { + __format_spec::__process_display_type_bool_string(__parser, __id); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_bool(__parser<_CharT>& __parser, const char* __id) { + switch (__parser.__type_) { + case __format_spec::__type::__default: + case __format_spec::__type::__string: + __format_spec::__process_display_type_bool_string(__parser, __id); + break; + + case __format_spec::__type::__binary_lower_case: + case __format_spec::__type::__binary_upper_case: + case __format_spec::__type::__octal: + case __format_spec::__type::__decimal: + case __format_spec::__type::__hexadecimal_lower_case: + case __format_spec::__type::__hexadecimal_upper_case: + break; + + default: + __format_spec::__throw_invalid_type_format_error(__id); + } +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_char(__parser<_CharT>& __parser, const char* __id) { + switch (__parser.__type_) { + case __format_spec::__type::__default: + case __format_spec::__type::__char: + case __format_spec::__type::__debug: + __format_spec::__process_display_type_char(__parser, __id); + break; + + case __format_spec::__type::__binary_lower_case: + case __format_spec::__type::__binary_upper_case: + case __format_spec::__type::__octal: + case __format_spec::__type::__decimal: + case __format_spec::__type::__hexadecimal_lower_case: + case __format_spec::__type::__hexadecimal_upper_case: + break; + + default: + __format_spec::__throw_invalid_type_format_error(__id); + } +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_integer(__parser<_CharT>& __parser, const char* __id) { + switch (__parser.__type_) { + case __format_spec::__type::__default: + case __format_spec::__type::__binary_lower_case: + case __format_spec::__type::__binary_upper_case: + case __format_spec::__type::__octal: + case __format_spec::__type::__decimal: + case __format_spec::__type::__hexadecimal_lower_case: + case __format_spec::__type::__hexadecimal_upper_case: + break; + + case __format_spec::__type::__char: + __format_spec::__process_display_type_char(__parser, __id); + break; + + default: + __format_spec::__throw_invalid_type_format_error(__id); + } +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr void __process_parsed_floating_point(__parser<_CharT>& __parser, const char* __id) { + switch (__parser.__type_) { + case __format_spec::__type::__default: + case __format_spec::__type::__hexfloat_lower_case: + case __format_spec::__type::__hexfloat_upper_case: + // Precision specific behavior will be handled later. + break; + case __format_spec::__type::__scientific_lower_case: + case __format_spec::__type::__scientific_upper_case: + case __format_spec::__type::__fixed_lower_case: + case __format_spec::__type::__fixed_upper_case: + case __format_spec::__type::__general_lower_case: + case __format_spec::__type::__general_upper_case: + if (!__parser.__precision_as_arg_ && __parser.__precision_ == -1) + // Set the default precision for the call to to_chars. + __parser.__precision_ = 6; + break; + + default: + __format_spec::__throw_invalid_type_format_error(__id); + } +} + +_LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_pointer(__format_spec::__type __type, const char* __id) { + switch (__type) { + case __format_spec::__type::__default: + case __format_spec::__type::__pointer_lower_case: + case __format_spec::__type::__pointer_upper_case: + break; + + default: + __format_spec::__throw_invalid_type_format_error(__id); + } +} + +template +struct __column_width_result { + /// The number of output columns. + size_t __width_; + /// One beyond the last code unit used in the estimation. + /// + /// This limits the original output to fit in the wanted number of columns. + _Iterator __last_; +}; + +template +__column_width_result(size_t, _Iterator) -> __column_width_result<_Iterator>; + +/// Since a column width can be two it's possible that the requested column +/// width can't be achieved. Depending on the intended usage the policy can be +/// selected. +/// - When used as precision the maximum width may not be exceeded and the +/// result should be "rounded down" to the previous boundary. +/// - When used as a width we're done once the minimum is reached, but +/// exceeding is not an issue. Rounding down is an issue since that will +/// result in writing fill characters. Therefore the result needs to be +/// "rounded up". +enum class __column_width_rounding { __down, __up }; + +# ifndef _LIBCPP_HAS_NO_UNICODE + +namespace __detail { +template +_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_Iterator> __estimate_column_width_grapheme_clustering( + _Iterator __first, _Iterator __last, size_t __maximum, __column_width_rounding __rounding) noexcept { + using _CharT = iter_value_t<_Iterator>; + __unicode::__extended_grapheme_cluster_view<_CharT> __view{__first, __last}; + + __column_width_result<_Iterator> __result{0, __first}; + while (__result.__last_ != __last && __result.__width_ <= __maximum) { + typename __unicode::__extended_grapheme_cluster_view<_CharT>::__cluster __cluster = __view.__consume(); + int __width = __width_estimation_table::__estimated_width(__cluster.__code_point_); + + // When the next entry would exceed the maximum width the previous width + // might be returned. For example when a width of 100 is requested the + // returned width might be 99, since the next code point has an estimated + // column width of 2. This depends on the rounding flag. + // When the maximum is exceeded the loop will abort the next iteration. + if (__rounding == __column_width_rounding::__down && __result.__width_ + __width > __maximum) + return __result; + + __result.__width_ += __width; + __result.__last_ = __cluster.__last_; + } + + return __result; +} + +} // namespace __detail + +// Unicode can be stored in several formats: UTF-8, UTF-16, and UTF-32. +// Depending on format the relation between the number of code units stored and +// the number of output columns differs. The first relation is the number of +// code units forming a code point. (The text assumes the code units are +// unsigned.) +// - UTF-8 The number of code units is between one and four. The first 127 +// Unicode code points match the ASCII character set. When the highest bit is +// set it means the code point has more than one code unit. +// - UTF-16: The number of code units is between 1 and 2. When the first +// code unit is in the range [0xd800,0xdfff) it means the code point uses two +// code units. +// - UTF-32: The number of code units is always one. +// +// The code point to the number of columns is specified in +// [format.string.std]/11. This list might change in the future. +// +// Another thing to be taken into account is Grapheme clustering. This means +// that in some cases multiple code points are combined one element in the +// output. For example: +// - an ASCII character with a combined diacritical mark +// - an emoji with a skin tone modifier +// - a group of combined people emoji to create a family +// - a combination of flag emoji +// +// See also: +// - [format.string.general]/11 +// - https://en.wikipedia.org/wiki/UTF-8#Encoding +// - https://en.wikipedia.org/wiki/UTF-16#U+D800_to_U+DFFF + +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_ascii(char32_t __c) { return __c < 0x80; } + +/// Determines the number of output columns needed to render the input. +/// +/// \note When the scanner encounters malformed Unicode it acts as-if every +/// code unit is a one column code point. Typically a terminal uses the same +/// strategy and replaces every malformed code unit with a one column +/// replacement character. +/// +/// \param __first Points to the first element of the input range. +/// \param __last Points beyond the last element of the input range. +/// \param __maximum The maximum number of output columns. The returned number +/// of estimated output columns will not exceed this value. +/// \param __rounding Selects the rounding method. +/// \c __down result.__width_ <= __maximum +/// \c __up result.__width_ <= __maximum + 1 +template ::const_iterator> +_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_Iterator> __estimate_column_width( + basic_string_view<_CharT> __str, size_t __maximum, __column_width_rounding __rounding) noexcept { + // The width estimation is done in two steps: + // - Quickly process for the ASCII part. ASCII has the following properties + // - One code unit is one code point + // - Every code point has an estimated width of one + // - When needed it will a Unicode Grapheme clustering algorithm to find + // the proper place for truncation. + + if (__str.empty() || __maximum == 0) + return {0, __str.begin()}; + + // ASCII has one caveat; when an ASCII character is followed by a non-ASCII + // character they might be part of an extended grapheme cluster. For example: + // an ASCII letter and a COMBINING ACUTE ACCENT + // The truncate should happen after the COMBINING ACUTE ACCENT. Therefore we + // need to scan one code unit beyond the requested precision. When this code + // unit is non-ASCII we omit the current code unit and let the Grapheme + // clustering algorithm do its work. + auto __it = __str.begin(); + if (__format_spec::__is_ascii(*__it)) { + do { + --__maximum; + ++__it; + if (__it == __str.end()) + return {__str.size(), __str.end()}; + + if (__maximum == 0) { + if (__format_spec::__is_ascii(*__it)) + return {static_cast(__it - __str.begin()), __it}; + + break; + } + } while (__format_spec::__is_ascii(*__it)); + --__it; + ++__maximum; + } + + ptrdiff_t __ascii_size = __it - __str.begin(); + __column_width_result __result = + __detail::__estimate_column_width_grapheme_clustering(__it, __str.end(), __maximum, __rounding); + + __result.__width_ += __ascii_size; + return __result; +} +# else // !defined(_LIBCPP_HAS_NO_UNICODE) +template +_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result::const_iterator> +__estimate_column_width(basic_string_view<_CharT> __str, size_t __maximum, __column_width_rounding) noexcept { + // When Unicode isn't supported assume ASCII and every code unit is one code + // point. In ASCII the estimated column width is always one. Thus there's no + // need for rounding. + size_t __width = std::min(__str.size(), __maximum); + return {__width, __str.begin() + __width}; +} + +# endif // !defined(_LIBCPP_HAS_NO_UNICODE) + +} // namespace __format_spec + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_PARSER_STD_FORMAT_SPEC_H diff --git a/libcxx/include/__cxx03/__format/range_default_formatter.h b/libcxx/include/__cxx03/__format/range_default_formatter.h new file mode 100644 index 0000000000000000000000000000000000000000..b35223ae933291c4aafecbd7040a38e38524f3d2 --- /dev/null +++ b/libcxx/include/__cxx03/__format/range_default_formatter.h @@ -0,0 +1,214 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H +#define _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#include <__algorithm/ranges_copy.h> +#include <__chrono/statically_widen.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__format/concepts.h> +#include <__format/formatter.h> +#include <__format/range_formatter.h> +#include <__iterator/back_insert_iterator.h> +#include <__ranges/concepts.h> +#include <__ranges/data.h> +#include <__ranges/from_range.h> +#include <__ranges/size.h> +#include <__type_traits/conditional.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/pair.h> +#include + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template +concept __const_formattable_range = + ranges::input_range && formattable, _CharT>; + +template +using __fmt_maybe_const = conditional_t<__const_formattable_range<_Rp, _CharT>, const _Rp, _Rp>; + +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wshadow") +_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshadow") +// This shadows map, set, and string. +enum class range_format { disabled, map, set, sequence, string, debug_string }; +_LIBCPP_DIAGNOSTIC_POP + +// There is no definition of this struct, it's purely intended to be used to +// generate diagnostics. +template +struct _LIBCPP_TEMPLATE_VIS __instantiated_the_primary_template_of_format_kind; + +template +constexpr range_format format_kind = [] { + // [format.range.fmtkind]/1 + // A program that instantiates the primary template of format_kind is ill-formed. + static_assert(sizeof(_Rp) != sizeof(_Rp), "create a template specialization of format_kind for your type"); + return range_format::disabled; +}(); + +template + requires same_as<_Rp, remove_cvref_t<_Rp>> +inline constexpr range_format format_kind<_Rp> = [] { + // [format.range.fmtkind]/2 + + // 2.1 If same_as>, R> is true, + // Otherwise format_kind is range_format::disabled. + if constexpr (same_as>, _Rp>) + return range_format::disabled; + // 2.2 Otherwise, if the qualified-id R::key_type is valid and denotes a type: + else if constexpr (requires { typename _Rp::key_type; }) { + // 2.2.1 If the qualified-id R::mapped_type is valid and denotes a type ... + if constexpr (requires { typename _Rp::mapped_type; } && + // 2.2.1 ... If either U is a specialization of pair or U is a specialization + // of tuple and tuple_size_v == 2 + __fmt_pair_like>>) + return range_format::map; + else + // 2.2.2 Otherwise format_kind is range_format::set. + return range_format::set; + } else + // 2.3 Otherwise, format_kind is range_format::sequence. + return range_format::sequence; +}(); + +template +struct _LIBCPP_TEMPLATE_VIS __range_default_formatter; + +// Required specializations + +template +struct _LIBCPP_TEMPLATE_VIS __range_default_formatter { +private: + using __maybe_const_r = __fmt_maybe_const<_Rp, _CharT>; + range_formatter>, _CharT> __underlying_; + +public: + _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept { + __underlying_.set_separator(__separator); + } + _LIBCPP_HIDE_FROM_ABI constexpr void + set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept { + __underlying_.set_brackets(__opening_bracket, __closing_bracket); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return __underlying_.parse(__ctx); + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator + format(__maybe_const_r& __range, _FormatContext& __ctx) const { + return __underlying_.format(__range, __ctx); + } +}; + +template +struct _LIBCPP_TEMPLATE_VIS __range_default_formatter { +private: + using __maybe_const_map = __fmt_maybe_const<_Rp, _CharT>; + using __element_type = remove_cvref_t>; + range_formatter<__element_type, _CharT> __underlying_; + +public: + _LIBCPP_HIDE_FROM_ABI constexpr __range_default_formatter() + requires(__fmt_pair_like<__element_type>) + { + __underlying_.set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}")); + __underlying_.underlying().set_brackets({}, {}); + __underlying_.underlying().set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": ")); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return __underlying_.parse(__ctx); + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator + format(__maybe_const_map& __range, _FormatContext& __ctx) const { + return __underlying_.format(__range, __ctx); + } +}; + +template +struct _LIBCPP_TEMPLATE_VIS __range_default_formatter { +private: + using __maybe_const_set = __fmt_maybe_const<_Rp, _CharT>; + using __element_type = remove_cvref_t>; + range_formatter<__element_type, _CharT> __underlying_; + +public: + _LIBCPP_HIDE_FROM_ABI constexpr __range_default_formatter() { + __underlying_.set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}")); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + return __underlying_.parse(__ctx); + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator + format(__maybe_const_set& __range, _FormatContext& __ctx) const { + return __underlying_.format(__range, __ctx); + } +}; + +template + requires(_Kp == range_format::string || _Kp == range_format::debug_string) +struct _LIBCPP_TEMPLATE_VIS __range_default_formatter<_Kp, _Rp, _CharT> { +private: + // This deviates from the Standard, there the exposition only type is + // formatter, charT> underlying_; + // Using a string_view allows the format function to avoid a copy of the + // input range when it is a contigious range. + formatter, _CharT> __underlying_; + +public: + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + typename _ParseContext::iterator __i = __underlying_.parse(__ctx); + if constexpr (_Kp == range_format::debug_string) + __underlying_.set_debug_format(); + return __i; + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator + format(conditional_t, const _Rp&, _Rp&> __range, _FormatContext& __ctx) const { + // When the range is contiguous use a basic_string_view instead to avoid a + // copy of the underlying data. The basic_string_view formatter + // specialization is the "basic" string formatter in libc++. + if constexpr (ranges::contiguous_range<_Rp> && std::ranges::sized_range<_Rp>) + return __underlying_.format(basic_string_view<_CharT>{ranges::data(__range), ranges::size(__range)}, __ctx); + else + return __underlying_.format(basic_string<_CharT>{from_range, __range}, __ctx); + } +}; + +template + requires(format_kind<_Rp> != range_format::disabled && formattable, _CharT>) +struct _LIBCPP_TEMPLATE_VIS formatter<_Rp, _CharT> : __range_default_formatter, _Rp, _CharT> {}; + +#endif //_LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H diff --git a/libcxx/include/__cxx03/__format/range_formatter.h b/libcxx/include/__cxx03/__format/range_formatter.h new file mode 100644 index 0000000000000000000000000000000000000000..6915630743493705f63c7bbfb8af18d3f9a29671 --- /dev/null +++ b/libcxx/include/__cxx03/__format/range_formatter.h @@ -0,0 +1,264 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_RANGE_FORMATTER_H +#define _LIBCPP___FORMAT_RANGE_FORMATTER_H + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#include <__algorithm/ranges_copy.h> +#include <__chrono/statically_widen.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__format/buffer.h> +#include <__format/concepts.h> +#include <__format/format_context.h> +#include <__format/format_error.h> +#include <__format/formatter.h> +#include <__format/formatter_output.h> +#include <__format/parser_std_format_spec.h> +#include <__iterator/back_insert_iterator.h> +#include <__ranges/concepts.h> +#include <__ranges/data.h> +#include <__ranges/from_range.h> +#include <__ranges/size.h> +#include <__type_traits/remove_cvref.h> +#include + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template + requires same_as, _Tp> && formattable<_Tp, _CharT> +struct _LIBCPP_TEMPLATE_VIS range_formatter { + _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept { + __separator_ = __separator; + } + _LIBCPP_HIDE_FROM_ABI constexpr void + set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept { + __opening_bracket_ = __opening_bracket; + __closing_bracket_ = __closing_bracket; + } + + _LIBCPP_HIDE_FROM_ABI constexpr formatter<_Tp, _CharT>& underlying() noexcept { return __underlying_; } + _LIBCPP_HIDE_FROM_ABI constexpr const formatter<_Tp, _CharT>& underlying() const noexcept { return __underlying_; } + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { + auto __begin = __parser_.__parse(__ctx, __format_spec::__fields_range); + auto __end = __ctx.end(); + // Note the cases where __begin == __end in this code only happens when the + // replacement-field has no terminating }, or when the parse is manually + // called with a format-spec. The former is an error and the latter means + // using a formatter without the format functions or print. + if (__begin == __end) [[unlikely]] + return __parse_empty_range_underlying_spec(__ctx, __begin); + + // The n field overrides a possible m type, therefore delay applying the + // effect of n until the type has been procesed. + __parse_type(__begin, __end); + if (__parser_.__clear_brackets_) + set_brackets({}, {}); + if (__begin == __end) [[unlikely]] + return __parse_empty_range_underlying_spec(__ctx, __begin); + + bool __has_range_underlying_spec = *__begin == _CharT(':'); + if (__has_range_underlying_spec) { + // range-underlying-spec: + // : format-spec + ++__begin; + } else if (__begin != __end && *__begin != _CharT('}')) + // When there is no underlaying range the current parse should have + // consumed the format-spec. If not, the not consumed input will be + // processed by the underlying. For example {:-} for a range in invalid, + // the sign field is not present. Without this check the underlying_ will + // get -} as input which my be valid. + std::__throw_format_error("The format specifier should consume the input or end with a '}'"); + + __ctx.advance_to(__begin); + __begin = __underlying_.parse(__ctx); + + // This test should not be required if __has_range_underlying_spec is false. + // However this test makes sure the underlying formatter left the parser in + // a valid state. (Note this is not a full protection against evil parsers. + // For example + // } this is test for the next argument {} + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ + // could consume more than it should. + if (__begin != __end && *__begin != _CharT('}')) + std::__throw_format_error("The format specifier should consume the input or end with a '}'"); + + if (__parser_.__type_ != __format_spec::__type::__default) { + // [format.range.formatter]/6 + // If the range-type is s or ?s, then there shall be no n option and no + // range-underlying-spec. + if (__parser_.__clear_brackets_) { + if (__parser_.__type_ == __format_spec::__type::__string) + std::__throw_format_error("The n option and type s can't be used together"); + std::__throw_format_error("The n option and type ?s can't be used together"); + } + if (__has_range_underlying_spec) { + if (__parser_.__type_ == __format_spec::__type::__string) + std::__throw_format_error("Type s and an underlying format specification can't be used together"); + std::__throw_format_error("Type ?s and an underlying format specification can't be used together"); + } + } else if (!__has_range_underlying_spec) + std::__set_debug_format(__underlying_); + + return __begin; + } + + template + requires formattable, _CharT> && + same_as>, _Tp> + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(_Rp&& __range, _FormatContext& __ctx) const { + __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx); + + if (!__specs.__has_width()) + return __format_range(__range, __ctx, __specs); + + // The size of the buffer needed is: + // - open bracket characters + // - close bracket character + // - n elements where every element may have a different size + // - (n -1) separators + // The size of the element is hard to predict, knowing the type helps but + // it depends on the format-spec. As an initial estimate we guess 6 + // characters. + // Typically both brackets are 1 character and the separator is 2 + // characters. Which means there will be + // (n - 1) * 2 + 1 + 1 = n * 2 character + // So estimate 8 times the range size as buffer. + std::size_t __capacity_hint = 0; + if constexpr (std::ranges::sized_range<_Rp>) + __capacity_hint = 8 * ranges::size(__range); + __format::__retarget_buffer<_CharT> __buffer{__capacity_hint}; + basic_format_context::__iterator, _CharT> __c{ + __buffer.__make_output_iterator(), __ctx}; + + __format_range(__range, __c, __specs); + + return __formatter::__write_string_no_precision(__buffer.__view(), __ctx.out(), __specs); + } + + template + typename _FormatContext::iterator _LIBCPP_HIDE_FROM_ABI + __format_range(_Rp&& __range, _FormatContext& __ctx, __format_spec::__parsed_specifications<_CharT> __specs) const { + if constexpr (same_as<_Tp, _CharT>) { + switch (__specs.__std_.__type_) { + case __format_spec::__type::__string: + case __format_spec::__type::__debug: + return __format_as_string(__range, __ctx, __specs.__std_.__type_ == __format_spec::__type::__debug); + default: + return __format_as_sequence(__range, __ctx); + } + } else + return __format_as_sequence(__range, __ctx); + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator + __format_as_string(_Rp&& __range, _FormatContext& __ctx, bool __debug_format) const { + // When the range is contiguous use a basic_string_view instead to avoid a + // copy of the underlying data. The basic_string_view formatter + // specialization is the "basic" string formatter in libc++. + if constexpr (ranges::contiguous_range<_Rp> && std::ranges::sized_range<_Rp>) { + std::formatter, _CharT> __formatter; + if (__debug_format) + __formatter.set_debug_format(); + return __formatter.format( + basic_string_view<_CharT>{ + ranges::data(__range), + ranges::size(__range), + }, + __ctx); + } else { + std::formatter, _CharT> __formatter; + if (__debug_format) + __formatter.set_debug_format(); + return __formatter.format(basic_string<_CharT>{from_range, __range}, __ctx); + } + } + + template + _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator + __format_as_sequence(_Rp&& __range, _FormatContext& __ctx) const { + __ctx.advance_to(ranges::copy(__opening_bracket_, __ctx.out()).out); + bool __use_separator = false; + for (auto&& __e : __range) { + if (__use_separator) + __ctx.advance_to(ranges::copy(__separator_, __ctx.out()).out); + else + __use_separator = true; + + __ctx.advance_to(__underlying_.format(__e, __ctx)); + } + + return ranges::copy(__closing_bracket_, __ctx.out()).out; + } + + __format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__left}; + +private: + template + _LIBCPP_HIDE_FROM_ABI constexpr void __parse_type(_Iterator& __begin, _Iterator __end) { + switch (*__begin) { + case _CharT('m'): + if constexpr (__fmt_pair_like<_Tp>) { + set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}")); + set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ", ")); + ++__begin; + } else + std::__throw_format_error("Type m requires a pair or a tuple with two elements"); + break; + + case _CharT('s'): + if constexpr (same_as<_Tp, _CharT>) { + __parser_.__type_ = __format_spec::__type::__string; + ++__begin; + } else + std::__throw_format_error("Type s requires character type as formatting argument"); + break; + + case _CharT('?'): + ++__begin; + if (__begin == __end || *__begin != _CharT('s')) + std::__throw_format_error("The format specifier should consume the input or end with a '}'"); + if constexpr (same_as<_Tp, _CharT>) { + __parser_.__type_ = __format_spec::__type::__debug; + ++__begin; + } else + std::__throw_format_error("Type ?s requires character type as formatting argument"); + } + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator + __parse_empty_range_underlying_spec(_ParseContext& __ctx, typename _ParseContext::iterator __begin) { + __ctx.advance_to(__begin); + [[maybe_unused]] typename _ParseContext::iterator __result = __underlying_.parse(__ctx); + _LIBCPP_ASSERT_INTERNAL(__result == __begin, + "the underlying's parse function should not advance the input beyond the end of the input"); + return __begin; + } + + formatter<_Tp, _CharT> __underlying_; + basic_string_view<_CharT> __separator_ = _LIBCPP_STATICALLY_WIDEN(_CharT, ", "); + basic_string_view<_CharT> __opening_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, "["); + basic_string_view<_CharT> __closing_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, "]"); +}; + +#endif //_LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_RANGE_FORMATTER_H diff --git a/libcxx/include/__cxx03/__format/unicode.h b/libcxx/include/__cxx03/__format/unicode.h new file mode 100644 index 0000000000000000000000000000000000000000..de7d0fea1df56af99881a72079d8dd9decef5e41 --- /dev/null +++ b/libcxx/include/__cxx03/__format/unicode.h @@ -0,0 +1,602 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_UNICODE_H +#define _LIBCPP___FORMAT_UNICODE_H + +#include <__assert> +#include <__bit/countl.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__format/extended_grapheme_cluster_table.h> +#include <__format/indic_conjunct_break_table.h> +#include <__iterator/concepts.h> +#include <__iterator/readable_traits.h> // iter_value_t +#include <__utility/unreachable.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __unicode { + +// Helper struct for the result of a consume operation. +// +// The status value for a correct code point is 0. This allows a valid value to +// be used without masking. +// When the decoding fails it know the number of code units affected. For the +// current use-cases that value is not needed, therefore it is not stored. +// The escape routine needs the number of code units for both a valid and +// invalid character and keeps track of it itself. Doing it in this result +// unconditionally would give some overhead when the value is unneeded. +struct __consume_result { + // When __status == __ok it contains the decoded code point. + // Else it contains the replacement character U+FFFD + char32_t __code_point : 31; + + enum : char32_t { + // Consumed a well-formed code point. + __ok = 0, + // Encountered invalid UTF-8 + __error = 1 + } __status : 1 {__ok}; +}; +static_assert(sizeof(__consume_result) == sizeof(char32_t)); + +# ifndef _LIBCPP_HAS_NO_UNICODE + +/// Implements the grapheme cluster boundary rules +/// +/// These rules are used to implement format's width estimation as stated in +/// [format.string.std]/11 +/// +/// The Standard refers to UAX \#29 for Unicode 12.0.0 +/// https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules +/// +/// The data tables used are +/// https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakProperty.txt +/// https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt +/// https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakTest.txt (for testing only) + +inline constexpr char32_t __replacement_character = U'\ufffd'; + +// The error of a consume operation. +// +// This sets the code point to the replacement character. This code point does +// not participate in the grapheme clustering, so grapheme clustering code can +// ignore the error status and always use the code point. +inline constexpr __consume_result __consume_result_error{__replacement_character, __consume_result::__error}; + +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool __is_high_surrogate(char32_t __value) { + return __value >= 0xd800 && __value <= 0xdbff; +} + +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool __is_low_surrogate(char32_t __value) { + return __value >= 0xdc00 && __value <= 0xdfff; +} + +// https://www.unicode.org/glossary/#surrogate_code_point +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool __is_surrogate(char32_t __value) { + return __value >= 0xd800 && __value <= 0xdfff; +} + +// https://www.unicode.org/glossary/#code_point +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool __is_code_point(char32_t __value) { + return __value <= 0x10ffff; +} + +// https://www.unicode.org/glossary/#unicode_scalar_value +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool __is_scalar_value(char32_t __value) { + return __unicode::__is_code_point(__value) && !__unicode::__is_surrogate(__value); +} + +template + requires same_as, char> +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_continuation(_Iterator __char, int __count) { + do { + if ((*__char & 0b1100'0000) != 0b1000'0000) + return false; + --__count; + ++__char; + } while (__count); + return true; +} + +/// Helper class to extract a code unit from a Unicode character range. +/// +/// The stored range is a view. There are multiple specialization for different +/// character types. +template +class __code_point_view; + +/// UTF-8 specialization. +template <> +class __code_point_view { + using _Iterator = basic_string_view::const_iterator; + +public: + _LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(_Iterator __first, _Iterator __last) + : __first_(__first), __last_(__last) {} + + _LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; } + _LIBCPP_HIDE_FROM_ABI constexpr _Iterator __position() const noexcept { return __first_; } + + // https://www.unicode.org/versions/latest/ch03.pdf#G7404 + // Based on Table 3-7, Well-Formed UTF-8 Byte Sequences + // + // Code Points First Byte Second Byte Third Byte Fourth Byte Remarks + // U+0000..U+007F 00..7F U+0000..U+007F 1 code unit range + // C0..C1 80..BF invalid overlong encoding + // U+0080..U+07FF C2..DF 80..BF U+0080..U+07FF 2 code unit range + // E0 80..9F 80..BF invalid overlong encoding + // U+0800..U+0FFF E0 A0..BF 80..BF U+0800..U+FFFF 3 code unit range + // U+1000..U+CFFF E1..EC 80..BF 80..BF + // U+D000..U+D7FF ED 80..9F 80..BF + // U+D800..U+DFFF ED A0..BF 80..BF invalid encoding of surrogate code point + // U+E000..U+FFFF EE..EF 80..BF 80..BF + // F0 80..8F 80..BF 80..BF invalid overlong encoding + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF U+10000..U+10FFFF 4 code unit range + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + // F4 90..BF 80..BF 80..BF U+110000.. invalid code point range + // + // Unlike other parsers, these invalid entries are tested after decoding. + // - The parser always needs to consume these code units + // - The code is optimized for well-formed UTF-8 + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept { + _LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "can't move beyond the end of input"); + + // Based on the number of leading 1 bits the number of code units in the + // code point can be determined. See + // https://en.wikipedia.org/wiki/UTF-8#Encoding + switch (std::countl_one(static_cast(*__first_))) { + case 0: + return {static_cast(*__first_++)}; + + case 2: { + if (__last_ - __first_ < 2 || !__unicode::__is_continuation(__first_ + 1, 1)) [[unlikely]] + break; + + char32_t __value = static_cast(*__first_++) & 0x1f; + __value <<= 6; + __value |= static_cast(*__first_++) & 0x3f; + + // These values should be encoded in 1 UTF-8 code unit. + if (__value < 0x0080) [[unlikely]] + return __consume_result_error; + + return {__value}; + } + + case 3: { + if (__last_ - __first_ < 3 || !__unicode::__is_continuation(__first_ + 1, 2)) [[unlikely]] + break; + + char32_t __value = static_cast(*__first_++) & 0x0f; + __value <<= 6; + __value |= static_cast(*__first_++) & 0x3f; + __value <<= 6; + __value |= static_cast(*__first_++) & 0x3f; + + // These values should be encoded in 1 or 2 UTF-8 code units. + if (__value < 0x0800) [[unlikely]] + return __consume_result_error; + + // A surrogate value is always encoded in 3 UTF-8 code units. + if (__unicode::__is_surrogate(__value)) [[unlikely]] + return __consume_result_error; + + return {__value}; + } + + case 4: { + if (__last_ - __first_ < 4 || !__unicode::__is_continuation(__first_ + 1, 3)) [[unlikely]] + break; + + char32_t __value = static_cast(*__first_++) & 0x07; + __value <<= 6; + __value |= static_cast(*__first_++) & 0x3f; + __value <<= 6; + __value |= static_cast(*__first_++) & 0x3f; + __value <<= 6; + __value |= static_cast(*__first_++) & 0x3f; + + // These values should be encoded in 1, 2, or 3 UTF-8 code units. + if (__value < 0x10000) [[unlikely]] + return __consume_result_error; + + // A value too large is always encoded in 4 UTF-8 code units. + if (!__unicode::__is_code_point(__value)) [[unlikely]] + return __consume_result_error; + + return {__value}; + } + } + // An invalid number of leading ones can be garbage or a code unit in the + // middle of a code point. By consuming one code unit the parser may get + // "in sync" after a few code units. + ++__first_; + return __consume_result_error; + } + +private: + _Iterator __first_; + _Iterator __last_; +}; + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_surrogate_pair_high(wchar_t __value) { + return __value >= 0xd800 && __value <= 0xdbff; +} + +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_surrogate_pair_low(wchar_t __value) { + return __value >= 0xdc00 && __value <= 0xdfff; +} + +/// This specialization depends on the size of wchar_t +/// - 2 UTF-16 (for example Windows and AIX) +/// - 4 UTF-32 (for example Linux) +template <> +class __code_point_view { + using _Iterator = typename basic_string_view::const_iterator; + +public: + static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "sizeof(wchar_t) has a not implemented value"); + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(_Iterator __first, _Iterator __last) + : __first_(__first), __last_(__last) {} + + _LIBCPP_HIDE_FROM_ABI constexpr _Iterator __position() const noexcept { return __first_; } + _LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept { + _LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "can't move beyond the end of input"); + + char32_t __value = static_cast(*__first_++); + if constexpr (sizeof(wchar_t) == 2) { + if (__unicode::__is_low_surrogate(__value)) [[unlikely]] + return __consume_result_error; + + if (__unicode::__is_high_surrogate(__value)) { + if (__first_ == __last_ || !__unicode::__is_low_surrogate(static_cast(*__first_))) [[unlikely]] + return __consume_result_error; + + __value -= 0xd800; + __value <<= 10; + __value += static_cast(*__first_++) - 0xdc00; + __value += 0x10000; + + if (!__unicode::__is_code_point(__value)) [[unlikely]] + return __consume_result_error; + } + } else { + if (!__unicode::__is_scalar_value(__value)) [[unlikely]] + return __consume_result_error; + } + + return {__value}; + } + +private: + _Iterator __first_; + _Iterator __last_; +}; +# endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS + +// State machine to implement the Extended Grapheme Cluster Boundary +// +// The exact rules may change between Unicode versions. +// This implements the extended rules see +// https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries +class __extended_grapheme_cluster_break { + using __EGC_property = __extended_grapheme_custer_property_boundary::__property; + using __inCB_property = __indic_conjunct_break::__property; + +public: + _LIBCPP_HIDE_FROM_ABI constexpr explicit __extended_grapheme_cluster_break(char32_t __first_code_point) + : __prev_code_point_(__first_code_point), + __prev_property_(__extended_grapheme_custer_property_boundary::__get_property(__first_code_point)) { + // Initializes the active rule. + if (__prev_property_ == __EGC_property::__Extended_Pictographic) + __active_rule_ = __rule::__GB11_emoji; + else if (__prev_property_ == __EGC_property::__Regional_Indicator) + __active_rule_ = __rule::__GB12_GB13_regional_indicator; + else if (__indic_conjunct_break::__get_property(__first_code_point) == __inCB_property::__Consonant) + __active_rule_ = __rule::__GB9c_indic_conjunct_break; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(char32_t __next_code_point) { + __EGC_property __next_property = __extended_grapheme_custer_property_boundary::__get_property(__next_code_point); + bool __result = __evaluate(__next_code_point, __next_property); + __prev_code_point_ = __next_code_point; + __prev_property_ = __next_property; + return __result; + } + + // The code point whose break propery are considered during the next + // evaluation cyle. + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr char32_t __current_code_point() const { return __prev_code_point_; } + +private: + // The naming of the identifiers matches the Unicode standard. + // NOLINTBEGIN(readability-identifier-naming) + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + __evaluate(char32_t __next_code_point, __EGC_property __next_property) { + switch (__active_rule_) { + case __rule::__none: + return __evaluate_none(__next_code_point, __next_property); + case __rule::__GB9c_indic_conjunct_break: + return __evaluate_GB9c_indic_conjunct_break(__next_code_point, __next_property); + case __rule::__GB11_emoji: + return __evaluate_GB11_emoji(__next_code_point, __next_property); + case __rule::__GB12_GB13_regional_indicator: + return __evaluate_GB12_GB13_regional_indicator(__next_code_point, __next_property); + } + __libcpp_unreachable(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr bool __evaluate_none(char32_t __next_code_point, __EGC_property __next_property) { + // *** Break at the start and end of text, unless the text is empty. *** + + _LIBCPP_ASSERT_INTERNAL(__prev_property_ != __EGC_property::__sot, "should be handled in the constructor"); // GB1 + _LIBCPP_ASSERT_INTERNAL(__prev_property_ != __EGC_property::__eot, "should be handled by our caller"); // GB2 + + // *** Do not break between a CR and LF. Otherwise, break before and after controls. *** + if (__prev_property_ == __EGC_property::__CR && __next_property == __EGC_property::__LF) // GB3 + return false; + + if (__prev_property_ == __EGC_property::__Control || __prev_property_ == __EGC_property::__CR || + __prev_property_ == __EGC_property::__LF) // GB4 + return true; + + if (__next_property == __EGC_property::__Control || __next_property == __EGC_property::__CR || + __next_property == __EGC_property::__LF) // GB5 + return true; + + // *** Do not break Hangul syllable sequences. *** + if (__prev_property_ == __EGC_property::__L && + (__next_property == __EGC_property::__L || __next_property == __EGC_property::__V || + __next_property == __EGC_property::__LV || __next_property == __EGC_property::__LVT)) // GB6 + return false; + + if ((__prev_property_ == __EGC_property::__LV || __prev_property_ == __EGC_property::__V) && + (__next_property == __EGC_property::__V || __next_property == __EGC_property::__T)) // GB7 + return false; + + if ((__prev_property_ == __EGC_property::__LVT || __prev_property_ == __EGC_property::__T) && + __next_property == __EGC_property::__T) // GB8 + return false; + + // *** Do not break before extending characters or ZWJ. *** + if (__next_property == __EGC_property::__Extend || __next_property == __EGC_property::__ZWJ) + return false; // GB9 + + // *** Do not break before SpacingMarks, or after Prepend characters. *** + if (__next_property == __EGC_property::__SpacingMark) // GB9a + return false; + + if (__prev_property_ == __EGC_property::__Prepend) // GB9b + return false; + + // *** Do not break within certain combinations with Indic_Conjunct_Break (InCB)=Linker. *** + if (__indic_conjunct_break::__get_property(__next_code_point) == __inCB_property::__Consonant) { + __active_rule_ = __rule::__GB9c_indic_conjunct_break; + __GB9c_indic_conjunct_break_state_ = __GB9c_indic_conjunct_break_state::__Consonant; + return true; + } + + // *** Do not break within emoji modifier sequences or emoji zwj sequences. *** + if (__next_property == __EGC_property::__Extended_Pictographic) { + __active_rule_ = __rule::__GB11_emoji; + __GB11_emoji_state_ = __GB11_emoji_state::__Extended_Pictographic; + return true; + } + + // *** Do not break within emoji flag sequences *** + + // That is, do not break between regional indicator (RI) symbols if there + // is an odd number of RI characters before the break point. + if (__next_property == __EGC_property::__Regional_Indicator) { // GB12 + GB13 + __active_rule_ = __rule::__GB12_GB13_regional_indicator; + return true; + } + + // *** Otherwise, break everywhere. *** + return true; // GB999 + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + __evaluate_GB9c_indic_conjunct_break(char32_t __next_code_point, __EGC_property __next_property) { + __inCB_property __break = __indic_conjunct_break::__get_property(__next_code_point); + if (__break == __inCB_property::__none) { + __active_rule_ = __rule::__none; + return __evaluate_none(__next_code_point, __next_property); + } + + switch (__GB9c_indic_conjunct_break_state_) { + case __GB9c_indic_conjunct_break_state::__Consonant: + if (__break == __inCB_property::__Extend) { + return false; + } + if (__break == __inCB_property::__Linker) { + __GB9c_indic_conjunct_break_state_ = __GB9c_indic_conjunct_break_state::__Linker; + return false; + } + __active_rule_ = __rule::__none; + return __evaluate_none(__next_code_point, __next_property); + + case __GB9c_indic_conjunct_break_state::__Linker: + if (__break == __inCB_property::__Extend) { + return false; + } + if (__break == __inCB_property::__Linker) { + return false; + } + if (__break == __inCB_property::__Consonant) { + __GB9c_indic_conjunct_break_state_ = __GB9c_indic_conjunct_break_state::__Consonant; + return false; + } + __active_rule_ = __rule::__none; + return __evaluate_none(__next_code_point, __next_property); + } + __libcpp_unreachable(); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + __evaluate_GB11_emoji(char32_t __next_code_point, __EGC_property __next_property) { + switch (__GB11_emoji_state_) { + case __GB11_emoji_state::__Extended_Pictographic: + if (__next_property == __EGC_property::__Extend) { + __GB11_emoji_state_ = __GB11_emoji_state::__Extend; + return false; + } + [[fallthrough]]; + case __GB11_emoji_state::__Extend: + if (__next_property == __EGC_property::__ZWJ) { + __GB11_emoji_state_ = __GB11_emoji_state::__ZWJ; + return false; + } + if (__next_property == __EGC_property::__Extend) + return false; + __active_rule_ = __rule::__none; + return __evaluate_none(__next_code_point, __next_property); + + case __GB11_emoji_state::__ZWJ: + if (__next_property == __EGC_property::__Extended_Pictographic) { + __GB11_emoji_state_ = __GB11_emoji_state::__Extended_Pictographic; + return false; + } + __active_rule_ = __rule::__none; + return __evaluate_none(__next_code_point, __next_property); + } + __libcpp_unreachable(); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool + __evaluate_GB12_GB13_regional_indicator(char32_t __next_code_point, __EGC_property __next_property) { + __active_rule_ = __rule::__none; + if (__next_property == __EGC_property::__Regional_Indicator) + return false; + return __evaluate_none(__next_code_point, __next_property); + } + + char32_t __prev_code_point_; + __EGC_property __prev_property_; + + enum class __rule { + __none, + __GB9c_indic_conjunct_break, + __GB11_emoji, + __GB12_GB13_regional_indicator, + }; + __rule __active_rule_ = __rule::__none; + + enum class __GB11_emoji_state { + __Extended_Pictographic, + __Extend, + __ZWJ, + }; + __GB11_emoji_state __GB11_emoji_state_ = __GB11_emoji_state::__Extended_Pictographic; + + enum class __GB9c_indic_conjunct_break_state { + __Consonant, + __Linker, + }; + + __GB9c_indic_conjunct_break_state __GB9c_indic_conjunct_break_state_ = __GB9c_indic_conjunct_break_state::__Consonant; + + // NOLINTEND(readability-identifier-naming) +}; + +/// Helper class to extract an extended grapheme cluster from a Unicode character range. +/// +/// This function is used to determine the column width of an extended grapheme +/// cluster. In order to do that only the first code point is evaluated. +/// Therefore only this code point is extracted. +template +class __extended_grapheme_cluster_view { + using _Iterator = typename basic_string_view<_CharT>::const_iterator; + +public: + _LIBCPP_HIDE_FROM_ABI constexpr explicit __extended_grapheme_cluster_view(_Iterator __first, _Iterator __last) + : __code_point_view_(__first, __last), __at_break_(__code_point_view_.__consume().__code_point) {} + + struct __cluster { + /// The first code point of the extended grapheme cluster. + /// + /// The first code point is used to estimate the width of the extended + /// grapheme cluster. + char32_t __code_point_; + + /// Points one beyond the last code unit in the extended grapheme cluster. + /// + /// It's expected the caller has the start position and thus can determine + /// the code unit range of the extended grapheme cluster. + _Iterator __last_; + }; + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __cluster __consume() { + char32_t __code_point = __at_break_.__current_code_point(); + _Iterator __position = __code_point_view_.__position(); + while (!__code_point_view_.__at_end()) { + if (__at_break_(__code_point_view_.__consume().__code_point)) + break; + __position = __code_point_view_.__position(); + } + return {__code_point, __position}; + } + +private: + __code_point_view<_CharT> __code_point_view_; + __extended_grapheme_cluster_break __at_break_; +}; + +template +__extended_grapheme_cluster_view(_Iterator, _Iterator) -> __extended_grapheme_cluster_view>; + +# else // _LIBCPP_HAS_NO_UNICODE + +// For ASCII every character is a "code point". +// This makes it easier to write code agnostic of the _LIBCPP_HAS_NO_UNICODE define. +template +class __code_point_view { + using _Iterator = typename basic_string_view<_CharT>::const_iterator; + +public: + _LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(_Iterator __first, _Iterator __last) + : __first_(__first), __last_(__last) {} + + _LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; } + _LIBCPP_HIDE_FROM_ABI constexpr _Iterator __position() const noexcept { return __first_; } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept { + _LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "can't move beyond the end of input"); + return {static_cast(*__first_++)}; + } + +private: + _Iterator __first_; + _Iterator __last_; +}; + +# endif // _LIBCPP_HAS_NO_UNICODE + +} // namespace __unicode + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_UNICODE_H diff --git a/libcxx/include/__cxx03/__format/width_estimation_table.h b/libcxx/include/__cxx03/__format/width_estimation_table.h new file mode 100644 index 0000000000000000000000000000000000000000..11f61dea18d696d60741875882a381ee8e879fc1 --- /dev/null +++ b/libcxx/include/__cxx03/__format/width_estimation_table.h @@ -0,0 +1,270 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// WARNING, this entire header is generated by +// utils/generate_width_estimation_table.py +// DO NOT MODIFY! + +// UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE +// +// See Terms of Use +// for definitions of Unicode Inc.'s Data Files and Software. +// +// NOTICE TO USER: Carefully read the following legal agreement. +// BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +// DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +// YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +// TERMS AND CONDITIONS OF THIS AGREEMENT. +// IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +// THE DATA FILES OR SOFTWARE. +// +// COPYRIGHT AND PERMISSION NOTICE +// +// Copyright (c) 1991-2022 Unicode, Inc. All rights reserved. +// Distributed under the Terms of Use in https://www.unicode.org/copyright.html. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of the Unicode data files and any associated documentation +// (the "Data Files") or Unicode software and any associated documentation +// (the "Software") to deal in the Data Files or Software +// without restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, and/or sell copies of +// the Data Files or Software, and to permit persons to whom the Data Files +// or Software are furnished to do so, provided that either +// (a) this copyright and permission notice appear with all copies +// of the Data Files or Software, or +// (b) this copyright and permission notice appear in associated +// Documentation. +// +// THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS. +// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +// NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +// DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THE DATA FILES OR SOFTWARE. +// +// Except as contained in this notice, the name of a copyright holder +// shall not be used in advertising or otherwise to promote the sale, +// use or other dealings in these Data Files or Software without prior +// written authorization of the copyright holder. + +#ifndef _LIBCPP___FORMAT_WIDTH_ESTIMATION_TABLE_H +#define _LIBCPP___FORMAT_WIDTH_ESTIMATION_TABLE_H + +#include <__algorithm/ranges_upper_bound.h> +#include <__config> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace __width_estimation_table { + +/// The entries of the characters with an estimated width of 2. +/// +/// Contains the entries for [format.string.std]/12 +/// - Any code point with the East_Asian_Width="W" or East_Asian_Width="F" +/// Derived Extracted Property as described by UAX #44 +/// - U+4DC0 - U+4DFF (Yijing Hexagram Symbols) +/// - U+1F300 - U+1F5FF (Miscellaneous Symbols and Pictographs) +/// - U+1F900 - U+1F9FF (Supplemental Symbols and Pictographs) +/// +/// The data is generated from +/// - https://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt +/// - The "overrides" in [format.string.std]/12 +/// +/// The format of EastAsianWidth.txt is two fields separated by a semicolon. +/// Field 0: Unicode code point value or range of code point values +/// Field 1: East_Asian_Width property, consisting of one of the following values: +/// "A", "F", "H", "N", "Na", "W" +/// - All code points, assigned or unassigned, that are not listed +/// explicitly are given the value "N". +/// - The unassigned code points in the following blocks default to "W": +/// CJK Unified Ideographs Extension A: U+3400..U+4DBF +/// CJK Unified Ideographs: U+4E00..U+9FFF +/// CJK Compatibility Ideographs: U+F900..U+FAFF +/// - All undesignated code points in Planes 2 and 3, whether inside or +/// outside of allocated blocks, default to "W": +/// Plane 2: U+20000..U+2FFFD +/// Plane 3: U+30000..U+3FFFD +/// +/// The table is similar to the table +/// __extended_grapheme_custer_property_boundary::__entries +/// which explains the details of these classes. The only difference is this +/// table lacks a property, thus having more bits available for the size. +/// +/// The maximum code point that has an estimated width of 2 is U+3FFFD. This +/// value can be encoded in 18 bits. Thus the upper 3 bits of the code point +/// are always 0. These 3 bits are used to enlarge the offset range. This +/// optimization reduces the table in Unicode 15 from 184 to 104 entries, +/// saving 320 bytes. +/// +/// The data has 2 values: +/// - bits [0, 13] The size of the range, allowing 16384 elements. +/// - bits [14, 31] The lower bound code point of the range. The upper bound of +/// the range is lower bound + size. +_LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[107] = { + 0x0440005f /* 00001100 - 0000115f [ 96] */, // + 0x08c68001 /* 0000231a - 0000231b [ 2] */, // + 0x08ca4001 /* 00002329 - 0000232a [ 2] */, // + 0x08fa4003 /* 000023e9 - 000023ec [ 4] */, // + 0x08fc0000 /* 000023f0 - 000023f0 [ 1] */, // + 0x08fcc000 /* 000023f3 - 000023f3 [ 1] */, // + 0x097f4001 /* 000025fd - 000025fe [ 2] */, // + 0x09850001 /* 00002614 - 00002615 [ 2] */, // + 0x0992000b /* 00002648 - 00002653 [ 12] */, // + 0x099fc000 /* 0000267f - 0000267f [ 1] */, // + 0x09a4c000 /* 00002693 - 00002693 [ 1] */, // + 0x09a84000 /* 000026a1 - 000026a1 [ 1] */, // + 0x09aa8001 /* 000026aa - 000026ab [ 2] */, // + 0x09af4001 /* 000026bd - 000026be [ 2] */, // + 0x09b10001 /* 000026c4 - 000026c5 [ 2] */, // + 0x09b38000 /* 000026ce - 000026ce [ 1] */, // + 0x09b50000 /* 000026d4 - 000026d4 [ 1] */, // + 0x09ba8000 /* 000026ea - 000026ea [ 1] */, // + 0x09bc8001 /* 000026f2 - 000026f3 [ 2] */, // + 0x09bd4000 /* 000026f5 - 000026f5 [ 1] */, // + 0x09be8000 /* 000026fa - 000026fa [ 1] */, // + 0x09bf4000 /* 000026fd - 000026fd [ 1] */, // + 0x09c14000 /* 00002705 - 00002705 [ 1] */, // + 0x09c28001 /* 0000270a - 0000270b [ 2] */, // + 0x09ca0000 /* 00002728 - 00002728 [ 1] */, // + 0x09d30000 /* 0000274c - 0000274c [ 1] */, // + 0x09d38000 /* 0000274e - 0000274e [ 1] */, // + 0x09d4c002 /* 00002753 - 00002755 [ 3] */, // + 0x09d5c000 /* 00002757 - 00002757 [ 1] */, // + 0x09e54002 /* 00002795 - 00002797 [ 3] */, // + 0x09ec0000 /* 000027b0 - 000027b0 [ 1] */, // + 0x09efc000 /* 000027bf - 000027bf [ 1] */, // + 0x0ac6c001 /* 00002b1b - 00002b1c [ 2] */, // + 0x0ad40000 /* 00002b50 - 00002b50 [ 1] */, // + 0x0ad54000 /* 00002b55 - 00002b55 [ 1] */, // + 0x0ba00019 /* 00002e80 - 00002e99 [ 26] */, // + 0x0ba6c058 /* 00002e9b - 00002ef3 [ 89] */, // + 0x0bc000d5 /* 00002f00 - 00002fd5 [ 214] */, // + 0x0bfc004e /* 00002ff0 - 0000303e [ 79] */, // + 0x0c104055 /* 00003041 - 00003096 [ 86] */, // + 0x0c264066 /* 00003099 - 000030ff [ 103] */, // + 0x0c41402a /* 00003105 - 0000312f [ 43] */, // + 0x0c4c405d /* 00003131 - 0000318e [ 94] */, // + 0x0c640053 /* 00003190 - 000031e3 [ 84] */, // + 0x0c7bc02f /* 000031ef - 0000321e [ 48] */, // + 0x0c880027 /* 00003220 - 00003247 [ 40] */, // + 0x0c943fff /* 00003250 - 0000724f [16384] */, // + 0x1c94323c /* 00007250 - 0000a48c [12861] */, // + 0x29240036 /* 0000a490 - 0000a4c6 [ 55] */, // + 0x2a58001c /* 0000a960 - 0000a97c [ 29] */, // + 0x2b002ba3 /* 0000ac00 - 0000d7a3 [11172] */, // + 0x3e4001ff /* 0000f900 - 0000faff [ 512] */, // + 0x3f840009 /* 0000fe10 - 0000fe19 [ 10] */, // + 0x3f8c0022 /* 0000fe30 - 0000fe52 [ 35] */, // + 0x3f950012 /* 0000fe54 - 0000fe66 [ 19] */, // + 0x3f9a0003 /* 0000fe68 - 0000fe6b [ 4] */, // + 0x3fc0405f /* 0000ff01 - 0000ff60 [ 96] */, // + 0x3ff80006 /* 0000ffe0 - 0000ffe6 [ 7] */, // + 0x5bf80004 /* 00016fe0 - 00016fe4 [ 5] */, // + 0x5bfc0001 /* 00016ff0 - 00016ff1 [ 2] */, // + 0x5c0017f7 /* 00017000 - 000187f7 [ 6136] */, // + 0x620004d5 /* 00018800 - 00018cd5 [ 1238] */, // + 0x63400008 /* 00018d00 - 00018d08 [ 9] */, // + 0x6bfc0003 /* 0001aff0 - 0001aff3 [ 4] */, // + 0x6bfd4006 /* 0001aff5 - 0001affb [ 7] */, // + 0x6bff4001 /* 0001affd - 0001affe [ 2] */, // + 0x6c000122 /* 0001b000 - 0001b122 [ 291] */, // + 0x6c4c8000 /* 0001b132 - 0001b132 [ 1] */, // + 0x6c540002 /* 0001b150 - 0001b152 [ 3] */, // + 0x6c554000 /* 0001b155 - 0001b155 [ 1] */, // + 0x6c590003 /* 0001b164 - 0001b167 [ 4] */, // + 0x6c5c018b /* 0001b170 - 0001b2fb [ 396] */, // + 0x7c010000 /* 0001f004 - 0001f004 [ 1] */, // + 0x7c33c000 /* 0001f0cf - 0001f0cf [ 1] */, // + 0x7c638000 /* 0001f18e - 0001f18e [ 1] */, // + 0x7c644009 /* 0001f191 - 0001f19a [ 10] */, // + 0x7c800002 /* 0001f200 - 0001f202 [ 3] */, // + 0x7c84002b /* 0001f210 - 0001f23b [ 44] */, // + 0x7c900008 /* 0001f240 - 0001f248 [ 9] */, // + 0x7c940001 /* 0001f250 - 0001f251 [ 2] */, // + 0x7c980005 /* 0001f260 - 0001f265 [ 6] */, // + 0x7cc0034f /* 0001f300 - 0001f64f [ 848] */, // + 0x7da00045 /* 0001f680 - 0001f6c5 [ 70] */, // + 0x7db30000 /* 0001f6cc - 0001f6cc [ 1] */, // + 0x7db40002 /* 0001f6d0 - 0001f6d2 [ 3] */, // + 0x7db54002 /* 0001f6d5 - 0001f6d7 [ 3] */, // + 0x7db70003 /* 0001f6dc - 0001f6df [ 4] */, // + 0x7dbac001 /* 0001f6eb - 0001f6ec [ 2] */, // + 0x7dbd0008 /* 0001f6f4 - 0001f6fc [ 9] */, // + 0x7df8000b /* 0001f7e0 - 0001f7eb [ 12] */, // + 0x7dfc0000 /* 0001f7f0 - 0001f7f0 [ 1] */, // + 0x7e4000ff /* 0001f900 - 0001f9ff [ 256] */, // + 0x7e9c000c /* 0001fa70 - 0001fa7c [ 13] */, // + 0x7ea00008 /* 0001fa80 - 0001fa88 [ 9] */, // + 0x7ea4002d /* 0001fa90 - 0001fabd [ 46] */, // + 0x7eafc006 /* 0001fabf - 0001fac5 [ 7] */, // + 0x7eb3800d /* 0001face - 0001fadb [ 14] */, // + 0x7eb80008 /* 0001fae0 - 0001fae8 [ 9] */, // + 0x7ebc0008 /* 0001faf0 - 0001faf8 [ 9] */, // + 0x80003fff /* 00020000 - 00023fff [16384] */, // + 0x90003fff /* 00024000 - 00027fff [16384] */, // + 0xa0003fff /* 00028000 - 0002bfff [16384] */, // + 0xb0003ffd /* 0002c000 - 0002fffd [16382] */, // + 0xc0003fff /* 00030000 - 00033fff [16384] */, // + 0xd0003fff /* 00034000 - 00037fff [16384] */, // + 0xe0003fff /* 00038000 - 0003bfff [16384] */, // + 0xf0003ffd /* 0003c000 - 0003fffd [16382] */}; + +/// The upper bound entry of EastAsianWidth.txt. +/// +/// Values greater than this value may have more than 18 significant bits. +/// They always have a width of 1. This property makes it possible to store +/// the table in its compact form. +inline constexpr uint32_t __table_upper_bound = 0x0003fffd; + +/// Returns the estimated width of a Unicode code point. +/// +/// \\pre The code point is a valid Unicode code point. +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int __estimated_width(const char32_t __code_point) noexcept { + // Since __table_upper_bound contains the unshifted range do the + // comparison without shifting. + if (__code_point > __table_upper_bound) [[unlikely]] + return 1; + + // When the code-point is less than the first element in the table + // the lookup is quite expensive. Since quite some scripts are in + // that range, it makes sense to validate that first. + // The std_format_spec_string_unicode benchmark gives a measurable + // improvement. + if (__code_point < (__entries[0] >> 14)) + return 1; + + ptrdiff_t __i = std::ranges::upper_bound(__entries, (__code_point << 14) | 0x3fffu) - __entries; + if (__i == 0) + return 1; + + --__i; + uint32_t __upper_bound = (__entries[__i] >> 14) + (__entries[__i] & 0x3fffu); + return 1 + (__code_point <= __upper_bound); +} + +} // namespace __width_estimation_table + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FORMAT_WIDTH_ESTIMATION_TABLE_H diff --git a/libcxx/include/__cxx03/__format/write_escaped.h b/libcxx/include/__cxx03/__format/write_escaped.h new file mode 100644 index 0000000000000000000000000000000000000000..052ea98c3c3b8c5c2764801c2d6886c5cf932c69 --- /dev/null +++ b/libcxx/include/__cxx03/__format/write_escaped.h @@ -0,0 +1,242 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FORMAT_WRITE_ESCAPED_H +#define _LIBCPP___FORMAT_WRITE_ESCAPED_H + +#include <__algorithm/ranges_copy.h> +#include <__algorithm/ranges_for_each.h> +#include <__charconv/to_chars_integral.h> +#include <__charconv/to_chars_result.h> +#include <__chrono/statically_widen.h> +#include <__format/escaped_output_table.h> +#include <__format/formatter_output.h> +#include <__format/parser_std_format_spec.h> +#include <__format/unicode.h> +#include <__iterator/back_insert_iterator.h> +#include <__memory/addressof.h> +#include <__system_error/errc.h> +#include <__type_traits/make_unsigned.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __formatter { + +#if _LIBCPP_STD_VER >= 20 + +/// Writes a string using format's width estimation algorithm. +/// +/// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the +/// input is ASCII. +template +_LIBCPP_HIDE_FROM_ABI auto +__write_string(basic_string_view<_CharT> __str, + output_iterator auto __out_it, + __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { + if (!__specs.__has_precision()) + return __formatter::__write_string_no_precision(__str, std::move(__out_it), __specs); + + int __size = __formatter::__truncate(__str, __specs.__precision_); + + return __formatter::__write(__str.begin(), __str.end(), std::move(__out_it), __specs, __size); +} + +#endif // _LIBCPP_STD_VER >= 20 +#if _LIBCPP_STD_VER >= 23 + +struct __nul_terminator {}; + +template +_LIBCPP_HIDE_FROM_ABI bool operator==(const _CharT* __cstr, __nul_terminator) { + return *__cstr == _CharT('\0'); +} + +template +_LIBCPP_HIDE_FROM_ABI void +__write_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value, const _CharT* __prefix) { + back_insert_iterator __out_it{__str}; + std::ranges::copy(__prefix, __nul_terminator{}, __out_it); + + char __buffer[8]; + to_chars_result __r = std::to_chars(std::begin(__buffer), std::end(__buffer), __value, 16); + _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small"); + std::ranges::copy(std::begin(__buffer), __r.ptr, __out_it); + + __str += _CharT('}'); +} + +// [format.string.escaped]/2.2.1.2 +// ... +// then the sequence \u{hex-digit-sequence} is appended to E, where +// hex-digit-sequence is the shortest hexadecimal representation of C using +// lower-case hexadecimal digits. +template +_LIBCPP_HIDE_FROM_ABI void __write_well_formed_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value) { + __formatter::__write_escaped_code_unit(__str, __value, _LIBCPP_STATICALLY_WIDEN(_CharT, "\\u{")); +} + +// [format.string.escaped]/2.2.3 +// Otherwise (X is a sequence of ill-formed code units), each code unit U is +// appended to E in order as the sequence \x{hex-digit-sequence}, where +// hex-digit-sequence is the shortest hexadecimal representation of U using +// lower-case hexadecimal digits. +template +_LIBCPP_HIDE_FROM_ABI void __write_escape_ill_formed_code_unit(basic_string<_CharT>& __str, char32_t __value) { + __formatter::__write_escaped_code_unit(__str, __value, _LIBCPP_STATICALLY_WIDEN(_CharT, "\\x{")); +} + +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool +__is_escaped_sequence_written(basic_string<_CharT>& __str, bool __last_escaped, char32_t __value) { +# ifdef _LIBCPP_HAS_NO_UNICODE + // For ASCII assume everything above 127 is printable. + if (__value > 127) + return false; +# endif + + // [format.string.escaped]/2.2.1.2.1 + // CE is UTF-8, UTF-16, or UTF-32 and C corresponds to a Unicode scalar + // value whose Unicode property General_Category has a value in the groups + // Separator (Z) or Other (C), as described by UAX #44 of the Unicode Standard, + if (!__escaped_output_table::__needs_escape(__value)) + // [format.string.escaped]/2.2.1.2.2 + // CE is UTF-8, UTF-16, or UTF-32 and C corresponds to a Unicode scalar + // value with the Unicode property Grapheme_Extend=Yes as described by UAX + // #44 of the Unicode Standard and C is not immediately preceded in S by a + // character P appended to E without translation to an escape sequence, + if (!__last_escaped || __extended_grapheme_custer_property_boundary::__get_property(__value) != + __extended_grapheme_custer_property_boundary::__property::__Extend) + return false; + + __formatter::__write_well_formed_escaped_code_unit(__str, __value); + return true; +} + +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr char32_t __to_char32(_CharT __value) { + return static_cast>(__value); +} + +enum class __escape_quotation_mark { __apostrophe, __double_quote }; + +// [format.string.escaped]/2 +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool __is_escaped_sequence_written( + basic_string<_CharT>& __str, char32_t __value, bool __last_escaped, __escape_quotation_mark __mark) { + // 2.2.1.1 - Mapped character in [tab:format.escape.sequences] + switch (__value) { + case _CharT('\t'): + __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\t"); + return true; + case _CharT('\n'): + __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\n"); + return true; + case _CharT('\r'): + __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\r"); + return true; + case _CharT('\''): + if (__mark == __escape_quotation_mark::__apostrophe) + __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\')"); + else + __str += __value; + return true; + case _CharT('"'): + if (__mark == __escape_quotation_mark::__double_quote) + __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\")"); + else + __str += __value; + return true; + case _CharT('\\'): + __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\\)"); + return true; + + // 2.2.1.2 - Space + case _CharT(' '): + __str += __value; + return true; + } + + // 2.2.2 + // Otherwise, if X is a shift sequence, the effect on E and further + // decoding of S is unspecified. + // For now shift sequences are ignored and treated as Unicode. Other parts + // of the format library do the same. It's unknown how ostream treats them. + // TODO FMT determine what to do with shift sequences. + + // 2.2.1.2.1 and 2.2.1.2.2 - Escape + return __formatter::__is_escaped_sequence_written(__str, __last_escaped, __formatter::__to_char32(__value)); +} + +template +_LIBCPP_HIDE_FROM_ABI void +__escape(basic_string<_CharT>& __str, basic_string_view<_CharT> __values, __escape_quotation_mark __mark) { + __unicode::__code_point_view<_CharT> __view{__values.begin(), __values.end()}; + + // When the first code unit has the property Grapheme_Extend=Yes it needs to + // be escaped. This happens when the previous code unit was also escaped. + bool __escape = true; + while (!__view.__at_end()) { + auto __first = __view.__position(); + typename __unicode::__consume_result __result = __view.__consume(); + if (__result.__status == __unicode::__consume_result::__ok) { + __escape = __formatter::__is_escaped_sequence_written(__str, __result.__code_point, __escape, __mark); + if (!__escape) + // 2.2.1.3 - Add the character + ranges::copy(__first, __view.__position(), std::back_insert_iterator(__str)); + } else { + // 2.2.3 sequence of ill-formed code units + ranges::for_each(__first, __view.__position(), [&](_CharT __value) { + __formatter::__write_escape_ill_formed_code_unit(__str, __formatter::__to_char32(__value)); + }); + } + } +} + +template +_LIBCPP_HIDE_FROM_ABI auto +__format_escaped_char(_CharT __value, + output_iterator auto __out_it, + __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { + basic_string<_CharT> __str; + __str += _CharT('\''); + __formatter::__escape(__str, basic_string_view{std::addressof(__value), 1}, __escape_quotation_mark::__apostrophe); + __str += _CharT('\''); + return __formatter::__write(__str.data(), __str.data() + __str.size(), std::move(__out_it), __specs, __str.size()); +} + +template +_LIBCPP_HIDE_FROM_ABI auto +__format_escaped_string(basic_string_view<_CharT> __values, + output_iterator auto __out_it, + __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { + basic_string<_CharT> __str; + __str += _CharT('"'); + __formatter::__escape(__str, __values, __escape_quotation_mark::__double_quote); + __str += _CharT('"'); + return __formatter::__write_string(basic_string_view{__str}, std::move(__out_it), __specs); +} + +#endif // _LIBCPP_STD_VER >= 23 + +} // namespace __formatter + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_WRITE_ESCAPED_H diff --git a/libcxx/include/__cxx03/__functional/binary_function.h b/libcxx/include/__cxx03/__functional/binary_function.h new file mode 100644 index 0000000000000000000000000000000000000000..ddee3b170311f057ed9589f98bd764e6d30c8e3b --- /dev/null +++ b/libcxx/include/__cxx03/__functional/binary_function.h @@ -0,0 +1,54 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_BINARY_FUNCTION_H +#define _LIBCPP___FUNCTIONAL_BINARY_FUNCTION_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION) + +template +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 binary_function { + typedef _Arg1 first_argument_type; + typedef _Arg2 second_argument_type; + typedef _Result result_type; +}; + +#endif // _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION) + +template +struct __binary_function_keep_layout_base { +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) + using first_argument_type _LIBCPP_DEPRECATED_IN_CXX17 = _Arg1; + using second_argument_type _LIBCPP_DEPRECATED_IN_CXX17 = _Arg2; + using result_type _LIBCPP_DEPRECATED_IN_CXX17 = _Result; +#endif +}; + +#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION) +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wdeprecated-declarations") +template +using __binary_function = binary_function<_Arg1, _Arg2, _Result>; +_LIBCPP_DIAGNOSTIC_POP +#else +template +using __binary_function = __binary_function_keep_layout_base<_Arg1, _Arg2, _Result>; +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_BINARY_FUNCTION_H diff --git a/libcxx/include/__cxx03/__functional/binary_negate.h b/libcxx/include/__cxx03/__functional/binary_negate.h new file mode 100644 index 0000000000000000000000000000000000000000..ce52b5ae9fc499d0a3f386826884a5761e0858ed --- /dev/null +++ b/libcxx/include/__cxx03/__functional/binary_negate.h @@ -0,0 +1,51 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_BINARY_NEGATE_H +#define _LIBCPP___FUNCTIONAL_BINARY_NEGATE_H + +#include <__config> +#include <__functional/binary_function.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_NEGATORS) + +template +class _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX17 binary_negate + : public __binary_function { + _Predicate __pred_; + +public: + _LIBCPP_HIDE_FROM_ABI explicit _LIBCPP_CONSTEXPR_SINCE_CXX14 binary_negate(const _Predicate& __pred) + : __pred_(__pred) {} + + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI bool operator()( + const typename _Predicate::first_argument_type& __x, const typename _Predicate::second_argument_type& __y) const { + return !__pred_(__x, __y); + } +}; + +template +_LIBCPP_DEPRECATED_IN_CXX17 inline _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI binary_negate<_Predicate> +not2(const _Predicate& __pred) { + return binary_negate<_Predicate>(__pred); +} + +#endif // _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_NEGATORS) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_BINARY_NEGATE_H diff --git a/libcxx/include/__cxx03/__functional/bind.h b/libcxx/include/__cxx03/__functional/bind.h new file mode 100644 index 0000000000000000000000000000000000000000..b4f46441da507471761237fa3560a5e620267bbe --- /dev/null +++ b/libcxx/include/__cxx03/__functional/bind.h @@ -0,0 +1,296 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_BIND_H +#define _LIBCPP___FUNCTIONAL_BIND_H + +#include <__config> +#include <__functional/invoke.h> +#include <__functional/weak_result_type.h> +#include <__fwd/functional.h> +#include <__type_traits/decay.h> +#include <__type_traits/is_reference_wrapper.h> +#include <__type_traits/is_void.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct is_bind_expression + : _If< _IsSame<_Tp, __remove_cvref_t<_Tp> >::value, false_type, is_bind_expression<__remove_cvref_t<_Tp> > > {}; + +#if _LIBCPP_STD_VER >= 17 +template +inline constexpr bool is_bind_expression_v = is_bind_expression<_Tp>::value; +#endif + +template +struct is_placeholder + : _If< _IsSame<_Tp, __remove_cvref_t<_Tp> >::value, + integral_constant, + is_placeholder<__remove_cvref_t<_Tp> > > {}; + +#if _LIBCPP_STD_VER >= 17 +template +inline constexpr int is_placeholder_v = is_placeholder<_Tp>::value; +#endif + +namespace placeholders { + +template +struct __ph {}; + +// C++17 recommends that we implement placeholders as `inline constexpr`, but allows +// implementing them as `extern `. Libc++ implements them as +// `extern const` in all standard modes to avoid an ABI break in C++03: making them +// `inline constexpr` requires removing their definition in the shared library to +// avoid ODR violations, which is an ABI break. +// +// In practice, since placeholders are empty, `extern const` is almost impossible +// to distinguish from `inline constexpr` from a usage stand point. +_LIBCPP_EXPORTED_FROM_ABI extern const __ph<1> _1; +_LIBCPP_EXPORTED_FROM_ABI extern const __ph<2> _2; +_LIBCPP_EXPORTED_FROM_ABI extern const __ph<3> _3; +_LIBCPP_EXPORTED_FROM_ABI extern const __ph<4> _4; +_LIBCPP_EXPORTED_FROM_ABI extern const __ph<5> _5; +_LIBCPP_EXPORTED_FROM_ABI extern const __ph<6> _6; +_LIBCPP_EXPORTED_FROM_ABI extern const __ph<7> _7; +_LIBCPP_EXPORTED_FROM_ABI extern const __ph<8> _8; +_LIBCPP_EXPORTED_FROM_ABI extern const __ph<9> _9; +_LIBCPP_EXPORTED_FROM_ABI extern const __ph<10> _10; + +} // namespace placeholders + +template +struct is_placeholder > : public integral_constant {}; + +#ifndef _LIBCPP_CXX03_LANG + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& __mu(reference_wrapper<_Tp> __t, _Uj&) { + return __t.get(); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __invoke_of<_Ti&, _Uj...>::type +__mu_expand(_Ti& __ti, tuple<_Uj...>& __uj, __tuple_indices<_Indx...>) { + return __ti(std::forward<_Uj>(std::get<_Indx>(__uj))...); +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __invoke_of<_Ti&, _Uj...>::type +__mu(_Ti& __ti, tuple<_Uj...>& __uj) { + typedef typename __make_tuple_indices::type __indices; + return std::__mu_expand(__ti, __uj, __indices()); +} + +template +struct __mu_return2 {}; + +template +struct __mu_return2 { + typedef typename tuple_element::value - 1, _Uj>::type type; +}; + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 +typename __mu_return2<0 < is_placeholder<_Ti>::value, _Ti, _Uj>::type +__mu(_Ti&, _Uj& __uj) { + const size_t __indx = is_placeholder<_Ti>::value - 1; + return std::forward::type>(std::get<__indx>(__uj)); +} + +template ::value && is_placeholder<_Ti>::value == 0 && + !__is_reference_wrapper<_Ti>::value, + int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Ti& __mu(_Ti& __ti, _Uj&) { + return __ti; +} + +template +struct __mu_return_impl; + +template +struct __mu_return_invokable // false +{ + typedef __nat type; +}; + +template +struct __mu_return_invokable { + typedef typename __invoke_of<_Ti&, _Uj...>::type type; +}; + +template +struct __mu_return_impl<_Ti, false, true, false, tuple<_Uj...> > + : public __mu_return_invokable<__invokable<_Ti&, _Uj...>::value, _Ti, _Uj...> {}; + +template +struct __mu_return_impl<_Ti, false, false, true, _TupleUj> { + typedef typename tuple_element::value - 1, _TupleUj>::type&& type; +}; + +template +struct __mu_return_impl<_Ti, true, false, false, _TupleUj> { + typedef typename _Ti::type& type; +}; + +template +struct __mu_return_impl<_Ti, false, false, false, _TupleUj> { + typedef _Ti& type; +}; + +template +struct __mu_return + : public __mu_return_impl< + _Ti, + __is_reference_wrapper<_Ti>::value, + is_bind_expression<_Ti>::value, + 0 < is_placeholder<_Ti>::value && is_placeholder<_Ti>::value <= tuple_size<_TupleUj>::value, + _TupleUj> {}; + +template +struct __is_valid_bind_return { + static const bool value = false; +}; + +template +struct __is_valid_bind_return<_Fp, tuple<_BoundArgs...>, _TupleUj> { + static const bool value = __invokable<_Fp, typename __mu_return<_BoundArgs, _TupleUj>::type...>::value; +}; + +template +struct __is_valid_bind_return<_Fp, const tuple<_BoundArgs...>, _TupleUj> { + static const bool value = __invokable<_Fp, typename __mu_return::type...>::value; +}; + +template ::value> +struct __bind_return; + +template +struct __bind_return<_Fp, tuple<_BoundArgs...>, _TupleUj, true> { + typedef typename __invoke_of< _Fp&, typename __mu_return< _BoundArgs, _TupleUj >::type... >::type type; +}; + +template +struct __bind_return<_Fp, const tuple<_BoundArgs...>, _TupleUj, true> { + typedef typename __invoke_of< _Fp&, typename __mu_return< const _BoundArgs, _TupleUj >::type... >::type type; +}; + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __bind_return<_Fp, _BoundArgs, _Args>::type +__apply_functor(_Fp& __f, _BoundArgs& __bound_args, __tuple_indices<_Indx...>, _Args&& __args) { + return std::__invoke(__f, std::__mu(std::get<_Indx>(__bound_args), __args)...); +} + +template +class __bind : public __weak_result_type<__decay_t<_Fp> > { +protected: + using _Fd = __decay_t<_Fp>; + typedef tuple<__decay_t<_BoundArgs>...> _Td; + +private: + _Fd __f_; + _Td __bound_args_; + + typedef typename __make_tuple_indices::type __indices; + +public: + template < + class _Gp, + class... _BA, + __enable_if_t::value && !is_same<__libcpp_remove_reference_t<_Gp>, __bind>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit __bind(_Gp&& __f, _BA&&... __bound_args) + : __f_(std::forward<_Gp>(__f)), __bound_args_(std::forward<_BA>(__bound_args)...) {} + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __bind_return<_Fd, _Td, tuple<_Args&&...> >::type + operator()(_Args&&... __args) { + return std::__apply_functor(__f_, __bound_args_, __indices(), tuple<_Args&&...>(std::forward<_Args>(__args)...)); + } + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + typename __bind_return >::type + operator()(_Args&&... __args) const { + return std::__apply_functor(__f_, __bound_args_, __indices(), tuple<_Args&&...>(std::forward<_Args>(__args)...)); + } +}; + +template +struct is_bind_expression<__bind<_Fp, _BoundArgs...> > : public true_type {}; + +template +class __bind_r : public __bind<_Fp, _BoundArgs...> { + typedef __bind<_Fp, _BoundArgs...> base; + typedef typename base::_Fd _Fd; + typedef typename base::_Td _Td; + +public: + typedef _Rp result_type; + + template < + class _Gp, + class... _BA, + __enable_if_t::value && !is_same<__libcpp_remove_reference_t<_Gp>, __bind_r>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit __bind_r(_Gp&& __f, _BA&&... __bound_args) + : base(std::forward<_Gp>(__f), std::forward<_BA>(__bound_args)...) {} + + template < + class... _Args, + __enable_if_t >::type, result_type>::value || + is_void<_Rp>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 result_type operator()(_Args&&... __args) { + typedef __invoke_void_return_wrapper<_Rp> _Invoker; + return _Invoker::__call(static_cast(*this), std::forward<_Args>(__args)...); + } + + template >::type, + result_type>::value || + is_void<_Rp>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 result_type operator()(_Args&&... __args) const { + typedef __invoke_void_return_wrapper<_Rp> _Invoker; + return _Invoker::__call(static_cast(*this), std::forward<_Args>(__args)...); + } +}; + +template +struct is_bind_expression<__bind_r<_Rp, _Fp, _BoundArgs...> > : public true_type {}; + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bind<_Fp, _BoundArgs...> +bind(_Fp&& __f, _BoundArgs&&... __bound_args) { + typedef __bind<_Fp, _BoundArgs...> type; + return type(std::forward<_Fp>(__f), std::forward<_BoundArgs>(__bound_args)...); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bind_r<_Rp, _Fp, _BoundArgs...> +bind(_Fp&& __f, _BoundArgs&&... __bound_args) { + typedef __bind_r<_Rp, _Fp, _BoundArgs...> type; + return type(std::forward<_Fp>(__f), std::forward<_BoundArgs>(__bound_args)...); +} + +#endif // _LIBCPP_CXX03_LANG + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_BIND_H diff --git a/libcxx/include/__cxx03/__functional/bind_back.h b/libcxx/include/__cxx03/__functional/bind_back.h new file mode 100644 index 0000000000000000000000000000000000000000..e44768d2283c08941198bbd87f4caf23b5774912 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/bind_back.h @@ -0,0 +1,83 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_BIND_BACK_H +#define _LIBCPP___FUNCTIONAL_BIND_BACK_H + +#include <__config> +#include <__functional/invoke.h> +#include <__functional/perfect_forward.h> +#include <__type_traits/decay.h> +#include <__utility/forward.h> +#include <__utility/integer_sequence.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template > +struct __bind_back_op; + +template +struct __bind_back_op<_NBound, index_sequence<_Ip...>> { + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Fn&& __f, _BoundArgs&& __bound_args, _Args&&... __args) const + noexcept(noexcept(std::invoke(std::forward<_Fn>(__f), + std::forward<_Args>(__args)..., + std::get<_Ip>(std::forward<_BoundArgs>(__bound_args))...))) + -> decltype(std::invoke(std::forward<_Fn>(__f), + std::forward<_Args>(__args)..., + std::get<_Ip>(std::forward<_BoundArgs>(__bound_args))...)) { + return std::invoke(std::forward<_Fn>(__f), + std::forward<_Args>(__args)..., + std::get<_Ip>(std::forward<_BoundArgs>(__bound_args))...); + } +}; + +template +struct __bind_back_t : __perfect_forward<__bind_back_op>, _Fn, _BoundArgs> { + using __perfect_forward<__bind_back_op>, _Fn, _BoundArgs>::__perfect_forward; +}; + +template + requires is_constructible_v, _Fn> && is_move_constructible_v> && + (is_constructible_v, _Args> && ...) && (is_move_constructible_v> && ...) +_LIBCPP_HIDE_FROM_ABI constexpr auto __bind_back(_Fn&& __f, _Args&&... __args) noexcept( + noexcept(__bind_back_t, tuple...>>( + std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...)))) + -> decltype(__bind_back_t, tuple...>>( + std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...))) { + return __bind_back_t, tuple...>>( + std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...)); +} + +# if _LIBCPP_STD_VER >= 23 +template +_LIBCPP_HIDE_FROM_ABI constexpr auto bind_back(_Fn&& __f, _Args&&... __args) { + static_assert(is_constructible_v, _Fn>, "bind_back requires decay_t to be constructible from F"); + static_assert(is_move_constructible_v>, "bind_back requires decay_t to be move constructible"); + static_assert((is_constructible_v, _Args> && ...), + "bind_back requires all decay_t to be constructible from respective Args"); + static_assert((is_move_constructible_v> && ...), + "bind_back requires all decay_t to be move constructible"); + return __bind_back_t, tuple...>>( + std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...)); +} +# endif // _LIBCPP_STD_VER >= 23 + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_BIND_BACK_H diff --git a/libcxx/include/__cxx03/__functional/bind_front.h b/libcxx/include/__cxx03/__functional/bind_front.h new file mode 100644 index 0000000000000000000000000000000000000000..87ef3affe80b63899b44d30e50be51696a0c06e7 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/bind_front.h @@ -0,0 +1,54 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_BIND_FRONT_H +#define _LIBCPP___FUNCTIONAL_BIND_FRONT_H + +#include <__config> +#include <__functional/invoke.h> +#include <__functional/perfect_forward.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/decay.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_constructible.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +struct __bind_front_op { + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) const noexcept( + noexcept(std::invoke(std::forward<_Args>(__args)...))) -> decltype(std::invoke(std::forward<_Args>(__args)...)) { + return std::invoke(std::forward<_Args>(__args)...); + } +}; + +template +struct __bind_front_t : __perfect_forward<__bind_front_op, _Fn, _BoundArgs...> { + using __perfect_forward<__bind_front_op, _Fn, _BoundArgs...>::__perfect_forward; +}; + +template + requires is_constructible_v, _Fn> && is_move_constructible_v> && + (is_constructible_v, _Args> && ...) && (is_move_constructible_v> && ...) +_LIBCPP_HIDE_FROM_ABI constexpr auto bind_front(_Fn&& __f, _Args&&... __args) { + return __bind_front_t, decay_t<_Args>...>(std::forward<_Fn>(__f), std::forward<_Args>(__args)...); +} + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_BIND_FRONT_H diff --git a/libcxx/include/__cxx03/__functional/binder1st.h b/libcxx/include/__cxx03/__functional/binder1st.h new file mode 100644 index 0000000000000000000000000000000000000000..04b51fefab70a9195927261c4c8c1ccbb394fdc9 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/binder1st.h @@ -0,0 +1,54 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_BINDER1ST_H +#define _LIBCPP___FUNCTIONAL_BINDER1ST_H + +#include <__config> +#include <__functional/unary_function.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_BINDERS) + +template +class _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 binder1st + : public __unary_function { +protected: + _Operation op; + typename _Operation::first_argument_type value; + +public: + _LIBCPP_HIDE_FROM_ABI binder1st(const _Operation& __x, const typename _Operation::first_argument_type __y) + : op(__x), value(__y) {} + _LIBCPP_HIDE_FROM_ABI typename _Operation::result_type + operator()(typename _Operation::second_argument_type& __x) const { + return op(value, __x); + } + _LIBCPP_HIDE_FROM_ABI typename _Operation::result_type + operator()(const typename _Operation::second_argument_type& __x) const { + return op(value, __x); + } +}; + +template +_LIBCPP_DEPRECATED_IN_CXX11 inline _LIBCPP_HIDE_FROM_ABI binder1st<_Operation> +bind1st(const _Operation& __op, const _Tp& __x) { + return binder1st<_Operation>(__op, __x); +} + +#endif // _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_BINDERS) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_BINDER1ST_H diff --git a/libcxx/include/__cxx03/__functional/binder2nd.h b/libcxx/include/__cxx03/__functional/binder2nd.h new file mode 100644 index 0000000000000000000000000000000000000000..9d22e4430b1b3405010b49d5b88bd7c7aaf3c3e9 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/binder2nd.h @@ -0,0 +1,54 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_BINDER2ND_H +#define _LIBCPP___FUNCTIONAL_BINDER2ND_H + +#include <__config> +#include <__functional/unary_function.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_BINDERS) + +template +class _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 binder2nd + : public __unary_function { +protected: + _Operation op; + typename _Operation::second_argument_type value; + +public: + _LIBCPP_HIDE_FROM_ABI binder2nd(const _Operation& __x, const typename _Operation::second_argument_type __y) + : op(__x), value(__y) {} + _LIBCPP_HIDE_FROM_ABI typename _Operation::result_type + operator()(typename _Operation::first_argument_type& __x) const { + return op(__x, value); + } + _LIBCPP_HIDE_FROM_ABI typename _Operation::result_type + operator()(const typename _Operation::first_argument_type& __x) const { + return op(__x, value); + } +}; + +template +_LIBCPP_DEPRECATED_IN_CXX11 inline _LIBCPP_HIDE_FROM_ABI binder2nd<_Operation> +bind2nd(const _Operation& __op, const _Tp& __x) { + return binder2nd<_Operation>(__op, __x); +} + +#endif // _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_BINDERS) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_BINDER2ND_H diff --git a/libcxx/include/__cxx03/__functional/boyer_moore_searcher.h b/libcxx/include/__cxx03/__functional/boyer_moore_searcher.h new file mode 100644 index 0000000000000000000000000000000000000000..648b60c50521910e8edf4d5b5d7f19f5f21f4c88 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/boyer_moore_searcher.h @@ -0,0 +1,306 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_BOYER_MOORE_SEARCHER_H +#define _LIBCPP___FUNCTIONAL_BOYER_MOORE_SEARCHER_H + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#include <__algorithm/fill_n.h> +#include <__config> +#include <__functional/hash.h> +#include <__functional/operations.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__memory/shared_ptr.h> +#include <__type_traits/make_unsigned.h> +#include <__utility/pair.h> +#include +#include +#include + +#if _LIBCPP_STD_VER >= 17 + +_LIBCPP_PUSH_MACROS +# include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class _BMSkipTable; + +// General case for BM data searching; use a map +template +class _BMSkipTable<_Key, _Value, _Hash, _BinaryPredicate, false> { +private: + using value_type = _Value; + using key_type = _Key; + + const value_type __default_value_; + unordered_map<_Key, _Value, _Hash, _BinaryPredicate> __table_; + +public: + _LIBCPP_HIDE_FROM_ABI explicit _BMSkipTable( + size_t __sz, value_type __default_value, _Hash __hash, _BinaryPredicate __pred) + : __default_value_(__default_value), __table_(__sz, __hash, __pred) {} + + _LIBCPP_HIDE_FROM_ABI void insert(const key_type& __key, value_type __val) { __table_[__key] = __val; } + + _LIBCPP_HIDE_FROM_ABI value_type operator[](const key_type& __key) const { + auto __it = __table_.find(__key); + return __it == __table_.end() ? __default_value_ : __it->second; + } +}; + +// Special case small numeric values; use an array +template +class _BMSkipTable<_Key, _Value, _Hash, _BinaryPredicate, true> { +private: + using value_type = _Value; + using key_type = _Key; + + using unsigned_key_type = make_unsigned_t; + std::array __table_; + static_assert(numeric_limits::max() < 256); + +public: + _LIBCPP_HIDE_FROM_ABI explicit _BMSkipTable(size_t, value_type __default_value, _Hash, _BinaryPredicate) { + std::fill_n(__table_.data(), __table_.size(), __default_value); + } + + _LIBCPP_HIDE_FROM_ABI void insert(key_type __key, value_type __val) { + __table_[static_cast(__key)] = __val; + } + + _LIBCPP_HIDE_FROM_ABI value_type operator[](key_type __key) const { + return __table_[static_cast(__key)]; + } +}; + +template ::value_type>, + class _BinaryPredicate = equal_to<>> +class _LIBCPP_TEMPLATE_VIS boyer_moore_searcher { +private: + using difference_type = typename std::iterator_traits<_RandomAccessIterator1>::difference_type; + using value_type = typename std::iterator_traits<_RandomAccessIterator1>::value_type; + using __skip_table_type = + _BMSkipTable && sizeof(value_type) == 1 && is_same_v<_Hash, hash> && + is_same_v<_BinaryPredicate, equal_to<>>>; + +public: + _LIBCPP_HIDE_FROM_ABI boyer_moore_searcher( + _RandomAccessIterator1 __first, + _RandomAccessIterator1 __last, + _Hash __hash = _Hash(), + _BinaryPredicate __pred = _BinaryPredicate()) + : __first_(__first), + __last_(__last), + __pred_(__pred), + __pattern_length_(__last - __first), + __skip_table_(std::make_shared<__skip_table_type>(__pattern_length_, -1, __hash, __pred_)), + __suffix_(std::__allocate_shared_unbounded_array( + allocator(), __pattern_length_ + 1)) { + difference_type __i = 0; + while (__first != __last) { + __skip_table_->insert(*__first, __i); + ++__first; + ++__i; + } + __build_suffix_table(__first_, __last_, __pred_); + } + + template + _LIBCPP_HIDE_FROM_ABI pair<_RandomAccessIterator2, _RandomAccessIterator2> + operator()(_RandomAccessIterator2 __first, _RandomAccessIterator2 __last) const { + static_assert(__is_same_uncvref::value_type, + typename iterator_traits<_RandomAccessIterator2>::value_type>::value, + "Corpus and Pattern iterators must point to the same type"); + if (__first == __last) + return std::make_pair(__last, __last); + if (__first_ == __last_) + return std::make_pair(__first, __first); + + if (__pattern_length_ > (__last - __first)) + return std::make_pair(__last, __last); + return __search(__first, __last); + } + +private: + _RandomAccessIterator1 __first_; + _RandomAccessIterator1 __last_; + _BinaryPredicate __pred_; + difference_type __pattern_length_; + shared_ptr<__skip_table_type> __skip_table_; + shared_ptr __suffix_; + + template + _LIBCPP_HIDE_FROM_ABI pair<_RandomAccessIterator2, _RandomAccessIterator2> + __search(_RandomAccessIterator2 __f, _RandomAccessIterator2 __l) const { + _RandomAccessIterator2 __current = __f; + const _RandomAccessIterator2 __last = __l - __pattern_length_; + const __skip_table_type& __skip_table = *__skip_table_; + + while (__current <= __last) { + difference_type __j = __pattern_length_; + while (__pred_(__first_[__j - 1], __current[__j - 1])) { + --__j; + if (__j == 0) + return std::make_pair(__current, __current + __pattern_length_); + } + + difference_type __k = __skip_table[__current[__j - 1]]; + difference_type __m = __j - __k - 1; + if (__k < __j && __m > __suffix_[__j]) + __current += __m; + else + __current += __suffix_[__j]; + } + return std::make_pair(__l, __l); + } + + template + _LIBCPP_HIDE_FROM_ABI void + __compute_bm_prefix(_Iterator __first, _Iterator __last, _BinaryPredicate __pred, _Container& __prefix) { + const size_t __count = __last - __first; + + __prefix[0] = 0; + size_t __k = 0; + + for (size_t __i = 1; __i != __count; ++__i) { + while (__k > 0 && !__pred(__first[__k], __first[__i])) + __k = __prefix[__k - 1]; + + if (__pred(__first[__k], __first[__i])) + ++__k; + __prefix[__i] = __k; + } + } + + _LIBCPP_HIDE_FROM_ABI void + __build_suffix_table(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _BinaryPredicate __pred) { + const size_t __count = __last - __first; + + if (__count == 0) + return; + + vector __scratch(__count); + + __compute_bm_prefix(__first, __last, __pred, __scratch); + for (size_t __i = 0; __i <= __count; ++__i) + __suffix_[__i] = __count - __scratch[__count - 1]; + + using _ReverseIter = reverse_iterator<_RandomAccessIterator1>; + __compute_bm_prefix(_ReverseIter(__last), _ReverseIter(__first), __pred, __scratch); + + for (size_t __i = 0; __i != __count; ++__i) { + const size_t __j = __count - __scratch[__i]; + const difference_type __k = __i - __scratch[__i] + 1; + + if (__suffix_[__j] > __k) + __suffix_[__j] = __k; + } + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(boyer_moore_searcher); + +template ::value_type>, + class _BinaryPredicate = equal_to<>> +class _LIBCPP_TEMPLATE_VIS boyer_moore_horspool_searcher { +private: + using difference_type = typename iterator_traits<_RandomAccessIterator1>::difference_type; + using value_type = typename iterator_traits<_RandomAccessIterator1>::value_type; + using __skip_table_type = + _BMSkipTable && sizeof(value_type) == 1 && is_same_v<_Hash, hash> && + is_same_v<_BinaryPredicate, equal_to<>>>; + +public: + _LIBCPP_HIDE_FROM_ABI boyer_moore_horspool_searcher( + _RandomAccessIterator1 __first, + _RandomAccessIterator1 __last, + _Hash __hash = _Hash(), + _BinaryPredicate __pred = _BinaryPredicate()) + : __first_(__first), + __last_(__last), + __pred_(__pred), + __pattern_length_(__last - __first), + __skip_table_(std::make_shared<__skip_table_type>(__pattern_length_, __pattern_length_, __hash, __pred_)) { + if (__first == __last) + return; + --__last; + difference_type __i = 0; + while (__first != __last) { + __skip_table_->insert(*__first, __pattern_length_ - 1 - __i); + ++__first; + ++__i; + } + } + + template + _LIBCPP_HIDE_FROM_ABI pair<_RandomAccessIterator2, _RandomAccessIterator2> + operator()(_RandomAccessIterator2 __first, _RandomAccessIterator2 __last) const { + static_assert(__is_same_uncvref::value_type, + typename std::iterator_traits<_RandomAccessIterator2>::value_type>::value, + "Corpus and Pattern iterators must point to the same type"); + if (__first == __last) + return std::make_pair(__last, __last); + if (__first_ == __last_) + return std::make_pair(__first, __first); + + if (__pattern_length_ > __last - __first) + return std::make_pair(__last, __last); + + return __search(__first, __last); + } + +private: + _RandomAccessIterator1 __first_; + _RandomAccessIterator1 __last_; + _BinaryPredicate __pred_; + difference_type __pattern_length_; + shared_ptr<__skip_table_type> __skip_table_; + + template + _LIBCPP_HIDE_FROM_ABI pair<_RandomAccessIterator2, _RandomAccessIterator2> + __search(_RandomAccessIterator2 __f, _RandomAccessIterator2 __l) const { + _RandomAccessIterator2 __current = __f; + const _RandomAccessIterator2 __last = __l - __pattern_length_; + const __skip_table_type& __skip_table = *__skip_table_; + + while (__current <= __last) { + difference_type __j = __pattern_length_; + while (__pred_(__first_[__j - 1], __current[__j - 1])) { + --__j; + if (__j == 0) + return std::make_pair(__current, __current + __pattern_length_); + } + __current += __skip_table[__current[__pattern_length_ - 1]]; + } + return std::make_pair(__l, __l); + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(boyer_moore_horspool_searcher); + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP_STD_VER >= 17 + +#endif // _LIBCPP___FUNCTIONAL_BOYER_MOORE_SEARCHER_H diff --git a/libcxx/include/__cxx03/__functional/compose.h b/libcxx/include/__cxx03/__functional/compose.h new file mode 100644 index 0000000000000000000000000000000000000000..4b86dd37cd48a4af6ee0aca37af85dcb1c655cb1 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/compose.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_COMPOSE_H +#define _LIBCPP___FUNCTIONAL_COMPOSE_H + +#include <__config> +#include <__functional/invoke.h> +#include <__functional/perfect_forward.h> +#include <__type_traits/decay.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +struct __compose_op { + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Fn1&& __f1, _Fn2&& __f2, _Args&&... __args) const noexcept(noexcept( + std::invoke(std::forward<_Fn1>(__f1), std::invoke(std::forward<_Fn2>(__f2), std::forward<_Args>(__args)...)))) + -> decltype(std::invoke(std::forward<_Fn1>(__f1), + std::invoke(std::forward<_Fn2>(__f2), std::forward<_Args>(__args)...))) { + return std::invoke(std::forward<_Fn1>(__f1), std::invoke(std::forward<_Fn2>(__f2), std::forward<_Args>(__args)...)); + } +}; + +template +struct __compose_t : __perfect_forward<__compose_op, _Fn1, _Fn2> { + using __perfect_forward<__compose_op, _Fn1, _Fn2>::__perfect_forward; +}; + +template +_LIBCPP_HIDE_FROM_ABI constexpr auto __compose(_Fn1&& __f1, _Fn2&& __f2) noexcept( + noexcept(__compose_t, decay_t<_Fn2>>(std::forward<_Fn1>(__f1), std::forward<_Fn2>(__f2)))) + -> decltype(__compose_t, decay_t<_Fn2>>(std::forward<_Fn1>(__f1), std::forward<_Fn2>(__f2))) { + return __compose_t, decay_t<_Fn2>>(std::forward<_Fn1>(__f1), std::forward<_Fn2>(__f2)); +} + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_COMPOSE_H diff --git a/libcxx/include/__cxx03/__functional/default_searcher.h b/libcxx/include/__cxx03/__functional/default_searcher.h new file mode 100644 index 0000000000000000000000000000000000000000..db89d10757c1b1fb10d3d67f6c28e1d878db4ead --- /dev/null +++ b/libcxx/include/__cxx03/__functional/default_searcher.h @@ -0,0 +1,54 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_DEFAULT_SEARCHER_H +#define _LIBCPP___FUNCTIONAL_DEFAULT_SEARCHER_H + +#include <__algorithm/search.h> +#include <__config> +#include <__functional/identity.h> +#include <__functional/operations.h> +#include <__iterator/iterator_traits.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +// default searcher +template > +class _LIBCPP_TEMPLATE_VIS default_searcher { +public: + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + default_searcher(_ForwardIterator __f, _ForwardIterator __l, _BinaryPredicate __p = _BinaryPredicate()) + : __first_(__f), __last_(__l), __pred_(__p) {} + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_ForwardIterator2, _ForwardIterator2> + operator()(_ForwardIterator2 __f, _ForwardIterator2 __l) const { + auto __proj = __identity(); + return std::__search_impl(__f, __l, __first_, __last_, __pred_, __proj, __proj); + } + +private: + _ForwardIterator __first_; + _ForwardIterator __last_; + _BinaryPredicate __pred_; +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(default_searcher); + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_DEFAULT_SEARCHER_H diff --git a/libcxx/include/__cxx03/__functional/function.h b/libcxx/include/__cxx03/__functional/function.h new file mode 100644 index 0000000000000000000000000000000000000000..c7b98035e34bfa0b506e4c6b06eae38b5424f275 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/function.h @@ -0,0 +1,1048 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_FUNCTION_H +#define _LIBCPP___FUNCTIONAL_FUNCTION_H + +#include <__assert> +#include <__config> +#include <__exception/exception.h> +#include <__functional/binary_function.h> +#include <__functional/invoke.h> +#include <__functional/unary_function.h> +#include <__iterator/iterator_traits.h> +#include <__memory/addressof.h> +#include <__memory/allocator.h> +#include <__memory/allocator_destructor.h> +#include <__memory/allocator_traits.h> +#include <__memory/builtin_new_allocator.h> +#include <__memory/compressed_pair.h> +#include <__memory/unique_ptr.h> +#include <__type_traits/aligned_storage.h> +#include <__type_traits/decay.h> +#include <__type_traits/is_core_convertible.h> +#include <__type_traits/is_scalar.h> +#include <__type_traits/is_trivially_constructible.h> +#include <__type_traits/is_trivially_destructible.h> +#include <__type_traits/is_void.h> +#include <__type_traits/strip_signature.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <__utility/piecewise_construct.h> +#include <__utility/swap.h> +#include <__verbose_abort> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#ifndef _LIBCPP_CXX03_LANG + +_LIBCPP_BEGIN_NAMESPACE_STD + +// bad_function_call + +_LIBCPP_DIAGNOSTIC_PUSH +# if !_LIBCPP_AVAILABILITY_HAS_BAD_FUNCTION_CALL_KEY_FUNCTION +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wweak-vtables") +# endif +class _LIBCPP_EXPORTED_FROM_ABI bad_function_call : public exception { +public: + _LIBCPP_HIDE_FROM_ABI bad_function_call() _NOEXCEPT = default; + _LIBCPP_HIDE_FROM_ABI bad_function_call(const bad_function_call&) _NOEXCEPT = default; + _LIBCPP_HIDE_FROM_ABI bad_function_call& operator=(const bad_function_call&) _NOEXCEPT = default; +// Note that when a key function is not used, every translation unit that uses +// bad_function_call will end up containing a weak definition of the vtable and +// typeinfo. +# if _LIBCPP_AVAILABILITY_HAS_BAD_FUNCTION_CALL_KEY_FUNCTION + ~bad_function_call() _NOEXCEPT override; +# else + _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~bad_function_call() _NOEXCEPT override {} +# endif + +# ifdef _LIBCPP_ABI_BAD_FUNCTION_CALL_GOOD_WHAT_MESSAGE + const char* what() const _NOEXCEPT override; +# endif +}; +_LIBCPP_DIAGNOSTIC_POP + +_LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void __throw_bad_function_call() { +# ifndef _LIBCPP_HAS_NO_EXCEPTIONS + throw bad_function_call(); +# else + _LIBCPP_VERBOSE_ABORT("bad_function_call was thrown in -fno-exceptions mode"); +# endif +} + +template +class _LIBCPP_TEMPLATE_VIS function; // undefined + +namespace __function { + +template +struct __maybe_derive_from_unary_function {}; + +template +struct __maybe_derive_from_unary_function<_Rp(_A1)> : public __unary_function<_A1, _Rp> {}; + +template +struct __maybe_derive_from_binary_function {}; + +template +struct __maybe_derive_from_binary_function<_Rp(_A1, _A2)> : public __binary_function<_A1, _A2, _Rp> {}; + +template +_LIBCPP_HIDE_FROM_ABI bool __not_null(_Fp const&) { + return true; +} + +template +_LIBCPP_HIDE_FROM_ABI bool __not_null(_Fp* __ptr) { + return __ptr; +} + +template +_LIBCPP_HIDE_FROM_ABI bool __not_null(_Ret _Class::*__ptr) { + return __ptr; +} + +template +_LIBCPP_HIDE_FROM_ABI bool __not_null(function<_Fp> const& __f) { + return !!__f; +} + +# ifdef _LIBCPP_HAS_EXTENSION_BLOCKS +template +_LIBCPP_HIDE_FROM_ABI bool __not_null(_Rp (^__p)(_Args...)) { + return __p; +} +# endif + +} // namespace __function + +namespace __function { + +// __alloc_func holds a functor and an allocator. + +template +class __alloc_func; +template +class __default_alloc_func; + +template +class __alloc_func<_Fp, _Ap, _Rp(_ArgTypes...)> { + __compressed_pair<_Fp, _Ap> __f_; + +public: + typedef _LIBCPP_NODEBUG _Fp _Target; + typedef _LIBCPP_NODEBUG _Ap _Alloc; + + _LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __f_.first(); } + + // WIN32 APIs may define __allocator, so use __get_allocator instead. + _LIBCPP_HIDE_FROM_ABI const _Alloc& __get_allocator() const { return __f_.second(); } + + _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f) + : __f_(piecewise_construct, std::forward_as_tuple(std::move(__f)), std::forward_as_tuple()) {} + + _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, const _Alloc& __a) + : __f_(piecewise_construct, std::forward_as_tuple(__f), std::forward_as_tuple(__a)) {} + + _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, _Alloc&& __a) + : __f_(piecewise_construct, std::forward_as_tuple(__f), std::forward_as_tuple(std::move(__a))) {} + + _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f, _Alloc&& __a) + : __f_(piecewise_construct, std::forward_as_tuple(std::move(__f)), std::forward_as_tuple(std::move(__a))) {} + + _LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __arg) { + typedef __invoke_void_return_wrapper<_Rp> _Invoker; + return _Invoker::__call(__f_.first(), std::forward<_ArgTypes>(__arg)...); + } + + _LIBCPP_HIDE_FROM_ABI __alloc_func* __clone() const { + typedef allocator_traits<_Alloc> __alloc_traits; + typedef __rebind_alloc<__alloc_traits, __alloc_func> _AA; + _AA __a(__f_.second()); + typedef __allocator_destructor<_AA> _Dp; + unique_ptr<__alloc_func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1)); + ::new ((void*)__hold.get()) __alloc_func(__f_.first(), _Alloc(__a)); + return __hold.release(); + } + + _LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT { __f_.~__compressed_pair<_Target, _Alloc>(); } + + _LIBCPP_HIDE_FROM_ABI static void __destroy_and_delete(__alloc_func* __f) { + typedef allocator_traits<_Alloc> __alloc_traits; + typedef __rebind_alloc<__alloc_traits, __alloc_func> _FunAlloc; + _FunAlloc __a(__f->__get_allocator()); + __f->destroy(); + __a.deallocate(__f, 1); + } +}; + +template +class __default_alloc_func<_Fp, _Rp(_ArgTypes...)> { + _Fp __f_; + +public: + typedef _LIBCPP_NODEBUG _Fp _Target; + + _LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __f_; } + + _LIBCPP_HIDE_FROM_ABI explicit __default_alloc_func(_Target&& __f) : __f_(std::move(__f)) {} + + _LIBCPP_HIDE_FROM_ABI explicit __default_alloc_func(const _Target& __f) : __f_(__f) {} + + _LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __arg) { + typedef __invoke_void_return_wrapper<_Rp> _Invoker; + return _Invoker::__call(__f_, std::forward<_ArgTypes>(__arg)...); + } + + _LIBCPP_HIDE_FROM_ABI __default_alloc_func* __clone() const { + __builtin_new_allocator::__holder_t __hold = __builtin_new_allocator::__allocate_type<__default_alloc_func>(1); + __default_alloc_func* __res = ::new ((void*)__hold.get()) __default_alloc_func(__f_); + (void)__hold.release(); + return __res; + } + + _LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT { __f_.~_Target(); } + + _LIBCPP_HIDE_FROM_ABI static void __destroy_and_delete(__default_alloc_func* __f) { + __f->destroy(); + __builtin_new_allocator::__deallocate_type<__default_alloc_func>(__f, 1); + } +}; + +// __base provides an abstract interface for copyable functors. + +template +class _LIBCPP_TEMPLATE_VIS __base; + +template +class __base<_Rp(_ArgTypes...)> { +public: + __base(const __base&) = delete; + __base& operator=(const __base&) = delete; + + _LIBCPP_HIDE_FROM_ABI __base() {} + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual ~__base() {} + virtual __base* __clone() const = 0; + virtual void __clone(__base*) const = 0; + virtual void destroy() _NOEXCEPT = 0; + virtual void destroy_deallocate() _NOEXCEPT = 0; + virtual _Rp operator()(_ArgTypes&&...) = 0; +# ifndef _LIBCPP_HAS_NO_RTTI + virtual const void* target(const type_info&) const _NOEXCEPT = 0; + virtual const std::type_info& target_type() const _NOEXCEPT = 0; +# endif // _LIBCPP_HAS_NO_RTTI +}; + +// __func implements __base for a given functor type. + +template +class __func; + +template +class __func<_Fp, _Alloc, _Rp(_ArgTypes...)> : public __base<_Rp(_ArgTypes...)> { + __alloc_func<_Fp, _Alloc, _Rp(_ArgTypes...)> __f_; + +public: + _LIBCPP_HIDE_FROM_ABI explicit __func(_Fp&& __f) : __f_(std::move(__f)) {} + + _LIBCPP_HIDE_FROM_ABI explicit __func(const _Fp& __f, const _Alloc& __a) : __f_(__f, __a) {} + + _LIBCPP_HIDE_FROM_ABI explicit __func(const _Fp& __f, _Alloc&& __a) : __f_(__f, std::move(__a)) {} + + _LIBCPP_HIDE_FROM_ABI explicit __func(_Fp&& __f, _Alloc&& __a) : __f_(std::move(__f), std::move(__a)) {} + + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual __base<_Rp(_ArgTypes...)>* __clone() const; + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __clone(__base<_Rp(_ArgTypes...)>*) const; + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void destroy() _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void destroy_deallocate() _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual _Rp operator()(_ArgTypes&&... __arg); +# ifndef _LIBCPP_HAS_NO_RTTI + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual const void* target(const type_info&) const _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual const std::type_info& target_type() const _NOEXCEPT; +# endif // _LIBCPP_HAS_NO_RTTI +}; + +template +__base<_Rp(_ArgTypes...)>* __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::__clone() const { + typedef allocator_traits<_Alloc> __alloc_traits; + typedef __rebind_alloc<__alloc_traits, __func> _Ap; + _Ap __a(__f_.__get_allocator()); + typedef __allocator_destructor<_Ap> _Dp; + unique_ptr<__func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1)); + ::new ((void*)__hold.get()) __func(__f_.__target(), _Alloc(__a)); + return __hold.release(); +} + +template +void __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::__clone(__base<_Rp(_ArgTypes...)>* __p) const { + ::new ((void*)__p) __func(__f_.__target(), __f_.__get_allocator()); +} + +template +void __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::destroy() _NOEXCEPT { + __f_.destroy(); +} + +template +void __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::destroy_deallocate() _NOEXCEPT { + typedef allocator_traits<_Alloc> __alloc_traits; + typedef __rebind_alloc<__alloc_traits, __func> _Ap; + _Ap __a(__f_.__get_allocator()); + __f_.destroy(); + __a.deallocate(this, 1); +} + +template +_Rp __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::operator()(_ArgTypes&&... __arg) { + return __f_(std::forward<_ArgTypes>(__arg)...); +} + +# ifndef _LIBCPP_HAS_NO_RTTI + +template +const void* __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::target(const type_info& __ti) const _NOEXCEPT { + if (__ti == typeid(_Fp)) + return std::addressof(__f_.__target()); + return nullptr; +} + +template +const std::type_info& __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::target_type() const _NOEXCEPT { + return typeid(_Fp); +} + +# endif // _LIBCPP_HAS_NO_RTTI + +// __value_func creates a value-type from a __func. + +template +class __value_func; + +template +class __value_func<_Rp(_ArgTypes...)> { + _LIBCPP_SUPPRESS_DEPRECATED_PUSH + typename aligned_storage<3 * sizeof(void*)>::type __buf_; + _LIBCPP_SUPPRESS_DEPRECATED_POP + + typedef __base<_Rp(_ArgTypes...)> __func; + __func* __f_; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_CFI static __func* __as_base(void* __p) { return reinterpret_cast<__func*>(__p); } + +public: + _LIBCPP_HIDE_FROM_ABI __value_func() _NOEXCEPT : __f_(nullptr) {} + + template + _LIBCPP_HIDE_FROM_ABI __value_func(_Fp&& __f, const _Alloc& __a) : __f_(nullptr) { + typedef allocator_traits<_Alloc> __alloc_traits; + typedef __function::__func<_Fp, _Alloc, _Rp(_ArgTypes...)> _Fun; + typedef __rebind_alloc<__alloc_traits, _Fun> _FunAlloc; + + if (__function::__not_null(__f)) { + _FunAlloc __af(__a); + if (sizeof(_Fun) <= sizeof(__buf_) && is_nothrow_copy_constructible<_Fp>::value && + is_nothrow_copy_constructible<_FunAlloc>::value) { + __f_ = ::new ((void*)&__buf_) _Fun(std::move(__f), _Alloc(__af)); + } else { + typedef __allocator_destructor<_FunAlloc> _Dp; + unique_ptr<__func, _Dp> __hold(__af.allocate(1), _Dp(__af, 1)); + ::new ((void*)__hold.get()) _Fun(std::move(__f), _Alloc(__a)); + __f_ = __hold.release(); + } + } + } + + template , __value_func>::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI explicit __value_func(_Fp&& __f) : __value_func(std::forward<_Fp>(__f), allocator<_Fp>()) {} + + _LIBCPP_HIDE_FROM_ABI __value_func(const __value_func& __f) { + if (__f.__f_ == nullptr) + __f_ = nullptr; + else if ((void*)__f.__f_ == &__f.__buf_) { + __f_ = __as_base(&__buf_); + __f.__f_->__clone(__f_); + } else + __f_ = __f.__f_->__clone(); + } + + _LIBCPP_HIDE_FROM_ABI __value_func(__value_func&& __f) _NOEXCEPT { + if (__f.__f_ == nullptr) + __f_ = nullptr; + else if ((void*)__f.__f_ == &__f.__buf_) { + __f_ = __as_base(&__buf_); + __f.__f_->__clone(__f_); + } else { + __f_ = __f.__f_; + __f.__f_ = nullptr; + } + } + + _LIBCPP_HIDE_FROM_ABI ~__value_func() { + if ((void*)__f_ == &__buf_) + __f_->destroy(); + else if (__f_) + __f_->destroy_deallocate(); + } + + _LIBCPP_HIDE_FROM_ABI __value_func& operator=(__value_func&& __f) { + *this = nullptr; + if (__f.__f_ == nullptr) + __f_ = nullptr; + else if ((void*)__f.__f_ == &__f.__buf_) { + __f_ = __as_base(&__buf_); + __f.__f_->__clone(__f_); + } else { + __f_ = __f.__f_; + __f.__f_ = nullptr; + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI __value_func& operator=(nullptr_t) { + __func* __f = __f_; + __f_ = nullptr; + if ((void*)__f == &__buf_) + __f->destroy(); + else if (__f) + __f->destroy_deallocate(); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __args) const { + if (__f_ == nullptr) + __throw_bad_function_call(); + return (*__f_)(std::forward<_ArgTypes>(__args)...); + } + + _LIBCPP_HIDE_FROM_ABI void swap(__value_func& __f) _NOEXCEPT { + if (&__f == this) + return; + if ((void*)__f_ == &__buf_ && (void*)__f.__f_ == &__f.__buf_) { + _LIBCPP_SUPPRESS_DEPRECATED_PUSH + typename aligned_storage::type __tempbuf; + _LIBCPP_SUPPRESS_DEPRECATED_POP + __func* __t = __as_base(&__tempbuf); + __f_->__clone(__t); + __f_->destroy(); + __f_ = nullptr; + __f.__f_->__clone(__as_base(&__buf_)); + __f.__f_->destroy(); + __f.__f_ = nullptr; + __f_ = __as_base(&__buf_); + __t->__clone(__as_base(&__f.__buf_)); + __t->destroy(); + __f.__f_ = __as_base(&__f.__buf_); + } else if ((void*)__f_ == &__buf_) { + __f_->__clone(__as_base(&__f.__buf_)); + __f_->destroy(); + __f_ = __f.__f_; + __f.__f_ = __as_base(&__f.__buf_); + } else if ((void*)__f.__f_ == &__f.__buf_) { + __f.__f_->__clone(__as_base(&__buf_)); + __f.__f_->destroy(); + __f.__f_ = __f_; + __f_ = __as_base(&__buf_); + } else + std::swap(__f_, __f.__f_); + } + + _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __f_ != nullptr; } + +# ifndef _LIBCPP_HAS_NO_RTTI + _LIBCPP_HIDE_FROM_ABI const std::type_info& target_type() const _NOEXCEPT { + if (__f_ == nullptr) + return typeid(void); + return __f_->target_type(); + } + + template + _LIBCPP_HIDE_FROM_ABI const _Tp* target() const _NOEXCEPT { + if (__f_ == nullptr) + return nullptr; + return (const _Tp*)__f_->target(typeid(_Tp)); + } +# endif // _LIBCPP_HAS_NO_RTTI +}; + +// Storage for a functor object, to be used with __policy to manage copy and +// destruction. +union __policy_storage { + mutable char __small[sizeof(void*) * 2]; + void* __large; +}; + +// True if _Fun can safely be held in __policy_storage.__small. +template +struct __use_small_storage + : public integral_constant< + bool, + sizeof(_Fun) <= sizeof(__policy_storage)&& _LIBCPP_ALIGNOF(_Fun) <= _LIBCPP_ALIGNOF(__policy_storage) && + is_trivially_copy_constructible<_Fun>::value && is_trivially_destructible<_Fun>::value> {}; + +// Policy contains information about how to copy, destroy, and move the +// underlying functor. You can think of it as a vtable of sorts. +struct __policy { + // Used to copy or destroy __large values. null for trivial objects. + void* (*const __clone)(const void*); + void (*const __destroy)(void*); + + // True if this is the null policy (no value). + const bool __is_null; + + // The target type. May be null if RTTI is disabled. + const std::type_info* const __type_info; + + // Returns a pointer to a static policy object suitable for the functor + // type. + template + _LIBCPP_HIDE_FROM_ABI static const __policy* __create() { + return __choose_policy<_Fun>(__use_small_storage<_Fun>()); + } + + _LIBCPP_HIDE_FROM_ABI static const __policy* __create_empty() { + static constexpr __policy __policy = { + nullptr, + nullptr, + true, +# ifndef _LIBCPP_HAS_NO_RTTI + &typeid(void) +# else + nullptr +# endif + }; + return &__policy; + } + +private: + template + _LIBCPP_HIDE_FROM_ABI static void* __large_clone(const void* __s) { + const _Fun* __f = static_cast(__s); + return __f->__clone(); + } + + template + _LIBCPP_HIDE_FROM_ABI static void __large_destroy(void* __s) { + _Fun::__destroy_and_delete(static_cast<_Fun*>(__s)); + } + + template + _LIBCPP_HIDE_FROM_ABI static const __policy* __choose_policy(/* is_small = */ false_type) { + static constexpr __policy __policy = { + &__large_clone<_Fun>, + &__large_destroy<_Fun>, + false, +# ifndef _LIBCPP_HAS_NO_RTTI + &typeid(typename _Fun::_Target) +# else + nullptr +# endif + }; + return &__policy; + } + + template + _LIBCPP_HIDE_FROM_ABI static const __policy* __choose_policy(/* is_small = */ true_type) { + static constexpr __policy __policy = { + nullptr, + nullptr, + false, +# ifndef _LIBCPP_HAS_NO_RTTI + &typeid(typename _Fun::_Target) +# else + nullptr +# endif + }; + return &__policy; + } +}; + +// Used to choose between perfect forwarding or pass-by-value. Pass-by-value is +// faster for types that can be passed in registers. +template +using __fast_forward = __conditional_t::value, _Tp, _Tp&&>; + +// __policy_invoker calls an instance of __alloc_func held in __policy_storage. + +template +struct __policy_invoker; + +template +struct __policy_invoker<_Rp(_ArgTypes...)> { + typedef _Rp (*__Call)(const __policy_storage*, __fast_forward<_ArgTypes>...); + + __Call __call_; + + // Creates an invoker that throws bad_function_call. + _LIBCPP_HIDE_FROM_ABI __policy_invoker() : __call_(&__call_empty) {} + + // Creates an invoker that calls the given instance of __func. + template + _LIBCPP_HIDE_FROM_ABI static __policy_invoker __create() { + return __policy_invoker(&__call_impl<_Fun>); + } + +private: + _LIBCPP_HIDE_FROM_ABI explicit __policy_invoker(__Call __c) : __call_(__c) {} + + _LIBCPP_HIDE_FROM_ABI static _Rp __call_empty(const __policy_storage*, __fast_forward<_ArgTypes>...) { + __throw_bad_function_call(); + } + + template + _LIBCPP_HIDE_FROM_ABI static _Rp __call_impl(const __policy_storage* __buf, __fast_forward<_ArgTypes>... __args) { + _Fun* __f = reinterpret_cast<_Fun*>(__use_small_storage<_Fun>::value ? &__buf->__small : __buf->__large); + return (*__f)(std::forward<_ArgTypes>(__args)...); + } +}; + +// __policy_func uses a __policy and __policy_invoker to create a type-erased, +// copyable functor. + +template +class __policy_func; + +template +class __policy_func<_Rp(_ArgTypes...)> { + // Inline storage for small objects. + __policy_storage __buf_; + + // Calls the value stored in __buf_. This could technically be part of + // policy, but storing it here eliminates a level of indirection inside + // operator(). + typedef __function::__policy_invoker<_Rp(_ArgTypes...)> __invoker; + __invoker __invoker_; + + // The policy that describes how to move / copy / destroy __buf_. Never + // null, even if the function is empty. + const __policy* __policy_; + +public: + _LIBCPP_HIDE_FROM_ABI __policy_func() : __policy_(__policy::__create_empty()) {} + + template + _LIBCPP_HIDE_FROM_ABI __policy_func(_Fp&& __f, const _Alloc& __a) : __policy_(__policy::__create_empty()) { + typedef __alloc_func<_Fp, _Alloc, _Rp(_ArgTypes...)> _Fun; + typedef allocator_traits<_Alloc> __alloc_traits; + typedef __rebind_alloc<__alloc_traits, _Fun> _FunAlloc; + + if (__function::__not_null(__f)) { + __invoker_ = __invoker::template __create<_Fun>(); + __policy_ = __policy::__create<_Fun>(); + + _FunAlloc __af(__a); + if (__use_small_storage<_Fun>()) { + ::new ((void*)&__buf_.__small) _Fun(std::move(__f), _Alloc(__af)); + } else { + typedef __allocator_destructor<_FunAlloc> _Dp; + unique_ptr<_Fun, _Dp> __hold(__af.allocate(1), _Dp(__af, 1)); + ::new ((void*)__hold.get()) _Fun(std::move(__f), _Alloc(__af)); + __buf_.__large = __hold.release(); + } + } + } + + template , __policy_func>::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI explicit __policy_func(_Fp&& __f) : __policy_(__policy::__create_empty()) { + typedef __default_alloc_func<_Fp, _Rp(_ArgTypes...)> _Fun; + + if (__function::__not_null(__f)) { + __invoker_ = __invoker::template __create<_Fun>(); + __policy_ = __policy::__create<_Fun>(); + if (__use_small_storage<_Fun>()) { + ::new ((void*)&__buf_.__small) _Fun(std::move(__f)); + } else { + __builtin_new_allocator::__holder_t __hold = __builtin_new_allocator::__allocate_type<_Fun>(1); + __buf_.__large = ::new ((void*)__hold.get()) _Fun(std::move(__f)); + (void)__hold.release(); + } + } + } + + _LIBCPP_HIDE_FROM_ABI __policy_func(const __policy_func& __f) + : __buf_(__f.__buf_), __invoker_(__f.__invoker_), __policy_(__f.__policy_) { + if (__policy_->__clone) + __buf_.__large = __policy_->__clone(__f.__buf_.__large); + } + + _LIBCPP_HIDE_FROM_ABI __policy_func(__policy_func&& __f) + : __buf_(__f.__buf_), __invoker_(__f.__invoker_), __policy_(__f.__policy_) { + if (__policy_->__destroy) { + __f.__policy_ = __policy::__create_empty(); + __f.__invoker_ = __invoker(); + } + } + + _LIBCPP_HIDE_FROM_ABI ~__policy_func() { + if (__policy_->__destroy) + __policy_->__destroy(__buf_.__large); + } + + _LIBCPP_HIDE_FROM_ABI __policy_func& operator=(__policy_func&& __f) { + *this = nullptr; + __buf_ = __f.__buf_; + __invoker_ = __f.__invoker_; + __policy_ = __f.__policy_; + __f.__policy_ = __policy::__create_empty(); + __f.__invoker_ = __invoker(); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI __policy_func& operator=(nullptr_t) { + const __policy* __p = __policy_; + __policy_ = __policy::__create_empty(); + __invoker_ = __invoker(); + if (__p->__destroy) + __p->__destroy(__buf_.__large); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __args) const { + return __invoker_.__call_(std::addressof(__buf_), std::forward<_ArgTypes>(__args)...); + } + + _LIBCPP_HIDE_FROM_ABI void swap(__policy_func& __f) { + std::swap(__invoker_, __f.__invoker_); + std::swap(__policy_, __f.__policy_); + std::swap(__buf_, __f.__buf_); + } + + _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return !__policy_->__is_null; } + +# ifndef _LIBCPP_HAS_NO_RTTI + _LIBCPP_HIDE_FROM_ABI const std::type_info& target_type() const _NOEXCEPT { return *__policy_->__type_info; } + + template + _LIBCPP_HIDE_FROM_ABI const _Tp* target() const _NOEXCEPT { + if (__policy_->__is_null || typeid(_Tp) != *__policy_->__type_info) + return nullptr; + if (__policy_->__clone) // Out of line storage. + return reinterpret_cast(__buf_.__large); + else + return reinterpret_cast(&__buf_.__small); + } +# endif // _LIBCPP_HAS_NO_RTTI +}; + +# if defined(_LIBCPP_HAS_BLOCKS_RUNTIME) + +extern "C" void* _Block_copy(const void*); +extern "C" void _Block_release(const void*); + +template +class __func<_Rp1 (^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)> : public __base<_Rp(_ArgTypes...)> { + typedef _Rp1 (^__block_type)(_ArgTypes1...); + __block_type __f_; + +public: + _LIBCPP_HIDE_FROM_ABI explicit __func(__block_type const& __f) +# ifdef _LIBCPP_HAS_OBJC_ARC + : __f_(__f) +# else + : __f_(reinterpret_cast<__block_type>(__f ? _Block_copy(__f) : nullptr)) +# endif + { + } + + // [TODO] add && to save on a retain + + _LIBCPP_HIDE_FROM_ABI explicit __func(__block_type __f, const _Alloc& /* unused */) +# ifdef _LIBCPP_HAS_OBJC_ARC + : __f_(__f) +# else + : __f_(reinterpret_cast<__block_type>(__f ? _Block_copy(__f) : nullptr)) +# endif + { + } + + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual __base<_Rp(_ArgTypes...)>* __clone() const { + _LIBCPP_ASSERT_INTERNAL( + false, + "Block pointers are just pointers, so they should always fit into " + "std::function's small buffer optimization. This function should " + "never be invoked."); + return nullptr; + } + + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __clone(__base<_Rp(_ArgTypes...)>* __p) const { + ::new ((void*)__p) __func(__f_); + } + + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void destroy() _NOEXCEPT { +# ifndef _LIBCPP_HAS_OBJC_ARC + if (__f_) + _Block_release(__f_); +# endif + __f_ = 0; + } + + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void destroy_deallocate() _NOEXCEPT { + _LIBCPP_ASSERT_INTERNAL( + false, + "Block pointers are just pointers, so they should always fit into " + "std::function's small buffer optimization. This function should " + "never be invoked."); + } + + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual _Rp operator()(_ArgTypes&&... __arg) { + return std::__invoke(__f_, std::forward<_ArgTypes>(__arg)...); + } + +# ifndef _LIBCPP_HAS_NO_RTTI + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual const void* target(type_info const& __ti) const _NOEXCEPT { + if (__ti == typeid(__func::__block_type)) + return &__f_; + return (const void*)nullptr; + } + + _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual const std::type_info& target_type() const _NOEXCEPT { + return typeid(__func::__block_type); + } +# endif // _LIBCPP_HAS_NO_RTTI +}; + +# endif // _LIBCPP_HAS_EXTENSION_BLOCKS + +} // namespace __function + +template +class _LIBCPP_TEMPLATE_VIS function<_Rp(_ArgTypes...)> + : public __function::__maybe_derive_from_unary_function<_Rp(_ArgTypes...)>, + public __function::__maybe_derive_from_binary_function<_Rp(_ArgTypes...)> { +# ifndef _LIBCPP_ABI_OPTIMIZED_FUNCTION + typedef __function::__value_func<_Rp(_ArgTypes...)> __func; +# else + typedef __function::__policy_func<_Rp(_ArgTypes...)> __func; +# endif + + __func __f_; + + template , function>, __invokable<_Fp, _ArgTypes...> >::value> + struct __callable; + template + struct __callable<_Fp, true> { + static const bool value = + is_void<_Rp>::value || __is_core_convertible::type, _Rp>::value; + }; + template + struct __callable<_Fp, false> { + static const bool value = false; + }; + + template + using _EnableIfLValueCallable = __enable_if_t<__callable<_Fp&>::value>; + +public: + typedef _Rp result_type; + + // construct/copy/destroy: + _LIBCPP_HIDE_FROM_ABI function() _NOEXCEPT {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_HIDE_FROM_ABI function(nullptr_t) _NOEXCEPT {} + _LIBCPP_HIDE_FROM_ABI function(const function&); + _LIBCPP_HIDE_FROM_ABI function(function&&) _NOEXCEPT; + template > + _LIBCPP_HIDE_FROM_ABI function(_Fp); + +# if _LIBCPP_STD_VER <= 14 + template + _LIBCPP_HIDE_FROM_ABI function(allocator_arg_t, const _Alloc&) _NOEXCEPT {} + template + _LIBCPP_HIDE_FROM_ABI function(allocator_arg_t, const _Alloc&, nullptr_t) _NOEXCEPT {} + template + _LIBCPP_HIDE_FROM_ABI function(allocator_arg_t, const _Alloc&, const function&); + template + _LIBCPP_HIDE_FROM_ABI function(allocator_arg_t, const _Alloc&, function&&); + template > + _LIBCPP_HIDE_FROM_ABI function(allocator_arg_t, const _Alloc& __a, _Fp __f); +# endif + + _LIBCPP_HIDE_FROM_ABI function& operator=(const function&); + _LIBCPP_HIDE_FROM_ABI function& operator=(function&&) _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI function& operator=(nullptr_t) _NOEXCEPT; + template >> + _LIBCPP_HIDE_FROM_ABI function& operator=(_Fp&&); + + _LIBCPP_HIDE_FROM_ABI ~function(); + + // function modifiers: + _LIBCPP_HIDE_FROM_ABI void swap(function&) _NOEXCEPT; + +# if _LIBCPP_STD_VER <= 14 + template + _LIBCPP_HIDE_FROM_ABI void assign(_Fp&& __f, const _Alloc& __a) { + function(allocator_arg, __a, std::forward<_Fp>(__f)).swap(*this); + } +# endif + + // function capacity: + _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return static_cast(__f_); } + + // deleted overloads close possible hole in the type system + template + bool operator==(const function<_R2(_ArgTypes2...)>&) const = delete; +# if _LIBCPP_STD_VER <= 17 + template + bool operator!=(const function<_R2(_ArgTypes2...)>&) const = delete; +# endif + +public: + // function invocation: + _LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes...) const; + +# ifndef _LIBCPP_HAS_NO_RTTI + // function target access: + _LIBCPP_HIDE_FROM_ABI const std::type_info& target_type() const _NOEXCEPT; + template + _LIBCPP_HIDE_FROM_ABI _Tp* target() _NOEXCEPT; + template + _LIBCPP_HIDE_FROM_ABI const _Tp* target() const _NOEXCEPT; +# endif // _LIBCPP_HAS_NO_RTTI +}; + +# if _LIBCPP_STD_VER >= 17 +template +function(_Rp (*)(_Ap...)) -> function<_Rp(_Ap...)>; + +template ::type> +function(_Fp) -> function<_Stripped>; +# endif // _LIBCPP_STD_VER >= 17 + +template +function<_Rp(_ArgTypes...)>::function(const function& __f) : __f_(__f.__f_) {} + +# if _LIBCPP_STD_VER <= 14 +template +template +function<_Rp(_ArgTypes...)>::function(allocator_arg_t, const _Alloc&, const function& __f) : __f_(__f.__f_) {} +# endif + +template +function<_Rp(_ArgTypes...)>::function(function&& __f) _NOEXCEPT : __f_(std::move(__f.__f_)) {} + +# if _LIBCPP_STD_VER <= 14 +template +template +function<_Rp(_ArgTypes...)>::function(allocator_arg_t, const _Alloc&, function&& __f) : __f_(std::move(__f.__f_)) {} +# endif + +template +template +function<_Rp(_ArgTypes...)>::function(_Fp __f) : __f_(std::move(__f)) {} + +# if _LIBCPP_STD_VER <= 14 +template +template +function<_Rp(_ArgTypes...)>::function(allocator_arg_t, const _Alloc& __a, _Fp __f) : __f_(std::move(__f), __a) {} +# endif + +template +function<_Rp(_ArgTypes...)>& function<_Rp(_ArgTypes...)>::operator=(const function& __f) { + function(__f).swap(*this); + return *this; +} + +template +function<_Rp(_ArgTypes...)>& function<_Rp(_ArgTypes...)>::operator=(function&& __f) _NOEXCEPT { + __f_ = std::move(__f.__f_); + return *this; +} + +template +function<_Rp(_ArgTypes...)>& function<_Rp(_ArgTypes...)>::operator=(nullptr_t) _NOEXCEPT { + __f_ = nullptr; + return *this; +} + +template +template +function<_Rp(_ArgTypes...)>& function<_Rp(_ArgTypes...)>::operator=(_Fp&& __f) { + function(std::forward<_Fp>(__f)).swap(*this); + return *this; +} + +template +function<_Rp(_ArgTypes...)>::~function() {} + +template +void function<_Rp(_ArgTypes...)>::swap(function& __f) _NOEXCEPT { + __f_.swap(__f.__f_); +} + +template +_Rp function<_Rp(_ArgTypes...)>::operator()(_ArgTypes... __arg) const { + return __f_(std::forward<_ArgTypes>(__arg)...); +} + +# ifndef _LIBCPP_HAS_NO_RTTI + +template +const std::type_info& function<_Rp(_ArgTypes...)>::target_type() const _NOEXCEPT { + return __f_.target_type(); +} + +template +template +_Tp* function<_Rp(_ArgTypes...)>::target() _NOEXCEPT { + return (_Tp*)(__f_.template target<_Tp>()); +} + +template +template +const _Tp* function<_Rp(_ArgTypes...)>::target() const _NOEXCEPT { + return __f_.template target<_Tp>(); +} + +# endif // _LIBCPP_HAS_NO_RTTI + +template +inline _LIBCPP_HIDE_FROM_ABI bool operator==(const function<_Rp(_ArgTypes...)>& __f, nullptr_t) _NOEXCEPT { + return !__f; +} + +# if _LIBCPP_STD_VER <= 17 + +template +inline _LIBCPP_HIDE_FROM_ABI bool operator==(nullptr_t, const function<_Rp(_ArgTypes...)>& __f) _NOEXCEPT { + return !__f; +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const function<_Rp(_ArgTypes...)>& __f, nullptr_t) _NOEXCEPT { + return (bool)__f; +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool operator!=(nullptr_t, const function<_Rp(_ArgTypes...)>& __f) _NOEXCEPT { + return (bool)__f; +} + +# endif // _LIBCPP_STD_VER <= 17 + +template +inline _LIBCPP_HIDE_FROM_ABI void swap(function<_Rp(_ArgTypes...)>& __x, function<_Rp(_ArgTypes...)>& __y) _NOEXCEPT { + return __x.swap(__y); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_CXX03_LANG + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FUNCTIONAL_FUNCTION_H diff --git a/libcxx/include/__cxx03/__functional/hash.h b/libcxx/include/__cxx03/__functional/hash.h new file mode 100644 index 0000000000000000000000000000000000000000..a9e450edd39f5352146901d546254a19e1d5b0a5 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/hash.h @@ -0,0 +1,542 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_HASH_H +#define _LIBCPP___FUNCTIONAL_HASH_H + +#include <__config> +#include <__functional/unary_function.h> +#include <__fwd/functional.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_enum.h> +#include <__type_traits/underlying_type.h> +#include <__utility/pair.h> +#include <__utility/swap.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _Size __loadword(const void* __p) { + _Size __r; + std::memcpy(&__r, __p, sizeof(__r)); + return __r; +} + +// We use murmur2 when size_t is 32 bits, and cityhash64 when size_t +// is 64 bits. This is because cityhash64 uses 64bit x 64bit +// multiplication, which can be very slow on 32-bit systems. +template +struct __murmur2_or_cityhash; + +template +struct __murmur2_or_cityhash<_Size, 32> { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK _Size + operator()(const void* __key, _Size __len) const { + // murmur2 + const _Size __m = 0x5bd1e995; + const _Size __r = 24; + _Size __h = __len; + const unsigned char* __data = static_cast(__key); + for (; __len >= 4; __data += 4, __len -= 4) { + _Size __k = std::__loadword<_Size>(__data); + __k *= __m; + __k ^= __k >> __r; + __k *= __m; + __h *= __m; + __h ^= __k; + } + switch (__len) { + case 3: + __h ^= static_cast<_Size>(__data[2] << 16); + _LIBCPP_FALLTHROUGH(); + case 2: + __h ^= static_cast<_Size>(__data[1] << 8); + _LIBCPP_FALLTHROUGH(); + case 1: + __h ^= __data[0]; + __h *= __m; + } + __h ^= __h >> 13; + __h *= __m; + __h ^= __h >> 15; + return __h; + } +}; + +template +struct __murmur2_or_cityhash<_Size, 64> { + // cityhash64 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK _Size + operator()(const void* __key, _Size __len) const { + const char* __s = static_cast(__key); + if (__len <= 32) { + if (__len <= 16) { + return __hash_len_0_to_16(__s, __len); + } else { + return __hash_len_17_to_32(__s, __len); + } + } else if (__len <= 64) { + return __hash_len_33_to_64(__s, __len); + } + + // For strings over 64 bytes we hash the end first, and then as we + // loop we keep 56 bytes of state: v, w, x, y, and z. + _Size __x = std::__loadword<_Size>(__s + __len - 40); + _Size __y = std::__loadword<_Size>(__s + __len - 16) + std::__loadword<_Size>(__s + __len - 56); + _Size __z = + __hash_len_16(std::__loadword<_Size>(__s + __len - 48) + __len, std::__loadword<_Size>(__s + __len - 24)); + pair<_Size, _Size> __v = __weak_hash_len_32_with_seeds(__s + __len - 64, __len, __z); + pair<_Size, _Size> __w = __weak_hash_len_32_with_seeds(__s + __len - 32, __y + __k1, __x); + __x = __x * __k1 + std::__loadword<_Size>(__s); + + // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. + __len = (__len - 1) & ~static_cast<_Size>(63); + do { + __x = __rotate(__x + __y + __v.first + std::__loadword<_Size>(__s + 8), 37) * __k1; + __y = __rotate(__y + __v.second + std::__loadword<_Size>(__s + 48), 42) * __k1; + __x ^= __w.second; + __y += __v.first + std::__loadword<_Size>(__s + 40); + __z = __rotate(__z + __w.first, 33) * __k1; + __v = __weak_hash_len_32_with_seeds(__s, __v.second * __k1, __x + __w.first); + __w = __weak_hash_len_32_with_seeds(__s + 32, __z + __w.second, __y + std::__loadword<_Size>(__s + 16)); + std::swap(__z, __x); + __s += 64; + __len -= 64; + } while (__len != 0); + return __hash_len_16(__hash_len_16(__v.first, __w.first) + __shift_mix(__y) * __k1 + __z, + __hash_len_16(__v.second, __w.second) + __x); + } + +private: + // Some primes between 2^63 and 2^64. + static const _Size __k0 = 0xc3a5c85c97cb3127ULL; + static const _Size __k1 = 0xb492b66fbe98f273ULL; + static const _Size __k2 = 0x9ae16a3b2f90404fULL; + static const _Size __k3 = 0xc949d7c7509e6557ULL; + + _LIBCPP_HIDE_FROM_ABI static _Size __rotate(_Size __val, int __shift) { + return __shift == 0 ? __val : ((__val >> __shift) | (__val << (64 - __shift))); + } + + _LIBCPP_HIDE_FROM_ABI static _Size __rotate_by_at_least_1(_Size __val, int __shift) { + return (__val >> __shift) | (__val << (64 - __shift)); + } + + _LIBCPP_HIDE_FROM_ABI static _Size __shift_mix(_Size __val) { return __val ^ (__val >> 47); } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK static _Size __hash_len_16(_Size __u, _Size __v) { + const _Size __mul = 0x9ddfea08eb382d69ULL; + _Size __a = (__u ^ __v) * __mul; + __a ^= (__a >> 47); + _Size __b = (__v ^ __a) * __mul; + __b ^= (__b >> 47); + __b *= __mul; + return __b; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK static _Size + __hash_len_0_to_16(const char* __s, _Size __len) { + if (__len > 8) { + const _Size __a = std::__loadword<_Size>(__s); + const _Size __b = std::__loadword<_Size>(__s + __len - 8); + return __hash_len_16(__a, __rotate_by_at_least_1(__b + __len, __len)) ^ __b; + } + if (__len >= 4) { + const uint32_t __a = std::__loadword(__s); + const uint32_t __b = std::__loadword(__s + __len - 4); +#ifdef _LIBCPP_ABI_FIX_CITYHASH_IMPLEMENTATION + return __hash_len_16(__len + (static_cast<_Size>(__a) << 3), __b); +#else + return __hash_len_16(__len + (__a << 3), __b); +#endif + } + if (__len > 0) { + const unsigned char __a = static_cast(__s[0]); + const unsigned char __b = static_cast(__s[__len >> 1]); + const unsigned char __c = static_cast(__s[__len - 1]); + const uint32_t __y = static_cast(__a) + (static_cast(__b) << 8); + const uint32_t __z = __len + (static_cast(__c) << 2); + return __shift_mix(__y * __k2 ^ __z * __k3) * __k2; + } + return __k2; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK static _Size + __hash_len_17_to_32(const char* __s, _Size __len) { + const _Size __a = std::__loadword<_Size>(__s) * __k1; + const _Size __b = std::__loadword<_Size>(__s + 8); + const _Size __c = std::__loadword<_Size>(__s + __len - 8) * __k2; + const _Size __d = std::__loadword<_Size>(__s + __len - 16) * __k0; + return __hash_len_16( + __rotate(__a - __b, 43) + __rotate(__c, 30) + __d, __a + __rotate(__b ^ __k3, 20) - __c + __len); + } + + // Return a 16-byte hash for 48 bytes. Quick and dirty. + // Callers do best to use "random-looking" values for a and b. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK static pair<_Size, _Size> + __weak_hash_len_32_with_seeds(_Size __w, _Size __x, _Size __y, _Size __z, _Size __a, _Size __b) { + __a += __w; + __b = __rotate(__b + __a + __z, 21); + const _Size __c = __a; + __a += __x; + __a += __y; + __b += __rotate(__a, 44); + return pair<_Size, _Size>(__a + __z, __b + __c); + } + + // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK static pair<_Size, _Size> + __weak_hash_len_32_with_seeds(const char* __s, _Size __a, _Size __b) { + return __weak_hash_len_32_with_seeds( + std::__loadword<_Size>(__s), + std::__loadword<_Size>(__s + 8), + std::__loadword<_Size>(__s + 16), + std::__loadword<_Size>(__s + 24), + __a, + __b); + } + + // Return an 8-byte hash for 33 to 64 bytes. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK static _Size + __hash_len_33_to_64(const char* __s, size_t __len) { + _Size __z = std::__loadword<_Size>(__s + 24); + _Size __a = std::__loadword<_Size>(__s) + (__len + std::__loadword<_Size>(__s + __len - 16)) * __k0; + _Size __b = __rotate(__a + __z, 52); + _Size __c = __rotate(__a, 37); + __a += std::__loadword<_Size>(__s + 8); + __c += __rotate(__a, 7); + __a += std::__loadword<_Size>(__s + 16); + _Size __vf = __a + __z; + _Size __vs = __b + __rotate(__a, 31) + __c; + __a = std::__loadword<_Size>(__s + 16) + std::__loadword<_Size>(__s + __len - 32); + __z += std::__loadword<_Size>(__s + __len - 8); + __b = __rotate(__a + __z, 52); + __c = __rotate(__a, 37); + __a += std::__loadword<_Size>(__s + __len - 24); + __c += __rotate(__a, 7); + __a += std::__loadword<_Size>(__s + __len - 16); + _Size __wf = __a + __z; + _Size __ws = __b + __rotate(__a, 31) + __c; + _Size __r = __shift_mix((__vf + __ws) * __k2 + (__wf + __vs) * __k0); + return __shift_mix(__r * __k0 + __vs) * __k2; + } +}; + +template +struct __scalar_hash; + +template +struct __scalar_hash<_Tp, 0> : public __unary_function<_Tp, size_t> { + _LIBCPP_HIDE_FROM_ABI size_t operator()(_Tp __v) const _NOEXCEPT { + union { + _Tp __t; + size_t __a; + } __u; + __u.__a = 0; + __u.__t = __v; + return __u.__a; + } +}; + +template +struct __scalar_hash<_Tp, 1> : public __unary_function<_Tp, size_t> { + _LIBCPP_HIDE_FROM_ABI size_t operator()(_Tp __v) const _NOEXCEPT { + union { + _Tp __t; + size_t __a; + } __u; + __u.__t = __v; + return __u.__a; + } +}; + +template +struct __scalar_hash<_Tp, 2> : public __unary_function<_Tp, size_t> { + _LIBCPP_HIDE_FROM_ABI size_t operator()(_Tp __v) const _NOEXCEPT { + union { + _Tp __t; + struct { + size_t __a; + size_t __b; + } __s; + } __u; + __u.__t = __v; + return __murmur2_or_cityhash()(&__u, sizeof(__u)); + } +}; + +template +struct __scalar_hash<_Tp, 3> : public __unary_function<_Tp, size_t> { + _LIBCPP_HIDE_FROM_ABI size_t operator()(_Tp __v) const _NOEXCEPT { + union { + _Tp __t; + struct { + size_t __a; + size_t __b; + size_t __c; + } __s; + } __u; + __u.__t = __v; + return __murmur2_or_cityhash()(&__u, sizeof(__u)); + } +}; + +template +struct __scalar_hash<_Tp, 4> : public __unary_function<_Tp, size_t> { + _LIBCPP_HIDE_FROM_ABI size_t operator()(_Tp __v) const _NOEXCEPT { + union { + _Tp __t; + struct { + size_t __a; + size_t __b; + size_t __c; + size_t __d; + } __s; + } __u; + __u.__t = __v; + return __murmur2_or_cityhash()(&__u, sizeof(__u)); + } +}; + +struct _PairT { + size_t first; + size_t second; +}; + +_LIBCPP_HIDE_FROM_ABI inline size_t __hash_combine(size_t __lhs, size_t __rhs) _NOEXCEPT { + typedef __scalar_hash<_PairT> _HashT; + const _PairT __p = {__lhs, __rhs}; + return _HashT()(__p); +} + +template +struct _LIBCPP_TEMPLATE_VIS hash<_Tp*> : public __unary_function<_Tp*, size_t> { + _LIBCPP_HIDE_FROM_ABI size_t operator()(_Tp* __v) const _NOEXCEPT { + union { + _Tp* __t; + size_t __a; + } __u; + __u.__t = __v; + return __murmur2_or_cityhash()(&__u, sizeof(__u)); + } +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(bool __v) const _NOEXCEPT { return static_cast(__v); } +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(char __v) const _NOEXCEPT { return static_cast(__v); } +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(signed char __v) const _NOEXCEPT { return static_cast(__v); } +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(unsigned char __v) const _NOEXCEPT { return static_cast(__v); } +}; + +#ifndef _LIBCPP_HAS_NO_CHAR8_T +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(char8_t __v) const _NOEXCEPT { return static_cast(__v); } +}; +#endif // !_LIBCPP_HAS_NO_CHAR8_T + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(char16_t __v) const _NOEXCEPT { return static_cast(__v); } +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(char32_t __v) const _NOEXCEPT { return static_cast(__v); } +}; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(wchar_t __v) const _NOEXCEPT { return static_cast(__v); } +}; +#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(short __v) const _NOEXCEPT { return static_cast(__v); } +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(unsigned short __v) const _NOEXCEPT { return static_cast(__v); } +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(int __v) const _NOEXCEPT { return static_cast(__v); } +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(unsigned int __v) const _NOEXCEPT { return static_cast(__v); } +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(long __v) const _NOEXCEPT { return static_cast(__v); } +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(unsigned long __v) const _NOEXCEPT { return static_cast(__v); } +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __scalar_hash {}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __scalar_hash {}; + +#ifndef _LIBCPP_HAS_NO_INT128 + +template <> +struct _LIBCPP_TEMPLATE_VIS hash<__int128_t> : public __scalar_hash<__int128_t> {}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash<__uint128_t> : public __scalar_hash<__uint128_t> {}; + +#endif + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __scalar_hash { + _LIBCPP_HIDE_FROM_ABI size_t operator()(float __v) const _NOEXCEPT { + // -0.0 and 0.0 should return same hash + if (__v == 0.0f) + return 0; + return __scalar_hash::operator()(__v); + } +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __scalar_hash { + _LIBCPP_HIDE_FROM_ABI size_t operator()(double __v) const _NOEXCEPT { + // -0.0 and 0.0 should return same hash + if (__v == 0.0) + return 0; + return __scalar_hash::operator()(__v); + } +}; + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __scalar_hash { + _LIBCPP_HIDE_FROM_ABI size_t operator()(long double __v) const _NOEXCEPT { + // -0.0 and 0.0 should return same hash + if (__v == 0.0L) + return 0; +#if defined(__i386__) || (defined(__x86_64__) && defined(__ILP32__)) + // Zero out padding bits + union { + long double __t; + struct { + size_t __a; + size_t __b; + size_t __c; + size_t __d; + } __s; + } __u; + __u.__s.__a = 0; + __u.__s.__b = 0; + __u.__s.__c = 0; + __u.__s.__d = 0; + __u.__t = __v; + return __u.__s.__a ^ __u.__s.__b ^ __u.__s.__c ^ __u.__s.__d; +#elif defined(__x86_64__) + // Zero out padding bits + union { + long double __t; + struct { + size_t __a; + size_t __b; + } __s; + } __u; + __u.__s.__a = 0; + __u.__s.__b = 0; + __u.__t = __v; + return __u.__s.__a ^ __u.__s.__b; +#else + return __scalar_hash::operator()(__v); +#endif + } +}; + +template ::value> +struct _LIBCPP_TEMPLATE_VIS __enum_hash : public __unary_function<_Tp, size_t> { + _LIBCPP_HIDE_FROM_ABI size_t operator()(_Tp __v) const _NOEXCEPT { + typedef typename underlying_type<_Tp>::type type; + return hash()(static_cast(__v)); + } +}; +template +struct _LIBCPP_TEMPLATE_VIS __enum_hash<_Tp, false> { + __enum_hash() = delete; + __enum_hash(__enum_hash const&) = delete; + __enum_hash& operator=(__enum_hash const&) = delete; +}; + +template +struct _LIBCPP_TEMPLATE_VIS hash : public __enum_hash<_Tp> {}; + +#if _LIBCPP_STD_VER >= 17 + +template <> +struct _LIBCPP_TEMPLATE_VIS hash : public __unary_function { + _LIBCPP_HIDE_FROM_ABI size_t operator()(nullptr_t) const _NOEXCEPT { return 662607004ull; } +}; +#endif + +#ifndef _LIBCPP_CXX03_LANG +template +using __check_hash_requirements _LIBCPP_NODEBUG = + integral_constant::value && is_move_constructible<_Hash>::value && + __invokable_r::value >; + +template > +using __has_enabled_hash _LIBCPP_NODEBUG = + integral_constant::value && is_default_constructible<_Hash>::value >; + +# if _LIBCPP_STD_VER >= 17 +template +using __enable_hash_helper_imp _LIBCPP_NODEBUG = _Type; + +template +using __enable_hash_helper _LIBCPP_NODEBUG = + __enable_hash_helper_imp<_Type, __enable_if_t<__all<__has_enabled_hash<_Keys>::value...>::value> >; +# else +template +using __enable_hash_helper _LIBCPP_NODEBUG = _Type; +# endif + +#endif // !_LIBCPP_CXX03_LANG + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_HASH_H diff --git a/libcxx/include/__cxx03/__functional/identity.h b/libcxx/include/__cxx03/__functional/identity.h new file mode 100644 index 0000000000000000000000000000000000000000..8468de3dae26c2ca4a1657a1f23688c684afc699 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/identity.h @@ -0,0 +1,65 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_IDENTITY_H +#define _LIBCPP___FUNCTIONAL_IDENTITY_H + +#include <__config> +#include <__fwd/functional.h> +#include <__type_traits/integral_constant.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __is_identity : false_type {}; + +struct __identity { + template + _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp&& operator()(_Tp&& __t) const _NOEXCEPT { + return std::forward<_Tp>(__t); + } + + using is_transparent = void; +}; + +template <> +struct __is_identity<__identity> : true_type {}; +template <> +struct __is_identity > : true_type {}; +template <> +struct __is_identity > : true_type {}; + +#if _LIBCPP_STD_VER >= 20 + +struct identity { + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator()(_Tp&& __t) const noexcept { + return std::forward<_Tp>(__t); + } + + using is_transparent = void; +}; + +template <> +struct __is_identity : true_type {}; +template <> +struct __is_identity > : true_type {}; +template <> +struct __is_identity > : true_type {}; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_IDENTITY_H diff --git a/libcxx/include/__cxx03/__functional/invoke.h b/libcxx/include/__cxx03/__functional/invoke.h new file mode 100644 index 0000000000000000000000000000000000000000..ef4bf25f07759f790a19122e678b6fe5b56c19b7 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/invoke.h @@ -0,0 +1,54 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_INVOKE_H +#define _LIBCPP___FUNCTIONAL_INVOKE_H + +#include <__config> +#include <__type_traits/invoke.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 invoke_result_t<_Fn, _Args...> +invoke(_Fn&& __f, _Args&&... __args) noexcept(is_nothrow_invocable_v<_Fn, _Args...>) { + return std::__invoke(std::forward<_Fn>(__f), std::forward<_Args>(__args)...); +} + +#endif // _LIBCPP_STD_VER >= 17 + +#if _LIBCPP_STD_VER >= 23 +template + requires is_invocable_r_v<_Result, _Fn, _Args...> +_LIBCPP_HIDE_FROM_ABI constexpr _Result +invoke_r(_Fn&& __f, _Args&&... __args) noexcept(is_nothrow_invocable_r_v<_Result, _Fn, _Args...>) { + if constexpr (is_void_v<_Result>) { + static_cast(std::invoke(std::forward<_Fn>(__f), std::forward<_Args>(__args)...)); + } else { + // TODO: Use reference_converts_from_temporary_v once implemented + // using _ImplicitInvokeResult = invoke_result_t<_Fn, _Args...>; + // static_assert(!reference_converts_from_temporary_v<_Result, _ImplicitInvokeResult>, + static_assert(true, + "Returning from invoke_r would bind a temporary object to the reference return type, " + "which would result in a dangling reference."); + return std::invoke(std::forward<_Fn>(__f), std::forward<_Args>(__args)...); + } +} +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_INVOKE_H diff --git a/libcxx/include/__cxx03/__functional/is_transparent.h b/libcxx/include/__cxx03/__functional/is_transparent.h new file mode 100644 index 0000000000000000000000000000000000000000..b2d62f2e3ead84134f80cf85cd94747decaaa37a --- /dev/null +++ b/libcxx/include/__cxx03/__functional/is_transparent.h @@ -0,0 +1,34 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_IS_TRANSPARENT +#define _LIBCPP___FUNCTIONAL_IS_TRANSPARENT + +#include <__config> +#include <__type_traits/void_t.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 14 + +template +inline const bool __is_transparent_v = false; + +template +inline const bool __is_transparent_v<_Tp, _Up, __void_t > = true; + +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_IS_TRANSPARENT diff --git a/libcxx/include/__cxx03/__functional/mem_fn.h b/libcxx/include/__cxx03/__functional/mem_fn.h new file mode 100644 index 0000000000000000000000000000000000000000..ee07a71774f9a9deba1f014e4d8755823bed277b --- /dev/null +++ b/libcxx/include/__cxx03/__functional/mem_fn.h @@ -0,0 +1,54 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_MEM_FN_H +#define _LIBCPP___FUNCTIONAL_MEM_FN_H + +#include <__config> +#include <__functional/binary_function.h> +#include <__functional/invoke.h> +#include <__functional/weak_result_type.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class __mem_fn : public __weak_result_type<_Tp> { +public: + // types + typedef _Tp type; + +private: + type __f_; + +public: + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __mem_fn(type __f) _NOEXCEPT : __f_(__f) {} + + // invoke + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + + typename __invoke_return::type + operator()(_ArgTypes&&... __args) const { + return std::__invoke(__f_, std::forward<_ArgTypes>(__args)...); + } +}; + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __mem_fn<_Rp _Tp::*> mem_fn(_Rp _Tp::*__pm) _NOEXCEPT { + return __mem_fn<_Rp _Tp::*>(__pm); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_MEM_FN_H diff --git a/libcxx/include/__cxx03/__functional/mem_fun_ref.h b/libcxx/include/__cxx03/__functional/mem_fun_ref.h new file mode 100644 index 0000000000000000000000000000000000000000..c344420b0299e04de31f4dec542f8079ee84e208 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/mem_fun_ref.h @@ -0,0 +1,146 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_MEM_FUN_REF_H +#define _LIBCPP___FUNCTIONAL_MEM_FUN_REF_H + +#include <__config> +#include <__functional/binary_function.h> +#include <__functional/unary_function.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_BINDERS) + +template +class _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 mem_fun_t : public __unary_function<_Tp*, _Sp> { + _Sp (_Tp::*__p_)(); + +public: + _LIBCPP_HIDE_FROM_ABI explicit mem_fun_t(_Sp (_Tp::*__p)()) : __p_(__p) {} + _LIBCPP_HIDE_FROM_ABI _Sp operator()(_Tp* __p) const { return (__p->*__p_)(); } +}; + +template +class _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 mem_fun1_t : public __binary_function<_Tp*, _Ap, _Sp> { + _Sp (_Tp::*__p_)(_Ap); + +public: + _LIBCPP_HIDE_FROM_ABI explicit mem_fun1_t(_Sp (_Tp::*__p)(_Ap)) : __p_(__p) {} + _LIBCPP_HIDE_FROM_ABI _Sp operator()(_Tp* __p, _Ap __x) const { return (__p->*__p_)(__x); } +}; + +template +_LIBCPP_DEPRECATED_IN_CXX11 inline _LIBCPP_HIDE_FROM_ABI mem_fun_t<_Sp, _Tp> mem_fun(_Sp (_Tp::*__f)()) { + return mem_fun_t<_Sp, _Tp>(__f); +} + +template +_LIBCPP_DEPRECATED_IN_CXX11 inline _LIBCPP_HIDE_FROM_ABI mem_fun1_t<_Sp, _Tp, _Ap> mem_fun(_Sp (_Tp::*__f)(_Ap)) { + return mem_fun1_t<_Sp, _Tp, _Ap>(__f); +} + +template +class _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 mem_fun_ref_t : public __unary_function<_Tp, _Sp> { + _Sp (_Tp::*__p_)(); + +public: + _LIBCPP_HIDE_FROM_ABI explicit mem_fun_ref_t(_Sp (_Tp::*__p)()) : __p_(__p) {} + _LIBCPP_HIDE_FROM_ABI _Sp operator()(_Tp& __p) const { return (__p.*__p_)(); } +}; + +template +class _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 mem_fun1_ref_t : public __binary_function<_Tp, _Ap, _Sp> { + _Sp (_Tp::*__p_)(_Ap); + +public: + _LIBCPP_HIDE_FROM_ABI explicit mem_fun1_ref_t(_Sp (_Tp::*__p)(_Ap)) : __p_(__p) {} + _LIBCPP_HIDE_FROM_ABI _Sp operator()(_Tp& __p, _Ap __x) const { return (__p.*__p_)(__x); } +}; + +template +_LIBCPP_DEPRECATED_IN_CXX11 inline _LIBCPP_HIDE_FROM_ABI mem_fun_ref_t<_Sp, _Tp> mem_fun_ref(_Sp (_Tp::*__f)()) { + return mem_fun_ref_t<_Sp, _Tp>(__f); +} + +template +_LIBCPP_DEPRECATED_IN_CXX11 inline _LIBCPP_HIDE_FROM_ABI mem_fun1_ref_t<_Sp, _Tp, _Ap> +mem_fun_ref(_Sp (_Tp::*__f)(_Ap)) { + return mem_fun1_ref_t<_Sp, _Tp, _Ap>(__f); +} + +template +class _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 const_mem_fun_t : public __unary_function { + _Sp (_Tp::*__p_)() const; + +public: + _LIBCPP_HIDE_FROM_ABI explicit const_mem_fun_t(_Sp (_Tp::*__p)() const) : __p_(__p) {} + _LIBCPP_HIDE_FROM_ABI _Sp operator()(const _Tp* __p) const { return (__p->*__p_)(); } +}; + +template +class _LIBCPP_TEMPLATE_VIS +_LIBCPP_DEPRECATED_IN_CXX11 const_mem_fun1_t : public __binary_function { + _Sp (_Tp::*__p_)(_Ap) const; + +public: + _LIBCPP_HIDE_FROM_ABI explicit const_mem_fun1_t(_Sp (_Tp::*__p)(_Ap) const) : __p_(__p) {} + _LIBCPP_HIDE_FROM_ABI _Sp operator()(const _Tp* __p, _Ap __x) const { return (__p->*__p_)(__x); } +}; + +template +_LIBCPP_DEPRECATED_IN_CXX11 inline _LIBCPP_HIDE_FROM_ABI const_mem_fun_t<_Sp, _Tp> mem_fun(_Sp (_Tp::*__f)() const) { + return const_mem_fun_t<_Sp, _Tp>(__f); +} + +template +_LIBCPP_DEPRECATED_IN_CXX11 inline _LIBCPP_HIDE_FROM_ABI const_mem_fun1_t<_Sp, _Tp, _Ap> +mem_fun(_Sp (_Tp::*__f)(_Ap) const) { + return const_mem_fun1_t<_Sp, _Tp, _Ap>(__f); +} + +template +class _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 const_mem_fun_ref_t : public __unary_function<_Tp, _Sp> { + _Sp (_Tp::*__p_)() const; + +public: + _LIBCPP_HIDE_FROM_ABI explicit const_mem_fun_ref_t(_Sp (_Tp::*__p)() const) : __p_(__p) {} + _LIBCPP_HIDE_FROM_ABI _Sp operator()(const _Tp& __p) const { return (__p.*__p_)(); } +}; + +template +class _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 const_mem_fun1_ref_t : public __binary_function<_Tp, _Ap, _Sp> { + _Sp (_Tp::*__p_)(_Ap) const; + +public: + _LIBCPP_HIDE_FROM_ABI explicit const_mem_fun1_ref_t(_Sp (_Tp::*__p)(_Ap) const) : __p_(__p) {} + _LIBCPP_HIDE_FROM_ABI _Sp operator()(const _Tp& __p, _Ap __x) const { return (__p.*__p_)(__x); } +}; + +template +_LIBCPP_DEPRECATED_IN_CXX11 inline _LIBCPP_HIDE_FROM_ABI const_mem_fun_ref_t<_Sp, _Tp> +mem_fun_ref(_Sp (_Tp::*__f)() const) { + return const_mem_fun_ref_t<_Sp, _Tp>(__f); +} + +template +_LIBCPP_DEPRECATED_IN_CXX11 inline _LIBCPP_HIDE_FROM_ABI const_mem_fun1_ref_t<_Sp, _Tp, _Ap> +mem_fun_ref(_Sp (_Tp::*__f)(_Ap) const) { + return const_mem_fun1_ref_t<_Sp, _Tp, _Ap>(__f); +} + +#endif // _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_BINDERS) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_MEM_FUN_REF_H diff --git a/libcxx/include/__cxx03/__functional/not_fn.h b/libcxx/include/__cxx03/__functional/not_fn.h new file mode 100644 index 0000000000000000000000000000000000000000..4b3ce5524a7434ec098ec677e83f6ef79099a8d1 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/not_fn.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_NOT_FN_H +#define _LIBCPP___FUNCTIONAL_NOT_FN_H + +#include <__config> +#include <__functional/invoke.h> +#include <__functional/perfect_forward.h> +#include <__type_traits/decay.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_constructible.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +struct __not_fn_op { + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 auto operator()(_Args&&... __args) const + noexcept(noexcept(!std::invoke(std::forward<_Args>(__args)...))) + -> decltype(!std::invoke(std::forward<_Args>(__args)...)) { + return !std::invoke(std::forward<_Args>(__args)...); + } +}; + +template +struct __not_fn_t : __perfect_forward<__not_fn_op, _Fn> { + using __perfect_forward<__not_fn_op, _Fn>::__perfect_forward; +}; + +template , _Fn> && is_move_constructible_v> >> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 auto not_fn(_Fn&& __f) { + return __not_fn_t>(std::forward<_Fn>(__f)); +} + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_NOT_FN_H diff --git a/libcxx/include/__cxx03/__functional/operations.h b/libcxx/include/__cxx03/__functional/operations.h new file mode 100644 index 0000000000000000000000000000000000000000..0a6320f19de3f320ddf01047395cfc0c07a540a4 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/operations.h @@ -0,0 +1,541 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_OPERATIONS_H +#define _LIBCPP___FUNCTIONAL_OPERATIONS_H + +#include <__config> +#include <__functional/binary_function.h> +#include <__functional/unary_function.h> +#include <__type_traits/desugars_to.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// Arithmetic operations + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS plus : __binary_function<_Tp, _Tp, _Tp> { + typedef _Tp __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _Tp operator()(const _Tp& __x, const _Tp& __y) const { + return __x + __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(plus); + +// The non-transparent std::plus specialization is only equivalent to a raw plus +// operator when we don't perform an implicit conversion when calling it. +template +inline const bool __desugars_to_v<__plus_tag, plus<_Tp>, _Tp, _Tp> = true; + +template +inline const bool __desugars_to_v<__plus_tag, plus, _Tp, _Up> = true; + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS plus { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) + std::forward<_T2>(__u))) // + -> decltype(std::forward<_T1>(__t) + std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) + std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS minus : __binary_function<_Tp, _Tp, _Tp> { + typedef _Tp __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _Tp operator()(const _Tp& __x, const _Tp& __y) const { + return __x - __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(minus); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS minus { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) - std::forward<_T2>(__u))) // + -> decltype(std::forward<_T1>(__t) - std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) - std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS multiplies : __binary_function<_Tp, _Tp, _Tp> { + typedef _Tp __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _Tp operator()(const _Tp& __x, const _Tp& __y) const { + return __x * __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(multiplies); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS multiplies { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) * std::forward<_T2>(__u))) // + -> decltype(std::forward<_T1>(__t) * std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) * std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS divides : __binary_function<_Tp, _Tp, _Tp> { + typedef _Tp __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _Tp operator()(const _Tp& __x, const _Tp& __y) const { + return __x / __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(divides); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS divides { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) / std::forward<_T2>(__u))) // + -> decltype(std::forward<_T1>(__t) / std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) / std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS modulus : __binary_function<_Tp, _Tp, _Tp> { + typedef _Tp __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _Tp operator()(const _Tp& __x, const _Tp& __y) const { + return __x % __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(modulus); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS modulus { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) % std::forward<_T2>(__u))) // + -> decltype(std::forward<_T1>(__t) % std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) % std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS negate : __unary_function<_Tp, _Tp> { + typedef _Tp __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _Tp operator()(const _Tp& __x) const { return -__x; } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(negate); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS negate { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_Tp&& __x) const + noexcept(noexcept(-std::forward<_Tp>(__x))) // + -> decltype(-std::forward<_Tp>(__x)) { + return -std::forward<_Tp>(__x); + } + typedef void is_transparent; +}; +#endif + +// Bitwise operations + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS bit_and : __binary_function<_Tp, _Tp, _Tp> { + typedef _Tp __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _Tp operator()(const _Tp& __x, const _Tp& __y) const { + return __x & __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(bit_and); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS bit_and { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) & + std::forward<_T2>(__u))) -> decltype(std::forward<_T1>(__t) & std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) & std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +#if _LIBCPP_STD_VER >= 14 +template +struct _LIBCPP_TEMPLATE_VIS bit_not : __unary_function<_Tp, _Tp> { + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _Tp operator()(const _Tp& __x) const { return ~__x; } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(bit_not); + +template <> +struct _LIBCPP_TEMPLATE_VIS bit_not { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_Tp&& __x) const + noexcept(noexcept(~std::forward<_Tp>(__x))) // + -> decltype(~std::forward<_Tp>(__x)) { + return ~std::forward<_Tp>(__x); + } + typedef void is_transparent; +}; +#endif + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS bit_or : __binary_function<_Tp, _Tp, _Tp> { + typedef _Tp __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _Tp operator()(const _Tp& __x, const _Tp& __y) const { + return __x | __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(bit_or); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS bit_or { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) | std::forward<_T2>(__u))) // + -> decltype(std::forward<_T1>(__t) | std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) | std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS bit_xor : __binary_function<_Tp, _Tp, _Tp> { + typedef _Tp __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _Tp operator()(const _Tp& __x, const _Tp& __y) const { + return __x ^ __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(bit_xor); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS bit_xor { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) ^ std::forward<_T2>(__u))) // + -> decltype(std::forward<_T1>(__t) ^ std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) ^ std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +// Comparison operations + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS equal_to : __binary_function<_Tp, _Tp, bool> { + typedef bool __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const _Tp& __y) const { + return __x == __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(equal_to); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS equal_to { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) == std::forward<_T2>(__u))) // + -> decltype(std::forward<_T1>(__t) == std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) == std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +// The non-transparent std::equal_to specialization is only equivalent to a raw equality +// comparison when we don't perform an implicit conversion when calling it. +template +inline const bool __desugars_to_v<__equal_tag, equal_to<_Tp>, _Tp, _Tp> = true; + +// In the transparent case, we do not enforce that +template +inline const bool __desugars_to_v<__equal_tag, equal_to, _Tp, _Up> = true; + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS not_equal_to : __binary_function<_Tp, _Tp, bool> { + typedef bool __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const _Tp& __y) const { + return __x != __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(not_equal_to); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS not_equal_to { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) != std::forward<_T2>(__u))) // + -> decltype(std::forward<_T1>(__t) != std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) != std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS less : __binary_function<_Tp, _Tp, bool> { + typedef bool __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const _Tp& __y) const { + return __x < __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(less); + +template +inline const bool __desugars_to_v<__less_tag, less<_Tp>, _Tp, _Tp> = true; + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS less { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) < std::forward<_T2>(__u))) // + -> decltype(std::forward<_T1>(__t) < std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) < std::forward<_T2>(__u); + } + typedef void is_transparent; +}; + +template +inline const bool __desugars_to_v<__less_tag, less<>, _Tp, _Tp> = true; +#endif + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS less_equal : __binary_function<_Tp, _Tp, bool> { + typedef bool __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const _Tp& __y) const { + return __x <= __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(less_equal); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS less_equal { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) <= std::forward<_T2>(__u))) // + -> decltype(std::forward<_T1>(__t) <= std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) <= std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS greater_equal : __binary_function<_Tp, _Tp, bool> { + typedef bool __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const _Tp& __y) const { + return __x >= __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(greater_equal); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS greater_equal { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) >= + std::forward<_T2>(__u))) -> decltype(std::forward<_T1>(__t) >= std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) >= std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS greater : __binary_function<_Tp, _Tp, bool> { + typedef bool __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const _Tp& __y) const { + return __x > __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(greater); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS greater { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) > std::forward<_T2>(__u))) // + -> decltype(std::forward<_T1>(__t) > std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) > std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +// Logical operations + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS logical_and : __binary_function<_Tp, _Tp, bool> { + typedef bool __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const _Tp& __y) const { + return __x && __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(logical_and); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS logical_and { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) && std::forward<_T2>(__u))) // + -> decltype(std::forward<_T1>(__t) && std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) && std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS logical_not : __unary_function<_Tp, bool> { + typedef bool __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x) const { return !__x; } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(logical_not); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS logical_not { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_Tp&& __x) const + noexcept(noexcept(!std::forward<_Tp>(__x))) // + -> decltype(!std::forward<_Tp>(__x)) { + return !std::forward<_Tp>(__x); + } + typedef void is_transparent; +}; +#endif + +#if _LIBCPP_STD_VER >= 14 +template +#else +template +#endif +struct _LIBCPP_TEMPLATE_VIS logical_or : __binary_function<_Tp, _Tp, bool> { + typedef bool __result_type; // used by valarray + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const _Tp& __y) const { + return __x || __y; + } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(logical_or); + +#if _LIBCPP_STD_VER >= 14 +template <> +struct _LIBCPP_TEMPLATE_VIS logical_or { + template + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(std::forward<_T1>(__t) || std::forward<_T2>(__u))) // + -> decltype(std::forward<_T1>(__t) || std::forward<_T2>(__u)) { + return std::forward<_T1>(__t) || std::forward<_T2>(__u); + } + typedef void is_transparent; +}; +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_OPERATIONS_H diff --git a/libcxx/include/__cxx03/__functional/perfect_forward.h b/libcxx/include/__cxx03/__functional/perfect_forward.h new file mode 100644 index 0000000000000000000000000000000000000000..74177c789b4ad0fddabbd02d7b1c2b0c3f2bd9c5 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/perfect_forward.h @@ -0,0 +1,104 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_PERFECT_FORWARD_H +#define _LIBCPP___FUNCTIONAL_PERFECT_FORWARD_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_constructible.h> +#include <__utility/declval.h> +#include <__utility/forward.h> +#include <__utility/integer_sequence.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +template +struct __perfect_forward_impl; + +template +struct __perfect_forward_impl<_Op, index_sequence<_Idx...>, _BoundArgs...> { +private: + tuple<_BoundArgs...> __bound_args_; + +public: + template , _Args&&...> >> + _LIBCPP_HIDE_FROM_ABI explicit constexpr __perfect_forward_impl(_Args&&... __bound_args) + : __bound_args_(std::forward<_Args>(__bound_args)...) {} + + _LIBCPP_HIDE_FROM_ABI __perfect_forward_impl(__perfect_forward_impl const&) = default; + _LIBCPP_HIDE_FROM_ABI __perfect_forward_impl(__perfect_forward_impl&&) = default; + + _LIBCPP_HIDE_FROM_ABI __perfect_forward_impl& operator=(__perfect_forward_impl const&) = default; + _LIBCPP_HIDE_FROM_ABI __perfect_forward_impl& operator=(__perfect_forward_impl&&) = default; + + template >> + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) & noexcept( + noexcept(_Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...))) + -> decltype(_Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...)) { + return _Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...); + } + + template >> + auto operator()(_Args&&...) & = delete; + + template >> + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) const& noexcept( + noexcept(_Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...))) + -> decltype(_Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...)) { + return _Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...); + } + + template >> + auto operator()(_Args&&...) const& = delete; + + template >> + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) && noexcept( + noexcept(_Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...))) + -> decltype(_Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...)) { + return _Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...); + } + + template >> + auto operator()(_Args&&...) && = delete; + + template >> + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) const&& noexcept( + noexcept(_Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...))) + -> decltype(_Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...)) { + return _Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...); + } + + template >> + auto operator()(_Args&&...) const&& = delete; +}; + +// __perfect_forward implements a perfect-forwarding call wrapper as explained in [func.require]. +template +using __perfect_forward = __perfect_forward_impl<_Op, index_sequence_for<_Args...>, _Args...>; + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FUNCTIONAL_PERFECT_FORWARD_H diff --git a/libcxx/include/__cxx03/__functional/pointer_to_binary_function.h b/libcxx/include/__cxx03/__functional/pointer_to_binary_function.h new file mode 100644 index 0000000000000000000000000000000000000000..e345250dcdd87296de8a9b2597dbf5902ce3cbb6 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/pointer_to_binary_function.h @@ -0,0 +1,44 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_POINTER_TO_BINARY_FUNCTION_H +#define _LIBCPP___FUNCTIONAL_POINTER_TO_BINARY_FUNCTION_H + +#include <__config> +#include <__functional/binary_function.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_BINDERS) + +template +class _LIBCPP_TEMPLATE_VIS +_LIBCPP_DEPRECATED_IN_CXX11 pointer_to_binary_function : public __binary_function<_Arg1, _Arg2, _Result> { + _Result (*__f_)(_Arg1, _Arg2); + +public: + _LIBCPP_HIDE_FROM_ABI explicit pointer_to_binary_function(_Result (*__f)(_Arg1, _Arg2)) : __f_(__f) {} + _LIBCPP_HIDE_FROM_ABI _Result operator()(_Arg1 __x, _Arg2 __y) const { return __f_(__x, __y); } +}; + +template +_LIBCPP_DEPRECATED_IN_CXX11 inline _LIBCPP_HIDE_FROM_ABI pointer_to_binary_function<_Arg1, _Arg2, _Result> +ptr_fun(_Result (*__f)(_Arg1, _Arg2)) { + return pointer_to_binary_function<_Arg1, _Arg2, _Result>(__f); +} + +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_POINTER_TO_BINARY_FUNCTION_H diff --git a/libcxx/include/__cxx03/__functional/pointer_to_unary_function.h b/libcxx/include/__cxx03/__functional/pointer_to_unary_function.h new file mode 100644 index 0000000000000000000000000000000000000000..3a5d153d36178c2f88ac3aa420724c6ea35d5a26 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/pointer_to_unary_function.h @@ -0,0 +1,44 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_POINTER_TO_UNARY_FUNCTION_H +#define _LIBCPP___FUNCTIONAL_POINTER_TO_UNARY_FUNCTION_H + +#include <__config> +#include <__functional/unary_function.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_BINDERS) + +template +class _LIBCPP_TEMPLATE_VIS +_LIBCPP_DEPRECATED_IN_CXX11 pointer_to_unary_function : public __unary_function<_Arg, _Result> { + _Result (*__f_)(_Arg); + +public: + _LIBCPP_HIDE_FROM_ABI explicit pointer_to_unary_function(_Result (*__f)(_Arg)) : __f_(__f) {} + _LIBCPP_HIDE_FROM_ABI _Result operator()(_Arg __x) const { return __f_(__x); } +}; + +template +_LIBCPP_DEPRECATED_IN_CXX11 inline _LIBCPP_HIDE_FROM_ABI pointer_to_unary_function<_Arg, _Result> +ptr_fun(_Result (*__f)(_Arg)) { + return pointer_to_unary_function<_Arg, _Result>(__f); +} + +#endif // _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_BINDERS) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_POINTER_TO_UNARY_FUNCTION_H diff --git a/libcxx/include/__cxx03/__functional/ranges_operations.h b/libcxx/include/__cxx03/__functional/ranges_operations.h new file mode 100644 index 0000000000000000000000000000000000000000..27f06eadd0eb112ae2b9d9760b0fef5defd0ec5e --- /dev/null +++ b/libcxx/include/__cxx03/__functional/ranges_operations.h @@ -0,0 +1,109 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_RANGES_OPERATIONS_H +#define _LIBCPP___FUNCTIONAL_RANGES_OPERATIONS_H + +#include <__concepts/equality_comparable.h> +#include <__concepts/totally_ordered.h> +#include <__config> +#include <__type_traits/desugars_to.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace ranges { + +struct equal_to { + template + requires equality_comparable_with<_Tp, _Up> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(bool(std::forward<_Tp>(__t) == std::forward<_Up>(__u)))) { + return std::forward<_Tp>(__t) == std::forward<_Up>(__u); + } + + using is_transparent = void; +}; + +struct not_equal_to { + template + requires equality_comparable_with<_Tp, _Up> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(bool(!(std::forward<_Tp>(__t) == std::forward<_Up>(__u))))) { + return !(std::forward<_Tp>(__t) == std::forward<_Up>(__u)); + } + + using is_transparent = void; +}; + +struct less { + template + requires totally_ordered_with<_Tp, _Up> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(bool(std::forward<_Tp>(__t) < std::forward<_Up>(__u)))) { + return std::forward<_Tp>(__t) < std::forward<_Up>(__u); + } + + using is_transparent = void; +}; + +struct less_equal { + template + requires totally_ordered_with<_Tp, _Up> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(bool(!(std::forward<_Up>(__u) < std::forward<_Tp>(__t))))) { + return !(std::forward<_Up>(__u) < std::forward<_Tp>(__t)); + } + + using is_transparent = void; +}; + +struct greater { + template + requires totally_ordered_with<_Tp, _Up> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(bool(std::forward<_Up>(__u) < std::forward<_Tp>(__t)))) { + return std::forward<_Up>(__u) < std::forward<_Tp>(__t); + } + + using is_transparent = void; +}; + +struct greater_equal { + template + requires totally_ordered_with<_Tp, _Up> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(bool(!(std::forward<_Tp>(__t) < std::forward<_Up>(__u))))) { + return !(std::forward<_Tp>(__t) < std::forward<_Up>(__u)); + } + + using is_transparent = void; +}; + +} // namespace ranges + +// For ranges we do not require that the types on each side of the equality +// operator are of the same type +template +inline const bool __desugars_to_v<__equal_tag, ranges::equal_to, _Tp, _Up> = true; + +template +inline const bool __desugars_to_v<__less_tag, ranges::less, _Tp, _Up> = true; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_RANGES_OPERATIONS_H diff --git a/libcxx/include/__cxx03/__functional/reference_wrapper.h b/libcxx/include/__cxx03/__functional/reference_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..3570e2673c8005847a484fde15e262d08a090e65 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/reference_wrapper.h @@ -0,0 +1,154 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H +#define _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H + +#include <__compare/synth_three_way.h> +#include <__concepts/boolean_testable.h> +#include <__config> +#include <__functional/invoke.h> +#include <__functional/weak_result_type.h> +#include <__memory/addressof.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_const.h> +#include <__type_traits/remove_cvref.h> +#include <__type_traits/void_t.h> +#include <__utility/declval.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class _LIBCPP_TEMPLATE_VIS reference_wrapper : public __weak_result_type<_Tp> { +public: + // types + typedef _Tp type; + +private: + type* __f_; + + static void __fun(_Tp&) _NOEXCEPT; + static void __fun(_Tp&&) = delete; // NOLINT(modernize-use-equals-delete) ; This is llvm.org/PR54276 + +public: + template ()))>, + __enable_if_t::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper(_Up&& __u) + _NOEXCEPT_(noexcept(__fun(std::declval<_Up>()))) { + type& __f = static_cast<_Up&&>(__u); + __f_ = std::addressof(__f); + } + + // access + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 operator type&() const _NOEXCEPT { return *__f_; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 type& get() const _NOEXCEPT { return *__f_; } + + // invoke + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __invoke_of::type + operator()(_ArgTypes&&... __args) const +#if _LIBCPP_STD_VER >= 17 + // Since is_nothrow_invocable requires C++17 LWG3764 is not backported + // to earlier versions. + noexcept(is_nothrow_invocable_v<_Tp&, _ArgTypes...>) +#endif + { + return std::__invoke(get(), std::forward<_ArgTypes>(__args)...); + } + +#if _LIBCPP_STD_VER >= 26 + + // [refwrap.comparisons], comparisons + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, reference_wrapper __y) + requires requires { + { __x.get() == __y.get() } -> __boolean_testable; + } + { + return __x.get() == __y.get(); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, const _Tp& __y) + requires requires { + { __x.get() == __y } -> __boolean_testable; + } + { + return __x.get() == __y; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(reference_wrapper __x, reference_wrapper __y) + requires(!is_const_v<_Tp>) && requires { + { __x.get() == __y.get() } -> __boolean_testable; + } + { + return __x.get() == __y.get(); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(reference_wrapper __x, reference_wrapper __y) + requires requires { std::__synth_three_way(__x.get(), __y.get()); } + { + return std::__synth_three_way(__x.get(), __y.get()); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(reference_wrapper __x, const _Tp& __y) + requires requires { std::__synth_three_way(__x.get(), __y); } + { + return std::__synth_three_way(__x.get(), __y); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(reference_wrapper __x, reference_wrapper __y) + requires(!is_const_v<_Tp>) && requires { std::__synth_three_way(__x.get(), __y.get()); } + { + return std::__synth_three_way(__x.get(), __y.get()); + } + +#endif // _LIBCPP_STD_VER >= 26 +}; + +#if _LIBCPP_STD_VER >= 17 +template +reference_wrapper(_Tp&) -> reference_wrapper<_Tp>; +#endif + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper<_Tp> ref(_Tp& __t) _NOEXCEPT { + return reference_wrapper<_Tp>(__t); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper<_Tp> +ref(reference_wrapper<_Tp> __t) _NOEXCEPT { + return __t; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper cref(const _Tp& __t) _NOEXCEPT { + return reference_wrapper(__t); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper +cref(reference_wrapper<_Tp> __t) _NOEXCEPT { + return __t; +} + +template +void ref(const _Tp&&) = delete; +template +void cref(const _Tp&&) = delete; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H diff --git a/libcxx/include/__cxx03/__functional/unary_function.h b/libcxx/include/__cxx03/__functional/unary_function.h new file mode 100644 index 0000000000000000000000000000000000000000..69b1bc94220ae6248e747cb7feaab2d8f8df6431 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/unary_function.h @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_UNARY_FUNCTION_H +#define _LIBCPP___FUNCTIONAL_UNARY_FUNCTION_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION) + +template +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 unary_function { + typedef _Arg argument_type; + typedef _Result result_type; +}; + +#endif // _LIBCPP_STD_VER <= 14 + +template +struct __unary_function_keep_layout_base { +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) + using argument_type _LIBCPP_DEPRECATED_IN_CXX17 = _Arg; + using result_type _LIBCPP_DEPRECATED_IN_CXX17 = _Result; +#endif +}; + +#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION) +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wdeprecated-declarations") +template +using __unary_function = unary_function<_Arg, _Result>; +_LIBCPP_DIAGNOSTIC_POP +#else +template +using __unary_function = __unary_function_keep_layout_base<_Arg, _Result>; +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_UNARY_FUNCTION_H diff --git a/libcxx/include/__cxx03/__functional/unary_negate.h b/libcxx/include/__cxx03/__functional/unary_negate.h new file mode 100644 index 0000000000000000000000000000000000000000..5bd487a97bcb331edbe3028991759dc61ab9bc6b --- /dev/null +++ b/libcxx/include/__cxx03/__functional/unary_negate.h @@ -0,0 +1,48 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_UNARY_NEGATE_H +#define _LIBCPP___FUNCTIONAL_UNARY_NEGATE_H + +#include <__config> +#include <__functional/unary_function.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_NEGATORS) + +template +class _LIBCPP_TEMPLATE_VIS +_LIBCPP_DEPRECATED_IN_CXX17 unary_negate : public __unary_function { + _Predicate __pred_; + +public: + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI explicit unary_negate(const _Predicate& __pred) + : __pred_(__pred) {} + _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI bool + operator()(const typename _Predicate::argument_type& __x) const { + return !__pred_(__x); + } +}; + +template +_LIBCPP_DEPRECATED_IN_CXX17 inline _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI unary_negate<_Predicate> +not1(const _Predicate& __pred) { + return unary_negate<_Predicate>(__pred); +} + +#endif // _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_NEGATORS) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_UNARY_NEGATE_H diff --git a/libcxx/include/__cxx03/__functional/weak_result_type.h b/libcxx/include/__cxx03/__functional/weak_result_type.h new file mode 100644 index 0000000000000000000000000000000000000000..ad7a8395186cd517f8f0a09afda143f96916b4a1 --- /dev/null +++ b/libcxx/include/__cxx03/__functional/weak_result_type.h @@ -0,0 +1,231 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_WEAK_RESULT_TYPE_H +#define _LIBCPP___FUNCTIONAL_WEAK_RESULT_TYPE_H + +#include <__config> +#include <__functional/binary_function.h> +#include <__functional/invoke.h> +#include <__functional/unary_function.h> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_same.h> +#include <__utility/declval.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __has_result_type { +private: + template + static false_type __test(...); + template + static true_type __test(typename _Up::result_type* = 0); + +public: + static const bool value = decltype(__test<_Tp>(0))::value; +}; + +// __weak_result_type + +template +struct __derives_from_unary_function { +private: + struct __two { + char __lx; + char __lxx; + }; + static __two __test(...); + template + static __unary_function<_Ap, _Rp> __test(const volatile __unary_function<_Ap, _Rp>*); + +public: + static const bool value = !is_same::value; + typedef decltype(__test((_Tp*)0)) type; +}; + +template +struct __derives_from_binary_function { +private: + struct __two { + char __lx; + char __lxx; + }; + static __two __test(...); + template + static __binary_function<_A1, _A2, _Rp> __test(const volatile __binary_function<_A1, _A2, _Rp>*); + +public: + static const bool value = !is_same::value; + typedef decltype(__test((_Tp*)0)) type; +}; + +template ::value> +struct __maybe_derive_from_unary_function // bool is true + : public __derives_from_unary_function<_Tp>::type {}; + +template +struct __maybe_derive_from_unary_function<_Tp, false> {}; + +template ::value> +struct __maybe_derive_from_binary_function // bool is true + : public __derives_from_binary_function<_Tp>::type {}; + +template +struct __maybe_derive_from_binary_function<_Tp, false> {}; + +template ::value> +struct __weak_result_type_imp // bool is true + : public __maybe_derive_from_unary_function<_Tp>, + public __maybe_derive_from_binary_function<_Tp> { +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) + using result_type _LIBCPP_NODEBUG _LIBCPP_DEPRECATED_IN_CXX17 = typename _Tp::result_type; +#endif +}; + +template +struct __weak_result_type_imp<_Tp, false> + : public __maybe_derive_from_unary_function<_Tp>, public __maybe_derive_from_binary_function<_Tp> {}; + +template +struct __weak_result_type : public __weak_result_type_imp<_Tp> {}; + +// 0 argument case + +template +struct __weak_result_type<_Rp()> { +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) + using result_type _LIBCPP_NODEBUG _LIBCPP_DEPRECATED_IN_CXX17 = _Rp; +#endif +}; + +template +struct __weak_result_type<_Rp (&)()> { +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) + using result_type _LIBCPP_NODEBUG _LIBCPP_DEPRECATED_IN_CXX17 = _Rp; +#endif +}; + +template +struct __weak_result_type<_Rp (*)()> { +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) + using result_type _LIBCPP_NODEBUG _LIBCPP_DEPRECATED_IN_CXX17 = _Rp; +#endif +}; + +// 1 argument case + +template +struct __weak_result_type<_Rp(_A1)> : public __unary_function<_A1, _Rp> {}; + +template +struct __weak_result_type<_Rp (&)(_A1)> : public __unary_function<_A1, _Rp> {}; + +template +struct __weak_result_type<_Rp (*)(_A1)> : public __unary_function<_A1, _Rp> {}; + +template +struct __weak_result_type<_Rp (_Cp::*)()> : public __unary_function<_Cp*, _Rp> {}; + +template +struct __weak_result_type<_Rp (_Cp::*)() const> : public __unary_function {}; + +template +struct __weak_result_type<_Rp (_Cp::*)() volatile> : public __unary_function {}; + +template +struct __weak_result_type<_Rp (_Cp::*)() const volatile> : public __unary_function {}; + +// 2 argument case + +template +struct __weak_result_type<_Rp(_A1, _A2)> : public __binary_function<_A1, _A2, _Rp> {}; + +template +struct __weak_result_type<_Rp (*)(_A1, _A2)> : public __binary_function<_A1, _A2, _Rp> {}; + +template +struct __weak_result_type<_Rp (&)(_A1, _A2)> : public __binary_function<_A1, _A2, _Rp> {}; + +template +struct __weak_result_type<_Rp (_Cp::*)(_A1)> : public __binary_function<_Cp*, _A1, _Rp> {}; + +template +struct __weak_result_type<_Rp (_Cp::*)(_A1) const> : public __binary_function {}; + +template +struct __weak_result_type<_Rp (_Cp::*)(_A1) volatile> : public __binary_function {}; + +template +struct __weak_result_type<_Rp (_Cp::*)(_A1) const volatile> : public __binary_function { +}; + +// 3 or more arguments + +template +struct __weak_result_type<_Rp(_A1, _A2, _A3, _A4...)> { +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) + using result_type _LIBCPP_NODEBUG _LIBCPP_DEPRECATED_IN_CXX17 = _Rp; +#endif +}; + +template +struct __weak_result_type<_Rp (&)(_A1, _A2, _A3, _A4...)> { +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) + using result_type _LIBCPP_NODEBUG _LIBCPP_DEPRECATED_IN_CXX17 = _Rp; +#endif +}; + +template +struct __weak_result_type<_Rp (*)(_A1, _A2, _A3, _A4...)> { +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) + using result_type _LIBCPP_NODEBUG _LIBCPP_DEPRECATED_IN_CXX17 = _Rp; +#endif +}; + +template +struct __weak_result_type<_Rp (_Cp::*)(_A1, _A2, _A3...)> { +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) + using result_type _LIBCPP_NODEBUG _LIBCPP_DEPRECATED_IN_CXX17 = _Rp; +#endif +}; + +template +struct __weak_result_type<_Rp (_Cp::*)(_A1, _A2, _A3...) const> { +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) + using result_type _LIBCPP_NODEBUG _LIBCPP_DEPRECATED_IN_CXX17 = _Rp; +#endif +}; + +template +struct __weak_result_type<_Rp (_Cp::*)(_A1, _A2, _A3...) volatile> { +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) + using result_type _LIBCPP_NODEBUG _LIBCPP_DEPRECATED_IN_CXX17 = _Rp; +#endif +}; + +template +struct __weak_result_type<_Rp (_Cp::*)(_A1, _A2, _A3...) const volatile> { +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_BINDER_TYPEDEFS) + using result_type _LIBCPP_NODEBUG _LIBCPP_DEPRECATED_IN_CXX17 = _Rp; +#endif +}; + +template +struct __invoke_return { + typedef decltype(std::__invoke(std::declval<_Tp>(), std::declval<_Args>()...)) type; +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_WEAK_RESULT_TYPE_H diff --git a/libcxx/include/__cxx03/__fwd/array.h b/libcxx/include/__cxx03/__fwd/array.h new file mode 100644 index 0000000000000000000000000000000000000000..b429d0c5a95427df0b6d41b210714fef1ac3f845 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/array.h @@ -0,0 +1,46 @@ +//===---------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_ARRAY_H +#define _LIBCPP___FWD_ARRAY_H + +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct _LIBCPP_TEMPLATE_VIS array; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp& get(array<_Tp, _Size>&) _NOEXCEPT; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp& get(const array<_Tp, _Size>&) _NOEXCEPT; + +#ifndef _LIBCPP_CXX03_LANG +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp&& get(array<_Tp, _Size>&&) _NOEXCEPT; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp&& get(const array<_Tp, _Size>&&) _NOEXCEPT; +#endif + +template +struct __is_std_array : false_type {}; + +template +struct __is_std_array > : true_type {}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_ARRAY_H diff --git a/libcxx/include/__cxx03/__fwd/bit_reference.h b/libcxx/include/__cxx03/__fwd/bit_reference.h new file mode 100644 index 0000000000000000000000000000000000000000..237efb6db66429735c35739e2bd78c8f9b97513f --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/bit_reference.h @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_BIT_REFERENCE_H +#define _LIBCPP___FWD_BIT_REFERENCE_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class __bit_iterator; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_BIT_REFERENCE_H diff --git a/libcxx/include/__cxx03/__fwd/complex.h b/libcxx/include/__cxx03/__fwd/complex.h new file mode 100644 index 0000000000000000000000000000000000000000..22c78c5cc3c77a07e95f8196f47698b3fb1c34bf --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/complex.h @@ -0,0 +1,42 @@ +//===---------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_COMPLEX_H +#define _LIBCPP___FWD_COMPLEX_H + +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class _LIBCPP_TEMPLATE_VIS complex; + +#if _LIBCPP_STD_VER >= 26 + +template +_LIBCPP_HIDE_FROM_ABI constexpr _Tp& get(complex<_Tp>&) noexcept; + +template +_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& get(complex<_Tp>&&) noexcept; + +template +_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& get(const complex<_Tp>&) noexcept; + +template +_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& get(const complex<_Tp>&&) noexcept; + +#endif // _LIBCPP_STD_VER >= 26 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_COMPLEX_H diff --git a/libcxx/include/__cxx03/__fwd/deque.h b/libcxx/include/__cxx03/__fwd/deque.h new file mode 100644 index 0000000000000000000000000000000000000000..fd2fb5bb4b8e9273d4d2482d5fb2a06e461c8e03 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/deque.h @@ -0,0 +1,26 @@ +//===---------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_DEQUE_H +#define _LIBCPP___FWD_DEQUE_H + +#include <__config> +#include <__fwd/memory.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template > +class _LIBCPP_TEMPLATE_VIS deque; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_DEQUE_H diff --git a/libcxx/include/__cxx03/__fwd/format.h b/libcxx/include/__cxx03/__fwd/format.h new file mode 100644 index 0000000000000000000000000000000000000000..b30c220f8a0435c95e4b2587ed572471aad05955 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/format.h @@ -0,0 +1,38 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_FORMAT_H +#define _LIBCPP___FWD_FORMAT_H + +#include <__config> +#include <__iterator/concepts.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +class _LIBCPP_TEMPLATE_VIS basic_format_arg; + +template + requires output_iterator<_OutIt, const _CharT&> +class _LIBCPP_TEMPLATE_VIS basic_format_context; + +template +struct _LIBCPP_TEMPLATE_VIS formatter; + +#endif //_LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_FORMAT_H diff --git a/libcxx/include/__cxx03/__fwd/fstream.h b/libcxx/include/__cxx03/__fwd/fstream.h new file mode 100644 index 0000000000000000000000000000000000000000..b4a112bfd4de6464f20b4cd7d4f6433324904124 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/fstream.h @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_FSTREAM_H +#define _LIBCPP___FWD_FSTREAM_H + +#include <__config> +#include <__fwd/string.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template > +class _LIBCPP_TEMPLATE_VIS basic_filebuf; +template > +class _LIBCPP_TEMPLATE_VIS basic_ifstream; +template > +class _LIBCPP_TEMPLATE_VIS basic_ofstream; +template > +class _LIBCPP_TEMPLATE_VIS basic_fstream; + +using filebuf = basic_filebuf; +using ifstream = basic_ifstream; +using ofstream = basic_ofstream; +using fstream = basic_fstream; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +using wfilebuf = basic_filebuf; +using wifstream = basic_ifstream; +using wofstream = basic_ofstream; +using wfstream = basic_fstream; +#endif + +template +class _LIBCPP_PREFERRED_NAME(filebuf) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wfilebuf)) basic_filebuf; +template +class _LIBCPP_PREFERRED_NAME(ifstream) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wifstream)) basic_ifstream; +template +class _LIBCPP_PREFERRED_NAME(ofstream) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wofstream)) basic_ofstream; +template +class _LIBCPP_PREFERRED_NAME(fstream) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wfstream)) basic_fstream; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_FSTREAM_H diff --git a/libcxx/include/__cxx03/__fwd/functional.h b/libcxx/include/__cxx03/__fwd/functional.h new file mode 100644 index 0000000000000000000000000000000000000000..32c9ef33e453b14a70013701b8fa5554d6c271b1 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/functional.h @@ -0,0 +1,28 @@ +//===---------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_FUNCTIONAL_H +#define _LIBCPP___FWD_FUNCTIONAL_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct _LIBCPP_TEMPLATE_VIS hash; + +template +class _LIBCPP_TEMPLATE_VIS reference_wrapper; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_FUNCTIONAL_H diff --git a/libcxx/include/__cxx03/__fwd/ios.h b/libcxx/include/__cxx03/__fwd/ios.h new file mode 100644 index 0000000000000000000000000000000000000000..48350709d4ce25a118003547578f141f32af966a --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/ios.h @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_IOS_H +#define _LIBCPP___FWD_IOS_H + +#include <__config> +#include <__fwd/string.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +class _LIBCPP_EXPORTED_FROM_ABI ios_base; + +template > +class _LIBCPP_TEMPLATE_VIS basic_ios; + +using ios = basic_ios; +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +using wios = basic_ios; +#endif + +template +class _LIBCPP_PREFERRED_NAME(ios) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wios)) basic_ios; + +#if defined(_NEWLIB_VERSION) +// On newlib, off_t is 'long int' +using streamoff = long int; // for char_traits in +#else +using streamoff = long long; // for char_traits in +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_IOS_H diff --git a/libcxx/include/__cxx03/__fwd/istream.h b/libcxx/include/__cxx03/__fwd/istream.h new file mode 100644 index 0000000000000000000000000000000000000000..a06907a6c8ef91d8ff9cc243610e8bc8d2512577 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/istream.h @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_ISTREAM_H +#define _LIBCPP___FWD_ISTREAM_H + +#include <__config> +#include <__fwd/string.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template > +class _LIBCPP_TEMPLATE_VIS basic_istream; + +template > +class _LIBCPP_TEMPLATE_VIS basic_iostream; + +using istream = basic_istream; +using iostream = basic_iostream; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +using wistream = basic_istream; +using wiostream = basic_iostream; +#endif + +template +class _LIBCPP_PREFERRED_NAME(istream) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wistream)) basic_istream; + +template +class _LIBCPP_PREFERRED_NAME(iostream) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wiostream)) basic_iostream; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_ISTREAM_H diff --git a/libcxx/include/__cxx03/__fwd/mdspan.h b/libcxx/include/__cxx03/__fwd/mdspan.h new file mode 100644 index 0000000000000000000000000000000000000000..8889567a047f6ec8ccc0654f3cbaf6013f68dbc8 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/mdspan.h @@ -0,0 +1,57 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Kokkos v. 4.0 +// Copyright (2022) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___MDSPAN_LAYOUTS_H +#define _LIBCPP___MDSPAN_LAYOUTS_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +// Layout policy with a mapping which corresponds to FORTRAN-style array layouts +struct layout_left { + template + class mapping; +}; + +// Layout policy with a mapping which corresponds to C-style array layouts +struct layout_right { + template + class mapping; +}; + +// Layout policy with a unique mapping where strides are arbitrary +struct layout_stride { + template + class mapping; +}; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_LAYOUTS_H diff --git a/libcxx/include/__cxx03/__fwd/memory.h b/libcxx/include/__cxx03/__fwd/memory.h new file mode 100644 index 0000000000000000000000000000000000000000..b9e151855ad7d8549a8d3b5ab9288cb4fff05853 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/memory.h @@ -0,0 +1,25 @@ +//===---------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_MEMORY_H +#define _LIBCPP___FWD_MEMORY_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class _LIBCPP_TEMPLATE_VIS allocator; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_MEMORY_H diff --git a/libcxx/include/__cxx03/__fwd/memory_resource.h b/libcxx/include/__cxx03/__fwd/memory_resource.h new file mode 100644 index 0000000000000000000000000000000000000000..d68b2c2b6315432200e82c5734584f5fab7386d1 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/memory_resource.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_MEMORY_RESOURCE_H +#define _LIBCPP___FWD_MEMORY_RESOURCE_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace pmr { +template +class _LIBCPP_AVAILABILITY_PMR _LIBCPP_TEMPLATE_VIS polymorphic_allocator; +} // namespace pmr + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_MEMORY_RESOURCE_H diff --git a/libcxx/include/__cxx03/__fwd/ostream.h b/libcxx/include/__cxx03/__fwd/ostream.h new file mode 100644 index 0000000000000000000000000000000000000000..3347e0f71d7a1c353860eeae369109b881cce1a1 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/ostream.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_OSTREAM_H +#define _LIBCPP___FWD_OSTREAM_H + +#include <__config> +#include <__fwd/string.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template > +class _LIBCPP_TEMPLATE_VIS basic_ostream; + +using ostream = basic_ostream; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +using wostream = basic_ostream; +#endif + +template +class _LIBCPP_PREFERRED_NAME(ostream) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wostream)) basic_ostream; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_OSTREAM_H diff --git a/libcxx/include/__cxx03/__fwd/pair.h b/libcxx/include/__cxx03/__fwd/pair.h new file mode 100644 index 0000000000000000000000000000000000000000..af32628fe1e0d037a11084fdceb6bbbcec9c5c35 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/pair.h @@ -0,0 +1,45 @@ +//===---------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_PAIR_H +#define _LIBCPP___FWD_PAIR_H + +#include <__config> +#include <__fwd/tuple.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct _LIBCPP_TEMPLATE_VIS pair; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, pair<_T1, _T2> >::type& +get(pair<_T1, _T2>&) _NOEXCEPT; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, pair<_T1, _T2> >::type& +get(const pair<_T1, _T2>&) _NOEXCEPT; + +#ifndef _LIBCPP_CXX03_LANG +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, pair<_T1, _T2> >::type&& +get(pair<_T1, _T2>&&) _NOEXCEPT; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, pair<_T1, _T2> >::type&& +get(const pair<_T1, _T2>&&) _NOEXCEPT; +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_PAIR_H diff --git a/libcxx/include/__cxx03/__fwd/queue.h b/libcxx/include/__cxx03/__fwd/queue.h new file mode 100644 index 0000000000000000000000000000000000000000..50d99ad9c29f4517cf978248c03aaa8964263d75 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/queue.h @@ -0,0 +1,31 @@ +//===---------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_QUEUE_H +#define _LIBCPP___FWD_QUEUE_H + +#include <__config> +#include <__functional/operations.h> +#include <__fwd/deque.h> +#include <__fwd/vector.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template > +class _LIBCPP_TEMPLATE_VIS queue; + +template , class _Compare = less > +class _LIBCPP_TEMPLATE_VIS priority_queue; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_QUEUE_H diff --git a/libcxx/include/__cxx03/__fwd/span.h b/libcxx/include/__cxx03/__fwd/span.h new file mode 100644 index 0000000000000000000000000000000000000000..8dafa742c19df5a877f73d991ec7afb65970c86b --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/span.h @@ -0,0 +1,38 @@ +// -*- C++ -*- +//===---------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_SPAN_H +#define _LIBCPP___FWD_SPAN_H + +#include <__config> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +inline constexpr size_t dynamic_extent = numeric_limits::max(); +template +class span; + +#endif + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FWD_SPAN_H diff --git a/libcxx/include/__cxx03/__fwd/sstream.h b/libcxx/include/__cxx03/__fwd/sstream.h new file mode 100644 index 0000000000000000000000000000000000000000..39a9c3faf1f800ca6373e8a94b08a943a5cacb30 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/sstream.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_SSTREAM_H +#define _LIBCPP___FWD_SSTREAM_H + +#include <__config> +#include <__fwd/memory.h> +#include <__fwd/string.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template , class _Allocator = allocator<_CharT> > +class _LIBCPP_TEMPLATE_VIS basic_stringbuf; + +template , class _Allocator = allocator<_CharT> > +class _LIBCPP_TEMPLATE_VIS basic_istringstream; +template , class _Allocator = allocator<_CharT> > +class _LIBCPP_TEMPLATE_VIS basic_ostringstream; +template , class _Allocator = allocator<_CharT> > +class _LIBCPP_TEMPLATE_VIS basic_stringstream; + +using stringbuf = basic_stringbuf; +using istringstream = basic_istringstream; +using ostringstream = basic_ostringstream; +using stringstream = basic_stringstream; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +using wstringbuf = basic_stringbuf; +using wistringstream = basic_istringstream; +using wostringstream = basic_ostringstream; +using wstringstream = basic_stringstream; +#endif + +template +class _LIBCPP_PREFERRED_NAME(stringbuf) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wstringbuf)) basic_stringbuf; +template +class _LIBCPP_PREFERRED_NAME(istringstream) + _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wistringstream)) basic_istringstream; +template +class _LIBCPP_PREFERRED_NAME(ostringstream) + _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wostringstream)) basic_ostringstream; +template +class _LIBCPP_PREFERRED_NAME(stringstream) + _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wstringstream)) basic_stringstream; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_SSTREAM_H diff --git a/libcxx/include/__cxx03/__fwd/stack.h b/libcxx/include/__cxx03/__fwd/stack.h new file mode 100644 index 0000000000000000000000000000000000000000..7dab6c1a4f4e2eaa3bb8ce0f0ca42813710b8862 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/stack.h @@ -0,0 +1,26 @@ +//===---------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_STACK_H +#define _LIBCPP___FWD_STACK_H + +#include <__config> +#include <__fwd/deque.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template > +class _LIBCPP_TEMPLATE_VIS stack; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_STACK_H diff --git a/libcxx/include/__cxx03/__fwd/streambuf.h b/libcxx/include/__cxx03/__fwd/streambuf.h new file mode 100644 index 0000000000000000000000000000000000000000..b35afa6afe34372677ed8a8da7042643c6ca792a --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/streambuf.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_STREAMBUF_H +#define _LIBCPP___FWD_STREAMBUF_H + +#include <__config> +#include <__fwd/string.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template > +class _LIBCPP_TEMPLATE_VIS basic_streambuf; + +using streambuf = basic_streambuf; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +using wstreambuf = basic_streambuf; +#endif + +template +class _LIBCPP_PREFERRED_NAME(streambuf) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wstreambuf)) basic_streambuf; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_STREAMBUF_H diff --git a/libcxx/include/__cxx03/__fwd/string.h b/libcxx/include/__cxx03/__fwd/string.h new file mode 100644 index 0000000000000000000000000000000000000000..2418e1f9b23d0d92947edb9676f96fbfa7b72c24 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/string.h @@ -0,0 +1,107 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_STRING_H +#define _LIBCPP___FWD_STRING_H + +#include <__config> +#include <__fwd/memory.h> +#include <__fwd/memory_resource.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct _LIBCPP_TEMPLATE_VIS char_traits; +template <> +struct char_traits; + +#ifndef _LIBCPP_HAS_NO_CHAR8_T +template <> +struct char_traits; +#endif + +template <> +struct char_traits; +template <> +struct char_traits; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <> +struct char_traits; +#endif + +template , class _Allocator = allocator<_CharT> > +class _LIBCPP_TEMPLATE_VIS basic_string; + +using string = basic_string; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +using wstring = basic_string; +#endif + +#ifndef _LIBCPP_HAS_NO_CHAR8_T +using u8string = basic_string; +#endif + +using u16string = basic_string; +using u32string = basic_string; + +#if _LIBCPP_STD_VER >= 17 + +namespace pmr { +template > +using basic_string _LIBCPP_AVAILABILITY_PMR = std::basic_string<_CharT, _Traits, polymorphic_allocator<_CharT>>; + +using string _LIBCPP_AVAILABILITY_PMR = basic_string; + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +using wstring _LIBCPP_AVAILABILITY_PMR = basic_string; +# endif + +# ifndef _LIBCPP_HAS_NO_CHAR8_T +using u8string _LIBCPP_AVAILABILITY_PMR = basic_string; +# endif + +using u16string _LIBCPP_AVAILABILITY_PMR = basic_string; +using u32string _LIBCPP_AVAILABILITY_PMR = basic_string; +} // namespace pmr + +#endif // _LIBCPP_STD_VER >= 17 + +// clang-format off +template +class _LIBCPP_PREFERRED_NAME(string) +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS + _LIBCPP_PREFERRED_NAME(wstring) +#endif +#ifndef _LIBCPP_HAS_NO_CHAR8_T + _LIBCPP_PREFERRED_NAME(u8string) +#endif + _LIBCPP_PREFERRED_NAME(u16string) + _LIBCPP_PREFERRED_NAME(u32string) +#if _LIBCPP_STD_VER >= 17 + _LIBCPP_PREFERRED_NAME(pmr::string) +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS + _LIBCPP_PREFERRED_NAME(pmr::wstring) +# endif +# ifndef _LIBCPP_HAS_NO_CHAR8_T + _LIBCPP_PREFERRED_NAME(pmr::u8string) +# endif + _LIBCPP_PREFERRED_NAME(pmr::u16string) + _LIBCPP_PREFERRED_NAME(pmr::u32string) +#endif + basic_string; +// clang-format on + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_STRING_H diff --git a/libcxx/include/__cxx03/__fwd/string_view.h b/libcxx/include/__cxx03/__fwd/string_view.h new file mode 100644 index 0000000000000000000000000000000000000000..72a64be5b00b54bf02026d8cb708aa8b0a724ce1 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/string_view.h @@ -0,0 +1,50 @@ +// -*- C++ -*- +//===---------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_STRING_VIEW_H +#define _LIBCPP___FWD_STRING_VIEW_H + +#include <__config> +#include <__fwd/string.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template > +class _LIBCPP_TEMPLATE_VIS basic_string_view; + +typedef basic_string_view string_view; +#ifndef _LIBCPP_HAS_NO_CHAR8_T +typedef basic_string_view u8string_view; +#endif +typedef basic_string_view u16string_view; +typedef basic_string_view u32string_view; +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +typedef basic_string_view wstring_view; +#endif + +// clang-format off +template +class _LIBCPP_PREFERRED_NAME(string_view) +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS + _LIBCPP_PREFERRED_NAME(wstring_view) +#endif +#ifndef _LIBCPP_HAS_NO_CHAR8_T + _LIBCPP_PREFERRED_NAME(u8string_view) +#endif + _LIBCPP_PREFERRED_NAME(u16string_view) + _LIBCPP_PREFERRED_NAME(u32string_view) + basic_string_view; +// clang-format on +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_STRING_VIEW_H diff --git a/libcxx/include/__cxx03/__fwd/subrange.h b/libcxx/include/__cxx03/__fwd/subrange.h new file mode 100644 index 0000000000000000000000000000000000000000..60a41da23dd44e48423cc4f668aecb10726f20cb --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/subrange.h @@ -0,0 +1,49 @@ +//===---------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_SUBRANGE_H +#define _LIBCPP___FWD_SUBRANGE_H + +#include <__concepts/copyable.h> +#include <__config> +#include <__iterator/concepts.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +enum class subrange_kind : bool { unsized, sized }; + +template _Sent, subrange_kind _Kind> + requires(_Kind == subrange_kind::sized || !sized_sentinel_for<_Sent, _Iter>) +class _LIBCPP_TEMPLATE_VIS subrange; + +template + requires((_Index == 0 && copyable<_Iter>) || _Index == 1) +_LIBCPP_HIDE_FROM_ABI constexpr auto get(const subrange<_Iter, _Sent, _Kind>&); + +template + requires(_Index < 2) +_LIBCPP_HIDE_FROM_ABI constexpr auto get(subrange<_Iter, _Sent, _Kind>&&); + +} // namespace ranges + +using ranges::get; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___FWD_SUBRANGE_H diff --git a/libcxx/include/__cxx03/__fwd/tuple.h b/libcxx/include/__cxx03/__fwd/tuple.h new file mode 100644 index 0000000000000000000000000000000000000000..902770c29555ed890c5e4b774b12a111a752ee25 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/tuple.h @@ -0,0 +1,52 @@ +//===---------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_TUPLE_H +#define _LIBCPP___FWD_TUPLE_H + +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct _LIBCPP_TEMPLATE_VIS tuple_element; + +#ifndef _LIBCPP_CXX03_LANG + +template +class _LIBCPP_TEMPLATE_VIS tuple; + +template +struct _LIBCPP_TEMPLATE_VIS tuple_size; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, tuple<_Tp...> >::type& +get(tuple<_Tp...>&) _NOEXCEPT; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, tuple<_Tp...> >::type& +get(const tuple<_Tp...>&) _NOEXCEPT; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, tuple<_Tp...> >::type&& +get(tuple<_Tp...>&&) _NOEXCEPT; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, tuple<_Tp...> >::type&& +get(const tuple<_Tp...>&&) _NOEXCEPT; + +#endif // _LIBCPP_CXX03_LANG + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_TUPLE_H diff --git a/libcxx/include/__cxx03/__fwd/vector.h b/libcxx/include/__cxx03/__fwd/vector.h new file mode 100644 index 0000000000000000000000000000000000000000..c9cc96137449f8bd20bb197633d8907429134288 --- /dev/null +++ b/libcxx/include/__cxx03/__fwd/vector.h @@ -0,0 +1,26 @@ +//===---------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___FWD_VECTOR_H +#define _LIBCPP___FWD_VECTOR_H + +#include <__config> +#include <__fwd/memory.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template > +class _LIBCPP_TEMPLATE_VIS vector; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FWD_VECTOR_H diff --git a/libcxx/include/__cxx03/__hash_table b/libcxx/include/__cxx03/__hash_table new file mode 100644 index 0000000000000000000000000000000000000000..025758528573f21382d310415fff84d9a828d474 --- /dev/null +++ b/libcxx/include/__cxx03/__hash_table @@ -0,0 +1,2044 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___HASH_TABLE +#define _LIBCPP___HASH_TABLE + +#include <__algorithm/max.h> +#include <__algorithm/min.h> +#include <__assert> +#include <__bit/countl.h> +#include <__config> +#include <__functional/hash.h> +#include <__functional/invoke.h> +#include <__iterator/iterator_traits.h> +#include <__memory/addressof.h> +#include <__memory/allocator_traits.h> +#include <__memory/compressed_pair.h> +#include <__memory/construct_at.h> +#include <__memory/pointer_traits.h> +#include <__memory/swap_allocator.h> +#include <__memory/unique_ptr.h> +#include <__type_traits/can_extract_key.h> +#include <__type_traits/conditional.h> +#include <__type_traits/is_const.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_nothrow_assignable.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_pointer.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/is_swappable.h> +#include <__type_traits/remove_const.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <__utility/pair.h> +#include <__utility/swap.h> +#include +#include +#include +#include // __launder + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __hash_value_type; + +template +struct __is_hash_value_type_imp : false_type {}; + +template +struct __is_hash_value_type_imp<__hash_value_type<_Key, _Value> > : true_type {}; + +template +struct __is_hash_value_type : false_type {}; + +template +struct __is_hash_value_type<_One> : __is_hash_value_type_imp<__remove_cvref_t<_One> > {}; + +_LIBCPP_EXPORTED_FROM_ABI size_t __next_prime(size_t __n); + +template +struct __hash_node_base { + typedef typename pointer_traits<_NodePtr>::element_type __node_type; + typedef __hash_node_base __first_node; + typedef __rebind_pointer_t<_NodePtr, __first_node> __node_base_pointer; + typedef _NodePtr __node_pointer; + +#if defined(_LIBCPP_ABI_FIX_UNORDERED_NODE_POINTER_UB) + typedef __node_base_pointer __next_pointer; +#else + typedef __conditional_t::value, __node_base_pointer, __node_pointer> __next_pointer; +#endif + + __next_pointer __next_; + + _LIBCPP_HIDE_FROM_ABI __next_pointer __ptr() _NOEXCEPT { + return static_cast<__next_pointer>(pointer_traits<__node_base_pointer>::pointer_to(*this)); + } + + _LIBCPP_HIDE_FROM_ABI __node_pointer __upcast() _NOEXCEPT { + return static_cast<__node_pointer>(pointer_traits<__node_base_pointer>::pointer_to(*this)); + } + + _LIBCPP_HIDE_FROM_ABI size_t __hash() const _NOEXCEPT { return static_cast<__node_type const&>(*this).__hash_; } + + _LIBCPP_HIDE_FROM_ABI __hash_node_base() _NOEXCEPT : __next_(nullptr) {} + _LIBCPP_HIDE_FROM_ABI explicit __hash_node_base(__next_pointer __next) _NOEXCEPT : __next_(__next) {} +}; + +template +struct __hash_node : public __hash_node_base< __rebind_pointer_t<_VoidPtr, __hash_node<_Tp, _VoidPtr> > > { + typedef _Tp __node_value_type; + using _Base = __hash_node_base<__rebind_pointer_t<_VoidPtr, __hash_node<_Tp, _VoidPtr> > >; + using __next_pointer = typename _Base::__next_pointer; + + size_t __hash_; + + // We allow starting the lifetime of nodes without initializing the value held by the node, + // since that is handled by the hash table itself in order to be allocator-aware. +#ifndef _LIBCPP_CXX03_LANG + +private: + union { + _Tp __value_; + }; + +public: + _LIBCPP_HIDE_FROM_ABI _Tp& __get_value() { return __value_; } +#else + +private: + _ALIGNAS_TYPE(_Tp) char __buffer_[sizeof(_Tp)]; + +public: + _LIBCPP_HIDE_FROM_ABI _Tp& __get_value() { return *std::__launder(reinterpret_cast<_Tp*>(&__buffer_)); } +#endif + + _LIBCPP_HIDE_FROM_ABI explicit __hash_node(__next_pointer __next, size_t __hash) : _Base(__next), __hash_(__hash) {} + _LIBCPP_HIDE_FROM_ABI ~__hash_node() {} +}; + +inline _LIBCPP_HIDE_FROM_ABI bool __is_hash_power2(size_t __bc) { return __bc > 2 && !(__bc & (__bc - 1)); } + +inline _LIBCPP_HIDE_FROM_ABI size_t __constrain_hash(size_t __h, size_t __bc) { + return !(__bc & (__bc - 1)) ? __h & (__bc - 1) : (__h < __bc ? __h : __h % __bc); +} + +inline _LIBCPP_HIDE_FROM_ABI size_t __next_hash_pow2(size_t __n) { + return __n < 2 ? __n : (size_t(1) << (numeric_limits::digits - __libcpp_clz(__n - 1))); +} + +template +class __hash_table; + +template +class _LIBCPP_TEMPLATE_VIS __hash_iterator; +template +class _LIBCPP_TEMPLATE_VIS __hash_const_iterator; +template +class _LIBCPP_TEMPLATE_VIS __hash_local_iterator; +template +class _LIBCPP_TEMPLATE_VIS __hash_const_local_iterator; +template +class _LIBCPP_TEMPLATE_VIS __hash_map_iterator; +template +class _LIBCPP_TEMPLATE_VIS __hash_map_const_iterator; + +template +struct __hash_key_value_types { + static_assert(!is_reference<_Tp>::value && !is_const<_Tp>::value, ""); + typedef _Tp key_type; + typedef _Tp __node_value_type; + typedef _Tp __container_value_type; + static const bool __is_map = false; + + _LIBCPP_HIDE_FROM_ABI static key_type const& __get_key(_Tp const& __v) { return __v; } + _LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(__node_value_type const& __v) { return __v; } + _LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) { return std::addressof(__n); } + _LIBCPP_HIDE_FROM_ABI static __container_value_type&& __move(__node_value_type& __v) { return std::move(__v); } +}; + +template +struct __hash_key_value_types<__hash_value_type<_Key, _Tp> > { + typedef _Key key_type; + typedef _Tp mapped_type; + typedef __hash_value_type<_Key, _Tp> __node_value_type; + typedef pair __container_value_type; + typedef __container_value_type __map_value_type; + static const bool __is_map = true; + + _LIBCPP_HIDE_FROM_ABI static key_type const& __get_key(__container_value_type const& __v) { return __v.first; } + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(_Up& __t) { + return __t.__get_value(); + } + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(_Up& __t) { + return __t; + } + + _LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) { + return std::addressof(__n.__get_value()); + } + _LIBCPP_HIDE_FROM_ABI static pair __move(__node_value_type& __v) { return __v.__move(); } +}; + +template , bool = _KVTypes::__is_map> +struct __hash_map_pointer_types {}; + +template +struct __hash_map_pointer_types<_Tp, _AllocPtr, _KVTypes, true> { + typedef typename _KVTypes::__map_value_type _Mv; + typedef __rebind_pointer_t<_AllocPtr, _Mv> __map_value_type_pointer; + typedef __rebind_pointer_t<_AllocPtr, const _Mv> __const_map_value_type_pointer; +}; + +template ::element_type> +struct __hash_node_types; + +template +struct __hash_node_types<_NodePtr, __hash_node<_Tp, _VoidPtr> > + : public __hash_key_value_types<_Tp>, + __hash_map_pointer_types<_Tp, _VoidPtr> + +{ + typedef __hash_key_value_types<_Tp> __base; + +public: + typedef ptrdiff_t difference_type; + typedef size_t size_type; + + typedef __rebind_pointer_t<_NodePtr, void> __void_pointer; + + typedef typename pointer_traits<_NodePtr>::element_type __node_type; + typedef _NodePtr __node_pointer; + + typedef __hash_node_base<__node_pointer> __node_base_type; + typedef __rebind_pointer_t<_NodePtr, __node_base_type> __node_base_pointer; + + typedef typename __node_base_type::__next_pointer __next_pointer; + + typedef _Tp __node_value_type; + typedef __rebind_pointer_t<_VoidPtr, __node_value_type> __node_value_type_pointer; + typedef __rebind_pointer_t<_VoidPtr, const __node_value_type> __const_node_value_type_pointer; + +private: + static_assert(!is_const<__node_type>::value, "_NodePtr should never be a pointer to const"); + static_assert(is_same::element_type, void>::value, + "_VoidPtr does not point to unqualified void type"); + static_assert(is_same<__rebind_pointer_t<_VoidPtr, __node_type>, _NodePtr>::value, + "_VoidPtr does not rebind to _NodePtr."); +}; + +template +struct __hash_node_types_from_iterator; +template +struct __hash_node_types_from_iterator<__hash_iterator<_NodePtr> > : __hash_node_types<_NodePtr> {}; +template +struct __hash_node_types_from_iterator<__hash_const_iterator<_NodePtr> > : __hash_node_types<_NodePtr> {}; +template +struct __hash_node_types_from_iterator<__hash_local_iterator<_NodePtr> > : __hash_node_types<_NodePtr> {}; +template +struct __hash_node_types_from_iterator<__hash_const_local_iterator<_NodePtr> > : __hash_node_types<_NodePtr> {}; + +template +struct __make_hash_node_types { + typedef __hash_node<_NodeValueTp, _VoidPtr> _NodeTp; + typedef __rebind_pointer_t<_VoidPtr, _NodeTp> _NodePtr; + typedef __hash_node_types<_NodePtr> type; +}; + +template +class _LIBCPP_TEMPLATE_VIS __hash_iterator { + typedef __hash_node_types<_NodePtr> _NodeTypes; + typedef _NodePtr __node_pointer; + typedef typename _NodeTypes::__next_pointer __next_pointer; + + __next_pointer __node_; + +public: + typedef forward_iterator_tag iterator_category; + typedef typename _NodeTypes::__node_value_type value_type; + typedef typename _NodeTypes::difference_type difference_type; + typedef value_type& reference; + typedef typename _NodeTypes::__node_value_type_pointer pointer; + + _LIBCPP_HIDE_FROM_ABI __hash_iterator() _NOEXCEPT : __node_(nullptr) {} + + _LIBCPP_HIDE_FROM_ABI reference operator*() const { + _LIBCPP_ASSERT_NON_NULL( + __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container iterator"); + return __node_->__upcast()->__get_value(); + } + + _LIBCPP_HIDE_FROM_ABI pointer operator->() const { + _LIBCPP_ASSERT_NON_NULL( + __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container iterator"); + return pointer_traits::pointer_to(__node_->__upcast()->__get_value()); + } + + _LIBCPP_HIDE_FROM_ABI __hash_iterator& operator++() { + _LIBCPP_ASSERT_NON_NULL( + __node_ != nullptr, "Attempted to increment a non-incrementable unordered container iterator"); + __node_ = __node_->__next_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI __hash_iterator operator++(int) { + __hash_iterator __t(*this); + ++(*this); + return __t; + } + + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const __hash_iterator& __x, const __hash_iterator& __y) { + return __x.__node_ == __y.__node_; + } + friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const __hash_iterator& __x, const __hash_iterator& __y) { + return !(__x == __y); + } + +private: + _LIBCPP_HIDE_FROM_ABI explicit __hash_iterator(__next_pointer __node) _NOEXCEPT : __node_(__node) {} + + template + friend class __hash_table; + template + friend class _LIBCPP_TEMPLATE_VIS __hash_const_iterator; + template + friend class _LIBCPP_TEMPLATE_VIS __hash_map_iterator; + template + friend class _LIBCPP_TEMPLATE_VIS unordered_map; + template + friend class _LIBCPP_TEMPLATE_VIS unordered_multimap; +}; + +template +class _LIBCPP_TEMPLATE_VIS __hash_const_iterator { + static_assert(!is_const::element_type>::value, ""); + typedef __hash_node_types<_NodePtr> _NodeTypes; + typedef _NodePtr __node_pointer; + typedef typename _NodeTypes::__next_pointer __next_pointer; + + __next_pointer __node_; + +public: + typedef __hash_iterator<_NodePtr> __non_const_iterator; + + typedef forward_iterator_tag iterator_category; + typedef typename _NodeTypes::__node_value_type value_type; + typedef typename _NodeTypes::difference_type difference_type; + typedef const value_type& reference; + typedef typename _NodeTypes::__const_node_value_type_pointer pointer; + + _LIBCPP_HIDE_FROM_ABI __hash_const_iterator() _NOEXCEPT : __node_(nullptr) {} + + _LIBCPP_HIDE_FROM_ABI __hash_const_iterator(const __non_const_iterator& __x) _NOEXCEPT : __node_(__x.__node_) {} + + _LIBCPP_HIDE_FROM_ABI reference operator*() const { + _LIBCPP_ASSERT_NON_NULL( + __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container const_iterator"); + return __node_->__upcast()->__get_value(); + } + _LIBCPP_HIDE_FROM_ABI pointer operator->() const { + _LIBCPP_ASSERT_NON_NULL( + __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container const_iterator"); + return pointer_traits::pointer_to(__node_->__upcast()->__get_value()); + } + + _LIBCPP_HIDE_FROM_ABI __hash_const_iterator& operator++() { + _LIBCPP_ASSERT_NON_NULL( + __node_ != nullptr, "Attempted to increment a non-incrementable unordered container const_iterator"); + __node_ = __node_->__next_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI __hash_const_iterator operator++(int) { + __hash_const_iterator __t(*this); + ++(*this); + return __t; + } + + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const __hash_const_iterator& __x, const __hash_const_iterator& __y) { + return __x.__node_ == __y.__node_; + } + friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const __hash_const_iterator& __x, const __hash_const_iterator& __y) { + return !(__x == __y); + } + +private: + _LIBCPP_HIDE_FROM_ABI explicit __hash_const_iterator(__next_pointer __node) _NOEXCEPT : __node_(__node) {} + + template + friend class __hash_table; + template + friend class _LIBCPP_TEMPLATE_VIS __hash_map_const_iterator; + template + friend class _LIBCPP_TEMPLATE_VIS unordered_map; + template + friend class _LIBCPP_TEMPLATE_VIS unordered_multimap; +}; + +template +class _LIBCPP_TEMPLATE_VIS __hash_local_iterator { + typedef __hash_node_types<_NodePtr> _NodeTypes; + typedef _NodePtr __node_pointer; + typedef typename _NodeTypes::__next_pointer __next_pointer; + + __next_pointer __node_; + size_t __bucket_; + size_t __bucket_count_; + +public: + typedef forward_iterator_tag iterator_category; + typedef typename _NodeTypes::__node_value_type value_type; + typedef typename _NodeTypes::difference_type difference_type; + typedef value_type& reference; + typedef typename _NodeTypes::__node_value_type_pointer pointer; + + _LIBCPP_HIDE_FROM_ABI __hash_local_iterator() _NOEXCEPT : __node_(nullptr) {} + + _LIBCPP_HIDE_FROM_ABI reference operator*() const { + _LIBCPP_ASSERT_NON_NULL( + __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container local_iterator"); + return __node_->__upcast()->__get_value(); + } + + _LIBCPP_HIDE_FROM_ABI pointer operator->() const { + _LIBCPP_ASSERT_NON_NULL( + __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container local_iterator"); + return pointer_traits::pointer_to(__node_->__upcast()->__get_value()); + } + + _LIBCPP_HIDE_FROM_ABI __hash_local_iterator& operator++() { + _LIBCPP_ASSERT_NON_NULL( + __node_ != nullptr, "Attempted to increment a non-incrementable unordered container local_iterator"); + __node_ = __node_->__next_; + if (__node_ != nullptr && std::__constrain_hash(__node_->__hash(), __bucket_count_) != __bucket_) + __node_ = nullptr; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI __hash_local_iterator operator++(int) { + __hash_local_iterator __t(*this); + ++(*this); + return __t; + } + + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const __hash_local_iterator& __x, const __hash_local_iterator& __y) { + return __x.__node_ == __y.__node_; + } + friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const __hash_local_iterator& __x, const __hash_local_iterator& __y) { + return !(__x == __y); + } + +private: + _LIBCPP_HIDE_FROM_ABI explicit __hash_local_iterator( + __next_pointer __node, size_t __bucket, size_t __bucket_count) _NOEXCEPT + : __node_(__node), + __bucket_(__bucket), + __bucket_count_(__bucket_count) { + if (__node_ != nullptr) + __node_ = __node_->__next_; + } + + template + friend class __hash_table; + template + friend class _LIBCPP_TEMPLATE_VIS __hash_const_local_iterator; + template + friend class _LIBCPP_TEMPLATE_VIS __hash_map_iterator; +}; + +template +class _LIBCPP_TEMPLATE_VIS __hash_const_local_iterator { + typedef __hash_node_types<_ConstNodePtr> _NodeTypes; + typedef _ConstNodePtr __node_pointer; + typedef typename _NodeTypes::__next_pointer __next_pointer; + + __next_pointer __node_; + size_t __bucket_; + size_t __bucket_count_; + + typedef pointer_traits<__node_pointer> __pointer_traits; + typedef typename __pointer_traits::element_type __node; + typedef __remove_const_t<__node> __non_const_node; + typedef __rebind_pointer_t<__node_pointer, __non_const_node> __non_const_node_pointer; + +public: + typedef __hash_local_iterator<__non_const_node_pointer> __non_const_iterator; + + typedef forward_iterator_tag iterator_category; + typedef typename _NodeTypes::__node_value_type value_type; + typedef typename _NodeTypes::difference_type difference_type; + typedef const value_type& reference; + typedef typename _NodeTypes::__const_node_value_type_pointer pointer; + + _LIBCPP_HIDE_FROM_ABI __hash_const_local_iterator() _NOEXCEPT : __node_(nullptr) {} + + _LIBCPP_HIDE_FROM_ABI __hash_const_local_iterator(const __non_const_iterator& __x) _NOEXCEPT + : __node_(__x.__node_), + __bucket_(__x.__bucket_), + __bucket_count_(__x.__bucket_count_) {} + + _LIBCPP_HIDE_FROM_ABI reference operator*() const { + _LIBCPP_ASSERT_NON_NULL( + __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container const_local_iterator"); + return __node_->__upcast()->__get_value(); + } + + _LIBCPP_HIDE_FROM_ABI pointer operator->() const { + _LIBCPP_ASSERT_NON_NULL( + __node_ != nullptr, "Attempted to dereference a non-dereferenceable unordered container const_local_iterator"); + return pointer_traits::pointer_to(__node_->__upcast()->__get_value()); + } + + _LIBCPP_HIDE_FROM_ABI __hash_const_local_iterator& operator++() { + _LIBCPP_ASSERT_NON_NULL( + __node_ != nullptr, "Attempted to increment a non-incrementable unordered container const_local_iterator"); + __node_ = __node_->__next_; + if (__node_ != nullptr && std::__constrain_hash(__node_->__hash(), __bucket_count_) != __bucket_) + __node_ = nullptr; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI __hash_const_local_iterator operator++(int) { + __hash_const_local_iterator __t(*this); + ++(*this); + return __t; + } + + friend _LIBCPP_HIDE_FROM_ABI bool + operator==(const __hash_const_local_iterator& __x, const __hash_const_local_iterator& __y) { + return __x.__node_ == __y.__node_; + } + friend _LIBCPP_HIDE_FROM_ABI bool + operator!=(const __hash_const_local_iterator& __x, const __hash_const_local_iterator& __y) { + return !(__x == __y); + } + +private: + _LIBCPP_HIDE_FROM_ABI explicit __hash_const_local_iterator( + __next_pointer __node_ptr, size_t __bucket, size_t __bucket_count) _NOEXCEPT + : __node_(__node_ptr), + __bucket_(__bucket), + __bucket_count_(__bucket_count) { + if (__node_ != nullptr) + __node_ = __node_->__next_; + } + + template + friend class __hash_table; + template + friend class _LIBCPP_TEMPLATE_VIS __hash_map_const_iterator; +}; + +template +class __bucket_list_deallocator { + typedef _Alloc allocator_type; + typedef allocator_traits __alloc_traits; + typedef typename __alloc_traits::size_type size_type; + + __compressed_pair __data_; + +public: + typedef typename __alloc_traits::pointer pointer; + + _LIBCPP_HIDE_FROM_ABI __bucket_list_deallocator() _NOEXCEPT_(is_nothrow_default_constructible::value) + : __data_(0, __default_init_tag()) {} + + _LIBCPP_HIDE_FROM_ABI __bucket_list_deallocator(const allocator_type& __a, size_type __size) + _NOEXCEPT_(is_nothrow_copy_constructible::value) + : __data_(__size, __a) {} + + _LIBCPP_HIDE_FROM_ABI __bucket_list_deallocator(__bucket_list_deallocator&& __x) + _NOEXCEPT_(is_nothrow_move_constructible::value) + : __data_(std::move(__x.__data_)) { + __x.size() = 0; + } + + _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __data_.first(); } + _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __data_.first(); } + + _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT { return __data_.second(); } + _LIBCPP_HIDE_FROM_ABI const allocator_type& __alloc() const _NOEXCEPT { return __data_.second(); } + + _LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT { __alloc_traits::deallocate(__alloc(), __p, size()); } +}; + +template +class __hash_map_node_destructor; + +template +class __hash_node_destructor { + typedef _Alloc allocator_type; + typedef allocator_traits __alloc_traits; + +public: + typedef typename __alloc_traits::pointer pointer; + +private: + typedef __hash_node_types _NodeTypes; + + allocator_type& __na_; + +public: + bool __value_constructed; + + _LIBCPP_HIDE_FROM_ABI __hash_node_destructor(__hash_node_destructor const&) = default; + _LIBCPP_HIDE_FROM_ABI __hash_node_destructor& operator=(const __hash_node_destructor&) = delete; + + _LIBCPP_HIDE_FROM_ABI explicit __hash_node_destructor(allocator_type& __na, bool __constructed = false) _NOEXCEPT + : __na_(__na), + __value_constructed(__constructed) {} + + _LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT { + if (__value_constructed) { + __alloc_traits::destroy(__na_, _NodeTypes::__get_ptr(__p->__get_value())); + std::__destroy_at(std::addressof(*__p)); + } + if (__p) + __alloc_traits::deallocate(__na_, __p, 1); + } + + template + friend class __hash_map_node_destructor; +}; + +#if _LIBCPP_STD_VER >= 17 +template +struct __generic_container_node_destructor; + +template +struct __generic_container_node_destructor<__hash_node<_Tp, _VoidPtr>, _Alloc> : __hash_node_destructor<_Alloc> { + using __hash_node_destructor<_Alloc>::__hash_node_destructor; +}; +#endif + +template +struct __enforce_unordered_container_requirements { +#ifndef _LIBCPP_CXX03_LANG + static_assert(__check_hash_requirements<_Key, _Hash>::value, + "the specified hash does not meet the Hash requirements"); + static_assert(is_copy_constructible<_Equal>::value, "the specified comparator is required to be copy constructible"); +#endif + typedef int type; +}; + +template +#ifndef _LIBCPP_CXX03_LANG +_LIBCPP_DIAGNOSE_WARNING(!__invokable<_Equal const&, _Key const&, _Key const&>::value, + "the specified comparator type does not provide a viable const call operator") +_LIBCPP_DIAGNOSE_WARNING(!__invokable<_Hash const&, _Key const&>::value, + "the specified hash functor does not provide a viable const call operator") +#endif + typename __enforce_unordered_container_requirements<_Key, _Hash, _Equal>::type + __diagnose_unordered_container_requirements(int); + +// This dummy overload is used so that the compiler won't emit a spurious +// "no matching function for call to __diagnose_unordered_xxx" diagnostic +// when the overload above causes a hard error. +template +int __diagnose_unordered_container_requirements(void*); + +template +class __hash_table { +public: + typedef _Tp value_type; + typedef _Hash hasher; + typedef _Equal key_equal; + typedef _Alloc allocator_type; + +private: + typedef allocator_traits __alloc_traits; + typedef typename __make_hash_node_types::type _NodeTypes; + +public: + typedef typename _NodeTypes::__node_value_type __node_value_type; + typedef typename _NodeTypes::__container_value_type __container_value_type; + typedef typename _NodeTypes::key_type key_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef typename __alloc_traits::pointer pointer; + typedef typename __alloc_traits::const_pointer const_pointer; +#ifndef _LIBCPP_ABI_FIX_UNORDERED_CONTAINER_SIZE_TYPE + typedef typename __alloc_traits::size_type size_type; +#else + typedef typename _NodeTypes::size_type size_type; +#endif + typedef typename _NodeTypes::difference_type difference_type; + +public: + // Create __node + + typedef typename _NodeTypes::__node_type __node; + typedef __rebind_alloc<__alloc_traits, __node> __node_allocator; + typedef allocator_traits<__node_allocator> __node_traits; + typedef typename _NodeTypes::__void_pointer __void_pointer; + typedef typename _NodeTypes::__node_pointer __node_pointer; + typedef typename _NodeTypes::__node_pointer __node_const_pointer; + typedef typename _NodeTypes::__node_base_type __first_node; + typedef typename _NodeTypes::__node_base_pointer __node_base_pointer; + typedef typename _NodeTypes::__next_pointer __next_pointer; + +private: + // check for sane allocator pointer rebinding semantics. Rebinding the + // allocator for a new pointer type should be exactly the same as rebinding + // the pointer using 'pointer_traits'. + static_assert(is_same<__node_pointer, typename __node_traits::pointer>::value, + "Allocator does not rebind pointers in a sane manner."); + typedef __rebind_alloc<__node_traits, __first_node> __node_base_allocator; + typedef allocator_traits<__node_base_allocator> __node_base_traits; + static_assert(is_same<__node_base_pointer, typename __node_base_traits::pointer>::value, + "Allocator does not rebind pointers in a sane manner."); + +private: + typedef __rebind_alloc<__node_traits, __next_pointer> __pointer_allocator; + typedef __bucket_list_deallocator<__pointer_allocator> __bucket_list_deleter; + typedef unique_ptr<__next_pointer[], __bucket_list_deleter> __bucket_list; + typedef allocator_traits<__pointer_allocator> __pointer_alloc_traits; + typedef typename __bucket_list_deleter::pointer __node_pointer_pointer; + + // --- Member data begin --- + __bucket_list __bucket_list_; + __compressed_pair<__first_node, __node_allocator> __p1_; + __compressed_pair __p2_; + __compressed_pair __p3_; + // --- Member data end --- + + _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __p2_.first(); } + +public: + _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __p2_.first(); } + + _LIBCPP_HIDE_FROM_ABI hasher& hash_function() _NOEXCEPT { return __p2_.second(); } + _LIBCPP_HIDE_FROM_ABI const hasher& hash_function() const _NOEXCEPT { return __p2_.second(); } + + _LIBCPP_HIDE_FROM_ABI float& max_load_factor() _NOEXCEPT { return __p3_.first(); } + _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __p3_.first(); } + + _LIBCPP_HIDE_FROM_ABI key_equal& key_eq() _NOEXCEPT { return __p3_.second(); } + _LIBCPP_HIDE_FROM_ABI const key_equal& key_eq() const _NOEXCEPT { return __p3_.second(); } + + _LIBCPP_HIDE_FROM_ABI __node_allocator& __node_alloc() _NOEXCEPT { return __p1_.second(); } + _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __p1_.second(); } + +public: + typedef __hash_iterator<__node_pointer> iterator; + typedef __hash_const_iterator<__node_pointer> const_iterator; + typedef __hash_local_iterator<__node_pointer> local_iterator; + typedef __hash_const_local_iterator<__node_pointer> const_local_iterator; + + _LIBCPP_HIDE_FROM_ABI __hash_table() _NOEXCEPT_( + is_nothrow_default_constructible<__bucket_list>::value&& is_nothrow_default_constructible<__first_node>::value&& + is_nothrow_default_constructible<__node_allocator>::value&& is_nothrow_default_constructible::value&& + is_nothrow_default_constructible::value); + _LIBCPP_HIDE_FROM_ABI __hash_table(const hasher& __hf, const key_equal& __eql); + _LIBCPP_HIDE_FROM_ABI __hash_table(const hasher& __hf, const key_equal& __eql, const allocator_type& __a); + _LIBCPP_HIDE_FROM_ABI explicit __hash_table(const allocator_type& __a); + _LIBCPP_HIDE_FROM_ABI __hash_table(const __hash_table& __u); + _LIBCPP_HIDE_FROM_ABI __hash_table(const __hash_table& __u, const allocator_type& __a); + _LIBCPP_HIDE_FROM_ABI __hash_table(__hash_table&& __u) _NOEXCEPT_( + is_nothrow_move_constructible<__bucket_list>::value&& is_nothrow_move_constructible<__first_node>::value&& + is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible::value&& + is_nothrow_move_constructible::value); + _LIBCPP_HIDE_FROM_ABI __hash_table(__hash_table&& __u, const allocator_type& __a); + _LIBCPP_HIDE_FROM_ABI ~__hash_table(); + + _LIBCPP_HIDE_FROM_ABI __hash_table& operator=(const __hash_table& __u); + _LIBCPP_HIDE_FROM_ABI __hash_table& operator=(__hash_table&& __u) + _NOEXCEPT_(__node_traits::propagate_on_container_move_assignment::value&& + is_nothrow_move_assignable<__node_allocator>::value&& is_nothrow_move_assignable::value&& + is_nothrow_move_assignable::value); + template + _LIBCPP_HIDE_FROM_ABI void __assign_unique(_InputIterator __first, _InputIterator __last); + template + _LIBCPP_HIDE_FROM_ABI void __assign_multi(_InputIterator __first, _InputIterator __last); + + _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { + return std::min(__node_traits::max_size(__node_alloc()), numeric_limits::max()); + } + +private: + _LIBCPP_HIDE_FROM_ABI __next_pointer __node_insert_multi_prepare(size_t __cp_hash, value_type& __cp_val); + _LIBCPP_HIDE_FROM_ABI void __node_insert_multi_perform(__node_pointer __cp, __next_pointer __pn) _NOEXCEPT; + + _LIBCPP_HIDE_FROM_ABI __next_pointer __node_insert_unique_prepare(size_t __nd_hash, value_type& __nd_val); + _LIBCPP_HIDE_FROM_ABI void __node_insert_unique_perform(__node_pointer __ptr) _NOEXCEPT; + +public: + _LIBCPP_HIDE_FROM_ABI pair __node_insert_unique(__node_pointer __nd); + _LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(__node_pointer __nd); + _LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(const_iterator __p, __node_pointer __nd); + + template + _LIBCPP_HIDE_FROM_ABI pair __emplace_unique_key_args(_Key const& __k, _Args&&... __args); + + template + _LIBCPP_HIDE_FROM_ABI pair __emplace_unique_impl(_Args&&... __args); + + template + _LIBCPP_HIDE_FROM_ABI pair __emplace_unique(_Pp&& __x) { + return __emplace_unique_extract_key(std::forward<_Pp>(__x), __can_extract_key<_Pp, key_type>()); + } + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI pair __emplace_unique(_First&& __f, _Second&& __s) { + return __emplace_unique_key_args(__f, std::forward<_First>(__f), std::forward<_Second>(__s)); + } + + template + _LIBCPP_HIDE_FROM_ABI pair __emplace_unique(_Args&&... __args) { + return __emplace_unique_impl(std::forward<_Args>(__args)...); + } + + template + _LIBCPP_HIDE_FROM_ABI pair __emplace_unique_extract_key(_Pp&& __x, __extract_key_fail_tag) { + return __emplace_unique_impl(std::forward<_Pp>(__x)); + } + template + _LIBCPP_HIDE_FROM_ABI pair __emplace_unique_extract_key(_Pp&& __x, __extract_key_self_tag) { + return __emplace_unique_key_args(__x, std::forward<_Pp>(__x)); + } + template + _LIBCPP_HIDE_FROM_ABI pair __emplace_unique_extract_key(_Pp&& __x, __extract_key_first_tag) { + return __emplace_unique_key_args(__x.first, std::forward<_Pp>(__x)); + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_multi(_Args&&... __args); + template + _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint_multi(const_iterator __p, _Args&&... __args); + + _LIBCPP_HIDE_FROM_ABI pair __insert_unique(__container_value_type&& __x) { + return __emplace_unique_key_args(_NodeTypes::__get_key(__x), std::move(__x)); + } + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI pair __insert_unique(_Pp&& __x) { + return __emplace_unique(std::forward<_Pp>(__x)); + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __insert_multi(_Pp&& __x) { + return __emplace_multi(std::forward<_Pp>(__x)); + } + + template + _LIBCPP_HIDE_FROM_ABI iterator __insert_multi(const_iterator __p, _Pp&& __x) { + return __emplace_hint_multi(__p, std::forward<_Pp>(__x)); + } + + _LIBCPP_HIDE_FROM_ABI pair __insert_unique(const __container_value_type& __x) { + return __emplace_unique_key_args(_NodeTypes::__get_key(__x), __x); + } + +#if _LIBCPP_STD_VER >= 17 + template + _LIBCPP_HIDE_FROM_ABI _InsertReturnType __node_handle_insert_unique(_NodeHandle&& __nh); + template + _LIBCPP_HIDE_FROM_ABI iterator __node_handle_insert_unique(const_iterator __hint, _NodeHandle&& __nh); + template + _LIBCPP_HIDE_FROM_ABI void __node_handle_merge_unique(_Table& __source); + + template + _LIBCPP_HIDE_FROM_ABI iterator __node_handle_insert_multi(_NodeHandle&& __nh); + template + _LIBCPP_HIDE_FROM_ABI iterator __node_handle_insert_multi(const_iterator __hint, _NodeHandle&& __nh); + template + _LIBCPP_HIDE_FROM_ABI void __node_handle_merge_multi(_Table& __source); + + template + _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(key_type const& __key); + template + _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(const_iterator __it); +#endif + + _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI void __rehash_unique(size_type __n) { __rehash(__n); } + _LIBCPP_HIDE_FROM_ABI void __rehash_multi(size_type __n) { __rehash(__n); } + _LIBCPP_HIDE_FROM_ABI void __reserve_unique(size_type __n) { + __rehash_unique(static_cast(std::ceil(__n / max_load_factor()))); + } + _LIBCPP_HIDE_FROM_ABI void __reserve_multi(size_type __n) { + __rehash_multi(static_cast(std::ceil(__n / max_load_factor()))); + } + + _LIBCPP_HIDE_FROM_ABI size_type bucket_count() const _NOEXCEPT { return __bucket_list_.get_deleter().size(); } + + _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT; + + template + _LIBCPP_HIDE_FROM_ABI size_type bucket(const _Key& __k) const { + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( + bucket_count() > 0, "unordered container::bucket(key) called when bucket_count() == 0"); + return std::__constrain_hash(hash_function()(__k), bucket_count()); + } + + template + _LIBCPP_HIDE_FROM_ABI iterator find(const _Key& __x); + template + _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Key& __x) const; + + typedef __hash_node_destructor<__node_allocator> _Dp; + typedef unique_ptr<__node, _Dp> __node_holder; + + _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p); + _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last); + template + _LIBCPP_HIDE_FROM_ABI size_type __erase_unique(const _Key& __k); + template + _LIBCPP_HIDE_FROM_ABI size_type __erase_multi(const _Key& __k); + _LIBCPP_HIDE_FROM_ABI __node_holder remove(const_iterator __p) _NOEXCEPT; + + template + _LIBCPP_HIDE_FROM_ABI size_type __count_unique(const _Key& __k) const; + template + _LIBCPP_HIDE_FROM_ABI size_type __count_multi(const _Key& __k) const; + + template + _LIBCPP_HIDE_FROM_ABI pair __equal_range_unique(const _Key& __k); + template + _LIBCPP_HIDE_FROM_ABI pair __equal_range_unique(const _Key& __k) const; + + template + _LIBCPP_HIDE_FROM_ABI pair __equal_range_multi(const _Key& __k); + template + _LIBCPP_HIDE_FROM_ABI pair __equal_range_multi(const _Key& __k) const; + + _LIBCPP_HIDE_FROM_ABI void swap(__hash_table& __u) +#if _LIBCPP_STD_VER <= 11 + _NOEXCEPT_(__is_nothrow_swappable_v&& __is_nothrow_swappable_v && + (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value || + __is_nothrow_swappable_v<__pointer_allocator>) && + (!__node_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__node_allocator>)); +#else + _NOEXCEPT_(__is_nothrow_swappable_v&& __is_nothrow_swappable_v); +#endif + + _LIBCPP_HIDE_FROM_ABI size_type max_bucket_count() const _NOEXCEPT { return max_size(); } + _LIBCPP_HIDE_FROM_ABI size_type bucket_size(size_type __n) const; + _LIBCPP_HIDE_FROM_ABI float load_factor() const _NOEXCEPT { + size_type __bc = bucket_count(); + return __bc != 0 ? (float)size() / __bc : 0.f; + } + _LIBCPP_HIDE_FROM_ABI void max_load_factor(float __mlf) _NOEXCEPT { + // While passing a non-positive load factor is undefined behavior, in practice the result will be benign (the + // call will be equivalent to `max_load_factor(load_factor())`, which is also the case for passing a valid value + // less than the current `load_factor`). + _LIBCPP_ASSERT_PEDANTIC(__mlf > 0, "unordered container::max_load_factor(lf) called with lf <= 0"); + max_load_factor() = std::max(__mlf, load_factor()); + } + + _LIBCPP_HIDE_FROM_ABI local_iterator begin(size_type __n) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __n < bucket_count(), "unordered container::begin(n) called with n >= bucket_count()"); + return local_iterator(__bucket_list_[__n], __n, bucket_count()); + } + + _LIBCPP_HIDE_FROM_ABI local_iterator end(size_type __n) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __n < bucket_count(), "unordered container::end(n) called with n >= bucket_count()"); + return local_iterator(nullptr, __n, bucket_count()); + } + + _LIBCPP_HIDE_FROM_ABI const_local_iterator cbegin(size_type __n) const { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __n < bucket_count(), "unordered container::cbegin(n) called with n >= bucket_count()"); + return const_local_iterator(__bucket_list_[__n], __n, bucket_count()); + } + + _LIBCPP_HIDE_FROM_ABI const_local_iterator cend(size_type __n) const { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __n < bucket_count(), "unordered container::cend(n) called with n >= bucket_count()"); + return const_local_iterator(nullptr, __n, bucket_count()); + } + +private: + template + _LIBCPP_HIDE_FROM_ABI void __rehash(size_type __n); + template + _LIBCPP_HIDE_FROM_ABI void __do_rehash(size_type __n); + + template + _LIBCPP_HIDE_FROM_ABI __node_holder __construct_node(_Args&&... __args); + + template + _LIBCPP_HIDE_FROM_ABI __node_holder __construct_node_hash(size_t __hash, _First&& __f, _Rest&&... __rest); + + _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __hash_table& __u) { + __copy_assign_alloc(__u, integral_constant()); + } + _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __hash_table& __u, true_type); + _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __hash_table&, false_type) {} + + _LIBCPP_HIDE_FROM_ABI void __move_assign(__hash_table& __u, false_type); + _LIBCPP_HIDE_FROM_ABI void __move_assign(__hash_table& __u, true_type) + _NOEXCEPT_(is_nothrow_move_assignable<__node_allocator>::value&& is_nothrow_move_assignable::value&& + is_nothrow_move_assignable::value); + _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__hash_table& __u) _NOEXCEPT_( + !__node_traits::propagate_on_container_move_assignment::value || + (is_nothrow_move_assignable<__pointer_allocator>::value && is_nothrow_move_assignable<__node_allocator>::value)) { + __move_assign_alloc(__u, integral_constant()); + } + _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__hash_table& __u, true_type) _NOEXCEPT_( + is_nothrow_move_assignable<__pointer_allocator>::value&& is_nothrow_move_assignable<__node_allocator>::value) { + __bucket_list_.get_deleter().__alloc() = std::move(__u.__bucket_list_.get_deleter().__alloc()); + __node_alloc() = std::move(__u.__node_alloc()); + } + _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__hash_table&, false_type) _NOEXCEPT {} + + _LIBCPP_HIDE_FROM_ABI void __deallocate_node(__next_pointer __np) _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI __next_pointer __detach() _NOEXCEPT; + + template + friend class _LIBCPP_TEMPLATE_VIS unordered_map; + template + friend class _LIBCPP_TEMPLATE_VIS unordered_multimap; +}; + +template +inline __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table() _NOEXCEPT_( + is_nothrow_default_constructible<__bucket_list>::value&& is_nothrow_default_constructible<__first_node>::value&& + is_nothrow_default_constructible<__node_allocator>::value&& is_nothrow_default_constructible::value&& + is_nothrow_default_constructible::value) + : __p2_(0, __default_init_tag()), __p3_(1.0f, __default_init_tag()) {} + +template +inline __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const hasher& __hf, const key_equal& __eql) + : __bucket_list_(nullptr, __bucket_list_deleter()), __p1_(), __p2_(0, __hf), __p3_(1.0f, __eql) {} + +template +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table( + const hasher& __hf, const key_equal& __eql, const allocator_type& __a) + : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)), + __p1_(__default_init_tag(), __node_allocator(__a)), + __p2_(0, __hf), + __p3_(1.0f, __eql) {} + +template +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const allocator_type& __a) + : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)), + __p1_(__default_init_tag(), __node_allocator(__a)), + __p2_(0, __default_init_tag()), + __p3_(1.0f, __default_init_tag()) {} + +template +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u) + : __bucket_list_(nullptr, + __bucket_list_deleter(allocator_traits<__pointer_allocator>::select_on_container_copy_construction( + __u.__bucket_list_.get_deleter().__alloc()), + 0)), + __p1_(__default_init_tag(), + allocator_traits<__node_allocator>::select_on_container_copy_construction(__u.__node_alloc())), + __p2_(0, __u.hash_function()), + __p3_(__u.__p3_) {} + +template +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u, const allocator_type& __a) + : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)), + __p1_(__default_init_tag(), __node_allocator(__a)), + __p2_(0, __u.hash_function()), + __p3_(__u.__p3_) {} + +template +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u) _NOEXCEPT_( + is_nothrow_move_constructible<__bucket_list>::value&& is_nothrow_move_constructible<__first_node>::value&& + is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible::value&& + is_nothrow_move_constructible::value) + : __bucket_list_(std::move(__u.__bucket_list_)), + __p1_(std::move(__u.__p1_)), + __p2_(std::move(__u.__p2_)), + __p3_(std::move(__u.__p3_)) { + if (size() > 0) { + __bucket_list_[std::__constrain_hash(__p1_.first().__next_->__hash(), bucket_count())] = __p1_.first().__ptr(); + __u.__p1_.first().__next_ = nullptr; + __u.size() = 0; + } +} + +template +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u, const allocator_type& __a) + : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)), + __p1_(__default_init_tag(), __node_allocator(__a)), + __p2_(0, std::move(__u.hash_function())), + __p3_(std::move(__u.__p3_)) { + if (__a == allocator_type(__u.__node_alloc())) { + __bucket_list_.reset(__u.__bucket_list_.release()); + __bucket_list_.get_deleter().size() = __u.__bucket_list_.get_deleter().size(); + __u.__bucket_list_.get_deleter().size() = 0; + if (__u.size() > 0) { + __p1_.first().__next_ = __u.__p1_.first().__next_; + __u.__p1_.first().__next_ = nullptr; + __bucket_list_[std::__constrain_hash(__p1_.first().__next_->__hash(), bucket_count())] = __p1_.first().__ptr(); + size() = __u.size(); + __u.size() = 0; + } + } +} + +template +__hash_table<_Tp, _Hash, _Equal, _Alloc>::~__hash_table() { +#if defined(_LIBCPP_CXX03_LANG) + static_assert(is_copy_constructible::value, "Predicate must be copy-constructible."); + static_assert(is_copy_constructible::value, "Hasher must be copy-constructible."); +#endif + + __deallocate_node(__p1_.first().__next_); +} + +template +void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__copy_assign_alloc(const __hash_table& __u, true_type) { + if (__node_alloc() != __u.__node_alloc()) { + clear(); + __bucket_list_.reset(); + __bucket_list_.get_deleter().size() = 0; + } + __bucket_list_.get_deleter().__alloc() = __u.__bucket_list_.get_deleter().__alloc(); + __node_alloc() = __u.__node_alloc(); +} + +template +__hash_table<_Tp, _Hash, _Equal, _Alloc>& __hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(const __hash_table& __u) { + if (this != std::addressof(__u)) { + __copy_assign_alloc(__u); + hash_function() = __u.hash_function(); + key_eq() = __u.key_eq(); + max_load_factor() = __u.max_load_factor(); + __assign_multi(__u.begin(), __u.end()); + } + return *this; +} + +template +void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__deallocate_node(__next_pointer __np) _NOEXCEPT { + __node_allocator& __na = __node_alloc(); + while (__np != nullptr) { + __next_pointer __next = __np->__next_; + __node_pointer __real_np = __np->__upcast(); + __node_traits::destroy(__na, _NodeTypes::__get_ptr(__real_np->__get_value())); + std::__destroy_at(std::addressof(*__real_np)); + __node_traits::deallocate(__na, __real_np, 1); + __np = __next; + } +} + +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__next_pointer +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__detach() _NOEXCEPT { + size_type __bc = bucket_count(); + for (size_type __i = 0; __i < __bc; ++__i) + __bucket_list_[__i] = nullptr; + size() = 0; + __next_pointer __cache = __p1_.first().__next_; + __p1_.first().__next_ = nullptr; + return __cache; +} + +template +void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u, true_type) + _NOEXCEPT_(is_nothrow_move_assignable<__node_allocator>::value&& is_nothrow_move_assignable::value&& + is_nothrow_move_assignable::value) { + clear(); + __bucket_list_.reset(__u.__bucket_list_.release()); + __bucket_list_.get_deleter().size() = __u.__bucket_list_.get_deleter().size(); + __u.__bucket_list_.get_deleter().size() = 0; + __move_assign_alloc(__u); + size() = __u.size(); + hash_function() = std::move(__u.hash_function()); + max_load_factor() = __u.max_load_factor(); + key_eq() = std::move(__u.key_eq()); + __p1_.first().__next_ = __u.__p1_.first().__next_; + if (size() > 0) { + __bucket_list_[std::__constrain_hash(__p1_.first().__next_->__hash(), bucket_count())] = __p1_.first().__ptr(); + __u.__p1_.first().__next_ = nullptr; + __u.size() = 0; + } +} + +template +void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u, false_type) { + if (__node_alloc() == __u.__node_alloc()) + __move_assign(__u, true_type()); + else { + hash_function() = std::move(__u.hash_function()); + key_eq() = std::move(__u.key_eq()); + max_load_factor() = __u.max_load_factor(); + if (bucket_count() != 0) { + __next_pointer __cache = __detach(); +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + try { +#endif // _LIBCPP_HAS_NO_EXCEPTIONS + const_iterator __i = __u.begin(); + while (__cache != nullptr && __u.size() != 0) { + __cache->__upcast()->__get_value() = std::move(__u.remove(__i++)->__get_value()); + __next_pointer __next = __cache->__next_; + __node_insert_multi(__cache->__upcast()); + __cache = __next; + } +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + } catch (...) { + __deallocate_node(__cache); + throw; + } +#endif // _LIBCPP_HAS_NO_EXCEPTIONS + __deallocate_node(__cache); + } + const_iterator __i = __u.begin(); + while (__u.size() != 0) { + __node_holder __h = __construct_node(_NodeTypes::__move(__u.remove(__i++)->__get_value())); + __node_insert_multi(__h.get()); + __h.release(); + } + } +} + +template +inline __hash_table<_Tp, _Hash, _Equal, _Alloc>& +__hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(__hash_table&& __u) _NOEXCEPT_( + __node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<__node_allocator>::value&& + is_nothrow_move_assignable::value&& is_nothrow_move_assignable::value) { + __move_assign(__u, integral_constant()); + return *this; +} + +template +template +void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __first, _InputIterator __last) { + typedef iterator_traits<_InputIterator> _ITraits; + typedef typename _ITraits::value_type _ItValueType; + static_assert(is_same<_ItValueType, __container_value_type>::value, + "__assign_unique may only be called with the containers value type"); + + if (bucket_count() != 0) { + __next_pointer __cache = __detach(); +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + try { +#endif // _LIBCPP_HAS_NO_EXCEPTIONS + for (; __cache != nullptr && __first != __last; ++__first) { + __cache->__upcast()->__get_value() = *__first; + __next_pointer __next = __cache->__next_; + __node_insert_unique(__cache->__upcast()); + __cache = __next; + } +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + } catch (...) { + __deallocate_node(__cache); + throw; + } +#endif // _LIBCPP_HAS_NO_EXCEPTIONS + __deallocate_node(__cache); + } + for (; __first != __last; ++__first) + __insert_unique(*__first); +} + +template +template +void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __first, _InputIterator __last) { + typedef iterator_traits<_InputIterator> _ITraits; + typedef typename _ITraits::value_type _ItValueType; + static_assert( + (is_same<_ItValueType, __container_value_type>::value || is_same<_ItValueType, __node_value_type>::value), + "__assign_multi may only be called with the containers value type" + " or the nodes value type"); + if (bucket_count() != 0) { + __next_pointer __cache = __detach(); +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + try { +#endif // _LIBCPP_HAS_NO_EXCEPTIONS + for (; __cache != nullptr && __first != __last; ++__first) { + __cache->__upcast()->__get_value() = *__first; + __next_pointer __next = __cache->__next_; + __node_insert_multi(__cache->__upcast()); + __cache = __next; + } +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + } catch (...) { + __deallocate_node(__cache); + throw; + } +#endif // _LIBCPP_HAS_NO_EXCEPTIONS + __deallocate_node(__cache); + } + for (; __first != __last; ++__first) + __insert_multi(_NodeTypes::__get_value(*__first)); +} + +template +inline typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::begin() _NOEXCEPT { + return iterator(__p1_.first().__next_); +} + +template +inline typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::end() _NOEXCEPT { + return iterator(nullptr); +} + +template +inline typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::begin() const _NOEXCEPT { + return const_iterator(__p1_.first().__next_); +} + +template +inline typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::end() const _NOEXCEPT { + return const_iterator(nullptr); +} + +template +void __hash_table<_Tp, _Hash, _Equal, _Alloc>::clear() _NOEXCEPT { + if (size() > 0) { + __deallocate_node(__p1_.first().__next_); + __p1_.first().__next_ = nullptr; + size_type __bc = bucket_count(); + for (size_type __i = 0; __i < __bc; ++__i) + __bucket_list_[__i] = nullptr; + size() = 0; + } +} + +// Prepare the container for an insertion of the value __value with the hash +// __hash. This does a lookup into the container to see if __value is already +// present, and performs a rehash if necessary. Returns a pointer to the +// existing element if it exists, otherwise nullptr. +// +// Note that this function does forward exceptions if key_eq() throws, and never +// mutates __value or actually inserts into the map. +template +_LIBCPP_HIDE_FROM_ABI typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__next_pointer +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique_prepare(size_t __hash, value_type& __value) { + size_type __bc = bucket_count(); + + if (__bc != 0) { + size_t __chash = std::__constrain_hash(__hash, __bc); + __next_pointer __ndptr = __bucket_list_[__chash]; + if (__ndptr != nullptr) { + for (__ndptr = __ndptr->__next_; + __ndptr != nullptr && + (__ndptr->__hash() == __hash || std::__constrain_hash(__ndptr->__hash(), __bc) == __chash); + __ndptr = __ndptr->__next_) { + if ((__ndptr->__hash() == __hash) && key_eq()(__ndptr->__upcast()->__get_value(), __value)) + return __ndptr; + } + } + } + if (size() + 1 > __bc * max_load_factor() || __bc == 0) { + __rehash_unique(std::max( + 2 * __bc + !std::__is_hash_power2(__bc), size_type(std::ceil(float(size() + 1) / max_load_factor())))); + } + return nullptr; +} + +// Insert the node __nd into the container by pushing it into the right bucket, +// and updating size(). Assumes that __nd->__hash is up-to-date, and that +// rehashing has already occurred and that no element with the same key exists +// in the map. +template +_LIBCPP_HIDE_FROM_ABI void +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique_perform(__node_pointer __nd) _NOEXCEPT { + size_type __bc = bucket_count(); + size_t __chash = std::__constrain_hash(__nd->__hash(), __bc); + // insert_after __bucket_list_[__chash], or __first_node if bucket is null + __next_pointer __pn = __bucket_list_[__chash]; + if (__pn == nullptr) { + __pn = __p1_.first().__ptr(); + __nd->__next_ = __pn->__next_; + __pn->__next_ = __nd->__ptr(); + // fix up __bucket_list_ + __bucket_list_[__chash] = __pn; + if (__nd->__next_ != nullptr) + __bucket_list_[std::__constrain_hash(__nd->__next_->__hash(), __bc)] = __nd->__ptr(); + } else { + __nd->__next_ = __pn->__next_; + __pn->__next_ = __nd->__ptr(); + } + ++size(); +} + +template +pair::iterator, bool> +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique(__node_pointer __nd) { + __nd->__hash_ = hash_function()(__nd->__get_value()); + __next_pointer __existing_node = __node_insert_unique_prepare(__nd->__hash(), __nd->__get_value()); + + // Insert the node, unless it already exists in the container. + bool __inserted = false; + if (__existing_node == nullptr) { + __node_insert_unique_perform(__nd); + __existing_node = __nd->__ptr(); + __inserted = true; + } + return pair(iterator(__existing_node), __inserted); +} + +// Prepare the container for an insertion of the value __cp_val with the hash +// __cp_hash. This does a lookup into the container to see if __cp_value is +// already present, and performs a rehash if necessary. Returns a pointer to the +// last occurrence of __cp_val in the map. +// +// Note that this function does forward exceptions if key_eq() throws, and never +// mutates __value or actually inserts into the map. +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__next_pointer +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi_prepare(size_t __cp_hash, value_type& __cp_val) { + size_type __bc = bucket_count(); + if (size() + 1 > __bc * max_load_factor() || __bc == 0) { + __rehash_multi(std::max( + 2 * __bc + !std::__is_hash_power2(__bc), size_type(std::ceil(float(size() + 1) / max_load_factor())))); + __bc = bucket_count(); + } + size_t __chash = std::__constrain_hash(__cp_hash, __bc); + __next_pointer __pn = __bucket_list_[__chash]; + if (__pn != nullptr) { + for (bool __found = false; + __pn->__next_ != nullptr && std::__constrain_hash(__pn->__next_->__hash(), __bc) == __chash; + __pn = __pn->__next_) { + // __found key_eq() action + // false false loop + // true true loop + // false true set __found to true + // true false break + if (__found != + (__pn->__next_->__hash() == __cp_hash && key_eq()(__pn->__next_->__upcast()->__get_value(), __cp_val))) { + if (!__found) + __found = true; + else + break; + } + } + } + return __pn; +} + +// Insert the node __cp into the container after __pn (which is the last node in +// the bucket that compares equal to __cp). Rehashing, and checking for +// uniqueness has already been performed (in __node_insert_multi_prepare), so +// all we need to do is update the bucket and size(). Assumes that __cp->__hash +// is up-to-date. +template +void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi_perform( + __node_pointer __cp, __next_pointer __pn) _NOEXCEPT { + size_type __bc = bucket_count(); + size_t __chash = std::__constrain_hash(__cp->__hash_, __bc); + if (__pn == nullptr) { + __pn = __p1_.first().__ptr(); + __cp->__next_ = __pn->__next_; + __pn->__next_ = __cp->__ptr(); + // fix up __bucket_list_ + __bucket_list_[__chash] = __pn; + if (__cp->__next_ != nullptr) + __bucket_list_[std::__constrain_hash(__cp->__next_->__hash(), __bc)] = __cp->__ptr(); + } else { + __cp->__next_ = __pn->__next_; + __pn->__next_ = __cp->__ptr(); + if (__cp->__next_ != nullptr) { + size_t __nhash = std::__constrain_hash(__cp->__next_->__hash(), __bc); + if (__nhash != __chash) + __bucket_list_[__nhash] = __cp->__ptr(); + } + } + ++size(); +} + +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(__node_pointer __cp) { + __cp->__hash_ = hash_function()(__cp->__get_value()); + __next_pointer __pn = __node_insert_multi_prepare(__cp->__hash(), __cp->__get_value()); + __node_insert_multi_perform(__cp, __pn); + + return iterator(__cp->__ptr()); +} + +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(const_iterator __p, __node_pointer __cp) { + if (__p != end() && key_eq()(*__p, __cp->__get_value())) { + __next_pointer __np = __p.__node_; + __cp->__hash_ = __np->__hash(); + size_type __bc = bucket_count(); + if (size() + 1 > __bc * max_load_factor() || __bc == 0) { + __rehash_multi(std::max( + 2 * __bc + !std::__is_hash_power2(__bc), size_type(std::ceil(float(size() + 1) / max_load_factor())))); + __bc = bucket_count(); + } + size_t __chash = std::__constrain_hash(__cp->__hash_, __bc); + __next_pointer __pp = __bucket_list_[__chash]; + while (__pp->__next_ != __np) + __pp = __pp->__next_; + __cp->__next_ = __np; + __pp->__next_ = static_cast<__next_pointer>(__cp); + ++size(); + return iterator(static_cast<__next_pointer>(__cp)); + } + return __node_insert_multi(__cp); +} + +template +template +pair::iterator, bool> +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_key_args(_Key const& __k, _Args&&... __args) { + size_t __hash = hash_function()(__k); + size_type __bc = bucket_count(); + bool __inserted = false; + __next_pointer __nd; + size_t __chash; + if (__bc != 0) { + __chash = std::__constrain_hash(__hash, __bc); + __nd = __bucket_list_[__chash]; + if (__nd != nullptr) { + for (__nd = __nd->__next_; + __nd != nullptr && (__nd->__hash() == __hash || std::__constrain_hash(__nd->__hash(), __bc) == __chash); + __nd = __nd->__next_) { + if ((__nd->__hash() == __hash) && key_eq()(__nd->__upcast()->__get_value(), __k)) + goto __done; + } + } + } + { + __node_holder __h = __construct_node_hash(__hash, std::forward<_Args>(__args)...); + if (size() + 1 > __bc * max_load_factor() || __bc == 0) { + __rehash_unique(std::max( + 2 * __bc + !std::__is_hash_power2(__bc), size_type(std::ceil(float(size() + 1) / max_load_factor())))); + __bc = bucket_count(); + __chash = std::__constrain_hash(__hash, __bc); + } + // insert_after __bucket_list_[__chash], or __first_node if bucket is null + __next_pointer __pn = __bucket_list_[__chash]; + if (__pn == nullptr) { + __pn = __p1_.first().__ptr(); + __h->__next_ = __pn->__next_; + __pn->__next_ = __h.get()->__ptr(); + // fix up __bucket_list_ + __bucket_list_[__chash] = __pn; + if (__h->__next_ != nullptr) + __bucket_list_[std::__constrain_hash(__h->__next_->__hash(), __bc)] = __h.get()->__ptr(); + } else { + __h->__next_ = __pn->__next_; + __pn->__next_ = static_cast<__next_pointer>(__h.get()); + } + __nd = static_cast<__next_pointer>(__h.release()); + // increment size + ++size(); + __inserted = true; + } +__done: + return pair(iterator(__nd), __inserted); +} + +template +template +pair::iterator, bool> +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_impl(_Args&&... __args) { + __node_holder __h = __construct_node(std::forward<_Args>(__args)...); + pair __r = __node_insert_unique(__h.get()); + if (__r.second) + __h.release(); + return __r; +} + +template +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_multi(_Args&&... __args) { + __node_holder __h = __construct_node(std::forward<_Args>(__args)...); + iterator __r = __node_insert_multi(__h.get()); + __h.release(); + return __r; +} + +template +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_hint_multi(const_iterator __p, _Args&&... __args) { + __node_holder __h = __construct_node(std::forward<_Args>(__args)...); + iterator __r = __node_insert_multi(__p, __h.get()); + __h.release(); + return __r; +} + +#if _LIBCPP_STD_VER >= 17 +template +template +_LIBCPP_HIDE_FROM_ABI _InsertReturnType +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_insert_unique(_NodeHandle&& __nh) { + if (__nh.empty()) + return _InsertReturnType{end(), false, _NodeHandle()}; + pair __result = __node_insert_unique(__nh.__ptr_); + if (__result.second) + __nh.__release_ptr(); + return _InsertReturnType{__result.first, __result.second, std::move(__nh)}; +} + +template +template +_LIBCPP_HIDE_FROM_ABI typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_insert_unique(const_iterator, _NodeHandle&& __nh) { + if (__nh.empty()) + return end(); + pair __result = __node_insert_unique(__nh.__ptr_); + if (__result.second) + __nh.__release_ptr(); + return __result.first; +} + +template +template +_LIBCPP_HIDE_FROM_ABI _NodeHandle +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_extract(key_type const& __key) { + iterator __i = find(__key); + if (__i == end()) + return _NodeHandle(); + return __node_handle_extract<_NodeHandle>(__i); +} + +template +template +_LIBCPP_HIDE_FROM_ABI _NodeHandle __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_extract(const_iterator __p) { + allocator_type __alloc(__node_alloc()); + return _NodeHandle(remove(__p).release(), __alloc); +} + +template +template +_LIBCPP_HIDE_FROM_ABI void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_merge_unique(_Table& __source) { + static_assert(is_same<__node, typename _Table::__node>::value, ""); + + for (typename _Table::iterator __it = __source.begin(); __it != __source.end();) { + __node_pointer __src_ptr = __it.__node_->__upcast(); + size_t __hash = hash_function()(__src_ptr->__get_value()); + __next_pointer __existing_node = __node_insert_unique_prepare(__hash, __src_ptr->__get_value()); + auto __prev_iter = __it++; + if (__existing_node == nullptr) { + (void)__source.remove(__prev_iter).release(); + __src_ptr->__hash_ = __hash; + __node_insert_unique_perform(__src_ptr); + } + } +} + +template +template +_LIBCPP_HIDE_FROM_ABI typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_insert_multi(_NodeHandle&& __nh) { + if (__nh.empty()) + return end(); + iterator __result = __node_insert_multi(__nh.__ptr_); + __nh.__release_ptr(); + return __result; +} + +template +template +_LIBCPP_HIDE_FROM_ABI typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_insert_multi(const_iterator __hint, _NodeHandle&& __nh) { + if (__nh.empty()) + return end(); + iterator __result = __node_insert_multi(__hint, __nh.__ptr_); + __nh.__release_ptr(); + return __result; +} + +template +template +_LIBCPP_HIDE_FROM_ABI void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_merge_multi(_Table& __source) { + static_assert(is_same::value, ""); + + for (typename _Table::iterator __it = __source.begin(); __it != __source.end();) { + __node_pointer __src_ptr = __it.__node_->__upcast(); + size_t __src_hash = hash_function()(__src_ptr->__get_value()); + __next_pointer __pn = __node_insert_multi_prepare(__src_hash, __src_ptr->__get_value()); + (void)__source.remove(__it++).release(); + __src_ptr->__hash_ = __src_hash; + __node_insert_multi_perform(__src_ptr, __pn); + } +} +#endif // _LIBCPP_STD_VER >= 17 + +template +template +void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__rehash(size_type __n) _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK { + if (__n == 1) + __n = 2; + else if (__n & (__n - 1)) + __n = std::__next_prime(__n); + size_type __bc = bucket_count(); + if (__n > __bc) + __do_rehash<_UniqueKeys>(__n); + else if (__n < __bc) { + __n = std::max( + __n, + std::__is_hash_power2(__bc) ? std::__next_hash_pow2(size_t(std::ceil(float(size()) / max_load_factor()))) + : std::__next_prime(size_t(std::ceil(float(size()) / max_load_factor())))); + if (__n < __bc) + __do_rehash<_UniqueKeys>(__n); + } +} + +template +template +void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__do_rehash(size_type __nbc) { + __pointer_allocator& __npa = __bucket_list_.get_deleter().__alloc(); + __bucket_list_.reset(__nbc > 0 ? __pointer_alloc_traits::allocate(__npa, __nbc) : nullptr); + __bucket_list_.get_deleter().size() = __nbc; + if (__nbc > 0) { + for (size_type __i = 0; __i < __nbc; ++__i) + __bucket_list_[__i] = nullptr; + __next_pointer __pp = __p1_.first().__ptr(); + __next_pointer __cp = __pp->__next_; + if (__cp != nullptr) { + size_type __chash = std::__constrain_hash(__cp->__hash(), __nbc); + __bucket_list_[__chash] = __pp; + size_type __phash = __chash; + for (__pp = __cp, void(), __cp = __cp->__next_; __cp != nullptr; __cp = __pp->__next_) { + __chash = std::__constrain_hash(__cp->__hash(), __nbc); + if (__chash == __phash) + __pp = __cp; + else { + if (__bucket_list_[__chash] == nullptr) { + __bucket_list_[__chash] = __pp; + __pp = __cp; + __phash = __chash; + } else { + __next_pointer __np = __cp; + if _LIBCPP_CONSTEXPR_SINCE_CXX17 (!_UniqueKeys) { + for (; __np->__next_ != nullptr && + key_eq()(__cp->__upcast()->__get_value(), __np->__next_->__upcast()->__get_value()); + __np = __np->__next_) + ; + } + __pp->__next_ = __np->__next_; + __np->__next_ = __bucket_list_[__chash]->__next_; + __bucket_list_[__chash]->__next_ = __cp; + } + } + } + } + } +} + +template +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k) { + size_t __hash = hash_function()(__k); + size_type __bc = bucket_count(); + if (__bc != 0) { + size_t __chash = std::__constrain_hash(__hash, __bc); + __next_pointer __nd = __bucket_list_[__chash]; + if (__nd != nullptr) { + for (__nd = __nd->__next_; + __nd != nullptr && (__nd->__hash() == __hash || std::__constrain_hash(__nd->__hash(), __bc) == __chash); + __nd = __nd->__next_) { + if ((__nd->__hash() == __hash) && key_eq()(__nd->__upcast()->__get_value(), __k)) + return iterator(__nd); + } + } + } + return end(); +} + +template +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k) const { + size_t __hash = hash_function()(__k); + size_type __bc = bucket_count(); + if (__bc != 0) { + size_t __chash = std::__constrain_hash(__hash, __bc); + __next_pointer __nd = __bucket_list_[__chash]; + if (__nd != nullptr) { + for (__nd = __nd->__next_; + __nd != nullptr && (__hash == __nd->__hash() || std::__constrain_hash(__nd->__hash(), __bc) == __chash); + __nd = __nd->__next_) { + if ((__nd->__hash() == __hash) && key_eq()(__nd->__upcast()->__get_value(), __k)) + return const_iterator(__nd); + } + } + } + return end(); +} + +template +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(_Args&&... __args) { + static_assert(!__is_hash_value_type<_Args...>::value, "Construct cannot be called with a hash value type"); + __node_allocator& __na = __node_alloc(); + __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na)); + + // Begin the lifetime of the node itself. Note that this doesn't begin the lifetime of the value + // held inside the node, since we need to use the allocator's construct() method for that. + // + // We don't use the allocator's construct() method to construct the node itself since the + // Cpp17FooInsertable named requirements don't require the allocator's construct() method + // to work on anything other than the value_type. + std::__construct_at(std::addressof(*__h), /* next = */ nullptr, /* hash = */ 0); + + // Now construct the value_type using the allocator's construct() method. + __node_traits::construct(__na, _NodeTypes::__get_ptr(__h->__get_value()), std::forward<_Args>(__args)...); + __h.get_deleter().__value_constructed = true; + + __h->__hash_ = hash_function()(__h->__get_value()); + return __h; +} + +template +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node_hash(size_t __hash, _First&& __f, _Rest&&... __rest) { + static_assert(!__is_hash_value_type<_First, _Rest...>::value, "Construct cannot be called with a hash value type"); + __node_allocator& __na = __node_alloc(); + __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na)); + std::__construct_at(std::addressof(*__h), /* next = */ nullptr, /* hash = */ __hash); + __node_traits::construct( + __na, _NodeTypes::__get_ptr(__h->__get_value()), std::forward<_First>(__f), std::forward<_Rest>(__rest)...); + __h.get_deleter().__value_constructed = true; + return __h; +} + +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __p) { + __next_pointer __np = __p.__node_; + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __p != end(), "unordered container::erase(iterator) called with a non-dereferenceable iterator"); + iterator __r(__np); + ++__r; + remove(__p); + return __r; +} + +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator +__hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __first, const_iterator __last) { + for (const_iterator __p = __first; __first != __last; __p = __first) { + ++__first; + erase(__p); + } + __next_pointer __np = __last.__node_; + return iterator(__np); +} + +template +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__erase_unique(const _Key& __k) { + iterator __i = find(__k); + if (__i == end()) + return 0; + erase(__i); + return 1; +} + +template +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__erase_multi(const _Key& __k) { + size_type __r = 0; + iterator __i = find(__k); + if (__i != end()) { + iterator __e = end(); + do { + erase(__i++); + ++__r; + } while (__i != __e && key_eq()(*__i, __k)); + } + return __r; +} + +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder +__hash_table<_Tp, _Hash, _Equal, _Alloc>::remove(const_iterator __p) _NOEXCEPT { + // current node + __next_pointer __cn = __p.__node_; + size_type __bc = bucket_count(); + size_t __chash = std::__constrain_hash(__cn->__hash(), __bc); + // find previous node + __next_pointer __pn = __bucket_list_[__chash]; + for (; __pn->__next_ != __cn; __pn = __pn->__next_) + ; + // Fix up __bucket_list_ + // if __pn is not in same bucket (before begin is not in same bucket) && + // if __cn->__next_ is not in same bucket (nullptr is not in same bucket) + if (__pn == __p1_.first().__ptr() || std::__constrain_hash(__pn->__hash(), __bc) != __chash) { + if (__cn->__next_ == nullptr || std::__constrain_hash(__cn->__next_->__hash(), __bc) != __chash) + __bucket_list_[__chash] = nullptr; + } + // if __cn->__next_ is not in same bucket (nullptr is in same bucket) + if (__cn->__next_ != nullptr) { + size_t __nhash = std::__constrain_hash(__cn->__next_->__hash(), __bc); + if (__nhash != __chash) + __bucket_list_[__nhash] = __pn; + } + // remove __cn + __pn->__next_ = __cn->__next_; + __cn->__next_ = nullptr; + --size(); + return __node_holder(__cn->__upcast(), _Dp(__node_alloc(), true)); +} + +template +template +inline typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__count_unique(const _Key& __k) const { + return static_cast(find(__k) != end()); +} + +template +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__count_multi(const _Key& __k) const { + size_type __r = 0; + const_iterator __i = find(__k); + if (__i != end()) { + const_iterator __e = end(); + do { + ++__i; + ++__r; + } while (__i != __e && key_eq()(*__i, __k)); + } + return __r; +} + +template +template +pair::iterator, + typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator> +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_unique(const _Key& __k) { + iterator __i = find(__k); + iterator __j = __i; + if (__i != end()) + ++__j; + return pair(__i, __j); +} + +template +template +pair::const_iterator, + typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator> +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_unique(const _Key& __k) const { + const_iterator __i = find(__k); + const_iterator __j = __i; + if (__i != end()) + ++__j; + return pair(__i, __j); +} + +template +template +pair::iterator, + typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator> +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_multi(const _Key& __k) { + iterator __i = find(__k); + iterator __j = __i; + if (__i != end()) { + iterator __e = end(); + do { + ++__j; + } while (__j != __e && key_eq()(*__j, __k)); + } + return pair(__i, __j); +} + +template +template +pair::const_iterator, + typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator> +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__equal_range_multi(const _Key& __k) const { + const_iterator __i = find(__k); + const_iterator __j = __i; + if (__i != end()) { + const_iterator __e = end(); + do { + ++__j; + } while (__j != __e && key_eq()(*__j, __k)); + } + return pair(__i, __j); +} + +template +void __hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u) +#if _LIBCPP_STD_VER <= 11 + _NOEXCEPT_(__is_nothrow_swappable_v&& __is_nothrow_swappable_v && + (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value || + __is_nothrow_swappable_v<__pointer_allocator>) && + (!__node_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__node_allocator>)) +#else + _NOEXCEPT_(__is_nothrow_swappable_v&& __is_nothrow_swappable_v) +#endif +{ + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR( + __node_traits::propagate_on_container_swap::value || this->__node_alloc() == __u.__node_alloc(), + "unordered container::swap: Either propagate_on_container_swap " + "must be true or the allocators must compare equal"); + { + __node_pointer_pointer __npp = __bucket_list_.release(); + __bucket_list_.reset(__u.__bucket_list_.release()); + __u.__bucket_list_.reset(__npp); + } + std::swap(__bucket_list_.get_deleter().size(), __u.__bucket_list_.get_deleter().size()); + std::__swap_allocator(__bucket_list_.get_deleter().__alloc(), __u.__bucket_list_.get_deleter().__alloc()); + std::__swap_allocator(__node_alloc(), __u.__node_alloc()); + std::swap(__p1_.first().__next_, __u.__p1_.first().__next_); + __p2_.swap(__u.__p2_); + __p3_.swap(__u.__p3_); + if (size() > 0) + __bucket_list_[std::__constrain_hash(__p1_.first().__next_->__hash(), bucket_count())] = __p1_.first().__ptr(); + if (__u.size() > 0) + __u.__bucket_list_[std::__constrain_hash(__u.__p1_.first().__next_->__hash(), __u.bucket_count())] = + __u.__p1_.first().__ptr(); +} + +template +typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::size_type +__hash_table<_Tp, _Hash, _Equal, _Alloc>::bucket_size(size_type __n) const { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __n < bucket_count(), "unordered container::bucket_size(n) called with n >= bucket_count()"); + __next_pointer __np = __bucket_list_[__n]; + size_type __bc = bucket_count(); + size_type __r = 0; + if (__np != nullptr) { + for (__np = __np->__next_; __np != nullptr && std::__constrain_hash(__np->__hash(), __bc) == __n; + __np = __np->__next_, (void)++__r) + ; + } + return __r; +} + +template +inline _LIBCPP_HIDE_FROM_ABI void +swap(__hash_table<_Tp, _Hash, _Equal, _Alloc>& __x, __hash_table<_Tp, _Hash, _Equal, _Alloc>& __y) + _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { + __x.swap(__y); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___HASH_TABLE diff --git a/libcxx/include/__cxx03/__ios/fpos.h b/libcxx/include/__cxx03/__ios/fpos.h new file mode 100644 index 0000000000000000000000000000000000000000..1af1e23ee50da1a3eb4ae7d7f57471fc49d6abb9 --- /dev/null +++ b/libcxx/include/__cxx03/__ios/fpos.h @@ -0,0 +1,76 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___IOS_FPOS_H +#define _LIBCPP___IOS_FPOS_H + +#include <__config> +#include <__fwd/ios.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class _LIBCPP_TEMPLATE_VIS fpos { +private: + _StateT __st_; + streamoff __off_; + +public: + _LIBCPP_HIDE_FROM_ABI fpos(streamoff __off = streamoff()) : __st_(), __off_(__off) {} + + _LIBCPP_HIDE_FROM_ABI operator streamoff() const { return __off_; } + + _LIBCPP_HIDE_FROM_ABI _StateT state() const { return __st_; } + _LIBCPP_HIDE_FROM_ABI void state(_StateT __st) { __st_ = __st; } + + _LIBCPP_HIDE_FROM_ABI fpos& operator+=(streamoff __off) { + __off_ += __off; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI fpos operator+(streamoff __off) const { + fpos __t(*this); + __t += __off; + return __t; + } + + _LIBCPP_HIDE_FROM_ABI fpos& operator-=(streamoff __off) { + __off_ -= __off; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI fpos operator-(streamoff __off) const { + fpos __t(*this); + __t -= __off; + return __t; + } +}; + +template +inline _LIBCPP_HIDE_FROM_ABI streamoff operator-(const fpos<_StateT>& __x, const fpos<_StateT>& __y) { + return streamoff(__x) - streamoff(__y); +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool operator==(const fpos<_StateT>& __x, const fpos<_StateT>& __y) { + return streamoff(__x) == streamoff(__y); +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const fpos<_StateT>& __x, const fpos<_StateT>& __y) { + return streamoff(__x) != streamoff(__y); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___IOS_FPOS_H diff --git a/libcxx/include/__cxx03/__iterator/access.h b/libcxx/include/__cxx03/__iterator/access.h new file mode 100644 index 0000000000000000000000000000000000000000..acc4f60bf697eac924b018469f60d6e51b69aaf0 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/access.h @@ -0,0 +1,95 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_ACCESS_H +#define _LIBCPP___ITERATOR_ACCESS_H + +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp* begin(_Tp (&__array)[_Np]) _NOEXCEPT { + return __array; +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp* end(_Tp (&__array)[_Np]) _NOEXCEPT { + return __array + _Np; +} + +#if !defined(_LIBCPP_CXX03_LANG) + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto begin(_Cp& __c) -> decltype(__c.begin()) { + return __c.begin(); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto begin(const _Cp& __c) -> decltype(__c.begin()) { + return __c.begin(); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto end(_Cp& __c) -> decltype(__c.end()) { + return __c.end(); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto end(const _Cp& __c) -> decltype(__c.end()) { + return __c.end(); +} + +# if _LIBCPP_STD_VER >= 14 + +template +_LIBCPP_HIDE_FROM_ABI constexpr auto +cbegin(const _Cp& __c) noexcept(noexcept(std::begin(__c))) -> decltype(std::begin(__c)) { + return std::begin(__c); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr auto cend(const _Cp& __c) noexcept(noexcept(std::end(__c))) -> decltype(std::end(__c)) { + return std::end(__c); +} + +# endif + +#else // defined(_LIBCPP_CXX03_LANG) + +template +_LIBCPP_HIDE_FROM_ABI typename _Cp::iterator begin(_Cp& __c) { + return __c.begin(); +} + +template +_LIBCPP_HIDE_FROM_ABI typename _Cp::const_iterator begin(const _Cp& __c) { + return __c.begin(); +} + +template +_LIBCPP_HIDE_FROM_ABI typename _Cp::iterator end(_Cp& __c) { + return __c.end(); +} + +template +_LIBCPP_HIDE_FROM_ABI typename _Cp::const_iterator end(const _Cp& __c) { + return __c.end(); +} + +#endif // !defined(_LIBCPP_CXX03_LANG) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_ACCESS_H diff --git a/libcxx/include/__cxx03/__iterator/advance.h b/libcxx/include/__cxx03/__iterator/advance.h new file mode 100644 index 0000000000000000000000000000000000000000..296db1aaab6526677fb6c1de2f2e35364b5eb972 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/advance.h @@ -0,0 +1,205 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_ADVANCE_H +#define _LIBCPP___ITERATOR_ADVANCE_H + +#include <__assert> +#include <__concepts/assignable.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_integral.h> +#include <__utility/convert_to_integral.h> +#include <__utility/declval.h> +#include <__utility/move.h> +#include <__utility/unreachable.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void +__advance(_InputIter& __i, typename iterator_traits<_InputIter>::difference_type __n, input_iterator_tag) { + for (; __n > 0; --__n) + ++__i; +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void +__advance(_BiDirIter& __i, typename iterator_traits<_BiDirIter>::difference_type __n, bidirectional_iterator_tag) { + if (__n >= 0) + for (; __n > 0; --__n) + ++__i; + else + for (; __n < 0; ++__n) + --__i; +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void +__advance(_RandIter& __i, typename iterator_traits<_RandIter>::difference_type __n, random_access_iterator_tag) { + __i += __n; +} + +template < class _InputIter, + class _Distance, + class _IntegralDistance = decltype(std::__convert_to_integral(std::declval<_Distance>())), + __enable_if_t::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void advance(_InputIter& __i, _Distance __orig_n) { + typedef typename iterator_traits<_InputIter>::difference_type _Difference; + _Difference __n = static_cast<_Difference>(std::__convert_to_integral(__orig_n)); + // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation. + _LIBCPP_ASSERT_PEDANTIC(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value, + "Attempt to advance(it, n) with negative n on a non-bidirectional iterator"); + std::__advance(__i, __n, typename iterator_traits<_InputIter>::iterator_category()); +} + +#if _LIBCPP_STD_VER >= 20 + +// [range.iter.op.advance] + +namespace ranges { +namespace __advance { + +struct __fn { +private: + template + _LIBCPP_HIDE_FROM_ABI static constexpr void __advance_forward(_Ip& __i, iter_difference_t<_Ip> __n) { + while (__n > 0) { + --__n; + ++__i; + } + } + + template + _LIBCPP_HIDE_FROM_ABI static constexpr void __advance_backward(_Ip& __i, iter_difference_t<_Ip> __n) { + while (__n < 0) { + ++__n; + --__i; + } + } + +public: + // Preconditions: If `I` does not model `bidirectional_iterator`, `n` is not negative. + template + _LIBCPP_HIDE_FROM_ABI constexpr void operator()(_Ip& __i, iter_difference_t<_Ip> __n) const { + // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation. + _LIBCPP_ASSERT_PEDANTIC( + __n >= 0 || bidirectional_iterator<_Ip>, "If `n < 0`, then `bidirectional_iterator` must be true."); + + // If `I` models `random_access_iterator`, equivalent to `i += n`. + if constexpr (random_access_iterator<_Ip>) { + __i += __n; + return; + } else if constexpr (bidirectional_iterator<_Ip>) { + // Otherwise, if `n` is non-negative, increments `i` by `n`. + __advance_forward(__i, __n); + // Otherwise, decrements `i` by `-n`. + __advance_backward(__i, __n); + return; + } else { + // Otherwise, if `n` is non-negative, increments `i` by `n`. + __advance_forward(__i, __n); + return; + } + } + + // Preconditions: Either `assignable_from || sized_sentinel_for` is modeled, or [i, bound_sentinel) + // denotes a range. + template _Sp> + _LIBCPP_HIDE_FROM_ABI constexpr void operator()(_Ip& __i, _Sp __bound_sentinel) const { + // If `I` and `S` model `assignable_from`, equivalent to `i = std::move(bound_sentinel)`. + if constexpr (assignable_from<_Ip&, _Sp>) { + __i = std::move(__bound_sentinel); + } + // Otherwise, if `S` and `I` model `sized_sentinel_for`, equivalent to `ranges::advance(i, bound_sentinel - + // i)`. + else if constexpr (sized_sentinel_for<_Sp, _Ip>) { + (*this)(__i, __bound_sentinel - __i); + } + // Otherwise, while `bool(i != bound_sentinel)` is true, increments `i`. + else { + while (__i != __bound_sentinel) { + ++__i; + } + } + } + + // Preconditions: + // * If `n > 0`, [i, bound_sentinel) denotes a range. + // * If `n == 0`, [i, bound_sentinel) or [bound_sentinel, i) denotes a range. + // * If `n < 0`, [bound_sentinel, i) denotes a range, `I` models `bidirectional_iterator`, and `I` and `S` model + // `same_as`. + // Returns: `n - M`, where `M` is the difference between the ending and starting position. + template _Sp> + _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Ip> + operator()(_Ip& __i, iter_difference_t<_Ip> __n, _Sp __bound_sentinel) const { + // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation. + _LIBCPP_ASSERT_PEDANTIC((__n >= 0) || (bidirectional_iterator<_Ip> && same_as<_Ip, _Sp>), + "If `n < 0`, then `bidirectional_iterator && same_as` must be true."); + // If `S` and `I` model `sized_sentinel_for`: + if constexpr (sized_sentinel_for<_Sp, _Ip>) { + // If |n| >= |bound_sentinel - i|, equivalent to `ranges::advance(i, bound_sentinel)`. + // __magnitude_geq(a, b) returns |a| >= |b|, assuming they have the same sign. + auto __magnitude_geq = [](auto __a, auto __b) { return __a == 0 ? __b == 0 : __a > 0 ? __a >= __b : __a <= __b; }; + if (const auto __m = __bound_sentinel - __i; __magnitude_geq(__n, __m)) { + (*this)(__i, __bound_sentinel); + return __n - __m; + } + + // Otherwise, equivalent to `ranges::advance(i, n)`. + (*this)(__i, __n); + return 0; + } else { + // Otherwise, if `n` is non-negative, while `bool(i != bound_sentinel)` is true, increments `i` but at + // most `n` times. + while (__n > 0 && __i != __bound_sentinel) { + ++__i; + --__n; + } + + // Otherwise, while `bool(i != bound_sentinel)` is true, decrements `i` but at most `-n` times. + if constexpr (bidirectional_iterator<_Ip> && same_as<_Ip, _Sp>) { + while (__n < 0 && __i != __bound_sentinel) { + --__i; + ++__n; + } + } + return __n; + } + + __libcpp_unreachable(); + } +}; + +} // namespace __advance + +inline namespace __cpo { +inline constexpr auto advance = __advance::__fn{}; +} // namespace __cpo +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_ADVANCE_H diff --git a/libcxx/include/__cxx03/__iterator/aliasing_iterator.h b/libcxx/include/__cxx03/__iterator/aliasing_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..94ba577078b5e8c9ca7c1ffb304f0279896ea055 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/aliasing_iterator.h @@ -0,0 +1,127 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_ALIASING_ITERATOR_H +#define _LIBCPP___ITERATOR_ALIASING_ITERATOR_H + +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__memory/pointer_traits.h> +#include <__type_traits/is_trivial.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +// This iterator wrapper is used to type-pun an iterator to return a different type. This is done without UB by not +// actually punning the type, but instead inspecting the object representation of the base type and copying that into +// an instance of the alias type. For that reason the alias type has to be trivial. The alias is returned as a prvalue +// when derferencing the iterator, since it is temporary storage. This wrapper is used to vectorize some algorithms. + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __aliasing_iterator_wrapper { + class __iterator { + _BaseIter __base_ = nullptr; + + using __iter_traits = iterator_traits<_BaseIter>; + using __base_value_type = typename __iter_traits::value_type; + + static_assert(__has_random_access_iterator_category<_BaseIter>::value, + "The base iterator has to be a random access iterator!"); + + public: + using iterator_category = random_access_iterator_tag; + using value_type = _Alias; + using difference_type = ptrdiff_t; + using reference = value_type&; + using pointer = value_type*; + + static_assert(is_trivial::value); + static_assert(sizeof(__base_value_type) == sizeof(value_type)); + + _LIBCPP_HIDE_FROM_ABI __iterator() = default; + _LIBCPP_HIDE_FROM_ABI __iterator(_BaseIter __base) _NOEXCEPT : __base_(__base) {} + + _LIBCPP_HIDE_FROM_ABI __iterator& operator++() _NOEXCEPT { + ++__base_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI __iterator operator++(int) _NOEXCEPT { + __iterator __tmp(*this); + ++__base_; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI __iterator& operator--() _NOEXCEPT { + --__base_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI __iterator operator--(int) _NOEXCEPT { + __iterator __tmp(*this); + --__base_; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI friend __iterator operator+(__iterator __iter, difference_type __n) _NOEXCEPT { + return __iterator(__iter.__base_ + __n); + } + + _LIBCPP_HIDE_FROM_ABI friend __iterator operator+(difference_type __n, __iterator __iter) _NOEXCEPT { + return __iterator(__n + __iter.__base_); + } + + _LIBCPP_HIDE_FROM_ABI __iterator& operator+=(difference_type __n) _NOEXCEPT { + __base_ += __n; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI friend __iterator operator-(__iterator __iter, difference_type __n) _NOEXCEPT { + return __iterator(__iter.__base_ - __n); + } + + _LIBCPP_HIDE_FROM_ABI friend difference_type operator-(__iterator __lhs, __iterator __rhs) _NOEXCEPT { + return __lhs.__base_ - __rhs.__base_; + } + + _LIBCPP_HIDE_FROM_ABI __iterator& operator-=(difference_type __n) _NOEXCEPT { + __base_ -= __n; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI _BaseIter __base() const _NOEXCEPT { return __base_; } + + _LIBCPP_HIDE_FROM_ABI _Alias operator*() const _NOEXCEPT { + _Alias __val; + __builtin_memcpy(&__val, std::__to_address(__base_), sizeof(value_type)); + return __val; + } + + _LIBCPP_HIDE_FROM_ABI value_type operator[](difference_type __n) const _NOEXCEPT { return *(*this + __n); } + + _LIBCPP_HIDE_FROM_ABI friend bool operator==(const __iterator& __lhs, const __iterator& __rhs) _NOEXCEPT { + return __lhs.__base_ == __rhs.__base_; + } + + _LIBCPP_HIDE_FROM_ABI friend bool operator!=(const __iterator& __lhs, const __iterator& __rhs) _NOEXCEPT { + return __lhs.__base_ != __rhs.__base_; + } + }; +}; + +// This is required to avoid ADL instantiations on _BaseT +template +using __aliasing_iterator = typename __aliasing_iterator_wrapper<_BaseT, _Alias>::__iterator; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_ALIASING_ITERATOR_H diff --git a/libcxx/include/__cxx03/__iterator/back_insert_iterator.h b/libcxx/include/__cxx03/__iterator/back_insert_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..6d3dd4b12966fe7547fcbfd73173b60c6569a20b --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/back_insert_iterator.h @@ -0,0 +1,85 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_BACK_INSERT_ITERATOR_H +#define _LIBCPP___ITERATOR_BACK_INSERT_ITERATOR_H + +#include <__config> +#include <__iterator/iterator.h> +#include <__iterator/iterator_traits.h> +#include <__memory/addressof.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +template +class _LIBCPP_TEMPLATE_VIS back_insert_iterator +#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) + : public iterator +#endif +{ + _LIBCPP_SUPPRESS_DEPRECATED_POP + +protected: + _Container* container; + +public: + typedef output_iterator_tag iterator_category; + typedef void value_type; +#if _LIBCPP_STD_VER >= 20 + typedef ptrdiff_t difference_type; +#else + typedef void difference_type; +#endif + typedef void pointer; + typedef void reference; + typedef _Container container_type; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit back_insert_iterator(_Container& __x) + : container(std::addressof(__x)) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 back_insert_iterator& + operator=(const typename _Container::value_type& __value) { + container->push_back(__value); + return *this; + } +#ifndef _LIBCPP_CXX03_LANG + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 back_insert_iterator& + operator=(typename _Container::value_type&& __value) { + container->push_back(std::move(__value)); + return *this; + } +#endif // _LIBCPP_CXX03_LANG + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 back_insert_iterator& operator*() { return *this; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 back_insert_iterator& operator++() { return *this; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 back_insert_iterator operator++(int) { return *this; } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Container* __get_container() const { return container; } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(back_insert_iterator); + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 back_insert_iterator<_Container> +back_inserter(_Container& __x) { + return back_insert_iterator<_Container>(__x); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_BACK_INSERT_ITERATOR_H diff --git a/libcxx/include/__cxx03/__iterator/bounded_iter.h b/libcxx/include/__cxx03/__iterator/bounded_iter.h new file mode 100644 index 0000000000000000000000000000000000000000..8a81c9ffbfc3fccc93698985890e1f54cf545d0f --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/bounded_iter.h @@ -0,0 +1,283 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_BOUNDED_ITER_H +#define _LIBCPP___ITERATOR_BOUNDED_ITER_H + +#include <__assert> +#include <__compare/ordering.h> +#include <__compare/three_way_comparable.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__memory/pointer_traits.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_convertible.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// Iterator wrapper that carries the valid range it is allowed to access. +// +// This is a simple iterator wrapper for contiguous iterators that points +// within a [begin, end] range and carries these bounds with it. The iterator +// ensures that it is pointing within [begin, end) range when it is +// dereferenced. It also ensures that it is never iterated outside of +// [begin, end]. This is important for two reasons: +// +// 1. It allows `operator*` and `operator++` bounds checks to be `iter != end`. +// This is both less for the optimizer to prove, and aligns with how callers +// typically use iterators. +// +// 2. Advancing an iterator out of bounds is undefined behavior (see the table +// in [input.iterators]). In particular, when the underlying iterator is a +// pointer, it is undefined at the language level (see [expr.add]). If +// bounded iterators exhibited this undefined behavior, we risk compiler +// optimizations deleting non-redundant bounds checks. +template ::value > > +struct __bounded_iter { + using value_type = typename iterator_traits<_Iterator>::value_type; + using difference_type = typename iterator_traits<_Iterator>::difference_type; + using pointer = typename iterator_traits<_Iterator>::pointer; + using reference = typename iterator_traits<_Iterator>::reference; + using iterator_category = typename iterator_traits<_Iterator>::iterator_category; +#if _LIBCPP_STD_VER >= 20 + using iterator_concept = contiguous_iterator_tag; +#endif + + // Create a singular iterator. + // + // Such an iterator points past the end of an empty span, so it is not dereferenceable. + // Observing operations like comparison and assignment are valid. + _LIBCPP_HIDE_FROM_ABI __bounded_iter() = default; + + _LIBCPP_HIDE_FROM_ABI __bounded_iter(__bounded_iter const&) = default; + _LIBCPP_HIDE_FROM_ABI __bounded_iter(__bounded_iter&&) = default; + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __bounded_iter(__bounded_iter<_OtherIterator> const& __other) _NOEXCEPT + : __current_(__other.__current_), + __begin_(__other.__begin_), + __end_(__other.__end_) {} + + // Assign a bounded iterator to another one, rebinding the bounds of the iterator as well. + _LIBCPP_HIDE_FROM_ABI __bounded_iter& operator=(__bounded_iter const&) = default; + _LIBCPP_HIDE_FROM_ABI __bounded_iter& operator=(__bounded_iter&&) = default; + +private: + // Create an iterator wrapping the given iterator, and whose bounds are described + // by the provided [begin, end] range. + // + // The constructor does not check whether the resulting iterator is within its bounds. It is a + // responsibility of the container to ensure that the given bounds are valid. + // + // Since it is non-standard for iterators to have this constructor, __bounded_iter must + // be created via `std::__make_bounded_iter`. + _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __bounded_iter(_Iterator __current, _Iterator __begin, _Iterator __end) + : __current_(__current), __begin_(__begin), __end_(__end) { + _LIBCPP_ASSERT_INTERNAL( + __begin <= __current, "__bounded_iter(current, begin, end): current and begin are inconsistent"); + _LIBCPP_ASSERT_INTERNAL( + __current <= __end, "__bounded_iter(current, begin, end): current and end are inconsistent"); + } + + template + friend _LIBCPP_CONSTEXPR __bounded_iter<_It> __make_bounded_iter(_It, _It, _It); + +public: + // Dereference and indexing operations. + // + // These operations check that the iterator is dereferenceable. Since the class invariant is + // that the iterator is always within `[begin, end]`, we only need to check it's not pointing to + // `end`. This is easier for the optimizer because it aligns with the `iter != container.end()` + // checks that typical callers already use (see + // https://github.com/llvm/llvm-project/issues/78829). + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator*() const _NOEXCEPT { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __current_ != __end_, "__bounded_iter::operator*: Attempt to dereference an iterator at the end"); + return *__current_; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pointer operator->() const _NOEXCEPT { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __current_ != __end_, "__bounded_iter::operator->: Attempt to dereference an iterator at the end"); + return std::__to_address(__current_); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator[](difference_type __n) const _NOEXCEPT { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __n >= __begin_ - __current_, "__bounded_iter::operator[]: Attempt to index an iterator past the start"); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __n < __end_ - __current_, "__bounded_iter::operator[]: Attempt to index an iterator at or past the end"); + return __current_[__n]; + } + + // Arithmetic operations. + // + // These operations check that the iterator remains within `[begin, end]`. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter& operator++() _NOEXCEPT { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __current_ != __end_, "__bounded_iter::operator++: Attempt to advance an iterator past the end"); + ++__current_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter operator++(int) _NOEXCEPT { + __bounded_iter __tmp(*this); + ++*this; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter& operator--() _NOEXCEPT { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __current_ != __begin_, "__bounded_iter::operator--: Attempt to rewind an iterator past the start"); + --__current_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter operator--(int) _NOEXCEPT { + __bounded_iter __tmp(*this); + --*this; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter& operator+=(difference_type __n) _NOEXCEPT { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __n >= __begin_ - __current_, "__bounded_iter::operator+=: Attempt to rewind an iterator past the start"); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __n <= __end_ - __current_, "__bounded_iter::operator+=: Attempt to advance an iterator past the end"); + __current_ += __n; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __bounded_iter + operator+(__bounded_iter const& __self, difference_type __n) _NOEXCEPT { + __bounded_iter __tmp(__self); + __tmp += __n; + return __tmp; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __bounded_iter + operator+(difference_type __n, __bounded_iter const& __self) _NOEXCEPT { + __bounded_iter __tmp(__self); + __tmp += __n; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter& operator-=(difference_type __n) _NOEXCEPT { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __n <= __current_ - __begin_, "__bounded_iter::operator-=: Attempt to rewind an iterator past the start"); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __n >= __current_ - __end_, "__bounded_iter::operator-=: Attempt to advance an iterator past the end"); + __current_ -= __n; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 friend __bounded_iter + operator-(__bounded_iter const& __self, difference_type __n) _NOEXCEPT { + __bounded_iter __tmp(__self); + __tmp -= __n; + return __tmp; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 friend difference_type + operator-(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { + return __x.__current_ - __y.__current_; + } + + // Comparison operations. + // + // These operations do not check whether the iterators are within their bounds. + // The valid range for each iterator is also not considered as part of the comparison, + // i.e. two iterators pointing to the same location will be considered equal even + // if they have different validity ranges. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool + operator==(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { + return __x.__current_ == __y.__current_; + } + +#if _LIBCPP_STD_VER <= 17 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool + operator!=(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { + return __x.__current_ != __y.__current_; + } +#endif + + // TODO(mordante) disable these overloads in the LLVM 20 release. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool + operator<(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { + return __x.__current_ < __y.__current_; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool + operator>(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { + return __x.__current_ > __y.__current_; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool + operator<=(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { + return __x.__current_ <= __y.__current_; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool + operator>=(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { + return __x.__current_ >= __y.__current_; + } + +#if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI constexpr friend strong_ordering + operator<=>(__bounded_iter const& __x, __bounded_iter const& __y) noexcept { + if constexpr (three_way_comparable<_Iterator, strong_ordering>) { + return __x.__current_ <=> __y.__current_; + } else { + if (__x.__current_ < __y.__current_) + return strong_ordering::less; + + if (__x.__current_ == __y.__current_) + return strong_ordering::equal; + + return strong_ordering::greater; + } + } +#endif // _LIBCPP_STD_VER >= 20 + +private: + template + friend struct pointer_traits; + template + friend struct __bounded_iter; + _Iterator __current_; // current iterator + _Iterator __begin_, __end_; // valid range represented as [begin, end] +}; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __bounded_iter<_It> __make_bounded_iter(_It __it, _It __begin, _It __end) { + return __bounded_iter<_It>(std::move(__it), std::move(__begin), std::move(__end)); +} + +#if _LIBCPP_STD_VER <= 17 +template +struct __libcpp_is_contiguous_iterator<__bounded_iter<_Iterator> > : true_type {}; +#endif + +template +struct pointer_traits<__bounded_iter<_Iterator> > { + using pointer = __bounded_iter<_Iterator>; + using element_type = typename pointer_traits<_Iterator>::element_type; + using difference_type = typename pointer_traits<_Iterator>::difference_type; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static element_type* to_address(pointer __it) _NOEXCEPT { + return std::__to_address(__it.__current_); + } +}; + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_BOUNDED_ITER_H diff --git a/libcxx/include/__cxx03/__iterator/common_iterator.h b/libcxx/include/__cxx03/__iterator/common_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..199de2cc7337b0097a1658907223030f65c5473f --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/common_iterator.h @@ -0,0 +1,299 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_COMMON_ITERATOR_H +#define _LIBCPP___ITERATOR_COMMON_ITERATOR_H + +#include <__assert> +#include <__concepts/assignable.h> +#include <__concepts/constructible.h> +#include <__concepts/convertible_to.h> +#include <__concepts/copyable.h> +#include <__concepts/derived_from.h> +#include <__concepts/equality_comparable.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iter_move.h> +#include <__iterator/iter_swap.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/readable_traits.h> +#include <__memory/addressof.h> +#include <__type_traits/is_pointer.h> +#include <__utility/declval.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +concept __can_use_postfix_proxy = + constructible_from, iter_reference_t<_Iter>> && move_constructible>; + +template _Sent> + requires(!same_as<_Iter, _Sent> && copyable<_Iter>) +class common_iterator { + struct __proxy { + _LIBCPP_HIDE_FROM_ABI constexpr const iter_value_t<_Iter>* operator->() const noexcept { + return std::addressof(__value_); + } + iter_value_t<_Iter> __value_; + }; + + struct __postfix_proxy { + _LIBCPP_HIDE_FROM_ABI constexpr const iter_value_t<_Iter>& operator*() const noexcept { return __value_; } + iter_value_t<_Iter> __value_; + }; + + variant<_Iter, _Sent> __hold_; + template _OtherSent> + requires(!same_as<_OtherIter, _OtherSent> && copyable<_OtherIter>) + friend class common_iterator; + +public: + _LIBCPP_HIDE_FROM_ABI common_iterator() + requires default_initializable<_Iter> + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr common_iterator(_Iter __i) : __hold_(in_place_type<_Iter>, std::move(__i)) {} + _LIBCPP_HIDE_FROM_ABI constexpr common_iterator(_Sent __s) : __hold_(in_place_type<_Sent>, std::move(__s)) {} + + template + requires convertible_to && convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr common_iterator(const common_iterator<_I2, _S2>& __other) + : __hold_([&]() -> variant<_Iter, _Sent> { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !__other.__hold_.valueless_by_exception(), "Attempted to construct from a valueless common_iterator"); + if (__other.__hold_.index() == 0) + return variant<_Iter, _Sent>{in_place_index<0>, std::__unchecked_get<0>(__other.__hold_)}; + return variant<_Iter, _Sent>{in_place_index<1>, std::__unchecked_get<1>(__other.__hold_)}; + }()) {} + + template + requires convertible_to && convertible_to && + assignable_from<_Iter&, const _I2&> && assignable_from<_Sent&, const _S2&> + _LIBCPP_HIDE_FROM_ABI common_iterator& operator=(const common_iterator<_I2, _S2>& __other) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !__other.__hold_.valueless_by_exception(), "Attempted to assign from a valueless common_iterator"); + + auto __idx = __hold_.index(); + auto __other_idx = __other.__hold_.index(); + + // If they're the same index, just assign. + if (__idx == 0 && __other_idx == 0) + std::__unchecked_get<0>(__hold_) = std::__unchecked_get<0>(__other.__hold_); + else if (__idx == 1 && __other_idx == 1) + std::__unchecked_get<1>(__hold_) = std::__unchecked_get<1>(__other.__hold_); + + // Otherwise replace with the oposite element. + else if (__other_idx == 1) + __hold_.template emplace<1>(std::__unchecked_get<1>(__other.__hold_)); + else if (__other_idx == 0) + __hold_.template emplace<0>(std::__unchecked_get<0>(__other.__hold_)); + + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + std::holds_alternative<_Iter>(__hold_), "Attempted to dereference a non-dereferenceable common_iterator"); + return *std::__unchecked_get<_Iter>(__hold_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const + requires __dereferenceable + { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + std::holds_alternative<_Iter>(__hold_), "Attempted to dereference a non-dereferenceable common_iterator"); + return *std::__unchecked_get<_Iter>(__hold_); + } + + template + _LIBCPP_HIDE_FROM_ABI auto operator->() const + requires indirectly_readable && (requires(const _I2& __i) { + __i.operator->(); + } || is_reference_v> || constructible_from, iter_reference_t<_I2>>) + { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + std::holds_alternative<_Iter>(__hold_), "Attempted to dereference a non-dereferenceable common_iterator"); + if constexpr (is_pointer_v<_Iter> || requires(const _Iter& __i) { __i.operator->(); }) { + return std::__unchecked_get<_Iter>(__hold_); + } else if constexpr (is_reference_v>) { + auto&& __tmp = *std::__unchecked_get<_Iter>(__hold_); + return std::addressof(__tmp); + } else { + return __proxy{*std::__unchecked_get<_Iter>(__hold_)}; + } + } + + _LIBCPP_HIDE_FROM_ABI common_iterator& operator++() { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + std::holds_alternative<_Iter>(__hold_), "Attempted to increment a non-dereferenceable common_iterator"); + ++std::__unchecked_get<_Iter>(__hold_); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI decltype(auto) operator++(int) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + std::holds_alternative<_Iter>(__hold_), "Attempted to increment a non-dereferenceable common_iterator"); + if constexpr (forward_iterator<_Iter>) { + auto __tmp = *this; + ++*this; + return __tmp; + } else if constexpr (requires(_Iter& __i) { + { *__i++ } -> __can_reference; + } || !__can_use_postfix_proxy<_Iter>) { + return std::__unchecked_get<_Iter>(__hold_)++; + } else { + auto __p = __postfix_proxy{**this}; + ++*this; + return __p; + } + } + + template _S2> + requires sentinel_for<_Sent, _I2> + _LIBCPP_HIDE_FROM_ABI friend constexpr bool + operator==(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !__x.__hold_.valueless_by_exception(), "Attempted to compare a valueless common_iterator"); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !__y.__hold_.valueless_by_exception(), "Attempted to compare a valueless common_iterator"); + + auto __x_index = __x.__hold_.index(); + auto __y_index = __y.__hold_.index(); + + if (__x_index == __y_index) + return true; + + if (__x_index == 0) + return std::__unchecked_get<_Iter>(__x.__hold_) == std::__unchecked_get<_S2>(__y.__hold_); + + return std::__unchecked_get<_Sent>(__x.__hold_) == std::__unchecked_get<_I2>(__y.__hold_); + } + + template _S2> + requires sentinel_for<_Sent, _I2> && equality_comparable_with<_Iter, _I2> + _LIBCPP_HIDE_FROM_ABI friend constexpr bool + operator==(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !__x.__hold_.valueless_by_exception(), "Attempted to compare a valueless common_iterator"); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !__y.__hold_.valueless_by_exception(), "Attempted to compare a valueless common_iterator"); + + auto __x_index = __x.__hold_.index(); + auto __y_index = __y.__hold_.index(); + + if (__x_index == 1 && __y_index == 1) + return true; + + if (__x_index == 0 && __y_index == 0) + return std::__unchecked_get<_Iter>(__x.__hold_) == std::__unchecked_get<_I2>(__y.__hold_); + + if (__x_index == 0) + return std::__unchecked_get<_Iter>(__x.__hold_) == std::__unchecked_get<_S2>(__y.__hold_); + + return std::__unchecked_get<_Sent>(__x.__hold_) == std::__unchecked_get<_I2>(__y.__hold_); + } + + template _I2, sized_sentinel_for<_Iter> _S2> + requires sized_sentinel_for<_Sent, _I2> + _LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_I2> + operator-(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !__x.__hold_.valueless_by_exception(), "Attempted to subtract from a valueless common_iterator"); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + !__y.__hold_.valueless_by_exception(), "Attempted to subtract a valueless common_iterator"); + + auto __x_index = __x.__hold_.index(); + auto __y_index = __y.__hold_.index(); + + if (__x_index == 1 && __y_index == 1) + return 0; + + if (__x_index == 0 && __y_index == 0) + return std::__unchecked_get<_Iter>(__x.__hold_) - std::__unchecked_get<_I2>(__y.__hold_); + + if (__x_index == 0) + return std::__unchecked_get<_Iter>(__x.__hold_) - std::__unchecked_get<_S2>(__y.__hold_); + + return std::__unchecked_get<_Sent>(__x.__hold_) - std::__unchecked_get<_I2>(__y.__hold_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr iter_rvalue_reference_t<_Iter> + iter_move(const common_iterator& __i) noexcept(noexcept(ranges::iter_move(std::declval()))) + requires input_iterator<_Iter> + { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + std::holds_alternative<_Iter>(__i.__hold_), "Attempted to iter_move a non-dereferenceable common_iterator"); + return ranges::iter_move(std::__unchecked_get<_Iter>(__i.__hold_)); + } + + template _I2, class _S2> + _LIBCPP_HIDE_FROM_ABI friend constexpr void + iter_swap(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) noexcept( + noexcept(ranges::iter_swap(std::declval(), std::declval()))) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + std::holds_alternative<_Iter>(__x.__hold_), "Attempted to iter_swap a non-dereferenceable common_iterator"); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + std::holds_alternative<_I2>(__y.__hold_), "Attempted to iter_swap a non-dereferenceable common_iterator"); + return ranges::iter_swap(std::__unchecked_get<_Iter>(__x.__hold_), std::__unchecked_get<_I2>(__y.__hold_)); + } +}; + +template +struct incrementable_traits> { + using difference_type = iter_difference_t<_Iter>; +}; + +template +concept __denotes_forward_iter = requires { + typename iterator_traits<_Iter>::iterator_category; +} && derived_from::iterator_category, forward_iterator_tag>; + +template +concept __common_iter_has_ptr_op = requires(const common_iterator<_Iter, _Sent>& __a) { __a.operator->(); }; + +template +struct __arrow_type_or_void { + using type = void; +}; + +template + requires __common_iter_has_ptr_op<_Iter, _Sent> +struct __arrow_type_or_void<_Iter, _Sent> { + using type = decltype(std::declval&>().operator->()); +}; + +template +struct iterator_traits> { + using iterator_concept = _If, forward_iterator_tag, input_iterator_tag>; + using iterator_category = _If<__denotes_forward_iter<_Iter>, forward_iterator_tag, input_iterator_tag>; + using pointer = typename __arrow_type_or_void<_Iter, _Sent>::type; + using value_type = iter_value_t<_Iter>; + using difference_type = iter_difference_t<_Iter>; + using reference = iter_reference_t<_Iter>; +}; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_COMMON_ITERATOR_H diff --git a/libcxx/include/__cxx03/__iterator/concepts.h b/libcxx/include/__cxx03/__iterator/concepts.h new file mode 100644 index 0000000000000000000000000000000000000000..0a4878308d55f00ea56c1dfbbf829c31dda89128 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/concepts.h @@ -0,0 +1,257 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_CONCEPTS_H +#define _LIBCPP___ITERATOR_CONCEPTS_H + +#include <__concepts/arithmetic.h> +#include <__concepts/assignable.h> +#include <__concepts/common_reference_with.h> +#include <__concepts/constructible.h> +#include <__concepts/copyable.h> +#include <__concepts/derived_from.h> +#include <__concepts/equality_comparable.h> +#include <__concepts/invocable.h> +#include <__concepts/movable.h> +#include <__concepts/predicate.h> +#include <__concepts/regular.h> +#include <__concepts/relation.h> +#include <__concepts/same_as.h> +#include <__concepts/semiregular.h> +#include <__concepts/totally_ordered.h> +#include <__config> +#include <__functional/invoke.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iter_move.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/readable_traits.h> +#include <__memory/pointer_traits.h> +#include <__type_traits/add_pointer.h> +#include <__type_traits/common_reference.h> +#include <__type_traits/is_pointer.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/remove_cv.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [iterator.concept.readable] +template +concept __indirectly_readable_impl = + requires(const _In __i) { + typename iter_value_t<_In>; + typename iter_reference_t<_In>; + typename iter_rvalue_reference_t<_In>; + { *__i } -> same_as>; + { ranges::iter_move(__i) } -> same_as>; + } && common_reference_with&&, iter_value_t<_In>&> && + common_reference_with&&, iter_rvalue_reference_t<_In>&&> && + common_reference_with&&, const iter_value_t<_In>&>; + +template +concept indirectly_readable = __indirectly_readable_impl>; + +template +using iter_common_reference_t = common_reference_t, iter_value_t<_Tp>&>; + +// [iterator.concept.writable] +template +concept indirectly_writable = requires(_Out&& __o, _Tp&& __t) { + *__o = std::forward<_Tp>(__t); // not required to be equality-preserving + *std::forward<_Out>(__o) = std::forward<_Tp>(__t); // not required to be equality-preserving + const_cast&&>(*__o) = std::forward<_Tp>(__t); // not required to be equality-preserving + const_cast&&>(*std::forward<_Out>(__o)) = + std::forward<_Tp>(__t); // not required to be equality-preserving +}; + +// [iterator.concept.winc] +template +concept __integer_like = integral<_Tp> && !same_as<_Tp, bool>; + +template +concept __signed_integer_like = signed_integral<_Tp>; + +template +concept weakly_incrementable = + // TODO: remove this once the clang bug is fixed (bugs.llvm.org/PR48173). + !same_as<_Ip, bool> && // Currently, clang does not handle bool correctly. + movable<_Ip> && requires(_Ip __i) { + typename iter_difference_t<_Ip>; + requires __signed_integer_like>; + { ++__i } -> same_as<_Ip&>; // not required to be equality-preserving + __i++; // not required to be equality-preserving + }; + +// [iterator.concept.inc] +template +concept incrementable = regular<_Ip> && weakly_incrementable<_Ip> && requires(_Ip __i) { + { __i++ } -> same_as<_Ip>; +}; + +// [iterator.concept.iterator] +template +concept input_or_output_iterator = requires(_Ip __i) { + { *__i } -> __can_reference; +} && weakly_incrementable<_Ip>; + +// [iterator.concept.sentinel] +template +concept sentinel_for = semiregular<_Sp> && input_or_output_iterator<_Ip> && __weakly_equality_comparable_with<_Sp, _Ip>; + +template +inline constexpr bool disable_sized_sentinel_for = false; + +template +concept sized_sentinel_for = + sentinel_for<_Sp, _Ip> && !disable_sized_sentinel_for, remove_cv_t<_Ip>> && + requires(const _Ip& __i, const _Sp& __s) { + { __s - __i } -> same_as>; + { __i - __s } -> same_as>; + }; + +// [iterator.concept.input] +template +concept input_iterator = input_or_output_iterator<_Ip> && indirectly_readable<_Ip> && requires { + typename _ITER_CONCEPT<_Ip>; +} && derived_from<_ITER_CONCEPT<_Ip>, input_iterator_tag>; + +// [iterator.concept.output] +template +concept output_iterator = + input_or_output_iterator<_Ip> && indirectly_writable<_Ip, _Tp> && requires(_Ip __it, _Tp&& __t) { + *__it++ = std::forward<_Tp>(__t); // not required to be equality-preserving + }; + +// [iterator.concept.forward] +template +concept forward_iterator = + input_iterator<_Ip> && derived_from<_ITER_CONCEPT<_Ip>, forward_iterator_tag> && incrementable<_Ip> && + sentinel_for<_Ip, _Ip>; + +// [iterator.concept.bidir] +template +concept bidirectional_iterator = + forward_iterator<_Ip> && derived_from<_ITER_CONCEPT<_Ip>, bidirectional_iterator_tag> && requires(_Ip __i) { + { --__i } -> same_as<_Ip&>; + { __i-- } -> same_as<_Ip>; + }; + +template +concept random_access_iterator = + bidirectional_iterator<_Ip> && derived_from<_ITER_CONCEPT<_Ip>, random_access_iterator_tag> && + totally_ordered<_Ip> && sized_sentinel_for<_Ip, _Ip> && + requires(_Ip __i, const _Ip __j, const iter_difference_t<_Ip> __n) { + { __i += __n } -> same_as<_Ip&>; + { __j + __n } -> same_as<_Ip>; + { __n + __j } -> same_as<_Ip>; + { __i -= __n } -> same_as<_Ip&>; + { __j - __n } -> same_as<_Ip>; + { __j[__n] } -> same_as>; + }; + +template +concept contiguous_iterator = + random_access_iterator<_Ip> && derived_from<_ITER_CONCEPT<_Ip>, contiguous_iterator_tag> && + is_lvalue_reference_v> && same_as, remove_cvref_t>> && + requires(const _Ip& __i) { + { std::to_address(__i) } -> same_as>>; + }; + +template +concept __has_arrow = input_iterator<_Ip> && (is_pointer_v<_Ip> || requires(_Ip __i) { __i.operator->(); }); + +// [indirectcallable.indirectinvocable] +template +concept indirectly_unary_invocable = + indirectly_readable<_It> && copy_constructible<_Fp> && invocable<_Fp&, iter_value_t<_It>&> && + invocable<_Fp&, iter_reference_t<_It>> && + common_reference_with< invoke_result_t<_Fp&, iter_value_t<_It>&>, invoke_result_t<_Fp&, iter_reference_t<_It>>>; + +template +concept indirectly_regular_unary_invocable = + indirectly_readable<_It> && copy_constructible<_Fp> && regular_invocable<_Fp&, iter_value_t<_It>&> && + regular_invocable<_Fp&, iter_reference_t<_It>> && + common_reference_with< invoke_result_t<_Fp&, iter_value_t<_It>&>, invoke_result_t<_Fp&, iter_reference_t<_It>>>; + +template +concept indirect_unary_predicate = + indirectly_readable<_It> && copy_constructible<_Fp> && predicate<_Fp&, iter_value_t<_It>&> && + predicate<_Fp&, iter_reference_t<_It>>; + +template +concept indirect_binary_predicate = + indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fp> && + predicate<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> && + predicate<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> && + predicate<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> && + predicate<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>; + +template +concept indirect_equivalence_relation = + indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fp> && + equivalence_relation<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> && + equivalence_relation<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> && + equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> && + equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>; + +template +concept indirect_strict_weak_order = + indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fp> && + strict_weak_order<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> && + strict_weak_order<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> && + strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> && + strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>; + +template + requires(indirectly_readable<_Its> && ...) && invocable<_Fp, iter_reference_t<_Its>...> +using indirect_result_t = invoke_result_t<_Fp, iter_reference_t<_Its>...>; + +template +concept indirectly_movable = indirectly_readable<_In> && indirectly_writable<_Out, iter_rvalue_reference_t<_In>>; + +template +concept indirectly_movable_storable = + indirectly_movable<_In, _Out> && indirectly_writable<_Out, iter_value_t<_In>> && movable> && + constructible_from, iter_rvalue_reference_t<_In>> && + assignable_from&, iter_rvalue_reference_t<_In>>; + +template +concept indirectly_copyable = indirectly_readable<_In> && indirectly_writable<_Out, iter_reference_t<_In>>; + +template +concept indirectly_copyable_storable = + indirectly_copyable<_In, _Out> && indirectly_writable<_Out, iter_value_t<_In>&> && + indirectly_writable<_Out, const iter_value_t<_In>&> && indirectly_writable<_Out, iter_value_t<_In>&&> && + indirectly_writable<_Out, const iter_value_t<_In>&&> && copyable> && + constructible_from, iter_reference_t<_In>> && + assignable_from&, iter_reference_t<_In>>; + +// Note: indirectly_swappable is located in iter_swap.h to prevent a dependency cycle +// (both iter_swap and indirectly_swappable require indirectly_readable). + +#endif // _LIBCPP_STD_VER >= 20 + +template +using __has_random_access_iterator_category_or_concept +#if _LIBCPP_STD_VER >= 20 + = integral_constant>; +#else // _LIBCPP_STD_VER < 20 + = __has_random_access_iterator_category<_Tp>; +#endif // _LIBCPP_STD_VER + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_CONCEPTS_H diff --git a/libcxx/include/__cxx03/__iterator/counted_iterator.h b/libcxx/include/__cxx03/__iterator/counted_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..ea2832e3b978dc50ce2f67950a18a03538f14d0c --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/counted_iterator.h @@ -0,0 +1,289 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_COUNTED_ITERATOR_H +#define _LIBCPP___ITERATOR_COUNTED_ITERATOR_H + +#include <__assert> +#include <__concepts/assignable.h> +#include <__concepts/common_with.h> +#include <__concepts/constructible.h> +#include <__concepts/convertible_to.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/default_sentinel.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iter_move.h> +#include <__iterator/iter_swap.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/readable_traits.h> +#include <__memory/pointer_traits.h> +#include <__type_traits/add_pointer.h> +#include <__type_traits/conditional.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +struct __counted_iterator_concept {}; + +template + requires requires { typename _Iter::iterator_concept; } +struct __counted_iterator_concept<_Iter> { + using iterator_concept = typename _Iter::iterator_concept; +}; + +template +struct __counted_iterator_category {}; + +template + requires requires { typename _Iter::iterator_category; } +struct __counted_iterator_category<_Iter> { + using iterator_category = typename _Iter::iterator_category; +}; + +template +struct __counted_iterator_value_type {}; + +template +struct __counted_iterator_value_type<_Iter> { + using value_type = iter_value_t<_Iter>; +}; + +template +class counted_iterator + : public __counted_iterator_concept<_Iter>, + public __counted_iterator_category<_Iter>, + public __counted_iterator_value_type<_Iter> { +public: + using iterator_type = _Iter; + using difference_type = iter_difference_t<_Iter>; + + _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator() + requires default_initializable<_Iter> + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator(_Iter __iter, iter_difference_t<_Iter> __n) + : __current_(std::move(__iter)), __count_(__n) { + _LIBCPP_ASSERT_UNCATEGORIZED(__n >= 0, "__n must not be negative."); + } + + template + requires convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator(const counted_iterator<_I2>& __other) + : __current_(__other.__current_), __count_(__other.__count_) {} + + template + requires assignable_from<_Iter&, const _I2&> + _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator& operator=(const counted_iterator<_I2>& __other) { + __current_ = __other.__current_; + __count_ = __other.__count_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Iter& base() const& noexcept { return __current_; } + + _LIBCPP_HIDE_FROM_ABI constexpr _Iter base() && { return std::move(__current_); } + + _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Iter> count() const noexcept { return __count_; } + + _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count_ > 0, "Iterator is equal to or past end."); + return *__current_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const + requires __dereferenceable + { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count_ > 0, "Iterator is equal to or past end."); + return *__current_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto operator->() const noexcept + requires contiguous_iterator<_Iter> + { + return std::to_address(__current_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator& operator++() { + _LIBCPP_ASSERT_UNCATEGORIZED(__count_ > 0, "Iterator already at or past end."); + ++__current_; + --__count_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator++(int) { + _LIBCPP_ASSERT_UNCATEGORIZED(__count_ > 0, "Iterator already at or past end."); + --__count_; +# ifndef _LIBCPP_HAS_NO_EXCEPTIONS + try { + return __current_++; + } catch (...) { + ++__count_; + throw; + } +# else + return __current_++; +# endif // _LIBCPP_HAS_NO_EXCEPTIONS + } + + _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator operator++(int) + requires forward_iterator<_Iter> + { + _LIBCPP_ASSERT_UNCATEGORIZED(__count_ > 0, "Iterator already at or past end."); + counted_iterator __tmp = *this; + ++*this; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator& operator--() + requires bidirectional_iterator<_Iter> + { + --__current_; + ++__count_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator operator--(int) + requires bidirectional_iterator<_Iter> + { + counted_iterator __tmp = *this; + --*this; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator operator+(iter_difference_t<_Iter> __n) const + requires random_access_iterator<_Iter> + { + return counted_iterator(__current_ + __n, __count_ - __n); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr counted_iterator + operator+(iter_difference_t<_Iter> __n, const counted_iterator& __x) + requires random_access_iterator<_Iter> + { + return __x + __n; + } + + _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator& operator+=(iter_difference_t<_Iter> __n) + requires random_access_iterator<_Iter> + { + _LIBCPP_ASSERT_UNCATEGORIZED(__n <= __count_, "Cannot advance iterator past end."); + __current_ += __n; + __count_ -= __n; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator operator-(iter_difference_t<_Iter> __n) const + requires random_access_iterator<_Iter> + { + return counted_iterator(__current_ - __n, __count_ + __n); + } + + template _I2> + _LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_I2> + operator-(const counted_iterator& __lhs, const counted_iterator<_I2>& __rhs) { + return __rhs.__count_ - __lhs.__count_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_Iter> + operator-(const counted_iterator& __lhs, default_sentinel_t) { + return -__lhs.__count_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_Iter> + operator-(default_sentinel_t, const counted_iterator& __rhs) { + return __rhs.__count_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr counted_iterator& operator-=(iter_difference_t<_Iter> __n) + requires random_access_iterator<_Iter> + { + _LIBCPP_ASSERT_UNCATEGORIZED( + -__n <= __count_, + "Attempt to subtract too large of a size: " + "counted_iterator would be decremented before the " + "first element of its range."); + __current_ -= __n; + __count_ += __n; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](iter_difference_t<_Iter> __n) const + requires random_access_iterator<_Iter> + { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < __count_, "Subscript argument must be less than size."); + return __current_[__n]; + } + + template _I2> + _LIBCPP_HIDE_FROM_ABI friend constexpr bool + operator==(const counted_iterator& __lhs, const counted_iterator<_I2>& __rhs) { + return __lhs.__count_ == __rhs.__count_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const counted_iterator& __lhs, default_sentinel_t) { + return __lhs.__count_ == 0; + } + + template _I2> + _LIBCPP_HIDE_FROM_ABI friend constexpr strong_ordering + operator<=>(const counted_iterator& __lhs, const counted_iterator<_I2>& __rhs) { + return __rhs.__count_ <=> __lhs.__count_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr iter_rvalue_reference_t<_Iter> + iter_move(const counted_iterator& __i) noexcept(noexcept(ranges::iter_move(__i.__current_))) + requires input_iterator<_Iter> + { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i.__count_ > 0, "Iterator must not be past end of range."); + return ranges::iter_move(__i.__current_); + } + + template _I2> + _LIBCPP_HIDE_FROM_ABI friend constexpr void + iter_swap(const counted_iterator& __x, + const counted_iterator<_I2>& __y) noexcept(noexcept(ranges::iter_swap(__x.__current_, __y.__current_))) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __x.__count_ > 0 && __y.__count_ > 0, "Iterators must not be past end of range."); + return ranges::iter_swap(__x.__current_, __y.__current_); + } + +private: + _LIBCPP_NO_UNIQUE_ADDRESS _Iter __current_ = _Iter(); + iter_difference_t<_Iter> __count_ = 0; + template + friend class counted_iterator; +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(counted_iterator); + +template + requires same_as<_ITER_TRAITS<_Iter>, iterator_traits<_Iter>> +struct iterator_traits> : iterator_traits<_Iter> { + using pointer = conditional_t, add_pointer_t>, void>; +}; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_COUNTED_ITERATOR_H diff --git a/libcxx/include/__cxx03/__iterator/cpp17_iterator_concepts.h b/libcxx/include/__cxx03/__iterator/cpp17_iterator_concepts.h new file mode 100644 index 0000000000000000000000000000000000000000..ba3536b686099132b81aa9594d1e0ec49a62b2d4 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/cpp17_iterator_concepts.h @@ -0,0 +1,190 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_CPP17_ITERATOR_CONCEPTS_H +#define _LIBCPP___ITERATOR_CPP17_ITERATOR_CONCEPTS_H + +#include <__concepts/boolean_testable.h> +#include <__concepts/convertible_to.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_signed.h> +#include <__type_traits/is_void.h> +#include <__utility/as_const.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <__utility/swap.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +concept __cpp17_move_constructible = is_move_constructible_v<_Tp>; + +template +concept __cpp17_copy_constructible = __cpp17_move_constructible<_Tp> && is_copy_constructible_v<_Tp>; + +template +concept __cpp17_move_assignable = requires(_Tp __lhs, _Tp __rhs) { + { __lhs = std::move(__rhs) } -> same_as<_Tp&>; +}; + +template +concept __cpp17_copy_assignable = __cpp17_move_assignable<_Tp> && requires(_Tp __lhs, _Tp __rhs) { + { __lhs = __rhs } -> same_as<_Tp&>; + { __lhs = std::as_const(__rhs) } -> same_as<_Tp&>; +}; + +template +concept __cpp17_destructible = requires(_Tp __v) { __v.~_Tp(); }; + +template +concept __cpp17_equality_comparable = requires(_Tp __lhs, _Tp __rhs) { + { __lhs == __rhs } -> __boolean_testable; + { std::as_const(__lhs) == __rhs } -> __boolean_testable; + { __lhs == std::as_const(__rhs) } -> __boolean_testable; + { std::as_const(__lhs) == std::as_const(__rhs) } -> __boolean_testable; +}; + +template +concept __cpp17_default_constructible = is_default_constructible_v<_Tp>; + +template +concept __cpp17_iterator = + __cpp17_copy_constructible<_Iter> && __cpp17_copy_assignable<_Iter> && __cpp17_destructible<_Iter> && + (is_signed_v<__iter_diff_t<_Iter>> || is_void_v<__iter_diff_t<_Iter>>) && requires(_Iter __iter) { + { *__iter }; + { ++__iter } -> same_as<_Iter&>; + }; + +template +concept __cpp17_input_iterator = + __cpp17_iterator<_Iter> && __cpp17_equality_comparable<_Iter> && requires(_Iter __lhs, _Iter __rhs) { + { __lhs != __rhs } -> __boolean_testable; + { std::as_const(__lhs) != __rhs } -> __boolean_testable; + { __lhs != std::as_const(__rhs) } -> __boolean_testable; + { std::as_const(__lhs) != std::as_const(__rhs) } -> __boolean_testable; + + { *__lhs } -> same_as<__iter_reference<_Iter>>; + { *std::as_const(__lhs) } -> same_as<__iter_reference<_Iter>>; + + { ++__lhs } -> same_as<_Iter&>; + { (void)__lhs++ }; + { *__lhs++ }; + }; + +template +concept __cpp17_output_iterator = __cpp17_iterator<_Iter> && requires(_Iter __iter, _WriteTo __write) { + { *__iter = std::forward<_WriteTo>(__write) }; + { ++__iter } -> same_as<_Iter&>; + { __iter++ } -> convertible_to; + { *__iter++ = std::forward<_WriteTo>(__write) }; +}; + +template +concept __cpp17_forward_iterator = + __cpp17_input_iterator<_Iter> && __cpp17_default_constructible<_Iter> && requires(_Iter __iter) { + { __iter++ } -> convertible_to; + { *__iter++ } -> same_as<__iter_reference<_Iter>>; + }; + +template +concept __cpp17_bidirectional_iterator = __cpp17_forward_iterator<_Iter> && requires(_Iter __iter) { + { --__iter } -> same_as<_Iter&>; + { __iter-- } -> convertible_to; + { *__iter-- } -> same_as<__iter_reference<_Iter>>; +}; + +template +concept __cpp17_random_access_iterator = + __cpp17_bidirectional_iterator<_Iter> && requires(_Iter __iter, __iter_diff_t<_Iter> __n) { + { __iter += __n } -> same_as<_Iter&>; + + { __iter + __n } -> same_as<_Iter>; + { __n + __iter } -> same_as<_Iter>; + { std::as_const(__iter) + __n } -> same_as<_Iter>; + { __n + std::as_const(__iter) } -> same_as<_Iter>; + + { __iter -= __n } -> same_as<_Iter&>; + { __iter - __n } -> same_as<_Iter>; + { std::as_const(__iter) - __n } -> same_as<_Iter>; + + { __iter - __iter } -> same_as<__iter_diff_t<_Iter>>; + { std::as_const(__iter) - __iter } -> same_as<__iter_diff_t<_Iter>>; + { __iter - std::as_const(__iter) } -> same_as<__iter_diff_t<_Iter>>; + { std::as_const(__iter) - std::as_const(__iter) } -> same_as<__iter_diff_t<_Iter>>; + + { __iter[__n] } -> convertible_to<__iter_reference<_Iter>>; + { std::as_const(__iter)[__n] } -> convertible_to<__iter_reference<_Iter>>; + + { __iter < __iter } -> __boolean_testable; + { std::as_const(__iter) < __iter } -> __boolean_testable; + { __iter < std::as_const(__iter) } -> __boolean_testable; + { std::as_const(__iter) < std::as_const(__iter) } -> __boolean_testable; + + { __iter > __iter } -> __boolean_testable; + { std::as_const(__iter) > __iter } -> __boolean_testable; + { __iter > std::as_const(__iter) } -> __boolean_testable; + { std::as_const(__iter) > std::as_const(__iter) } -> __boolean_testable; + + { __iter >= __iter } -> __boolean_testable; + { std::as_const(__iter) >= __iter } -> __boolean_testable; + { __iter >= std::as_const(__iter) } -> __boolean_testable; + { std::as_const(__iter) >= std::as_const(__iter) } -> __boolean_testable; + + { __iter <= __iter } -> __boolean_testable; + { std::as_const(__iter) <= __iter } -> __boolean_testable; + { __iter <= std::as_const(__iter) } -> __boolean_testable; + { std::as_const(__iter) <= std::as_const(__iter) } -> __boolean_testable; + }; + +_LIBCPP_END_NAMESPACE_STD + +# ifndef _LIBCPP_DISABLE_ITERATOR_CHECKS +# define _LIBCPP_REQUIRE_CPP17_INPUT_ITERATOR(iter_t, message) \ + static_assert(::std::__cpp17_input_iterator, message) +# define _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(iter_t, write_t, message) \ + static_assert(::std::__cpp17_output_iterator, message) +# define _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(iter_t, message) \ + static_assert(::std::__cpp17_forward_iterator, message) +# define _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(iter_t, message) \ + static_assert(::std::__cpp17_bidirectional_iterator, message) +# define _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(iter_t, message) \ + static_assert(::std::__cpp17_random_access_iterator, message) +# else +# define _LIBCPP_REQUIRE_CPP17_INPUT_ITERATOR(iter_t, message) static_assert(true) +# define _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(iter_t, write_t, message) static_assert(true) +# define _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(iter_t, message) static_assert(true) +# define _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(iter_t, message) static_assert(true) +# define _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(iter_t, message) static_assert(true) +# endif + +#else // _LIBCPP_STD_VER >= 20 + +# define _LIBCPP_REQUIRE_CPP17_INPUT_ITERATOR(iter_t, message) static_assert(true) +# define _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(iter_t, write_t, message) static_assert(true) +# define _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(iter_t, message) static_assert(true) +# define _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(iter_t, message) static_assert(true) +# define _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(iter_t, message) static_assert(true) + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_CPP17_ITERATOR_CONCEPTS_H diff --git a/libcxx/include/__cxx03/__iterator/data.h b/libcxx/include/__cxx03/__iterator/data.h new file mode 100644 index 0000000000000000000000000000000000000000..b7c1603652b0e6c49a7d35cfa4a30020f2d1d791 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/data.h @@ -0,0 +1,49 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_DATA_H +#define _LIBCPP___ITERATOR_DATA_H + +#include <__config> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +template +constexpr _LIBCPP_HIDE_FROM_ABI auto data(_Cont& __c) noexcept(noexcept(__c.data())) -> decltype(__c.data()) { + return __c.data(); +} + +template +constexpr _LIBCPP_HIDE_FROM_ABI auto data(const _Cont& __c) noexcept(noexcept(__c.data())) -> decltype(__c.data()) { + return __c.data(); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr _Tp* data(_Tp (&__array)[_Sz]) noexcept { + return __array; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr const _Ep* data(initializer_list<_Ep> __il) noexcept { + return __il.begin(); +} + +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_DATA_H diff --git a/libcxx/include/__cxx03/__iterator/default_sentinel.h b/libcxx/include/__cxx03/__iterator/default_sentinel.h new file mode 100644 index 0000000000000000000000000000000000000000..3b65f442f1a85ba5f8b68402ff8a694aa1ca797a --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/default_sentinel.h @@ -0,0 +1,30 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_DEFAULT_SENTINEL_H +#define _LIBCPP___ITERATOR_DEFAULT_SENTINEL_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +struct default_sentinel_t {}; +inline constexpr default_sentinel_t default_sentinel{}; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_DEFAULT_SENTINEL_H diff --git a/libcxx/include/__cxx03/__iterator/distance.h b/libcxx/include/__cxx03/__iterator/distance.h new file mode 100644 index 0000000000000000000000000000000000000000..75bd49c9ae732b1008bbdab6e69d4d4160803ffd --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/distance.h @@ -0,0 +1,99 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_DISTANCE_H +#define _LIBCPP___ITERATOR_DISTANCE_H + +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iterator_traits.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/size.h> +#include <__type_traits/decay.h> +#include <__type_traits/remove_cvref.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 typename iterator_traits<_InputIter>::difference_type +__distance(_InputIter __first, _InputIter __last, input_iterator_tag) { + typename iterator_traits<_InputIter>::difference_type __r(0); + for (; __first != __last; ++__first) + ++__r; + return __r; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 typename iterator_traits<_RandIter>::difference_type +__distance(_RandIter __first, _RandIter __last, random_access_iterator_tag) { + return __last - __first; +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 typename iterator_traits<_InputIter>::difference_type +distance(_InputIter __first, _InputIter __last) { + return std::__distance(__first, __last, typename iterator_traits<_InputIter>::iterator_category()); +} + +#if _LIBCPP_STD_VER >= 20 + +// [range.iter.op.distance] + +namespace ranges { +namespace __distance { + +struct __fn { + template _Sp> + requires(!sized_sentinel_for<_Sp, _Ip>) + _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Ip> operator()(_Ip __first, _Sp __last) const { + iter_difference_t<_Ip> __n = 0; + while (__first != __last) { + ++__first; + ++__n; + } + return __n; + } + + template > _Sp> + _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Ip> operator()(_Ip&& __first, _Sp __last) const { + if constexpr (sized_sentinel_for<_Sp, __remove_cvref_t<_Ip>>) { + return __last - __first; + } else { + return __last - decay_t<_Ip>(__first); + } + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr range_difference_t<_Rp> operator()(_Rp&& __r) const { + if constexpr (sized_range<_Rp>) { + return static_cast>(ranges::size(__r)); + } else { + return operator()(ranges::begin(__r), ranges::end(__r)); + } + } +}; + +} // namespace __distance + +inline namespace __cpo { +inline constexpr auto distance = __distance::__fn{}; +} // namespace __cpo +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_DISTANCE_H diff --git a/libcxx/include/__cxx03/__iterator/empty.h b/libcxx/include/__cxx03/__iterator/empty.h new file mode 100644 index 0000000000000000000000000000000000000000..773f2776955b2a16707e1805e40967e35757cbef --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/empty.h @@ -0,0 +1,45 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_EMPTY_H +#define _LIBCPP___ITERATOR_EMPTY_H + +#include <__config> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto +empty(const _Cont& __c) noexcept(noexcept(__c.empty())) -> decltype(__c.empty()) { + return __c.empty(); +} + +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty(const _Tp (&)[_Sz]) noexcept { + return false; +} + +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty(initializer_list<_Ep> __il) noexcept { + return __il.size() == 0; +} + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_EMPTY_H diff --git a/libcxx/include/__cxx03/__iterator/erase_if_container.h b/libcxx/include/__cxx03/__iterator/erase_if_container.h new file mode 100644 index 0000000000000000000000000000000000000000..0f87f50cd1c160486adeff4c2a6085a90e84a650 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/erase_if_container.h @@ -0,0 +1,43 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_ERASE_IF_CONTAINER_H +#define _LIBCPP___ITERATOR_ERASE_IF_CONTAINER_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI typename _Container::size_type __libcpp_erase_if_container(_Container& __c, _Predicate& __pred) { + typename _Container::size_type __old_size = __c.size(); + + const typename _Container::iterator __last = __c.end(); + for (typename _Container::iterator __iter = __c.begin(); __iter != __last;) { + if (__pred(*__iter)) + __iter = __c.erase(__iter); + else + ++__iter; + } + + return __old_size - __c.size(); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_ERASE_IF_CONTAINER_H diff --git a/libcxx/include/__cxx03/__iterator/front_insert_iterator.h b/libcxx/include/__cxx03/__iterator/front_insert_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..7f2c54ec87442e20004b4d9e2f2066e81dd3aa9b --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/front_insert_iterator.h @@ -0,0 +1,83 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_FRONT_INSERT_ITERATOR_H +#define _LIBCPP___ITERATOR_FRONT_INSERT_ITERATOR_H + +#include <__config> +#include <__iterator/iterator.h> +#include <__iterator/iterator_traits.h> +#include <__memory/addressof.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +template +class _LIBCPP_TEMPLATE_VIS front_insert_iterator +#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) + : public iterator +#endif +{ + _LIBCPP_SUPPRESS_DEPRECATED_POP + +protected: + _Container* container; + +public: + typedef output_iterator_tag iterator_category; + typedef void value_type; +#if _LIBCPP_STD_VER >= 20 + typedef ptrdiff_t difference_type; +#else + typedef void difference_type; +#endif + typedef void pointer; + typedef void reference; + typedef _Container container_type; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit front_insert_iterator(_Container& __x) + : container(std::addressof(__x)) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 front_insert_iterator& + operator=(const typename _Container::value_type& __value) { + container->push_front(__value); + return *this; + } +#ifndef _LIBCPP_CXX03_LANG + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 front_insert_iterator& + operator=(typename _Container::value_type&& __value) { + container->push_front(std::move(__value)); + return *this; + } +#endif // _LIBCPP_CXX03_LANG + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 front_insert_iterator& operator*() { return *this; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 front_insert_iterator& operator++() { return *this; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 front_insert_iterator operator++(int) { return *this; } +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(front_insert_iterator); + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 front_insert_iterator<_Container> +front_inserter(_Container& __x) { + return front_insert_iterator<_Container>(__x); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_FRONT_INSERT_ITERATOR_H diff --git a/libcxx/include/__cxx03/__iterator/incrementable_traits.h b/libcxx/include/__cxx03/__iterator/incrementable_traits.h new file mode 100644 index 0000000000000000000000000000000000000000..a228b228f6e552046314d7dceeddf7d196327137 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/incrementable_traits.h @@ -0,0 +1,79 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_INCREMENTABLE_TRAITS_H +#define _LIBCPP___ITERATOR_INCREMENTABLE_TRAITS_H + +#include <__concepts/arithmetic.h> +#include <__config> +#include <__type_traits/conditional.h> +#include <__type_traits/is_object.h> +#include <__type_traits/is_primary_template.h> +#include <__type_traits/make_signed.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/declval.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [incrementable.traits] +template +struct incrementable_traits {}; + +template + requires is_object_v<_Tp> +struct incrementable_traits<_Tp*> { + using difference_type = ptrdiff_t; +}; + +template +struct incrementable_traits : incrementable_traits<_Ip> {}; + +template +concept __has_member_difference_type = requires { typename _Tp::difference_type; }; + +template <__has_member_difference_type _Tp> +struct incrementable_traits<_Tp> { + using difference_type = typename _Tp::difference_type; +}; + +template +concept __has_integral_minus = requires(const _Tp& __x, const _Tp& __y) { + { __x - __y } -> integral; +}; + +template <__has_integral_minus _Tp> + requires(!__has_member_difference_type<_Tp>) +struct incrementable_traits<_Tp> { + using difference_type = make_signed_t() - std::declval<_Tp>())>; +}; + +template +struct iterator_traits; + +// Let `RI` be `remove_cvref_t`. The type `iter_difference_t` denotes +// `incrementable_traits::difference_type` if `iterator_traits` names a specialization +// generated from the primary template, and `iterator_traits::difference_type` otherwise. +template +using iter_difference_t = + typename conditional_t<__is_primary_template > >::value, + incrementable_traits >, + iterator_traits > >::difference_type; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_INCREMENTABLE_TRAITS_H diff --git a/libcxx/include/__cxx03/__iterator/indirectly_comparable.h b/libcxx/include/__cxx03/__iterator/indirectly_comparable.h new file mode 100644 index 0000000000000000000000000000000000000000..e8a7398bacd2b0ce562f6d38f513aa00f3649124 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/indirectly_comparable.h @@ -0,0 +1,33 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_INDIRECTLY_COMPARABLE_H +#define _LIBCPP___ITERATOR_INDIRECTLY_COMPARABLE_H + +#include <__config> +#include <__functional/identity.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +concept indirectly_comparable = indirect_binary_predicate<_Rp, projected<_I1, _P1>, projected<_I2, _P2>>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_INDIRECTLY_COMPARABLE_H diff --git a/libcxx/include/__cxx03/__iterator/insert_iterator.h b/libcxx/include/__cxx03/__iterator/insert_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..8b7574dc9ec0afdfafb59854360d74a743631fc3 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/insert_iterator.h @@ -0,0 +1,95 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_INSERT_ITERATOR_H +#define _LIBCPP___ITERATOR_INSERT_ITERATOR_H + +#include <__config> +#include <__iterator/iterator.h> +#include <__iterator/iterator_traits.h> +#include <__memory/addressof.h> +#include <__ranges/access.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 +template +using __insert_iterator_iter_t = ranges::iterator_t<_Container>; +#else +template +using __insert_iterator_iter_t = typename _Container::iterator; +#endif + +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +template +class _LIBCPP_TEMPLATE_VIS insert_iterator +#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) + : public iterator +#endif +{ + _LIBCPP_SUPPRESS_DEPRECATED_POP + +protected: + _Container* container; + __insert_iterator_iter_t<_Container> iter; + +public: + typedef output_iterator_tag iterator_category; + typedef void value_type; +#if _LIBCPP_STD_VER >= 20 + typedef ptrdiff_t difference_type; +#else + typedef void difference_type; +#endif + typedef void pointer; + typedef void reference; + typedef _Container container_type; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + insert_iterator(_Container& __x, __insert_iterator_iter_t<_Container> __i) + : container(std::addressof(__x)), iter(__i) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 insert_iterator& + operator=(const typename _Container::value_type& __value) { + iter = container->insert(iter, __value); + ++iter; + return *this; + } +#ifndef _LIBCPP_CXX03_LANG + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 insert_iterator& + operator=(typename _Container::value_type&& __value) { + iter = container->insert(iter, std::move(__value)); + ++iter; + return *this; + } +#endif // _LIBCPP_CXX03_LANG + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 insert_iterator& operator*() { return *this; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 insert_iterator& operator++() { return *this; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 insert_iterator& operator++(int) { return *this; } +}; + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 insert_iterator<_Container> +inserter(_Container& __x, __insert_iterator_iter_t<_Container> __i) { + return insert_iterator<_Container>(__x, __i); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_INSERT_ITERATOR_H diff --git a/libcxx/include/__cxx03/__iterator/istream_iterator.h b/libcxx/include/__cxx03/__iterator/istream_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..58c9ac6d4ccceab42066051f90192e20dcb5640b --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/istream_iterator.h @@ -0,0 +1,101 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_ISTREAM_ITERATOR_H +#define _LIBCPP___ITERATOR_ISTREAM_ITERATOR_H + +#include <__config> +#include <__fwd/istream.h> +#include <__fwd/string.h> +#include <__iterator/default_sentinel.h> +#include <__iterator/iterator.h> +#include <__iterator/iterator_traits.h> +#include <__memory/addressof.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +template , class _Distance = ptrdiff_t> +class _LIBCPP_TEMPLATE_VIS istream_iterator +#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) + : public iterator +#endif +{ + _LIBCPP_SUPPRESS_DEPRECATED_POP + +public: + typedef input_iterator_tag iterator_category; + typedef _Tp value_type; + typedef _Distance difference_type; + typedef const _Tp* pointer; + typedef const _Tp& reference; + typedef _CharT char_type; + typedef _Traits traits_type; + typedef basic_istream<_CharT, _Traits> istream_type; + +private: + istream_type* __in_stream_; + _Tp __value_; + +public: + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR istream_iterator() : __in_stream_(nullptr), __value_() {} +#if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI constexpr istream_iterator(default_sentinel_t) : istream_iterator() {} +#endif // _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI istream_iterator(istream_type& __s) : __in_stream_(std::addressof(__s)) { + if (!(*__in_stream_ >> __value_)) + __in_stream_ = nullptr; + } + + _LIBCPP_HIDE_FROM_ABI const _Tp& operator*() const { return __value_; } + _LIBCPP_HIDE_FROM_ABI const _Tp* operator->() const { return std::addressof((operator*())); } + _LIBCPP_HIDE_FROM_ABI istream_iterator& operator++() { + if (!(*__in_stream_ >> __value_)) + __in_stream_ = nullptr; + return *this; + } + _LIBCPP_HIDE_FROM_ABI istream_iterator operator++(int) { + istream_iterator __t(*this); + ++(*this); + return __t; + } + + template + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const istream_iterator<_Up, _CharU, _TraitsU, _DistanceU>& __x, + const istream_iterator<_Up, _CharU, _TraitsU, _DistanceU>& __y); + +#if _LIBCPP_STD_VER >= 20 + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const istream_iterator& __i, default_sentinel_t) { + return __i.__in_stream_ == nullptr; + } +#endif // _LIBCPP_STD_VER >= 20 +}; + +template +inline _LIBCPP_HIDE_FROM_ABI bool operator==(const istream_iterator<_Tp, _CharT, _Traits, _Distance>& __x, + const istream_iterator<_Tp, _CharT, _Traits, _Distance>& __y) { + return __x.__in_stream_ == __y.__in_stream_; +} + +#if _LIBCPP_STD_VER <= 17 +template +inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const istream_iterator<_Tp, _CharT, _Traits, _Distance>& __x, + const istream_iterator<_Tp, _CharT, _Traits, _Distance>& __y) { + return !(__x == __y); +} +#endif // _LIBCPP_STD_VER <= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_ISTREAM_ITERATOR_H diff --git a/libcxx/include/__cxx03/__iterator/istreambuf_iterator.h b/libcxx/include/__cxx03/__iterator/istreambuf_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..51c4ecff351f52b8009fa0c0519c072af1487b1e --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/istreambuf_iterator.h @@ -0,0 +1,109 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_ISTREAMBUF_ITERATOR_H +#define _LIBCPP___ITERATOR_ISTREAMBUF_ITERATOR_H + +#include <__config> +#include <__fwd/istream.h> +#include <__fwd/streambuf.h> +#include <__iterator/default_sentinel.h> +#include <__iterator/iterator.h> +#include <__iterator/iterator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +template +class _LIBCPP_TEMPLATE_VIS istreambuf_iterator +#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) + : public iterator +#endif +{ + _LIBCPP_SUPPRESS_DEPRECATED_POP + +public: + typedef input_iterator_tag iterator_category; + typedef _CharT value_type; + typedef typename _Traits::off_type difference_type; + typedef _CharT* pointer; + typedef _CharT reference; + typedef _CharT char_type; + typedef _Traits traits_type; + typedef typename _Traits::int_type int_type; + typedef basic_streambuf<_CharT, _Traits> streambuf_type; + typedef basic_istream<_CharT, _Traits> istream_type; + +private: + mutable streambuf_type* __sbuf_; + + class __proxy { + char_type __keep_; + streambuf_type* __sbuf_; + _LIBCPP_HIDE_FROM_ABI explicit __proxy(char_type __c, streambuf_type* __s) : __keep_(__c), __sbuf_(__s) {} + friend class istreambuf_iterator; + + public: + _LIBCPP_HIDE_FROM_ABI char_type operator*() const { return __keep_; } + }; + + _LIBCPP_HIDE_FROM_ABI bool __test_for_eof() const { + if (__sbuf_ && traits_type::eq_int_type(__sbuf_->sgetc(), traits_type::eof())) + __sbuf_ = nullptr; + return __sbuf_ == nullptr; + } + +public: + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR istreambuf_iterator() _NOEXCEPT : __sbuf_(nullptr) {} +#if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI constexpr istreambuf_iterator(default_sentinel_t) noexcept : istreambuf_iterator() {} +#endif // _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI istreambuf_iterator(istream_type& __s) _NOEXCEPT : __sbuf_(__s.rdbuf()) {} + _LIBCPP_HIDE_FROM_ABI istreambuf_iterator(streambuf_type* __s) _NOEXCEPT : __sbuf_(__s) {} + _LIBCPP_HIDE_FROM_ABI istreambuf_iterator(const __proxy& __p) _NOEXCEPT : __sbuf_(__p.__sbuf_) {} + + _LIBCPP_HIDE_FROM_ABI char_type operator*() const { return static_cast(__sbuf_->sgetc()); } + _LIBCPP_HIDE_FROM_ABI istreambuf_iterator& operator++() { + __sbuf_->sbumpc(); + return *this; + } + _LIBCPP_HIDE_FROM_ABI __proxy operator++(int) { return __proxy(__sbuf_->sbumpc(), __sbuf_); } + + _LIBCPP_HIDE_FROM_ABI bool equal(const istreambuf_iterator& __b) const { + return __test_for_eof() == __b.__test_for_eof(); + } + +#if _LIBCPP_STD_VER >= 20 + friend _LIBCPP_HIDE_FROM_ABI bool operator==(const istreambuf_iterator& __i, default_sentinel_t) { + return __i.__test_for_eof(); + } +#endif // _LIBCPP_STD_VER >= 20 +}; + +template +inline _LIBCPP_HIDE_FROM_ABI bool +operator==(const istreambuf_iterator<_CharT, _Traits>& __a, const istreambuf_iterator<_CharT, _Traits>& __b) { + return __a.equal(__b); +} + +#if _LIBCPP_STD_VER <= 17 +template +inline _LIBCPP_HIDE_FROM_ABI bool +operator!=(const istreambuf_iterator<_CharT, _Traits>& __a, const istreambuf_iterator<_CharT, _Traits>& __b) { + return !__a.equal(__b); +} +#endif // _LIBCPP_STD_VER <= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_ISTREAMBUF_ITERATOR_H diff --git a/libcxx/include/__cxx03/__iterator/iter_move.h b/libcxx/include/__cxx03/__iterator/iter_move.h new file mode 100644 index 0000000000000000000000000000000000000000..ba8aed3c0ffbbdc0383ddd878e735d5f94c09174 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/iter_move.h @@ -0,0 +1,103 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_ITER_MOVE_H +#define _LIBCPP___ITERATOR_ITER_MOVE_H + +#include <__concepts/class_or_enum.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/declval.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [iterator.cust.move] + +namespace ranges { +namespace __iter_move { + +void iter_move() = delete; + +template +concept __unqualified_iter_move = __class_or_enum> && requires(_Tp&& __t) { + // NOLINTNEXTLINE(libcpp-robust-against-adl) iter_swap ADL calls should only be made through ranges::iter_swap + iter_move(std::forward<_Tp>(__t)); +}; + +template +concept __move_deref = !__unqualified_iter_move<_Tp> && requires(_Tp&& __t) { + *__t; + requires is_lvalue_reference_v; +}; + +template +concept __just_deref = !__unqualified_iter_move<_Tp> && !__move_deref<_Tp> && requires(_Tp&& __t) { + *__t; + requires(!is_lvalue_reference_v); +}; + +// [iterator.cust.move] + +struct __fn { + // NOLINTBEGIN(libcpp-robust-against-adl) iter_move ADL calls should only be made through ranges::iter_move + template + requires __unqualified_iter_move<_Ip> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator()(_Ip&& __i) const + noexcept(noexcept(iter_move(std::forward<_Ip>(__i)))) { + return iter_move(std::forward<_Ip>(__i)); + } + // NOLINTEND(libcpp-robust-against-adl) + + template + requires __move_deref<_Ip> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Ip&& __i) const + noexcept(noexcept(std::move(*std::forward<_Ip>(__i)))) -> decltype(std::move(*std::forward<_Ip>(__i))) { + return std::move(*std::forward<_Ip>(__i)); + } + + template + requires __just_deref<_Ip> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Ip&& __i) const + noexcept(noexcept(*std::forward<_Ip>(__i))) -> decltype(*std::forward<_Ip>(__i)) { + return *std::forward<_Ip>(__i); + } +}; +} // namespace __iter_move + +inline namespace __cpo { +inline constexpr auto iter_move = __iter_move::__fn{}; +} // namespace __cpo +} // namespace ranges + +template <__dereferenceable _Tp> + requires requires(_Tp& __t) { + { ranges::iter_move(__t) } -> __can_reference; + } +using iter_rvalue_reference_t = decltype(ranges::iter_move(std::declval<_Tp&>())); + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_ITER_MOVE_H diff --git a/libcxx/include/__cxx03/__iterator/iter_swap.h b/libcxx/include/__cxx03/__iterator/iter_swap.h new file mode 100644 index 0000000000000000000000000000000000000000..01ab1b97d6501f85893a59da1a171ff689b0a8ee --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/iter_swap.h @@ -0,0 +1,108 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_ITER_SWAP_H +#define _LIBCPP___ITERATOR_ITER_SWAP_H + +#include <__concepts/class_or_enum.h> +#include <__concepts/swappable.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/iter_move.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/readable_traits.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/declval.h> +#include <__utility/forward.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [iter.cust.swap] + +namespace ranges { +namespace __iter_swap { +template +void iter_swap(_I1, _I2) = delete; + +template +concept __unqualified_iter_swap = + (__class_or_enum> || __class_or_enum>) && requires(_T1&& __x, _T2&& __y) { + // NOLINTNEXTLINE(libcpp-robust-against-adl) iter_swap ADL calls should only be made through ranges::iter_swap + iter_swap(std::forward<_T1>(__x), std::forward<_T2>(__y)); + }; + +template +concept __readable_swappable = + indirectly_readable<_T1> && indirectly_readable<_T2> && + swappable_with, iter_reference_t<_T2>>; + +struct __fn { + // NOLINTBEGIN(libcpp-robust-against-adl) iter_swap ADL calls should only be made through ranges::iter_swap + template + requires __unqualified_iter_swap<_T1, _T2> + _LIBCPP_HIDE_FROM_ABI constexpr void operator()(_T1&& __x, _T2&& __y) const + noexcept(noexcept(iter_swap(std::forward<_T1>(__x), std::forward<_T2>(__y)))) { + (void)iter_swap(std::forward<_T1>(__x), std::forward<_T2>(__y)); + } + // NOLINTEND(libcpp-robust-against-adl) + + template + requires(!__unqualified_iter_swap<_T1, _T2>) && __readable_swappable<_T1, _T2> + _LIBCPP_HIDE_FROM_ABI constexpr void operator()(_T1&& __x, _T2&& __y) const + noexcept(noexcept(ranges::swap(*std::forward<_T1>(__x), *std::forward<_T2>(__y)))) { + ranges::swap(*std::forward<_T1>(__x), *std::forward<_T2>(__y)); + } + + template + requires(!__unqualified_iter_swap<_T1, _T2> && // + !__readable_swappable<_T1, _T2>) && // + indirectly_movable_storable<_T1, _T2> && // + indirectly_movable_storable<_T2, _T1> + _LIBCPP_HIDE_FROM_ABI constexpr void operator()(_T1&& __x, _T2&& __y) const + noexcept(noexcept(iter_value_t<_T2>(ranges::iter_move(__y))) && // + noexcept(*__y = ranges::iter_move(__x)) && // + noexcept(*std::forward<_T1>(__x) = std::declval>())) { + iter_value_t<_T2> __old(ranges::iter_move(__y)); + *__y = ranges::iter_move(__x); + *std::forward<_T1>(__x) = std::move(__old); + } +}; +} // namespace __iter_swap + +inline namespace __cpo { +inline constexpr auto iter_swap = __iter_swap::__fn{}; +} // namespace __cpo +} // namespace ranges + +template +concept indirectly_swappable = + indirectly_readable<_I1> && indirectly_readable<_I2> && requires(const _I1 __i1, const _I2 __i2) { + ranges::iter_swap(__i1, __i1); + ranges::iter_swap(__i2, __i2); + ranges::iter_swap(__i1, __i2); + ranges::iter_swap(__i2, __i1); + }; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_ITER_SWAP_H diff --git a/libcxx/include/__cxx03/__iterator/iterator.h b/libcxx/include/__cxx03/__iterator/iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..ba9308f3c2243013da46ccef745c2082dc95054a --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/iterator.h @@ -0,0 +1,33 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_ITERATOR_H +#define _LIBCPP___ITERATOR_ITERATOR_H + +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX17 iterator { + typedef _Tp value_type; + typedef _Distance difference_type; + typedef _Pointer pointer; + typedef _Reference reference; + typedef _Category iterator_category; +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_ITERATOR_H diff --git a/libcxx/include/__cxx03/__iterator/iterator_traits.h b/libcxx/include/__cxx03/__iterator/iterator_traits.h new file mode 100644 index 0000000000000000000000000000000000000000..11af9e301842cf55fdf74d674e367b90f17e6c3c --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/iterator_traits.h @@ -0,0 +1,528 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_ITERATOR_TRAITS_H +#define _LIBCPP___ITERATOR_ITERATOR_TRAITS_H + +#include <__concepts/arithmetic.h> +#include <__concepts/constructible.h> +#include <__concepts/convertible_to.h> +#include <__concepts/copyable.h> +#include <__concepts/equality_comparable.h> +#include <__concepts/same_as.h> +#include <__concepts/totally_ordered.h> +#include <__config> +#include <__fwd/pair.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/readable_traits.h> +#include <__type_traits/common_reference.h> +#include <__type_traits/conditional.h> +#include <__type_traits/disjunction.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_object.h> +#include <__type_traits/is_primary_template.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/is_valid_expansion.h> +#include <__type_traits/remove_const.h> +#include <__type_traits/remove_cv.h> +#include <__type_traits/remove_cvref.h> +#include <__type_traits/void_t.h> +#include <__utility/declval.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +using __with_reference = _Tp&; + +template +concept __can_reference = requires { typename __with_reference<_Tp>; }; + +template +concept __dereferenceable = requires(_Tp& __t) { + { *__t } -> __can_reference; // not required to be equality-preserving +}; + +// [iterator.traits] +template <__dereferenceable _Tp> +using iter_reference_t = decltype(*std::declval<_Tp&>()); + +#endif // _LIBCPP_STD_VER >= 20 + +template +struct _LIBCPP_TEMPLATE_VIS iterator_traits; + +struct _LIBCPP_TEMPLATE_VIS input_iterator_tag {}; +struct _LIBCPP_TEMPLATE_VIS output_iterator_tag {}; +struct _LIBCPP_TEMPLATE_VIS forward_iterator_tag : public input_iterator_tag {}; +struct _LIBCPP_TEMPLATE_VIS bidirectional_iterator_tag : public forward_iterator_tag {}; +struct _LIBCPP_TEMPLATE_VIS random_access_iterator_tag : public bidirectional_iterator_tag {}; +#if _LIBCPP_STD_VER >= 20 +struct _LIBCPP_TEMPLATE_VIS contiguous_iterator_tag : public random_access_iterator_tag {}; +#endif + +template +struct __iter_traits_cache { + using type = _If< __is_primary_template >::value, _Iter, iterator_traits<_Iter> >; +}; +template +using _ITER_TRAITS = typename __iter_traits_cache<_Iter>::type; + +struct __iter_concept_concept_test { + template + using _Apply = typename _ITER_TRAITS<_Iter>::iterator_concept; +}; +struct __iter_concept_category_test { + template + using _Apply = typename _ITER_TRAITS<_Iter>::iterator_category; +}; +struct __iter_concept_random_fallback { + template + using _Apply = __enable_if_t< __is_primary_template >::value, random_access_iterator_tag >; +}; + +template +struct __test_iter_concept : _IsValidExpansion<_Tester::template _Apply, _Iter>, _Tester {}; + +template +struct __iter_concept_cache { + using type = _Or< __test_iter_concept<_Iter, __iter_concept_concept_test>, + __test_iter_concept<_Iter, __iter_concept_category_test>, + __test_iter_concept<_Iter, __iter_concept_random_fallback> >; +}; + +template +using _ITER_CONCEPT = typename __iter_concept_cache<_Iter>::type::template _Apply<_Iter>; + +template +struct __has_iterator_typedefs { +private: + template + static false_type __test(...); + template + static true_type + __test(__void_t* = nullptr, + __void_t* = nullptr, + __void_t* = nullptr, + __void_t* = nullptr, + __void_t* = nullptr); + +public: + static const bool value = decltype(__test<_Tp>(nullptr, nullptr, nullptr, nullptr, nullptr))::value; +}; + +template +struct __has_iterator_category { +private: + template + static false_type __test(...); + template + static true_type __test(typename _Up::iterator_category* = nullptr); + +public: + static const bool value = decltype(__test<_Tp>(nullptr))::value; +}; + +template +struct __has_iterator_concept { +private: + template + static false_type __test(...); + template + static true_type __test(typename _Up::iterator_concept* = nullptr); + +public: + static const bool value = decltype(__test<_Tp>(nullptr))::value; +}; + +#if _LIBCPP_STD_VER >= 20 + +// The `cpp17-*-iterator` exposition-only concepts have very similar names to the `Cpp17*Iterator` named requirements +// from `[iterator.cpp17]`. To avoid confusion between the two, the exposition-only concepts have been banished to +// a "detail" namespace indicating they have a niche use-case. +namespace __iterator_traits_detail { +template +concept __cpp17_iterator = requires(_Ip __i) { + { *__i } -> __can_reference; + { ++__i } -> same_as<_Ip&>; + { *__i++ } -> __can_reference; +} && copyable<_Ip>; + +template +concept __cpp17_input_iterator = __cpp17_iterator<_Ip> && equality_comparable<_Ip> && requires(_Ip __i) { + typename incrementable_traits<_Ip>::difference_type; + typename indirectly_readable_traits<_Ip>::value_type; + typename common_reference_t&&, typename indirectly_readable_traits<_Ip>::value_type&>; + typename common_reference_t::value_type&>; + requires signed_integral::difference_type>; +}; + +template +concept __cpp17_forward_iterator = + __cpp17_input_iterator<_Ip> && constructible_from<_Ip> && is_reference_v> && + same_as>, typename indirectly_readable_traits<_Ip>::value_type> && + requires(_Ip __i) { + { __i++ } -> convertible_to<_Ip const&>; + { *__i++ } -> same_as>; + }; + +template +concept __cpp17_bidirectional_iterator = __cpp17_forward_iterator<_Ip> && requires(_Ip __i) { + { --__i } -> same_as<_Ip&>; + { __i-- } -> convertible_to<_Ip const&>; + { *__i-- } -> same_as>; +}; + +template +concept __cpp17_random_access_iterator = + __cpp17_bidirectional_iterator<_Ip> && totally_ordered<_Ip> && + requires(_Ip __i, typename incrementable_traits<_Ip>::difference_type __n) { + { __i += __n } -> same_as<_Ip&>; + { __i -= __n } -> same_as<_Ip&>; + { __i + __n } -> same_as<_Ip>; + { __n + __i } -> same_as<_Ip>; + { __i - __n } -> same_as<_Ip>; + { __i - __i } -> same_as; // NOLINT(misc-redundant-expression) ; This is llvm.org/PR54114 + { __i[__n] } -> convertible_to>; + }; +} // namespace __iterator_traits_detail + +template +concept __has_member_reference = requires { typename _Ip::reference; }; + +template +concept __has_member_pointer = requires { typename _Ip::pointer; }; + +template +concept __has_member_iterator_category = requires { typename _Ip::iterator_category; }; + +template +concept __specifies_members = requires { + typename _Ip::value_type; + typename _Ip::difference_type; + requires __has_member_reference<_Ip>; + requires __has_member_iterator_category<_Ip>; +}; + +template +struct __iterator_traits_member_pointer_or_void { + using type = void; +}; + +template <__has_member_pointer _Tp> +struct __iterator_traits_member_pointer_or_void<_Tp> { + using type = typename _Tp::pointer; +}; + +template +concept __cpp17_iterator_missing_members = !__specifies_members<_Tp> && __iterator_traits_detail::__cpp17_iterator<_Tp>; + +template +concept __cpp17_input_iterator_missing_members = + __cpp17_iterator_missing_members<_Tp> && __iterator_traits_detail::__cpp17_input_iterator<_Tp>; + +// Otherwise, `pointer` names `void`. +template +struct __iterator_traits_member_pointer_or_arrow_or_void { + using type = void; +}; + +// [iterator.traits]/3.2.1 +// If the qualified-id `I::pointer` is valid and denotes a type, `pointer` names that type. +template <__has_member_pointer _Ip> +struct __iterator_traits_member_pointer_or_arrow_or_void<_Ip> { + using type = typename _Ip::pointer; +}; + +// Otherwise, if `decltype(declval().operator->())` is well-formed, then `pointer` names that +// type. +template + requires requires(_Ip& __i) { __i.operator->(); } && (!__has_member_pointer<_Ip>) +struct __iterator_traits_member_pointer_or_arrow_or_void<_Ip> { + using type = decltype(std::declval<_Ip&>().operator->()); +}; + +// Otherwise, `reference` names `iter-reference-t`. +template +struct __iterator_traits_member_reference { + using type = iter_reference_t<_Ip>; +}; + +// [iterator.traits]/3.2.2 +// If the qualified-id `I::reference` is valid and denotes a type, `reference` names that type. +template <__has_member_reference _Ip> +struct __iterator_traits_member_reference<_Ip> { + using type = typename _Ip::reference; +}; + +// [iterator.traits]/3.2.3.4 +// input_iterator_tag +template +struct __deduce_iterator_category { + using type = input_iterator_tag; +}; + +// [iterator.traits]/3.2.3.1 +// `random_access_iterator_tag` if `I` satisfies `cpp17-random-access-iterator`, or otherwise +template <__iterator_traits_detail::__cpp17_random_access_iterator _Ip> +struct __deduce_iterator_category<_Ip> { + using type = random_access_iterator_tag; +}; + +// [iterator.traits]/3.2.3.2 +// `bidirectional_iterator_tag` if `I` satisfies `cpp17-bidirectional-iterator`, or otherwise +template <__iterator_traits_detail::__cpp17_bidirectional_iterator _Ip> +struct __deduce_iterator_category<_Ip> { + using type = bidirectional_iterator_tag; +}; + +// [iterator.traits]/3.2.3.3 +// `forward_iterator_tag` if `I` satisfies `cpp17-forward-iterator`, or otherwise +template <__iterator_traits_detail::__cpp17_forward_iterator _Ip> +struct __deduce_iterator_category<_Ip> { + using type = forward_iterator_tag; +}; + +template +struct __iterator_traits_iterator_category : __deduce_iterator_category<_Ip> {}; + +// [iterator.traits]/3.2.3 +// If the qualified-id `I::iterator-category` is valid and denotes a type, `iterator-category` names +// that type. +template <__has_member_iterator_category _Ip> +struct __iterator_traits_iterator_category<_Ip> { + using type = typename _Ip::iterator_category; +}; + +// otherwise, it names void. +template +struct __iterator_traits_difference_type { + using type = void; +}; + +// If the qualified-id `incrementable_traits::difference_type` is valid and denotes a type, then +// `difference_type` names that type; +template + requires requires { typename incrementable_traits<_Ip>::difference_type; } +struct __iterator_traits_difference_type<_Ip> { + using type = typename incrementable_traits<_Ip>::difference_type; +}; + +// [iterator.traits]/3.4 +// Otherwise, `iterator_traits` has no members by any of the above names. +template +struct __iterator_traits {}; + +// [iterator.traits]/3.1 +// If `I` has valid ([temp.deduct]) member types `difference-type`, `value-type`, `reference`, and +// `iterator-category`, then `iterator-traits` has the following publicly accessible members: +template <__specifies_members _Ip> +struct __iterator_traits<_Ip> { + using iterator_category = typename _Ip::iterator_category; + using value_type = typename _Ip::value_type; + using difference_type = typename _Ip::difference_type; + using pointer = typename __iterator_traits_member_pointer_or_void<_Ip>::type; + using reference = typename _Ip::reference; +}; + +// [iterator.traits]/3.2 +// Otherwise, if `I` satisfies the exposition-only concept `cpp17-input-iterator`, +// `iterator-traits` has the following publicly accessible members: +template <__cpp17_input_iterator_missing_members _Ip> +struct __iterator_traits<_Ip> { + using iterator_category = typename __iterator_traits_iterator_category<_Ip>::type; + using value_type = typename indirectly_readable_traits<_Ip>::value_type; + using difference_type = typename incrementable_traits<_Ip>::difference_type; + using pointer = typename __iterator_traits_member_pointer_or_arrow_or_void<_Ip>::type; + using reference = typename __iterator_traits_member_reference<_Ip>::type; +}; + +// Otherwise, if `I` satisfies the exposition-only concept `cpp17-iterator`, then +// `iterator_traits` has the following publicly accessible members: +template <__cpp17_iterator_missing_members _Ip> +struct __iterator_traits<_Ip> { + using iterator_category = output_iterator_tag; + using value_type = void; + using difference_type = typename __iterator_traits_difference_type<_Ip>::type; + using pointer = void; + using reference = void; +}; + +template +struct iterator_traits : __iterator_traits<_Ip> { + using __primary_template = iterator_traits; +}; + +#else // _LIBCPP_STD_VER >= 20 + +template +struct __iterator_traits {}; + +template +struct __iterator_traits_impl {}; + +template +struct __iterator_traits_impl<_Iter, true> { + typedef typename _Iter::difference_type difference_type; + typedef typename _Iter::value_type value_type; + typedef typename _Iter::pointer pointer; + typedef typename _Iter::reference reference; + typedef typename _Iter::iterator_category iterator_category; +}; + +template +struct __iterator_traits<_Iter, true> + : __iterator_traits_impl< _Iter, + is_convertible::value || + is_convertible::value > {}; + +// iterator_traits will only have the nested types if Iterator::iterator_category +// exists. Else iterator_traits will be an empty class. This is a +// conforming extension which allows some programs to compile and behave as +// the client expects instead of failing at compile time. + +template +struct _LIBCPP_TEMPLATE_VIS iterator_traits : __iterator_traits<_Iter, __has_iterator_typedefs<_Iter>::value> { + using __primary_template = iterator_traits; +}; +#endif // _LIBCPP_STD_VER >= 20 + +template +#if _LIBCPP_STD_VER >= 20 + requires is_object_v<_Tp> +#endif +struct _LIBCPP_TEMPLATE_VIS iterator_traits<_Tp*> { + typedef ptrdiff_t difference_type; + typedef __remove_cv_t<_Tp> value_type; + typedef _Tp* pointer; + typedef _Tp& reference; + typedef random_access_iterator_tag iterator_category; +#if _LIBCPP_STD_VER >= 20 + typedef contiguous_iterator_tag iterator_concept; +#endif +}; + +template >::value> +struct __has_iterator_category_convertible_to : is_convertible::iterator_category, _Up> { +}; + +template +struct __has_iterator_category_convertible_to<_Tp, _Up, false> : false_type {}; + +template ::value> +struct __has_iterator_concept_convertible_to : is_convertible {}; + +template +struct __has_iterator_concept_convertible_to<_Tp, _Up, false> : false_type {}; + +template +using __has_input_iterator_category = __has_iterator_category_convertible_to<_Tp, input_iterator_tag>; + +template +using __has_forward_iterator_category = __has_iterator_category_convertible_to<_Tp, forward_iterator_tag>; + +template +using __has_bidirectional_iterator_category = __has_iterator_category_convertible_to<_Tp, bidirectional_iterator_tag>; + +template +using __has_random_access_iterator_category = __has_iterator_category_convertible_to<_Tp, random_access_iterator_tag>; + +// __libcpp_is_contiguous_iterator determines if an iterator is known by +// libc++ to be contiguous, either because it advertises itself as such +// (in C++20) or because it is a pointer type or a known trivial wrapper +// around a (possibly fancy) pointer type, such as __wrap_iter. +// Such iterators receive special "contiguous" optimizations in +// std::copy and std::sort. +// +#if _LIBCPP_STD_VER >= 20 +template +struct __libcpp_is_contiguous_iterator + : _Or< __has_iterator_category_convertible_to<_Tp, contiguous_iterator_tag>, + __has_iterator_concept_convertible_to<_Tp, contiguous_iterator_tag> > {}; +#else +template +struct __libcpp_is_contiguous_iterator : false_type {}; +#endif + +// Any native pointer which is an iterator is also a contiguous iterator. +template +struct __libcpp_is_contiguous_iterator<_Up*> : true_type {}; + +template +class __wrap_iter; + +template +using __has_exactly_input_iterator_category = + integral_constant::value && + !__has_iterator_category_convertible_to<_Tp, forward_iterator_tag>::value>; + +template +using __has_exactly_forward_iterator_category = + integral_constant::value && + !__has_iterator_category_convertible_to<_Tp, bidirectional_iterator_tag>::value>; + +template +using __has_exactly_bidirectional_iterator_category = + integral_constant::value && + !__has_iterator_category_convertible_to<_Tp, random_access_iterator_tag>::value>; + +template +using __iter_value_type = typename iterator_traits<_InputIterator>::value_type; + +template +using __iter_key_type = __remove_const_t::value_type::first_type>; + +template +using __iter_mapped_type = typename iterator_traits<_InputIterator>::value_type::second_type; + +template +using __iter_to_alloc_type = + pair::value_type::first_type, + typename iterator_traits<_InputIterator>::value_type::second_type>; + +template +using __iterator_category_type = typename iterator_traits<_Iter>::iterator_category; + +template +using __iterator_pointer_type = typename iterator_traits<_Iter>::pointer; + +template +using __iter_diff_t = typename iterator_traits<_Iter>::difference_type; + +template +using __iter_reference = typename iterator_traits<_Iter>::reference; + +#if _LIBCPP_STD_VER >= 20 + +// [readable.traits] + +// Let `RI` be `remove_cvref_t`. The type `iter_value_t` denotes +// `indirectly_readable_traits::value_type` if `iterator_traits` names a specialization +// generated from the primary template, and `iterator_traits::value_type` otherwise. +// This has to be in this file and not readable_traits.h to break the include cycle between the two. +template +using iter_value_t = + typename conditional_t<__is_primary_template > >::value, + indirectly_readable_traits >, + iterator_traits > >::value_type; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_ITERATOR_TRAITS_H diff --git a/libcxx/include/__cxx03/__iterator/iterator_with_data.h b/libcxx/include/__cxx03/__iterator/iterator_with_data.h new file mode 100644 index 0000000000000000000000000000000000000000..afdc0a4e12e21c1b63ab2c9a11da57b16ee68feb --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/iterator_with_data.h @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_ITERATOR_WITH_DATA_H +#define _LIBCPP___ITERATOR_ITERATOR_WITH_DATA_H + +#include <__compare/compare_three_way_result.h> +#include <__compare/three_way_comparable.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iter_move.h> +#include <__iterator/iter_swap.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/readable_traits.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class __iterator_with_data { + _Iterator __iter_{}; + _Data __data_{}; + +public: + using value_type = iter_value_t<_Iterator>; + using difference_type = iter_difference_t<_Iterator>; + + _LIBCPP_HIDE_FROM_ABI __iterator_with_data() = default; + + constexpr _LIBCPP_HIDE_FROM_ABI __iterator_with_data(_Iterator __iter, _Data __data) + : __iter_(std::move(__iter)), __data_(std::move(__data)) {} + + constexpr _LIBCPP_HIDE_FROM_ABI _Iterator __get_iter() const { return __iter_; } + + constexpr _LIBCPP_HIDE_FROM_ABI _Data __get_data() && { return std::move(__data_); } + + friend constexpr _LIBCPP_HIDE_FROM_ABI bool + operator==(const __iterator_with_data& __lhs, const __iterator_with_data& __rhs) { + return __lhs.__iter_ == __rhs.__iter_; + } + + constexpr _LIBCPP_HIDE_FROM_ABI __iterator_with_data& operator++() { + ++__iter_; + return *this; + } + + constexpr _LIBCPP_HIDE_FROM_ABI __iterator_with_data operator++(int) { + auto __tmp = *this; + __iter_++; + return __tmp; + } + + constexpr _LIBCPP_HIDE_FROM_ABI __iterator_with_data& operator--() + requires bidirectional_iterator<_Iterator> + { + --__iter_; + return *this; + } + + constexpr _LIBCPP_HIDE_FROM_ABI __iterator_with_data operator--(int) + requires bidirectional_iterator<_Iterator> + { + auto __tmp = *this; + --__iter_; + return __tmp; + } + + constexpr _LIBCPP_HIDE_FROM_ABI iter_reference_t<_Iterator> operator*() const { return *__iter_; } + + _LIBCPP_HIDE_FROM_ABI friend constexpr iter_rvalue_reference_t<_Iterator> + iter_move(const __iterator_with_data& __iter) noexcept(noexcept(ranges::iter_move(__iter.__iter_))) { + return ranges::iter_move(__iter.__iter_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void + iter_swap(const __iterator_with_data& __lhs, + const __iterator_with_data& __rhs) noexcept(noexcept(ranges::iter_swap(__lhs.__iter_, __rhs.__iter_))) + requires indirectly_swappable<_Iterator> + { + return ranges::iter_swap(__lhs.__data_, __rhs.__iter_); + } +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_ITERATOR_WITH_DATA_H diff --git a/libcxx/include/__cxx03/__iterator/mergeable.h b/libcxx/include/__cxx03/__iterator/mergeable.h new file mode 100644 index 0000000000000000000000000000000000000000..7976d751095e581d815d0205a6d2a197816c80c6 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/mergeable.h @@ -0,0 +1,42 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_MERGEABLE_H +#define _LIBCPP___ITERATOR_MERGEABLE_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/projected.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +concept mergeable = + input_iterator<_Input1> && input_iterator<_Input2> && weakly_incrementable<_Output> && + indirectly_copyable<_Input1, _Output> && indirectly_copyable<_Input2, _Output> && + indirect_strict_weak_order<_Comp, projected<_Input1, _Proj1>, projected<_Input2, _Proj2>>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_MERGEABLE_H diff --git a/libcxx/include/__cxx03/__iterator/move_iterator.h b/libcxx/include/__cxx03/__iterator/move_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..a1c53e9bd2b596e69572c420a694a951d578a20b --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/move_iterator.h @@ -0,0 +1,347 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_MOVE_ITERATOR_H +#define _LIBCPP___ITERATOR_MOVE_ITERATOR_H + +#include <__compare/compare_three_way_result.h> +#include <__compare/three_way_comparable.h> +#include <__concepts/assignable.h> +#include <__concepts/convertible_to.h> +#include <__concepts/derived_from.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iter_move.h> +#include <__iterator/iter_swap.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/move_sentinel.h> +#include <__iterator/readable_traits.h> +#include <__type_traits/conditional.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_assignable.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/is_same.h> +#include <__type_traits/remove_reference.h> +#include <__utility/declval.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 +template +struct __move_iter_category_base {}; + +template + requires requires { typename iterator_traits<_Iter>::iterator_category; } +struct __move_iter_category_base<_Iter> { + using iterator_category = + _If< derived_from::iterator_category, random_access_iterator_tag>, + random_access_iterator_tag, + typename iterator_traits<_Iter>::iterator_category >; +}; + +template +concept __move_iter_comparable = requires { + { std::declval() == std::declval<_Sent>() } -> convertible_to; +}; +#endif // _LIBCPP_STD_VER >= 20 + +template +class _LIBCPP_TEMPLATE_VIS move_iterator +#if _LIBCPP_STD_VER >= 20 + : public __move_iter_category_base<_Iter> +#endif +{ +#if _LIBCPP_STD_VER >= 20 + +private: + _LIBCPP_HIDE_FROM_ABI static constexpr auto __get_iter_concept() { + if constexpr (random_access_iterator<_Iter>) { + return random_access_iterator_tag{}; + } else if constexpr (bidirectional_iterator<_Iter>) { + return bidirectional_iterator_tag{}; + } else if constexpr (forward_iterator<_Iter>) { + return forward_iterator_tag{}; + } else { + return input_iterator_tag{}; + } + } +#endif // _LIBCPP_STD_VER >= 20 + +public: +#if _LIBCPP_STD_VER >= 20 + using iterator_type = _Iter; + using iterator_concept = decltype(__get_iter_concept()); + // iterator_category is inherited and not always present + using value_type = iter_value_t<_Iter>; + using difference_type = iter_difference_t<_Iter>; + using pointer = _Iter; + using reference = iter_rvalue_reference_t<_Iter>; +#else + typedef _Iter iterator_type; + typedef _If< __has_random_access_iterator_category<_Iter>::value, + random_access_iterator_tag, + typename iterator_traits<_Iter>::iterator_category > + iterator_category; + typedef typename iterator_traits::value_type value_type; + typedef typename iterator_traits::difference_type difference_type; + typedef iterator_type pointer; + + typedef typename iterator_traits::reference __reference; + typedef __conditional_t::value, __libcpp_remove_reference_t<__reference>&&, __reference> + reference; +#endif // _LIBCPP_STD_VER >= 20 + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 explicit move_iterator(_Iter __i) : __current_(std::move(__i)) {} + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 move_iterator& operator++() { + ++__current_; + return *this; + } + + _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 pointer operator->() const { + return __current_; + } + +#if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI constexpr move_iterator() + requires is_constructible_v<_Iter> + : __current_() {} + + template + requires(!_IsSame<_Up, _Iter>::value) && convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr move_iterator(const move_iterator<_Up>& __u) : __current_(__u.base()) {} + + template + requires(!_IsSame<_Up, _Iter>::value) && convertible_to && assignable_from<_Iter&, const _Up&> + _LIBCPP_HIDE_FROM_ABI constexpr move_iterator& operator=(const move_iterator<_Up>& __u) { + __current_ = __u.base(); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Iter& base() const& noexcept { return __current_; } + _LIBCPP_HIDE_FROM_ABI constexpr _Iter base() && { return std::move(__current_); } + + _LIBCPP_HIDE_FROM_ABI constexpr reference operator*() const { return ranges::iter_move(__current_); } + _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](difference_type __n) const { + return ranges::iter_move(__current_ + __n); + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto operator++(int) + requires forward_iterator<_Iter> + { + move_iterator __tmp(*this); + ++__current_; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++__current_; } +#else + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 move_iterator() : __current_() {} + + template ::value && is_convertible::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 move_iterator(const move_iterator<_Up>& __u) + : __current_(__u.base()) {} + + template ::value && is_convertible::value && + is_assignable<_Iter&, const _Up&>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 move_iterator& operator=(const move_iterator<_Up>& __u) { + __current_ = __u.base(); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _Iter base() const { return __current_; } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference operator*() const { + return static_cast(*__current_); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference operator[](difference_type __n) const { + return static_cast(__current_[__n]); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 move_iterator operator++(int) { + move_iterator __tmp(*this); + ++__current_; + return __tmp; + } +#endif // _LIBCPP_STD_VER >= 20 + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 move_iterator& operator--() { + --__current_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 move_iterator operator--(int) { + move_iterator __tmp(*this); + --__current_; + return __tmp; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 move_iterator operator+(difference_type __n) const { + return move_iterator(__current_ + __n); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 move_iterator& operator+=(difference_type __n) { + __current_ += __n; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 move_iterator operator-(difference_type __n) const { + return move_iterator(__current_ - __n); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 move_iterator& operator-=(difference_type __n) { + __current_ -= __n; + return *this; + } + +#if _LIBCPP_STD_VER >= 20 + template _Sent> + friend _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const move_iterator& __x, const move_sentinel<_Sent>& __y) + requires __move_iter_comparable<_Iter, _Sent> + { + return __x.base() == __y.base(); + } + + template _Sent> + friend _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Iter> + operator-(const move_sentinel<_Sent>& __x, const move_iterator& __y) { + return __x.base() - __y.base(); + } + + template _Sent> + friend _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Iter> + operator-(const move_iterator& __x, const move_sentinel<_Sent>& __y) { + return __x.base() - __y.base(); + } + + friend _LIBCPP_HIDE_FROM_ABI constexpr iter_rvalue_reference_t<_Iter> + iter_move(const move_iterator& __i) noexcept(noexcept(ranges::iter_move(__i.__current_))) { + return ranges::iter_move(__i.__current_); + } + + template _It2> + friend _LIBCPP_HIDE_FROM_ABI constexpr void + iter_swap(const move_iterator& __x, + const move_iterator<_It2>& __y) noexcept(noexcept(ranges::iter_swap(__x.__current_, __y.__current_))) { + return ranges::iter_swap(__x.__current_, __y.__current_); + } +#endif // _LIBCPP_STD_VER >= 20 + +private: + template + friend class move_iterator; + + _Iter __current_; +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(move_iterator); + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 bool +operator==(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y) { + return __x.base() == __y.base(); +} + +#if _LIBCPP_STD_VER <= 17 +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 bool +operator!=(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y) { + return __x.base() != __y.base(); +} +#endif // _LIBCPP_STD_VER <= 17 + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 bool +operator<(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y) { + return __x.base() < __y.base(); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 bool +operator>(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y) { + return __x.base() > __y.base(); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 bool +operator<=(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y) { + return __x.base() <= __y.base(); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 bool +operator>=(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y) { + return __x.base() >= __y.base(); +} + +#if _LIBCPP_STD_VER >= 20 +template _Iter2> +inline _LIBCPP_HIDE_FROM_ABI constexpr auto +operator<=>(const move_iterator<_Iter1>& __x, + const move_iterator<_Iter2>& __y) -> compare_three_way_result_t<_Iter1, _Iter2> { + return __x.base() <=> __y.base(); +} +#endif // _LIBCPP_STD_VER >= 20 + +#ifndef _LIBCPP_CXX03_LANG +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto +operator-(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y) -> decltype(__x.base() - __y.base()) { + return __x.base() - __y.base(); +} +#else +template +inline _LIBCPP_HIDE_FROM_ABI typename move_iterator<_Iter1>::difference_type +operator-(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y) { + return __x.base() - __y.base(); +} +#endif // !_LIBCPP_CXX03_LANG + +#if _LIBCPP_STD_VER >= 20 +template +inline _LIBCPP_HIDE_FROM_ABI constexpr move_iterator<_Iter> +operator+(iter_difference_t<_Iter> __n, const move_iterator<_Iter>& __x) + requires requires { + { __x.base() + __n } -> same_as<_Iter>; + } +{ + return __x + __n; +} +#else +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 move_iterator<_Iter> +operator+(typename move_iterator<_Iter>::difference_type __n, const move_iterator<_Iter>& __x) { + return move_iterator<_Iter>(__x.base() + __n); +} +#endif // _LIBCPP_STD_VER >= 20 + +#if _LIBCPP_STD_VER >= 20 +template + requires(!sized_sentinel_for<_Iter1, _Iter2>) +inline constexpr bool disable_sized_sentinel_for, move_iterator<_Iter2>> = true; +#endif // _LIBCPP_STD_VER >= 20 + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 move_iterator<_Iter> make_move_iterator(_Iter __i) { + return move_iterator<_Iter>(std::move(__i)); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_MOVE_ITERATOR_H diff --git a/libcxx/include/__cxx03/__iterator/move_sentinel.h b/libcxx/include/__cxx03/__iterator/move_sentinel.h new file mode 100644 index 0000000000000000000000000000000000000000..4a2a09ef0611d248fe598646abe1e4201a817237 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/move_sentinel.h @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_MOVE_SENTINEL_H +#define _LIBCPP___ITERATOR_MOVE_SENTINEL_H + +#include <__concepts/assignable.h> +#include <__concepts/convertible_to.h> +#include <__concepts/semiregular.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +class _LIBCPP_TEMPLATE_VIS move_sentinel { +public: + _LIBCPP_HIDE_FROM_ABI move_sentinel() = default; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit move_sentinel(_Sent __s) : __last_(std::move(__s)) {} + + template + requires convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr move_sentinel(const move_sentinel<_S2>& __s) : __last_(__s.base()) {} + + template + requires assignable_from<_Sent&, const _S2&> + _LIBCPP_HIDE_FROM_ABI constexpr move_sentinel& operator=(const move_sentinel<_S2>& __s) { + __last_ = __s.base(); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr _Sent base() const { return __last_; } + +private: + _Sent __last_ = _Sent(); +}; + +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(move_sentinel); + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ITERATOR_MOVE_SENTINEL_H diff --git a/libcxx/include/__cxx03/__iterator/next.h b/libcxx/include/__cxx03/__iterator/next.h new file mode 100644 index 0000000000000000000000000000000000000000..21d3688ad9eb600f2e5a89a39a047103972f261b --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/next.h @@ -0,0 +1,83 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_NEXT_H +#define _LIBCPP___ITERATOR_NEXT_H + +#include <__assert> +#include <__config> +#include <__iterator/advance.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/enable_if.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter +next(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = 1) { + // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation. + // Note that this check duplicates the similar check in `std::advance`. + _LIBCPP_ASSERT_PEDANTIC(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value, + "Attempt to next(it, n) with negative n on a non-bidirectional iterator"); + + std::advance(__x, __n); + return __x; +} + +#if _LIBCPP_STD_VER >= 20 + +// [range.iter.op.next] + +namespace ranges { +namespace __next { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x) const { + ++__x; + return __x; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x, iter_difference_t<_Ip> __n) const { + ranges::advance(__x, __n); + return __x; + } + + template _Sp> + _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x, _Sp __bound_sentinel) const { + ranges::advance(__x, __bound_sentinel); + return __x; + } + + template _Sp> + _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x, iter_difference_t<_Ip> __n, _Sp __bound_sentinel) const { + ranges::advance(__x, __n, __bound_sentinel); + return __x; + } +}; + +} // namespace __next + +inline namespace __cpo { +inline constexpr auto next = __next::__fn{}; +} // namespace __cpo +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_NEXT_H diff --git a/libcxx/include/__cxx03/__iterator/ostream_iterator.h b/libcxx/include/__cxx03/__iterator/ostream_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..05697e62d9dcb9751e425af65d676d1817cb121d --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/ostream_iterator.h @@ -0,0 +1,75 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_OSTREAM_ITERATOR_H +#define _LIBCPP___ITERATOR_OSTREAM_ITERATOR_H + +#include <__config> +#include <__fwd/ostream.h> +#include <__fwd/string.h> +#include <__iterator/iterator.h> +#include <__iterator/iterator_traits.h> +#include <__memory/addressof.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +template > +class _LIBCPP_TEMPLATE_VIS ostream_iterator +#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) + : public iterator +#endif +{ + _LIBCPP_SUPPRESS_DEPRECATED_POP + +public: + typedef output_iterator_tag iterator_category; + typedef void value_type; +#if _LIBCPP_STD_VER >= 20 + typedef ptrdiff_t difference_type; +#else + typedef void difference_type; +#endif + typedef void pointer; + typedef void reference; + typedef _CharT char_type; + typedef _Traits traits_type; + typedef basic_ostream<_CharT, _Traits> ostream_type; + +private: + ostream_type* __out_stream_; + const char_type* __delim_; + +public: + _LIBCPP_HIDE_FROM_ABI ostream_iterator(ostream_type& __s) _NOEXCEPT + : __out_stream_(std::addressof(__s)), + __delim_(nullptr) {} + _LIBCPP_HIDE_FROM_ABI ostream_iterator(ostream_type& __s, const _CharT* __delimiter) _NOEXCEPT + : __out_stream_(std::addressof(__s)), + __delim_(__delimiter) {} + _LIBCPP_HIDE_FROM_ABI ostream_iterator& operator=(const _Tp& __value) { + *__out_stream_ << __value; + if (__delim_) + *__out_stream_ << __delim_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI ostream_iterator& operator*() { return *this; } + _LIBCPP_HIDE_FROM_ABI ostream_iterator& operator++() { return *this; } + _LIBCPP_HIDE_FROM_ABI ostream_iterator& operator++(int) { return *this; } +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_OSTREAM_ITERATOR_H diff --git a/libcxx/include/__cxx03/__iterator/ostreambuf_iterator.h b/libcxx/include/__cxx03/__iterator/ostreambuf_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..dda0094dc3f5351a6e004d13ed92c63ae4140443 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/ostreambuf_iterator.h @@ -0,0 +1,72 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_OSTREAMBUF_ITERATOR_H +#define _LIBCPP___ITERATOR_OSTREAMBUF_ITERATOR_H + +#include <__config> +#include <__iterator/iterator.h> +#include <__iterator/iterator_traits.h> +#include +#include // for forward declaration of basic_streambuf + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +template +class _LIBCPP_TEMPLATE_VIS ostreambuf_iterator +#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) + : public iterator +#endif +{ + _LIBCPP_SUPPRESS_DEPRECATED_POP + +public: + typedef output_iterator_tag iterator_category; + typedef void value_type; +#if _LIBCPP_STD_VER >= 20 + typedef ptrdiff_t difference_type; +#else + typedef void difference_type; +#endif + typedef void pointer; + typedef void reference; + typedef _CharT char_type; + typedef _Traits traits_type; + typedef basic_streambuf<_CharT, _Traits> streambuf_type; + typedef basic_ostream<_CharT, _Traits> ostream_type; + +private: + streambuf_type* __sbuf_; + +public: + _LIBCPP_HIDE_FROM_ABI ostreambuf_iterator(ostream_type& __s) _NOEXCEPT : __sbuf_(__s.rdbuf()) {} + _LIBCPP_HIDE_FROM_ABI ostreambuf_iterator(streambuf_type* __s) _NOEXCEPT : __sbuf_(__s) {} + _LIBCPP_HIDE_FROM_ABI ostreambuf_iterator& operator=(_CharT __c) { + if (__sbuf_ && traits_type::eq_int_type(__sbuf_->sputc(__c), traits_type::eof())) + __sbuf_ = nullptr; + return *this; + } + _LIBCPP_HIDE_FROM_ABI ostreambuf_iterator& operator*() { return *this; } + _LIBCPP_HIDE_FROM_ABI ostreambuf_iterator& operator++() { return *this; } + _LIBCPP_HIDE_FROM_ABI ostreambuf_iterator& operator++(int) { return *this; } + _LIBCPP_HIDE_FROM_ABI bool failed() const _NOEXCEPT { return __sbuf_ == nullptr; } + + template + friend _LIBCPP_HIDE_FROM_ABI ostreambuf_iterator<_Ch, _Tr> __pad_and_output( + ostreambuf_iterator<_Ch, _Tr> __s, const _Ch* __ob, const _Ch* __op, const _Ch* __oe, ios_base& __iob, _Ch __fl); +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_OSTREAMBUF_ITERATOR_H diff --git a/libcxx/include/__cxx03/__iterator/permutable.h b/libcxx/include/__cxx03/__iterator/permutable.h new file mode 100644 index 0000000000000000000000000000000000000000..f65ba3bfbbaad44c47a475ca2bddde205bd17cfb --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/permutable.h @@ -0,0 +1,34 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_PERMUTABLE_H +#define _LIBCPP___ITERATOR_PERMUTABLE_H + +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/iter_swap.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +concept permutable = + forward_iterator<_Iterator> && indirectly_movable_storable<_Iterator, _Iterator> && + indirectly_swappable<_Iterator, _Iterator>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_PERMUTABLE_H diff --git a/libcxx/include/__cxx03/__iterator/prev.h b/libcxx/include/__cxx03/__iterator/prev.h new file mode 100644 index 0000000000000000000000000000000000000000..2f0e6a088edb366edbc17448b9c0ab9f8768e1c2 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/prev.h @@ -0,0 +1,76 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_PREV_H +#define _LIBCPP___ITERATOR_PREV_H + +#include <__assert> +#include <__config> +#include <__iterator/advance.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iterator_traits.h> +#include <__type_traits/enable_if.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter +prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = 1) { + // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation. + // Note that this check duplicates the similar check in `std::advance`. + _LIBCPP_ASSERT_PEDANTIC(__n <= 0 || __has_bidirectional_iterator_category<_InputIter>::value, + "Attempt to prev(it, n) with a positive n on a non-bidirectional iterator"); + std::advance(__x, -__n); + return __x; +} + +#if _LIBCPP_STD_VER >= 20 + +// [range.iter.op.prev] + +namespace ranges { +namespace __prev { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x) const { + --__x; + return __x; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x, iter_difference_t<_Ip> __n) const { + ranges::advance(__x, -__n); + return __x; + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x, iter_difference_t<_Ip> __n, _Ip __bound_iter) const { + ranges::advance(__x, -__n, __bound_iter); + return __x; + } +}; + +} // namespace __prev + +inline namespace __cpo { +inline constexpr auto prev = __prev::__fn{}; +} // namespace __cpo +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_PREV_H diff --git a/libcxx/include/__cxx03/__iterator/projected.h b/libcxx/include/__cxx03/__iterator/projected.h new file mode 100644 index 0000000000000000000000000000000000000000..463d07b0d33c2d0ccaf980d1310bd55f5353a9fb --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/projected.h @@ -0,0 +1,53 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_PROJECTED_H +#define _LIBCPP___ITERATOR_PROJECTED_H + +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> // iter_difference_t +#include <__type_traits/remove_cvref.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +struct __projected_impl { + struct __type { + using value_type = remove_cvref_t>; + indirect_result_t<_Proj&, _It> operator*() const; // not defined + }; +}; + +template +struct __projected_impl<_It, _Proj> { + struct __type { + using value_type = remove_cvref_t>; + using difference_type = iter_difference_t<_It>; + indirect_result_t<_Proj&, _It> operator*() const; // not defined + }; +}; + +// Note that we implement std::projected in a way that satisfies P2538R1 even in standard +// modes before C++26 to avoid breaking the ABI between standard modes (even though ABI +// breaks with std::projected are expected to have essentially no impact). +template _Proj> +using projected = typename __projected_impl<_It, _Proj>::__type; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_PROJECTED_H diff --git a/libcxx/include/__cxx03/__iterator/ranges_iterator_traits.h b/libcxx/include/__cxx03/__iterator/ranges_iterator_traits.h new file mode 100644 index 0000000000000000000000000000000000000000..859e7082048ac1ed830deb682e6c8f78ab4cf4f1 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/ranges_iterator_traits.h @@ -0,0 +1,40 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_RANGES_ITERATOR_TRAITS_H +#define _LIBCPP___ITERATOR_RANGES_ITERATOR_TRAITS_H + +#include <__config> +#include <__fwd/pair.h> +#include <__ranges/concepts.h> +#include <__type_traits/remove_const.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template +using __range_key_type = __remove_const_t::first_type>; + +template +using __range_mapped_type = typename ranges::range_value_t<_Range>::second_type; + +template +using __range_to_alloc_type = + pair::first_type, typename ranges::range_value_t<_Range>::second_type>; + +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_RANGES_ITERATOR_TRAITS_H diff --git a/libcxx/include/__cxx03/__iterator/readable_traits.h b/libcxx/include/__cxx03/__iterator/readable_traits.h new file mode 100644 index 0000000000000000000000000000000000000000..25e74567fff11dd93782468170c84a3a24c18452 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/readable_traits.h @@ -0,0 +1,81 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_READABLE_TRAITS_H +#define _LIBCPP___ITERATOR_READABLE_TRAITS_H + +#include <__concepts/same_as.h> +#include <__config> +#include <__type_traits/conditional.h> +#include <__type_traits/is_array.h> +#include <__type_traits/is_object.h> +#include <__type_traits/is_primary_template.h> +#include <__type_traits/remove_cv.h> +#include <__type_traits/remove_cvref.h> +#include <__type_traits/remove_extent.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// [readable.traits] +template +struct __cond_value_type {}; + +template + requires is_object_v<_Tp> +struct __cond_value_type<_Tp> { + using value_type = remove_cv_t<_Tp>; +}; + +template +concept __has_member_value_type = requires { typename _Tp::value_type; }; + +template +concept __has_member_element_type = requires { typename _Tp::element_type; }; + +template +struct indirectly_readable_traits {}; + +template + requires is_array_v<_Ip> +struct indirectly_readable_traits<_Ip> { + using value_type = remove_cv_t>; +}; + +template +struct indirectly_readable_traits : indirectly_readable_traits<_Ip> {}; + +template +struct indirectly_readable_traits<_Tp*> : __cond_value_type<_Tp> {}; + +template <__has_member_value_type _Tp> +struct indirectly_readable_traits<_Tp> : __cond_value_type {}; + +template <__has_member_element_type _Tp> +struct indirectly_readable_traits<_Tp> : __cond_value_type {}; + +template <__has_member_value_type _Tp> + requires __has_member_element_type<_Tp> +struct indirectly_readable_traits<_Tp> {}; + +template <__has_member_value_type _Tp> + requires __has_member_element_type<_Tp> && + same_as, remove_cv_t> +struct indirectly_readable_traits<_Tp> : __cond_value_type {}; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_READABLE_TRAITS_H diff --git a/libcxx/include/__cxx03/__iterator/reverse_access.h b/libcxx/include/__cxx03/__iterator/reverse_access.h new file mode 100644 index 0000000000000000000000000000000000000000..54d7270b04a53784a2a791fc97f3bdbe86e0ada0 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/reverse_access.h @@ -0,0 +1,80 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_REVERSE_ACCESS_H +#define _LIBCPP___ITERATOR_REVERSE_ACCESS_H + +#include <__config> +#include <__iterator/reverse_iterator.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 14 + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator<_Tp*> rbegin(_Tp (&__array)[_Np]) { + return reverse_iterator<_Tp*>(__array + _Np); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator<_Tp*> rend(_Tp (&__array)[_Np]) { + return reverse_iterator<_Tp*>(__array); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator rbegin(initializer_list<_Ep> __il) { + return reverse_iterator(__il.end()); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator rend(initializer_list<_Ep> __il) { + return reverse_iterator(__il.begin()); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto rbegin(_Cp& __c) -> decltype(__c.rbegin()) { + return __c.rbegin(); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto rbegin(const _Cp& __c) -> decltype(__c.rbegin()) { + return __c.rbegin(); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto rend(_Cp& __c) -> decltype(__c.rend()) { + return __c.rend(); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto rend(const _Cp& __c) -> decltype(__c.rend()) { + return __c.rend(); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto crbegin(const _Cp& __c) -> decltype(std::rbegin(__c)) { + return std::rbegin(__c); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto crend(const _Cp& __c) -> decltype(std::rend(__c)) { + return std::rend(__c); +} + +#endif // _LIBCPP_STD_VER >= 14 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_REVERSE_ACCESS_H diff --git a/libcxx/include/__cxx03/__iterator/reverse_iterator.h b/libcxx/include/__cxx03/__iterator/reverse_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..50c0f21eaa286b0f4aa4aa0216d45e68dc73b6ba --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/reverse_iterator.h @@ -0,0 +1,346 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_REVERSE_ITERATOR_H +#define _LIBCPP___ITERATOR_REVERSE_ITERATOR_H + +#include <__algorithm/unwrap_iter.h> +#include <__compare/compare_three_way_result.h> +#include <__compare/three_way_comparable.h> +#include <__concepts/convertible_to.h> +#include <__config> +#include <__iterator/advance.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iter_move.h> +#include <__iterator/iter_swap.h> +#include <__iterator/iterator.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/prev.h> +#include <__iterator/readable_traits.h> +#include <__iterator/segmented_iterator.h> +#include <__memory/addressof.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/subrange.h> +#include <__type_traits/conditional.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_assignable.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_pointer.h> +#include <__type_traits/is_same.h> +#include <__utility/declval.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +template +class _LIBCPP_TEMPLATE_VIS reverse_iterator +#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) + : public iterator::iterator_category, + typename iterator_traits<_Iter>::value_type, + typename iterator_traits<_Iter>::difference_type, + typename iterator_traits<_Iter>::pointer, + typename iterator_traits<_Iter>::reference> +#endif +{ + _LIBCPP_SUPPRESS_DEPRECATED_POP + +private: +#ifndef _LIBCPP_ABI_NO_ITERATOR_BASES + _Iter __t_; // no longer used as of LWG #2360, not removed due to ABI break +#endif + +#if _LIBCPP_STD_VER >= 20 + static_assert(__has_bidirectional_iterator_category<_Iter>::value || bidirectional_iterator<_Iter>, + "reverse_iterator requires It to be a bidirectional iterator."); +#endif // _LIBCPP_STD_VER >= 20 + +protected: + _Iter current; + +public: + using iterator_type = _Iter; + + using iterator_category = + _If<__has_random_access_iterator_category<_Iter>::value, + random_access_iterator_tag, + typename iterator_traits<_Iter>::iterator_category>; + using pointer = typename iterator_traits<_Iter>::pointer; +#if _LIBCPP_STD_VER >= 20 + using iterator_concept = _If, random_access_iterator_tag, bidirectional_iterator_tag>; + using value_type = iter_value_t<_Iter>; + using difference_type = iter_difference_t<_Iter>; + using reference = iter_reference_t<_Iter>; +#else + using value_type = typename iterator_traits<_Iter>::value_type; + using difference_type = typename iterator_traits<_Iter>::difference_type; + using reference = typename iterator_traits<_Iter>::reference; +#endif + +#ifndef _LIBCPP_ABI_NO_ITERATOR_BASES + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator() : __t_(), current() {} + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 explicit reverse_iterator(_Iter __x) : __t_(__x), current(__x) {} + + template ::value && is_convertible<_Up const&, _Iter>::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator(const reverse_iterator<_Up>& __u) + : __t_(__u.base()), current(__u.base()) {} + + template ::value && is_convertible<_Up const&, _Iter>::value && + is_assignable<_Iter&, _Up const&>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator& operator=(const reverse_iterator<_Up>& __u) { + __t_ = current = __u.base(); + return *this; + } +#else + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator() : current() {} + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 explicit reverse_iterator(_Iter __x) : current(__x) {} + + template ::value && is_convertible<_Up const&, _Iter>::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator(const reverse_iterator<_Up>& __u) + : current(__u.base()) {} + + template ::value && is_convertible<_Up const&, _Iter>::value && + is_assignable<_Iter&, _Up const&>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator& operator=(const reverse_iterator<_Up>& __u) { + current = __u.base(); + return *this; + } +#endif + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _Iter base() const { return current; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference operator*() const { + _Iter __tmp = current; + return *--__tmp; + } + +#if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI constexpr pointer operator->() const + requires is_pointer_v<_Iter> || requires(const _Iter __i) { __i.operator->(); } + { + if constexpr (is_pointer_v<_Iter>) { + return std::prev(current); + } else { + return std::prev(current).operator->(); + } + } +#else + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 pointer operator->() const { return std::addressof(operator*()); } +#endif // _LIBCPP_STD_VER >= 20 + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator& operator++() { + --current; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator operator++(int) { + reverse_iterator __tmp(*this); + --current; + return __tmp; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator& operator--() { + ++current; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator operator--(int) { + reverse_iterator __tmp(*this); + ++current; + return __tmp; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator operator+(difference_type __n) const { + return reverse_iterator(current - __n); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator& operator+=(difference_type __n) { + current -= __n; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator operator-(difference_type __n) const { + return reverse_iterator(current + __n); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator& operator-=(difference_type __n) { + current += __n; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference operator[](difference_type __n) const { + return *(*this + __n); + } + +#if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI friend constexpr iter_rvalue_reference_t<_Iter> iter_move(const reverse_iterator& __i) noexcept( + is_nothrow_copy_constructible_v<_Iter> && noexcept(ranges::iter_move(--std::declval<_Iter&>()))) { + auto __tmp = __i.base(); + return ranges::iter_move(--__tmp); + } + + template _Iter2> + _LIBCPP_HIDE_FROM_ABI friend constexpr void + iter_swap(const reverse_iterator& __x, const reverse_iterator<_Iter2>& __y) noexcept( + is_nothrow_copy_constructible_v<_Iter> && is_nothrow_copy_constructible_v<_Iter2> && + noexcept(ranges::iter_swap(--std::declval<_Iter&>(), --std::declval<_Iter2&>()))) { + auto __xtmp = __x.base(); + auto __ytmp = __y.base(); + ranges::iter_swap(--__xtmp, --__ytmp); + } +#endif // _LIBCPP_STD_VER >= 20 +}; + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 bool +operator==(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) +#if _LIBCPP_STD_VER >= 20 + requires requires { + { __x.base() == __y.base() } -> convertible_to; + } +#endif // _LIBCPP_STD_VER >= 20 +{ + return __x.base() == __y.base(); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 bool +operator<(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) +#if _LIBCPP_STD_VER >= 20 + requires requires { + { __x.base() > __y.base() } -> convertible_to; + } +#endif // _LIBCPP_STD_VER >= 20 +{ + return __x.base() > __y.base(); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 bool +operator!=(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) +#if _LIBCPP_STD_VER >= 20 + requires requires { + { __x.base() != __y.base() } -> convertible_to; + } +#endif // _LIBCPP_STD_VER >= 20 +{ + return __x.base() != __y.base(); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 bool +operator>(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) +#if _LIBCPP_STD_VER >= 20 + requires requires { + { __x.base() < __y.base() } -> convertible_to; + } +#endif // _LIBCPP_STD_VER >= 20 +{ + return __x.base() < __y.base(); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 bool +operator>=(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) +#if _LIBCPP_STD_VER >= 20 + requires requires { + { __x.base() <= __y.base() } -> convertible_to; + } +#endif // _LIBCPP_STD_VER >= 20 +{ + return __x.base() <= __y.base(); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 bool +operator<=(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) +#if _LIBCPP_STD_VER >= 20 + requires requires { + { __x.base() >= __y.base() } -> convertible_to; + } +#endif // _LIBCPP_STD_VER >= 20 +{ + return __x.base() >= __y.base(); +} + +#if _LIBCPP_STD_VER >= 20 +template _Iter2> +_LIBCPP_HIDE_FROM_ABI constexpr compare_three_way_result_t<_Iter1, _Iter2> +operator<=>(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) { + return __y.base() <=> __x.base(); +} +#endif // _LIBCPP_STD_VER >= 20 + +#ifndef _LIBCPP_CXX03_LANG +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 auto +operator-(const reverse_iterator<_Iter1>& __x, + const reverse_iterator<_Iter2>& __y) -> decltype(__y.base() - __x.base()) { + return __y.base() - __x.base(); +} +#else +template +inline _LIBCPP_HIDE_FROM_ABI typename reverse_iterator<_Iter1>::difference_type +operator-(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) { + return __y.base() - __x.base(); +} +#endif + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator<_Iter> +operator+(typename reverse_iterator<_Iter>::difference_type __n, const reverse_iterator<_Iter>& __x) { + return reverse_iterator<_Iter>(__x.base() - __n); +} + +#if _LIBCPP_STD_VER >= 20 +template + requires(!sized_sentinel_for<_Iter1, _Iter2>) +inline constexpr bool disable_sized_sentinel_for, reverse_iterator<_Iter2>> = true; +#endif // _LIBCPP_STD_VER >= 20 + +#if _LIBCPP_STD_VER >= 14 +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator<_Iter> make_reverse_iterator(_Iter __i) { + return reverse_iterator<_Iter>(__i); +} +#endif + +#if _LIBCPP_STD_VER >= 20 +template +_LIBCPP_HIDE_FROM_ABI constexpr ranges::subrange>, + reverse_iterator>> +__reverse_range(_Range&& __range) { + auto __first = ranges::begin(__range); + return {std::make_reverse_iterator(ranges::next(__first, ranges::end(__range))), std::make_reverse_iterator(__first)}; +} +#endif + +template +struct __unwrap_iter_impl >, __b> { + using _UnwrappedIter = decltype(__unwrap_iter_impl<_Iter>::__unwrap(std::declval<_Iter>())); + using _ReverseWrapper = reverse_iterator >; + + static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ReverseWrapper + __rewrap(_ReverseWrapper __orig_iter, _UnwrappedIter __unwrapped_iter) { + return _ReverseWrapper( + reverse_iterator<_Iter>(__unwrap_iter_impl<_Iter>::__rewrap(__orig_iter.base().base(), __unwrapped_iter))); + } + + static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _UnwrappedIter __unwrap(_ReverseWrapper __i) _NOEXCEPT { + return __unwrap_iter_impl<_Iter>::__unwrap(__i.base().base()); + } +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_REVERSE_ITERATOR_H diff --git a/libcxx/include/__cxx03/__iterator/segmented_iterator.h b/libcxx/include/__cxx03/__iterator/segmented_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..f3cd1e5fa1f5da2e03800d96e9e17fdfdef50811 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/segmented_iterator.h @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___SEGMENTED_ITERATOR_H +#define _LIBCPP___SEGMENTED_ITERATOR_H + +// Segmented iterators are iterators over (not necessarily contiguous) sub-ranges. +// +// For example, std::deque stores its data into multiple blocks of contiguous memory, +// which are not stored contiguously themselves. The concept of segmented iterators +// allows algorithms to operate over these multi-level iterators natively, opening the +// door to various optimizations. See http://lafstern.org/matt/segmented.pdf for details. +// +// If __segmented_iterator_traits can be instantiated, the following functions and associated types must be provided: +// - Traits::__local_iterator +// The type of iterators used to iterate inside a segment. +// +// - Traits::__segment_iterator +// The type of iterators used to iterate over segments. +// Segment iterators can be forward iterators or bidirectional iterators, depending on the +// underlying data structure. +// +// - static __segment_iterator Traits::__segment(It __it) +// Returns an iterator to the segment that the provided iterator is in. +// +// - static __local_iterator Traits::__local(It __it) +// Returns the local iterator pointing to the element that the provided iterator points to. +// +// - static __local_iterator Traits::__begin(__segment_iterator __it) +// Returns the local iterator to the beginning of the segment that the provided iterator is pointing into. +// +// - static __local_iterator Traits::__end(__segment_iterator __it) +// Returns the one-past-the-end local iterator to the segment that the provided iterator is pointing into. +// +// - static It Traits::__compose(__segment_iterator, __local_iterator) +// Returns the iterator composed of the segment iterator and local iterator. + +#include <__config> +#include <__type_traits/integral_constant.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __segmented_iterator_traits; +/* exposition-only: +{ + using __segment_iterator = ...; + using __local_iterator = ...; + + static __segment_iterator __segment(_Iterator); + static __local_iterator __local(_Iterator); + static __local_iterator __begin(__segment_iterator); + static __local_iterator __end(__segment_iterator); + static _Iterator __compose(__segment_iterator, __local_iterator); +}; +*/ + +template +struct __has_specialization : false_type {}; + +template +struct __has_specialization<_Tp, sizeof(_Tp) * 0> : true_type {}; + +template +using __is_segmented_iterator = __has_specialization<__segmented_iterator_traits<_Iterator> >; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___SEGMENTED_ITERATOR_H diff --git a/libcxx/include/__cxx03/__iterator/size.h b/libcxx/include/__cxx03/__iterator/size.h new file mode 100644 index 0000000000000000000000000000000000000000..876e6963f77d91eda9a6ace89372af3270062d18 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/size.h @@ -0,0 +1,59 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_SIZE_H +#define _LIBCPP___ITERATOR_SIZE_H + +#include <__config> +#include <__type_traits/common_type.h> +#include <__type_traits/make_signed.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +template +_LIBCPP_HIDE_FROM_ABI constexpr auto size(const _Cont& __c) noexcept(noexcept(__c.size())) -> decltype(__c.size()) { + return __c.size(); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr size_t size(const _Tp (&)[_Sz]) noexcept { + return _Sz; +} + +# if _LIBCPP_STD_VER >= 20 +template +_LIBCPP_HIDE_FROM_ABI constexpr auto +ssize(const _Cont& __c) noexcept(noexcept(static_cast>>( + __c.size()))) -> common_type_t> { + return static_cast>>(__c.size()); +} + +// GCC complains about the implicit conversion from ptrdiff_t to size_t in +// the array bound. +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wsign-conversion") +template +_LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t ssize(const _Tp (&)[_Sz]) noexcept { + return _Sz; +} +_LIBCPP_DIAGNOSTIC_POP +# endif + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_SIZE_H diff --git a/libcxx/include/__cxx03/__iterator/sortable.h b/libcxx/include/__cxx03/__iterator/sortable.h new file mode 100644 index 0000000000000000000000000000000000000000..1444860f2aa105fb145e2f7bcb0d7da8753eb557 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/sortable.h @@ -0,0 +1,35 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_SORTABLE_H +#define _LIBCPP___ITERATOR_SORTABLE_H + +#include <__config> +#include <__functional/identity.h> +#include <__functional/ranges_operations.h> +#include <__iterator/concepts.h> +#include <__iterator/permutable.h> +#include <__iterator/projected.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template +concept sortable = permutable<_Iter> && indirect_strict_weak_order<_Comp, projected<_Iter, _Proj>>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_SORTABLE_H diff --git a/libcxx/include/__cxx03/__iterator/unreachable_sentinel.h b/libcxx/include/__cxx03/__iterator/unreachable_sentinel.h new file mode 100644 index 0000000000000000000000000000000000000000..77e663da4b3a6a15cb37e17b9fa19c15e7c43a44 --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/unreachable_sentinel.h @@ -0,0 +1,37 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_UNREACHABLE_SENTINEL_H +#define _LIBCPP___ITERATOR_UNREACHABLE_SENTINEL_H + +#include <__config> +#include <__iterator/concepts.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +struct unreachable_sentinel_t { + template + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(unreachable_sentinel_t, const _Iter&) noexcept { + return false; + } +}; + +inline constexpr unreachable_sentinel_t unreachable_sentinel{}; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_UNREACHABLE_SENTINEL_H diff --git a/libcxx/include/__cxx03/__iterator/wrap_iter.h b/libcxx/include/__cxx03/__iterator/wrap_iter.h new file mode 100644 index 0000000000000000000000000000000000000000..56183c0ee794d0e32f3970d353358fe57c1136de --- /dev/null +++ b/libcxx/include/__cxx03/__iterator/wrap_iter.h @@ -0,0 +1,244 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_WRAP_ITER_H +#define _LIBCPP___ITERATOR_WRAP_ITER_H + +#include <__compare/ordering.h> +#include <__compare/three_way_comparable.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__memory/addressof.h> +#include <__memory/pointer_traits.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_convertible.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class __wrap_iter { +public: + typedef _Iter iterator_type; + typedef typename iterator_traits::value_type value_type; + typedef typename iterator_traits::difference_type difference_type; + typedef typename iterator_traits::pointer pointer; + typedef typename iterator_traits::reference reference; + typedef typename iterator_traits::iterator_category iterator_category; +#if _LIBCPP_STD_VER >= 20 + typedef contiguous_iterator_tag iterator_concept; +#endif + +private: + iterator_type __i_; + +public: + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter() _NOEXCEPT : __i_() {} + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter(const __wrap_iter<_Up>& __u) _NOEXCEPT + : __i_(__u.base()) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator*() const _NOEXCEPT { return *__i_; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pointer operator->() const _NOEXCEPT { + return std::__to_address(__i_); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter& operator++() _NOEXCEPT { + ++__i_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter operator++(int) _NOEXCEPT { + __wrap_iter __tmp(*this); + ++(*this); + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter& operator--() _NOEXCEPT { + --__i_; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter operator--(int) _NOEXCEPT { + __wrap_iter __tmp(*this); + --(*this); + return __tmp; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter operator+(difference_type __n) const _NOEXCEPT { + __wrap_iter __w(*this); + __w += __n; + return __w; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter& operator+=(difference_type __n) _NOEXCEPT { + __i_ += __n; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter operator-(difference_type __n) const _NOEXCEPT { + return *this + (-__n); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter& operator-=(difference_type __n) _NOEXCEPT { + *this += -__n; + return *this; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator[](difference_type __n) const _NOEXCEPT { + return __i_[__n]; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 iterator_type base() const _NOEXCEPT { return __i_; } + +private: + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __wrap_iter(iterator_type __x) _NOEXCEPT : __i_(__x) {} + + template + friend class __wrap_iter; + template + friend class basic_string; + template + friend class basic_string_view; + template + friend class _LIBCPP_TEMPLATE_VIS vector; + template + friend class _LIBCPP_TEMPLATE_VIS span; + template + friend struct array; +}; + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { + return __x.base() == __y.base(); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { + return __x.base() == __y.base(); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool +operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { + return __x.base() < __y.base(); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool +operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { + return __x.base() < __y.base(); +} + +#if _LIBCPP_STD_VER <= 17 +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { + return !(__x == __y); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { + return !(__x == __y); +} +#endif + +// TODO(mordante) disable these overloads in the LLVM 20 release. +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { + return __y < __x; +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { + return __y < __x; +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { + return !(__x < __y); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { + return !(__x < __y); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { + return !(__y < __x); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool +operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { + return !(__y < __x); +} + +#if _LIBCPP_STD_VER >= 20 +template +_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering +operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) noexcept { + if constexpr (three_way_comparable_with<_Iter1, _Iter2, strong_ordering>) { + return __x.base() <=> __y.base(); + } else { + if (__x.base() < __y.base()) + return strong_ordering::less; + + if (__x.base() == __y.base()) + return strong_ordering::equal; + + return strong_ordering::greater; + } +} +#endif // _LIBCPP_STD_VER >= 20 + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +#ifndef _LIBCPP_CXX03_LANG + auto + operator-(const __wrap_iter<_Iter1>& __x, + const __wrap_iter<_Iter2>& __y) _NOEXCEPT->decltype(__x.base() - __y.base()) +#else +typename __wrap_iter<_Iter1>::difference_type +operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT +#endif // C++03 +{ + return __x.base() - __y.base(); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter<_Iter1> +operator+(typename __wrap_iter<_Iter1>::difference_type __n, __wrap_iter<_Iter1> __x) _NOEXCEPT { + __x += __n; + return __x; +} + +#if _LIBCPP_STD_VER <= 17 +template +struct __libcpp_is_contiguous_iterator<__wrap_iter<_It> > : true_type {}; +#endif + +template +struct _LIBCPP_TEMPLATE_VIS pointer_traits<__wrap_iter<_It> > { + typedef __wrap_iter<_It> pointer; + typedef typename pointer_traits<_It>::element_type element_type; + typedef typename pointer_traits<_It>::difference_type difference_type; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static element_type* to_address(pointer __w) _NOEXCEPT { + return std::__to_address(__w.base()); + } +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_WRAP_ITER_H diff --git a/libcxx/include/__cxx03/__locale b/libcxx/include/__cxx03/__locale new file mode 100644 index 0000000000000000000000000000000000000000..4b382764b446453e6db5bfce70d9f663e0049795 --- /dev/null +++ b/libcxx/include/__cxx03/__locale @@ -0,0 +1,1513 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___LOCALE +#define _LIBCPP___LOCALE + +#include <__config> +#include <__locale_dir/locale_base_api.h> +#include <__memory/shared_ptr.h> // __shared_count +#include <__mutex/once_flag.h> +#include <__type_traits/make_unsigned.h> +#include <__utility/no_destroy.h> +#include <__utility/private_constructor_tag.h> +#include +#include +#include +#include +#include + +// Some platforms require more includes than others. Keep the includes on all plaforms for now. +#include +#include + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +# include +#else +# include <__std_mbstate_t.h> +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +class _LIBCPP_EXPORTED_FROM_ABI locale; + +template +_LIBCPP_HIDE_FROM_ABI bool has_facet(const locale&) _NOEXCEPT; + +template +_LIBCPP_HIDE_FROM_ABI const _Facet& use_facet(const locale&); + +class _LIBCPP_EXPORTED_FROM_ABI locale { +public: + // locale is essentially a shared_ptr that doesn't support weak_ptrs and never got a move constructor. + using __trivially_relocatable = locale; + + // types: + class _LIBCPP_EXPORTED_FROM_ABI facet; + class _LIBCPP_EXPORTED_FROM_ABI id; + + typedef int category; + + static const category // values assigned here are for exposition only + none = 0, + collate = LC_COLLATE_MASK, ctype = LC_CTYPE_MASK, monetary = LC_MONETARY_MASK, numeric = LC_NUMERIC_MASK, + time = LC_TIME_MASK, messages = LC_MESSAGES_MASK, all = collate | ctype | monetary | numeric | time | messages; + + // construct/copy/destroy: + locale() _NOEXCEPT; + locale(const locale&) _NOEXCEPT; + explicit locale(const char*); + explicit locale(const string&); + locale(const locale&, const char*, category); + locale(const locale&, const string&, category); + template + _LIBCPP_HIDE_FROM_ABI locale(const locale&, _Facet*); + locale(const locale&, const locale&, category); + + ~locale(); + + const locale& operator=(const locale&) _NOEXCEPT; + + template + _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS locale combine(const locale&) const; + + // locale operations: + string name() const; + bool operator==(const locale&) const; +#if _LIBCPP_STD_VER <= 17 + _LIBCPP_HIDE_FROM_ABI bool operator!=(const locale& __y) const { return !(*this == __y); } +#endif + template + _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool + operator()(const basic_string<_CharT, _Traits, _Allocator>&, const basic_string<_CharT, _Traits, _Allocator>&) const; + + // global locale objects: + static locale global(const locale&); + static const locale& classic(); + +private: + class __imp; + __imp* __locale_; + + template + friend struct __no_destroy; + _LIBCPP_HIDE_FROM_ABI explicit locale(__private_constructor_tag, __imp* __loc) : __locale_(__loc) {} + + void __install_ctor(const locale&, facet*, long); + static locale& __global(); + bool has_facet(id&) const; + const facet* use_facet(id&) const; + + template + friend bool has_facet(const locale&) _NOEXCEPT; + template + friend const _Facet& use_facet(const locale&); +}; + +class _LIBCPP_EXPORTED_FROM_ABI locale::facet : public __shared_count { +protected: + _LIBCPP_HIDE_FROM_ABI explicit facet(size_t __refs = 0) : __shared_count(static_cast(__refs) - 1) {} + + ~facet() override; + + // facet(const facet&) = delete; // effectively done in __shared_count + // void operator=(const facet&) = delete; + +private: + void __on_zero_shared() _NOEXCEPT override; +}; + +class _LIBCPP_EXPORTED_FROM_ABI locale::id { + once_flag __flag_; + int32_t __id_; + + static int32_t __next_id; + +public: + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR id() : __id_(0) {} + void operator=(const id&) = delete; + id(const id&) = delete; + +public: // only needed for tests + long __get(); + + friend class locale; + friend class locale::__imp; +}; + +template +inline _LIBCPP_HIDE_FROM_ABI locale::locale(const locale& __other, _Facet* __f) { + __install_ctor(__other, __f, __f ? __f->id.__get() : 0); +} + +template +locale locale::combine(const locale& __other) const { + if (!std::has_facet<_Facet>(__other)) + __throw_runtime_error("locale::combine: locale missing facet"); + + return locale(*this, &const_cast<_Facet&>(std::use_facet<_Facet>(__other))); +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool has_facet(const locale& __l) _NOEXCEPT { + return __l.has_facet(_Facet::id); +} + +template +inline _LIBCPP_HIDE_FROM_ABI const _Facet& use_facet(const locale& __l) { + return static_cast(*__l.use_facet(_Facet::id)); +} + +// template class collate; + +template +class _LIBCPP_TEMPLATE_VIS collate : public locale::facet { +public: + typedef _CharT char_type; + typedef basic_string string_type; + + _LIBCPP_HIDE_FROM_ABI explicit collate(size_t __refs = 0) : locale::facet(__refs) {} + + _LIBCPP_HIDE_FROM_ABI int + compare(const char_type* __lo1, const char_type* __hi1, const char_type* __lo2, const char_type* __hi2) const { + return do_compare(__lo1, __hi1, __lo2, __hi2); + } + + // FIXME(EricWF): The _LIBCPP_ALWAYS_INLINE is needed on Windows to work + // around a dllimport bug that expects an external instantiation. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE string_type + transform(const char_type* __lo, const char_type* __hi) const { + return do_transform(__lo, __hi); + } + + _LIBCPP_HIDE_FROM_ABI long hash(const char_type* __lo, const char_type* __hi) const { return do_hash(__lo, __hi); } + + static locale::id id; + +protected: + ~collate() override; + virtual int + do_compare(const char_type* __lo1, const char_type* __hi1, const char_type* __lo2, const char_type* __hi2) const; + virtual string_type do_transform(const char_type* __lo, const char_type* __hi) const { + return string_type(__lo, __hi); + } + virtual long do_hash(const char_type* __lo, const char_type* __hi) const; +}; + +template +locale::id collate<_CharT>::id; + +template +collate<_CharT>::~collate() {} + +template +int collate<_CharT>::do_compare( + const char_type* __lo1, const char_type* __hi1, const char_type* __lo2, const char_type* __hi2) const { + for (; __lo2 != __hi2; ++__lo1, ++__lo2) { + if (__lo1 == __hi1 || *__lo1 < *__lo2) + return -1; + if (*__lo2 < *__lo1) + return 1; + } + return __lo1 != __hi1; +} + +template +long collate<_CharT>::do_hash(const char_type* __lo, const char_type* __hi) const { + size_t __h = 0; + const size_t __sr = __CHAR_BIT__ * sizeof(size_t) - 8; + const size_t __mask = size_t(0xF) << (__sr + 4); + for (const char_type* __p = __lo; __p != __hi; ++__p) { + __h = (__h << 4) + static_cast(*__p); + size_t __g = __h & __mask; + __h ^= __g | (__g >> __sr); + } + return static_cast(__h); +} + +extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS collate; +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS collate; +#endif + +// template class collate_byname; + +template +class _LIBCPP_TEMPLATE_VIS collate_byname; + +template <> +class _LIBCPP_EXPORTED_FROM_ABI collate_byname : public collate { + locale_t __l_; + +public: + typedef char char_type; + typedef basic_string string_type; + + explicit collate_byname(const char* __n, size_t __refs = 0); + explicit collate_byname(const string& __n, size_t __refs = 0); + +protected: + ~collate_byname() override; + int do_compare( + const char_type* __lo1, const char_type* __hi1, const char_type* __lo2, const char_type* __hi2) const override; + string_type do_transform(const char_type* __lo, const char_type* __hi) const override; +}; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <> +class _LIBCPP_EXPORTED_FROM_ABI collate_byname : public collate { + locale_t __l_; + +public: + typedef wchar_t char_type; + typedef basic_string string_type; + + explicit collate_byname(const char* __n, size_t __refs = 0); + explicit collate_byname(const string& __n, size_t __refs = 0); + +protected: + ~collate_byname() override; + + int do_compare( + const char_type* __lo1, const char_type* __hi1, const char_type* __lo2, const char_type* __hi2) const override; + string_type do_transform(const char_type* __lo, const char_type* __hi) const override; +}; +#endif + +template +bool locale::operator()(const basic_string<_CharT, _Traits, _Allocator>& __x, + const basic_string<_CharT, _Traits, _Allocator>& __y) const { + return std::use_facet >(*this).compare( + __x.data(), __x.data() + __x.size(), __y.data(), __y.data() + __y.size()) < 0; +} + +// template class ctype + +class _LIBCPP_EXPORTED_FROM_ABI ctype_base { +public: +#if defined(_LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE) + typedef unsigned long mask; + static const mask space = 1 << 0; + static const mask print = 1 << 1; + static const mask cntrl = 1 << 2; + static const mask upper = 1 << 3; + static const mask lower = 1 << 4; + static const mask alpha = 1 << 5; + static const mask digit = 1 << 6; + static const mask punct = 1 << 7; + static const mask xdigit = 1 << 8; + static const mask blank = 1 << 9; +# if defined(__BIONIC__) + // Historically this was a part of regex_traits rather than ctype_base. The + // historical value of the constant is preserved for ABI compatibility. + static const mask __regex_word = 0x8000; +# else + static const mask __regex_word = 1 << 10; +# endif // defined(__BIONIC__) +#elif defined(__GLIBC__) + typedef unsigned short mask; + static const mask space = _ISspace; + static const mask print = _ISprint; + static const mask cntrl = _IScntrl; + static const mask upper = _ISupper; + static const mask lower = _ISlower; + static const mask alpha = _ISalpha; + static const mask digit = _ISdigit; + static const mask punct = _ISpunct; + static const mask xdigit = _ISxdigit; + static const mask blank = _ISblank; +# if defined(__mips__) || (BYTE_ORDER == BIG_ENDIAN) + static const mask __regex_word = static_cast(_ISbit(15)); +# else + static const mask __regex_word = 0x80; +# endif +#elif defined(_LIBCPP_MSVCRT_LIKE) + typedef unsigned short mask; + static const mask space = _SPACE; + static const mask print = _BLANK | _PUNCT | _ALPHA | _DIGIT; + static const mask cntrl = _CONTROL; + static const mask upper = _UPPER; + static const mask lower = _LOWER; + static const mask alpha = _ALPHA; + static const mask digit = _DIGIT; + static const mask punct = _PUNCT; + static const mask xdigit = _HEX; + static const mask blank = _BLANK; + static const mask __regex_word = 0x4000; // 0x8000 and 0x0100 and 0x00ff are used +# define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT +# define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_ALPHA +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) +# ifdef __APPLE__ + typedef __uint32_t mask; +# elif defined(__FreeBSD__) + typedef unsigned long mask; +# elif defined(__NetBSD__) + typedef unsigned short mask; +# endif + static const mask space = _CTYPE_S; + static const mask print = _CTYPE_R; + static const mask cntrl = _CTYPE_C; + static const mask upper = _CTYPE_U; + static const mask lower = _CTYPE_L; + static const mask alpha = _CTYPE_A; + static const mask digit = _CTYPE_D; + static const mask punct = _CTYPE_P; + static const mask xdigit = _CTYPE_X; + +# if defined(__NetBSD__) + static const mask blank = _CTYPE_BL; + // NetBSD defines classes up to 0x2000 + // see sys/ctype_bits.h, _CTYPE_Q + static const mask __regex_word = 0x8000; +# else + static const mask blank = _CTYPE_B; + static const mask __regex_word = 0x80; +# endif +#elif defined(_AIX) + typedef unsigned int mask; + static const mask space = _ISSPACE; + static const mask print = _ISPRINT; + static const mask cntrl = _ISCNTRL; + static const mask upper = _ISUPPER; + static const mask lower = _ISLOWER; + static const mask alpha = _ISALPHA; + static const mask digit = _ISDIGIT; + static const mask punct = _ISPUNCT; + static const mask xdigit = _ISXDIGIT; + static const mask blank = _ISBLANK; + static const mask __regex_word = 0x8000; +#elif defined(_NEWLIB_VERSION) + // Same type as Newlib's _ctype_ array in newlib/libc/include/ctype.h. + typedef char mask; + // In case char is signed, static_cast is needed to avoid warning on + // positive value becomming negative. + static const mask space = static_cast(_S); + static const mask print = static_cast(_P | _U | _L | _N | _B); + static const mask cntrl = static_cast(_C); + static const mask upper = static_cast(_U); + static const mask lower = static_cast(_L); + static const mask alpha = static_cast(_U | _L); + static const mask digit = static_cast(_N); + static const mask punct = static_cast(_P); + static const mask xdigit = static_cast(_X | _N); + static const mask blank = static_cast(_B); + // mask is already fully saturated, use a different type in regex_type_traits. + static const unsigned short __regex_word = 0x100; +# define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT +# define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_ALPHA +# define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_XDIGIT +#elif defined(__MVS__) +# if defined(__NATIVE_ASCII_F) + typedef unsigned int mask; + static const mask space = _ISSPACE_A; + static const mask print = _ISPRINT_A; + static const mask cntrl = _ISCNTRL_A; + static const mask upper = _ISUPPER_A; + static const mask lower = _ISLOWER_A; + static const mask alpha = _ISALPHA_A; + static const mask digit = _ISDIGIT_A; + static const mask punct = _ISPUNCT_A; + static const mask xdigit = _ISXDIGIT_A; + static const mask blank = _ISBLANK_A; +# else + typedef unsigned short mask; + static const mask space = __ISSPACE; + static const mask print = __ISPRINT; + static const mask cntrl = __ISCNTRL; + static const mask upper = __ISUPPER; + static const mask lower = __ISLOWER; + static const mask alpha = __ISALPHA; + static const mask digit = __ISDIGIT; + static const mask punct = __ISPUNCT; + static const mask xdigit = __ISXDIGIT; + static const mask blank = __ISBLANK; +# endif + static const mask __regex_word = 0x8000; +#else +# error unknown rune table for this platform -- do you mean to define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE? +#endif + static const mask alnum = alpha | digit; + static const mask graph = alnum | punct; + + _LIBCPP_HIDE_FROM_ABI ctype_base() {} + + static_assert((__regex_word & ~(std::make_unsigned::type)(space | print | cntrl | upper | lower | alpha | + digit | punct | xdigit | blank)) == __regex_word, + "__regex_word can't overlap other bits"); +}; + +template +class _LIBCPP_TEMPLATE_VIS ctype; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <> +class _LIBCPP_EXPORTED_FROM_ABI ctype : public locale::facet, public ctype_base { +public: + typedef wchar_t char_type; + + _LIBCPP_HIDE_FROM_ABI explicit ctype(size_t __refs = 0) : locale::facet(__refs) {} + + _LIBCPP_HIDE_FROM_ABI bool is(mask __m, char_type __c) const { return do_is(__m, __c); } + + _LIBCPP_HIDE_FROM_ABI const char_type* is(const char_type* __low, const char_type* __high, mask* __vec) const { + return do_is(__low, __high, __vec); + } + + _LIBCPP_HIDE_FROM_ABI const char_type* scan_is(mask __m, const char_type* __low, const char_type* __high) const { + return do_scan_is(__m, __low, __high); + } + + _LIBCPP_HIDE_FROM_ABI const char_type* scan_not(mask __m, const char_type* __low, const char_type* __high) const { + return do_scan_not(__m, __low, __high); + } + + _LIBCPP_HIDE_FROM_ABI char_type toupper(char_type __c) const { return do_toupper(__c); } + + _LIBCPP_HIDE_FROM_ABI const char_type* toupper(char_type* __low, const char_type* __high) const { + return do_toupper(__low, __high); + } + + _LIBCPP_HIDE_FROM_ABI char_type tolower(char_type __c) const { return do_tolower(__c); } + + _LIBCPP_HIDE_FROM_ABI const char_type* tolower(char_type* __low, const char_type* __high) const { + return do_tolower(__low, __high); + } + + _LIBCPP_HIDE_FROM_ABI char_type widen(char __c) const { return do_widen(__c); } + + _LIBCPP_HIDE_FROM_ABI const char* widen(const char* __low, const char* __high, char_type* __to) const { + return do_widen(__low, __high, __to); + } + + _LIBCPP_HIDE_FROM_ABI char narrow(char_type __c, char __dfault) const { return do_narrow(__c, __dfault); } + + _LIBCPP_HIDE_FROM_ABI const char_type* + narrow(const char_type* __low, const char_type* __high, char __dfault, char* __to) const { + return do_narrow(__low, __high, __dfault, __to); + } + + static locale::id id; + +protected: + ~ctype() override; + virtual bool do_is(mask __m, char_type __c) const; + virtual const char_type* do_is(const char_type* __low, const char_type* __high, mask* __vec) const; + virtual const char_type* do_scan_is(mask __m, const char_type* __low, const char_type* __high) const; + virtual const char_type* do_scan_not(mask __m, const char_type* __low, const char_type* __high) const; + virtual char_type do_toupper(char_type) const; + virtual const char_type* do_toupper(char_type* __low, const char_type* __high) const; + virtual char_type do_tolower(char_type) const; + virtual const char_type* do_tolower(char_type* __low, const char_type* __high) const; + virtual char_type do_widen(char) const; + virtual const char* do_widen(const char* __low, const char* __high, char_type* __dest) const; + virtual char do_narrow(char_type, char __dfault) const; + virtual const char_type* + do_narrow(const char_type* __low, const char_type* __high, char __dfault, char* __dest) const; +}; +#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS + +template <> +class _LIBCPP_EXPORTED_FROM_ABI ctype : public locale::facet, public ctype_base { + const mask* __tab_; + bool __del_; + +public: + typedef char char_type; + + explicit ctype(const mask* __tab = nullptr, bool __del = false, size_t __refs = 0); + + _LIBCPP_HIDE_FROM_ABI bool is(mask __m, char_type __c) const { + return isascii(__c) ? (__tab_[static_cast(__c)] & __m) != 0 : false; + } + + _LIBCPP_HIDE_FROM_ABI const char_type* is(const char_type* __low, const char_type* __high, mask* __vec) const { + for (; __low != __high; ++__low, ++__vec) + *__vec = isascii(*__low) ? __tab_[static_cast(*__low)] : 0; + return __low; + } + + _LIBCPP_HIDE_FROM_ABI const char_type* scan_is(mask __m, const char_type* __low, const char_type* __high) const { + for (; __low != __high; ++__low) + if (isascii(*__low) && (__tab_[static_cast(*__low)] & __m)) + break; + return __low; + } + + _LIBCPP_HIDE_FROM_ABI const char_type* scan_not(mask __m, const char_type* __low, const char_type* __high) const { + for (; __low != __high; ++__low) + if (!isascii(*__low) || !(__tab_[static_cast(*__low)] & __m)) + break; + return __low; + } + + _LIBCPP_HIDE_FROM_ABI char_type toupper(char_type __c) const { return do_toupper(__c); } + + _LIBCPP_HIDE_FROM_ABI const char_type* toupper(char_type* __low, const char_type* __high) const { + return do_toupper(__low, __high); + } + + _LIBCPP_HIDE_FROM_ABI char_type tolower(char_type __c) const { return do_tolower(__c); } + + _LIBCPP_HIDE_FROM_ABI const char_type* tolower(char_type* __low, const char_type* __high) const { + return do_tolower(__low, __high); + } + + _LIBCPP_HIDE_FROM_ABI char_type widen(char __c) const { return do_widen(__c); } + + _LIBCPP_HIDE_FROM_ABI const char* widen(const char* __low, const char* __high, char_type* __to) const { + return do_widen(__low, __high, __to); + } + + _LIBCPP_HIDE_FROM_ABI char narrow(char_type __c, char __dfault) const { return do_narrow(__c, __dfault); } + + _LIBCPP_HIDE_FROM_ABI const char* + narrow(const char_type* __low, const char_type* __high, char __dfault, char* __to) const { + return do_narrow(__low, __high, __dfault, __to); + } + + static locale::id id; + +#ifdef _CACHED_RUNES + static const size_t table_size = _CACHED_RUNES; +#else + static const size_t table_size = 256; // FIXME: Don't hardcode this. +#endif + _LIBCPP_HIDE_FROM_ABI const mask* table() const _NOEXCEPT { return __tab_; } + static const mask* classic_table() _NOEXCEPT; +#if defined(__GLIBC__) || defined(__EMSCRIPTEN__) + static const int* __classic_upper_table() _NOEXCEPT; + static const int* __classic_lower_table() _NOEXCEPT; +#endif +#if defined(__NetBSD__) + static const short* __classic_upper_table() _NOEXCEPT; + static const short* __classic_lower_table() _NOEXCEPT; +#endif +#if defined(__MVS__) + static const unsigned short* __classic_upper_table() _NOEXCEPT; + static const unsigned short* __classic_lower_table() _NOEXCEPT; +#endif + +protected: + ~ctype() override; + virtual char_type do_toupper(char_type __c) const; + virtual const char_type* do_toupper(char_type* __low, const char_type* __high) const; + virtual char_type do_tolower(char_type __c) const; + virtual const char_type* do_tolower(char_type* __low, const char_type* __high) const; + virtual char_type do_widen(char __c) const; + virtual const char* do_widen(const char* __low, const char* __high, char_type* __to) const; + virtual char do_narrow(char_type __c, char __dfault) const; + virtual const char* do_narrow(const char_type* __low, const char_type* __high, char __dfault, char* __to) const; +}; + +// template class ctype_byname; + +template +class _LIBCPP_TEMPLATE_VIS ctype_byname; + +template <> +class _LIBCPP_EXPORTED_FROM_ABI ctype_byname : public ctype { + locale_t __l_; + +public: + explicit ctype_byname(const char*, size_t = 0); + explicit ctype_byname(const string&, size_t = 0); + +protected: + ~ctype_byname() override; + char_type do_toupper(char_type) const override; + const char_type* do_toupper(char_type* __low, const char_type* __high) const override; + char_type do_tolower(char_type) const override; + const char_type* do_tolower(char_type* __low, const char_type* __high) const override; +}; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <> +class _LIBCPP_EXPORTED_FROM_ABI ctype_byname : public ctype { + locale_t __l_; + +public: + explicit ctype_byname(const char*, size_t = 0); + explicit ctype_byname(const string&, size_t = 0); + +protected: + ~ctype_byname() override; + bool do_is(mask __m, char_type __c) const override; + const char_type* do_is(const char_type* __low, const char_type* __high, mask* __vec) const override; + const char_type* do_scan_is(mask __m, const char_type* __low, const char_type* __high) const override; + const char_type* do_scan_not(mask __m, const char_type* __low, const char_type* __high) const override; + char_type do_toupper(char_type) const override; + const char_type* do_toupper(char_type* __low, const char_type* __high) const override; + char_type do_tolower(char_type) const override; + const char_type* do_tolower(char_type* __low, const char_type* __high) const override; + char_type do_widen(char) const override; + const char* do_widen(const char* __low, const char* __high, char_type* __dest) const override; + char do_narrow(char_type, char __dfault) const override; + const char_type* + do_narrow(const char_type* __low, const char_type* __high, char __dfault, char* __dest) const override; +}; +#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS + +template +inline _LIBCPP_HIDE_FROM_ABI bool isspace(_CharT __c, const locale& __loc) { + return std::use_facet >(__loc).is(ctype_base::space, __c); +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool isprint(_CharT __c, const locale& __loc) { + return std::use_facet >(__loc).is(ctype_base::print, __c); +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool iscntrl(_CharT __c, const locale& __loc) { + return std::use_facet >(__loc).is(ctype_base::cntrl, __c); +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool isupper(_CharT __c, const locale& __loc) { + return std::use_facet >(__loc).is(ctype_base::upper, __c); +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool islower(_CharT __c, const locale& __loc) { + return std::use_facet >(__loc).is(ctype_base::lower, __c); +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool isalpha(_CharT __c, const locale& __loc) { + return std::use_facet >(__loc).is(ctype_base::alpha, __c); +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool isdigit(_CharT __c, const locale& __loc) { + return std::use_facet >(__loc).is(ctype_base::digit, __c); +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool ispunct(_CharT __c, const locale& __loc) { + return std::use_facet >(__loc).is(ctype_base::punct, __c); +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool isxdigit(_CharT __c, const locale& __loc) { + return std::use_facet >(__loc).is(ctype_base::xdigit, __c); +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool isalnum(_CharT __c, const locale& __loc) { + return std::use_facet >(__loc).is(ctype_base::alnum, __c); +} + +template +inline _LIBCPP_HIDE_FROM_ABI bool isgraph(_CharT __c, const locale& __loc) { + return std::use_facet >(__loc).is(ctype_base::graph, __c); +} + +template +_LIBCPP_HIDE_FROM_ABI bool isblank(_CharT __c, const locale& __loc) { + return std::use_facet >(__loc).is(ctype_base::blank, __c); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _CharT toupper(_CharT __c, const locale& __loc) { + return std::use_facet >(__loc).toupper(__c); +} + +template +inline _LIBCPP_HIDE_FROM_ABI _CharT tolower(_CharT __c, const locale& __loc) { + return std::use_facet >(__loc).tolower(__c); +} + +// codecvt_base + +class _LIBCPP_EXPORTED_FROM_ABI codecvt_base { +public: + _LIBCPP_HIDE_FROM_ABI codecvt_base() {} + enum result { ok, partial, error, noconv }; +}; + +// template class codecvt; + +template +class _LIBCPP_TEMPLATE_VIS codecvt; + +// template <> class codecvt + +template <> +class _LIBCPP_EXPORTED_FROM_ABI codecvt : public locale::facet, public codecvt_base { +public: + typedef char intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + _LIBCPP_HIDE_FROM_ABI explicit codecvt(size_t __refs = 0) : locale::facet(__refs) {} + + _LIBCPP_HIDE_FROM_ABI result + out(state_type& __st, + const intern_type* __frm, + const intern_type* __frm_end, + const intern_type*& __frm_nxt, + extern_type* __to, + extern_type* __to_end, + extern_type*& __to_nxt) const { + return do_out(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI result + unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const { + return do_unshift(__st, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI result + in(state_type& __st, + const extern_type* __frm, + const extern_type* __frm_end, + const extern_type*& __frm_nxt, + intern_type* __to, + intern_type* __to_end, + intern_type*& __to_nxt) const { + return do_in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); } + + _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); } + + _LIBCPP_HIDE_FROM_ABI int + length(state_type& __st, const extern_type* __frm, const extern_type* __end, size_t __mx) const { + return do_length(__st, __frm, __end, __mx); + } + + _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); } + + static locale::id id; + +protected: + _LIBCPP_HIDE_FROM_ABI explicit codecvt(const char*, size_t __refs = 0) : locale::facet(__refs) {} + + ~codecvt() override; + + virtual result + do_out(state_type& __st, + const intern_type* __frm, + const intern_type* __frm_end, + const intern_type*& __frm_nxt, + extern_type* __to, + extern_type* __to_end, + extern_type*& __to_nxt) const; + virtual result + do_in(state_type& __st, + const extern_type* __frm, + const extern_type* __frm_end, + const extern_type*& __frm_nxt, + intern_type* __to, + intern_type* __to_end, + intern_type*& __to_nxt) const; + virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; + virtual int do_length(state_type& __st, const extern_type* __frm, const extern_type* __end, size_t __mx) const; + virtual int do_max_length() const _NOEXCEPT; +}; + +// template <> class codecvt + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <> +class _LIBCPP_EXPORTED_FROM_ABI codecvt : public locale::facet, public codecvt_base { + locale_t __l_; + +public: + typedef wchar_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + explicit codecvt(size_t __refs = 0); + + _LIBCPP_HIDE_FROM_ABI result + out(state_type& __st, + const intern_type* __frm, + const intern_type* __frm_end, + const intern_type*& __frm_nxt, + extern_type* __to, + extern_type* __to_end, + extern_type*& __to_nxt) const { + return do_out(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI result + unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const { + return do_unshift(__st, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI result + in(state_type& __st, + const extern_type* __frm, + const extern_type* __frm_end, + const extern_type*& __frm_nxt, + intern_type* __to, + intern_type* __to_end, + intern_type*& __to_nxt) const { + return do_in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); } + + _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); } + + _LIBCPP_HIDE_FROM_ABI int + length(state_type& __st, const extern_type* __frm, const extern_type* __end, size_t __mx) const { + return do_length(__st, __frm, __end, __mx); + } + + _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); } + + static locale::id id; + +protected: + explicit codecvt(const char*, size_t __refs = 0); + + ~codecvt() override; + + virtual result + do_out(state_type& __st, + const intern_type* __frm, + const intern_type* __frm_end, + const intern_type*& __frm_nxt, + extern_type* __to, + extern_type* __to_end, + extern_type*& __to_nxt) const; + virtual result + do_in(state_type& __st, + const extern_type* __frm, + const extern_type* __frm_end, + const extern_type*& __frm_nxt, + intern_type* __to, + intern_type* __to_end, + intern_type*& __to_nxt) const; + virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; + virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; + virtual int do_max_length() const _NOEXCEPT; +}; +#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS + +// template <> class codecvt // deprecated in C++20 + +template <> +class _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_EXPORTED_FROM_ABI codecvt + : public locale::facet, public codecvt_base { +public: + typedef char16_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + _LIBCPP_HIDE_FROM_ABI explicit codecvt(size_t __refs = 0) : locale::facet(__refs) {} + + _LIBCPP_HIDE_FROM_ABI result + out(state_type& __st, + const intern_type* __frm, + const intern_type* __frm_end, + const intern_type*& __frm_nxt, + extern_type* __to, + extern_type* __to_end, + extern_type*& __to_nxt) const { + return do_out(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI result + unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const { + return do_unshift(__st, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI result + in(state_type& __st, + const extern_type* __frm, + const extern_type* __frm_end, + const extern_type*& __frm_nxt, + intern_type* __to, + intern_type* __to_end, + intern_type*& __to_nxt) const { + return do_in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); } + + _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); } + + _LIBCPP_HIDE_FROM_ABI int + length(state_type& __st, const extern_type* __frm, const extern_type* __end, size_t __mx) const { + return do_length(__st, __frm, __end, __mx); + } + + _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); } + + static locale::id id; + +protected: + _LIBCPP_HIDE_FROM_ABI explicit codecvt(const char*, size_t __refs = 0) : locale::facet(__refs) {} + + ~codecvt() override; + + virtual result + do_out(state_type& __st, + const intern_type* __frm, + const intern_type* __frm_end, + const intern_type*& __frm_nxt, + extern_type* __to, + extern_type* __to_end, + extern_type*& __to_nxt) const; + virtual result + do_in(state_type& __st, + const extern_type* __frm, + const extern_type* __frm_end, + const extern_type*& __frm_nxt, + intern_type* __to, + intern_type* __to_end, + intern_type*& __to_nxt) const; + virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; + virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; + virtual int do_max_length() const _NOEXCEPT; +}; + +#ifndef _LIBCPP_HAS_NO_CHAR8_T + +// template <> class codecvt // C++20 + +template <> +class _LIBCPP_EXPORTED_FROM_ABI codecvt : public locale::facet, public codecvt_base { +public: + typedef char16_t intern_type; + typedef char8_t extern_type; + typedef mbstate_t state_type; + + _LIBCPP_HIDE_FROM_ABI explicit codecvt(size_t __refs = 0) : locale::facet(__refs) {} + + _LIBCPP_HIDE_FROM_ABI result + out(state_type& __st, + const intern_type* __frm, + const intern_type* __frm_end, + const intern_type*& __frm_nxt, + extern_type* __to, + extern_type* __to_end, + extern_type*& __to_nxt) const { + return do_out(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI result + unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const { + return do_unshift(__st, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI result + in(state_type& __st, + const extern_type* __frm, + const extern_type* __frm_end, + const extern_type*& __frm_nxt, + intern_type* __to, + intern_type* __to_end, + intern_type*& __to_nxt) const { + return do_in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); } + + _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); } + + _LIBCPP_HIDE_FROM_ABI int + length(state_type& __st, const extern_type* __frm, const extern_type* __end, size_t __mx) const { + return do_length(__st, __frm, __end, __mx); + } + + _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); } + + static locale::id id; + +protected: + _LIBCPP_HIDE_FROM_ABI explicit codecvt(const char*, size_t __refs = 0) : locale::facet(__refs) {} + + ~codecvt() override; + + virtual result + do_out(state_type& __st, + const intern_type* __frm, + const intern_type* __frm_end, + const intern_type*& __frm_nxt, + extern_type* __to, + extern_type* __to_end, + extern_type*& __to_nxt) const; + virtual result + do_in(state_type& __st, + const extern_type* __frm, + const extern_type* __frm_end, + const extern_type*& __frm_nxt, + intern_type* __to, + intern_type* __to_end, + intern_type*& __to_nxt) const; + virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; + virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; + virtual int do_max_length() const _NOEXCEPT; +}; + +#endif + +// template <> class codecvt // deprecated in C++20 + +template <> +class _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_EXPORTED_FROM_ABI codecvt + : public locale::facet, public codecvt_base { +public: + typedef char32_t intern_type; + typedef char extern_type; + typedef mbstate_t state_type; + + _LIBCPP_HIDE_FROM_ABI explicit codecvt(size_t __refs = 0) : locale::facet(__refs) {} + + _LIBCPP_HIDE_FROM_ABI result + out(state_type& __st, + const intern_type* __frm, + const intern_type* __frm_end, + const intern_type*& __frm_nxt, + extern_type* __to, + extern_type* __to_end, + extern_type*& __to_nxt) const { + return do_out(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI result + unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const { + return do_unshift(__st, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI result + in(state_type& __st, + const extern_type* __frm, + const extern_type* __frm_end, + const extern_type*& __frm_nxt, + intern_type* __to, + intern_type* __to_end, + intern_type*& __to_nxt) const { + return do_in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); } + + _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); } + + _LIBCPP_HIDE_FROM_ABI int + length(state_type& __st, const extern_type* __frm, const extern_type* __end, size_t __mx) const { + return do_length(__st, __frm, __end, __mx); + } + + _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); } + + static locale::id id; + +protected: + _LIBCPP_HIDE_FROM_ABI explicit codecvt(const char*, size_t __refs = 0) : locale::facet(__refs) {} + + ~codecvt() override; + + virtual result + do_out(state_type& __st, + const intern_type* __frm, + const intern_type* __frm_end, + const intern_type*& __frm_nxt, + extern_type* __to, + extern_type* __to_end, + extern_type*& __to_nxt) const; + virtual result + do_in(state_type& __st, + const extern_type* __frm, + const extern_type* __frm_end, + const extern_type*& __frm_nxt, + intern_type* __to, + intern_type* __to_end, + intern_type*& __to_nxt) const; + virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; + virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; + virtual int do_max_length() const _NOEXCEPT; +}; + +#ifndef _LIBCPP_HAS_NO_CHAR8_T + +// template <> class codecvt // C++20 + +template <> +class _LIBCPP_EXPORTED_FROM_ABI codecvt : public locale::facet, public codecvt_base { +public: + typedef char32_t intern_type; + typedef char8_t extern_type; + typedef mbstate_t state_type; + + _LIBCPP_HIDE_FROM_ABI explicit codecvt(size_t __refs = 0) : locale::facet(__refs) {} + + _LIBCPP_HIDE_FROM_ABI result + out(state_type& __st, + const intern_type* __frm, + const intern_type* __frm_end, + const intern_type*& __frm_nxt, + extern_type* __to, + extern_type* __to_end, + extern_type*& __to_nxt) const { + return do_out(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI result + unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const { + return do_unshift(__st, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI result + in(state_type& __st, + const extern_type* __frm, + const extern_type* __frm_end, + const extern_type*& __frm_nxt, + intern_type* __to, + intern_type* __to_end, + intern_type*& __to_nxt) const { + return do_in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt); + } + + _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); } + + _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); } + + _LIBCPP_HIDE_FROM_ABI int + length(state_type& __st, const extern_type* __frm, const extern_type* __end, size_t __mx) const { + return do_length(__st, __frm, __end, __mx); + } + + _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); } + + static locale::id id; + +protected: + _LIBCPP_HIDE_FROM_ABI explicit codecvt(const char*, size_t __refs = 0) : locale::facet(__refs) {} + + ~codecvt() override; + + virtual result + do_out(state_type& __st, + const intern_type* __frm, + const intern_type* __frm_end, + const intern_type*& __frm_nxt, + extern_type* __to, + extern_type* __to_end, + extern_type*& __to_nxt) const; + virtual result + do_in(state_type& __st, + const extern_type* __frm, + const extern_type* __frm_end, + const extern_type*& __frm_nxt, + intern_type* __to, + intern_type* __to_end, + intern_type*& __to_nxt) const; + virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; + virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; + virtual int do_max_length() const _NOEXCEPT; +}; + +#endif + +// template class codecvt_byname + +template +class _LIBCPP_TEMPLATE_VIS codecvt_byname : public codecvt<_InternT, _ExternT, _StateT> { +public: + _LIBCPP_HIDE_FROM_ABI explicit codecvt_byname(const char* __nm, size_t __refs = 0) + : codecvt<_InternT, _ExternT, _StateT>(__nm, __refs) {} + _LIBCPP_HIDE_FROM_ABI explicit codecvt_byname(const string& __nm, size_t __refs = 0) + : codecvt<_InternT, _ExternT, _StateT>(__nm.c_str(), __refs) {} + +protected: + ~codecvt_byname() override; +}; + +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +template +codecvt_byname<_InternT, _ExternT, _StateT>::~codecvt_byname() {} +_LIBCPP_SUPPRESS_DEPRECATED_POP + +extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS codecvt_byname; +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS codecvt_byname; +#endif +extern template class _LIBCPP_DEPRECATED_IN_CXX20 +_LIBCPP_EXTERN_TEMPLATE_TYPE_VIS codecvt_byname; // deprecated in C++20 +extern template class _LIBCPP_DEPRECATED_IN_CXX20 +_LIBCPP_EXTERN_TEMPLATE_TYPE_VIS codecvt_byname; // deprecated in C++20 +#ifndef _LIBCPP_HAS_NO_CHAR8_T +extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS codecvt_byname; // C++20 +extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS codecvt_byname; // C++20 +#endif + +template +struct __narrow_to_utf8 { + template + _OutputIterator operator()(_OutputIterator __s, const _CharT* __wb, const _CharT* __we) const; +}; + +template <> +struct __narrow_to_utf8<8> { + template + _LIBCPP_HIDE_FROM_ABI _OutputIterator operator()(_OutputIterator __s, const _CharT* __wb, const _CharT* __we) const { + for (; __wb < __we; ++__wb, ++__s) + *__s = *__wb; + return __s; + } +}; + +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +template <> +struct _LIBCPP_EXPORTED_FROM_ABI __narrow_to_utf8<16> : public codecvt { + _LIBCPP_HIDE_FROM_ABI __narrow_to_utf8() : codecvt(1) {} + _LIBCPP_SUPPRESS_DEPRECATED_POP + + ~__narrow_to_utf8() override; + + template + _LIBCPP_HIDE_FROM_ABI _OutputIterator operator()(_OutputIterator __s, const _CharT* __wb, const _CharT* __we) const { + result __r = ok; + mbstate_t __mb; + while (__wb < __we && __r != error) { + const int __sz = 32; + char __buf[__sz]; + char* __bn; + const char16_t* __wn = (const char16_t*)__wb; + __r = do_out(__mb, (const char16_t*)__wb, (const char16_t*)__we, __wn, __buf, __buf + __sz, __bn); + if (__r == codecvt_base::error || __wn == (const char16_t*)__wb) + __throw_runtime_error("locale not supported"); + for (const char* __p = __buf; __p < __bn; ++__p, ++__s) + *__s = *__p; + __wb = (const _CharT*)__wn; + } + return __s; + } +}; + +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +template <> +struct _LIBCPP_EXPORTED_FROM_ABI __narrow_to_utf8<32> : public codecvt { + _LIBCPP_HIDE_FROM_ABI __narrow_to_utf8() : codecvt(1) {} + _LIBCPP_SUPPRESS_DEPRECATED_POP + + ~__narrow_to_utf8() override; + + template + _LIBCPP_HIDE_FROM_ABI _OutputIterator operator()(_OutputIterator __s, const _CharT* __wb, const _CharT* __we) const { + result __r = ok; + mbstate_t __mb; + while (__wb < __we && __r != error) { + const int __sz = 32; + char __buf[__sz]; + char* __bn; + const char32_t* __wn = (const char32_t*)__wb; + __r = do_out(__mb, (const char32_t*)__wb, (const char32_t*)__we, __wn, __buf, __buf + __sz, __bn); + if (__r == codecvt_base::error || __wn == (const char32_t*)__wb) + __throw_runtime_error("locale not supported"); + for (const char* __p = __buf; __p < __bn; ++__p, ++__s) + *__s = *__p; + __wb = (const _CharT*)__wn; + } + return __s; + } +}; + +template +struct __widen_from_utf8 { + template + _OutputIterator operator()(_OutputIterator __s, const char* __nb, const char* __ne) const; +}; + +template <> +struct __widen_from_utf8<8> { + template + _LIBCPP_HIDE_FROM_ABI _OutputIterator operator()(_OutputIterator __s, const char* __nb, const char* __ne) const { + for (; __nb < __ne; ++__nb, ++__s) + *__s = *__nb; + return __s; + } +}; + +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +template <> +struct _LIBCPP_EXPORTED_FROM_ABI __widen_from_utf8<16> : public codecvt { + _LIBCPP_HIDE_FROM_ABI __widen_from_utf8() : codecvt(1) {} + _LIBCPP_SUPPRESS_DEPRECATED_POP + + ~__widen_from_utf8() override; + + template + _LIBCPP_HIDE_FROM_ABI _OutputIterator operator()(_OutputIterator __s, const char* __nb, const char* __ne) const { + result __r = ok; + mbstate_t __mb; + while (__nb < __ne && __r != error) { + const int __sz = 32; + char16_t __buf[__sz]; + char16_t* __bn; + const char* __nn = __nb; + __r = do_in(__mb, __nb, __ne - __nb > __sz ? __nb + __sz : __ne, __nn, __buf, __buf + __sz, __bn); + if (__r == codecvt_base::error || __nn == __nb) + __throw_runtime_error("locale not supported"); + for (const char16_t* __p = __buf; __p < __bn; ++__p, ++__s) + *__s = *__p; + __nb = __nn; + } + return __s; + } +}; + +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +template <> +struct _LIBCPP_EXPORTED_FROM_ABI __widen_from_utf8<32> : public codecvt { + _LIBCPP_HIDE_FROM_ABI __widen_from_utf8() : codecvt(1) {} + _LIBCPP_SUPPRESS_DEPRECATED_POP + + ~__widen_from_utf8() override; + + template + _LIBCPP_HIDE_FROM_ABI _OutputIterator operator()(_OutputIterator __s, const char* __nb, const char* __ne) const { + result __r = ok; + mbstate_t __mb; + while (__nb < __ne && __r != error) { + const int __sz = 32; + char32_t __buf[__sz]; + char32_t* __bn; + const char* __nn = __nb; + __r = do_in(__mb, __nb, __ne - __nb > __sz ? __nb + __sz : __ne, __nn, __buf, __buf + __sz, __bn); + if (__r == codecvt_base::error || __nn == __nb) + __throw_runtime_error("locale not supported"); + for (const char32_t* __p = __buf; __p < __bn; ++__p, ++__s) + *__s = *__p; + __nb = __nn; + } + return __s; + } +}; + +// template class numpunct + +template +class _LIBCPP_TEMPLATE_VIS numpunct; + +template <> +class _LIBCPP_EXPORTED_FROM_ABI numpunct : public locale::facet { +public: + typedef char char_type; + typedef basic_string string_type; + + explicit numpunct(size_t __refs = 0); + + _LIBCPP_HIDE_FROM_ABI char_type decimal_point() const { return do_decimal_point(); } + _LIBCPP_HIDE_FROM_ABI char_type thousands_sep() const { return do_thousands_sep(); } + _LIBCPP_HIDE_FROM_ABI string grouping() const { return do_grouping(); } + _LIBCPP_HIDE_FROM_ABI string_type truename() const { return do_truename(); } + _LIBCPP_HIDE_FROM_ABI string_type falsename() const { return do_falsename(); } + + static locale::id id; + +protected: + ~numpunct() override; + virtual char_type do_decimal_point() const; + virtual char_type do_thousands_sep() const; + virtual string do_grouping() const; + virtual string_type do_truename() const; + virtual string_type do_falsename() const; + + char_type __decimal_point_; + char_type __thousands_sep_; + string __grouping_; +}; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <> +class _LIBCPP_EXPORTED_FROM_ABI numpunct : public locale::facet { +public: + typedef wchar_t char_type; + typedef basic_string string_type; + + explicit numpunct(size_t __refs = 0); + + _LIBCPP_HIDE_FROM_ABI char_type decimal_point() const { return do_decimal_point(); } + _LIBCPP_HIDE_FROM_ABI char_type thousands_sep() const { return do_thousands_sep(); } + _LIBCPP_HIDE_FROM_ABI string grouping() const { return do_grouping(); } + _LIBCPP_HIDE_FROM_ABI string_type truename() const { return do_truename(); } + _LIBCPP_HIDE_FROM_ABI string_type falsename() const { return do_falsename(); } + + static locale::id id; + +protected: + ~numpunct() override; + virtual char_type do_decimal_point() const; + virtual char_type do_thousands_sep() const; + virtual string do_grouping() const; + virtual string_type do_truename() const; + virtual string_type do_falsename() const; + + char_type __decimal_point_; + char_type __thousands_sep_; + string __grouping_; +}; +#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS + +// template class numpunct_byname + +template +class _LIBCPP_TEMPLATE_VIS numpunct_byname; + +template <> +class _LIBCPP_EXPORTED_FROM_ABI numpunct_byname : public numpunct { +public: + typedef char char_type; + typedef basic_string string_type; + + explicit numpunct_byname(const char* __nm, size_t __refs = 0); + explicit numpunct_byname(const string& __nm, size_t __refs = 0); + +protected: + ~numpunct_byname() override; + +private: + void __init(const char*); +}; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <> +class _LIBCPP_EXPORTED_FROM_ABI numpunct_byname : public numpunct { +public: + typedef wchar_t char_type; + typedef basic_string string_type; + + explicit numpunct_byname(const char* __nm, size_t __refs = 0); + explicit numpunct_byname(const string& __nm, size_t __refs = 0); + +protected: + ~numpunct_byname() override; + +private: + void __init(const char*); +}; +#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___LOCALE diff --git a/libcxx/include/__cxx03/__locale_dir/locale_base_api.h b/libcxx/include/__cxx03/__locale_dir/locale_base_api.h new file mode 100644 index 0000000000000000000000000000000000000000..8c000c558c52793f5f334d11898da8e7e8486388 --- /dev/null +++ b/libcxx/include/__cxx03/__locale_dir/locale_base_api.h @@ -0,0 +1,98 @@ +//===-----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_H +#define _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_H + +#if defined(_LIBCPP_MSVCRT_LIKE) +# include <__locale_dir/locale_base_api/win32.h> +#elif defined(_AIX) || defined(__MVS__) +# include <__locale_dir/locale_base_api/ibm.h> +#elif defined(__ANDROID__) +# include <__locale_dir/locale_base_api/android.h> +#elif defined(__sun__) +# include <__locale_dir/locale_base_api/solaris.h> +#elif defined(_NEWLIB_VERSION) +# include <__locale_dir/locale_base_api/newlib.h> +#elif defined(__OpenBSD__) +# include <__locale_dir/locale_base_api/openbsd.h> +#elif defined(__Fuchsia__) +# include <__locale_dir/locale_base_api/fuchsia.h> +#elif defined(__wasi__) || defined(_LIBCPP_HAS_MUSL_LIBC) +# include <__locale_dir/locale_base_api/musl.h> +#elif defined(__APPLE__) || defined(__FreeBSD__) +# include +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +/* +The platform-specific headers have to provide the following interface: + +// TODO: rename this to __libcpp_locale_t +using locale_t = implementation-defined; + +implementation-defined __libcpp_mb_cur_max_l(locale_t); +wint_t __libcpp_btowc_l(int, locale_t); +int __libcpp_wctob_l(wint_t, locale_t); +size_t __libcpp_wcsnrtombs_l(char* dest, const wchar_t** src, size_t wide_char_count, size_t len, mbstate_t, locale_t); +size_t __libcpp_wcrtomb_l(char* str, wchar_t wide_char, mbstate_t*, locale_t); +size_t __libcpp_mbsnrtowcs_l(wchar_t* dest, const char** src, size_t max_out, size_t len, mbstate_t*, locale_t); +size_t __libcpp_mbrtowc_l(wchar_t* dest, cosnt char* src, size_t count, mbstate_t*, locale_t); +int __libcpp_mbtowc_l(wchar_t* dest, const char* src, size_t count, locale_t); +size_t __libcpp_mbrlen_l(const char* str, size_t count, mbstate_t*, locale_t); +lconv* __libcpp_localeconv_l(locale_t); +size_t __libcpp_mbsrtowcs_l(wchar_t* dest, const char** src, size_t len, mbstate_t*, locale_t); +int __libcpp_snprintf_l(char* dest, size_t buff_size, locale_t, const char* format, ...); +int __libcpp_asprintf_l(char** dest, locale_t, const char* format, ...); +int __libcpp_sscanf_l(const char* dest, locale_t, const char* format, ...); + +// TODO: change these to reserved names +float strtof_l(const char* str, char** str_end, locale_t); +double strtod_l(const char* str, char** str_end, locale_t); +long double strtold_l(const char* str, char** str_end, locale_t); +long long strtoll_l(const char* str, char** str_end, locale_t); +unsigned long long strtoull_l(const char* str, char** str_end, locale_t); + +locale_t newlocale(int category_mask, const char* locale, locale_t base); +void freelocale(locale_t); + +int islower_l(int ch, locale_t); +int isupper_l(int ch, locale_t); +int isdigit_l(int ch, locale_t); +int isxdigit_l(int ch, locale_t); +int strcoll_l(const char* lhs, const char* rhs, locale_t); +size_t strxfrm_l(char* dst, const char* src, size_t n, locale_t); +int wcscoll_l(const char* lhs, const char* rhs, locale_t); +size_t wcsxfrm_l(wchar_t* dst, const wchar_t* src, size_t n, locale_t); +int toupper_l(int ch, locale_t); +int tolower_l(int ch, locale_t); +int iswspace_l(wint_t ch, locale_t); +int iswprint_l(wint_t ch, locale_t); +int iswcntrl_l(wint_t ch, locale_t); +int iswupper_l(wint_t ch, locale_t); +int iswlower_l(wint_t ch, locale_t); +int iswalpha_l(wint_t ch, locale_t); +int iswblank_l(wint_t ch, locale_t); +int iswdigit_l(wint_t ch, locale_t); +int iswpunct_l(wint_t ch, locale_t); +int iswxdigit_l(wint_t ch, locale_t); +wint_t towupper_l(wint_t ch, locale_t); +wint_t towlower_l(wint_t ch, locale_t); +size_t strftime_l(char* str, size_t len, const char* format, const tm*, locale_t); + + +These functions are equivalent to their C counterparts, +except that locale_t is used instead of the current global locale. + +The variadic functions may be implemented as templates with a parameter pack instead of variadic functions. +*/ + +#endif // _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_H diff --git a/libcxx/include/__cxx03/__locale_dir/locale_base_api/android.h b/libcxx/include/__cxx03/__locale_dir/locale_base_api/android.h new file mode 100644 index 0000000000000000000000000000000000000000..9965d8bbf6a2eccb9d75850293dc29fee70cce3a --- /dev/null +++ b/libcxx/include/__cxx03/__locale_dir/locale_base_api/android.h @@ -0,0 +1,50 @@ +// -*- C++ -*- +//===-----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___LOCALE_LOCALE_BASE_API_ANDROID_H +#define _LIBCPP___LOCALE_LOCALE_BASE_API_ANDROID_H + +#include + +// FIXME: Is this actually required? +extern "C" { +#include +} + +#include +#if __ANDROID_API__ < 21 +# include <__support/xlocale/__posix_l_fallback.h> +#endif + +// If we do not have this header, we are in a platform build rather than an NDK +// build, which will always be at least as new as the ToT NDK, in which case we +// don't need any of the inlines below since libc provides them. +#if __has_include() +# include +// In NDK versions later than 16, locale-aware functions are provided by +// legacy_stdlib_inlines.h +# if __NDK_MAJOR__ <= 16 +# if __ANDROID_API__ < 21 +# include <__support/xlocale/__strtonum_fallback.h> +# elif __ANDROID_API__ < 26 + +inline _LIBCPP_HIDE_FROM_ABI float strtof_l(const char* __nptr, char** __endptr, locale_t) { + return ::strtof(__nptr, __endptr); +} + +inline _LIBCPP_HIDE_FROM_ABI double strtod_l(const char* __nptr, char** __endptr, locale_t) { + return ::strtod(__nptr, __endptr); +} + +# endif // __ANDROID_API__ < 26 + +# endif // __NDK_MAJOR__ <= 16 +#endif // __has_include() + +#endif // _LIBCPP___LOCALE_LOCALE_BASE_API_ANDROID_H diff --git a/libcxx/include/__cxx03/__locale_dir/locale_base_api/bsd_locale_defaults.h b/libcxx/include/__cxx03/__locale_dir/locale_base_api/bsd_locale_defaults.h new file mode 100644 index 0000000000000000000000000000000000000000..1f9607209842cad26e1d2f2848ec2643da48c52f --- /dev/null +++ b/libcxx/include/__cxx03/__locale_dir/locale_base_api/bsd_locale_defaults.h @@ -0,0 +1,36 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// The BSDs have lots of *_l functions. We don't want to define those symbols +// on other platforms though, for fear of conflicts with user code. So here, +// we will define the mapping from an internal macro to the real BSD symbol. +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___LOCALE_LOCALE_BASE_API_BSD_LOCALE_DEFAULTS_H +#define _LIBCPP___LOCALE_LOCALE_BASE_API_BSD_LOCALE_DEFAULTS_H + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#define __libcpp_mb_cur_max_l(loc) MB_CUR_MAX_L(loc) +#define __libcpp_btowc_l(ch, loc) btowc_l(ch, loc) +#define __libcpp_wctob_l(wch, loc) wctob_l(wch, loc) +#define __libcpp_wcsnrtombs_l(dst, src, nwc, len, ps, loc) wcsnrtombs_l(dst, src, nwc, len, ps, loc) +#define __libcpp_wcrtomb_l(src, wc, ps, loc) wcrtomb_l(src, wc, ps, loc) +#define __libcpp_mbsnrtowcs_l(dst, src, nms, len, ps, loc) mbsnrtowcs_l(dst, src, nms, len, ps, loc) +#define __libcpp_mbrtowc_l(pwc, s, n, ps, l) mbrtowc_l(pwc, s, n, ps, l) +#define __libcpp_mbtowc_l(pwc, pmb, max, l) mbtowc_l(pwc, pmb, max, l) +#define __libcpp_mbrlen_l(s, n, ps, l) mbrlen_l(s, n, ps, l) +#define __libcpp_localeconv_l(l) localeconv_l(l) +#define __libcpp_mbsrtowcs_l(dest, src, len, ps, l) mbsrtowcs_l(dest, src, len, ps, l) +#define __libcpp_snprintf_l(...) snprintf_l(__VA_ARGS__) +#define __libcpp_asprintf_l(...) asprintf_l(__VA_ARGS__) +#define __libcpp_sscanf_l(...) sscanf_l(__VA_ARGS__) + +#endif // _LIBCPP___LOCALE_LOCALE_BASE_API_BSD_LOCALE_DEFAULTS_H diff --git a/libcxx/include/__cxx03/__locale_dir/locale_base_api/bsd_locale_fallbacks.h b/libcxx/include/__cxx03/__locale_dir/locale_base_api/bsd_locale_fallbacks.h new file mode 100644 index 0000000000000000000000000000000000000000..76b94287cd6cc88ba0e7fc0a157e3072ab197206 --- /dev/null +++ b/libcxx/include/__cxx03/__locale_dir/locale_base_api/bsd_locale_fallbacks.h @@ -0,0 +1,126 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// The BSDs have lots of *_l functions. This file provides reimplementations +// of those functions for non-BSD platforms. +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___LOCALE_LOCALE_BASE_API_BSD_LOCALE_FALLBACKS_H +#define _LIBCPP___LOCALE_LOCALE_BASE_API_BSD_LOCALE_FALLBACKS_H + +#include <__locale_dir/locale_base_api/locale_guard.h> +#include +#include +#include + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +# include +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +inline _LIBCPP_HIDE_FROM_ABI decltype(MB_CUR_MAX) __libcpp_mb_cur_max_l(locale_t __l) { + __libcpp_locale_guard __current(__l); + return MB_CUR_MAX; +} + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +inline _LIBCPP_HIDE_FROM_ABI wint_t __libcpp_btowc_l(int __c, locale_t __l) { + __libcpp_locale_guard __current(__l); + return btowc(__c); +} + +inline _LIBCPP_HIDE_FROM_ABI int __libcpp_wctob_l(wint_t __c, locale_t __l) { + __libcpp_locale_guard __current(__l); + return wctob(__c); +} + +inline _LIBCPP_HIDE_FROM_ABI size_t +__libcpp_wcsnrtombs_l(char* __dest, const wchar_t** __src, size_t __nwc, size_t __len, mbstate_t* __ps, locale_t __l) { + __libcpp_locale_guard __current(__l); + return wcsnrtombs(__dest, __src, __nwc, __len, __ps); +} + +inline _LIBCPP_HIDE_FROM_ABI size_t __libcpp_wcrtomb_l(char* __s, wchar_t __wc, mbstate_t* __ps, locale_t __l) { + __libcpp_locale_guard __current(__l); + return wcrtomb(__s, __wc, __ps); +} + +inline _LIBCPP_HIDE_FROM_ABI size_t +__libcpp_mbsnrtowcs_l(wchar_t* __dest, const char** __src, size_t __nms, size_t __len, mbstate_t* __ps, locale_t __l) { + __libcpp_locale_guard __current(__l); + return mbsnrtowcs(__dest, __src, __nms, __len, __ps); +} + +inline _LIBCPP_HIDE_FROM_ABI size_t +__libcpp_mbrtowc_l(wchar_t* __pwc, const char* __s, size_t __n, mbstate_t* __ps, locale_t __l) { + __libcpp_locale_guard __current(__l); + return mbrtowc(__pwc, __s, __n, __ps); +} + +inline _LIBCPP_HIDE_FROM_ABI int __libcpp_mbtowc_l(wchar_t* __pwc, const char* __pmb, size_t __max, locale_t __l) { + __libcpp_locale_guard __current(__l); + return mbtowc(__pwc, __pmb, __max); +} + +inline _LIBCPP_HIDE_FROM_ABI size_t __libcpp_mbrlen_l(const char* __s, size_t __n, mbstate_t* __ps, locale_t __l) { + __libcpp_locale_guard __current(__l); + return mbrlen(__s, __n, __ps); +} +#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS + +inline _LIBCPP_HIDE_FROM_ABI lconv* __libcpp_localeconv_l(locale_t __l) { + __libcpp_locale_guard __current(__l); + return localeconv(); +} + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +inline _LIBCPP_HIDE_FROM_ABI size_t +__libcpp_mbsrtowcs_l(wchar_t* __dest, const char** __src, size_t __len, mbstate_t* __ps, locale_t __l) { + __libcpp_locale_guard __current(__l); + return mbsrtowcs(__dest, __src, __len, __ps); +} +#endif + +inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 4, 5) int __libcpp_snprintf_l( + char* __s, size_t __n, locale_t __l, const char* __format, ...) { + va_list __va; + va_start(__va, __format); + __libcpp_locale_guard __current(__l); + int __res = vsnprintf(__s, __n, __format, __va); + va_end(__va); + return __res; +} + +inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __libcpp_asprintf_l( + char** __s, locale_t __l, const char* __format, ...) { + va_list __va; + va_start(__va, __format); + __libcpp_locale_guard __current(__l); + int __res = vasprintf(__s, __format, __va); + va_end(__va); + return __res; +} + +inline _LIBCPP_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __libcpp_sscanf_l( + const char* __s, locale_t __l, const char* __format, ...) { + va_list __va; + va_start(__va, __format); + __libcpp_locale_guard __current(__l); + int __res = vsscanf(__s, __format, __va); + va_end(__va); + return __res; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___LOCALE_LOCALE_BASE_API_BSD_LOCALE_FALLBACKS_H diff --git a/libcxx/include/__cxx03/__locale_dir/locale_base_api/fuchsia.h b/libcxx/include/__cxx03/__locale_dir/locale_base_api/fuchsia.h new file mode 100644 index 0000000000000000000000000000000000000000..4c3440f981c6d0820ca6341836605a95e4dca957 --- /dev/null +++ b/libcxx/include/__cxx03/__locale_dir/locale_base_api/fuchsia.h @@ -0,0 +1,18 @@ +// -*- C++ -*- +//===-----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___LOCALE_LOCALE_BASE_API_FUCHSIA_H +#define _LIBCPP___LOCALE_LOCALE_BASE_API_FUCHSIA_H + +#include <__support/xlocale/__posix_l_fallback.h> +#include <__support/xlocale/__strtonum_fallback.h> +#include +#include + +#endif // _LIBCPP___LOCALE_LOCALE_BASE_API_FUCHSIA_H diff --git a/libcxx/include/__cxx03/__locale_dir/locale_base_api/ibm.h b/libcxx/include/__cxx03/__locale_dir/locale_base_api/ibm.h new file mode 100644 index 0000000000000000000000000000000000000000..01af20194428b94d3e7bb90d07a9c43448ae93b9 --- /dev/null +++ b/libcxx/include/__cxx03/__locale_dir/locale_base_api/ibm.h @@ -0,0 +1,108 @@ +// -*- C++ -*- +//===-----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___LOCALE_LOCALE_BASE_API_IBM_H +#define _LIBCPP___LOCALE_LOCALE_BASE_API_IBM_H + +#if defined(__MVS__) +# include <__support/ibm/locale_mgmt_zos.h> +#endif // defined(__MVS__) + +#include +#include +#include + +#include "cstdlib" + +#if defined(__MVS__) +# include +// POSIX routines +# include <__support/xlocale/__posix_l_fallback.h> +#endif // defined(__MVS__) + +namespace { + +struct __setAndRestore { + explicit __setAndRestore(locale_t locale) { + if (locale == (locale_t)0) { + __cloc = newlocale(LC_ALL_MASK, "C", /* base */ (locale_t)0); + __stored = uselocale(__cloc); + } else { + __stored = uselocale(locale); + } + } + + ~__setAndRestore() { + uselocale(__stored); + if (__cloc) + freelocale(__cloc); + } + +private: + locale_t __stored = (locale_t)0; + locale_t __cloc = (locale_t)0; +}; + +} // namespace + +// The following are not POSIX routines. These are quick-and-dirty hacks +// to make things pretend to work +inline _LIBCPP_HIDE_FROM_ABI long long strtoll_l(const char* __nptr, char** __endptr, int __base, locale_t locale) { + __setAndRestore __newloc(locale); + return ::strtoll(__nptr, __endptr, __base); +} + +inline _LIBCPP_HIDE_FROM_ABI double strtod_l(const char* __nptr, char** __endptr, locale_t locale) { + __setAndRestore __newloc(locale); + return ::strtod(__nptr, __endptr); +} + +inline _LIBCPP_HIDE_FROM_ABI float strtof_l(const char* __nptr, char** __endptr, locale_t locale) { + __setAndRestore __newloc(locale); + return ::strtof(__nptr, __endptr); +} + +inline _LIBCPP_HIDE_FROM_ABI long double strtold_l(const char* __nptr, char** __endptr, locale_t locale) { + __setAndRestore __newloc(locale); + return ::strtold(__nptr, __endptr); +} + +inline _LIBCPP_HIDE_FROM_ABI unsigned long long +strtoull_l(const char* __nptr, char** __endptr, int __base, locale_t locale) { + __setAndRestore __newloc(locale); + return ::strtoull(__nptr, __endptr, __base); +} + +inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_ATTRIBUTE_FORMAT(__printf__, 2, 0) int vasprintf(char** strp, const char* fmt, va_list ap) { + const size_t buff_size = 256; + if ((*strp = (char*)malloc(buff_size)) == NULL) { + return -1; + } + + va_list ap_copy; + // va_copy may not be provided by the C library in C++03 mode. +#if defined(_LIBCPP_CXX03_LANG) && __has_builtin(__builtin_va_copy) + __builtin_va_copy(ap_copy, ap); +#else + va_copy(ap_copy, ap); +#endif + int str_size = vsnprintf(*strp, buff_size, fmt, ap_copy); + va_end(ap_copy); + + if ((size_t)str_size >= buff_size) { + if ((*strp = (char*)realloc(*strp, str_size + 1)) == NULL) { + return -1; + } + str_size = vsnprintf(*strp, str_size + 1, fmt, ap); + } + return str_size; +} + +#endif // _LIBCPP___LOCALE_LOCALE_BASE_API_IBM_H diff --git a/libcxx/include/__locale_dir/locale_base_api/locale_guard.h b/libcxx/include/__cxx03/__locale_dir/locale_base_api/locale_guard.h similarity index 100% rename from libcxx/include/__locale_dir/locale_base_api/locale_guard.h rename to libcxx/include/__cxx03/__locale_dir/locale_base_api/locale_guard.h diff --git a/libcxx/include/__cxx03/__locale_dir/locale_base_api/musl.h b/libcxx/include/__cxx03/__locale_dir/locale_base_api/musl.h new file mode 100644 index 0000000000000000000000000000000000000000..bf7b849d5863421c65972b94cfc09e6f6406e7e5 --- /dev/null +++ b/libcxx/include/__cxx03/__locale_dir/locale_base_api/musl.h @@ -0,0 +1,31 @@ +// -*- C++ -*- +//===-----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// This adds support for the extended locale functions that are currently +// missing from the Musl C library. +// +// This only works when the specified locale is "C" or "POSIX", but that's +// about as good as we can do without implementing full xlocale support +// in Musl. +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___LOCALE_LOCALE_BASE_API_MUSL_H +#define _LIBCPP___LOCALE_LOCALE_BASE_API_MUSL_H + +#include +#include + +inline _LIBCPP_HIDE_FROM_ABI long long strtoll_l(const char* __nptr, char** __endptr, int __base, locale_t) { + return ::strtoll(__nptr, __endptr, __base); +} + +inline _LIBCPP_HIDE_FROM_ABI unsigned long long strtoull_l(const char* __nptr, char** __endptr, int __base, locale_t) { + return ::strtoull(__nptr, __endptr, __base); +} + +#endif // _LIBCPP___LOCALE_LOCALE_BASE_API_MUSL_H diff --git a/libcxx/include/__locale_dir/locale_base_api/newlib.h b/libcxx/include/__cxx03/__locale_dir/locale_base_api/newlib.h similarity index 100% rename from libcxx/include/__locale_dir/locale_base_api/newlib.h rename to libcxx/include/__cxx03/__locale_dir/locale_base_api/newlib.h diff --git a/libcxx/include/__cxx03/__locale_dir/locale_base_api/openbsd.h b/libcxx/include/__cxx03/__locale_dir/locale_base_api/openbsd.h new file mode 100644 index 0000000000000000000000000000000000000000..0c05d6a0f7887476e1163415f41d2a9137e7a576 --- /dev/null +++ b/libcxx/include/__cxx03/__locale_dir/locale_base_api/openbsd.h @@ -0,0 +1,19 @@ +// -*- C++ -*- +//===-----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___LOCALE_LOCALE_BASE_API_OPENBSD_H +#define _LIBCPP___LOCALE_LOCALE_BASE_API_OPENBSD_H + +#include <__support/xlocale/__strtonum_fallback.h> +#include +#include +#include +#include + +#endif // _LIBCPP___LOCALE_LOCALE_BASE_API_OPENBSD_H diff --git a/libcxx/include/__cxx03/__locale_dir/locale_base_api/win32.h b/libcxx/include/__cxx03/__locale_dir/locale_base_api/win32.h new file mode 100644 index 0000000000000000000000000000000000000000..f66baffb6920456e15053d7a44b056c435bcf398 --- /dev/null +++ b/libcxx/include/__cxx03/__locale_dir/locale_base_api/win32.h @@ -0,0 +1,235 @@ +// -*- C++ -*- +//===-----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___LOCALE_LOCALE_BASE_API_WIN32_H +#define _LIBCPP___LOCALE_LOCALE_BASE_API_WIN32_H + +#include <__config> +#include +#include // _locale_t +#include +#include + +#define _X_ALL LC_ALL +#define _X_COLLATE LC_COLLATE +#define _X_CTYPE LC_CTYPE +#define _X_MONETARY LC_MONETARY +#define _X_NUMERIC LC_NUMERIC +#define _X_TIME LC_TIME +#define _X_MAX LC_MAX +#define _X_MESSAGES 6 +#define _NCAT (_X_MESSAGES + 1) + +#define _CATMASK(n) ((1 << (n)) >> 1) +#define _M_COLLATE _CATMASK(_X_COLLATE) +#define _M_CTYPE _CATMASK(_X_CTYPE) +#define _M_MONETARY _CATMASK(_X_MONETARY) +#define _M_NUMERIC _CATMASK(_X_NUMERIC) +#define _M_TIME _CATMASK(_X_TIME) +#define _M_MESSAGES _CATMASK(_X_MESSAGES) +#define _M_ALL (_CATMASK(_NCAT) - 1) + +#define LC_COLLATE_MASK _M_COLLATE +#define LC_CTYPE_MASK _M_CTYPE +#define LC_MONETARY_MASK _M_MONETARY +#define LC_NUMERIC_MASK _M_NUMERIC +#define LC_TIME_MASK _M_TIME +#define LC_MESSAGES_MASK _M_MESSAGES +#define LC_ALL_MASK \ + (LC_COLLATE_MASK | LC_CTYPE_MASK | LC_MESSAGES_MASK | LC_MONETARY_MASK | LC_NUMERIC_MASK | LC_TIME_MASK) + +class __lconv_storage { +public: + __lconv_storage(const lconv* __lc_input) { + __lc_ = *__lc_input; + + __decimal_point_ = __lc_input->decimal_point; + __thousands_sep_ = __lc_input->thousands_sep; + __grouping_ = __lc_input->grouping; + __int_curr_symbol_ = __lc_input->int_curr_symbol; + __currency_symbol_ = __lc_input->currency_symbol; + __mon_decimal_point_ = __lc_input->mon_decimal_point; + __mon_thousands_sep_ = __lc_input->mon_thousands_sep; + __mon_grouping_ = __lc_input->mon_grouping; + __positive_sign_ = __lc_input->positive_sign; + __negative_sign_ = __lc_input->negative_sign; + + __lc_.decimal_point = const_cast(__decimal_point_.c_str()); + __lc_.thousands_sep = const_cast(__thousands_sep_.c_str()); + __lc_.grouping = const_cast(__grouping_.c_str()); + __lc_.int_curr_symbol = const_cast(__int_curr_symbol_.c_str()); + __lc_.currency_symbol = const_cast(__currency_symbol_.c_str()); + __lc_.mon_decimal_point = const_cast(__mon_decimal_point_.c_str()); + __lc_.mon_thousands_sep = const_cast(__mon_thousands_sep_.c_str()); + __lc_.mon_grouping = const_cast(__mon_grouping_.c_str()); + __lc_.positive_sign = const_cast(__positive_sign_.c_str()); + __lc_.negative_sign = const_cast(__negative_sign_.c_str()); + } + + lconv* __get() { return &__lc_; } + +private: + lconv __lc_; + std::string __decimal_point_; + std::string __thousands_sep_; + std::string __grouping_; + std::string __int_curr_symbol_; + std::string __currency_symbol_; + std::string __mon_decimal_point_; + std::string __mon_thousands_sep_; + std::string __mon_grouping_; + std::string __positive_sign_; + std::string __negative_sign_; +}; + +class locale_t { +public: + locale_t() : __locale_(nullptr), __locale_str_(nullptr), __lc_(nullptr) {} + locale_t(std::nullptr_t) : __locale_(nullptr), __locale_str_(nullptr), __lc_(nullptr) {} + locale_t(_locale_t __xlocale, const char* __xlocale_str) + : __locale_(__xlocale), __locale_str_(__xlocale_str), __lc_(nullptr) {} + locale_t(const locale_t& __l) : __locale_(__l.__locale_), __locale_str_(__l.__locale_str_), __lc_(nullptr) {} + + ~locale_t() { delete __lc_; } + + locale_t& operator=(const locale_t& __l) { + __locale_ = __l.__locale_; + __locale_str_ = __l.__locale_str_; + // __lc_ not copied + return *this; + } + + friend bool operator==(const locale_t& __left, const locale_t& __right) { + return __left.__locale_ == __right.__locale_; + } + + friend bool operator==(const locale_t& __left, int __right) { return __left.__locale_ == nullptr && __right == 0; } + + friend bool operator==(const locale_t& __left, long long __right) { + return __left.__locale_ == nullptr && __right == 0; + } + + friend bool operator==(const locale_t& __left, std::nullptr_t) { return __left.__locale_ == nullptr; } + + friend bool operator==(int __left, const locale_t& __right) { return __left == 0 && nullptr == __right.__locale_; } + + friend bool operator==(std::nullptr_t, const locale_t& __right) { return nullptr == __right.__locale_; } + + friend bool operator!=(const locale_t& __left, const locale_t& __right) { return !(__left == __right); } + + friend bool operator!=(const locale_t& __left, int __right) { return !(__left == __right); } + + friend bool operator!=(const locale_t& __left, long long __right) { return !(__left == __right); } + + friend bool operator!=(const locale_t& __left, std::nullptr_t __right) { return !(__left == __right); } + + friend bool operator!=(int __left, const locale_t& __right) { return !(__left == __right); } + + friend bool operator!=(std::nullptr_t __left, const locale_t& __right) { return !(__left == __right); } + + operator bool() const { return __locale_ != nullptr; } + + const char* __get_locale() const { return __locale_str_; } + + operator _locale_t() const { return __locale_; } + + lconv* __store_lconv(const lconv* __input_lc) { + delete __lc_; + __lc_ = new __lconv_storage(__input_lc); + return __lc_->__get(); + } + +private: + _locale_t __locale_; + const char* __locale_str_; + __lconv_storage* __lc_ = nullptr; +}; + +// Locale management functions +#define freelocale _free_locale +// FIXME: base currently unused. Needs manual work to construct the new locale +locale_t newlocale(int __mask, const char* __locale, locale_t __base); +// uselocale can't be implemented on Windows because Windows allows partial modification +// of thread-local locale and so _get_current_locale() returns a copy while uselocale does +// not create any copies. +// We can still implement raii even without uselocale though. + +lconv* localeconv_l(locale_t& __loc); +size_t mbrlen_l(const char* __restrict __s, size_t __n, mbstate_t* __restrict __ps, locale_t __loc); +size_t mbsrtowcs_l( + wchar_t* __restrict __dst, const char** __restrict __src, size_t __len, mbstate_t* __restrict __ps, locale_t __loc); +size_t wcrtomb_l(char* __restrict __s, wchar_t __wc, mbstate_t* __restrict __ps, locale_t __loc); +size_t mbrtowc_l( + wchar_t* __restrict __pwc, const char* __restrict __s, size_t __n, mbstate_t* __restrict __ps, locale_t __loc); +size_t mbsnrtowcs_l(wchar_t* __restrict __dst, + const char** __restrict __src, + size_t __nms, + size_t __len, + mbstate_t* __restrict __ps, + locale_t __loc); +size_t wcsnrtombs_l(char* __restrict __dst, + const wchar_t** __restrict __src, + size_t __nwc, + size_t __len, + mbstate_t* __restrict __ps, + locale_t __loc); +wint_t btowc_l(int __c, locale_t __loc); +int wctob_l(wint_t __c, locale_t __loc); + +decltype(MB_CUR_MAX) MB_CUR_MAX_L(locale_t __l); + +// the *_l functions are prefixed on Windows, only available for msvcr80+, VS2005+ +#define mbtowc_l _mbtowc_l +#define strtoll_l _strtoi64_l +#define strtoull_l _strtoui64_l +#define strtod_l _strtod_l +#if defined(_LIBCPP_MSVCRT) +# define strtof_l _strtof_l +# define strtold_l _strtold_l +#else +_LIBCPP_EXPORTED_FROM_ABI float strtof_l(const char*, char**, locale_t); +_LIBCPP_EXPORTED_FROM_ABI long double strtold_l(const char*, char**, locale_t); +#endif +inline _LIBCPP_HIDE_FROM_ABI int islower_l(int __c, _locale_t __loc) { return _islower_l((int)__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI int isupper_l(int __c, _locale_t __loc) { return _isupper_l((int)__c, __loc); } + +#define isdigit_l _isdigit_l +#define isxdigit_l _isxdigit_l +#define strcoll_l _strcoll_l +#define strxfrm_l _strxfrm_l +#define wcscoll_l _wcscoll_l +#define wcsxfrm_l _wcsxfrm_l +#define toupper_l _toupper_l +#define tolower_l _tolower_l +#define iswspace_l _iswspace_l +#define iswprint_l _iswprint_l +#define iswcntrl_l _iswcntrl_l +#define iswupper_l _iswupper_l +#define iswlower_l _iswlower_l +#define iswalpha_l _iswalpha_l +#define iswdigit_l _iswdigit_l +#define iswpunct_l _iswpunct_l +#define iswxdigit_l _iswxdigit_l +#define towupper_l _towupper_l +#define towlower_l _towlower_l +#if defined(__MINGW32__) && __MSVCRT_VERSION__ < 0x0800 +_LIBCPP_EXPORTED_FROM_ABI size_t strftime_l(char* ret, size_t n, const char* format, const struct tm* tm, locale_t loc); +#else +# define strftime_l _strftime_l +#endif +#define sscanf_l(__s, __l, __f, ...) _sscanf_l(__s, __f, __l, __VA_ARGS__) +_LIBCPP_EXPORTED_FROM_ABI int snprintf_l(char* __ret, size_t __n, locale_t __loc, const char* __format, ...); +_LIBCPP_EXPORTED_FROM_ABI int asprintf_l(char** __ret, locale_t __loc, const char* __format, ...); +_LIBCPP_EXPORTED_FROM_ABI int vasprintf_l(char** __ret, locale_t __loc, const char* __format, va_list __ap); + +// not-so-pressing FIXME: use locale to determine blank characters +inline int iswblank_l(wint_t __c, locale_t /*loc*/) { return (__c == L' ' || __c == L'\t'); } + +#endif // _LIBCPP___LOCALE_LOCALE_BASE_API_WIN32_H diff --git a/libcxx/include/__cxx03/__math/abs.h b/libcxx/include/__cxx03/__math/abs.h new file mode 100644 index 0000000000000000000000000000000000000000..ab82a2800f53c918c5cdf6cdfc9ade264167f245 --- /dev/null +++ b/libcxx/include/__cxx03/__math/abs.h @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_ABS_H +#define _LIBCPP___MATH_ABS_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_integral.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// fabs + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI float fabs(float __x) _NOEXCEPT { return __builtin_fabsf(__x); } + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI double fabs(double __x) _NOEXCEPT { + return __builtin_fabs(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI long double fabs(long double __x) _NOEXCEPT { + return __builtin_fabsl(__x); +} + +template ::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI double fabs(_A1 __x) _NOEXCEPT { + return __builtin_fabs((double)__x); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_ABS_H diff --git a/libcxx/include/__cxx03/__math/copysign.h b/libcxx/include/__cxx03/__math/copysign.h new file mode 100644 index 0000000000000000000000000000000000000000..b38690bb581a1155325bf9a25d4e2a4399a8e7b2 --- /dev/null +++ b/libcxx/include/__cxx03/__math/copysign.h @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_COPYSIGN_H +#define _LIBCPP___MATH_COPYSIGN_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/promote.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// copysign + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI float copysign(float __x, float __y) _NOEXCEPT { + return ::__builtin_copysignf(__x, __y); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI long double copysign(long double __x, long double __y) _NOEXCEPT { + return ::__builtin_copysignl(__x, __y); +} + +template ::value && is_arithmetic<_A2>::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type copysign(_A1 __x, _A2 __y) _NOEXCEPT { + return ::__builtin_copysign(__x, __y); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_COPYSIGN_H diff --git a/libcxx/include/__cxx03/__math/error_functions.h b/libcxx/include/__cxx03/__math/error_functions.h new file mode 100644 index 0000000000000000000000000000000000000000..6b528bb290001a36170c6b1bea94c95b8d3b79f1 --- /dev/null +++ b/libcxx/include/__cxx03/__math/error_functions.h @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_ERROR_FUNCTIONS_H +#define _LIBCPP___MATH_ERROR_FUNCTIONS_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_integral.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// erf + +inline _LIBCPP_HIDE_FROM_ABI float erf(float __x) _NOEXCEPT { return __builtin_erff(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double erf(double __x) _NOEXCEPT { + return __builtin_erf(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double erf(long double __x) _NOEXCEPT { return __builtin_erfl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double erf(_A1 __x) _NOEXCEPT { + return __builtin_erf((double)__x); +} + +// erfc + +inline _LIBCPP_HIDE_FROM_ABI float erfc(float __x) _NOEXCEPT { return __builtin_erfcf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double erfc(double __x) _NOEXCEPT { + return __builtin_erfc(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double erfc(long double __x) _NOEXCEPT { return __builtin_erfcl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double erfc(_A1 __x) _NOEXCEPT { + return __builtin_erfc((double)__x); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_ERROR_FUNCTIONS_H diff --git a/libcxx/include/__cxx03/__math/exponential_functions.h b/libcxx/include/__cxx03/__math/exponential_functions.h new file mode 100644 index 0000000000000000000000000000000000000000..109c3349970f67ad0545fc0bf9b42d6db840df6d --- /dev/null +++ b/libcxx/include/__cxx03/__math/exponential_functions.h @@ -0,0 +1,171 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_EXPONENTIAL_FUNCTIONS_H +#define _LIBCPP___MATH_EXPONENTIAL_FUNCTIONS_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_integral.h> +#include <__type_traits/is_same.h> +#include <__type_traits/promote.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// exp + +inline _LIBCPP_HIDE_FROM_ABI float exp(float __x) _NOEXCEPT { return __builtin_expf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double exp(double __x) _NOEXCEPT { + return __builtin_exp(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double exp(long double __x) _NOEXCEPT { return __builtin_expl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double exp(_A1 __x) _NOEXCEPT { + return __builtin_exp((double)__x); +} + +// frexp + +inline _LIBCPP_HIDE_FROM_ABI float frexp(float __x, int* __e) _NOEXCEPT { return __builtin_frexpf(__x, __e); } + +template +_LIBCPP_HIDE_FROM_ABI double frexp(double __x, int* __e) _NOEXCEPT { + return __builtin_frexp(__x, __e); +} + +inline _LIBCPP_HIDE_FROM_ABI long double frexp(long double __x, int* __e) _NOEXCEPT { + return __builtin_frexpl(__x, __e); +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double frexp(_A1 __x, int* __e) _NOEXCEPT { + return __builtin_frexp((double)__x, __e); +} + +// ldexp + +inline _LIBCPP_HIDE_FROM_ABI float ldexp(float __x, int __e) _NOEXCEPT { return __builtin_ldexpf(__x, __e); } + +template +_LIBCPP_HIDE_FROM_ABI double ldexp(double __x, int __e) _NOEXCEPT { + return __builtin_ldexp(__x, __e); +} + +inline _LIBCPP_HIDE_FROM_ABI long double ldexp(long double __x, int __e) _NOEXCEPT { + return __builtin_ldexpl(__x, __e); +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double ldexp(_A1 __x, int __e) _NOEXCEPT { + return __builtin_ldexp((double)__x, __e); +} + +// exp2 + +inline _LIBCPP_HIDE_FROM_ABI float exp2(float __x) _NOEXCEPT { return __builtin_exp2f(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double exp2(double __x) _NOEXCEPT { + return __builtin_exp2(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double exp2(long double __x) _NOEXCEPT { return __builtin_exp2l(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double exp2(_A1 __x) _NOEXCEPT { + return __builtin_exp2((double)__x); +} + +// expm1 + +inline _LIBCPP_HIDE_FROM_ABI float expm1(float __x) _NOEXCEPT { return __builtin_expm1f(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double expm1(double __x) _NOEXCEPT { + return __builtin_expm1(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double expm1(long double __x) _NOEXCEPT { return __builtin_expm1l(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double expm1(_A1 __x) _NOEXCEPT { + return __builtin_expm1((double)__x); +} + +// scalbln + +inline _LIBCPP_HIDE_FROM_ABI float scalbln(float __x, long __y) _NOEXCEPT { return __builtin_scalblnf(__x, __y); } + +template +_LIBCPP_HIDE_FROM_ABI double scalbln(double __x, long __y) _NOEXCEPT { + return __builtin_scalbln(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI long double scalbln(long double __x, long __y) _NOEXCEPT { + return __builtin_scalblnl(__x, __y); +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double scalbln(_A1 __x, long __y) _NOEXCEPT { + return __builtin_scalbln((double)__x, __y); +} + +// scalbn + +inline _LIBCPP_HIDE_FROM_ABI float scalbn(float __x, int __y) _NOEXCEPT { return __builtin_scalbnf(__x, __y); } + +template +_LIBCPP_HIDE_FROM_ABI double scalbn(double __x, int __y) _NOEXCEPT { + return __builtin_scalbn(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI long double scalbn(long double __x, int __y) _NOEXCEPT { + return __builtin_scalbnl(__x, __y); +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double scalbn(_A1 __x, int __y) _NOEXCEPT { + return __builtin_scalbn((double)__x, __y); +} + +// pow + +inline _LIBCPP_HIDE_FROM_ABI float pow(float __x, float __y) _NOEXCEPT { return __builtin_powf(__x, __y); } + +template +_LIBCPP_HIDE_FROM_ABI double pow(double __x, double __y) _NOEXCEPT { + return __builtin_pow(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI long double pow(long double __x, long double __y) _NOEXCEPT { + return __builtin_powl(__x, __y); +} + +template ::value && is_arithmetic<_A2>::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type pow(_A1 __x, _A2 __y) _NOEXCEPT { + using __result_type = typename __promote<_A1, _A2>::type; + static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), ""); + return __math::pow((__result_type)__x, (__result_type)__y); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_EXPONENTIAL_FUNCTIONS_H diff --git a/libcxx/include/__cxx03/__math/fdim.h b/libcxx/include/__cxx03/__math/fdim.h new file mode 100644 index 0000000000000000000000000000000000000000..dc1b4ecc07dce4a136c69d92496f14c8fbae7af9 --- /dev/null +++ b/libcxx/include/__cxx03/__math/fdim.h @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_FDIM_H +#define _LIBCPP___MATH_FDIM_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_same.h> +#include <__type_traits/promote.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +inline _LIBCPP_HIDE_FROM_ABI float fdim(float __x, float __y) _NOEXCEPT { return __builtin_fdimf(__x, __y); } + +template +_LIBCPP_HIDE_FROM_ABI double fdim(double __x, double __y) _NOEXCEPT { + return __builtin_fdim(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI long double fdim(long double __x, long double __y) _NOEXCEPT { + return __builtin_fdiml(__x, __y); +} + +template ::value && is_arithmetic<_A2>::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type fdim(_A1 __x, _A2 __y) _NOEXCEPT { + using __result_type = typename __promote<_A1, _A2>::type; + static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), ""); + return __math::fdim((__result_type)__x, (__result_type)__y); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_FDIM_H diff --git a/libcxx/include/__cxx03/__math/fma.h b/libcxx/include/__cxx03/__math/fma.h new file mode 100644 index 0000000000000000000000000000000000000000..6ba7a5a2d26d6074d30ce1a50838a7c445f0efe7 --- /dev/null +++ b/libcxx/include/__cxx03/__math/fma.h @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_FMA_H +#define _LIBCPP___MATH_FMA_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_same.h> +#include <__type_traits/promote.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +inline _LIBCPP_HIDE_FROM_ABI float fma(float __x, float __y, float __z) _NOEXCEPT { + return __builtin_fmaf(__x, __y, __z); +} + +template +_LIBCPP_HIDE_FROM_ABI double fma(double __x, double __y, double __z) _NOEXCEPT { + return __builtin_fma(__x, __y, __z); +} + +inline _LIBCPP_HIDE_FROM_ABI long double fma(long double __x, long double __y, long double __z) _NOEXCEPT { + return __builtin_fmal(__x, __y, __z); +} + +template ::value && is_arithmetic<_A2>::value && is_arithmetic<_A3>::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2, _A3>::type fma(_A1 __x, _A2 __y, _A3 __z) _NOEXCEPT { + using __result_type = typename __promote<_A1, _A2, _A3>::type; + static_assert( + !(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value && _IsSame<_A3, __result_type>::value), + ""); + return __builtin_fma((__result_type)__x, (__result_type)__y, (__result_type)__z); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_FMA_H diff --git a/libcxx/include/__cxx03/__math/gamma.h b/libcxx/include/__cxx03/__math/gamma.h new file mode 100644 index 0000000000000000000000000000000000000000..693e111a84e99dfa1197cc6d2ed81ce0edcbdb86 --- /dev/null +++ b/libcxx/include/__cxx03/__math/gamma.h @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_GAMMA_H +#define _LIBCPP___MATH_GAMMA_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_integral.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// lgamma + +inline _LIBCPP_HIDE_FROM_ABI float lgamma(float __x) _NOEXCEPT { return __builtin_lgammaf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double lgamma(double __x) _NOEXCEPT { + return __builtin_lgamma(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double lgamma(long double __x) _NOEXCEPT { return __builtin_lgammal(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double lgamma(_A1 __x) _NOEXCEPT { + return __builtin_lgamma((double)__x); +} + +// nan + +// tgamma + +inline _LIBCPP_HIDE_FROM_ABI float tgamma(float __x) _NOEXCEPT { return __builtin_tgammaf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double tgamma(double __x) _NOEXCEPT { + return __builtin_tgamma(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double tgamma(long double __x) _NOEXCEPT { return __builtin_tgammal(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double tgamma(_A1 __x) _NOEXCEPT { + return __builtin_tgamma((double)__x); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_GAMMA_H diff --git a/libcxx/include/__cxx03/__math/hyperbolic_functions.h b/libcxx/include/__cxx03/__math/hyperbolic_functions.h new file mode 100644 index 0000000000000000000000000000000000000000..78832bae70c9d159d2986a0fdf09f2229fc2158a --- /dev/null +++ b/libcxx/include/__cxx03/__math/hyperbolic_functions.h @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_HYPERBOLIC_FUNCTIONS_H +#define _LIBCPP___MATH_HYPERBOLIC_FUNCTIONS_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_integral.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// cosh + +inline _LIBCPP_HIDE_FROM_ABI float cosh(float __x) _NOEXCEPT { return __builtin_coshf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double cosh(double __x) _NOEXCEPT { + return __builtin_cosh(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double cosh(long double __x) _NOEXCEPT { return __builtin_coshl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double cosh(_A1 __x) _NOEXCEPT { + return __builtin_cosh((double)__x); +} + +// sinh + +inline _LIBCPP_HIDE_FROM_ABI float sinh(float __x) _NOEXCEPT { return __builtin_sinhf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double sinh(double __x) _NOEXCEPT { + return __builtin_sinh(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double sinh(long double __x) _NOEXCEPT { return __builtin_sinhl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double sinh(_A1 __x) _NOEXCEPT { + return __builtin_sinh((double)__x); +} + +// tanh + +inline _LIBCPP_HIDE_FROM_ABI float tanh(float __x) _NOEXCEPT { return __builtin_tanhf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double tanh(double __x) _NOEXCEPT { + return __builtin_tanh(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double tanh(long double __x) _NOEXCEPT { return __builtin_tanhl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double tanh(_A1 __x) _NOEXCEPT { + return __builtin_tanh((double)__x); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_HYPERBOLIC_FUNCTIONS_H diff --git a/libcxx/include/__cxx03/__math/hypot.h b/libcxx/include/__cxx03/__math/hypot.h new file mode 100644 index 0000000000000000000000000000000000000000..b992163711010a9eccc43ffdf37b68e285fa3a3f --- /dev/null +++ b/libcxx/include/__cxx03/__math/hypot.h @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_HYPOT_H +#define _LIBCPP___MATH_HYPOT_H + +#include <__algorithm/max.h> +#include <__config> +#include <__math/abs.h> +#include <__math/exponential_functions.h> +#include <__math/roots.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_same.h> +#include <__type_traits/promote.h> +#include <__utility/pair.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +inline _LIBCPP_HIDE_FROM_ABI float hypot(float __x, float __y) _NOEXCEPT { return __builtin_hypotf(__x, __y); } + +template +_LIBCPP_HIDE_FROM_ABI double hypot(double __x, double __y) _NOEXCEPT { + return __builtin_hypot(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI long double hypot(long double __x, long double __y) _NOEXCEPT { + return __builtin_hypotl(__x, __y); +} + +template ::value && is_arithmetic<_A2>::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type hypot(_A1 __x, _A2 __y) _NOEXCEPT { + using __result_type = typename __promote<_A1, _A2>::type; + static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), ""); + return __math::hypot((__result_type)__x, (__result_type)__y); +} + +#if _LIBCPP_STD_VER >= 17 +// Computes the three-dimensional hypotenuse: `std::hypot(x,y,z)`. +// The naive implementation might over-/underflow which is why this implementation is more involved: +// If the square of an argument might run into issues, we scale the arguments appropriately. +// See https://github.com/llvm/llvm-project/issues/92782 for a detailed discussion and summary. +template +_LIBCPP_HIDE_FROM_ABI _Real __hypot(_Real __x, _Real __y, _Real __z) { + // Factors needed to determine if over-/underflow might happen + constexpr int __exp = std::numeric_limits<_Real>::max_exponent / 2; + const _Real __overflow_threshold = __math::ldexp(_Real(1), __exp); + const _Real __overflow_scale = __math::ldexp(_Real(1), -(__exp + 20)); + + // Scale arguments depending on their size + const _Real __max_abs = std::max(__math::fabs(__x), std::max(__math::fabs(__y), __math::fabs(__z))); + _Real __scale; + if (__max_abs > __overflow_threshold) { // x*x + y*y + z*z might overflow + __scale = __overflow_scale; + } else if (__max_abs < 1 / __overflow_threshold) { // x*x + y*y + z*z might underflow + __scale = 1 / __overflow_scale; + } else { + __scale = 1; + } + __x *= __scale; + __y *= __scale; + __z *= __scale; + + // Compute hypot of scaled arguments and undo scaling + return __math::sqrt(__x * __x + __y * __y + __z * __z) / __scale; +} + +inline _LIBCPP_HIDE_FROM_ABI float hypot(float __x, float __y, float __z) { return __math::__hypot(__x, __y, __z); } + +inline _LIBCPP_HIDE_FROM_ABI double hypot(double __x, double __y, double __z) { return __math::__hypot(__x, __y, __z); } + +inline _LIBCPP_HIDE_FROM_ABI long double hypot(long double __x, long double __y, long double __z) { + return __math::__hypot(__x, __y, __z); +} + +template && is_arithmetic_v<_A2> && is_arithmetic_v<_A3>, int> = 0 > +_LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2, _A3>::type hypot(_A1 __x, _A2 __y, _A3 __z) _NOEXCEPT { + using __result_type = typename __promote<_A1, _A2, _A3>::type; + static_assert(!( + std::is_same_v<_A1, __result_type> && std::is_same_v<_A2, __result_type> && std::is_same_v<_A3, __result_type>)); + return __math::__hypot( + static_cast<__result_type>(__x), static_cast<__result_type>(__y), static_cast<__result_type>(__z)); +} +#endif + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MATH_HYPOT_H diff --git a/libcxx/include/__cxx03/__math/inverse_hyperbolic_functions.h b/libcxx/include/__cxx03/__math/inverse_hyperbolic_functions.h new file mode 100644 index 0000000000000000000000000000000000000000..4660a58e4eba02a345a04edf1d3167f03af2f9a2 --- /dev/null +++ b/libcxx/include/__cxx03/__math/inverse_hyperbolic_functions.h @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_INVERSE_HYPERBOLIC_FUNCTIONS_H +#define _LIBCPP___MATH_INVERSE_HYPERBOLIC_FUNCTIONS_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_integral.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// acosh + +inline _LIBCPP_HIDE_FROM_ABI float acosh(float __x) _NOEXCEPT { return __builtin_acoshf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double acosh(double __x) _NOEXCEPT { + return __builtin_acosh(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double acosh(long double __x) _NOEXCEPT { return __builtin_acoshl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double acosh(_A1 __x) _NOEXCEPT { + return __builtin_acosh((double)__x); +} + +// asinh + +inline _LIBCPP_HIDE_FROM_ABI float asinh(float __x) _NOEXCEPT { return __builtin_asinhf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double asinh(double __x) _NOEXCEPT { + return __builtin_asinh(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double asinh(long double __x) _NOEXCEPT { return __builtin_asinhl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double asinh(_A1 __x) _NOEXCEPT { + return __builtin_asinh((double)__x); +} + +// atanh + +inline _LIBCPP_HIDE_FROM_ABI float atanh(float __x) _NOEXCEPT { return __builtin_atanhf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double atanh(double __x) _NOEXCEPT { + return __builtin_atanh(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double atanh(long double __x) _NOEXCEPT { return __builtin_atanhl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double atanh(_A1 __x) _NOEXCEPT { + return __builtin_atanh((double)__x); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_INVERSE_HYPERBOLIC_FUNCTIONS_H diff --git a/libcxx/include/__cxx03/__math/inverse_trigonometric_functions.h b/libcxx/include/__cxx03/__math/inverse_trigonometric_functions.h new file mode 100644 index 0000000000000000000000000000000000000000..cd98b46a6aab8b6991a1a91505d0313217bc90ed --- /dev/null +++ b/libcxx/include/__cxx03/__math/inverse_trigonometric_functions.h @@ -0,0 +1,99 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_INVERSE_TRIGONOMETRIC_FUNCTIONS_H +#define _LIBCPP___MATH_INVERSE_TRIGONOMETRIC_FUNCTIONS_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_integral.h> +#include <__type_traits/is_same.h> +#include <__type_traits/promote.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// acos + +inline _LIBCPP_HIDE_FROM_ABI float acos(float __x) _NOEXCEPT { return __builtin_acosf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double acos(double __x) _NOEXCEPT { + return __builtin_acos(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double acos(long double __x) _NOEXCEPT { return __builtin_acosl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double acos(_A1 __x) _NOEXCEPT { + return __builtin_acos((double)__x); +} + +// asin + +inline _LIBCPP_HIDE_FROM_ABI float asin(float __x) _NOEXCEPT { return __builtin_asinf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double asin(double __x) _NOEXCEPT { + return __builtin_asin(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double asin(long double __x) _NOEXCEPT { return __builtin_asinl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double asin(_A1 __x) _NOEXCEPT { + return __builtin_asin((double)__x); +} + +// atan + +inline _LIBCPP_HIDE_FROM_ABI float atan(float __x) _NOEXCEPT { return __builtin_atanf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double atan(double __x) _NOEXCEPT { + return __builtin_atan(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double atan(long double __x) _NOEXCEPT { return __builtin_atanl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double atan(_A1 __x) _NOEXCEPT { + return __builtin_atan((double)__x); +} + +// atan2 + +inline _LIBCPP_HIDE_FROM_ABI float atan2(float __y, float __x) _NOEXCEPT { return __builtin_atan2f(__y, __x); } + +template +_LIBCPP_HIDE_FROM_ABI double atan2(double __x, double __y) _NOEXCEPT { + return __builtin_atan2(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI long double atan2(long double __y, long double __x) _NOEXCEPT { + return __builtin_atan2l(__y, __x); +} + +template ::value && is_arithmetic<_A2>::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type atan2(_A1 __y, _A2 __x) _NOEXCEPT { + using __result_type = typename __promote<_A1, _A2>::type; + static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), ""); + return __math::atan2((__result_type)__y, (__result_type)__x); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_INVERSE_TRIGONOMETRIC_FUNCTIONS_H diff --git a/libcxx/include/__cxx03/__math/logarithms.h b/libcxx/include/__cxx03/__math/logarithms.h new file mode 100644 index 0000000000000000000000000000000000000000..5f5f943977a508ad05913999191ba229fb711fa8 --- /dev/null +++ b/libcxx/include/__cxx03/__math/logarithms.h @@ -0,0 +1,124 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_LOGARITHMS_H +#define _LIBCPP___MATH_LOGARITHMS_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_integral.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// log + +inline _LIBCPP_HIDE_FROM_ABI float log(float __x) _NOEXCEPT { return __builtin_logf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double log(double __x) _NOEXCEPT { + return __builtin_log(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double log(long double __x) _NOEXCEPT { return __builtin_logl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double log(_A1 __x) _NOEXCEPT { + return __builtin_log((double)__x); +} + +// log10 + +inline _LIBCPP_HIDE_FROM_ABI float log10(float __x) _NOEXCEPT { return __builtin_log10f(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double log10(double __x) _NOEXCEPT { + return __builtin_log10(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double log10(long double __x) _NOEXCEPT { return __builtin_log10l(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double log10(_A1 __x) _NOEXCEPT { + return __builtin_log10((double)__x); +} + +// ilogb + +inline _LIBCPP_HIDE_FROM_ABI int ilogb(float __x) _NOEXCEPT { return __builtin_ilogbf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double ilogb(double __x) _NOEXCEPT { + return __builtin_ilogb(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI int ilogb(long double __x) _NOEXCEPT { return __builtin_ilogbl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI int ilogb(_A1 __x) _NOEXCEPT { + return __builtin_ilogb((double)__x); +} + +// log1p + +inline _LIBCPP_HIDE_FROM_ABI float log1p(float __x) _NOEXCEPT { return __builtin_log1pf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double log1p(double __x) _NOEXCEPT { + return __builtin_log1p(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double log1p(long double __x) _NOEXCEPT { return __builtin_log1pl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double log1p(_A1 __x) _NOEXCEPT { + return __builtin_log1p((double)__x); +} + +// log2 + +inline _LIBCPP_HIDE_FROM_ABI float log2(float __x) _NOEXCEPT { return __builtin_log2f(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double log2(double __x) _NOEXCEPT { + return __builtin_log2(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double log2(long double __x) _NOEXCEPT { return __builtin_log2l(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double log2(_A1 __x) _NOEXCEPT { + return __builtin_log2((double)__x); +} + +// logb + +inline _LIBCPP_HIDE_FROM_ABI float logb(float __x) _NOEXCEPT { return __builtin_logbf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double logb(double __x) _NOEXCEPT { + return __builtin_logb(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double logb(long double __x) _NOEXCEPT { return __builtin_logbl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double logb(_A1 __x) _NOEXCEPT { + return __builtin_logb((double)__x); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_LOGARITHMS_H diff --git a/libcxx/include/__cxx03/__math/min_max.h b/libcxx/include/__cxx03/__math/min_max.h new file mode 100644 index 0000000000000000000000000000000000000000..27997b44910a124a3b1170bf87016eba8fbc9f12 --- /dev/null +++ b/libcxx/include/__cxx03/__math/min_max.h @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_MIN_MAX_H +#define _LIBCPP___MATH_MIN_MAX_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_same.h> +#include <__type_traits/promote.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// fmax + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI float fmax(float __x, float __y) _NOEXCEPT { + return __builtin_fmaxf(__x, __y); +} + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI double fmax(double __x, double __y) _NOEXCEPT { + return __builtin_fmax(__x, __y); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI long double fmax(long double __x, long double __y) _NOEXCEPT { + return __builtin_fmaxl(__x, __y); +} + +template ::value && is_arithmetic<_A2>::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type fmax(_A1 __x, _A2 __y) _NOEXCEPT { + using __result_type = typename __promote<_A1, _A2>::type; + static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), ""); + return __math::fmax((__result_type)__x, (__result_type)__y); +} + +// fmin + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI float fmin(float __x, float __y) _NOEXCEPT { + return __builtin_fminf(__x, __y); +} + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI double fmin(double __x, double __y) _NOEXCEPT { + return __builtin_fmin(__x, __y); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI long double fmin(long double __x, long double __y) _NOEXCEPT { + return __builtin_fminl(__x, __y); +} + +template ::value && is_arithmetic<_A2>::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type fmin(_A1 __x, _A2 __y) _NOEXCEPT { + using __result_type = typename __promote<_A1, _A2>::type; + static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), ""); + return __math::fmin((__result_type)__x, (__result_type)__y); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_MIN_MAX_H diff --git a/libcxx/include/__cxx03/__math/modulo.h b/libcxx/include/__cxx03/__math/modulo.h new file mode 100644 index 0000000000000000000000000000000000000000..c8ea506f37d755ef0c7045d65654260a00f22049 --- /dev/null +++ b/libcxx/include/__cxx03/__math/modulo.h @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_MODULO_H +#define _LIBCPP___MATH_MODULO_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_same.h> +#include <__type_traits/promote.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// fmod + +inline _LIBCPP_HIDE_FROM_ABI float fmod(float __x, float __y) _NOEXCEPT { return __builtin_fmodf(__x, __y); } + +template +_LIBCPP_HIDE_FROM_ABI double fmod(double __x, double __y) _NOEXCEPT { + return __builtin_fmod(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI long double fmod(long double __x, long double __y) _NOEXCEPT { + return __builtin_fmodl(__x, __y); +} + +template ::value && is_arithmetic<_A2>::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type fmod(_A1 __x, _A2 __y) _NOEXCEPT { + using __result_type = typename __promote<_A1, _A2>::type; + static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), ""); + return __math::fmod((__result_type)__x, (__result_type)__y); +} + +// modf + +inline _LIBCPP_HIDE_FROM_ABI float modf(float __x, float* __y) _NOEXCEPT { return __builtin_modff(__x, __y); } + +template +_LIBCPP_HIDE_FROM_ABI double modf(double __x, double* __y) _NOEXCEPT { + return __builtin_modf(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI long double modf(long double __x, long double* __y) _NOEXCEPT { + return __builtin_modfl(__x, __y); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_MODULO_H diff --git a/libcxx/include/__cxx03/__math/remainder.h b/libcxx/include/__cxx03/__math/remainder.h new file mode 100644 index 0000000000000000000000000000000000000000..0fbf0b8ef97b9e3746880a5b85ec11ea64cbb1b5 --- /dev/null +++ b/libcxx/include/__cxx03/__math/remainder.h @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_REMAINDER_H +#define _LIBCPP___MATH_REMAINDER_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_same.h> +#include <__type_traits/promote.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// remainder + +inline _LIBCPP_HIDE_FROM_ABI float remainder(float __x, float __y) _NOEXCEPT { return __builtin_remainderf(__x, __y); } + +template +_LIBCPP_HIDE_FROM_ABI double remainder(double __x, double __y) _NOEXCEPT { + return __builtin_remainder(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI long double remainder(long double __x, long double __y) _NOEXCEPT { + return __builtin_remainderl(__x, __y); +} + +template ::value && is_arithmetic<_A2>::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type remainder(_A1 __x, _A2 __y) _NOEXCEPT { + using __result_type = typename __promote<_A1, _A2>::type; + static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), ""); + return __math::remainder((__result_type)__x, (__result_type)__y); +} + +// remquo + +inline _LIBCPP_HIDE_FROM_ABI float remquo(float __x, float __y, int* __z) _NOEXCEPT { + return __builtin_remquof(__x, __y, __z); +} + +template +_LIBCPP_HIDE_FROM_ABI double remquo(double __x, double __y, int* __z) _NOEXCEPT { + return __builtin_remquo(__x, __y, __z); +} + +inline _LIBCPP_HIDE_FROM_ABI long double remquo(long double __x, long double __y, int* __z) _NOEXCEPT { + return __builtin_remquol(__x, __y, __z); +} + +template ::value && is_arithmetic<_A2>::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type remquo(_A1 __x, _A2 __y, int* __z) _NOEXCEPT { + using __result_type = typename __promote<_A1, _A2>::type; + static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), ""); + return __math::remquo((__result_type)__x, (__result_type)__y, __z); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_REMAINDER_H diff --git a/libcxx/include/__cxx03/__math/roots.h b/libcxx/include/__cxx03/__math/roots.h new file mode 100644 index 0000000000000000000000000000000000000000..359fd747cfbef396cc28b42784fcd67c027344c7 --- /dev/null +++ b/libcxx/include/__cxx03/__math/roots.h @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_ROOTS_H +#define _LIBCPP___MATH_ROOTS_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_integral.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// sqrt + +inline _LIBCPP_HIDE_FROM_ABI float sqrt(float __x) _NOEXCEPT { return __builtin_sqrtf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double sqrt(double __x) _NOEXCEPT { + return __builtin_sqrt(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double sqrt(long double __x) _NOEXCEPT { return __builtin_sqrtl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double sqrt(_A1 __x) _NOEXCEPT { + return __builtin_sqrt((double)__x); +} + +// cbrt + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI float cbrt(float __x) _NOEXCEPT { return __builtin_cbrtf(__x); } + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI double cbrt(double __x) _NOEXCEPT { + return __builtin_cbrt(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI long double cbrt(long double __x) _NOEXCEPT { + return __builtin_cbrtl(__x); +} + +template ::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI double cbrt(_A1 __x) _NOEXCEPT { + return __builtin_cbrt((double)__x); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_ROOTS_H diff --git a/libcxx/include/__cxx03/__math/rounding_functions.h b/libcxx/include/__cxx03/__math/rounding_functions.h new file mode 100644 index 0000000000000000000000000000000000000000..f7246ba7fed0d69278e0f35778583ebf047d7480 --- /dev/null +++ b/libcxx/include/__cxx03/__math/rounding_functions.h @@ -0,0 +1,245 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_ROUNDING_FUNCTIONS_H +#define _LIBCPP___MATH_ROUNDING_FUNCTIONS_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_integral.h> +#include <__type_traits/is_same.h> +#include <__type_traits/promote.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// ceil + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI float ceil(float __x) _NOEXCEPT { return __builtin_ceilf(__x); } + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI double ceil(double __x) _NOEXCEPT { + return __builtin_ceil(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI long double ceil(long double __x) _NOEXCEPT { + return __builtin_ceill(__x); +} + +template ::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI double ceil(_A1 __x) _NOEXCEPT { + return __builtin_ceil((double)__x); +} + +// floor + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI float floor(float __x) _NOEXCEPT { return __builtin_floorf(__x); } + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI double floor(double __x) _NOEXCEPT { + return __builtin_floor(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI long double floor(long double __x) _NOEXCEPT { + return __builtin_floorl(__x); +} + +template ::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI double floor(_A1 __x) _NOEXCEPT { + return __builtin_floor((double)__x); +} + +// llrint + +inline _LIBCPP_HIDE_FROM_ABI long long llrint(float __x) _NOEXCEPT { return __builtin_llrintf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI long long llrint(double __x) _NOEXCEPT { + return __builtin_llrint(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long long llrint(long double __x) _NOEXCEPT { return __builtin_llrintl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI long long llrint(_A1 __x) _NOEXCEPT { + return __builtin_llrint((double)__x); +} + +// llround + +inline _LIBCPP_HIDE_FROM_ABI long long llround(float __x) _NOEXCEPT { return __builtin_llroundf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI long long llround(double __x) _NOEXCEPT { + return __builtin_llround(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long long llround(long double __x) _NOEXCEPT { return __builtin_llroundl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI long long llround(_A1 __x) _NOEXCEPT { + return __builtin_llround((double)__x); +} + +// lrint + +inline _LIBCPP_HIDE_FROM_ABI long lrint(float __x) _NOEXCEPT { return __builtin_lrintf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI long lrint(double __x) _NOEXCEPT { + return __builtin_lrint(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long lrint(long double __x) _NOEXCEPT { return __builtin_lrintl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI long lrint(_A1 __x) _NOEXCEPT { + return __builtin_lrint((double)__x); +} + +// lround + +inline _LIBCPP_HIDE_FROM_ABI long lround(float __x) _NOEXCEPT { return __builtin_lroundf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI long lround(double __x) _NOEXCEPT { + return __builtin_lround(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long lround(long double __x) _NOEXCEPT { return __builtin_lroundl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI long lround(_A1 __x) _NOEXCEPT { + return __builtin_lround((double)__x); +} + +// nearbyint + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI float nearbyint(float __x) _NOEXCEPT { + return __builtin_nearbyintf(__x); +} + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI double nearbyint(double __x) _NOEXCEPT { + return __builtin_nearbyint(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI long double nearbyint(long double __x) _NOEXCEPT { + return __builtin_nearbyintl(__x); +} + +template ::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI double nearbyint(_A1 __x) _NOEXCEPT { + return __builtin_nearbyint((double)__x); +} + +// nextafter + +inline _LIBCPP_HIDE_FROM_ABI float nextafter(float __x, float __y) _NOEXCEPT { return __builtin_nextafterf(__x, __y); } + +template +_LIBCPP_HIDE_FROM_ABI double nextafter(double __x, double __y) _NOEXCEPT { + return __builtin_nextafter(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI long double nextafter(long double __x, long double __y) _NOEXCEPT { + return __builtin_nextafterl(__x, __y); +} + +template ::value && is_arithmetic<_A2>::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type nextafter(_A1 __x, _A2 __y) _NOEXCEPT { + using __result_type = typename __promote<_A1, _A2>::type; + static_assert(!(_IsSame<_A1, __result_type>::value && _IsSame<_A2, __result_type>::value), ""); + return __math::nextafter((__result_type)__x, (__result_type)__y); +} + +// nexttoward + +inline _LIBCPP_HIDE_FROM_ABI float nexttoward(float __x, long double __y) _NOEXCEPT { + return __builtin_nexttowardf(__x, __y); +} + +template +_LIBCPP_HIDE_FROM_ABI double nexttoward(double __x, long double __y) _NOEXCEPT { + return __builtin_nexttoward(__x, __y); +} + +inline _LIBCPP_HIDE_FROM_ABI long double nexttoward(long double __x, long double __y) _NOEXCEPT { + return __builtin_nexttowardl(__x, __y); +} + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double nexttoward(_A1 __x, long double __y) _NOEXCEPT { + return __builtin_nexttoward((double)__x, __y); +} + +// rint + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI float rint(float __x) _NOEXCEPT { return __builtin_rintf(__x); } + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI double rint(double __x) _NOEXCEPT { + return __builtin_rint(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI long double rint(long double __x) _NOEXCEPT { + return __builtin_rintl(__x); +} + +template ::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI double rint(_A1 __x) _NOEXCEPT { + return __builtin_rint((double)__x); +} + +// round + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI float round(float __x) _NOEXCEPT { return __builtin_round(__x); } + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI double round(double __x) _NOEXCEPT { + return __builtin_round(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI long double round(long double __x) _NOEXCEPT { + return __builtin_roundl(__x); +} + +template ::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI double round(_A1 __x) _NOEXCEPT { + return __builtin_round((double)__x); +} + +// trunc + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI float trunc(float __x) _NOEXCEPT { return __builtin_trunc(__x); } + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI double trunc(double __x) _NOEXCEPT { + return __builtin_trunc(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI long double trunc(long double __x) _NOEXCEPT { + return __builtin_truncl(__x); +} + +template ::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI double trunc(_A1 __x) _NOEXCEPT { + return __builtin_trunc((double)__x); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_ROUNDING_FUNCTIONS_H diff --git a/libcxx/include/__cxx03/__math/special_functions.h b/libcxx/include/__cxx03/__math/special_functions.h new file mode 100644 index 0000000000000000000000000000000000000000..0b1c753a659adec9f408c37fced4427f6a372d1f --- /dev/null +++ b/libcxx/include/__cxx03/__math/special_functions.h @@ -0,0 +1,84 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_SPECIAL_FUNCTIONS_H +#define _LIBCPP___MATH_SPECIAL_FUNCTIONS_H + +#include <__config> +#include <__math/copysign.h> +#include <__math/traits.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_integral.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 17 + +template +_LIBCPP_HIDE_FROM_ABI _Real __hermite(unsigned __n, _Real __x) { + // The Hermite polynomial H_n(x). + // The implementation is based on the recurrence formula: H_{n+1}(x) = 2x H_n(x) - 2n H_{n-1}. + // Press, William H., et al. Numerical recipes 3rd edition: The art of scientific computing. + // Cambridge university press, 2007, p. 183. + + // NOLINTBEGIN(readability-identifier-naming) + if (__math::isnan(__x)) + return __x; + + _Real __H_0{1}; + if (__n == 0) + return __H_0; + + _Real __H_n_prev = __H_0; + _Real __H_n = 2 * __x; + for (unsigned __i = 1; __i < __n; ++__i) { + _Real __H_n_next = 2 * (__x * __H_n - __i * __H_n_prev); + __H_n_prev = __H_n; + __H_n = __H_n_next; + } + + if (!__math::isfinite(__H_n)) { + // Overflow occured. Two possible cases: + // n is odd: return infinity of the same sign as x. + // n is even: return +Inf + _Real __inf = std::numeric_limits<_Real>::infinity(); + return (__n & 1) ? __math::copysign(__inf, __x) : __inf; + } + return __H_n; + // NOLINTEND(readability-identifier-naming) +} + +inline _LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, double __x) { return std::__hermite(__n, __x); } + +inline _LIBCPP_HIDE_FROM_ABI float hermite(unsigned __n, float __x) { + // use double internally -- float is too prone to overflow! + return static_cast(std::hermite(__n, static_cast(__x))); +} + +inline _LIBCPP_HIDE_FROM_ABI long double hermite(unsigned __n, long double __x) { return std::__hermite(__n, __x); } + +inline _LIBCPP_HIDE_FROM_ABI float hermitef(unsigned __n, float __x) { return std::hermite(__n, __x); } + +inline _LIBCPP_HIDE_FROM_ABI long double hermitel(unsigned __n, long double __x) { return std::hermite(__n, __x); } + +template , int> = 0> +_LIBCPP_HIDE_FROM_ABI double hermite(unsigned __n, _Integer __x) { + return std::hermite(__n, static_cast(__x)); +} + +#endif // _LIBCPP_STD_VER >= 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_SPECIAL_FUNCTIONS_H diff --git a/libcxx/include/__cxx03/__math/traits.h b/libcxx/include/__cxx03/__math/traits.h new file mode 100644 index 0000000000000000000000000000000000000000..27ec52ecef022e9a8cc81788b323034ce51a1a8d --- /dev/null +++ b/libcxx/include/__cxx03/__math/traits.h @@ -0,0 +1,188 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_TRAITS_H +#define _LIBCPP___MATH_TRAITS_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_floating_point.h> +#include <__type_traits/is_integral.h> +#include <__type_traits/is_signed.h> +#include <__type_traits/promote.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// signbit + +template ::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool signbit(_A1 __x) _NOEXCEPT { + return __builtin_signbit(__x); +} + +template ::value && is_signed<_A1>::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool signbit(_A1 __x) _NOEXCEPT { + return __x < 0; +} + +template ::value && !is_signed<_A1>::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool signbit(_A1) _NOEXCEPT { + return false; +} + +// isfinite + +template ::value && numeric_limits<_A1>::has_infinity, int> = 0> +_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfinite(_A1 __x) _NOEXCEPT { + return __builtin_isfinite((typename __promote<_A1>::type)__x); +} + +template ::value && !numeric_limits<_A1>::has_infinity, int> = 0> +_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfinite(_A1) _NOEXCEPT { + return true; +} + +_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfinite(float __x) _NOEXCEPT { + return __builtin_isfinite(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfinite(double __x) _NOEXCEPT { + return __builtin_isfinite(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfinite(long double __x) _NOEXCEPT { + return __builtin_isfinite(__x); +} + +// isinf + +template ::value && numeric_limits<_A1>::has_infinity, int> = 0> +_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(_A1 __x) _NOEXCEPT { + return __builtin_isinf((typename __promote<_A1>::type)__x); +} + +template ::value && !numeric_limits<_A1>::has_infinity, int> = 0> +_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(_A1) _NOEXCEPT { + return false; +} + +#ifdef _LIBCPP_PREFERRED_OVERLOAD +_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(float __x) _NOEXCEPT { + return __builtin_isinf(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD bool +isinf(double __x) _NOEXCEPT { + return __builtin_isinf(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(long double __x) _NOEXCEPT { + return __builtin_isinf(__x); +} +#endif + +// isnan + +template ::value, int> = 0> +_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(_A1 __x) _NOEXCEPT { + return __builtin_isnan(__x); +} + +template ::value, int> = 0> +_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(_A1) _NOEXCEPT { + return false; +} + +#ifdef _LIBCPP_PREFERRED_OVERLOAD +_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(float __x) _NOEXCEPT { + return __builtin_isnan(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _LIBCPP_PREFERRED_OVERLOAD bool +isnan(double __x) _NOEXCEPT { + return __builtin_isnan(__x); +} + +_LIBCPP_NODISCARD inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(long double __x) _NOEXCEPT { + return __builtin_isnan(__x); +} +#endif + +// isnormal + +template ::value, int> = 0> +_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnormal(_A1 __x) _NOEXCEPT { + return __builtin_isnormal(__x); +} + +template ::value, int> = 0> +_LIBCPP_NODISCARD _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnormal(_A1 __x) _NOEXCEPT { + return __x != 0; +} + +// isgreater + +template ::value && is_arithmetic<_A2>::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool isgreater(_A1 __x, _A2 __y) _NOEXCEPT { + using type = typename __promote<_A1, _A2>::type; + return __builtin_isgreater((type)__x, (type)__y); +} + +// isgreaterequal + +template ::value && is_arithmetic<_A2>::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool isgreaterequal(_A1 __x, _A2 __y) _NOEXCEPT { + using type = typename __promote<_A1, _A2>::type; + return __builtin_isgreaterequal((type)__x, (type)__y); +} + +// isless + +template ::value && is_arithmetic<_A2>::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool isless(_A1 __x, _A2 __y) _NOEXCEPT { + using type = typename __promote<_A1, _A2>::type; + return __builtin_isless((type)__x, (type)__y); +} + +// islessequal + +template ::value && is_arithmetic<_A2>::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool islessequal(_A1 __x, _A2 __y) _NOEXCEPT { + using type = typename __promote<_A1, _A2>::type; + return __builtin_islessequal((type)__x, (type)__y); +} + +// islessgreater + +template ::value && is_arithmetic<_A2>::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool islessgreater(_A1 __x, _A2 __y) _NOEXCEPT { + using type = typename __promote<_A1, _A2>::type; + return __builtin_islessgreater((type)__x, (type)__y); +} + +// isunordered + +template ::value && is_arithmetic<_A2>::value, int> = 0> +_LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI bool isunordered(_A1 __x, _A2 __y) _NOEXCEPT { + using type = typename __promote<_A1, _A2>::type; + return __builtin_isunordered((type)__x, (type)__y); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_TRAITS_H diff --git a/libcxx/include/__cxx03/__math/trigonometric_functions.h b/libcxx/include/__cxx03/__math/trigonometric_functions.h new file mode 100644 index 0000000000000000000000000000000000000000..0ad91c76316091931db30c6d111fc529288e53f3 --- /dev/null +++ b/libcxx/include/__cxx03/__math/trigonometric_functions.h @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MATH_TRIGONOMETRIC_FUNCTIONS_H +#define _LIBCPP___MATH_TRIGONOMETRIC_FUNCTIONS_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_integral.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace __math { + +// cos + +inline _LIBCPP_HIDE_FROM_ABI float cos(float __x) _NOEXCEPT { return __builtin_cosf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double cos(double __x) _NOEXCEPT { + return __builtin_cos(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double cos(long double __x) _NOEXCEPT { return __builtin_cosl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double cos(_A1 __x) _NOEXCEPT { + return __builtin_cos((double)__x); +} + +// sin + +inline _LIBCPP_HIDE_FROM_ABI float sin(float __x) _NOEXCEPT { return __builtin_sinf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double sin(double __x) _NOEXCEPT { + return __builtin_sin(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double sin(long double __x) _NOEXCEPT { return __builtin_sinl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double sin(_A1 __x) _NOEXCEPT { + return __builtin_sin((double)__x); +} + +// tan + +inline _LIBCPP_HIDE_FROM_ABI float tan(float __x) _NOEXCEPT { return __builtin_tanf(__x); } + +template +_LIBCPP_HIDE_FROM_ABI double tan(double __x) _NOEXCEPT { + return __builtin_tan(__x); +} + +inline _LIBCPP_HIDE_FROM_ABI long double tan(long double __x) _NOEXCEPT { return __builtin_tanl(__x); } + +template ::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI double tan(_A1 __x) _NOEXCEPT { + return __builtin_tan((double)__x); +} + +} // namespace __math + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_TRIGONOMETRIC_FUNCTIONS_H diff --git a/libcxx/include/__cxx03/__mbstate_t.h b/libcxx/include/__cxx03/__mbstate_t.h new file mode 100644 index 0000000000000000000000000000000000000000..bfa6d617e2b8f543999c625cb5db2c4ae94154e0 --- /dev/null +++ b/libcxx/include/__cxx03/__mbstate_t.h @@ -0,0 +1,54 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MBSTATE_T_H +#define _LIBCPP___MBSTATE_T_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +// The goal of this header is to provide mbstate_t without requiring all of +// or . It's also used by the libc++ versions of +// and to get mbstate_t when the C library doesn't provide +// or , hence the #include_next of those headers instead of #include. +// (e.g. if isn't present in the C library, the libc++ +// will include this header. This header needs to not turn around and cyclically +// include , but fall through to .) +// +// This does not define std::mbstate_t -- this only brings in the declaration +// in the global namespace. + +// We define this here to support older versions of glibc that do +// not define this for clang. This is also set in libc++'s header, +// and we need to do so here too to avoid a different function signature given +// a different include order. +#ifdef __cplusplus +# define __CORRECT_ISO_CPP_WCHAR_H_PROTO +#endif + +#if defined(_LIBCPP_HAS_MUSL_LIBC) +# define __NEED_mbstate_t +# include +# undef __NEED_mbstate_t +#elif __has_include() +# include // works on most Unixes +#elif __has_include() +# include // works on Darwin +#elif !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS) && __has_include_next() +# include_next // fall back to the C standard provider of mbstate_t +#elif __has_include_next() +# include_next // is also required to make mbstate_t visible +#else +# error "We don't know how to get the definition of mbstate_t without on your platform." +#endif + +#endif // _LIBCPP___MBSTATE_T_H diff --git a/libcxx/include/__cxx03/__mdspan/default_accessor.h b/libcxx/include/__cxx03/__mdspan/default_accessor.h new file mode 100644 index 0000000000000000000000000000000000000000..1cc5f15545fc8cb8d50c8d74a896b89a955456e2 --- /dev/null +++ b/libcxx/include/__cxx03/__mdspan/default_accessor.h @@ -0,0 +1,66 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Kokkos v. 4.0 +// Copyright (2022) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___MDSPAN_DEFAULT_ACCESSOR_H +#define _LIBCPP___MDSPAN_DEFAULT_ACCESSOR_H + +#include <__config> +#include <__type_traits/is_abstract.h> +#include <__type_traits/is_array.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/remove_const.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template +struct default_accessor { + static_assert(!is_array_v<_ElementType>, "default_accessor: template argument may not be an array type"); + static_assert(!is_abstract_v<_ElementType>, "default_accessor: template argument may not be an abstract class"); + + using offset_policy = default_accessor; + using element_type = _ElementType; + using reference = _ElementType&; + using data_handle_type = _ElementType*; + + _LIBCPP_HIDE_FROM_ABI constexpr default_accessor() noexcept = default; + template + requires(is_convertible_v<_OtherElementType (*)[], element_type (*)[]>) + _LIBCPP_HIDE_FROM_ABI constexpr default_accessor(default_accessor<_OtherElementType>) noexcept {} + + _LIBCPP_HIDE_FROM_ABI constexpr reference access(data_handle_type __p, size_t __i) const noexcept { return __p[__i]; } + _LIBCPP_HIDE_FROM_ABI constexpr data_handle_type offset(data_handle_type __p, size_t __i) const noexcept { + return __p + __i; + } +}; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_DEFAULT_ACCESSOR_H diff --git a/libcxx/include/__cxx03/__mdspan/extents.h b/libcxx/include/__cxx03/__mdspan/extents.h new file mode 100644 index 0000000000000000000000000000000000000000..95082ef3d11ac90db40fa126831438ae944b4609 --- /dev/null +++ b/libcxx/include/__cxx03/__mdspan/extents.h @@ -0,0 +1,532 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Kokkos v. 4.0 +// Copyright (2022) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___MDSPAN_EXTENTS_H +#define _LIBCPP___MDSPAN_EXTENTS_H + +#include <__assert> +#include <__config> +#include <__type_traits/common_type.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_same.h> +#include <__type_traits/make_unsigned.h> +#include <__utility/integer_sequence.h> +#include <__utility/unreachable.h> +#include +#include +#include +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +namespace __mdspan_detail { + +// ------------------------------------------------------------------ +// ------------ __static_array -------------------------------------- +// ------------------------------------------------------------------ +// array like class which provides an array of static values with get +template +struct __static_array { + static constexpr array<_Tp, sizeof...(_Values)> __array = {_Values...}; + +public: + _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return sizeof...(_Values); } + _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get(size_t __index) noexcept { return __array[__index]; } + + template + _LIBCPP_HIDE_FROM_ABI static constexpr _Tp __get() { + return __get(_Index); + } +}; + +// ------------------------------------------------------------------ +// ------------ __possibly_empty_array ----------------------------- +// ------------------------------------------------------------------ + +// array like class which provides get function and operator [], and +// has a specialization for the size 0 case. +// This is needed to make the __maybe_static_array be truly empty, for +// all static values. + +template +struct __possibly_empty_array { + _Tp __vals_[_Size]; + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator[](size_t __index) { return __vals_[__index]; } + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](size_t __index) const { return __vals_[__index]; } +}; + +template +struct __possibly_empty_array<_Tp, 0> { + _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator[](size_t) { __libcpp_unreachable(); } + _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](size_t) const { __libcpp_unreachable(); } +}; + +// ------------------------------------------------------------------ +// ------------ static_partial_sums --------------------------------- +// ------------------------------------------------------------------ + +// Provides a compile time partial sum one can index into + +template +struct __static_partial_sums { + _LIBCPP_HIDE_FROM_ABI static constexpr array __static_partial_sums_impl() { + array __values{_Values...}; + array __partial_sums{{}}; + size_t __running_sum = 0; + for (int __i = 0; __i != sizeof...(_Values); ++__i) { + __partial_sums[__i] = __running_sum; + __running_sum += __values[__i]; + } + return __partial_sums; + } + static constexpr array __result{__static_partial_sums_impl()}; + + _LIBCPP_HIDE_FROM_ABI static constexpr size_t __get(size_t __index) { return __result[__index]; } +}; + +// ------------------------------------------------------------------ +// ------------ __maybe_static_array -------------------------------- +// ------------------------------------------------------------------ + +// array like class which has a mix of static and runtime values but +// only stores the runtime values. +// The type of the static and the runtime values can be different. +// The position of a dynamic value is indicated through a tag value. +template +struct __maybe_static_array { + static_assert(is_convertible<_TStatic, _TDynamic>::value, + "__maybe_static_array: _TStatic must be convertible to _TDynamic"); + static_assert(is_convertible<_TDynamic, _TStatic>::value, + "__maybe_static_array: _TDynamic must be convertible to _TStatic"); + +private: + // Static values member + static constexpr size_t __size_ = sizeof...(_Values); + static constexpr size_t __size_dynamic_ = ((_Values == _DynTag) + ... + 0); + using _StaticValues = __static_array<_TStatic, _Values...>; + using _DynamicValues = __possibly_empty_array<_TDynamic, __size_dynamic_>; + + // Dynamic values member + _LIBCPP_NO_UNIQUE_ADDRESS _DynamicValues __dyn_vals_; + + // static mapping of indices to the position in the dynamic values array + using _DynamicIdxMap = __static_partial_sums(_Values == _DynTag)...>; + + template + _LIBCPP_HIDE_FROM_ABI static constexpr _DynamicValues __zeros(index_sequence<_Indices...>) noexcept { + return _DynamicValues{((void)_Indices, 0)...}; + } + +public: + _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array() noexcept + : __dyn_vals_{__zeros(make_index_sequence<__size_dynamic_>())} {} + + // constructors from dynamic values only -- this covers the case for rank() == 0 + template + requires(sizeof...(_DynVals) == __size_dynamic_) + _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(_DynVals... __vals) + : __dyn_vals_{static_cast<_TDynamic>(__vals)...} {} + + template + requires(_Size == __size_dynamic_) + _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array([[maybe_unused]] const span<_Tp, _Size>& __vals) { + if constexpr (_Size > 0) { + for (size_t __i = 0; __i < _Size; __i++) + __dyn_vals_[__i] = static_cast<_TDynamic>(__vals[__i]); + } + } + + // constructors from all values -- here rank will be greater than 0 + template + requires(sizeof...(_DynVals) != __size_dynamic_) + _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(_DynVals... __vals) { + static_assert(sizeof...(_DynVals) == __size_, "Invalid number of values."); + _TDynamic __values[__size_] = {static_cast<_TDynamic>(__vals)...}; + for (size_t __i = 0; __i < __size_; __i++) { + _TStatic __static_val = _StaticValues::__get(__i); + if (__static_val == _DynTag) { + __dyn_vals_[_DynamicIdxMap::__get(__i)] = __values[__i]; + } else + // Not catching this could lead to out of bounds errors later + // e.g. using my_mdspan_t = mdspan>; my_mdspan_t = m(new int[5], 5); + // Right-hand-side construction looks ok with allocation and size matching, + // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not 5 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __values[__i] == static_cast<_TDynamic>(__static_val), + "extents construction: mismatch of provided arguments with static extents."); + } + } + + template + requires(_Size != __size_dynamic_) + _LIBCPP_HIDE_FROM_ABI constexpr __maybe_static_array(const span<_Tp, _Size>& __vals) { + static_assert(_Size == __size_ || __size_ == dynamic_extent); + for (size_t __i = 0; __i < __size_; __i++) { + _TStatic __static_val = _StaticValues::__get(__i); + if (__static_val == _DynTag) { + __dyn_vals_[_DynamicIdxMap::__get(__i)] = static_cast<_TDynamic>(__vals[__i]); + } else + // Not catching this could lead to out of bounds errors later + // e.g. using my_mdspan_t = mdspan>; my_mdspan_t = m(new int[N], span(&N)); + // Right-hand-side construction looks ok with allocation and size matching, + // but since (potentially elsewhere defined) my_mdspan_t has static size m now thinks its range is 10 not N + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + static_cast<_TDynamic>(__vals[__i]) == static_cast<_TDynamic>(__static_val), + "extents construction: mismatch of provided arguments with static extents."); + } + } + + // access functions + _LIBCPP_HIDE_FROM_ABI static constexpr _TStatic __static_value(size_t __i) noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank"); + return _StaticValues::__get(__i); + } + + _LIBCPP_HIDE_FROM_ABI constexpr _TDynamic __value(size_t __i) const { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank"); + _TStatic __static_val = _StaticValues::__get(__i); + return __static_val == _DynTag ? __dyn_vals_[_DynamicIdxMap::__get(__i)] : static_cast<_TDynamic>(__static_val); + } + _LIBCPP_HIDE_FROM_ABI constexpr _TDynamic operator[](size_t __i) const { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < __size_, "extents access: index must be less than rank"); + return __value(__i); + } + + // observers + _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return __size_; } + _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size_dynamic() { return __size_dynamic_; } +}; + +// Function to check whether a value is representable as another type +// value must be a positive integer otherwise returns false +// if _From is not an integral, we just check positivity +template + requires(integral<_From>) +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_representable_as(_From __value) { + using _To_u = make_unsigned_t<_To>; + using _From_u = make_unsigned_t<_From>; + if constexpr (is_signed_v<_From>) { + if (__value < 0) + return false; + } + if constexpr (static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(numeric_limits<_From>::max())) { + return true; + } else { + return static_cast<_To_u>(numeric_limits<_To>::max()) >= static_cast<_From_u>(__value); + } +} + +template + requires(!integral<_From>) +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_representable_as(_From __value) { + if constexpr (is_signed_v<_To>) { + if (static_cast<_To>(__value) < 0) + return false; + } + return true; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool __are_representable_as(_From... __values) { + return (__mdspan_detail::__is_representable_as<_To>(__values) && ... && true); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool __are_representable_as(span<_From, _Size> __values) { + for (size_t __i = 0; __i < _Size; __i++) + if (!__mdspan_detail::__is_representable_as<_To>(__values[__i])) + return false; + return true; +} + +} // namespace __mdspan_detail + +// ------------------------------------------------------------------ +// ------------ extents --------------------------------------------- +// ------------------------------------------------------------------ + +// Class to describe the extents of a multi dimensional array. +// Used by mdspan, mdarray and layout mappings. +// See ISO C++ standard [mdspan.extents] + +template +class extents { +public: + // typedefs for integral types used + using index_type = _IndexType; + using size_type = make_unsigned_t; + using rank_type = size_t; + + static_assert(is_integral::value && !is_same::value, + "extents::index_type must be a signed or unsigned integer type"); + static_assert(((__mdspan_detail::__is_representable_as(_Extents) || (_Extents == dynamic_extent)) && ...), + "extents ctor: arguments must be representable as index_type and nonnegative"); + +private: + static constexpr rank_type __rank_ = sizeof...(_Extents); + static constexpr rank_type __rank_dynamic_ = ((_Extents == dynamic_extent) + ... + 0); + + // internal storage type using __maybe_static_array + using _Values = __mdspan_detail::__maybe_static_array<_IndexType, size_t, dynamic_extent, _Extents...>; + [[no_unique_address]] _Values __vals_; + +public: + // [mdspan.extents.obs], observers of multidimensional index space + _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return __rank_; } + _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { return __rank_dynamic_; } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept { return __vals_.__value(__r); } + _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept { + return _Values::__static_value(__r); + } + + // [mdspan.extents.cons], constructors + _LIBCPP_HIDE_FROM_ABI constexpr extents() noexcept = default; + + // Construction from just dynamic or all values. + // Precondition check is deferred to __maybe_static_array constructor + template + requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) && + (is_nothrow_constructible_v && ...) && + (sizeof...(_OtherIndexTypes) == __rank_ || sizeof...(_OtherIndexTypes) == __rank_dynamic_)) + _LIBCPP_HIDE_FROM_ABI constexpr explicit extents(_OtherIndexTypes... __dynvals) noexcept + : __vals_(static_cast(__dynvals)...) { + // Not catching this could lead to out of bounds errors later + // e.g. mdspan m(ptr, dextents(200u)); leads to an extent of -56 on m + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as(__dynvals...), + "extents ctor: arguments must be representable as index_type and nonnegative"); + } + + template + requires(is_convertible_v && + is_nothrow_constructible_v && + (_Size == __rank_ || _Size == __rank_dynamic_)) + explicit(_Size != __rank_dynamic_) + _LIBCPP_HIDE_FROM_ABI constexpr extents(const array<_OtherIndexType, _Size>& __exts) noexcept + : __vals_(span(__exts)) { + // Not catching this could lead to out of bounds errors later + // e.g. mdspan m(ptr, dextents(array(200))); leads to an extent of -56 on m + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as(span(__exts)), + "extents ctor: arguments must be representable as index_type and nonnegative"); + } + + template + requires(is_convertible_v && + is_nothrow_constructible_v && + (_Size == __rank_ || _Size == __rank_dynamic_)) + explicit(_Size != __rank_dynamic_) + _LIBCPP_HIDE_FROM_ABI constexpr extents(const span<_OtherIndexType, _Size>& __exts) noexcept + : __vals_(__exts) { + // Not catching this could lead to out of bounds errors later + // e.g. array a{200u}; mdspan> m(ptr, extents(span(a))); leads to an extent of -56 + // on m + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__are_representable_as(__exts), + "extents ctor: arguments must be representable as index_type and nonnegative"); + } + +private: + // Function to construct extents storage from other extents. + template + requires(_Idx < __rank_) + _LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents( + integral_constant, + integral_constant, + const _OtherExtents& __exts, + _DynamicValues... __dynamic_values) noexcept { + if constexpr (static_extent(_Idx) == dynamic_extent) + return __construct_vals_from_extents( + integral_constant(), + integral_constant(), + __exts, + __dynamic_values..., + __exts.extent(_Idx)); + else + return __construct_vals_from_extents( + integral_constant(), integral_constant(), __exts, __dynamic_values...); + } + + template + requires((_Idx == __rank_) && (_DynCount == __rank_dynamic_)) + _LIBCPP_HIDE_FROM_ABI constexpr _Values __construct_vals_from_extents( + integral_constant, + integral_constant, + const _OtherExtents&, + _DynamicValues... __dynamic_values) noexcept { + return _Values{static_cast(__dynamic_values)...}; + } + +public: + // Converting constructor from other extents specializations + template + requires((sizeof...(_OtherExtents) == sizeof...(_Extents)) && + ((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...)) + explicit((((_Extents != dynamic_extent) && (_OtherExtents == dynamic_extent)) || ...) || + (static_cast>(numeric_limits::max()) < + static_cast>(numeric_limits<_OtherIndexType>::max()))) + _LIBCPP_HIDE_FROM_ABI constexpr extents(const extents<_OtherIndexType, _OtherExtents...>& __other) noexcept + : __vals_( + __construct_vals_from_extents(integral_constant(), integral_constant(), __other)) { + if constexpr (rank() > 0) { + for (size_t __r = 0; __r < rank(); __r++) { + if constexpr (static_cast>(numeric_limits::max()) < + static_cast>(numeric_limits<_OtherIndexType>::max())) { + // Not catching this could lead to out of bounds errors later + // e.g. dextents> e(dextents(200)) leads to an extent of -56 on e + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.extent(__r)), + "extents ctor: arguments must be representable as index_type and nonnegative"); + } + // Not catching this could lead to out of bounds errors later + // e.g. mdspan> m = mdspan>(new int[5], 5); + // Right-hand-side construction was ok, but m now thinks its range is 10 not 5 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + (_Values::__static_value(__r) == dynamic_extent) || + (static_cast(__other.extent(__r)) == static_cast(_Values::__static_value(__r))), + "extents construction: mismatch of provided arguments with static extents."); + } + } + } + + // Comparison operator + template + _LIBCPP_HIDE_FROM_ABI friend constexpr bool + operator==(const extents& __lhs, const extents<_OtherIndexType, _OtherExtents...>& __rhs) noexcept { + if constexpr (rank() != sizeof...(_OtherExtents)) { + return false; + } else { + for (rank_type __r = 0; __r < __rank_; __r++) { + // avoid warning when comparing signed and unsigner integers and pick the wider of two types + using _CommonType = common_type_t; + if (static_cast<_CommonType>(__lhs.extent(__r)) != static_cast<_CommonType>(__rhs.extent(__r))) { + return false; + } + } + } + return true; + } +}; + +// Recursive helper classes to implement dextents alias for extents +namespace __mdspan_detail { + +template > +struct __make_dextents; + +template +struct __make_dextents< _IndexType, _Rank, extents<_IndexType, _ExtentsPack...>> { + using type = + typename __make_dextents< _IndexType, _Rank - 1, extents<_IndexType, dynamic_extent, _ExtentsPack...>>::type; +}; + +template +struct __make_dextents< _IndexType, 0, extents<_IndexType, _ExtentsPack...>> { + using type = extents<_IndexType, _ExtentsPack...>; +}; + +} // end namespace __mdspan_detail + +// [mdspan.extents.dextents], alias template +template +using dextents = typename __mdspan_detail::__make_dextents<_IndexType, _Rank>::type; + +# if _LIBCPP_STD_VER >= 26 +// [mdspan.extents.dims], alias template `dims` +template +using dims = dextents<_IndexType, _Rank>; +# endif + +// Deduction guide for extents +# if _LIBCPP_STD_VER >= 26 +template + requires(is_convertible_v<_IndexTypes, size_t> && ...) +explicit extents(_IndexTypes...) -> extents...>; +# else +template + requires(is_convertible_v<_IndexTypes, size_t> && ...) +explicit extents(_IndexTypes...) -> extents; +# endif + +namespace __mdspan_detail { + +// Helper type traits for identifying a class as extents. +template +struct __is_extents : false_type {}; + +template +struct __is_extents> : true_type {}; + +template +inline constexpr bool __is_extents_v = __is_extents<_Tp>::value; + +// Function to check whether a set of indices are a multidimensional +// index into extents. This is a word of power in the C++ standard +// requiring that the indices are larger than 0 and smaller than +// the respective extents. + +template + requires(integral<_From>) +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_index_in_extent(_IndexType __extent, _From __value) { + if constexpr (is_signed_v<_From>) { + if (__value < 0) + return false; + } + using _Tp = common_type_t<_IndexType, _From>; + return static_cast<_Tp>(__value) < static_cast<_Tp>(__extent); +} + +template + requires(!integral<_From>) +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_index_in_extent(_IndexType __extent, _From __value) { + if constexpr (is_signed_v<_IndexType>) { + if (static_cast<_IndexType>(__value) < 0) + return false; + } + return static_cast<_IndexType>(__value) < __extent; +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool +__is_multidimensional_index_in_impl(index_sequence<_Idxs...>, const _Extents& __ext, _From... __values) { + return (__mdspan_detail::__is_index_in_extent(__ext.extent(_Idxs), __values) && ...); +} + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_multidimensional_index_in(const _Extents& __ext, _From... __values) { + return __mdspan_detail::__is_multidimensional_index_in_impl( + make_index_sequence<_Extents::rank()>(), __ext, __values...); +} + +} // namespace __mdspan_detail + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_EXTENTS_H diff --git a/libcxx/include/__cxx03/__mdspan/layout_left.h b/libcxx/include/__cxx03/__mdspan/layout_left.h new file mode 100644 index 0000000000000000000000000000000000000000..d058cbccffd96ddf2044eb073a29fa844b6cd953 --- /dev/null +++ b/libcxx/include/__cxx03/__mdspan/layout_left.h @@ -0,0 +1,204 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Kokkos v. 4.0 +// Copyright (2022) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___MDSPAN_LAYOUT_LEFT_H +#define _LIBCPP___MDSPAN_LAYOUT_LEFT_H + +#include <__assert> +#include <__config> +#include <__fwd/mdspan.h> +#include <__mdspan/extents.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__utility/integer_sequence.h> +#include +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template +class layout_left::mapping { +public: + static_assert(__mdspan_detail::__is_extents<_Extents>::value, + "layout_left::mapping template argument must be a specialization of extents."); + + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_left; + +private: + _LIBCPP_HIDE_FROM_ABI static constexpr bool __required_span_size_is_representable(const extents_type& __ext) { + if constexpr (extents_type::rank() == 0) + return true; + + index_type __prod = __ext.extent(0); + for (rank_type __r = 1; __r < extents_type::rank(); __r++) { + bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), &__prod); + if (__overflowed) + return false; + } + return true; + } + + static_assert(extents_type::rank_dynamic() > 0 || __required_span_size_is_representable(extents_type()), + "layout_left::mapping product of static extents must be representable as index_type."); + +public: + // [mdspan.layout.left.cons], constructors + _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext) noexcept : __extents_(__ext) { + // not catching this could lead to out-of-bounds access later when used inside mdspan + // mapping> map(dextents(40,40)); map(10, 3) == -126 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __required_span_size_is_representable(__ext), + "layout_left::mapping extents ctor: product of extents must be representable as index_type."); + } + + template + requires(is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) + mapping(const mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + // not catching this could lead to out-of-bounds access later when used inside mdspan + // mapping> map(mapping>(dextents(40,40))); map(10, 3) == -126 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_left::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + + template + requires(is_constructible_v && _OtherExtents::rank() <= 1) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) + mapping(const layout_right::mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + // not catching this could lead to out-of-bounds access later when used inside mdspan + // Note: since this is constraint to rank 1, extents itself would catch the invalid conversion first + // and thus this assertion should never be triggered, but keeping it here for consistency + // layout_left::mapping> map( + // layout_right::mapping>(dextents(200))); map.extents().extent(0) == + // -56 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_left::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + + template + requires(is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + if constexpr (extents_type::rank() > 0) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + ([&]() { + using _CommonType = common_type_t; + for (rank_type __r = 0; __r < extents_type::rank(); __r++) + if (static_cast<_CommonType>(stride(__r)) != static_cast<_CommonType>(__other.stride(__r))) + return false; + return true; + }()), + "layout_left::mapping from layout_stride ctor: strides are not compatible with layout_left."); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_left::mapping from layout_stride ctor: other.required_span_size() must be representable as " + "index_type."); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default; + + // [mdspan.layout.left.obs], observers + _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __extents_; } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type required_span_size() const noexcept { + index_type __size = 1; + for (size_t __r = 0; __r < extents_type::rank(); __r++) + __size *= __extents_.extent(__r); + return __size; + } + + template + requires((sizeof...(_Indices) == extents_type::rank()) && (is_convertible_v<_Indices, index_type> && ...) && + (is_nothrow_constructible_v && ...)) + _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept { + // Mappings are generally meant to be used for accessing allocations and are meant to guarantee to never + // return a value exceeding required_span_size(), which is used to know how large an allocation one needs + // Thus, this is a canonical point in multi-dimensional data structures to make invalid element access checks + // However, mdspan does check this on its own, so for now we avoid double checking in hardened mode + _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...), + "layout_left::mapping: out of bounds indexing"); + array __idx_a{static_cast(__idx)...}; + return [&](index_sequence<_Pos...>) { + index_type __res = 0; + ((__res = __idx_a[extents_type::rank() - 1 - _Pos] + __extents_.extent(extents_type::rank() - 1 - _Pos) * __res), + ...); + return __res; + }(make_index_sequence()); + } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { return true; } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_unique() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_exhaustive() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_strided() noexcept { return true; } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept + requires(extents_type::rank() > 0) + { + // While it would be caught by extents itself too, using a too large __r + // is functionally an out of bounds access on the stored information needed to compute strides + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __r < extents_type::rank(), "layout_left::mapping::stride(): invalid rank index"); + index_type __s = 1; + for (rank_type __i = 0; __i < __r; __i++) + __s *= __extents_.extent(__i); + return __s; + } + + template + requires(_OtherExtents::rank() == extents_type::rank()) + _LIBCPP_HIDE_FROM_ABI friend constexpr bool + operator==(const mapping& __lhs, const mapping<_OtherExtents>& __rhs) noexcept { + return __lhs.extents() == __rhs.extents(); + } + +private: + _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{}; +}; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_LAYOUT_LEFT_H diff --git a/libcxx/include/__cxx03/__mdspan/layout_right.h b/libcxx/include/__cxx03/__mdspan/layout_right.h new file mode 100644 index 0000000000000000000000000000000000000000..6842e9dc37fdccc6820ee6d4500c5b3cac462015 --- /dev/null +++ b/libcxx/include/__cxx03/__mdspan/layout_right.h @@ -0,0 +1,201 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Kokkos v. 4.0 +// Copyright (2022) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___MDSPAN_LAYOUT_RIGHT_H +#define _LIBCPP___MDSPAN_LAYOUT_RIGHT_H + +#include <__assert> +#include <__config> +#include <__fwd/mdspan.h> +#include <__mdspan/extents.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__utility/integer_sequence.h> +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template +class layout_right::mapping { +public: + static_assert(__mdspan_detail::__is_extents<_Extents>::value, + "layout_right::mapping template argument must be a specialization of extents."); + + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_right; + +private: + _LIBCPP_HIDE_FROM_ABI static constexpr bool __required_span_size_is_representable(const extents_type& __ext) { + if constexpr (extents_type::rank() == 0) + return true; + + index_type __prod = __ext.extent(0); + for (rank_type __r = 1; __r < extents_type::rank(); __r++) { + bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), &__prod); + if (__overflowed) + return false; + } + return true; + } + + static_assert(extents_type::rank_dynamic() > 0 || __required_span_size_is_representable(extents_type()), + "layout_right::mapping product of static extents must be representable as index_type."); + +public: + // [mdspan.layout.right.cons], constructors + _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext) noexcept : __extents_(__ext) { + // not catching this could lead to out-of-bounds access later when used inside mdspan + // mapping> map(dextents(40,40)); map(3, 10) == -126 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __required_span_size_is_representable(__ext), + "layout_right::mapping extents ctor: product of extents must be representable as index_type."); + } + + template + requires(is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) + mapping(const mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + // not catching this could lead to out-of-bounds access later when used inside mdspan + // mapping> map(mapping>(dextents(40,40))); map(3, 10) == -126 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_right::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + + template + requires(is_constructible_v && _OtherExtents::rank() <= 1) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) + mapping(const layout_left::mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + // not catching this could lead to out-of-bounds access later when used inside mdspan + // Note: since this is constraint to rank 1, extents itself would catch the invalid conversion first + // and thus this assertion should never be triggered, but keeping it here for consistency + // layout_right::mapping> map( + // layout_left::mapping>(dextents(200))); map.extents().extent(0) == + // -56 + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_right::mapping converting ctor: other.required_span_size() must be representable as index_type."); + } + + template + requires(is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping<_OtherExtents>& __other) noexcept + : __extents_(__other.extents()) { + if constexpr (extents_type::rank() > 0) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + ([&]() { + using _CommonType = common_type_t; + for (rank_type __r = 0; __r < extents_type::rank(); __r++) + if (static_cast<_CommonType>(stride(__r)) != static_cast<_CommonType>(__other.stride(__r))) + return false; + return true; + }()), + "layout_right::mapping from layout_stride ctor: strides are not compatible with layout_right."); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_right::mapping from layout_stride ctor: other.required_span_size() must be representable as " + "index_type."); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default; + + // [mdspan.layout.right.obs], observers + _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __extents_; } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type required_span_size() const noexcept { + index_type __size = 1; + for (size_t __r = 0; __r < extents_type::rank(); __r++) + __size *= __extents_.extent(__r); + return __size; + } + + template + requires((sizeof...(_Indices) == extents_type::rank()) && (is_convertible_v<_Indices, index_type> && ...) && + (is_nothrow_constructible_v && ...)) + _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept { + // Mappings are generally meant to be used for accessing allocations and are meant to guarantee to never + // return a value exceeding required_span_size(), which is used to know how large an allocation one needs + // Thus, this is a canonical point in multi-dimensional data structures to make invalid element access checks + // However, mdspan does check this on its own, so for now we avoid double checking in hardened mode + _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...), + "layout_right::mapping: out of bounds indexing"); + return [&](index_sequence<_Pos...>) { + index_type __res = 0; + ((__res = static_cast(__idx) + __extents_.extent(_Pos) * __res), ...); + return __res; + }(make_index_sequence()); + } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { return true; } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_unique() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_exhaustive() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_strided() noexcept { return true; } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept + requires(extents_type::rank() > 0) + { + // While it would be caught by extents itself too, using a too large __r + // is functionally an out of bounds access on the stored information needed to compute strides + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __r < extents_type::rank(), "layout_right::mapping::stride(): invalid rank index"); + index_type __s = 1; + for (rank_type __i = extents_type::rank() - 1; __i > __r; __i--) + __s *= __extents_.extent(__i); + return __s; + } + + template + requires(_OtherExtents::rank() == extents_type::rank()) + _LIBCPP_HIDE_FROM_ABI friend constexpr bool + operator==(const mapping& __lhs, const mapping<_OtherExtents>& __rhs) noexcept { + return __lhs.extents() == __rhs.extents(); + } + +private: + _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{}; +}; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_LAYOUT_RIGHT_H diff --git a/libcxx/include/__cxx03/__mdspan/layout_stride.h b/libcxx/include/__cxx03/__mdspan/layout_stride.h new file mode 100644 index 0000000000000000000000000000000000000000..86148ac849eca5a4786df0eefa9f70f8c710c304 --- /dev/null +++ b/libcxx/include/__cxx03/__mdspan/layout_stride.h @@ -0,0 +1,366 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Kokkos v. 4.0 +// Copyright (2022) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___MDSPAN_LAYOUT_STRIDE_H +#define _LIBCPP___MDSPAN_LAYOUT_STRIDE_H + +#include <__assert> +#include <__config> +#include <__fwd/mdspan.h> +#include <__mdspan/extents.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__utility/as_const.h> +#include <__utility/integer_sequence.h> +#include <__utility/swap.h> +#include +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +namespace __mdspan_detail { +template +constexpr bool __is_mapping_of = + is_same_v, _Mapping>; + +template +concept __layout_mapping_alike = requires { + requires __is_mapping_of; + requires __is_extents_v; + { _Mapping::is_always_strided() } -> same_as; + { _Mapping::is_always_exhaustive() } -> same_as; + { _Mapping::is_always_unique() } -> same_as; + bool_constant<_Mapping::is_always_strided()>::value; + bool_constant<_Mapping::is_always_exhaustive()>::value; + bool_constant<_Mapping::is_always_unique()>::value; +}; +} // namespace __mdspan_detail + +template +class layout_stride::mapping { +public: + static_assert(__mdspan_detail::__is_extents<_Extents>::value, + "layout_stride::mapping template argument must be a specialization of extents."); + + using extents_type = _Extents; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using layout_type = layout_stride; + +private: + static constexpr rank_type __rank_ = extents_type::rank(); + + // Used for default construction check and mandates + _LIBCPP_HIDE_FROM_ABI static constexpr bool __required_span_size_is_representable(const extents_type& __ext) { + if constexpr (__rank_ == 0) + return true; + + index_type __prod = __ext.extent(0); + for (rank_type __r = 1; __r < __rank_; __r++) { + bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), &__prod); + if (__overflowed) + return false; + } + return true; + } + + template + _LIBCPP_HIDE_FROM_ABI static constexpr bool + __required_span_size_is_representable(const extents_type& __ext, span<_OtherIndexType, __rank_> __strides) { + if constexpr (__rank_ == 0) + return true; + + index_type __size = 1; + for (rank_type __r = 0; __r < __rank_; __r++) { + // We can only check correct conversion of _OtherIndexType if it is an integral + if constexpr (is_integral_v<_OtherIndexType>) { + using _CommonType = common_type_t; + if (static_cast<_CommonType>(__strides[__r]) > static_cast<_CommonType>(numeric_limits::max())) + return false; + } + if (__ext.extent(__r) == static_cast(0)) + return true; + index_type __prod = (__ext.extent(__r) - 1); + bool __overflowed_mul = __builtin_mul_overflow(__prod, static_cast(__strides[__r]), &__prod); + if (__overflowed_mul) + return false; + bool __overflowed_add = __builtin_add_overflow(__size, __prod, &__size); + if (__overflowed_add) + return false; + } + return true; + } + + // compute offset of a strided layout mapping + template + _LIBCPP_HIDE_FROM_ABI static constexpr index_type __offset(const _StridedMapping& __mapping) { + if constexpr (_StridedMapping::extents_type::rank() == 0) { + return static_cast(__mapping()); + } else if (__mapping.required_span_size() == static_cast(0)) { + return static_cast(0); + } else { + return [&](index_sequence<_Pos...>) { + return static_cast(__mapping((_Pos ? 0 : 0)...)); + }(make_index_sequence<__rank_>()); + } + } + + // compute the permutation for sorting the stride array + // we never actually sort the stride array + _LIBCPP_HIDE_FROM_ABI constexpr void __bubble_sort_by_strides(array& __permute) const { + for (rank_type __i = __rank_ - 1; __i > 0; __i--) { + for (rank_type __r = 0; __r < __i; __r++) { + if (__strides_[__permute[__r]] > __strides_[__permute[__r + 1]]) { + swap(__permute[__r], __permute[__r + 1]); + } else { + // if two strides are the same then one of the associated extents must be 1 or 0 + // both could be, but you can't have one larger than 1 come first + if ((__strides_[__permute[__r]] == __strides_[__permute[__r + 1]]) && + (__extents_.extent(__permute[__r]) > static_cast(1))) + swap(__permute[__r], __permute[__r + 1]); + } + } + } + } + + static_assert(extents_type::rank_dynamic() > 0 || __required_span_size_is_representable(extents_type()), + "layout_stride::mapping product of static extents must be representable as index_type."); + +public: + // [mdspan.layout.stride.cons], constructors + _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept : __extents_(extents_type()) { + // Note the nominal precondition is covered by above static assert since + // if rank_dynamic is != 0 required_span_size is zero for default construction + if constexpr (__rank_ > 0) { + index_type __stride = 1; + for (rank_type __r = __rank_ - 1; __r > static_cast(0); __r--) { + __strides_[__r] = __stride; + __stride *= __extents_.extent(__r); + } + __strides_[0] = __stride; + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default; + + template + requires(is_convertible_v && + is_nothrow_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, span<_OtherIndexType, __rank_> __strides) noexcept + : __extents_(__ext), __strides_([&](index_sequence<_Pos...>) { + return __mdspan_detail::__possibly_empty_array{ + static_cast(std::as_const(__strides[_Pos]))...}; + }(make_index_sequence<__rank_>())) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + ([&](index_sequence<_Pos...>) { + // For integrals we can do a pre-conversion check, for other types not + if constexpr (is_integral_v<_OtherIndexType>) { + return ((__strides[_Pos] > static_cast<_OtherIndexType>(0)) && ... && true); + } else { + return ((static_cast(__strides[_Pos]) > static_cast(0)) && ... && true); + } + }(make_index_sequence<__rank_>())), + "layout_stride::mapping ctor: all strides must be greater than 0"); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __required_span_size_is_representable(__ext, __strides), + "layout_stride::mapping ctor: required span size is not representable as index_type."); + if constexpr (__rank_ > 1) { + _LIBCPP_ASSERT_UNCATEGORIZED( + ([&](index_sequence<_Pos...>) { + // basically sort the dimensions based on strides and extents, sorting is represented in permute array + array __permute{_Pos...}; + __bubble_sort_by_strides(__permute); + + // check that this permutations represents a growing set + for (rank_type __i = 1; __i < __rank_; __i++) + if (static_cast(__strides[__permute[__i]]) < + static_cast(__strides[__permute[__i - 1]]) * __extents_.extent(__permute[__i - 1])) + return false; + return true; + }(make_index_sequence<__rank_>())), + "layout_stride::mapping ctor: the provided extents and strides lead to a non-unique mapping"); + } + } + + template + requires(is_convertible_v && + is_nothrow_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, + const array<_OtherIndexType, __rank_>& __strides) noexcept + : mapping(__ext, span(__strides)) {} + + template + requires(__mdspan_detail::__layout_mapping_alike<_StridedLayoutMapping> && + is_constructible_v && + _StridedLayoutMapping::is_always_unique() && _StridedLayoutMapping::is_always_strided()) + _LIBCPP_HIDE_FROM_ABI constexpr explicit( + !(is_convertible_v && + (__mdspan_detail::__is_mapping_of || + __mdspan_detail::__is_mapping_of || + __mdspan_detail::__is_mapping_of))) + mapping(const _StridedLayoutMapping& __other) noexcept + : __extents_(__other.extents()), __strides_([&](index_sequence<_Pos...>) { + // stride() only compiles for rank > 0 + if constexpr (__rank_ > 0) { + return __mdspan_detail::__possibly_empty_array{ + static_cast(__other.stride(_Pos))...}; + } else { + return __mdspan_detail::__possibly_empty_array{}; + } + }(make_index_sequence<__rank_>())) { + // stride() only compiles for rank > 0 + if constexpr (__rank_ > 0) { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + ([&](index_sequence<_Pos...>) { + return ((static_cast(__other.stride(_Pos)) > static_cast(0)) && ... && true); + }(make_index_sequence<__rank_>())), + "layout_stride::mapping converting ctor: all strides must be greater than 0"); + } + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __mdspan_detail::__is_representable_as(__other.required_span_size()), + "layout_stride::mapping converting ctor: other.required_span_size() must be representable as index_type."); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(static_cast(0) == __offset(__other), + "layout_stride::mapping converting ctor: base offset of mapping must be zero."); + } + + _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default; + + // [mdspan.layout.stride.obs], observers + _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __extents_; } + + _LIBCPP_HIDE_FROM_ABI constexpr array strides() const noexcept { + return [&](index_sequence<_Pos...>) { + return array{__strides_[_Pos]...}; + }(make_index_sequence<__rank_>()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr index_type required_span_size() const noexcept { + if constexpr (__rank_ == 0) { + return static_cast(1); + } else { + return [&](index_sequence<_Pos...>) { + if ((__extents_.extent(_Pos) * ... * 1) == 0) + return static_cast(0); + else + return static_cast( + static_cast(1) + + (((__extents_.extent(_Pos) - static_cast(1)) * __strides_[_Pos]) + ... + + static_cast(0))); + }(make_index_sequence<__rank_>()); + } + } + + template + requires((sizeof...(_Indices) == __rank_) && (is_convertible_v<_Indices, index_type> && ...) && + (is_nothrow_constructible_v && ...)) + _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept { + // Mappings are generally meant to be used for accessing allocations and are meant to guarantee to never + // return a value exceeding required_span_size(), which is used to know how large an allocation one needs + // Thus, this is a canonical point in multi-dimensional data structures to make invalid element access checks + // However, mdspan does check this on its own, so for now we avoid double checking in hardened mode + _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...), + "layout_stride::mapping: out of bounds indexing"); + return [&](index_sequence<_Pos...>) { + return ((static_cast(__idx) * __strides_[_Pos]) + ... + index_type(0)); + }(make_index_sequence()); + } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return true; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept { return false; } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { return true; } + + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_unique() noexcept { return true; } + // The answer of this function is fairly complex in the case where one or more + // extents are zero. + // Technically it is meaningless to query is_exhaustive() in that case, but unfortunately + // the way the standard defines this function, we can't give a simple true or false then. + _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const noexcept { + if constexpr (__rank_ == 0) + return true; + else { + index_type __span_size = required_span_size(); + if (__span_size == static_cast(0)) { + if constexpr (__rank_ == 1) + return __strides_[0] == 1; + else { + rank_type __r_largest = 0; + for (rank_type __r = 1; __r < __rank_; __r++) + if (__strides_[__r] > __strides_[__r_largest]) + __r_largest = __r; + for (rank_type __r = 0; __r < __rank_; __r++) + if (__extents_.extent(__r) == 0 && __r != __r_largest) + return false; + return true; + } + } else { + return required_span_size() == [&](index_sequence<_Pos...>) { + return (__extents_.extent(_Pos) * ... * static_cast(1)); + }(make_index_sequence<__rank_>()); + } + } + } + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_strided() noexcept { return true; } + + // according to the standard layout_stride does not have a constraint on stride(r) for rank>0 + // it still has the precondition though + _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__r < __rank_, "layout_stride::mapping::stride(): invalid rank index"); + return __strides_[__r]; + } + + template + requires(__mdspan_detail::__layout_mapping_alike<_OtherMapping> && + (_OtherMapping::extents_type::rank() == __rank_) && _OtherMapping::is_always_strided()) + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const mapping& __lhs, const _OtherMapping& __rhs) noexcept { + if (__offset(__rhs)) + return false; + if constexpr (__rank_ == 0) + return true; + else { + return __lhs.extents() == __rhs.extents() && [&](index_sequence<_Pos...>) { + // avoid warning when comparing signed and unsigner integers and pick the wider of two types + using _CommonType = common_type_t; + return ((static_cast<_CommonType>(__lhs.stride(_Pos)) == static_cast<_CommonType>(__rhs.stride(_Pos))) && ... && + true); + }(make_index_sequence<__rank_>()); + } + } + +private: + _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{}; + _LIBCPP_NO_UNIQUE_ADDRESS __mdspan_detail::__possibly_empty_array __strides_{}; +}; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_LAYOUT_STRIDE_H diff --git a/libcxx/include/__cxx03/__mdspan/mdspan.h b/libcxx/include/__cxx03/__mdspan/mdspan.h new file mode 100644 index 0000000000000000000000000000000000000000..1ff4fd4ba4a8298d3eb5b3b1702e9eca46cbbac8 --- /dev/null +++ b/libcxx/include/__cxx03/__mdspan/mdspan.h @@ -0,0 +1,319 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Kokkos v. 4.0 +// Copyright (2022) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +//===---------------------------------------------------------------------===// + +#ifndef _LIBCPP___MDSPAN_MDSPAN_H +#define _LIBCPP___MDSPAN_MDSPAN_H + +#include <__assert> +#include <__config> +#include <__fwd/mdspan.h> +#include <__mdspan/default_accessor.h> +#include <__mdspan/extents.h> +#include <__type_traits/extent.h> +#include <__type_traits/is_abstract.h> +#include <__type_traits/is_array.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_pointer.h> +#include <__type_traits/is_same.h> +#include <__type_traits/rank.h> +#include <__type_traits/remove_all_extents.h> +#include <__type_traits/remove_cv.h> +#include <__type_traits/remove_pointer.h> +#include <__type_traits/remove_reference.h> +#include <__utility/integer_sequence.h> +#include +#include +#include +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +// Helper for lightweight test checking that one did pass a layout policy as LayoutPolicy template argument +namespace __mdspan_detail { +template +concept __has_invalid_mapping = !requires { typename _Layout::template mapping<_Extents>; }; +} // namespace __mdspan_detail + +template > +class mdspan { +private: + static_assert(__mdspan_detail::__is_extents_v<_Extents>, + "mdspan: Extents template parameter must be a specialization of extents."); + static_assert(!is_array_v<_ElementType>, "mdspan: ElementType template parameter may not be an array type"); + static_assert(!is_abstract_v<_ElementType>, "mdspan: ElementType template parameter may not be an abstract class"); + static_assert(is_same_v<_ElementType, typename _AccessorPolicy::element_type>, + "mdspan: ElementType template parameter must match AccessorPolicy::element_type"); + static_assert(!__mdspan_detail::__has_invalid_mapping<_LayoutPolicy, _Extents>, + "mdspan: LayoutPolicy template parameter is invalid. A common mistake is to pass a layout mapping " + "instead of a layout policy"); + +public: + using extents_type = _Extents; + using layout_type = _LayoutPolicy; + using accessor_type = _AccessorPolicy; + using mapping_type = typename layout_type::template mapping; + using element_type = _ElementType; + using value_type = remove_cv_t; + using index_type = typename extents_type::index_type; + using size_type = typename extents_type::size_type; + using rank_type = typename extents_type::rank_type; + using data_handle_type = typename accessor_type::data_handle_type; + using reference = typename accessor_type::reference; + + _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return extents_type::rank(); } + _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { return extents_type::rank_dynamic(); } + _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept { + return extents_type::static_extent(__r); + } + _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept { + return __map_.extents().extent(__r); + }; + +public: + //-------------------------------------------------------------------------------- + // [mdspan.mdspan.cons], mdspan constructors, assignment, and destructor + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan() + requires((extents_type::rank_dynamic() > 0) && is_default_constructible_v && + is_default_constructible_v && is_default_constructible_v) + = default; + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(const mdspan&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(mdspan&&) = default; + + template + requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) && + (is_nothrow_constructible_v && ...) && + ((sizeof...(_OtherIndexTypes) == rank()) || (sizeof...(_OtherIndexTypes) == rank_dynamic())) && + is_constructible_v && is_default_constructible_v) + _LIBCPP_HIDE_FROM_ABI explicit constexpr mdspan(data_handle_type __p, _OtherIndexTypes... __exts) + : __ptr_(std::move(__p)), __map_(extents_type(static_cast(std::move(__exts))...)), __acc_{} {} + + template + requires(is_convertible_v && + is_nothrow_constructible_v && + ((_Size == rank()) || (_Size == rank_dynamic())) && is_constructible_v && + is_default_constructible_v) + explicit(_Size != rank_dynamic()) + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const array<_OtherIndexType, _Size>& __exts) + : __ptr_(std::move(__p)), __map_(extents_type(__exts)), __acc_{} {} + + template + requires(is_convertible_v && + is_nothrow_constructible_v && + ((_Size == rank()) || (_Size == rank_dynamic())) && is_constructible_v && + is_default_constructible_v) + explicit(_Size != rank_dynamic()) + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, span<_OtherIndexType, _Size> __exts) + : __ptr_(std::move(__p)), __map_(extents_type(__exts)), __acc_{} {} + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const extents_type& __exts) + requires(is_default_constructible_v && is_constructible_v) + : __ptr_(std::move(__p)), __map_(__exts), __acc_{} {} + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const mapping_type& __m) + requires(is_default_constructible_v) + : __ptr_(std::move(__p)), __map_(__m), __acc_{} {} + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const mapping_type& __m, const accessor_type& __a) + : __ptr_(std::move(__p)), __map_(__m), __acc_(__a) {} + + template + requires(is_constructible_v&> && + is_constructible_v) + explicit(!is_convertible_v&, mapping_type> || + !is_convertible_v) + _LIBCPP_HIDE_FROM_ABI constexpr mdspan( + const mdspan<_OtherElementType, _OtherExtents, _OtherLayoutPolicy, _OtherAccessor>& __other) + : __ptr_(__other.__ptr_), __map_(__other.__map_), __acc_(__other.__acc_) { + static_assert(is_constructible_v, + "mdspan: incompatible data_handle_type for mdspan construction"); + static_assert( + is_constructible_v, "mdspan: incompatible extents for mdspan construction"); + + // The following precondition is part of the standard, but is unlikely to be triggered. + // The extents constructor checks this and the mapping must be storing the extents, since + // its extents() function returns a const reference to extents_type. + // The only way this can be triggered is if the mapping conversion constructor would for example + // always construct its extents() only from the dynamic extents, instead of from the other extents. + if constexpr (rank() > 0) { + for (size_t __r = 0; __r < rank(); __r++) { + // Not catching this could lead to out of bounds errors later + // e.g. mdspan, non_checking_layout> m = + // mdspan, non_checking_layout>(ptr, 200); leads to an extent of -56 on m + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + (static_extent(__r) == dynamic_extent) || + (static_cast(__other.extent(__r)) == static_cast(static_extent(__r))), + "mdspan: conversion mismatch of source dynamic extents with static extents"); + } + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr mdspan& operator=(const mdspan&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr mdspan& operator=(mdspan&&) = default; + + //-------------------------------------------------------------------------------- + // [mdspan.mdspan.members], members + + template + requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) && + (is_nothrow_constructible_v && ...) && + (sizeof...(_OtherIndexTypes) == rank())) + _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](_OtherIndexTypes... __indices) const { + // Note the standard layouts would also check this, but user provided ones may not, so we + // check the precondition here + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__is_multidimensional_index_in(extents(), __indices...), + "mdspan: operator[] out of bounds access"); + return __acc_.access(__ptr_, __map_(static_cast(std::move(__indices))...)); + } + + template + requires(is_convertible_v && + is_nothrow_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](const array< _OtherIndexType, rank()>& __indices) const { + return __acc_.access(__ptr_, [&](index_sequence<_Idxs...>) { + return __map_(__indices[_Idxs]...); + }(make_index_sequence())); + } + + template + requires(is_convertible_v && + is_nothrow_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](span<_OtherIndexType, rank()> __indices) const { + return __acc_.access(__ptr_, [&](index_sequence<_Idxs...>) { + return __map_(__indices[_Idxs]...); + }(make_index_sequence())); + } + + _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept { + // Could leave this as only checked in debug mode: semantically size() is never + // guaranteed to be related to any accessible range + _LIBCPP_ASSERT_UNCATEGORIZED( + false == ([&](index_sequence<_Idxs...>) { + size_type __prod = 1; + return (__builtin_mul_overflow(__prod, extent(_Idxs), &__prod) || ... || false); + }(make_index_sequence())), + "mdspan: size() is not representable as size_type"); + return [&](index_sequence<_Idxs...>) { + return ((static_cast(__map_.extents().extent(_Idxs))) * ... * size_type(1)); + }(make_index_sequence()); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const noexcept { + return [&](index_sequence<_Idxs...>) { + return (rank() > 0) && ((__map_.extents().extent(_Idxs) == index_type(0)) || ... || false); + }(make_index_sequence()); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(mdspan& __x, mdspan& __y) noexcept { + swap(__x.__ptr_, __y.__ptr_); + swap(__x.__map_, __y.__map_); + swap(__x.__acc_, __y.__acc_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __map_.extents(); }; + _LIBCPP_HIDE_FROM_ABI constexpr const data_handle_type& data_handle() const noexcept { return __ptr_; }; + _LIBCPP_HIDE_FROM_ABI constexpr const mapping_type& mapping() const noexcept { return __map_; }; + _LIBCPP_HIDE_FROM_ABI constexpr const accessor_type& accessor() const noexcept { return __acc_; }; + + // per LWG-4021 "mdspan::is_always_meow() should be noexcept" + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return mapping_type::is_always_unique(); }; + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept { + return mapping_type::is_always_exhaustive(); + }; + _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { + return mapping_type::is_always_strided(); + }; + + _LIBCPP_HIDE_FROM_ABI constexpr bool is_unique() const { return __map_.is_unique(); }; + _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const { return __map_.is_exhaustive(); }; + _LIBCPP_HIDE_FROM_ABI constexpr bool is_strided() const { return __map_.is_strided(); }; + _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const { return __map_.stride(__r); }; + +private: + _LIBCPP_NO_UNIQUE_ADDRESS data_handle_type __ptr_{}; + _LIBCPP_NO_UNIQUE_ADDRESS mapping_type __map_{}; + _LIBCPP_NO_UNIQUE_ADDRESS accessor_type __acc_{}; + + template + friend class mdspan; +}; + +# if _LIBCPP_STD_VER >= 26 +template + requires((is_convertible_v<_OtherIndexTypes, size_t> && ...) && (sizeof...(_OtherIndexTypes) > 0)) +explicit mdspan(_ElementType*, + _OtherIndexTypes...) -> mdspan<_ElementType, extents...>>; +# else +template + requires((is_convertible_v<_OtherIndexTypes, size_t> && ...) && (sizeof...(_OtherIndexTypes) > 0)) +explicit mdspan(_ElementType*, + _OtherIndexTypes...) -> mdspan<_ElementType, dextents>; +# endif + +template + requires(is_pointer_v>) +mdspan(_Pointer&&) -> mdspan>, extents>; + +template + requires(is_array_v<_CArray> && (rank_v<_CArray> == 1)) +mdspan(_CArray&) -> mdspan, extents>>; + +template +mdspan(_ElementType*, const array<_OtherIndexType, _Size>&) -> mdspan<_ElementType, dextents>; + +template +mdspan(_ElementType*, span<_OtherIndexType, _Size>) -> mdspan<_ElementType, dextents>; + +// This one is necessary because all the constructors take `data_handle_type`s, not +// `_ElementType*`s, and `data_handle_type` is taken from `accessor_type::data_handle_type`, which +// seems to throw off automatic deduction guides. +template +mdspan(_ElementType*, const extents<_OtherIndexType, _ExtentsPack...>&) + -> mdspan<_ElementType, extents<_OtherIndexType, _ExtentsPack...>>; + +template +mdspan(_ElementType*, const _MappingType&) + -> mdspan<_ElementType, typename _MappingType::extents_type, typename _MappingType::layout_type>; + +template +mdspan(const typename _AccessorType::data_handle_type, const _MappingType&, const _AccessorType&) + -> mdspan; + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MDSPAN_MDSPAN_H diff --git a/libcxx/include/__cxx03/__memory/addressof.h b/libcxx/include/__cxx03/__memory/addressof.h new file mode 100644 index 0000000000000000000000000000000000000000..fa590212c49b96effe9ac549dacf617b716b7134 --- /dev/null +++ b/libcxx/include/__cxx03/__memory/addressof.h @@ -0,0 +1,61 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MEMORY_ADDRESSOF_H +#define _LIBCPP___MEMORY_ADDRESSOF_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_NO_CFI _LIBCPP_HIDE_FROM_ABI _Tp* addressof(_Tp& __x) _NOEXCEPT { + return __builtin_addressof(__x); +} + +#if defined(_LIBCPP_HAS_OBJC_ARC) && !defined(_LIBCPP_PREDEFINED_OBJC_ARC_ADDRESSOF) +// Objective-C++ Automatic Reference Counting uses qualified pointers +// that require special addressof() signatures. When +// _LIBCPP_PREDEFINED_OBJC_ARC_ADDRESSOF is defined, the compiler +// itself is providing these definitions. Otherwise, we provide them. +template +inline _LIBCPP_HIDE_FROM_ABI __strong _Tp* addressof(__strong _Tp& __x) _NOEXCEPT { + return &__x; +} + +# ifdef _LIBCPP_HAS_OBJC_ARC_WEAK +template +inline _LIBCPP_HIDE_FROM_ABI __weak _Tp* addressof(__weak _Tp& __x) _NOEXCEPT { + return &__x; +} +# endif + +template +inline _LIBCPP_HIDE_FROM_ABI __autoreleasing _Tp* addressof(__autoreleasing _Tp& __x) _NOEXCEPT { + return &__x; +} + +template +inline _LIBCPP_HIDE_FROM_ABI __unsafe_unretained _Tp* addressof(__unsafe_unretained _Tp& __x) _NOEXCEPT { + return &__x; +} +#endif + +#if !defined(_LIBCPP_CXX03_LANG) +template +_Tp* addressof(const _Tp&&) noexcept = delete; +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MEMORY_ADDRESSOF_H diff --git a/libcxx/include/__cxx03/__memory/align.h b/libcxx/include/__cxx03/__memory/align.h new file mode 100644 index 0000000000000000000000000000000000000000..bbb995f4a8c8eddb34c3911a8b4adfa4256bc89b --- /dev/null +++ b/libcxx/include/__cxx03/__memory/align.h @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MEMORY_ALIGN_H +#define _LIBCPP___MEMORY_ALIGN_H + +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_EXPORTED_FROM_ABI void* align(size_t __align, size_t __sz, void*& __ptr, size_t& __space); + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MEMORY_ALIGN_H diff --git a/libcxx/include/__cxx03/__memory/aligned_alloc.h b/libcxx/include/__cxx03/__memory/aligned_alloc.h new file mode 100644 index 0000000000000000000000000000000000000000..cb424328bcafc174ef7d3df0d8388d591a519e76 --- /dev/null +++ b/libcxx/include/__cxx03/__memory/aligned_alloc.h @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MEMORY_ALIGNED_ALLOC_H +#define _LIBCPP___MEMORY_ALIGNED_ALLOC_H + +#include <__config> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#ifndef _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION + +// Low-level helpers to call the aligned allocation and deallocation functions +// on the target platform. This is used to implement libc++'s own memory +// allocation routines -- if you need to allocate memory inside the library, +// chances are that you want to use `__libcpp_allocate` instead. +// +// Returns the allocated memory, or `nullptr` on failure. +inline _LIBCPP_HIDE_FROM_ABI void* __libcpp_aligned_alloc(std::size_t __alignment, std::size_t __size) { +# if defined(_LIBCPP_MSVCRT_LIKE) + return ::_aligned_malloc(__size, __alignment); +# elif _LIBCPP_STD_VER >= 17 && !defined(_LIBCPP_HAS_NO_C11_ALIGNED_ALLOC) + // aligned_alloc() requires that __size is a multiple of __alignment, + // but for C++ [new.delete.general], only states "if the value of an + // alignment argument passed to any of these functions is not a valid + // alignment value, the behavior is undefined". + // To handle calls such as ::operator new(1, std::align_val_t(128)), we + // round __size up to the next multiple of __alignment. + size_t __rounded_size = (__size + __alignment - 1) & ~(__alignment - 1); + // Rounding up could have wrapped around to zero, so we have to add another + // max() ternary to the actual call site to avoid succeeded in that case. + return ::aligned_alloc(__alignment, __size > __rounded_size ? __size : __rounded_size); +# else + void* __result = nullptr; + (void)::posix_memalign(&__result, __alignment, __size); + // If posix_memalign fails, __result is unmodified so we still return `nullptr`. + return __result; +# endif +} + +inline _LIBCPP_HIDE_FROM_ABI void __libcpp_aligned_free(void* __ptr) { +# if defined(_LIBCPP_MSVCRT_LIKE) + ::_aligned_free(__ptr); +# else + ::free(__ptr); +# endif +} + +#endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MEMORY_ALIGNED_ALLOC_H diff --git a/libcxx/include/__cxx03/__memory/allocate_at_least.h b/libcxx/include/__cxx03/__memory/allocate_at_least.h new file mode 100644 index 0000000000000000000000000000000000000000..df73d9a2e94aa6f31f5615ccc46c8eb3d49c88f8 --- /dev/null +++ b/libcxx/include/__cxx03/__memory/allocate_at_least.h @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MEMORY_ALLOCATE_AT_LEAST_H +#define _LIBCPP___MEMORY_ALLOCATE_AT_LEAST_H + +#include <__config> +#include <__memory/allocator_traits.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +template +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto __allocate_at_least(_Alloc& __alloc, size_t __n) { + return std::allocator_traits<_Alloc>::allocate_at_least(__alloc, __n); +} + +#else + +template +struct __allocation_result { + _Pointer ptr; + size_t count; +}; + +template +_LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR __allocation_result::pointer> +__allocate_at_least(_Alloc& __alloc, size_t __n) { + return {__alloc.allocate(__n), __n}; +} + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MEMORY_ALLOCATE_AT_LEAST_H diff --git a/libcxx/include/__cxx03/__memory/allocation_guard.h b/libcxx/include/__cxx03/__memory/allocation_guard.h new file mode 100644 index 0000000000000000000000000000000000000000..cb870af7be6760ea780921b0708ef301411c41a0 --- /dev/null +++ b/libcxx/include/__cxx03/__memory/allocation_guard.h @@ -0,0 +1,108 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MEMORY_ALLOCATION_GUARD_H +#define _LIBCPP___MEMORY_ALLOCATION_GUARD_H + +#include <__config> +#include <__memory/addressof.h> +#include <__memory/allocator_traits.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// Helper class to allocate memory using an Allocator in an exception safe +// manner. +// +// The intended usage of this class is as follows: +// +// 0 +// 1 __allocation_guard guard(alloc, 10); +// 2 do_some_initialization_that_may_throw(guard.__get()); +// 3 save_allocated_pointer_in_a_noexcept_operation(guard.__release_ptr()); +// 4 +// +// If line (2) throws an exception during initialization of the memory, the +// guard's destructor will be called, and the memory will be released using +// Allocator deallocation. Otherwise, we release the memory from the guard on +// line (3) in an operation that can't throw -- after that, the guard is not +// responsible for the memory anymore. +// +// This is similar to a unique_ptr, except it's easier to use with a +// custom allocator. +template +struct __allocation_guard { + using _Pointer = typename allocator_traits<_Alloc>::pointer; + using _Size = typename allocator_traits<_Alloc>::size_type; + + template // we perform the allocator conversion inside the constructor + _LIBCPP_HIDE_FROM_ABI explicit __allocation_guard(_AllocT __alloc, _Size __n) + : __alloc_(std::move(__alloc)), + __n_(__n), + __ptr_(allocator_traits<_Alloc>::allocate(__alloc_, __n_)) // initialization order is important + {} + + _LIBCPP_HIDE_FROM_ABI ~__allocation_guard() _NOEXCEPT { __destroy(); } + + _LIBCPP_HIDE_FROM_ABI __allocation_guard(const __allocation_guard&) = delete; + _LIBCPP_HIDE_FROM_ABI __allocation_guard(__allocation_guard&& __other) _NOEXCEPT + : __alloc_(std::move(__other.__alloc_)), + __n_(__other.__n_), + __ptr_(__other.__ptr_) { + __other.__ptr_ = nullptr; + } + + _LIBCPP_HIDE_FROM_ABI __allocation_guard& operator=(const __allocation_guard& __other) = delete; + _LIBCPP_HIDE_FROM_ABI __allocation_guard& operator=(__allocation_guard&& __other) _NOEXCEPT { + if (std::addressof(__other) != this) { + __destroy(); + + __alloc_ = std::move(__other.__alloc_); + __n_ = __other.__n_; + __ptr_ = __other.__ptr_; + __other.__ptr_ = nullptr; + } + + return *this; + } + + _LIBCPP_HIDE_FROM_ABI _Pointer + __release_ptr() _NOEXCEPT { // not called __release() because it's a keyword in objective-c++ + _Pointer __tmp = __ptr_; + __ptr_ = nullptr; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI _Pointer __get() const _NOEXCEPT { return __ptr_; } + +private: + _LIBCPP_HIDE_FROM_ABI void __destroy() _NOEXCEPT { + if (__ptr_ != nullptr) { + allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __n_); + } + } + + _Alloc __alloc_; + _Size __n_; + _Pointer __ptr_; +}; + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MEMORY_ALLOCATION_GUARD_H diff --git a/libcxx/include/__cxx03/__memory/allocator.h b/libcxx/include/__cxx03/__memory/allocator.h new file mode 100644 index 0000000000000000000000000000000000000000..2d8624e771bce07cf3128ea0086753a857028590 --- /dev/null +++ b/libcxx/include/__cxx03/__memory/allocator.h @@ -0,0 +1,268 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MEMORY_ALLOCATOR_H +#define _LIBCPP___MEMORY_ALLOCATOR_H + +#include <__config> +#include <__memory/addressof.h> +#include <__memory/allocate_at_least.h> +#include <__memory/allocator_traits.h> +#include <__type_traits/is_const.h> +#include <__type_traits/is_constant_evaluated.h> +#include <__type_traits/is_same.h> +#include <__type_traits/is_void.h> +#include <__type_traits/is_volatile.h> +#include <__utility/forward.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class allocator; + +#if _LIBCPP_STD_VER <= 17 +// These specializations shouldn't be marked _LIBCPP_DEPRECATED_IN_CXX17. +// Specializing allocator is deprecated, but not using it. +template <> +class _LIBCPP_TEMPLATE_VIS allocator { +public: + _LIBCPP_DEPRECATED_IN_CXX17 typedef void* pointer; + _LIBCPP_DEPRECATED_IN_CXX17 typedef const void* const_pointer; + _LIBCPP_DEPRECATED_IN_CXX17 typedef void value_type; + + template + struct _LIBCPP_DEPRECATED_IN_CXX17 rebind { + typedef allocator<_Up> other; + }; +}; + +// TODO(LLVM 20): Remove the escape hatch +# ifdef _LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST +template <> +class _LIBCPP_TEMPLATE_VIS allocator { +public: + _LIBCPP_DEPRECATED_IN_CXX17 typedef const void* pointer; + _LIBCPP_DEPRECATED_IN_CXX17 typedef const void* const_pointer; + _LIBCPP_DEPRECATED_IN_CXX17 typedef const void value_type; + + template + struct _LIBCPP_DEPRECATED_IN_CXX17 rebind { + typedef allocator<_Up> other; + }; +}; +# endif // _LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST +#endif // _LIBCPP_STD_VER <= 17 + +// This class provides a non-trivial default constructor to the class that derives from it +// if the condition is satisfied. +// +// The second template parameter exists to allow giving a unique type to __non_trivial_if, +// which makes it possible to avoid breaking the ABI when making this a base class of an +// existing class. Without that, imagine we have classes D1 and D2, both of which used to +// have no base classes, but which now derive from __non_trivial_if. The layout of a class +// that inherits from both D1 and D2 will change because the two __non_trivial_if base +// classes are not allowed to share the same address. +// +// By making those __non_trivial_if base classes unique, we work around this problem and +// it is safe to start deriving from __non_trivial_if in existing classes. +template +struct __non_trivial_if {}; + +template +struct __non_trivial_if { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __non_trivial_if() _NOEXCEPT {} +}; + +// allocator +// +// Note: For ABI compatibility between C++20 and previous standards, we make +// allocator trivial in C++20. + +template +class _LIBCPP_TEMPLATE_VIS allocator : private __non_trivial_if::value, allocator<_Tp> > { + static_assert(!is_const<_Tp>::value, "std::allocator does not support const types"); + static_assert(!is_volatile<_Tp>::value, "std::allocator does not support volatile types"); + +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef _Tp value_type; + typedef true_type propagate_on_container_move_assignment; +#if _LIBCPP_STD_VER <= 23 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_ALLOCATOR_MEMBERS) + _LIBCPP_DEPRECATED_IN_CXX23 typedef true_type is_always_equal; +#endif + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 allocator() _NOEXCEPT = default; + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 allocator(const allocator<_Up>&) _NOEXCEPT {} + + _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp* allocate(size_t __n) { + if (__n > allocator_traits::max_size(*this)) + __throw_bad_array_new_length(); + if (__libcpp_is_constant_evaluated()) { + return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); + } else { + return static_cast<_Tp*>(std::__libcpp_allocate(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp))); + } + } + +#if _LIBCPP_STD_VER >= 23 + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr allocation_result<_Tp*> allocate_at_least(size_t __n) { + return {allocate(__n), __n}; + } +#endif + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void deallocate(_Tp* __p, size_t __n) _NOEXCEPT { + if (__libcpp_is_constant_evaluated()) { + ::operator delete(__p); + } else { + std::__libcpp_deallocate((void*)__p, __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp)); + } + } + + // C++20 Removed members +#if _LIBCPP_STD_VER <= 17 + _LIBCPP_DEPRECATED_IN_CXX17 typedef _Tp* pointer; + _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp* const_pointer; + _LIBCPP_DEPRECATED_IN_CXX17 typedef _Tp& reference; + _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp& const_reference; + + template + struct _LIBCPP_DEPRECATED_IN_CXX17 rebind { + typedef allocator<_Up> other; + }; + + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI pointer address(reference __x) const _NOEXCEPT { + return std::addressof(__x); + } + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI const_pointer address(const_reference __x) const _NOEXCEPT { + return std::addressof(__x); + } + + _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_IN_CXX17 _Tp* allocate(size_t __n, const void*) { + return allocate(__n); + } + + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { + return size_type(~0) / sizeof(_Tp); + } + + template + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI void construct(_Up* __p, _Args&&... __args) { + ::new ((void*)__p) _Up(std::forward<_Args>(__args)...); + } + + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI void destroy(pointer __p) { __p->~_Tp(); } +#endif +}; + +// TODO(LLVM 20): Remove the escape hatch +#ifdef _LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST +template +class _LIBCPP_TEMPLATE_VIS allocator + : private __non_trivial_if::value, allocator > { + static_assert(!is_volatile<_Tp>::value, "std::allocator does not support volatile types"); + +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef const _Tp value_type; + typedef true_type propagate_on_container_move_assignment; +# if _LIBCPP_STD_VER <= 23 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_ALLOCATOR_MEMBERS) + _LIBCPP_DEPRECATED_IN_CXX23 typedef true_type is_always_equal; +# endif + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 allocator() _NOEXCEPT = default; + + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 allocator(const allocator<_Up>&) _NOEXCEPT {} + + _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const _Tp* allocate(size_t __n) { + if (__n > allocator_traits::max_size(*this)) + __throw_bad_array_new_length(); + if (__libcpp_is_constant_evaluated()) { + return static_cast(::operator new(__n * sizeof(_Tp))); + } else { + return static_cast(std::__libcpp_allocate(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp))); + } + } + +# if _LIBCPP_STD_VER >= 23 + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr allocation_result allocate_at_least(size_t __n) { + return {allocate(__n), __n}; + } +# endif + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void deallocate(const _Tp* __p, size_t __n) { + if (__libcpp_is_constant_evaluated()) { + ::operator delete(const_cast<_Tp*>(__p)); + } else { + std::__libcpp_deallocate((void*)const_cast<_Tp*>(__p), __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp)); + } + } + + // C++20 Removed members +# if _LIBCPP_STD_VER <= 17 + _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp* pointer; + _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp* const_pointer; + _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp& reference; + _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp& const_reference; + + template + struct _LIBCPP_DEPRECATED_IN_CXX17 rebind { + typedef allocator<_Up> other; + }; + + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI const_pointer address(const_reference __x) const _NOEXCEPT { + return std::addressof(__x); + } + + _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_IN_CXX17 const _Tp* allocate(size_t __n, const void*) { + return allocate(__n); + } + + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { + return size_type(~0) / sizeof(_Tp); + } + + template + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI void construct(_Up* __p, _Args&&... __args) { + ::new ((void*)__p) _Up(std::forward<_Args>(__args)...); + } + + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI void destroy(pointer __p) { __p->~_Tp(); } +# endif +}; +#endif // _LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool +operator==(const allocator<_Tp>&, const allocator<_Up>&) _NOEXCEPT { + return true; +} + +#if _LIBCPP_STD_VER <= 17 + +template +inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const allocator<_Tp>&, const allocator<_Up>&) _NOEXCEPT { + return false; +} + +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MEMORY_ALLOCATOR_H diff --git a/libcxx/include/__cxx03/__memory/allocator_arg_t.h b/libcxx/include/__cxx03/__memory/allocator_arg_t.h new file mode 100644 index 0000000000000000000000000000000000000000..7e66da740cd4fd8f0435fa91175dbae13c188274 --- /dev/null +++ b/libcxx/include/__cxx03/__memory/allocator_arg_t.h @@ -0,0 +1,75 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_ALLOCATOR_ARG_T_H +#define _LIBCPP___FUNCTIONAL_ALLOCATOR_ARG_T_H + +#include <__config> +#include <__memory/uses_allocator.h> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +struct _LIBCPP_TEMPLATE_VIS allocator_arg_t { + explicit allocator_arg_t() = default; +}; + +#if _LIBCPP_STD_VER >= 17 +inline constexpr allocator_arg_t allocator_arg = allocator_arg_t(); +#elif !defined(_LIBCPP_CXX03_LANG) +constexpr allocator_arg_t allocator_arg = allocator_arg_t(); +#endif + +#ifndef _LIBCPP_CXX03_LANG + +// allocator construction + +template +struct __uses_alloc_ctor_imp { + typedef _LIBCPP_NODEBUG __remove_cvref_t<_Alloc> _RawAlloc; + static const bool __ua = uses_allocator<_Tp, _RawAlloc>::value; + static const bool __ic = is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>::value; + static const int value = __ua ? 2 - __ic : 0; +}; + +template +struct __uses_alloc_ctor : integral_constant::value> {}; + +template +inline _LIBCPP_HIDE_FROM_ABI void +__user_alloc_construct_impl(integral_constant, _Tp* __storage, const _Allocator&, _Args&&... __args) { + new (__storage) _Tp(std::forward<_Args>(__args)...); +} + +// FIXME: This should have a version which takes a non-const alloc. +template +inline _LIBCPP_HIDE_FROM_ABI void +__user_alloc_construct_impl(integral_constant, _Tp* __storage, const _Allocator& __a, _Args&&... __args) { + new (__storage) _Tp(allocator_arg, __a, std::forward<_Args>(__args)...); +} + +// FIXME: This should have a version which takes a non-const alloc. +template +inline _LIBCPP_HIDE_FROM_ABI void +__user_alloc_construct_impl(integral_constant, _Tp* __storage, const _Allocator& __a, _Args&&... __args) { + new (__storage) _Tp(std::forward<_Args>(__args)..., __a); +} + +#endif // _LIBCPP_CXX03_LANG + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_ALLOCATOR_ARG_T_H diff --git a/libcxx/include/__cxx03/__memory/allocator_destructor.h b/libcxx/include/__cxx03/__memory/allocator_destructor.h new file mode 100644 index 0000000000000000000000000000000000000000..ed3d8918f5fe3fb24b2bf9f3fd16c119b49d3fcd --- /dev/null +++ b/libcxx/include/__cxx03/__memory/allocator_destructor.h @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MEMORY_ALLOCATOR_DESTRUCTOR_H +#define _LIBCPP___MEMORY_ALLOCATOR_DESTRUCTOR_H + +#include <__config> +#include <__memory/allocator_traits.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class __allocator_destructor { + typedef _LIBCPP_NODEBUG allocator_traits<_Alloc> __alloc_traits; + +public: + typedef _LIBCPP_NODEBUG typename __alloc_traits::pointer pointer; + typedef _LIBCPP_NODEBUG typename __alloc_traits::size_type size_type; + +private: + _Alloc& __alloc_; + size_type __s_; + +public: + _LIBCPP_HIDE_FROM_ABI __allocator_destructor(_Alloc& __a, size_type __s) _NOEXCEPT : __alloc_(__a), __s_(__s) {} + _LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT { __alloc_traits::deallocate(__alloc_, __p, __s_); } +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MEMORY_ALLOCATOR_DESTRUCTOR_H diff --git a/libcxx/include/__cxx03/__memory/allocator_traits.h b/libcxx/include/__cxx03/__memory/allocator_traits.h new file mode 100644 index 0000000000000000000000000000000000000000..c5fcc89327b8f7d11df6ac95e0915cd2f78e8b00 --- /dev/null +++ b/libcxx/include/__cxx03/__memory/allocator_traits.h @@ -0,0 +1,424 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MEMORY_ALLOCATOR_TRAITS_H +#define _LIBCPP___MEMORY_ALLOCATOR_TRAITS_H + +#include <__config> +#include <__memory/construct_at.h> +#include <__memory/pointer_traits.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_constructible.h> +#include <__type_traits/is_empty.h> +#include <__type_traits/is_same.h> +#include <__type_traits/make_unsigned.h> +#include <__type_traits/remove_reference.h> +#include <__type_traits/void_t.h> +#include <__utility/declval.h> +#include <__utility/forward.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#define _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(NAME, PROPERTY) \ + template \ + struct NAME : false_type {}; \ + template \ + struct NAME<_Tp, __void_t > : true_type {} + +// __pointer +template , + bool = __has_pointer<_RawAlloc>::value> +struct __pointer { + using type _LIBCPP_NODEBUG = typename _RawAlloc::pointer; +}; +template +struct __pointer<_Tp, _Alloc, _RawAlloc, false> { + using type _LIBCPP_NODEBUG = _Tp*; +}; + +// __const_pointer +_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_const_pointer, const_pointer); +template ::value> +struct __const_pointer { + using type _LIBCPP_NODEBUG = typename _Alloc::const_pointer; +}; +template +struct __const_pointer<_Tp, _Ptr, _Alloc, false> { +#ifdef _LIBCPP_CXX03_LANG + using type = typename pointer_traits<_Ptr>::template rebind::other; +#else + using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind; +#endif +}; + +// __void_pointer +_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_void_pointer, void_pointer); +template ::value> +struct __void_pointer { + using type _LIBCPP_NODEBUG = typename _Alloc::void_pointer; +}; +template +struct __void_pointer<_Ptr, _Alloc, false> { +#ifdef _LIBCPP_CXX03_LANG + using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind::other; +#else + using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind; +#endif +}; + +// __const_void_pointer +_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_const_void_pointer, const_void_pointer); +template ::value> +struct __const_void_pointer { + using type _LIBCPP_NODEBUG = typename _Alloc::const_void_pointer; +}; +template +struct __const_void_pointer<_Ptr, _Alloc, false> { +#ifdef _LIBCPP_CXX03_LANG + using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind::other; +#else + using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::template rebind; +#endif +}; + +// __size_type +_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_size_type, size_type); +template ::value> +struct __size_type : make_unsigned<_DiffType> {}; +template +struct __size_type<_Alloc, _DiffType, true> { + using type _LIBCPP_NODEBUG = typename _Alloc::size_type; +}; + +// __alloc_traits_difference_type +_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_alloc_traits_difference_type, difference_type); +template ::value> +struct __alloc_traits_difference_type { + using type _LIBCPP_NODEBUG = typename pointer_traits<_Ptr>::difference_type; +}; +template +struct __alloc_traits_difference_type<_Alloc, _Ptr, true> { + using type _LIBCPP_NODEBUG = typename _Alloc::difference_type; +}; + +// __propagate_on_container_copy_assignment +_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_copy_assignment, propagate_on_container_copy_assignment); +template ::value> +struct __propagate_on_container_copy_assignment : false_type {}; +template +struct __propagate_on_container_copy_assignment<_Alloc, true> { + using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_copy_assignment; +}; + +// __propagate_on_container_move_assignment +_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_move_assignment, propagate_on_container_move_assignment); +template ::value> +struct __propagate_on_container_move_assignment : false_type {}; +template +struct __propagate_on_container_move_assignment<_Alloc, true> { + using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_move_assignment; +}; + +// __propagate_on_container_swap +_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_propagate_on_container_swap, propagate_on_container_swap); +template ::value> +struct __propagate_on_container_swap : false_type {}; +template +struct __propagate_on_container_swap<_Alloc, true> { + using type _LIBCPP_NODEBUG = typename _Alloc::propagate_on_container_swap; +}; + +// __is_always_equal +_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_is_always_equal, is_always_equal); +template ::value> +struct __is_always_equal : is_empty<_Alloc> {}; +template +struct __is_always_equal<_Alloc, true> { + using type _LIBCPP_NODEBUG = typename _Alloc::is_always_equal; +}; + +// __allocator_traits_rebind +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +template +struct __has_rebind_other : false_type {}; +template +struct __has_rebind_other<_Tp, _Up, __void_t::other> > : true_type {}; + +template ::value> +struct __allocator_traits_rebind { + static_assert(__has_rebind_other<_Tp, _Up>::value, "This allocator has to implement rebind"); + using type _LIBCPP_NODEBUG = typename _Tp::template rebind<_Up>::other; +}; +template