diff options
Diffstat (limited to 'tests')
24 files changed, 3403 insertions, 7 deletions
diff --git a/tests/auto/gestures/tst_gestures.cpp b/tests/auto/gestures/tst_gestures.cpp index a968520..ddc3939 100644 --- a/tests/auto/gestures/tst_gestures.cpp +++ b/tests/auto/gestures/tst_gestures.cpp @@ -395,7 +395,12 @@ void tst_Gestures::customGesture() { GestureWidget widget; widget.grabGesture(CustomGesture::GestureType, Qt::DontStartGestureOnChildren); + widget.show(); + QTest::qWaitForWindowShown(&widget); + CustomEvent event; + event.hotSpot = widget.mapToGlobal(QPoint(5,5)); + event.hasHotSpot = true; sendCustomGesture(&event, &widget); static const int TotalGestureEventsCount = CustomGesture::SerialFinishedThreshold - CustomGesture::SerialStartedThreshold + 1; diff --git a/tests/auto/headers/tst_headers.cpp b/tests/auto/headers/tst_headers.cpp index 06c70f9..7ccf058 100644 --- a/tests/auto/headers/tst_headers.cpp +++ b/tests/auto/headers/tst_headers.cpp @@ -213,7 +213,8 @@ void tst_Headers::licenseCheck() return; if (content.first().contains("generated")) { - content.takeFirst(); + // don't scan generated files + return; } if (sourceFile.endsWith("/tests/auto/linguist/lupdate/testdata/good/merge_ordering/foo.cpp") diff --git a/tests/auto/linguist/lupdate/testdata/good/parsejs/main.js b/tests/auto/linguist/lupdate/testdata/good/parsejs/main.js new file mode 100644 index 0000000..9f61cea --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsejs/main.js @@ -0,0 +1,91 @@ +qsTr("One"); +qsTranslate("FooContext", "Two"); + +var greeting_strings = [ + QT_TR_NOOP("Hello"), + QT_TRANSLATE_NOOP("FooContext", "Goodbye") +]; + +qsTr("One", "not the same one"); + +//: My first comment. +qsTr("See comment"); + +//: My second comment. +qsTranslate("BarContext", "See other comment"); + +//: My third comment +//: spans two lines. +qsTr("The comment explains it all"); + +//: My fourth comment +//: spans a whopping +//: three lines. +qsTranslate("BazContext", "It should be clear by now"); + +/*: C-style comment. */ +qsTr("I love C++"); + +/*: Another C-style comment. */ +qsTranslate("FooContext", "I really love C++"); + +/*: C-style comment, followed by */ +/*: another one. */ +qsTr("Qt is the best"); + +/*: Another C-style comment, followed by */ +/*: yet another one. */ +qsTranslate("BarContext", "Qt is the very best"); + +// This comment doesn't have any effect. +qsTr("The comment had no effect"); + +// This comment doesn't have any effect either. +qsTranslate("BazContext", "The comment had no effect, really"); + +/* This C-style comment doesn't have any effect. */ +qsTr("No comment to your comment"); + +/* This C-style comment doesn't have any effect either. */ +qsTranslate("FooContext", "I refuse to comment on that"); + +//= id_foo +qsTr("This string has an identifier"); + +//= id_bar +qsTranslate("BarContext", "This string also has an identifier"); + +//~ loc-blank False +qsTr("This string has meta-data"); + +//~ loc-layout_id foo_dialog +qsTranslate("BazContext", "This string also has meta-data"); + +// This comment is to be ignored. +//: This is a comment for the translator. +//= id_baz +//~ foo 123 +//~ magic-stuff This means something special. +qsTr("This string has a lot of information"); + +// This comment is also to be ignored. +//: This is another comment for the translator. +//= id_babar +//~ foo-bar Important stuff +//~ needle-in-haystack Found +//~ overflow True +qsTranslate("FooContext", "This string has even more information"); + +qsTr("This string has disambiguation", "Disambiguation"); + +qsTranslate("BarContext", "This string also has disambiguation", "Another disambiguation"); + +qsTr("This string contains plurals", "", 10); + +qsTrId("qtn_foo_bar"); + +var more_greeting_strings = [ QT_TRID_NOOP("qtn_needle"), QT_TRID_NOOP("qtn_haystack") ]; + +//: qsTrId() with comment, meta-data and plurals. +//~ well-tested True +qsTrId("qtn_bar_baz", 10); diff --git a/tests/auto/linguist/lupdate/testdata/good/parsejs/project.pro b/tests/auto/linguist/lupdate/testdata/good/parsejs/project.pro new file mode 100644 index 0000000..d549039 --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsejs/project.pro @@ -0,0 +1,3 @@ +SOURCES += main.js + +TRANSLATIONS = project.ts diff --git a/tests/auto/linguist/lupdate/testdata/good/parsejs/project.ts.result b/tests/auto/linguist/lupdate/testdata/good/parsejs/project.ts.result new file mode 100644 index 0000000..d03c713 --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsejs/project.ts.result @@ -0,0 +1,195 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0"> +<context> + <name></name> + <message id="qtn_foo_bar"> + <location filename="main.js" line="85"/> + <source></source> + <translation type="unfinished"></translation> + </message> + <message id="qtn_needle"> + <location filename="main.js" line="87"/> + <source></source> + <translation type="unfinished"></translation> + </message> + <message id="qtn_haystack"> + <location filename="main.js" line="87"/> + <source></source> + <translation type="unfinished"></translation> + </message> + <message id="qtn_bar_baz" numerus="yes"> + <location filename="main.js" line="91"/> + <source></source> + <extracomment>qsTrId() with comment, meta-data and plurals.</extracomment> + <translation type="unfinished"> + <numerusform></numerusform> + </translation> + <extra-well-tested>True</extra-well-tested> + </message> +</context> +<context> + <name>BarContext</name> + <message> + <location filename="main.js" line="15"/> + <source>See other comment</source> + <extracomment>My second comment.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="38"/> + <source>Qt is the very best</source> + <extracomment>Another C-style comment, followed by yet another one.</extracomment> + <translation type="unfinished"></translation> + </message> + <message id="id_bar"> + <location filename="main.js" line="56"/> + <source>This string also has an identifier</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="81"/> + <source>This string also has disambiguation</source> + <comment>Another disambiguation</comment> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>BazContext</name> + <message> + <location filename="main.js" line="24"/> + <source>It should be clear by now</source> + <extracomment>My fourth comment spans a whopping three lines.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="44"/> + <source>The comment had no effect, really</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="62"/> + <source>This string also has meta-data</source> + <translation type="unfinished"></translation> + <extra-loc-layout_id>foo_dialog</extra-loc-layout_id> + </message> +</context> +<context> + <name>FooContext</name> + <message> + <location filename="main.js" line="2"/> + <source>Two</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="6"/> + <source>Goodbye</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="30"/> + <source>I really love C++</source> + <extracomment>Another C-style comment.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="50"/> + <source>I refuse to comment on that</source> + <translation type="unfinished"></translation> + </message> + <message id="id_babar"> + <location filename="main.js" line="77"/> + <source>This string has even more information</source> + <extracomment>This is another comment for the translator.</extracomment> + <translation type="unfinished"></translation> + <extra-needle-in-haystack>Found</extra-needle-in-haystack> + <extra-overflow>True</extra-overflow> + <extra-foo-bar>Important stuff</extra-foo-bar> + </message> +</context> +<context> + <name>main</name> + <message> + <location filename="main.js" line="1"/> + <source>One</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="5"/> + <source>Hello</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="9"/> + <source>One</source> + <comment>not the same one</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="12"/> + <source>See comment</source> + <extracomment>My first comment.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="19"/> + <source>The comment explains it all</source> + <extracomment>My third comment spans two lines.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="27"/> + <source>I love C++</source> + <extracomment>C-style comment.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="34"/> + <source>Qt is the best</source> + <extracomment>C-style comment, followed by another one.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="41"/> + <source>The comment had no effect</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="47"/> + <source>No comment to your comment</source> + <translation type="unfinished"></translation> + </message> + <message id="id_foo"> + <location filename="main.js" line="53"/> + <source>This string has an identifier</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="59"/> + <source>This string has meta-data</source> + <translation type="unfinished"></translation> + <extra-loc-blank>False</extra-loc-blank> + </message> + <message id="id_baz"> + <location filename="main.js" line="69"/> + <source>This string has a lot of information</source> + <extracomment>This is a comment for the translator.</extracomment> + <translation type="unfinished"></translation> + <extra-foo>123</extra-foo> + <extra-magic-stuff>This means something special.</extra-magic-stuff> + </message> + <message> + <location filename="main.js" line="79"/> + <source>This string has disambiguation</source> + <comment>Disambiguation</comment> + <translation type="unfinished"></translation> + </message> + <message numerus="yes"> + <location filename="main.js" line="83"/> + <source>This string contains plurals</source> + <translation type="unfinished"> + <numerusform></numerusform> + </translation> + </message> +</context> +</TS> diff --git a/tests/auto/linguist/lupdate/testdata/good/parsejs2/expectedoutput.txt b/tests/auto/linguist/lupdate/testdata/good/parsejs2/expectedoutput.txt new file mode 100644 index 0000000..d6c977f --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsejs2/expectedoutput.txt @@ -0,0 +1,29 @@ +.*/lupdate/testdata/good/parsejs2/main.js:3: qsTranslate\(\) requires at least two arguments. +.*/lupdate/testdata/good/parsejs2/main.js:4: qsTranslate\(\) requires at least two arguments. +.*/lupdate/testdata/good/parsejs2/main.js:5: qsTranslate\(\): both arguments must be literal strings. +.*/lupdate/testdata/good/parsejs2/main.js:6: qsTranslate\(\): both arguments must be literal strings. +.*/lupdate/testdata/good/parsejs2/main.js:7: qsTranslate\(\): both arguments must be literal strings. +.*/lupdate/testdata/good/parsejs2/main.js:9: QT_TRANSLATE_NOOP\(\) requires at least two arguments. +.*/lupdate/testdata/good/parsejs2/main.js:10: QT_TRANSLATE_NOOP\(\) requires at least two arguments. +.*/lupdate/testdata/good/parsejs2/main.js:11: QT_TRANSLATE_NOOP\(\): both arguments must be literal strings. +.*/lupdate/testdata/good/parsejs2/main.js:12: QT_TRANSLATE_NOOP\(\): both arguments must be literal strings. +.*/lupdate/testdata/good/parsejs2/main.js:13: QT_TRANSLATE_NOOP\(\): both arguments must be literal strings. +.*/lupdate/testdata/good/parsejs2/main.js:15: qsTr\(\) requires at least one argument. +.*/lupdate/testdata/good/parsejs2/main.js:16: qsTr\(\): text to translate must be a literal string. +.*/lupdate/testdata/good/parsejs2/main.js:18: QT_TR_NOOP\(\) requires at least one argument. +.*/lupdate/testdata/good/parsejs2/main.js:19: QT_TR_NOOP\(\): text to translate must be a literal string. +.*/lupdate/testdata/good/parsejs2/main.js:21: qsTrId\(\) requires at least one argument. +.*/lupdate/testdata/good/parsejs2/main.js:22: qsTrId\(\): identifier must be a literal string. +.*/lupdate/testdata/good/parsejs2/main.js:24: QT_TRID_NOOP\(\) requires at least one argument. +.*/lupdate/testdata/good/parsejs2/main.js:25: QT_TRID_NOOP\(\): identifier must be a literal string. +.*/lupdate/testdata/good/parsejs2/main.js:27: Unexpected character in meta string +.*/lupdate/testdata/good/parsejs2/main.js:28: Unexpected character in meta string +.*/lupdate/testdata/good/parsejs2/main.js:29: Unterminated meta string +.*/lupdate/testdata/good/parsejs2/main.js:30: Unterminated meta string +.*/lupdate/testdata/good/parsejs2/main.js:33: //% cannot be used with qsTranslate\(\). Ignoring +.*/lupdate/testdata/good/parsejs2/main.js:35: //% cannot be used with QT_TRANSLATE_NOOP\(\). Ignoring +.*/lupdate/testdata/good/parsejs2/main.js:37: //% cannot be used with qsTr\(\). Ignoring +.*/lupdate/testdata/good/parsejs2/main.js:39: //% cannot be used with QT_TR_NOOP\(\). Ignoring +.*/lupdate/testdata/good/parsejs2/main.js:42: Discarding unconsumed meta data +.*/lupdate/testdata/good/parsejs2/main.js:44: Discarding unconsumed meta data +.*/lupdate/testdata/good/parsejs2/main.js:46: Discarding unconsumed meta data diff --git a/tests/auto/linguist/lupdate/testdata/good/parsejs2/main.js b/tests/auto/linguist/lupdate/testdata/good/parsejs2/main.js new file mode 100644 index 0000000..ea02957 --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsejs2/main.js @@ -0,0 +1,56 @@ +// This script exercises lupdate errors and warnings. + +qsTranslate(); +qsTranslate(10); +qsTranslate(10, 20); +qsTranslate("10", 20); +qsTranslate(10, "20"); + +QT_TRANSLATE_NOOP(); +QT_TRANSLATE_NOOP(10); +QT_TRANSLATE_NOOP(10, 20); +QT_TRANSLATE_NOOP("10", 20); +QT_TRANSLATE_NOOP(10, "20"); + +qsTr(); +qsTr(10); + +QT_TR_NOOP(); +QT_TR_NOOP(10); + +qsTrId(); +qsTrId(10); + +QT_TRID_NOOP(); +QT_TRID_NOOP(10); + +//% This is wrong +//% "This is not wrong" This is wrong +//% "I forgot to close the meta string +//% "Being evil \ + +//% "Should cause a warning" +qsTranslate("FooContext", "Hello"); +//% "Should cause a warning" +QT_TRANSLATE_NOOP("FooContext", "World"); +//% "Should cause a warning" +qsTr("Hello"); +//% "Should cause a warning" +QT_TR_NOOP("World"); + +//: This comment will be discarded. +Math.sin(1); +//= id_foobar +Math.cos(2); +//~ underflow False +Math.tan(3); + +/* +Not tested for now, because these should perhaps not cause +translation entries to be generated at all; see QTBUG-11843. + +//= qtn_foo +qsTrId("qtn_foo"); +//= qtn_bar +QT_TRID_NOOP("qtn_bar"); +*/ diff --git a/tests/auto/linguist/lupdate/testdata/good/parsejs2/project.pro b/tests/auto/linguist/lupdate/testdata/good/parsejs2/project.pro new file mode 100644 index 0000000..d549039 --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsejs2/project.pro @@ -0,0 +1,3 @@ +SOURCES += main.js + +TRANSLATIONS = project.ts diff --git a/tests/auto/linguist/lupdate/testdata/good/parsejs2/project.ts.result b/tests/auto/linguist/lupdate/testdata/good/parsejs2/project.ts.result new file mode 100644 index 0000000..bfa1b3d --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsejs2/project.ts.result @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0"> +<context> + <name>FooContext</name> + <message> + <location filename="main.js" line="33"/> + <source>Hello</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="35"/> + <source>World</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>main</name> + <message> + <location filename="main.js" line="37"/> + <source>Hello</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="39"/> + <source>World</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/tests/auto/qmake/testdata/substitutes/test.pro b/tests/auto/qmake/testdata/substitutes/test.pro index ddad93f..26b0272 100644 --- a/tests/auto/qmake/testdata/substitutes/test.pro +++ b/tests/auto/qmake/testdata/substitutes/test.pro @@ -1 +1,5 @@ -QMAKE_SUBSTITUTES += test.in sub/test2.in +QMAKE_SUBSTITUTES += test.in sub/test2.in indirect + +indirect.input = $$PWD/test3.txt +indirect.output = $$OUT_PWD/sub/indirect_test.txt + diff --git a/tests/auto/qmake/testdata/substitutes/test3.txt b/tests/auto/qmake/testdata/substitutes/test3.txt new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/tests/auto/qmake/testdata/substitutes/test3.txt @@ -0,0 +1 @@ +hello diff --git a/tests/auto/qmake/tst_qmake.cpp b/tests/auto/qmake/tst_qmake.cpp index 060fa01..277e9f8 100644 --- a/tests/auto/qmake/tst_qmake.cpp +++ b/tests/auto/qmake/tst_qmake.cpp @@ -484,12 +484,14 @@ void tst_qmake::substitutes() QVERIFY( test_compiler.qmake( workDir, "test" )); QVERIFY( test_compiler.exists( workDir, "test", Plain, "" )); QVERIFY( test_compiler.exists( workDir, "sub/test2", Plain, "" )); + QVERIFY( test_compiler.exists( workDir, "sub/indirect_test.txt", Plain, "" )); QVERIFY( test_compiler.makeDistClean( workDir )); QString buildDir = base_path + "/testdata/substitutes_build"; QVERIFY( test_compiler.qmake( workDir, "test", buildDir )); QVERIFY( test_compiler.exists( buildDir, "test", Plain, "" )); QVERIFY( test_compiler.exists( buildDir, "sub/test2", Plain, "" )); + QVERIFY( test_compiler.exists( buildDir, "sub/indirect_test.txt", Plain, "" )); QVERIFY( test_compiler.makeDistClean( buildDir )); } diff --git a/tests/auto/qscriptengine/idtranslatable.js b/tests/auto/qscriptengine/idtranslatable.js new file mode 100644 index 0000000..554ca88 --- /dev/null +++ b/tests/auto/qscriptengine/idtranslatable.js @@ -0,0 +1,5 @@ +qsTrId("qtn_foo_bar"); + +var more_greeting_strings = [ QT_TRID_NOOP("qtn_needle"), QT_TRID_NOOP("qtn_haystack") ]; + +qsTrId("qtn_bar_baz", 10); diff --git a/tests/auto/qscriptengine/qscriptengine.qrc b/tests/auto/qscriptengine/qscriptengine.qrc index b87f985..fa55a5b 100644 --- a/tests/auto/qscriptengine/qscriptengine.qrc +++ b/tests/auto/qscriptengine/qscriptengine.qrc @@ -1,5 +1,6 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource> <file>translations/translatable_la.qm</file> + <file>translations/idtranslatable_la.qm</file> </qresource> </RCC> diff --git a/tests/auto/qscriptengine/translations/idtranslatable_la.qm b/tests/auto/qscriptengine/translations/idtranslatable_la.qm Binary files differnew file mode 100644 index 0000000..c8c0b72 --- /dev/null +++ b/tests/auto/qscriptengine/translations/idtranslatable_la.qm diff --git a/tests/auto/qscriptengine/translations/idtranslatable_la.ts b/tests/auto/qscriptengine/translations/idtranslatable_la.ts new file mode 100644 index 0000000..b6d7053 --- /dev/null +++ b/tests/auto/qscriptengine/translations/idtranslatable_la.ts @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="nb_NO"> +<context> + <name></name> + <message id="qtn_foo_bar"> + <location filename="idtranslatable.js" line="1"/> + <source></source> + <translation>First string</translation> + </message> + <message id="qtn_needle"> + <location filename="idtranslatable.js" line="3"/> + <source></source> + <translation>Second string</translation> + </message> + <message id="qtn_haystack"> + <location filename="idtranslatable.js" line="3"/> + <source></source> + <translation>Third string</translation> + </message> + <message id="qtn_bar_baz" numerus="yes"> + <location filename="idtranslatable.js" line="5"/> + <source></source> + <translation> + <numerusform>Fourth string</numerusform> + <numerusform>%n fooish bar(s) found</numerusform> + </translation> + </message> +</context> +</TS> diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp index 7a732cc..4cff043 100644 --- a/tests/auto/qscriptengine/tst_qscriptengine.cpp +++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp @@ -162,6 +162,7 @@ private slots: void translateWithInvalidArgs(); void translationContext_data(); void translationContext(); + void translateScriptIdBased(); void functionScopes(); void nativeFunctionScopes(); void evaluateProgram(); @@ -4386,6 +4387,8 @@ void tst_QScriptEngine::installTranslatorFunctions() QVERIFY(!global.property("QT_TRANSLATE_NOOP").isValid()); QVERIFY(!global.property("qsTr").isValid()); QVERIFY(!global.property("QT_TR_NOOP").isValid()); + QVERIFY(!global.property("qsTrId").isValid()); + QVERIFY(!global.property("QT_TRID_NOOP").isValid()); QVERIFY(!globalOrig.property("String").property("prototype").property("arg").isValid()); eng.installTranslatorFunctions(); @@ -4393,6 +4396,8 @@ void tst_QScriptEngine::installTranslatorFunctions() QVERIFY(global.property("QT_TRANSLATE_NOOP").isFunction()); QVERIFY(global.property("qsTr").isFunction()); QVERIFY(global.property("QT_TR_NOOP").isFunction()); + QVERIFY(global.property("qsTrId").isFunction()); + QVERIFY(global.property("QT_TRID_NOOP").isFunction()); QVERIFY(globalOrig.property("String").property("prototype").property("arg").isFunction()); if (useCustomGlobalObject) { @@ -4400,6 +4405,8 @@ void tst_QScriptEngine::installTranslatorFunctions() QVERIFY(!globalOrig.property("QT_TRANSLATE_NOOP").isValid()); QVERIFY(!globalOrig.property("qsTr").isValid()); QVERIFY(!globalOrig.property("QT_TR_NOOP").isValid()); + QVERIFY(!globalOrig.property("qsTrId").isValid()); + QVERIFY(!globalOrig.property("QT_TRID_NOOP").isValid()); } { @@ -4427,6 +4434,17 @@ void tst_QScriptEngine::installTranslatorFunctions() QVERIFY(ret.isString()); QCOMPARE(ret.toString(), QString::fromLatin1("foobar")); } + + { + QScriptValue ret = eng.evaluate("qsTrId('foo')"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("foo")); + } + { + QScriptValue ret = eng.evaluate("QT_TRID_NOOP('foo')"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("foo")); + } } static QScriptValue callQsTr(QScriptContext *ctx, QScriptEngine *eng) @@ -4537,6 +4555,10 @@ void tst_QScriptEngine::translateWithInvalidArgs_data() QTest::newRow("qsTranslate('foo', 'bar', 'baz', 123)") << "qsTranslate('foo', 'bar', 'baz', 123)" << "Error: qsTranslate(): fourth argument (encoding) must be a string"; QTest::newRow("qsTranslate('foo', 'bar', 'baz', 'zab', 'rab')") << "qsTranslate('foo', 'bar', 'baz', 'zab', 'rab')" << "Error: qsTranslate(): fifth argument (n) must be a number"; QTest::newRow("qsTranslate('foo', 'bar', 'baz', 'zab', 123)") << "qsTranslate('foo', 'bar', 'baz', 'zab', 123)" << "Error: qsTranslate(): invalid encoding 'zab'"; + + QTest::newRow("qsTrId()") << "qsTrId()" << "Error: qsTrId() requires at least one argument"; + QTest::newRow("qsTrId(123)") << "qsTrId(123)" << "TypeError: qsTrId(): first argument (id) must be a string"; + QTest::newRow("qsTrId('foo', 'bar')") << "qsTrId('foo', 'bar')" << "TypeError: qsTrId(): second argument (n) must be a number"; } void tst_QScriptEngine::translateWithInvalidArgs() @@ -4598,6 +4620,53 @@ void tst_QScriptEngine::translationContext() QCoreApplication::instance()->removeTranslator(&translator); } +void tst_QScriptEngine::translateScriptIdBased() +{ + QScriptEngine engine; + + QTranslator translator; + translator.load(":/translations/idtranslatable_la"); + QCoreApplication::instance()->installTranslator(&translator); + engine.installTranslatorFunctions(); + + QString fileName = QString::fromLatin1("idtranslatable.js"); + + QHash<QString, QString> expectedTranslations; + expectedTranslations["qtn_foo_bar"] = "First string"; + expectedTranslations["qtn_needle"] = "Second string"; + expectedTranslations["qtn_haystack"] = "Third string"; + expectedTranslations["qtn_bar_baz"] = "Fourth string"; + + QHash<QString, QString>::const_iterator it; + for (it = expectedTranslations.constBegin(); it != expectedTranslations.constEnd(); ++it) { + for (int x = 0; x < 2; ++x) { + QString fn; + if (x) + fn = fileName; + // Top-level + QCOMPARE(engine.evaluate(QString::fromLatin1("qsTrId('%0')") + .arg(it.key()), fn).toString(), + it.value()); + QCOMPARE(engine.evaluate(QString::fromLatin1("QT_TRID_NOOP('%0')") + .arg(it.key()), fn).toString(), + it.key()); + // From function + QCOMPARE(engine.evaluate(QString::fromLatin1("(function() { return qsTrId('%0'); })()") + .arg(it.key()), fn).toString(), + it.value()); + QCOMPARE(engine.evaluate(QString::fromLatin1("(function() { return QT_TRID_NOOP('%0'); })()") + .arg(it.key()), fn).toString(), + it.key()); + } + } + + // Plural form + QCOMPARE(engine.evaluate("qsTrId('qtn_bar_baz', 10)").toString(), + QString::fromLatin1("10 fooish bar(s) found")); + QCOMPARE(engine.evaluate("qsTrId('qtn_foo_bar', 10)").toString(), + QString::fromLatin1("qtn_foo_bar")); // Doesn't have plural +} + void tst_QScriptEngine::functionScopes() { QScriptEngine eng; diff --git a/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp b/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp index e370309..04b1e79 100644 --- a/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp +++ b/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp @@ -698,20 +698,25 @@ void tst_QStyleSheetStyle::fontPrecedence() QCOMPARE(FONTSIZE(edit2), 26); } -static bool testForColors(const QImage& image, const QColor& color) +// Ensure primary will only return true if the color covers more than 50% of pixels +static bool testForColors(const QImage& image, const QColor& color, bool ensurePrimary=false) { int count = 0; QRgb rgb = color.rgba(); + int totalCount = image.height()*image.width(); for (int y = 0; y < image.height(); ++y) { for (int x = 0; x < image.width(); ++x) { // Because of antialiasing we allow a certain range of errors here. QRgb pixel = image.pixel(x, y); + if (qAbs((int)(pixel & 0xff) - (int)(rgb & 0xff)) + qAbs((int)((pixel & 0xff00) >> 8) - (int)((rgb & 0xff00) >> 8)) + qAbs((int)((pixel & 0xff0000) >> 16) - (int)((rgb & 0xff0000) >> 16)) <= 50) { - if (++count >= 10) { + count++; + if (!ensurePrimary && count >=10 ) + return true; + else if (count > totalCount/2) return true; - } } } } @@ -1528,6 +1533,15 @@ void tst_QStyleSheetStyle::task188195_baseBackground() tree.render(&image); QVERIFY(testForColors(image, tree.palette().base().color())); QVERIFY(!testForColors(image, QColor(0xab, 0x12, 0x51))); + + QTableWidget table(12, 12); + table.setItem(0, 0, new QTableWidgetItem()); + table.setStyleSheet( "QTableView {background-color: #ff0000}" ); + table.show(); + QTest::qWait(20); + image = QImage(table.width(), table.height(), QImage::Format_ARGB32); + table.render(&image); + QVERIFY(testForColors(image, Qt::red, true)); } void tst_QStyleSheetStyle::task232085_spinBoxLineEditBg() diff --git a/tests/auto/qtouchevent/tst_qtouchevent.cpp b/tests/auto/qtouchevent/tst_qtouchevent.cpp index bb80fde..4219ef4 100644 --- a/tests/auto/qtouchevent/tst_qtouchevent.cpp +++ b/tests/auto/qtouchevent/tst_qtouchevent.cpp @@ -109,6 +109,7 @@ class tst_QTouchEventGraphicsItem : public QGraphicsItem public: QList<QTouchEvent::TouchPoint> touchBeginPoints, touchUpdatePoints, touchEndPoints; bool seenTouchBegin, seenTouchUpdate, seenTouchEnd; + int touchBeginCounter, touchUpdateCounter, touchEndCounter; bool acceptTouchBegin, acceptTouchUpdate, acceptTouchEnd; bool deleteInTouchBegin, deleteInTouchUpdate, deleteInTouchEnd; tst_QTouchEventGraphicsItem **weakpointer; @@ -131,6 +132,7 @@ public: touchUpdatePoints.clear(); touchEndPoints.clear(); seenTouchBegin = seenTouchUpdate = seenTouchEnd = false; + touchBeginCounter = touchUpdateCounter = touchEndCounter = 0; acceptTouchBegin = acceptTouchUpdate = acceptTouchEnd = true; deleteInTouchBegin = deleteInTouchUpdate = deleteInTouchEnd = false; } @@ -146,6 +148,7 @@ public: if (seenTouchUpdate) qWarning("TouchBegin: TouchUpdate cannot happen before TouchBegin"); if (seenTouchEnd) qWarning("TouchBegin: TouchEnd cannot happen before TouchBegin"); seenTouchBegin = !seenTouchBegin && !seenTouchUpdate && !seenTouchEnd; + ++touchBeginCounter; touchBeginPoints = static_cast<QTouchEvent *>(event)->touchPoints(); event->setAccepted(acceptTouchBegin); if (deleteInTouchBegin) @@ -155,6 +158,7 @@ public: if (!seenTouchBegin) qWarning("TouchUpdate: have not seen TouchBegin"); if (seenTouchEnd) qWarning("TouchUpdate: TouchEnd cannot happen before TouchUpdate"); seenTouchUpdate = seenTouchBegin && !seenTouchEnd; + ++touchUpdateCounter; touchUpdatePoints = static_cast<QTouchEvent *>(event)->touchPoints(); event->setAccepted(acceptTouchUpdate); if (deleteInTouchUpdate) @@ -164,6 +168,7 @@ public: if (!seenTouchBegin) qWarning("TouchEnd: have not seen TouchBegin"); if (seenTouchEnd) qWarning("TouchEnd: already seen a TouchEnd"); seenTouchEnd = seenTouchBegin && !seenTouchEnd; + ++touchEndCounter; touchEndPoints = static_cast<QTouchEvent *>(event)->touchPoints(); event->setAccepted(acceptTouchEnd); if (deleteInTouchEnd) @@ -194,6 +199,7 @@ private slots: void deleteInEventHandler(); void deleteInRawEventTranslation(); void crashInQGraphicsSceneAfterNotHandlingTouchBegin(); + void touchBeginWithGraphicsWidget(); }; void tst_QTouchEvent::touchDisabledByDefault() @@ -1334,6 +1340,59 @@ void tst_QTouchEvent::crashInQGraphicsSceneAfterNotHandlingTouchBegin() QTest::touchEvent(view.viewport()).release(0, view.mapFromScene(QPoint(10, 10))); } +void tst_QTouchEvent::touchBeginWithGraphicsWidget() +{ + QGraphicsScene scene; + QGraphicsView view(&scene); + tst_QTouchEventGraphicsItem *root; + root = new tst_QTouchEventGraphicsItem; + root->setAcceptTouchEvents(true); + scene.addItem(root); + + QGraphicsWidget *glassWidget = new QGraphicsWidget; + glassWidget->setMinimumSize(100, 100); + scene.addItem(glassWidget); + + view.resize(200, 200); + view.show(); + QTest::qWaitForWindowShown(&view); + view.fitInView(scene.sceneRect()); + + QTest::touchEvent() + .press(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport()); + QTest::touchEvent() + .stationary(0) + .press(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport()); + QTest::touchEvent() + .release(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport()) + .release(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport()); + + QCOMPARE(root->touchBeginCounter, 1); + QCOMPARE(root->touchUpdateCounter, 1); + QCOMPARE(root->touchEndCounter, 1); + QCOMPARE(root->touchUpdatePoints.size(), 2); + + root->reset(); + glassWidget->setWindowFlags(Qt::Window); // make the glassWidget a panel + + QTest::touchEvent() + .press(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport()); + QTest::touchEvent() + .stationary(0) + .press(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport()); + QTest::touchEvent() + .release(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport()) + .release(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport()); + + QCOMPARE(root->touchBeginCounter, 0); + QCOMPARE(root->touchUpdateCounter, 0); + QCOMPARE(root->touchEndCounter, 0); + + + delete root; + delete glassWidget; +} + QTEST_MAIN(tst_QTouchEvent) #include "tst_qtouchevent.moc" diff --git a/tests/benchmarks/corelib/tools/qstring/data.cpp b/tests/benchmarks/corelib/tools/qstring/data.cpp new file mode 100644 index 0000000..6d1a069 --- /dev/null +++ b/tests/benchmarks/corelib/tools/qstring/data.cpp @@ -0,0 +1,1284 @@ +// This is a generated file - DO NOT EDIT +static const ushort stringCollectionData[] __attribute__((aligned(16))) = { + // #0 + 65535, + 99, 111, 109, 112, 105, 108, 101, 114, 32, 118, 101, 114, 115, 105, 111, 110, 115, 47, + 65535,65534,65533,65532,65531, // 24 + 65535,65534,65533,65532,65531, + 99, 111, 109, 112, 105, 108, 101, 114, 32, 118, 101, 114, 115, 105, 111, 110, 115, 47, + 65535, // 48 + + // #1 + 65535,65534,65533,65532,65531, + 99, 111, 109, 112, 105, 108, 101, 114, 32, 118, 101, 114, 115, 105, 111, 110, 115, 47, + 65535, // 72 + 65535,65534,65533,65532,65531, + 67, 111, 109, 112, 105, 108, 101, 114, 32, 86, 101, 114, 115, 105, 111, 110, 115, 47, + 65535, // 96 + + // #2 + 65535, + 99, 111, 109, 112, 105, 108, 101, 114, 32, 116, 105, 109, 101, 115, 116, 97, 109, 112, 115, 47, + 65535,65534,65533, // 120 + 65535,65534,65533,65532,65531, + 99, 111, 109, 112, 105, 108, 101, 114, 32, 116, 105, 109, 101, 115, 116, 97, 109, 112, 115, 47, + 65535,65534,65533,65532,65531,65530,65529, // 152 + + // #3 + 65535,65534,65533,65532,65531, + 99, 111, 109, 112, 105, 108, 101, 114, 32, 116, 105, 109, 101, 115, 116, 97, 109, 112, 115, 47, + 65535,65534,65533,65532,65531,65530,65529, // 184 + 65535, + 67, 111, 109, 112, 105, 108, 101, 114, 32, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 47, + 65535,65534,65533, // 208 + + // #4 + 65535,65534,65533,65532,65531,65530,65529,65528,65527,65526,65525,65524,65523,65522,65521,65520,65519, + 47, 118, 97, 114, 47, 116, 109, 112, 47, 116, 101, 97, 109, 98, 117, 105, 108, 100, 101, 114, 45, 116, 109, 97, 99, 105, 101, 105, 114, 47, 99, 108, 105, 101, 110, 116, 47, 99, 111, 109, 112, 105, 108, 101, 114, 115, 46, 99, 111, 110, 102, + 65535,65534,65533,65532, // 280+ + + + // #5 + 65535,65534,65533,65532,65531,65530,65529,65528,65527,65526,65525,65524,65523, + 47, 118, 97, 114, 47, 116, 109, 112, 47, 116, 101, 97, 109, 98, 117, 105, 108, 100, 101, 114, 45, 116, 109, 97, 99, 105, 101, 105, 114, 47, 99, 108, 105, 101, 110, 116, 47, 99, 111, 109, 112, 105, 108, 101, 114, 115, 46, 99, 111, 110, 102, + 65535,65534,65533,65532,65531,65530,65529,65528, // 352+ + 65535, + 47, 118, 97, 114, 47, 116, 109, 112, 47, 116, 101, 97, 109, 98, 117, 105, 108, 100, 101, 114, 45, 116, 109, 97, 99, 105, 101, 105, 114, 47, 99, 108, 105, 101, 110, 116, 47, 99, 111, 109, 112, 105, 108, 101, 114, 115, 46, 99, 111, 110, 102, + 65535,65534,65533,65532, // 408+ + + // #6 + 65535,65534,65533,65532,65531,65530,65529,65528,65527, + 47, 118, 97, 114, 47, 116, 109, 112, 47, 116, 101, 97, 109, 98, 117, 105, 108, 100, 101, 114, 45, 116, 109, 97, 99, 105, 101, 105, 114, 47, 99, 108, 105, 101, 110, 116, 47, 99, 111, 109, 112, 105, 108, 101, 114, 115, 46, 99, 111, 110, 102, + 65535,65534,65533,65532, // 472+ + + + // #7 + 65535, + 97, 114, 99, 104, 105, 118, 101, 100, 32, 99, 111, 109, 112, 105, 108, 101, 114, 115, 47, + 65535,65534,65533,65532, // 496 + 65535,65534,65533,65532,65531, + 97, 114, 99, 104, 105, 118, 101, 100, 32, 99, 111, 109, 112, 105, 108, 101, 114, 115, 47, + 65535,65534,65533,65532,65531,65530,65529,65528, // 528 + + // #8 + 65535,65534,65533,65532,65531, + 97, 114, 99, 104, 105, 118, 101, 100, 32, 99, 111, 109, 112, 105, 108, 101, 114, 115, 47, + 65535,65534,65533,65532,65531,65530,65529,65528, // 560 + 65535,65534,65533,65532,65531, + 65, 114, 99, 104, 105, 118, 101, 100, 32, 67, 111, 109, 112, 105, 108, 101, 114, 115, 47, + 65535,65534,65533,65532,65531,65530,65529,65528, // 592 + + // #9 + 65535,65534,65533,65532,65531,65530,65529,65528,65527,65526,65525,65524,65523,65522,65521,65520,65519, + 47, 118, 97, 114, 47, 116, 109, 112, 47, 116, 101, 97, 109, 98, 117, 105, 108, 100, 101, 114, 45, 116, 109, 97, 99, 105, 101, 105, 114, 47, 99, 108, 105, 101, 110, 116, 47, 99, 111, 109, 112, 105, 108, 101, 114, 115, 46, 99, 111, 110, 102, + 65535,65534,65533,65532, // 664+ + 65535,65534,65533,65532,65531,65530,65529,65528,65527,65526,65525,65524,65523, + 47, 118, 97, 114, 47, 116, 109, 112, 47, 116, 101, 97, 109, 98, 117, 105, 108, 100, 101, 114, 45, 116, 109, 97, 99, 105, 101, 105, 114, 47, 99, 108, 105, 101, 110, 116, 47, 99, 111, 109, 112, 105, 108, 101, 114, 115, 46, 99, 111, 110, 102, + 65535,65534,65533,65532,65531,65530,65529,65528, // 736+ + + // #10 + 65535,65534,65533,65532,65531, + 76, 105, 110, 117, 120, + 65535,65534,65533,65532,65531,65530, // 752 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 760 + + // #11 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 776 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 792 + + // #12 + 65535, + 105, 99, 99, + 65535,65534,65533,65532, // 800 + 65535,65534,65533,65532,65531, + 103, 43, 43, + 65535,65534,65533,65532,65531,65530,65529,65528, // 816 + + // #13 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 824 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 832 + + // #14 + 65535, + 105, 51, 56, 54, + 65535,65534,65533, // 840 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 856 + + // #15 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 864 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 872 + + // #16 + 65535, + 105, 51, 56, 54, + 65535,65534,65533, // 880 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 896 + + // #17 + 65535, + 103, 99, 99, + 65535,65534,65533,65532, // 904 + 65535,65534,65533,65532,65531, + 103, 43, 43, + 65535,65534,65533,65532,65531,65530,65529,65528, // 920 + + // #18 + 65535,65534,65533,65532,65531, + 76, 105, 110, 117, 120, + 65535,65534,65533,65532,65531,65530, // 936 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 944 + + // #19 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 960 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 976 + + // #20 + 65535, + 103, 43, 43, + 65535,65534,65533,65532, // 984 + 65535,65534,65533,65532,65531, + 103, 43, 43, + 65535,65534,65533,65532,65531,65530,65529,65528, // 1000 + + // #21 + 65535,65534,65533,65532,65531, + 52, 46, 52, 46, 51, + 65535,65534,65533,65532,65531,65530, // 1016 + 65535,65534,65533,65532,65531, + 52, 46, 52, 46, 51, + 65535,65534,65533,65532,65531,65530, // 1032 + + // #22 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1040 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1048 + + // #23 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1064 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1080 + + // #24 + 65535, + 47, 117, 115, 114, 47, 98, 105, 110, 47, 103, 43, 43, + 65535,65534,65533, // 1096 + 65535, + 47, 117, 115, 114, 47, 98, 105, 110, 47, 103, 43, 43, + 65535,65534,65533, // 1112 + + // #25 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1120 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1128 + + // #26 + 65535, + 105, 51, 56, 54, + 65535,65534,65533, // 1136 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1152 + + // #27 + 65535, + 105, 99, 99, + 65535,65534,65533,65532, // 1160 + 65535,65534,65533,65532,65531, + 103, 43, 43, + 65535,65534,65533,65532,65531,65530,65529,65528, // 1176 + + // #28 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1184 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1192 + + // #29 + 65535, + 105, 51, 56, 54, + 65535,65534,65533, // 1200 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1216 + + // #30 + 65535,65534,65533,65532,65531, + 76, 105, 110, 117, 120, + 65535,65534,65533,65532,65531,65530, // 1232 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1240 + + // #31 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1256 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1272 + + // #32 + 65535,65534,65533,65532,65531, + 76, 105, 110, 117, 120, + 65535,65534,65533,65532,65531,65530, // 1288 + 65535, + 76, 105, 110, 117, 120, + 65535,65534, // 1296 + + // #33 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1312 + 65535,65534,65533,65532,65531, + 105, 51, 56, 54, + 65535,65534,65533,65532,65531,65530,65529, // 1328 + + // #34 + 65535, + 45, 109, 97, 114, 99, 104, 61, 99, 111, 114, 101, 50, + 65535,65534,65533, // 1344 + 65535, + 116, 98, 51, 54, 57, 54, 56, 95, 50, 46, 105, 105, + 65535,65534,65533, // 1360 + + // #35 + 65535,65534,65533,65532,65531, + 45, 102, 108, 111, 111, 112, 45, 98, 108, 111, 99, 107, + 65535,65534,65533,65532,65531,65530,65529, // 1384 + 65535, + 116, 98, 51, 54, 57, 54, 56, 95, 50, 46, 105, 105, + 65535,65534,65533, // 1400 + + // #36 + 65535,65534,65533,65532,65531, + 116, 98, 51, 54, 57, 54, 56, 95, 50, 46, 105, 105, + 65535,65534,65533,65532,65531,65530,65529, // 1424 + 65535, + 116, 98, 51, 54, 57, 54, 56, 95, 50, 46, 105, 105, + 65535,65534,65533, // 1440 + + // #37 + 65535,65534,65533,65532,65531, + 45, 109, 115, 115, 101, 52, + 65535,65534,65533,65532,65531, // 1456 + 65535,65534,65533,65532,65531, + 108, 101, 110, 103, 116, 104, + 65535,65534,65533,65532,65531, // 1472 + + // #38 + 65535,65534,65533,65532,65531, + 116, 98, 51, 54, 57, 54, 56, 95, 49, 46, 111, + 65535,65534,65533,65532,65531,65530,65529,65528, // 1496 + 65535,65534,65533,65532,65531, + 116, 98, 51, 54, 57, 54, 56, 95, 49, 46, 111, + 65535,65534,65533,65532,65531,65530,65529,65528, // 1520 + + // #39 + 65535,65534,65533,65532,65531, + 68, 69, 83, 75, 84, 79, 80, 95, 83, 69, 83, 83, + 65535,65534,65533,65532,65531,65530,65529, // 1544 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1560 + + // #40 + 65535,65534,65533,65532,65531, + 76, 67, 95, 83, 79, 85, 82, 67, 69, 68, 61, 49, + 65535,65534,65533,65532,65531,65530,65529, // 1584 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1600 + + // #41 + 65535,65534,65533,65532,65531, + 81, 84, 68, 73, 82, 61, 47, 104, 111, 109, 101, 47, + 65535,65534,65533,65532,65531,65530,65529, // 1624 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1640 + + // #42 + 65535, + 76, 67, 95, 67, 84, 89, 80, 69, 61, 112, 116, 95, + 65535,65534,65533, // 1656 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1672 + + // #43 + 65535, + 71, 84, 75, 95, 82, 67, 95, 70, 73, 76, 69, 83, + 65535,65534,65533, // 1688 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1704 + + // #44 + 65535, + 88, 77, 79, 68, 73, 70, 73, 69, 82, 83, 61, 64, + 65535,65534,65533, // 1720 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1736 + + // #45 + 65535, + 83, 72, 69, 76, 76, 61, 47, 98, 105, 110, 47, 122, + 65535,65534,65533, // 1752 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1768 + + // #46 + 65535,65534,65533,65532,65531, + 85, 61, 64, 123, 117, 112, 115, 116, 114, 101, 97, 109, + 65535,65534,65533,65532,65531,65530,65529, // 1792 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1808 + + // #47 + 65535, + 95, 61, 47, 117, 115, 114, 47, 98, 105, 110, 47, 105, + 65535,65534,65533, // 1824 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1840 + + // #48 + 65535, + 88, 68, 71, 95, 67, 79, 78, 70, 73, 71, 95, 68, + 65535,65534,65533, // 1856 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1872 + + // #49 + 65535,65534,65533,65532,65531, + 83, 65, 86, 69, 72, 73, 83, 84, 61, 49, 48, 48, + 65535,65534,65533,65532,65531,65530,65529, // 1896 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1912 + + // #50 + 65535, + 75, 68, 69, 95, 77, 85, 76, 84, 73, 72, 69, 65, + 65535,65534,65533, // 1928 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1944 + + // #51 + 65535,65534,65533,65532,65531, + 77, 65, 76, 76, 79, 67, 95, 67, 72, 69, 67, 75, + 65535,65534,65533,65532,65531,65530,65529, // 1968 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 1984 + + // #52 + 65535,65534,65533,65532,65531, + 72, 73, 83, 84, 67, 79, 78, 84, 82, 79, 76, 61, + 65535,65534,65533,65532,65531,65530,65529, // 2008 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2024 + + // #53 + 65535,65534,65533,65532,65531, + 88, 68, 71, 95, 68, 65, 84, 65, 95, 68, 73, 82, + 65535,65534,65533,65532,65531,65530,65529, // 2048 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2064 + + // #54 + 65535,65534,65533,65532,65531, + 88, 68, 77, 95, 77, 65, 78, 65, 71, 69, 68, 61, + 65535,65534,65533,65532,65531,65530,65529, // 2088 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2104 + + // #55 + 65535, + 76, 67, 95, 67, 79, 76, 76, 65, 84, 69, 61, 112, + 65535,65534,65533, // 2120 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2136 + + // #56 + 65535, + 81, 84, 95, 80, 76, 85, 71, 73, 78, 95, 80, 65, + 65535,65534,65533, // 2152 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2168 + + // #57 + 65535, + 83, 67, 82, 69, 69, 78, 68, 73, 82, 61, 47, 104, + 65535,65534,65533, // 2184 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2200 + + // #58 + 65535,65534,65533,65532,65531, + 76, 69, 83, 83, 79, 80, 69, 78, 61, 124, 47, 117, + 65535,65534,65533,65532,65531,65530,65529, // 2224 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2240 + + // #59 + 65535, + 76, 67, 95, 78, 65, 77, 69, 61, 110, 98, 95, 78, + 65535,65534,65533, // 2256 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2272 + + // #60 + 65535,65534,65533,65532,65531, + 80, 52, 67, 76, 73, 69, 78, 84, 61, 116, 109, 97, + 65535,65534,65533,65532,65531,65530,65529, // 2296 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2312 + + // #61 + 65535, + 80, 65, 84, 72, 61, 47, 104, 111, 109, 101, 47, 116, + 65535,65534,65533, // 2328 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2344 + + // #62 + 65535,65534,65533,65532,65531, + 71, 80, 71, 95, 65, 71, 69, 78, 84, 95, 73, 78, + 65535,65534,65533,65532,65531,65530,65529, // 2368 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2384 + + // #63 + 65535,65534,65533,65532,65531, + 88, 67, 85, 82, 83, 79, 82, 95, 84, 72, 69, 77, + 65535,65534,65533,65532,65531,65530,65529, // 2408 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2424 + + // #64 + 65535,65534,65533,65532,65531, + 83, 69, 83, 83, 73, 79, 78, 95, 77, 65, 78, 65, + 65535,65534,65533,65532,65531,65530,65529, // 2448 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2464 + + // #65 + 65535, + 81, 84, 83, 82, 67, 68, 73, 82, 61, 47, 104, 111, + 65535,65534,65533, // 2480 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2496 + + // #66 + 65535,65534,65533,65532,65531, + 87, 73, 78, 68, 79, 87, 73, 68, 61, 52, 54, 49, + 65535,65534,65533,65532,65531,65530,65529, // 2520 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2536 + + // #67 + 65535,65534,65533,65532,65531, + 76, 67, 95, 77, 69, 83, 83, 65, 71, 69, 83, 61, + 65535,65534,65533,65532,65531,65530,65529, // 2560 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2576 + + // #68 + 65535, + 76, 67, 95, 78, 85, 77, 69, 82, 73, 67, 61, 110, + 65535,65534,65533, // 2592 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2608 + + // #69 + 65535, + 71, 84, 75, 50, 95, 82, 67, 95, 70, 73, 76, 69, + 65535,65534,65533, // 2624 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2640 + + // #70 + 65535, + 80, 82, 79, 70, 73, 76, 69, 72, 79, 77, 69, 61, + 65535,65534,65533, // 2656 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2672 + + // #71 + 65535,65534,65533,65532,65531, + 68, 77, 95, 67, 79, 78, 84, 82, 79, 76, 61, 47, + 65535,65534,65533,65532,65531,65530,65529, // 2696 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2712 + + // #72 + 65535, + 76, 83, 95, 67, 79, 76, 79, 82, 83, 61, 114, 115, + 65535,65534,65533, // 2728 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2744 + + // #73 + 65535,65534,65533,65532,65531, + 83, 83, 72, 95, 65, 85, 84, 72, 95, 83, 79, 67, + 65535,65534,65533,65532,65531,65530,65529, // 2768 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2784 + + // #74 + 65535,65534,65533,65532,65531, + 75, 68, 69, 68, 73, 82, 83, 61, 47, 104, 111, 109, + 65535,65534,65533,65532,65531,65530,65529, // 2808 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2824 + + // #75 + 65535,65534,65533,65532,65531, + 76, 68, 95, 80, 82, 69, 76, 79, 65, 68, 61, 47, + 65535,65534,65533,65532,65531,65530,65529, // 2848 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2864 + + // #76 + 65535,65534,65533,65532,65531, + 88, 67, 85, 82, 83, 79, 82, 95, 80, 65, 84, 72, + 65535,65534,65533,65532,65531,65530,65529, // 2888 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2904 + + // #77 + 65535, + 115, 114, 99, 100, 105, 114, 61, 47, 104, 111, 109, 101, + 65535,65534,65533, // 2920 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2936 + + // #78 + 65535,65534,65533,65532,65531, + 72, 79, 77, 69, 61, 47, 104, 111, 109, 101, 47, 116, + 65535,65534,65533,65532,65531,65530,65529, // 2960 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 2976 + + // #79 + 65535, + 81, 84, 52, 68, 79, 67, 68, 73, 82, 61, 47, 117, + 65535,65534,65533, // 2992 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3008 + + // #80 + 65535,65534,65533,65532,65531, + 80, 87, 68, 61, 47, 104, 111, 109, 101, 47, 116, 109, + 65535,65534,65533,65532,65531,65530,65529, // 3032 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3048 + + // #81 + 65535,65534,65533,65532,65531, + 75, 68, 69, 95, 83, 69, 83, 83, 73, 79, 78, 95, + 65535,65534,65533,65532,65531,65530,65529, // 3072 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3088 + + // #82 + 65535, + 73, 78, 83, 73, 68, 69, 95, 83, 80, 69, 67, 73, + 65535,65534,65533, // 3104 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3120 + + // #83 + 65535, + 83, 83, 72, 95, 65, 71, 69, 78, 84, 95, 80, 73, + 65535,65534,65533, // 3136 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3152 + + // #84 + 65535, + 80, 75, 71, 95, 67, 79, 78, 70, 73, 71, 95, 80, + 65535,65534,65533, // 3168 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3184 + + // #85 + 65535,65534,65533,65532,65531, + 68, 66, 85, 83, 95, 83, 69, 83, 83, 73, 79, 78, + 65535,65534,65533,65532,65531,65530,65529, // 3208 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3224 + + // #86 + 65535, + 76, 68, 95, 76, 73, 66, 82, 65, 82, 89, 95, 80, + 65535,65534,65533, // 3240 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3256 + + // #87 + 65535,65534,65533,65532,65531, + 80, 52, 85, 83, 69, 82, 61, 116, 106, 109, 97, 99, + 65535,65534,65533,65532,65531,65530,65529, // 3280 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3296 + + // #88 + 65535,65534,65533,65532,65531, + 81, 84, 69, 83, 84, 95, 67, 79, 76, 79, 82, 69, + 65535,65534,65533,65532,65531,65530,65529, // 3320 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3336 + + // #89 + 65535,65534,65533,65532,65531, + 88, 68, 71, 95, 83, 69, 83, 83, 73, 79, 78, 95, + 65535,65534,65533,65532,65531,65530,65529, // 3360 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3376 + + // #90 + 65535,65534,65533,65532,65531, + 76, 69, 83, 83, 75, 69, 89, 61, 47, 101, 116, 99, + 65535,65534,65533,65532,65531,65530,65529, // 3400 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3416 + + // #91 + 65535, + 76, 79, 71, 78, 65, 77, 69, 61, 116, 109, 97, 99, + 65535,65534,65533, // 3432 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3448 + + // #92 + 65535, + 71, 95, 70, 73, 76, 69, 78, 65, 77, 69, 95, 69, + 65535,65534,65533, // 3464 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3480 + + // #93 + 65535, + 75, 68, 69, 95, 70, 85, 76, 76, 95, 83, 69, 83, + 65535,65534,65533, // 3496 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3512 + + // #94 + 65535,65534,65533,65532,65531, + 72, 79, 83, 84, 78, 65, 77, 69, 61, 108, 111, 116, + 65535,65534,65533,65532,65531,65530,65529, // 3536 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3552 + + // #95 + 65535,65534,65533,65532,65531, + 76, 67, 95, 84, 73, 77, 69, 61, 112, 116, 95, 66, + 65535,65534,65533,65532,65531,65530,65529, // 3576 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3592 + + // #96 + 65535, + 83, 83, 72, 95, 65, 83, 75, 80, 65, 83, 83, 61, + 65535,65534,65533, // 3608 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3624 + + // #97 + 65535,65534,65533,65532,65531, + 72, 73, 83, 84, 70, 73, 76, 69, 61, 47, 104, 111, + 65535,65534,65533,65532,65531,65530,65529, // 3648 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3664 + + // #98 + 65535, + 75, 79, 78, 83, 79, 76, 69, 95, 68, 66, 85, 83, + 65535,65534,65533, // 3680 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3696 + + // #99 + 65535, + 77, 65, 75, 69, 61, 47, 117, 115, 114, 47, 98, 105, + 65535,65534,65533, // 3712 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3728 + + // #100 + 65535, + 67, 65, 78, 66, 69, 82, 82, 65, 95, 68, 82, 73, + 65535,65534,65533, // 3744 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3760 + + // #101 + 65535, + 71, 67, 79, 78, 70, 95, 84, 77, 80, 68, 73, 82, + 65535,65534,65533, // 3776 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3792 + + // #102 + 65535,65534,65533,65532,65531, + 85, 83, 69, 82, 61, 116, 109, 97, 99, 105, 101, 105, + 65535,65534,65533,65532,65531,65530,65529, // 3816 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3832 + + // #103 + 65535, + 111, 98, 106, 100, 105, 114, 61, 47, 104, 111, 109, 101, + 65535,65534,65533, // 3848 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3864 + + // #104 + 65535,65534,65533,65532,65531, + 76, 67, 95, 77, 79, 78, 69, 84, 65, 82, 89, 61, + 65535,65534,65533,65532,65531,65530,65529, // 3888 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3904 + + // #105 + 65535,65534,65533,65532,65531, + 81, 84, 76, 73, 66, 61, 47, 117, 115, 114, 47, 108, + 65535,65534,65533,65532,65531,65530,65529, // 3928 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3944 + + // #106 + 65535,65534,65533,65532,65531, + 76, 67, 95, 84, 69, 76, 69, 80, 72, 79, 78, 69, + 65535,65534,65533,65532,65531,65530,65529, // 3968 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 3984 + + // #107 + 65535, + 80, 89, 84, 72, 79, 78, 68, 79, 78, 84, 87, 82, + 65535,65534,65533, // 4000 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4016 + + // #108 + 65535,65534,65533,65532,65531, + 84, 77, 80, 68, 73, 82, 61, 47, 116, 109, 112, 47, + 65535,65534,65533,65532,65531,65530,65529, // 4040 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4056 + + // #109 + 65535,65534,65533,65532,65531, + 65, 82, 77, 76, 77, 68, 95, 76, 73, 67, 69, 78, + 65535,65534,65533,65532,65531,65530,65529, // 4080 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4096 + + // #110 + 65535, + 80, 89, 84, 72, 79, 78, 80, 65, 84, 72, 61, 47, + 65535,65534,65533, // 4112 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4128 + + // #111 + 65535,65534,65533,65532,65531, + 77, 65, 75, 69, 70, 76, 65, 71, 83, 61, 119, 32, + 65535,65534,65533,65532,65531,65530,65529, // 4152 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4168 + + // #112 + 65535, + 77, 70, 76, 65, 71, 83, 61, 45, 119, 32, 45, 45, + 65535,65534,65533, // 4184 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4200 + + // #113 + 65535, + 77, 65, 73, 76, 61, 47, 118, 97, 114, 47, 115, 112, + 65535,65534,65533, // 4216 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4232 + + // #114 + 65535,65534,65533,65532,65531, + 83, 72, 69, 76, 76, 95, 83, 69, 83, 83, 73, 79, + 65535,65534,65533,65532,65531,65530,65529, // 4256 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4272 + + // #115 + 65535, + 75, 68, 69, 68, 73, 82, 61, 47, 104, 111, 109, 101, + 65535,65534,65533, // 4288 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4304 + + // #116 + 65535,65534,65533,65532,65531, + 76, 69, 83, 83, 67, 72, 65, 82, 83, 69, 84, 61, + 65535,65534,65533,65532,65531,65530,65529, // 4328 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4344 + + // #117 + 65535,65534,65533,65532,65531, + 76, 67, 95, 80, 65, 80, 69, 82, 61, 110, 98, 95, + 65535,65534,65533,65532,65531,65530,65529, // 4368 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4384 + + // #118 + 65535, + 66, 82, 79, 87, 83, 69, 82, 61, 47, 117, 115, 114, + 65535,65534,65533, // 4400 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4416 + + // #119 + 65535, + 77, 69, 84, 65, 95, 67, 76, 65, 83, 83, 61, 100, + 65535,65534,65533, // 4432 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4448 + + // #120 + 65535,65534,65533,65532,65531, + 77, 68, 86, 95, 77, 69, 78, 85, 95, 83, 84, 89, + 65535,65534,65533,65532,65531,65530,65529, // 4472 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4488 + + // #121 + 65535,65534,65533,65532,65531, + 67, 79, 76, 79, 82, 70, 71, 66, 71, 61, 49, 53, + 65535,65534,65533,65532,65531,65530,65529, // 4512 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4528 + + // #122 + 65535,65534,65533,65532,65531, + 80, 89, 84, 72, 79, 78, 83, 84, 65, 82, 84, 85, + 65535,65534,65533,65532,65531,65530,65529, // 4552 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4568 + + // #123 + 65535, + 76, 67, 95, 77, 69, 65, 83, 85, 82, 69, 77, 69, + 65535,65534,65533, // 4584 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4600 + + // #124 + 65535,65534,65533,65532,65531, + 69, 68, 73, 84, 79, 82, 61, 47, 117, 115, 114, 47, + 65535,65534,65533,65532,65531,65530,65529, // 4624 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4640 + + // #125 + 65535,65534,65533,65532,65531, + 69, 78, 95, 84, 66, 61, 109, 111, 99, 58, 117, 105, + 65535,65534,65533,65532,65531,65530,65529, // 4664 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4680 + + // #126 + 65535, + 72, 73, 83, 84, 83, 73, 90, 69, 61, 49, 48, 48, + 65535,65534,65533, // 4696 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4712 + + // #127 + 65535,65534,65533,65532,65531, + 71, 83, 95, 76, 73, 66, 61, 47, 104, 111, 109, 101, + 65535,65534,65533,65532,65531,65530,65529, // 4736 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4752 + + // #128 + 65535,65534,65533,65532,65531, + 78, 76, 83, 80, 65, 84, 72, 61, 47, 117, 115, 114, + 65535,65534,65533,65532,65531,65530,65529, // 4776 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4792 + + // #129 + 65535,65534,65533,65532,65531, + 87, 73, 78, 68, 79, 87, 80, 65, 84, 72, 61, 55, + 65535,65534,65533,65532,65531,65530,65529, // 4816 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4832 + + // #130 + 65535,65534,65533,65532,65531, + 75, 79, 78, 83, 79, 76, 69, 95, 68, 66, 85, 83, + 65535,65534,65533,65532,65531,65530,65529, // 4856 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4872 + + // #131 + 65535, + 76, 67, 95, 73, 68, 69, 78, 84, 73, 70, 73, 67, + 65535,65534,65533, // 4888 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4904 + + // #132 + 65535, + 73, 78, 80, 85, 84, 82, 67, 61, 47, 101, 116, 99, + 65535,65534,65533, // 4920 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4936 + + // #133 + 65535,65534,65533,65532,65531, + 81, 84, 73, 78, 67, 61, 47, 117, 115, 114, 47, 108, + 65535,65534,65533,65532,65531,65530,65529, // 4960 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 4976 + + // #134 + 65535, + 76, 67, 95, 65, 68, 68, 82, 69, 83, 83, 61, 110, + 65535,65534,65533, // 4992 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5008 + + // #135 + 65535,65534,65533,65532,65531, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 95, + 65535,65534,65533,65532,65531,65530,65529, // 5032 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5048 + + // #136 + 65535, + 76, 65, 78, 71, 61, 112, 116, 95, 66, 82, 46, 85, + 65535,65534,65533, // 5064 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5080 + + // #137 + 65535, + 80, 52, 80, 79, 82, 84, 61, 112, 52, 46, 116, 114, + 65535,65534,65533, // 5096 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5112 + + // #138 + 65535,65534,65533,65532,65531, + 80, 73, 76, 79, 84, 80, 79, 82, 84, 61, 117, 115, + 65535,65534,65533,65532,65531,65530,65529, // 5136 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5152 + + // #139 + 65535, + 75, 68, 69, 95, 83, 69, 83, 83, 73, 79, 78, 95, + 65535,65534,65533, // 5168 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5184 + + // #140 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5200 + 65535, + 84, 69, 65, 77, 66, 85, 73, 76, 68, 69, 82, 61, + 65535,65534,65533, // 5216 + + +}; +static struct StringCollection +{ + int len; + int offset1, offset2; + ushort align1, align2; +} stringCollection[] = { + {18, 1, 29, 3666, 106}, // #0 + {18, 53, 77, 106, 1978}, // #1 + {20, 97, 125, 2850, 3210}, // #2 + {20, 157, 185, 3210, 3138}, // #3 + {51, 225, 225, 3362, 3362}, // #4 + {51, 293, 353, 1434, 3362}, // #5 + {51, 417, 417, 3362, 3362}, // #6 + {19, 473, 501, 2850, 10}, // #7 + {19, 533, 565, 10, 442}, // #8 + {51, 609, 677, 3362, 1434}, // #9 + {5, 741, 753, 2666, 2066}, // #10 + {4, 765, 781, 2362, 3930}, // #11 + {3, 793, 805, 3330, 2138}, // #12 + {5, 817, 825, 738, 2066}, // #13 + {4, 833, 845, 434, 3930}, // #14 + {5, 857, 865, 3842, 2066}, // #15 + {4, 873, 885, 3538, 3930}, // #16 + {3, 897, 909, 3330, 2138}, // #17 + {5, 925, 937, 1898, 2066}, // #18 + {4, 949, 965, 1594, 3930}, // #19 + {3, 977, 989, 3330, 2138}, // #20 + {5, 1005, 1021, 2218, 762}, // #21 + {5, 1033, 1041, 3346, 2066}, // #22 + {4, 1053, 1069, 3082, 3930}, // #23 + {12, 1081, 1097, 2082, 962}, // #24 + {5, 1113, 1121, 3362, 2066}, // #25 + {4, 1129, 1141, 322, 3930}, // #26 + {3, 1153, 1165, 2050, 2138}, // #27 + {5, 1177, 1185, 1538, 2066}, // #28 + {4, 1193, 1205, 1234, 3930}, // #29 + {5, 1221, 1233, 554, 2066}, // #30 + {4, 1245, 1261, 250, 3930}, // #31 + {5, 1277, 1289, 2858, 2066}, // #32 + {4, 1301, 1317, 2554, 3930}, // #33 + {12, 1329, 1345, 2194, 1762}, // #34 + {12, 1365, 1385, 2170, 1762}, // #35 + {12, 1405, 1425, 2314, 1762}, // #36 + {6, 1445, 1461, 3626, 666}, // #37 + {11, 1477, 1501, 3882, 842}, // #38 + {12, 1525, 1545, 1722, 2930}, // #39 + {12, 1565, 1585, 1914, 2930}, // #40 + {12, 1605, 1625, 442, 2930}, // #41 + {12, 1641, 1657, 626, 2930}, // #42 + {12, 1673, 1689, 946, 2930}, // #43 + {12, 1705, 1721, 738, 2930}, // #44 + {12, 1737, 1753, 2066, 2930}, // #45 + {12, 1773, 1793, 1210, 2930}, // #46 + {12, 1809, 1825, 1426, 2930}, // #47 + {12, 1841, 1857, 1650, 2930}, // #48 + {12, 1877, 1897, 1530, 2930}, // #49 + {12, 1913, 1929, 1858, 2930}, // #50 + {12, 1949, 1969, 2106, 2930}, // #51 + {12, 1989, 2009, 2202, 2930}, // #52 + {12, 2029, 2049, 2490, 2930}, // #53 + {12, 2069, 2089, 2794, 2930}, // #54 + {12, 2105, 2121, 2322, 2930}, // #55 + {12, 2137, 2153, 2834, 2930}, // #56 + {12, 2169, 2185, 1266, 2930}, // #57 + {12, 2205, 2225, 2538, 2930}, // #58 + {12, 2241, 2257, 2706, 2930}, // #59 + {12, 2277, 2297, 3402, 2930}, // #60 + {12, 2313, 2329, 146, 2930}, // #61 + {12, 2349, 2369, 3690, 2930}, // #62 + {12, 2389, 2409, 810, 2930}, // #63 + {12, 2429, 2449, 1178, 2930}, // #64 + {12, 2465, 2481, 1442, 2930}, // #65 + {12, 2501, 2521, 3546, 2930}, // #66 + {12, 2541, 2561, 1930, 2930}, // #67 + {12, 2577, 2593, 1634, 2930}, // #68 + {12, 2609, 2625, 1986, 2930}, // #69 + {12, 2641, 2657, 1970, 2930}, // #70 + {12, 2677, 2697, 1834, 2930}, // #71 + {12, 2713, 2729, 1474, 2930}, // #72 + {12, 2749, 2769, 2250, 2930}, // #73 + {12, 2789, 2809, 2458, 2930}, // #74 + {12, 2829, 2849, 2618, 2930}, // #75 + {12, 2869, 2889, 3066, 2930}, // #76 + {12, 2905, 2921, 3330, 2930}, // #77 + {12, 2941, 2961, 1706, 2930}, // #78 + {12, 2977, 2993, 2802, 2930}, // #79 + {12, 3013, 3033, 3770, 2930}, // #80 + {12, 3053, 3073, 3594, 2930}, // #81 + {12, 3089, 3105, 2, 2930}, // #82 + {12, 3121, 3137, 2962, 2930}, // #83 + {12, 3153, 3169, 290, 2930}, // #84 + {12, 3189, 3209, 794, 2930}, // #85 + {12, 3225, 3241, 1058, 2930}, // #86 + {12, 3261, 3281, 2394, 2930}, // #87 + {12, 3301, 3321, 138, 2930}, // #88 + {12, 3341, 3361, 1482, 2930}, // #89 + {12, 3381, 3401, 570, 2930}, // #90 + {12, 3417, 3433, 674, 2930}, // #91 + {12, 3449, 3465, 1282, 2930}, // #92 + {12, 3481, 3497, 1746, 2930}, // #93 + {12, 3517, 3537, 1866, 2930}, // #94 + {12, 3557, 3577, 1978, 2930}, // #95 + {12, 3593, 3609, 3954, 2930}, // #96 + {12, 3629, 3649, 2570, 2930}, // #97 + {12, 3665, 3681, 2754, 2930}, // #98 + {12, 3697, 3713, 3666, 2930}, // #99 + {12, 3729, 3745, 34, 2930}, // #100 + {12, 3761, 3777, 2914, 2930}, // #101 + {12, 3797, 3817, 1194, 2930}, // #102 + {12, 3833, 3849, 3202, 2930}, // #103 + {12, 3869, 3889, 3018, 2930}, // #104 + {12, 3909, 3929, 202, 2930}, // #105 + {12, 3949, 3969, 3546, 2930}, // #106 + {12, 3985, 4001, 3682, 2930}, // #107 + {12, 4021, 4041, 3466, 2930}, // #108 + {12, 4061, 4081, 4074, 2930}, // #109 + {12, 4097, 4113, 306, 2930}, // #110 + {12, 4133, 4153, 634, 2930}, // #111 + {12, 4169, 4185, 802, 2930}, // #112 + {12, 4201, 4217, 962, 2930}, // #113 + {12, 4237, 4257, 1114, 2930}, // #114 + {12, 4273, 4289, 1250, 2930}, // #115 + {12, 4309, 4329, 3898, 2930}, // #116 + {12, 4349, 4369, 1386, 2930}, // #117 + {12, 4385, 4401, 1586, 2930}, // #118 + {12, 4417, 4433, 1730, 2930}, // #119 + {12, 4453, 4473, 1914, 2930}, // #120 + {12, 4493, 4513, 1498, 2930}, // #121 + {12, 4533, 4553, 2138, 2930}, // #122 + {12, 4569, 4585, 2290, 2930}, // #123 + {12, 4605, 4625, 2426, 2930}, // #124 + {12, 4645, 4665, 2666, 2930}, // #125 + {12, 4681, 4697, 2050, 2930}, // #126 + {12, 4717, 4737, 2874, 2930}, // #127 + {12, 4757, 4777, 3018, 2930}, // #128 + {12, 4797, 4817, 1834, 2930}, // #129 + {12, 4837, 4857, 3178, 2930}, // #130 + {12, 4873, 4889, 3314, 2930}, // #131 + {12, 4905, 4921, 2546, 2930}, // #132 + {12, 4941, 4961, 3546, 2930}, // #133 + {12, 4977, 4993, 3682, 2930}, // #134 + {12, 5013, 5033, 3802, 2930}, // #135 + {12, 5049, 5065, 3922, 2930}, // #136 + {12, 5081, 5097, 4018, 2930}, // #137 + {12, 5117, 5137, 42, 2930}, // #138 + {12, 5153, 5169, 130, 2930}, // #139 + {12, 5185, 5201, 242, 2930}, // #140 +}; +static const int stringCollectionCount = 141; +static const int stringCollectionMaxLen = 51; +// average comparison length: 12.0922 +// cache-line crosses: 6 (2.1%) +// alignment histogram: +// 0xXXX2 = 188 (66.7%) strings, 57 (30.3%) of which same-aligned +// 0xXXXa = 94 (33.3%) strings, 10 (10.6%) of which same-aligned +// total = 282 (100%) strings, 67 (23.8%) of which same-aligned diff --git a/tests/benchmarks/corelib/tools/qstring/data.h b/tests/benchmarks/corelib/tools/qstring/data.h new file mode 100644 index 0000000..c7a7467 --- /dev/null +++ b/tests/benchmarks/corelib/tools/qstring/data.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qglobal.h> + +struct StringCollection +{ + int len; + int offset1, offset2; + ushort align1, align2; +}; + +extern const ushort stringCollectionData[]; +extern StringCollection stringCollection[]; +extern const int stringCollectionCount; diff --git a/tests/benchmarks/corelib/tools/qstring/generatelist.pl b/tests/benchmarks/corelib/tools/qstring/generatelist.pl new file mode 100644 index 0000000..d027adb --- /dev/null +++ b/tests/benchmarks/corelib/tools/qstring/generatelist.pl @@ -0,0 +1,198 @@ +#!/usr/bin/perl +## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +## All rights reserved. +## Contact: Nokia Corporation (qt-info@nokia.com) +## +## This file is part of the QtCore module of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL$ +## No Commercial Usage +## This file contains pre-release code and may not be distributed. +## You may use this file in accordance with the terms and conditions +## contained in the Technology Preview License Agreement accompanying +## this package. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 2.1 as published by the Free Software +## Foundation and appearing in the file LICENSE.LGPL included in the +## packaging of this file. Please review the following information to +## ensure the GNU Lesser General Public License version 2.1 requirements +## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +## +## In addition, as a special exception, Nokia gives you certain additional +## rights. These rights are described in the Nokia Qt LGPL Exception +## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +## +## If you have questions regarding the use of this file, please contact +## Nokia at qt-info@nokia.com. +## +## +## +## +## +## +## +## +## $QT_END_LICENSE$ +# +# Parses a file (passed as argument) that contains a dump of pairs of +# strings and generates C source code including said data. +# +# The format of the file is: +# LEN = <len> <keyword> <align1> <align2>\n<data1><data2>\n +# where: +# LEN the literal string "LEN" +# <len> the length of the data, in 16-bit words +# <keyword> the literal string "SAME" or "DIFF" +# <align1> the alignment or pointer value of the first data +# <align2> the alignment or pointer value of the second data +# <data1> the first data +# <data2> the second data +# \n newline +# +# The code to write this data would be: +# fprintf(out, "LEN = %d %s %d %d\n", len, +# (p1 == p2) ? "SAME" : "DIFF", +# uint(quintptr(p1)) & 0xfff, uint(quintptr(p2)) & 0xfff); +# fwrite(p1, 2, len, out); +# fwrite(p2, 2, len, out); +# fwrite("\n", 1, 1, out); + +sub printUshortArray($$$) { + $str = $_[0]; + $align = $_[1] & 0x1f; + $offset = $_[2]; + + die if ($align & 1) != 0; + $align /= 2; + + $len = (length $str) / 2; + $headpadding = $align & 0x7; + $tailpadding = 8 - (($len + $headpadding) & 0x7); + $multiplecachelines = ($align + $len) > 0x20; + + if ($multiplecachelines) { + # if this string crosses into a new cacheline, then + # replicate the result + $headpadding |= ($offset & ~0x1f); + $headpadding += 0x20 + if ($headpadding < $offset); + $headpadding -= $offset; + ++$cachelinecrosses; + } + for $i (1..$headpadding) { + print 65536-$i,","; + } + print "\n " if ($headpadding > 0); + print " " if ($headpadding == 0); + + for ($i = 0; $i < $len * 2; $i += 2) { + print " ", ord(substr($str, $i, 1)) + + ord(substr($str, $i + 1, 1)) * 256, + ","; + } + print "\n " if ($tailpadding > 0); + + for $i (1..$tailpadding) { + print 65536-$i, ","; + } + print " // ", $offset + $headpadding + $len + $tailpadding; + print "+" if $multiplecachelines; + + return ($offset + $headpadding, $offset + $headpadding + $len + $tailpadding); +} + +print "#include \"data.h\"\n\n"; + +print "// This is a generated file - DO NOT EDIT\n"; +print "const ushort stringCollectionData[] __attribute__((aligned(64))) = {\n"; +$count = 0; +$offset = 0; +$totalsize = 0; +$maxlen = 0; +$cachelinecrosses = 0; + +open IN, "<" . $ARGV[0]; +while (1) { + $line = readline(*IN); + last unless defined($line); + $line =~ /LEN = (\d+) (\w+) (\d+) (\d+)/; + $len = $1; + $data[$count]->{len} = $len; + $sameptr = $2; + $data[$count]->{align1} = $3 - 0; + $data[$count]->{align2} = $4 - 0; + + # statistics + $alignhistogram{$3 & 0xf}++; + $alignhistogram{$4 & 0xf}++; + $samealignments{$3 & 0xf}++ if ($3 & 0xf) == ($4 & 0xf); + + read IN, $a, $len * 2; + read IN, $b, $len * 2; + + <IN>; # Eat the newline + + if ($len == 0) { + $data[$count]->{offset1} = $offset; + $data[$count]->{offset2} = $data[$count]->{offset1}; + ++$data[$count]->{offset2} if ($sameptr eq "DIFF"); + } else { + print " // #$count\n"; + print " "; + ($data[$count]->{offset1}, $offset) = + printUshortArray($a, $data[$count]->{align1}, $offset); + print "\n "; + die if ($offset & 0x7) != 0; + + if ($sameptr eq "DIFF") { + ($data[$count]->{offset2}, $offset) = + printUshortArray($b, $data[$count]->{align2}, $offset); + print "\n\n"; + } else { + $data[$count]->{offset2} = $data[$count]->{offset1}; + print "\n\n"; + } + } + ++$count; + + $totalsize += $len; + $maxlen = $len if $len > $maxlen; +} +print "\n};\n"; +close IN; + +print "struct StringCollection stringCollection[] = {\n"; + +for $i (0..$count-1) { + print " {", + $data[$i]->{len}, ", ", + $data[$i]->{offset1}, ", ", + $data[$i]->{offset2}, ", ", + $data[$i]->{align1}, ", ", + $data[$i]->{align2}, + "}, // #$i\n"; + next if $data[$i]->{len} == 0; + die if (($data[$i]->{offset1} & 0x7) != ($data[$i]->{align1} & 0xf)/2); + die if (($data[$i]->{offset2} & 0x7) != ($data[$i]->{align2} & 0xf)/2); +} +print "};\n"; + +print "const int stringCollectionCount = $count;\n"; +print "const int stringCollectionMaxLen = $maxlen;\n"; +printf "// average comparison length: %.4f\n", ($totalsize * 1.0 / $count); +printf "// cache-line crosses: %d (%.1f%%)\n", + $cachelinecrosses, ($cachelinecrosses * 100.0 / $count / 2); + +print "// alignment histogram:\n"; +for $key (sort { $a <=> $b } keys(%alignhistogram)) { + $value = $alignhistogram{$key}; + $samealigned = $samealignments{$key}; + printf "// 0xXXX%x = %d (%.1f%%) strings, %d (%.1f%%) of which same-aligned\n", + $key, $value, $value * 100.0 / ($count*2), + $samealigned, $samealigned * 100.0 / $value; + $samealignedtotal += $samealigned; +} +printf "// total = %d (100%) strings, %d (%.1f%%) of which same-aligned\n", + $count * 2, $samealignedtotal, $samealignedtotal * 100 / $count / 2; diff --git a/tests/benchmarks/corelib/tools/qstring/main.cpp b/tests/benchmarks/corelib/tools/qstring/main.cpp index 12826eb..9616052 100644 --- a/tests/benchmarks/corelib/tools/qstring/main.cpp +++ b/tests/benchmarks/corelib/tools/qstring/main.cpp @@ -40,7 +40,7 @@ ****************************************************************************/ #include <QStringList> #include <QFile> -#include <qtest.h> +#include <QtTest/QtTest> #ifdef Q_OS_SYMBIAN // In Symbian OS test data is located in applications private dir @@ -48,12 +48,27 @@ #define SRCDIR "" #endif +#ifdef Q_OS_UNIX +#include <sys/mman.h> +#include <unistd.h> +#endif + +#include <private/qsimd_p.h> + +#include "data.h" + class tst_QString: public QObject { Q_OBJECT +public: + tst_QString(); private slots: void equals() const; void equals_data() const; + void equals2_data() const; + void equals2() const; + void ucstrncmp_data() const; + void ucstrncmp() const; void fromUtf8() const; }; @@ -67,6 +82,10 @@ void tst_QString::equals() const } } +tst_QString::tst_QString() +{ +} + void tst_QString::equals_data() const { static const struct { @@ -126,6 +145,1247 @@ void tst_QString::equals_data() const << QString::fromRawData(ptr + 1, 58) << QString::fromRawData(ptr + 3, 58); } +static bool equals2_memcmp_call(const ushort *p1, const ushort *p2, int len) +{ + return memcmp(p1, p2, len * 2) == 0; +} + +static bool equals2_bytewise(const ushort *p1, const ushort *p2, int len) +{ + if (p1 == p2 || !len) + return true; + uchar *b1 = (uchar *)p1; + uchar *b2 = (uchar *)p2; + len *= 2; + while (len--) + if (*b1++ != *b2++) + return false; + return true; +} + +static bool equals2_shortwise(const ushort *p1, const ushort *p2, int len) +{ + if (p1 == p2 || !len) + return true; +// for (register int counter; counter < len; ++counter) +// if (p1[counter] != p2[counter]) +// return false; + while (len--) { + if (p1[len] != p2[len]) + return false; + } + return true; +} + +static bool equals2_intwise(const ushort *p1, const ushort *p2, int length) +{ + if (p1 == p2 || !length) + return true; + register union { + const quint16 *w; + const quint32 *d; + quintptr value; + } sa, sb; + sa.w = p1; + sb.w = p2; + + // check alignment + if ((sa.value & 2) == (sb.value & 2)) { + // both addresses have the same alignment + if (sa.value & 2) { + // both addresses are not aligned to 4-bytes boundaries + // compare the first character + if (*sa.w != *sb.w) + return false; + --length; + ++sa.w; + ++sb.w; + + // now both addresses are 4-bytes aligned + } + + // both addresses are 4-bytes aligned + // do a fast 32-bit comparison + register const quint32 *e = sa.d + (length >> 1); + for ( ; sa.d != e; ++sa.d, ++sb.d) { + if (*sa.d != *sb.d) + return false; + } + + // do we have a tail? + return (length & 1) ? *sa.w == *sb.w : true; + } else { + // one of the addresses isn't 4-byte aligned but the other is + register const quint16 *e = sa.w + length; + for ( ; sa.w != e; ++sa.w, ++sb.w) { + if (*sa.w != *sb.w) + return false; + } + } + return true; +} + +static inline bool equals2_short_tail(const ushort *p1, const ushort *p2, int len) +{ + if (len) { + if (*p1 != *p2) + return false; + if (--len) { + if (p1[1] != p2[1]) + return false; + if (--len) { + if (p1[2] != p2[2]) + return false; + if (--len) { + if (p1[3] != p2[3]) + return false; + if (--len) { + if (p1[4] != p2[4]) + return false; + if (--len) { + if (p1[5] != p2[5]) + return false; + if (--len) { + if (p1[6] != p2[6]) + return false; + return p1[7] == p2[7]; + } + } + } + } + } + } + } + return true; +} + +//#pragma GCC optimize("no-unroll-loops") +#ifdef __SSE2__ +static bool equals2_sse2_aligned(const ushort *p1, const ushort *p2, int len) +{ + if (len >= 8) { + qptrdiff counter = 0; + while (len > 8) { + __m128i q1 = _mm_load_si128((__m128i *)(p1 + counter)); + __m128i q2 = _mm_load_si128((__m128i *)(p2 + counter)); + __m128i cmp = _mm_cmpeq_epi16(q1, q2); + if (ushort(_mm_movemask_epi8(cmp)) != ushort(0xffff)) + return false; + + len -= 8; + counter += 8; + } + p1 += counter; + p2 += counter; + } + + return equals2_short_tail(p1, p2, len); +} + +static bool __attribute__((optimize("no-unroll-loops"))) equals2_sse2(const ushort *p1, const ushort *p2, int len) +{ + if (p1 == p2 || !len) + return true; + + if (len >= 8) { + qptrdiff counter = 0; + while (len >= 8) { + __m128i q1 = _mm_loadu_si128((__m128i *)(p1 + counter)); + __m128i q2 = _mm_loadu_si128((__m128i *)(p2 + counter)); + __m128i cmp = _mm_cmpeq_epi16(q1, q2); + if (ushort(_mm_movemask_epi8(cmp)) != 0xffff) + return false; + + len -= 8; + counter += 8; + } + p1 += counter; + p2 += counter; + } + + return equals2_short_tail(p1, p2, len); +} + +//static bool equals2_sse2(const ushort *p1, const ushort *p2, int len) +//{ +// register int val1 = quintptr(p1) & 0xf; +// register int val2 = quintptr(p2) & 0xf; +// if (false && val1 + val2 == 0) +// return equals2_sse2_aligned(p1, p2, len); +// else +// return equals2_sse2_unaligned(p1, p2, len); +//} + +static bool equals2_sse2_aligning(const ushort *p1, const ushort *p2, int len) +{ + if (len < 8) + return equals2_short_tail(p1, p2, len); + + qptrdiff counter = 0; + + // which one is easier to align, p1 or p2 ? + register int val1 = quintptr(p1) & 0xf; + register int val2 = quintptr(p2) & 0xf; + if (val1 && val2) { +#if 0 + // we'll align the one which requires the least number of steps + if (val1 > val2) { + qSwap(p1, p2); + val1 = val2; + } + + // val1 contains the number of bytes past the 16-aligned mark + // we must read 16-val1 bytes to align + val1 = 16 - val1; + if (val1 & 0x2) { + if (*p1 != *p2) + return false; + --len; + ++counter; + } + while (val1 & 12) { + if (*(uint*)p1 != *(uint*)p2) + return false; + --len; + counter += 2; + val1 -= 4; + } +#else + // we'll align the one closest to the 16-byte mark + if (val1 > val2) { + qSwap(p1, p2); + val1 = val2; + } + + // we're reading val1 bytes too many + __m128i q2 = _mm_loadu_si128((__m128i *)(p2 - val1/2)); + __m128i cmp = _mm_cmpeq_epi16(*(__m128i *)(p1 - val1/2), q2); + if (short(_mm_movemask_epi8(cmp)) >> val1 != short(-1)) + return false; + + counter = 8 - val1/2; + len -= 8 - val1/2; +#endif + } else if (!val2) { + // p2 is already aligned + qSwap(p1, p2); + } + + // p1 is aligned + + while (len >= 8) { + __m128i q1 = _mm_load_si128((__m128i *)(p1 + counter)); + __m128i q2 = _mm_loadu_si128((__m128i *)(p2 + counter)); + __m128i cmp = _mm_cmpeq_epi16(q1, q2); + if (ushort(_mm_movemask_epi8(cmp)) != ushort(0xffff)) + return false; + + len -= 8; + counter += 8; + } + + // tail + return equals2_short_tail(p1 + counter, p2 + counter, len); +} + +#ifdef __SSE3__ +static bool __attribute__((optimize("no-unroll-loops"))) equals2_sse3(const ushort *p1, const ushort *p2, int len) +{ + if (p1 == p2 || !len) + return true; + + if (len >= 8) { + qptrdiff counter = 0; + while (len >= 8) { + __m128i q1 = _mm_lddqu_si128((__m128i *)(p1 + counter)); + __m128i q2 = _mm_lddqu_si128((__m128i *)(p2 + counter)); + __m128i cmp = _mm_cmpeq_epi16(q1, q2); + if (ushort(_mm_movemask_epi8(cmp)) != 0xffff) + return false; + + len -= 8; + counter += 8; + } + p1 += counter; + p2 += counter; + } + + return equals2_short_tail(p1, p2, len); +} + +#ifdef __SSSE3__ +template<int N> static __attribute__((optimize("unroll-loops"))) inline bool equals2_ssse3_alignr(__m128i *m1, __m128i *m2, int len) +{ + __m128i lower = _mm_load_si128(m1); + while (len >= 8) { + __m128i upper = _mm_load_si128(m1 + 1); + __m128i correct; + correct = _mm_alignr_epi8(upper, lower, N); + + __m128i q2 = _mm_lddqu_si128(m2); + __m128i cmp = _mm_cmpeq_epi16(correct, q2); + if (ushort(_mm_movemask_epi8(cmp)) != 0xffff) + return false; + + len -= 8; + ++m2; + ++m1; + lower = upper; + } + + // tail + return len == 0 || equals2_short_tail((const ushort *)m1 + N / 2, (const ushort*)m2, len); +} + +static inline __attribute__((optimize("unroll-loops"))) bool equals2_ssse3_aligned(__m128i *m1, __m128i *m2, int len) +{ + while (len >= 8) { + __m128i q2 = _mm_lddqu_si128(m2); + __m128i cmp = _mm_cmpeq_epi16(*m1, q2); + if (ushort(_mm_movemask_epi8(cmp)) != 0xffff) + return false; + + len -= 8; + ++m1; + ++m2; + } + return len == 0 || equals2_short_tail((const ushort *)m1, (const ushort *)m2, len); +} + +static bool equals2_ssse3(const ushort *p1, const ushort *p2, int len) +{ + // p1 & 0xf can be: + // 0, 2, 4, 6, 8, 10, 12, 14 + // If it's 0, we're aligned + // If it's not, then we're interested in the 16 - (p1 & 0xf) bytes only + + if (len >= 8) { + // find the last aligned position below the p1 memory + __m128i *m1 = (__m128i *)(quintptr(p1) & ~0xf); + __m128i *m2 = (__m128i *)p2; + qptrdiff diff = quintptr(p1) - quintptr(m1); + + // diff contains the number of extra bytes + if (diff == 10) + return equals2_ssse3_alignr<10>(m1, m2, len); + else if (diff == 2) + return equals2_ssse3_alignr<2>(m1, m2, len); + if (diff < 8) { + if (diff < 4) { + return equals2_ssse3_aligned(m1, m2, len); + } else { + if (diff == 4) + return equals2_ssse3_alignr<4>(m1, m2, len); + else // diff == 6 + return equals2_ssse3_alignr<6>(m1, m2, len); + } + } else { + if (diff < 12) { + return equals2_ssse3_alignr<8>(m1, m2, len); + } else { + if (diff == 12) + return equals2_ssse3_alignr<12>(m1, m2, len); + else // diff == 14 + return equals2_ssse3_alignr<14>(m1, m2, len); + } + } + } + + // tail + return equals2_short_tail(p1, p2, len); +} + +template<int N> static inline bool equals2_ssse3_aligning_alignr(__m128i *m1, __m128i *m2, int len) +{ + __m128i lower = _mm_load_si128(m1); + while (len >= 8) { + __m128i upper = _mm_load_si128(m1 + 1); + __m128i correct; + correct = _mm_alignr_epi8(upper, lower, N); + + __m128i cmp = _mm_cmpeq_epi16(correct, *m2); + if (ushort(_mm_movemask_epi8(cmp)) != 0xffff) + return false; + + len -= 8; + ++m2; + ++m1; + lower = upper; + } + + // tail + return len == 0 || equals2_short_tail((const ushort *)m1 + N / 2, (const ushort*)m2, len); +} + +static bool equals2_ssse3_aligning(const ushort *p1, const ushort *p2, int len) +{ + if (len < 8) + return equals2_short_tail(p1, p2, len); + qptrdiff counter = 0; + + // which one is easier to align, p1 or p2 ? + { + register int val1 = quintptr(p1) & 0xf; + register int val2 = quintptr(p2) & 0xf; + if (val1 && val2) { + // we'll align the one closest to the 16-byte mark + if (val1 < val2) { + qSwap(p1, p2); + val2 = val1; + } + + // we're reading val1 bytes too many + __m128i q1 = _mm_lddqu_si128((__m128i *)(p1 - val2/2)); + __m128i cmp = _mm_cmpeq_epi16(q1, *(__m128i *)(p2 - val2/2)); + if (short(_mm_movemask_epi8(cmp)) >> val1 != short(-1)) + return false; + + counter = 8 - val2/2; + len -= 8 - val2/2; + } else if (!val1) { + // p1 is already aligned + qSwap(p1, p2); + } + } + + // p2 is aligned now + // we want to use palignr in the mis-alignment of p1 + __m128i *m1 = (__m128i *)(quintptr(p1 + counter) & ~0xf); + __m128i *m2 = (__m128i *)(p2 + counter); + register int val1 = quintptr(p1 + counter) - quintptr(m1); + + // val1 contains the number of extra bytes + if (val1 == 8) + return equals2_ssse3_aligning_alignr<8>(m1, m2, len); + if (val1 == 0) + return equals2_sse2_aligned(p1 + counter, p2 + counter, len); + if (val1 < 8) { + if (val1 < 4) { + return equals2_ssse3_aligning_alignr<2>(m1, m2, len); + } else { + if (val1 == 4) + return equals2_ssse3_aligning_alignr<4>(m1, m2, len); + else // diff == 6 + return equals2_ssse3_aligning_alignr<6>(m1, m2, len); + } + } else { + if (val1 < 12) { + return equals2_ssse3_aligning_alignr<10>(m1, m2, len); + } else { + if (val1 == 12) + return equals2_ssse3_aligning_alignr<12>(m1, m2, len); + else // diff == 14 + return equals2_ssse3_aligning_alignr<14>(m1, m2, len); + } + } +} + +#ifdef __SSE4_1__ +static bool equals2_sse4(const ushort *p1, const ushort *p2, int len) +{ + // We use the pcmpestrm instruction searching for differences (negative polarity) + // it will reset CF if it's all equal + // it will reset OF if the first char is equal + // it will set ZF & SF if the length is less than 8 (which means we've done the last operation) + // the three possible conditions are: + // difference found: CF = 1 + // all equal, not finished: CF = ZF = SF = 0 + // all equal, finished: CF = 0, ZF = SF = 1 + // We use the JA instruction that jumps if ZF = 0 and CF = 0 + if (p1 == p2 || !len) + return true; + + // This function may read some bytes past the end of p1 or p2 + // It is safe to do that, as long as those extra bytes (beyond p1+len and p2+len) + // are on the same page as the last valid byte. + // If len is a multiple of 8, we'll never load invalid bytes. + if (len & 7) { + // The last load would load (len & ~7) valid bytes and (8 - (len & ~7)) invalid bytes. + // So we can't do the last load if any of those bytes is in a different + // page. That is, if: + // pX + len is on a different page from pX + (len & ~7) + 8 + // + // that is, if second-to-last load ended up less than 16 bytes from the page end: + // pX + (len & ~7) is the last ushort read in the second-to-last load + if (len < 8) + return equals2_short_tail(p1, p2, len); + if ((quintptr(p1 + (len & ~7)) & 0xfff) > 0xff0 || + (quintptr(p2 + (len & ~7)) & 0xfff) > 0xff0) { + + // yes, so we mustn't do the final 128-bit load + bool result; + asm ( + "sub %[p1], %[p2]\n\t" + "sub $16, %[p1]\n\t" + "add $8, %[len]\n\t" + + // main loop: + "0:\n\t" + "add $16, %[p1]\n\t" + "sub $8, %[len]\n\t" + "jz 1f\n\t" + "lddqu (%[p1]), %%xmm0\n\t" + "mov %[len], %%edx\n\t" + "pcmpestri %[mode], (%[p2],%[p1]), %%xmm0\n\t" + + "jna 1f\n\t" + "add $16, %[p1]\n\t" + "sub $8, %[len]\n\t" + "jz 1f\n\t" + "lddqu (%[p1]), %%xmm0\n\t" + "mov %[len], %%edx\n\t" + "pcmpestri %[mode], (%[p2],%[p1]), %%xmm0\n\t" + + "ja 0b\n\t" + "1:\n\t" + "setnc %[result]\n\t" + : [result] "=a" (result), + [p1] "+r" (p1), + [p2] "+r" (p2) + : [len] "0" (len & ~7), + [mode] "i" (_SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_EACH | _SIDD_NEGATIVE_POLARITY) + : "%edx", "%ecx", "%xmm0" + ); + return result && equals2_short_tail(p1, (const ushort *)(quintptr(p1) + quintptr(p2)), len & 7); + } + } + +// const qptrdiff disp = p2 - p1; +// p1 -= 8; +// len += 8; +// while (true) { +// enum { Mode = _SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_EACH | _SIDD_NEGATIVE_POLARITY }; + +// p1 += 8; +// len -= 8; +// if (!len) +// return true; + +// __m128i q1 = _mm_lddqu_si128((__m128i *)(p1 + disp)); +// __m128i *m2 = (__m128i *)p1; + +// bool cmp_a = _mm_cmpestra(q1, len, *m2, len, Mode); +// if (cmp_a) +// continue; +// return !_mm_cmpestrc(q1, len, *m2, len, Mode); +// } +// return true; + bool result; + asm ( + "sub %[p1], %[p2]\n\t" + "sub $16, %[p1]\n\t" + "add $8, %[len]\n\t" + + "0:\n\t" + "add $16, %[p1]\n\t" + "sub $8, %[len]\n\t" + "jz 1f\n\t" + "lddqu (%[p2],%[p1]), %%xmm0\n\t" + "mov %[len], %%edx\n\t" + "pcmpestri %[mode], (%[p1]), %%xmm0\n\t" + + "jna 1f\n\t" + "add $16, %[p1]\n\t" + "sub $8, %[len]\n\t" + "jz 1f\n\t" + "lddqu (%[p2],%[p1]), %%xmm0\n\t" + "mov %[len], %%edx\n\t" + "pcmpestri %[mode], (%[p1]), %%xmm0\n\t" + + "ja 0b\n\t" + + "1:\n\t" + "setnc %[result]\n\t" + : [result] "=a" (result) + : [len] "0" (len), + [p1] "r" (p1), + [p2] "r" (p2), + [mode] "i" (_SIDD_UWORD_OPS | _SIDD_CMP_EQUAL_EACH | _SIDD_NEGATIVE_POLARITY) + : "%edx", "%ecx", "%xmm0" + ); + return result; +} + +#endif +#endif +#endif +#endif + +typedef bool (* FuncPtr)(const ushort *, const ushort *, int); +static const FuncPtr func[] = { + equals2_memcmp_call, // 0 + equals2_bytewise, // 1 + equals2_shortwise, // 1 + equals2_intwise, // 3 +#ifdef __SSE2__ + equals2_sse2, // 4 + equals2_sse2_aligning, // 5 +#ifdef __SSE3__ + equals2_sse3, // 6 +#ifdef __SSSE3__ + equals2_ssse3, // 7 + equals2_ssse3, // 8 +#ifdef __SSE4_1__ + equals2_sse4, // 9 +#endif +#endif +#endif +#endif + 0 +}; +static const int functionCount = sizeof(func)/sizeof(func[0]) - 1; + +void tst_QString::equals2_data() const +{ + QTest::addColumn<int>("algorithm"); + QTest::newRow("selftest") << -1; + QTest::newRow("memcmp_call") << 0; + QTest::newRow("bytewise") << 1; + QTest::newRow("shortwise") << 2; + QTest::newRow("intwise") << 3; +#ifdef __SSE2__ + QTest::newRow("sse2") << 4; + QTest::newRow("sse2_aligning") << 5; +#ifdef __SSE3__ + QTest::newRow("sse3") << 6; +#ifdef __SSSE3__ + QTest::newRow("ssse3") << 7; + QTest::newRow("ssse3_aligning") << 8; +#ifdef __SSE4_1__ + QTest::newRow("sse4.2") << 9; +#endif +#endif +#endif +#endif +} + +static void __attribute__((noinline)) equals2_selftest() +{ +#ifdef Q_OS_UNIX + const long pagesize = sysconf(_SC_PAGESIZE); + void *page1, *page3; + ushort *page2; + page1 = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + page2 = (ushort *)mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0); + page3 = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + Q_ASSERT(quintptr(page2) == quintptr(page1) + pagesize || quintptr(page2) == quintptr(page1) - pagesize); + Q_ASSERT(quintptr(page3) == quintptr(page2) + pagesize || quintptr(page3) == quintptr(page2) - pagesize); + munmap(page1, pagesize); + munmap(page3, pagesize); + + // populate our page + for (uint i = 0; i < pagesize / sizeof(long long); ++i) + ((long long *)page2)[i] = Q_INT64_C(0x0041004100410041); + + // the following should crash: + //page2[-1] = 0xdead; + //page2[pagesize / sizeof(ushort) + 1] = 0xbeef; + + static const ushort needle[] = { + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41 + }; + + for (int algo = 0; algo < functionCount; ++algo) { + // boundary condition test: + for (int i = 0; i < 8; ++i) { + (func[algo])(page2 + i, needle, sizeof needle / 2); + (func[algo])(page2 - i - 1 - sizeof(needle)/2 + pagesize/2, needle, sizeof needle/2); + } + } + + munmap(page2, pagesize); +#endif + + for (int algo = 0; algo < functionCount; ++algo) { + for (int i = 0; i < stringCollectionCount; ++i) { + const ushort *p1 = stringCollectionData + stringCollection[i].offset1; + const ushort *p2 = stringCollectionData + stringCollection[i].offset2; + bool expected = memcmp(p1, p2, stringCollection[i].len * 2) == 0; + + bool result = (func[algo])(p1, p2, stringCollection[i].len); + if (expected != result) + qWarning().nospace() + << "algo=" << algo + << " i=" << i + << " failed (" << result << "!=" << expected + << "); strings were " + << QByteArray((char*)p1, stringCollection[i].len).toHex() + << " and " + << QByteArray((char*)p2, stringCollection[i].len).toHex(); + } + } +} + +void tst_QString::equals2() const +{ + QFETCH(int, algorithm); + if (algorithm == -1) { + equals2_selftest(); + return; + } + + QBENCHMARK { + for (int i = 0; i < stringCollectionCount; ++i) { + const ushort *p1 = stringCollectionData + stringCollection[i].offset1; + const ushort *p2 = stringCollectionData + stringCollection[i].offset2; + bool result = (func[algorithm])(p1, p2, stringCollection[i].len); + Q_UNUSED(result); + } + } +} + +static int ucstrncmp_shortwise(const ushort *a, const ushort *b, int l) +{ + while (l-- && *a == *b) + a++,b++; + if (l==-1) + return 0; + return *a - *b; +} + +static int ucstrncmp_intwise(const ushort *a, const ushort *b, int len) +{ + // do both strings have the same alignment? + if ((quintptr(a) & 2) == (quintptr(b) & 2)) { + // are we aligned to 4 bytes? + if (quintptr(a) & 2) { + if (*a != *b) + return *a - *b; + ++a; + ++b; + --len; + } + + const uint *p1 = (const uint *)a; + const uint *p2 = (const uint *)b; + quintptr counter = 0; + for ( ; len > 1 ; len -= 2, ++counter) { + if (p1[counter] != p2[counter]) { + // which ushort isn't equal? + int diff = a[2*counter] - b[2*counter]; + return diff ? diff : a[2*counter + 1] - b[2*counter + 1]; + } + } + + return len ? a[2*counter] - b[2*counter] : 0; + } else { + while (len-- && *a == *b) + a++,b++; + if (len==-1) + return 0; + return *a - *b; + } +} + +#ifdef __SSE2__ +static inline int ucstrncmp_short_tail(const ushort *p1, const ushort *p2, int len) +{ + if (len) { + if (*p1 != *p2) + return *p1 - *p2; + if (--len) { + if (p1[1] != p2[1]) + return p1[1] - p2[1]; + if (--len) { + if (p1[2] != p2[2]) + return p1[2] - p2[2]; + if (--len) { + if (p1[3] != p2[3]) + return p1[3] - p2[3]; + if (--len) { + if (p1[4] != p2[4]) + return p1[4] - p2[4]; + if (--len) { + if (p1[5] != p2[5]) + return p1[5] - p2[5]; + if (--len) { + if (p1[6] != p2[6]) + return p1[6] - p2[6]; + return p1[7] - p2[7]; + } + } + } + } + } + } + } + return 0; +} + +static inline int bsf_nonzero(register long val) +{ + int result; +# ifdef Q_CC_GNU + // returns the first non-zero bit on a non-zero reg + asm ("bsf %1, %0" : "=r" (result) : "r" (val)); + return result; +# elif defined(Q_CC_MSVC) + _BitScanForward(&result, val); + return result; +# endif +} + +static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2(const ushort *a, const ushort *b, int len) +{ + qptrdiff counter = 0; + while (len >= 8) { + __m128i m1 = _mm_loadu_si128((__m128i *)(a + counter)); + __m128i m2 = _mm_loadu_si128((__m128i *)(b + counter)); + __m128i cmp = _mm_cmpeq_epi16(m1, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + counter += bsf_nonzero(mask)/2; + return a[counter] - b[counter]; + } + + counter += 8; + len -= 8; + } + return ucstrncmp_short_tail(a + counter, b + counter, len); +} + +static __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2_aligning(const ushort *a, const ushort *b, int len) +{ + if (len >= 8) { + __m128i m1 = _mm_loadu_si128((__m128i *)a); + __m128i m2 = _mm_loadu_si128((__m128i *)b); + __m128i cmp = _mm_cmpeq_epi16(m1, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + int counter = bsf_nonzero(mask)/2; + return a[counter] - b[counter]; + } + + + // now align to do 16-byte loads + int diff = 8 - (quintptr(a) & 0xf)/2; + len -= diff; + a += diff; + b += diff; + } + + qptrdiff counter = 0; + while (len >= 8) { + __m128i m1 = _mm_load_si128((__m128i *)(a + counter)); + __m128i m2 = _mm_loadu_si128((__m128i *)(b + counter)); + __m128i cmp = _mm_cmpeq_epi16(m1, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + counter += bsf_nonzero(mask)/2; + return a[counter] - b[counter]; + } + + counter += 8; + len -= 8; + } + return ucstrncmp_short_tail(a + counter, b + counter, len); +} + +static inline __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_sse2_aligned(const ushort *a, const ushort *b, int len) +{ + quintptr counter = 0; + while (len >= 8) { + __m128i m1 = _mm_load_si128((__m128i *)(a + counter)); + __m128i m2 = _mm_load_si128((__m128i *)(b + counter)); + __m128i cmp = _mm_cmpeq_epi16(m1, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + counter += bsf_nonzero(mask)/2; + return a[counter] - b[counter]; + } + + counter += 8; + len -= 8; + } + return ucstrncmp_short_tail(a + counter, b + counter, len); +} + +static inline __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_ssse3_alignr_aligned(const ushort *a, const ushort *b, int len) +{ + quintptr counter = 0; + while (len >= 8) { + __m128i m1 = _mm_load_si128((__m128i *)(a + counter)); + __m128i m2 = _mm_lddqu_si128((__m128i *)(b + counter)); + __m128i cmp = _mm_cmpeq_epi16(m1, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + counter += bsf_nonzero(mask)/2; + return a[counter] - b[counter]; + } + + counter += 8; + len -= 8; + } + return ucstrncmp_short_tail(a + counter, b + counter, len); +} + + +typedef __m128i (* MMLoadFunction)(const __m128i *); +template<int N, MMLoadFunction LoadFunction> +static inline __attribute__((optimize("no-unroll-loops"))) int ucstrncmp_ssse3_alignr(const ushort *a, const ushort *b, int len) +{ + qptrdiff counter = 0; + __m128i lower, upper; + upper = _mm_load_si128((__m128i *)a); + + do { + lower = upper; + upper = _mm_load_si128((__m128i *)(a + counter) + 1); + __m128i merged = _mm_alignr_epi8(upper, lower, N); + + __m128i m2 = LoadFunction((__m128i *)(b + counter)); + __m128i cmp = _mm_cmpeq_epi16(merged, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + counter += bsf_nonzero(mask)/2; + return a[counter + N/2] - b[counter]; + } + + counter += 8; + len -= 8; + } while (len >= 8); + + return ucstrncmp_short_tail(a + counter + N/2, b + counter, len); +} + +static int ucstrncmp_ssse3(const ushort *a, const ushort *b, int len) +{ + if (len >= 8) { + int val = quintptr(a) & 0xf; + a -= val/2; + + if (val == 10) + return ucstrncmp_ssse3_alignr<10, _mm_lddqu_si128>(a, b, len); + else if (val == 2) + return ucstrncmp_ssse3_alignr<2, _mm_lddqu_si128>(a, b, len); + if (val < 8) { + if (val < 4) + return ucstrncmp_ssse3_alignr_aligned(a, b, len); + else if (val == 4) + return ucstrncmp_ssse3_alignr<4, _mm_lddqu_si128>(a, b, len); + else + return ucstrncmp_ssse3_alignr<6, _mm_lddqu_si128>(a, b, len); + } else { + if (val < 12) + return ucstrncmp_ssse3_alignr<8, _mm_lddqu_si128>(a, b, len); + else if (val == 12) + return ucstrncmp_ssse3_alignr<12, _mm_lddqu_si128>(a, b, len); + else + return ucstrncmp_ssse3_alignr<14, _mm_lddqu_si128>(a, b, len); + } + } + return ucstrncmp_short_tail(a, b, len); +} + +static int ucstrncmp_ssse3_aligning(const ushort *a, const ushort *b, int len) +{ + if (len >= 8) { + __m128i m1 = _mm_loadu_si128((__m128i *)a); + __m128i m2 = _mm_loadu_si128((__m128i *)b); + __m128i cmp = _mm_cmpeq_epi16(m1, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + int counter = bsf_nonzero(mask)/2; + return a[counter] - b[counter]; + } + + + // now 'b' align to do 16-byte loads + int diff = 8 - (quintptr(b) & 0xf)/2; + len -= diff; + a += diff; + b += diff; + } + + if (len < 8) + return ucstrncmp_short_tail(a, b, len); + + // 'b' is aligned + int val = quintptr(a) & 0xf; + a -= val/2; + + if (val == 8) + return ucstrncmp_ssse3_alignr<8, _mm_load_si128>(a, b, len); + else if (val == 0) + return ucstrncmp_sse2_aligned(a, b, len); + if (val < 8) { + if (val < 4) + return ucstrncmp_ssse3_alignr<2, _mm_load_si128>(a, b, len); + else if (val == 4) + return ucstrncmp_ssse3_alignr<4, _mm_load_si128>(a, b, len); + else + return ucstrncmp_ssse3_alignr<6, _mm_load_si128>(a, b, len); + } else { + if (val < 12) + return ucstrncmp_ssse3_alignr<10, _mm_load_si128>(a, b, len); + else if (val == 12) + return ucstrncmp_ssse3_alignr<12, _mm_load_si128>(a, b, len); + else + return ucstrncmp_ssse3_alignr<14, _mm_load_si128>(a, b, len); + } +} + +static inline __attribute__((optimize("no-unroll-loops"))) +int ucstrncmp_ssse3_aligning2_aligned(const ushort *a, const ushort *b, int len, int garbage) +{ + // len >= 8 + __m128i m1 = _mm_load_si128((const __m128i *)a); + __m128i m2 = _mm_load_si128((const __m128i *)b); + __m128i cmp = _mm_cmpeq_epi16(m1, m2); + int mask = short(_mm_movemask_epi8(cmp)); // force sign extension + mask >>= garbage; + if (~mask) { + // which ushort isn't equal? + uint counter = (garbage + bsf_nonzero(~mask)); + return a[counter/2] - b[counter/2]; + } + + // the first 16-garbage bytes (8-garbage/2 ushorts) were equal + len -= 8 - garbage/2; + return ucstrncmp_sse2_aligned(a + 8, b + 8, len); +} + +template<int N> static inline __attribute__((optimize("no-unroll-loops"),always_inline)) +int ucstrncmp_ssse3_aligning2_alignr(const ushort *a, const ushort *b, int len, int garbage) +{ + // len >= 8 + __m128i lower, upper, merged; + lower = _mm_load_si128((const __m128i*)a); + upper = _mm_load_si128((const __m128i*)(a + 8)); + merged = _mm_alignr_epi8(upper, lower, N); + + __m128i m2 = _mm_load_si128((const __m128i*)b); + __m128i cmp = _mm_cmpeq_epi16(merged, m2); + int mask = short(_mm_movemask_epi8(cmp)); // force sign extension + mask >>= garbage; + if (~mask) { + // which ushort isn't equal? + uint counter = (garbage + bsf_nonzero(~mask)); + return a[counter/2 + N/2] - b[counter/2]; + } + + // the first 16-garbage bytes (8-garbage/2 ushorts) were equal + quintptr counter = 8; + len -= 8 - garbage/2; + while (len >= 8) { + lower = upper; + upper = _mm_load_si128((__m128i *)(a + counter) + 1); + merged = _mm_alignr_epi8(upper, lower, N); + + m2 = _mm_load_si128((__m128i *)(b + counter)); + cmp = _mm_cmpeq_epi16(merged, m2); + ushort mask = ~uint(_mm_movemask_epi8(cmp)); + if (mask) { + // which ushort isn't equal? + counter += bsf_nonzero(mask)/2; + return a[counter + N/2] - b[counter]; + } + + counter += 8; + len -= 8; + } + + return ucstrncmp_short_tail(a + counter + N/2, b + counter, len); +} + +static inline int conditional_invert(int result, bool invert) +{ + if (invert) + return -result; + return result; +} + +static int ucstrncmp_ssse3_aligning2(const ushort *a, const ushort *b, int len) +{ + // Different strategy from above: instead of doing two unaligned loads + // when trying to align, we'll only do aligned loads and round down the + // addresses of a and b. This means the first load will contain garbage + // in the beginning of the string, which we'll shift out of the way + // (after _mm_movemask_epi8) + + if (len < 8) + return ucstrncmp_intwise(a, b, len); + + // both a and b are misaligned + // we'll call the alignr function with the alignment *difference* between the two + int offset = (quintptr(a) & 0xf) - (quintptr(b) & 0xf); + if (offset >= 0) { + // from this point on, b has the shortest alignment + // and align(a) = align(b) + offset + // round down the alignment so align(b) == align(a) == 0 + int garbage = (quintptr(b) & 0xf); + a = (const ushort*)(quintptr(a) & ~0xf); + b = (const ushort*)(quintptr(b) & ~0xf); + + // now the first load of b will load 'garbage' extra bytes + // and the first load of a will load 'garbage + offset' extra bytes + if (offset == 8) + return ucstrncmp_ssse3_aligning2_alignr<8>(a, b, len, garbage); + if (offset == 0) + return ucstrncmp_ssse3_aligning2_aligned(a, b, len, garbage); + if (offset < 8) { + if (offset < 4) + return ucstrncmp_ssse3_aligning2_alignr<2>(a, b, len, garbage); + else if (offset == 4) + return ucstrncmp_ssse3_aligning2_alignr<4>(a, b, len, garbage); + else + return ucstrncmp_ssse3_aligning2_alignr<6>(a, b, len, garbage); + } else { + if (offset < 12) + return ucstrncmp_ssse3_aligning2_alignr<10>(a, b, len, garbage); + else if (offset == 12) + return ucstrncmp_ssse3_aligning2_alignr<12>(a, b, len, garbage); + else + return ucstrncmp_ssse3_aligning2_alignr<14>(a, b, len, garbage); + } + } else { + // same as above but inverted + int garbage = (quintptr(a) & 0xf); + a = (const ushort*)(quintptr(a) & ~0xf); + b = (const ushort*)(quintptr(b) & ~0xf); + + offset = -offset; + if (offset == 8) + return -ucstrncmp_ssse3_aligning2_alignr<8>(b, a, len, garbage); + if (offset < 8) { + if (offset < 4) + return -ucstrncmp_ssse3_aligning2_alignr<2>(b, a, len, garbage); + else if (offset == 4) + return -ucstrncmp_ssse3_aligning2_alignr<4>(b, a, len, garbage); + else + return -ucstrncmp_ssse3_aligning2_alignr<6>(b, a, len, garbage); + } else { + if (offset < 12) + return -ucstrncmp_ssse3_aligning2_alignr<10>(b, a, len, garbage); + else if (offset == 12) + return -ucstrncmp_ssse3_aligning2_alignr<12>(b, a, len, garbage); + else + return -ucstrncmp_ssse3_aligning2_alignr<14>(b, a, len, garbage); + } + } +} + +#endif + +typedef int (* UcstrncmpFunction)(const ushort *, const ushort *, int); +Q_DECLARE_METATYPE(UcstrncmpFunction) + +void tst_QString::ucstrncmp_data() const +{ + QTest::addColumn<UcstrncmpFunction>("function"); + QTest::newRow("selftest") << UcstrncmpFunction(0); + QTest::newRow("shortwise") << &ucstrncmp_shortwise; + QTest::newRow("intwise") << &ucstrncmp_intwise; +#ifdef __SSE2__ + QTest::newRow("sse2") << &ucstrncmp_sse2; + QTest::newRow("sse2_aligning") << &ucstrncmp_sse2_aligning; +#ifdef __SSSE3__ + QTest::newRow("ssse3") << &ucstrncmp_ssse3; + QTest::newRow("ssse3_aligning") << &ucstrncmp_ssse3_aligning; + QTest::newRow("ssse3_aligning2") << &ucstrncmp_ssse3_aligning2; +#endif +#endif +} + +void tst_QString::ucstrncmp() const +{ + QFETCH(UcstrncmpFunction, function); + if (!function) { + static const UcstrncmpFunction func[] = { + &ucstrncmp_shortwise, + &ucstrncmp_intwise, +#ifdef __SSE2__ + &ucstrncmp_sse2, + &ucstrncmp_sse2_aligning, +#ifdef __SSSE3__ + &ucstrncmp_ssse3, + &ucstrncmp_ssse3_aligning, + &ucstrncmp_ssse3_aligning2 +#endif +#endif + }; + static const int functionCount = sizeof func / sizeof func[0]; + +#ifdef Q_OS_UNIX + const long pagesize = sysconf(_SC_PAGESIZE); + void *page1, *page3; + ushort *page2; + page1 = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + page2 = (ushort *)mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0); + page3 = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + Q_ASSERT(quintptr(page2) == quintptr(page1) + pagesize || quintptr(page2) == quintptr(page1) - pagesize); + Q_ASSERT(quintptr(page3) == quintptr(page2) + pagesize || quintptr(page3) == quintptr(page2) - pagesize); + munmap(page1, pagesize); + munmap(page3, pagesize); + + // populate our page + for (uint i = 0; i < pagesize / sizeof(long long); ++i) + ((long long *)page2)[i] = Q_INT64_C(0x0041004100410041); + + // the following should crash: + //page2[-1] = 0xdead; + //page2[pagesize / sizeof(ushort) + 1] = 0xbeef; + + static const ushort needle[] = { + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41 + }; + + for (int algo = 0; algo < functionCount; ++algo) { + // boundary condition test: + for (int i = 0; i < 8; ++i) { + (func[algo])(page2 + i, needle, sizeof needle / 2); + (func[algo])(page2 - i - 1 - sizeof(needle)/2 + pagesize/2, needle, sizeof needle/2); + } + } + + munmap(page2, pagesize); +#endif + + for (int algo = 0; algo < functionCount; ++algo) { + for (int i = 0; i < stringCollectionCount; ++i) { + const ushort *p1 = stringCollectionData + stringCollection[i].offset1; + const ushort *p2 = stringCollectionData + stringCollection[i].offset2; + int expected = ucstrncmp_shortwise(p1, p2, stringCollection[i].len); + expected = qBound(-1, expected, 1); + + int result = (func[algo])(p1, p2, stringCollection[i].len); + result = qBound(-1, result, 1); + if (expected != result) + qWarning().nospace() + << "algo=" << algo + << " i=" << i + << " failed (" << result << "!=" << expected + << "); strings were " + << QByteArray((char*)p1, stringCollection[i].len).toHex() + << " and " + << QByteArray((char*)p2, stringCollection[i].len).toHex(); + } + } + return; + } + + QBENCHMARK { + for (int i = 0; i < stringCollectionCount; ++i) { + const ushort *p1 = stringCollectionData + stringCollection[i].offset1; + const ushort *p2 = stringCollectionData + stringCollection[i].offset2; + (function)(p1, p2, stringCollection[i].len); + } + } +} + void tst_QString::fromUtf8() const { QFile file(SRCDIR "utf-8.txt"); diff --git a/tests/benchmarks/corelib/tools/qstring/qstring.pro b/tests/benchmarks/corelib/tools/qstring/qstring.pro index fa4310e..e8720e1 100644 --- a/tests/benchmarks/corelib/tools/qstring/qstring.pro +++ b/tests/benchmarks/corelib/tools/qstring/qstring.pro @@ -1,7 +1,7 @@ load(qttest_p4) TARGET = tst_bench_qstring QT -= gui -SOURCES += main.cpp +SOURCES += main.cpp data.cpp wince*:{ DEFINES += SRCDIR=\\\"\\\" @@ -14,3 +14,6 @@ wince*:{ DEFINES += SRCDIR=\\\"$$PWD/\\\" } +sse4:QMAKE_CXXFLAGS += -msse4 +else:ssse3:QMAKE_FLAGS += -mssse3 +else:sse2:QMAKE_CXXFLAGS += -msse2 |