[flang-commits] [flang] 6811b96 - [flang] Runtime: implement INDEX intrinsic function
peter klausler via flang-commits
flang-commits at lists.llvm.org
Mon Mar 15 14:19:21 PDT 2021
Author: peter klausler
Date: 2021-03-15T14:19:13-07:00
New Revision: 6811b961000fea84b44a225162ffa6cd434e1d63
URL: https://github.com/llvm/llvm-project/commit/6811b961000fea84b44a225162ffa6cd434e1d63
DIFF: https://github.com/llvm/llvm-project/commit/6811b961000fea84b44a225162ffa6cd434e1d63.diff
LOG: [flang] Runtime: implement INDEX intrinsic function
Implement INDEX in the runtime, reusing some infrastructure
(with generalization and renaming as needed) put into place
for its cousins SCAN and VERIFY.
I did not implement full Boyer-Moore substring searching
for the forward case, but did accelerate some advancement on
mismatches.
I (re)implemented unit testing for INDEX in the new gtest
framework, combining it with the tests that have recently
been ported to gtest for SCAN and VERIFY.
Differential Revision: https://reviews.llvm.org/D98553
Added:
Modified:
flang/runtime/character.cpp
flang/runtime/character.h
flang/test/Evaluate/folding05.f90
flang/unittests/RuntimeGTest/CharacterTest.cpp
Removed:
################################################################################
diff --git a/flang/runtime/character.cpp b/flang/runtime/character.cpp
index 21a8bb8d99b1f..8c9dfec390d6d 100644
--- a/flang/runtime/character.cpp
+++ b/flang/runtime/character.cpp
@@ -235,11 +235,87 @@ static void LenTrimKind(Descriptor &result, const Descriptor &string, int kind,
}
}
+// Utility for dealing with elemental LOGICAL arguments
+static bool IsLogicalElementTrue(
+ const Descriptor &logical, const SubscriptValue at[]) {
+ // A LOGICAL value is false if and only if all of its bytes are zero.
+ const char *p{logical.Element<char>(at)};
+ for (std::size_t j{logical.ElementBytes()}; j-- > 0; ++p) {
+ if (*p) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// INDEX implementation
+template <typename CHAR>
+inline std::size_t Index(const CHAR *x, std::size_t xLen, const CHAR *want,
+ std::size_t wantLen, bool back) {
+ if (xLen < wantLen) {
+ return 0;
+ }
+ if (xLen == 0) {
+ return 1; // wantLen is also 0, so trivial match
+ }
+ if (back) {
+ // If wantLen==0, returns xLen + 1 per standard (and all other compilers)
+ std::size_t at{xLen - wantLen + 1};
+ for (; at > 0; --at) {
+ std::size_t j{1};
+ for (; j <= wantLen; ++j) {
+ if (x[at + j - 2] != want[j - 1]) {
+ break;
+ }
+ }
+ if (j > wantLen) {
+ return at;
+ }
+ }
+ return 0;
+ }
+ // Non-trivial forward substring search: use a simplified form of
+ // Boyer-Moore substring searching.
+ for (std::size_t at{1}; at + wantLen - 1 <= xLen;) {
+ // Compare x(at:at+wantLen-1) with want(1:wantLen).
+ // The comparison proceeds from the ends of the substrings forward
+ // so that we can skip ahead by multiple positions on a miss.
+ std::size_t j{wantLen};
+ CHAR ch;
+ for (; j > 0; --j) {
+ ch = x[at + j - 2];
+ if (ch != want[j - 1]) {
+ break;
+ }
+ }
+ if (j == 0) {
+ return at; // found a match
+ }
+ // Suppose we have at==2:
+ // "THAT FORTRAN THAT I RAN" <- the string (x) in which we search
+ // "THAT I RAN" <- the string (want) for which we search
+ // ^------------------ j==7, ch=='T'
+ // We can shift ahead 3 positions to at==5 to align the 'T's:
+ // "THAT FORTRAN THAT I RAN"
+ // "THAT I RAN"
+ std::size_t shift{1};
+ for (; shift < j; ++shift) {
+ if (want[j - shift - 1] == ch) {
+ break;
+ }
+ }
+ at += shift;
+ }
+ return 0;
+}
+
// SCAN and VERIFY implementation help. These intrinsic functions
// do pretty much the same thing, so they're templatized with a
// distinguishing flag.
-template <typename CHAR, bool IS_VERIFY = false>
+enum class CharFunc { Index, Scan, Verify };
+
+template <typename CHAR, CharFunc FUNC>
inline std::size_t ScanVerify(const CHAR *x, std::size_t xLen, const CHAR *set,
std::size_t setLen, bool back) {
std::size_t at{back ? xLen : 1};
@@ -254,7 +330,7 @@ inline std::size_t ScanVerify(const CHAR *x, std::size_t xLen, const CHAR *set,
break;
}
}
- if (inSet != IS_VERIFY) {
+ if (inSet != (FUNC == CharFunc::Verify)) {
return at;
}
}
@@ -285,35 +361,25 @@ inline std::size_t ScanVerify(const char *x, std::size_t xLen, const char *set,
return 0;
}
-static bool IsLogicalElementTrue(
- const Descriptor &logical, const SubscriptValue at[]) {
- // A LOGICAL value is false if and only if all of its bytes are zero.
- const char *p{logical.Element<char>(at)};
- for (std::size_t j{logical.ElementBytes()}; j-- > 0; ++p) {
- if (*p) {
- return true;
- }
- }
- return false;
-}
-
-template <typename INT, typename CHAR, bool IS_VERIFY = false>
-static void ScanVerify(Descriptor &result, const Descriptor &string,
- const Descriptor &set, const Descriptor *back,
+template <typename INT, typename CHAR, CharFunc FUNC>
+static void GeneralCharFunc(Descriptor &result, const Descriptor &string,
+ const Descriptor &arg, const Descriptor *back,
const Terminator &terminator) {
int rank{string.rank() ? string.rank()
- : set.rank() ? set.rank() : back ? back->rank() : 0};
- SubscriptValue lb[maxRank], ub[maxRank], stringAt[maxRank], setAt[maxRank],
+ : arg.rank() ? arg.rank()
+ : back ? back->rank()
+ : 0};
+ SubscriptValue lb[maxRank], ub[maxRank], stringAt[maxRank], argAt[maxRank],
backAt[maxRank];
SubscriptValue elements{1};
for (int j{0}; j < rank; ++j) {
lb[j] = 1;
- ub[j] = string.rank()
- ? string.GetDimension(j).Extent()
- : set.rank() ? set.GetDimension(j).Extent()
- : back ? back->GetDimension(j).Extent() : 1;
+ ub[j] = string.rank() ? string.GetDimension(j).Extent()
+ : arg.rank() ? arg.GetDimension(j).Extent()
+ : back ? back->GetDimension(j).Extent()
+ : 1;
elements *= ub[j];
- stringAt[j] = setAt[j] = backAt[j] = 1;
+ stringAt[j] = argAt[j] = backAt[j] = 1;
}
result.Establish(TypeCategory::Integer, sizeof(INT), nullptr, rank, ub,
CFI_attribute_allocatable);
@@ -321,44 +387,59 @@ static void ScanVerify(Descriptor &result, const Descriptor &string,
terminator.Crash("SCAN/VERIFY: could not allocate storage for result");
}
std::size_t stringElementChars{string.ElementBytes() >> shift<CHAR>};
- std::size_t setElementChars{set.ElementBytes() >> shift<CHAR>};
+ std::size_t argElementChars{arg.ElementBytes() >> shift<CHAR>};
for (SubscriptValue resultAt{0}; elements-- > 0; resultAt += sizeof(INT),
- string.IncrementSubscripts(stringAt), set.IncrementSubscripts(setAt),
+ string.IncrementSubscripts(stringAt), arg.IncrementSubscripts(argAt),
back && back->IncrementSubscripts(backAt)) {
- *result.OffsetElement<INT>(resultAt) =
- ScanVerify<CHAR, IS_VERIFY>(string.Element<CHAR>(stringAt),
- stringElementChars, set.Element<CHAR>(setAt), setElementChars,
- back && IsLogicalElementTrue(*back, backAt));
+ if constexpr (FUNC == CharFunc::Index) {
+ *result.OffsetElement<INT>(resultAt) =
+ Index<CHAR>(string.Element<CHAR>(stringAt), stringElementChars,
+ arg.Element<CHAR>(argAt), argElementChars,
+ back && IsLogicalElementTrue(*back, backAt));
+ } else if constexpr (FUNC == CharFunc::Scan) {
+ *result.OffsetElement<INT>(resultAt) =
+ ScanVerify<CHAR, CharFunc::Scan>(string.Element<CHAR>(stringAt),
+ stringElementChars, arg.Element<CHAR>(argAt), argElementChars,
+ back && IsLogicalElementTrue(*back, backAt));
+ } else if constexpr (FUNC == CharFunc::Verify) {
+ *result.OffsetElement<INT>(resultAt) =
+ ScanVerify<CHAR, CharFunc::Verify>(string.Element<CHAR>(stringAt),
+ stringElementChars, arg.Element<CHAR>(argAt), argElementChars,
+ back && IsLogicalElementTrue(*back, backAt));
+ } else {
+ static_assert(FUNC == CharFunc::Index || FUNC == CharFunc::Scan ||
+ FUNC == CharFunc::Verify);
+ }
}
}
-template <typename CHAR, bool IS_VERIFY = false>
-static void ScanVerifyKind(Descriptor &result, const Descriptor &string,
- const Descriptor &set, const Descriptor *back, int kind,
+template <typename CHAR, CharFunc FUNC>
+static void GeneralCharFuncKind(Descriptor &result, const Descriptor &string,
+ const Descriptor &arg, const Descriptor *back, int kind,
const Terminator &terminator) {
switch (kind) {
case 1:
- ScanVerify<std::int8_t, CHAR, IS_VERIFY>(
- result, string, set, back, terminator);
+ GeneralCharFunc<std::int8_t, CHAR, FUNC>(
+ result, string, arg, back, terminator);
break;
case 2:
- ScanVerify<std::int16_t, CHAR, IS_VERIFY>(
- result, string, set, back, terminator);
+ GeneralCharFunc<std::int16_t, CHAR, FUNC>(
+ result, string, arg, back, terminator);
break;
case 4:
- ScanVerify<std::int32_t, CHAR, IS_VERIFY>(
- result, string, set, back, terminator);
+ GeneralCharFunc<std::int32_t, CHAR, FUNC>(
+ result, string, arg, back, terminator);
break;
case 8:
- ScanVerify<std::int64_t, CHAR, IS_VERIFY>(
- result, string, set, back, terminator);
+ GeneralCharFunc<std::int64_t, CHAR, FUNC>(
+ result, string, arg, back, terminator);
break;
case 16:
- ScanVerify<common::uint128_t, CHAR, IS_VERIFY>(
- result, string, set, back, terminator);
+ GeneralCharFunc<common::uint128_t, CHAR, FUNC>(
+ result, string, arg, back, terminator);
break;
default:
- terminator.Crash("SCAN/VERIFY: bad KIND=%d", kind);
+ terminator.Crash("INDEX/SCAN/VERIFY: bad KIND=%d", kind);
}
}
@@ -750,6 +831,42 @@ void RTNAME(AdjustR)(Descriptor &result, const Descriptor &string,
AdjustLR<true>(result, string, sourceFile, sourceLine);
}
+std::size_t RTNAME(Index1)(const char *x, std::size_t xLen, const char *set,
+ std::size_t setLen, bool back) {
+ return Index<char>(x, xLen, set, setLen, back);
+}
+std::size_t RTNAME(Index2)(const char16_t *x, std::size_t xLen,
+ const char16_t *set, std::size_t setLen, bool back) {
+ return Index<char16_t>(x, xLen, set, setLen, back);
+}
+std::size_t RTNAME(Index4)(const char32_t *x, std::size_t xLen,
+ const char32_t *set, std::size_t setLen, bool back) {
+ return Index<char32_t>(x, xLen, set, setLen, back);
+}
+
+void RTNAME(Index)(Descriptor &result, const Descriptor &string,
+ const Descriptor &substring, const Descriptor *back, int kind,
+ const char *sourceFile, int sourceLine) {
+ Terminator terminator{sourceFile, sourceLine};
+ switch (string.raw().type) {
+ case CFI_type_char:
+ GeneralCharFuncKind<char, CharFunc::Index>(
+ result, string, substring, back, kind, terminator);
+ break;
+ case CFI_type_char16_t:
+ GeneralCharFuncKind<char16_t, CharFunc::Index>(
+ result, string, substring, back, kind, terminator);
+ break;
+ case CFI_type_char32_t:
+ GeneralCharFuncKind<char32_t, CharFunc::Index>(
+ result, string, substring, back, kind, terminator);
+ break;
+ default:
+ terminator.Crash(
+ "INDEX: bad string type code %d", static_cast<int>(string.raw().type));
+ }
+}
+
std::size_t RTNAME(LenTrim1)(const char *x, std::size_t chars) {
return LenTrim(x, chars);
}
@@ -781,15 +898,15 @@ void RTNAME(LenTrim)(Descriptor &result, const Descriptor &string, int kind,
std::size_t RTNAME(Scan1)(const char *x, std::size_t xLen, const char *set,
std::size_t setLen, bool back) {
- return ScanVerify<char, false>(x, xLen, set, setLen, back);
+ return ScanVerify<char, CharFunc::Scan>(x, xLen, set, setLen, back);
}
std::size_t RTNAME(Scan2)(const char16_t *x, std::size_t xLen,
const char16_t *set, std::size_t setLen, bool back) {
- return ScanVerify<char16_t, false>(x, xLen, set, setLen, back);
+ return ScanVerify<char16_t, CharFunc::Scan>(x, xLen, set, setLen, back);
}
std::size_t RTNAME(Scan4)(const char32_t *x, std::size_t xLen,
const char32_t *set, std::size_t setLen, bool back) {
- return ScanVerify<char32_t, false>(x, xLen, set, setLen, back);
+ return ScanVerify<char32_t, CharFunc::Scan>(x, xLen, set, setLen, back);
}
void RTNAME(Scan)(Descriptor &result, const Descriptor &string,
@@ -798,14 +915,15 @@ void RTNAME(Scan)(Descriptor &result, const Descriptor &string,
Terminator terminator{sourceFile, sourceLine};
switch (string.raw().type) {
case CFI_type_char:
- ScanVerifyKind<char, false>(result, string, set, back, kind, terminator);
+ GeneralCharFuncKind<char, CharFunc::Scan>(
+ result, string, set, back, kind, terminator);
break;
case CFI_type_char16_t:
- ScanVerifyKind<char16_t, false>(
+ GeneralCharFuncKind<char16_t, CharFunc::Scan>(
result, string, set, back, kind, terminator);
break;
case CFI_type_char32_t:
- ScanVerifyKind<char32_t, false>(
+ GeneralCharFuncKind<char32_t, CharFunc::Scan>(
result, string, set, back, kind, terminator);
break;
default:
@@ -860,15 +978,15 @@ void RTNAME(Trim)(Descriptor &result, const Descriptor &string,
std::size_t RTNAME(Verify1)(const char *x, std::size_t xLen, const char *set,
std::size_t setLen, bool back) {
- return ScanVerify<char, true>(x, xLen, set, setLen, back);
+ return ScanVerify<char, CharFunc::Verify>(x, xLen, set, setLen, back);
}
std::size_t RTNAME(Verify2)(const char16_t *x, std::size_t xLen,
const char16_t *set, std::size_t setLen, bool back) {
- return ScanVerify<char16_t, true>(x, xLen, set, setLen, back);
+ return ScanVerify<char16_t, CharFunc::Verify>(x, xLen, set, setLen, back);
}
std::size_t RTNAME(Verify4)(const char32_t *x, std::size_t xLen,
const char32_t *set, std::size_t setLen, bool back) {
- return ScanVerify<char32_t, true>(x, xLen, set, setLen, back);
+ return ScanVerify<char32_t, CharFunc::Verify>(x, xLen, set, setLen, back);
}
void RTNAME(Verify)(Descriptor &result, const Descriptor &string,
@@ -877,13 +995,16 @@ void RTNAME(Verify)(Descriptor &result, const Descriptor &string,
Terminator terminator{sourceFile, sourceLine};
switch (string.raw().type) {
case CFI_type_char:
- ScanVerifyKind<char, true>(result, string, set, back, kind, terminator);
+ GeneralCharFuncKind<char, CharFunc::Verify>(
+ result, string, set, back, kind, terminator);
break;
case CFI_type_char16_t:
- ScanVerifyKind<char16_t, true>(result, string, set, back, kind, terminator);
+ GeneralCharFuncKind<char16_t, CharFunc::Verify>(
+ result, string, set, back, kind, terminator);
break;
case CFI_type_char32_t:
- ScanVerifyKind<char32_t, true>(result, string, set, back, kind, terminator);
+ GeneralCharFuncKind<char32_t, CharFunc::Verify>(
+ result, string, set, back, kind, terminator);
break;
default:
terminator.Crash(
diff --git a/flang/runtime/character.h b/flang/runtime/character.h
index 8879f3e25c37b..6b813bfa34dab 100644
--- a/flang/runtime/character.h
+++ b/flang/runtime/character.h
@@ -108,6 +108,16 @@ void RTNAME(CharacterMinLoc)(Descriptor &result, const Descriptor &x,
int dim = 0, const Descriptor *mask = nullptr, int kind = sizeof(int),
bool back = false, const char *sourceFile = nullptr, int sourceLine = 0);
+std::size_t RTNAME(Index1)(const char *, std::size_t, const char *substring,
+ std::size_t, bool back = false);
+std::size_t RTNAME(Index2)(const char16_t *, std::size_t,
+ const char16_t *substring, std::size_t, bool back = false);
+std::size_t RTNAME(Index4)(const char32_t *, std::size_t,
+ const char32_t *substring, std::size_t, bool back = false);
+void RTNAME(Index)(Descriptor &result, const Descriptor &string,
+ const Descriptor &substring, const Descriptor *back /*can be null*/,
+ int kind, const char *sourceFile = nullptr, int sourceLine = 0);
+
std::size_t RTNAME(Scan1)(
const char *, std::size_t, const char *set, std::size_t, bool back = false);
std::size_t RTNAME(Scan2)(const char16_t *, std::size_t, const char16_t *set,
diff --git a/flang/test/Evaluate/folding05.f90 b/flang/test/Evaluate/folding05.f90
index aeccee04b5cbd..f68ce124fa8f8 100644
Binary files a/flang/test/Evaluate/folding05.f90 and b/flang/test/Evaluate/folding05.f90
diff er
diff --git a/flang/unittests/RuntimeGTest/CharacterTest.cpp b/flang/unittests/RuntimeGTest/CharacterTest.cpp
index a025429035f88..6afba32e33e35 100644
--- a/flang/unittests/RuntimeGTest/CharacterTest.cpp
+++ b/flang/unittests/RuntimeGTest/CharacterTest.cpp
@@ -6,6 +6,9 @@
//
//===----------------------------------------------------------------------===//
+// Basic sanity tests of CHARACTER API; exhaustive testing will be done
+// in Fortran.
+
#include "../../runtime/character.h"
#include "gtest/gtest.h"
#include <cstring>
@@ -136,147 +139,86 @@ TYPED_TEST(CharacterComparisonTests, CompareCharacters) {
}
}
-//------------------------------------------------------------------------------
-/// Tests and infrastructure for Scan functions
-//------------------------------------------------------------------------------
+// Test search functions INDEX(), SCAN(), and VERIFY()
template <typename CHAR>
-using ScanFuncTy = std::function<int(
+using SearchFunction = std::function<std::size_t(
const CHAR *, std::size_t, const CHAR *, std::size_t, bool)>;
-
-using ScanFuncsTy =
- std::tuple<ScanFuncTy<char>, ScanFuncTy<char16_t>, ScanFuncTy<char32_t>>;
-
-// These functions are the systems under test in CharacterScanTests test cases.
-static ScanFuncsTy scanFuncs{
- RTNAME(Scan1),
- RTNAME(Scan2),
- RTNAME(Scan4),
+template <template <typename> class FUNC>
+using CharTypedFunctions =
+ std::tuple<FUNC<char>, FUNC<char16_t>, FUNC<char32_t>>;
+using SearchFunctions = CharTypedFunctions<SearchFunction>;
+struct SearchTestCase {
+ const char *x, *y;
+ bool back;
+ std::size_t expect;
};
-// Types of _values_ over which tests are parameterized
template <typename CHAR>
-using ScanParametersTy =
- std::vector<std::tuple<const CHAR *, const CHAR *, bool, int>>;
-
-using ScanTestCasesTy = std::tuple<ScanParametersTy<char>,
- ScanParametersTy<char16_t>, ScanParametersTy<char32_t>>;
-
-static ScanTestCasesTy scanTestCases{
- {
- std::make_tuple("abc", "abc", false, 1),
- std::make_tuple("abc", "abc", true, 3),
- std::make_tuple("abc", "cde", false, 3),
- std::make_tuple("abc", "cde", true, 3),
- std::make_tuple("abc", "x", false, 0),
- std::make_tuple("", "x", false, 0),
- },
- {
- std::make_tuple(u"abc", u"abc", false, 1),
- std::make_tuple(u"abc", u"abc", true, 3),
- std::make_tuple(u"abc", u"cde", false, 3),
- std::make_tuple(u"abc", u"cde", true, 3),
- std::make_tuple(u"abc", u"x", false, 0),
- std::make_tuple(u"", u"x", false, 0),
- },
- {
- std::make_tuple(U"abc", U"abc", false, 1),
- std::make_tuple(U"abc", U"abc", true, 3),
- std::make_tuple(U"abc", U"cde", false, 3),
- std::make_tuple(U"abc", U"cde", true, 3),
- std::make_tuple(U"abc", U"x", false, 0),
- std::make_tuple(U"", U"x", false, 0),
- }};
-
-template <typename CHAR> struct CharacterScanTests : public ::testing::Test {
- CharacterScanTests()
- : parameters{std::get<ScanParametersTy<CHAR>>(scanTestCases)},
- characterScanFunc{std::get<ScanFuncTy<CHAR>>(scanFuncs)} {}
- ScanParametersTy<CHAR> parameters;
- ScanFuncTy<CHAR> characterScanFunc;
-};
-
-// Type-parameterized over the same character types as CharacterComparisonTests
-TYPED_TEST_CASE(CharacterScanTests, CharacterTypes);
-
-TYPED_TEST(CharacterScanTests, ScanCharacters) {
- for (auto const &[str, set, back, expect] : this->parameters) {
- auto res{
- this->characterScanFunc(str, std::char_traits<TypeParam>::length(str),
- set, std::char_traits<TypeParam>::length(set), back)};
- ASSERT_EQ(res, expect) << "Scan(" << str << ',' << set << ",back=" << back
- << "): got " << res << ", should be " << expect;
+void RunSearchTests(const char *which,
+ const std::vector<SearchTestCase> &testCases,
+ const SearchFunction<CHAR> &function) {
+ for (const auto &t : testCases) {
+ // Convert default character to desired kind
+ std::size_t xLen{std::strlen(t.x)}, yLen{std::strlen(t.y)};
+ std::basic_string<CHAR> x{t.x, t.x + xLen};
+ std::basic_string<CHAR> y{t.y, t.y + yLen};
+ auto got{function(x.data(), xLen, y.data(), yLen, t.back)};
+ ASSERT_EQ(got, t.expect)
+ << which << "('" << t.x << "','" << t.y << "',back=" << t.back
+ << ") for CHARACTER(kind=" << sizeof(CHAR) << "): got " << got
+ << ", expected " << t.expect;
}
}
-//------------------------------------------------------------------------------
-/// Tests and infrastructure for Verify functions
-//------------------------------------------------------------------------------
-template <typename CHAR>
-using VerifyFuncTy = std::function<int(
- const CHAR *, std::size_t, const CHAR *, std::size_t, bool)>;
-
-using VerifyFuncsTy = std::tuple<VerifyFuncTy<char>, VerifyFuncTy<char16_t>,
- VerifyFuncTy<char32_t>>;
-
-// These functions are the systems under test in CharacterVerifyTests test cases
-static VerifyFuncsTy verifyFuncs{
- RTNAME(Verify1),
- RTNAME(Verify2),
- RTNAME(Verify4),
-};
-
-// Types of _values_ over which tests are parameterized
-template <typename CHAR>
-using VerifyParametersTy =
- std::vector<std::tuple<const CHAR *, const CHAR *, bool, int>>;
-
-using VerifyTestCasesTy = std::tuple<VerifyParametersTy<char>,
- VerifyParametersTy<char16_t>, VerifyParametersTy<char32_t>>;
-
-static VerifyTestCasesTy verifyTestCases{
- {
- std::make_tuple("abc", "abc", false, 0),
- std::make_tuple("abc", "abc", true, 0),
- std::make_tuple("abc", "cde", false, 1),
- std::make_tuple("abc", "cde", true, 2),
- std::make_tuple("abc", "x", false, 1),
- std::make_tuple("", "x", false, 0),
- },
- {
- std::make_tuple(u"abc", u"abc", false, 0),
- std::make_tuple(u"abc", u"abc", true, 0),
- std::make_tuple(u"abc", u"cde", false, 1),
- std::make_tuple(u"abc", u"cde", true, 2),
- std::make_tuple(u"abc", u"x", false, 1),
- std::make_tuple(u"", u"x", false, 0),
- },
- {
- std::make_tuple(U"abc", U"abc", false, 0),
- std::make_tuple(U"abc", U"abc", true, 0),
- std::make_tuple(U"abc", U"cde", false, 1),
- std::make_tuple(U"abc", U"cde", true, 2),
- std::make_tuple(U"abc", U"x", false, 1),
- std::make_tuple(U"", U"x", false, 0),
- }};
-
-template <typename CHAR> struct CharacterVerifyTests : public ::testing::Test {
- CharacterVerifyTests()
- : parameters{std::get<VerifyParametersTy<CHAR>>(verifyTestCases)},
- characterVerifyFunc{std::get<VerifyFuncTy<CHAR>>(verifyFuncs)} {}
- VerifyParametersTy<CHAR> parameters;
- VerifyFuncTy<CHAR> characterVerifyFunc;
-};
+template <typename CHAR> struct SearchTests : public ::testing::Test {};
+TYPED_TEST_CASE(SearchTests, CharacterTypes);
+
+TYPED_TEST(SearchTests, IndexTests) {
+ static SearchFunctions functions{
+ RTNAME(Index1), RTNAME(Index2), RTNAME(Index4)};
+ static std::vector<SearchTestCase> tests{
+ {"", "", false, 1},
+ {"", "", true, 1},
+ {"a", "", false, 1},
+ {"a", "", true, 2},
+ {"", "a", false, 0},
+ {"", "a", true, 0},
+ {"aa", "a", false, 1},
+ {"aa", "a", true, 2},
+ {"Fortran that I ran", "that I ran", false, 9},
+ {"Fortran that I ran", "that I ran", true, 9},
+ {"Fortran that you ran", "that I ran", false, 0},
+ {"Fortran that you ran", "that I ran", true, 0},
+ };
+ RunSearchTests(
+ "INDEX", tests, std::get<SearchFunction<TypeParam>>(functions));
+}
-// Type-parameterized over the same character types as CharacterComparisonTests
-TYPED_TEST_CASE(CharacterVerifyTests, CharacterTypes);
+TYPED_TEST(SearchTests, ScanTests) {
+ static SearchFunctions functions{RTNAME(Scan1), RTNAME(Scan2), RTNAME(Scan4)};
+ static std::vector<SearchTestCase> tests{
+ {"abc", "abc", false, 1},
+ {"abc", "abc", true, 3},
+ {"abc", "cde", false, 3},
+ {"abc", "cde", true, 3},
+ {"abc", "x", false, 0},
+ {"", "x", false, 0},
+ };
+ RunSearchTests("SCAN", tests, std::get<SearchFunction<TypeParam>>(functions));
+}
-TYPED_TEST(CharacterVerifyTests, VerifyCharacters) {
- for (auto const &[str, set, back, expect] : this->parameters) {
- auto res{
- this->characterVerifyFunc(str, std::char_traits<TypeParam>::length(str),
- set, std::char_traits<TypeParam>::length(set), back)};
- ASSERT_EQ(res, expect) << "Verify(" << str << ',' << set << ",back=" << back
- << "): got " << res << ", should be " << expect;
- }
+TYPED_TEST(SearchTests, VerifyTests) {
+ static SearchFunctions functions{
+ RTNAME(Verify1), RTNAME(Verify2), RTNAME(Verify4)};
+ static std::vector<SearchTestCase> tests{
+ {"abc", "abc", false, 0},
+ {"abc", "abc", true, 0},
+ {"abc", "cde", false, 1},
+ {"abc", "cde", true, 2},
+ {"abc", "x", false, 1},
+ {"", "x", false, 0},
+ };
+ RunSearchTests(
+ "VERIFY", tests, std::get<SearchFunction<TypeParam>>(functions));
}
More information about the flang-commits
mailing list