WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
224733
Refactor sorted array mapping machinery in LocaleToScriptMapping.cpp for reuse elsewhere
https://bugs.webkit.org/show_bug.cgi?id=224733
Summary
Refactor sorted array mapping machinery in LocaleToScriptMapping.cpp for reus...
Darin Adler
Reported
2021-04-18 12:24:38 PDT
Refactor sorted array mapping machinery in LocaleToScriptMapping.cpp for reuse elsewhere
Attachments
Patch
(17.25 KB, patch)
2021-04-18 12:30 PDT
,
Darin Adler
no flags
Details
Formatted Diff
Diff
Patch
(22.55 KB, patch)
2021-04-18 15:22 PDT
,
Darin Adler
ews-feeder
: commit-queue-
Details
Formatted Diff
Diff
Patch
(21.18 KB, patch)
2021-04-18 15:31 PDT
,
Darin Adler
ews-feeder
: commit-queue-
Details
Formatted Diff
Diff
Patch
(26.29 KB, patch)
2021-04-18 16:15 PDT
,
Darin Adler
ews-feeder
: commit-queue-
Details
Formatted Diff
Diff
Patch
(26.30 KB, patch)
2021-04-18 16:25 PDT
,
Darin Adler
no flags
Details
Formatted Diff
Diff
Patch
(30.34 KB, patch)
2021-04-19 10:02 PDT
,
Darin Adler
ysuzuki
: review+
Details
Formatted Diff
Diff
Show Obsolete
(5)
View All
Add attachment
proposed patch, testcase, etc.
Darin Adler
Comment 1
2021-04-18 12:30:27 PDT
Created
attachment 426382
[details]
Patch
Yusuke Suzuki
Comment 2
2021-04-18 12:45:48 PDT
Comment on
attachment 426382
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=426382&action=review
> Source/WebCore/platform/text/LocaleToScriptMapping.cpp:231 > + static const SortedArrayMap map { scriptNameCodeList };
Can we make it constexpr? This map becomes runtime constructed one so that this cannot be used in multithreaded case without call_once and LazyMeverDestroyed.
Darin Adler
Comment 3
2021-04-18 13:18:54 PDT
Comment on
attachment 426382
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=426382&action=review
>> Source/WebCore/platform/text/LocaleToScriptMapping.cpp:231 >> + static const SortedArrayMap map { scriptNameCodeList }; > > Can we make it constexpr? This map becomes runtime constructed one so that this cannot be used in multithreaded case without call_once and LazyMeverDestroyed.
That might be difficult: 1) I don’t think I can use references or pointers in constexpr code, but maybe I can figure it out. 2) We want to run one-time code to check the sorting and uniqueness of keys in the map in debug builds when this is constructed. Not sure I can do that in a constexpr constructor. Your point about making sure it’s thread-safe is a good one. I am looking for a good solution. Would appreciate your advice if you have ideas.
Darin Adler
Comment 4
2021-04-18 13:46:22 PDT
Maybe I can make it constexpr with the array as a deduced template argument? If I could, then I could use call_once in the constructor to do the one-time sorted checking. But I don’t think template arguments can be arrays of such complex types.
Darin Adler
Comment 5
2021-04-18 14:09:21 PDT
(In reply to Darin Adler from
comment #3
)
> 2) We want to run one-time code to check the sorting and uniqueness of keys > in the map in debug builds when this is constructed. Not sure I can do that > in a constexpr constructor.
C++20 has constexpr std::is_sorted; we could check the sorting at compile time if we had that.
Darin Adler
Comment 6
2021-04-18 14:09:50 PDT
Hope that wouldn't make us compile too slowly, but it would be nice!
Darin Adler
Comment 7
2021-04-18 15:22:54 PDT
Created
attachment 426385
[details]
Patch
Darin Adler
Comment 8
2021-04-18 15:24:40 PDT
New version of the patch solves the thread safety problem by not using globals for SortedArrayMap objects, which are simple adapters. Still probably doesn't have includes right for non-unified builds. Also used this in one place in WebKit as a test for wider applicability. Backed off using KeyValuePair. Even though the member names are much nicer, std::pair handles generic programming much better, and it would be considerable work to fix KeyValuePair to remedy those problems. Yusuke, hoping for more feedback from you.
Darin Adler
Comment 9
2021-04-18 15:31:39 PDT
Created
attachment 426386
[details]
Patch
Darin Adler
Comment 10
2021-04-18 16:15:59 PDT
Created
attachment 426387
[details]
Patch
Darin Adler
Comment 11
2021-04-18 16:25:47 PDT
Created
attachment 426388
[details]
Patch
Yusuke Suzuki
Comment 12
2021-04-18 23:08:44 PDT
Comment on
attachment 426382
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=426382&action=review
>>> Source/WebCore/platform/text/LocaleToScriptMapping.cpp:231 >>> + static const SortedArrayMap map { scriptNameCodeList }; >> >> Can we make it constexpr? This map becomes runtime constructed one so that this cannot be used in multithreaded case without call_once and LazyMeverDestroyed. > > That might be difficult: > > 1) I don’t think I can use references or pointers in constexpr code, but maybe I can figure it out. > > 2) We want to run one-time code to check the sorting and uniqueness of keys in the map in debug builds when this is constructed. Not sure I can do that in a constexpr constructor. > > Your point about making sure it’s thread-safe is a good one. I am looking for a good solution. Would appreciate your advice if you have ideas.
1) We can use references in constexpr! 2) If we construct it in constexpr, then it is called only at compile-time, and one time per map since we are putting it in cpp file. I've tried making it constexpr by implementing adjacent_find and is_sorted for constexpr (since it becomes constexpr only after C++20 unfortunately. But I think adding an implementation for this debug purpose would be nice since the function is fairly small). And I've ensured that this can be a constexpr :) I think this is really nice: it becomes compile-error when the conditions are not met :D There are several notes. 1. After C++17, lambda can be a constexpr! So we can use lambda in constexpr freely :D 2. After C++17, std::begin and std::end are constexpr so we can use it too! 75 template<typename Iterator, typename Predicate> 76 constexpr Iterator adjacentFindConstexpr(Iterator begin, Iterator end, Predicate predicate) 77 { 78 if (begin == end) 79 return end; 80 auto current = begin; 81 auto previous = current; 82 ++current; 83 while (current != end) { 84 if (predicate(*previous, *current)) 85 return previous; 86 previous = current; 87 ++current; 88 } 89 return end; 90 } 91 92 template<typename Iterator, typename Predicate> 93 constexpr bool isSortedConstexpr(Iterator begin, Iterator end, Predicate predicate) 94 { 95 return adjacentFindConstexpr(begin, end, [&](auto& a, auto& b) { 96 return !predicate(a, b); 97 }) == end; 98 } 99 100 template<typename ArrayType> 101 constexpr SortedArrayMap<ArrayType>::SortedArrayMap(const ArrayType& array) 102 : m_array { array } 103 { 104 ASSERT_UNDER_CONSTEXPR_CONTEXT(isSortedConstexpr(std::begin(array), std::end(array), [] (auto& a, auto b) { 105 return a.first < b.first; 106 })); 107 ASSERT_UNDER_CONSTEXPR_CONTEXT(adjacentFindConstexpr(std::begin(array), std::end(array), [] (auto& a, auto& b) { 108 return a.first == b.first; 109 }) == std::end(array)); 110 } And using it via, 39 static constexpr std::pair<unsigned, unsigned> test[] = { 40 { 0, 0 }, 41 { 1, 1 }, 42 }; 43 44 static constexpr SortedArrayMap mapping { test }; This completely works! L44 does not specify array type in SortedArrayMap<XXX>'s XXX place since we can leverage C++17 template type deduction! This avoids writing array-size explicitly, so everything works well without specifying size etc...
Yusuke Suzuki
Comment 13
2021-04-18 23:11:28 PDT
Comment on
attachment 426382
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=426382&action=review
>>>> Source/WebCore/platform/text/LocaleToScriptMapping.cpp:231 >>>> + static const SortedArrayMap map { scriptNameCodeList }; >>> >>> Can we make it constexpr? This map becomes runtime constructed one so that this cannot be used in multithreaded case without call_once and LazyMeverDestroyed. >> >> That might be difficult: >> >> 1) I don’t think I can use references or pointers in constexpr code, but maybe I can figure it out. >> >> 2) We want to run one-time code to check the sorting and uniqueness of keys in the map in debug builds when this is constructed. Not sure I can do that in a constexpr constructor. >> >> Your point about making sure it’s thread-safe is a good one. I am looking for a good solution. Would appreciate your advice if you have ideas. > > 1) We can use references in constexpr! > 2) If we construct it in constexpr, then it is called only at compile-time, and one time per map since we are putting it in cpp file. > > I've tried making it constexpr by implementing adjacent_find and is_sorted for constexpr (since it becomes constexpr only after C++20 unfortunately. But I think adding an implementation for this debug purpose would be nice since the function is fairly small). > And I've ensured that this can be a constexpr :) > I think this is really nice: it becomes compile-error when the conditions are not met :D > > There are several notes. > > 1. After C++17, lambda can be a constexpr! So we can use lambda in constexpr freely :D > 2. After C++17, std::begin and std::end are constexpr so we can use it too! > > > 75 template<typename Iterator, typename Predicate> > 76 constexpr Iterator adjacentFindConstexpr(Iterator begin, Iterator end, Predicate predicate) > 77 { > 78 if (begin == end) > 79 return end; > 80 auto current = begin; > 81 auto previous = current; > 82 ++current; > 83 while (current != end) { > 84 if (predicate(*previous, *current)) > 85 return previous; > 86 previous = current; > 87 ++current; > 88 } > 89 return end; > 90 } > 91 > 92 template<typename Iterator, typename Predicate> > 93 constexpr bool isSortedConstexpr(Iterator begin, Iterator end, Predicate predicate) > 94 { > 95 return adjacentFindConstexpr(begin, end, [&](auto& a, auto& b) { > 96 return !predicate(a, b); > 97 }) == end; > 98 } > 99 > 100 template<typename ArrayType> > 101 constexpr SortedArrayMap<ArrayType>::SortedArrayMap(const ArrayType& array) > 102 : m_array { array } > 103 { > 104 ASSERT_UNDER_CONSTEXPR_CONTEXT(isSortedConstexpr(std::begin(array), std::end(array), [] (auto& a, auto b) { > 105 return a.first < b.first; > 106 })); > 107 ASSERT_UNDER_CONSTEXPR_CONTEXT(adjacentFindConstexpr(std::begin(array), std::end(array), [] (auto& a, auto& b) { > 108 return a.first == b.first; > 109 }) == std::end(array)); > 110 } > > And using it via, > > 39 static constexpr std::pair<unsigned, unsigned> test[] = { > 40 { 0, 0 }, > 41 { 1, 1 }, > 42 }; > 43 > 44 static constexpr SortedArrayMap mapping { test }; > > This completely works! L44 does not specify array type in SortedArrayMap<XXX>'s XXX place since we can leverage C++17 template type deduction! > This avoids writing array-size explicitly, so everything works well without specifying size etc...
And if we use something like, 39 static constexpr std::pair<unsigned, unsigned> test[] = { 40 { 1, 0 }, 41 { 1, 1 }, 42 }; 43 44 static constexpr SortedArrayMap mapping { test }; We can get awesome compile-error since this doesn't meet sorted array's ASSERT_UNDER_CONSTEXPR_CONTEXT. /Volumes/Data/OpenSource/Source/WTF/wtf/SortedArrayMap.cpp:44:33: error: constexpr variable 'mapping' must be initialized by a constant expression static constexpr SortedArrayMap mapping { test }; ^~~~~~~~~~~~~~~~ In file included from /Volumes/Data/OpenSource/Source/WTF/wtf/SortedArrayMap.cpp:28: /Volumes/Data/OpenSource/Source/WTF/wtf/SortedArrayMap.h:104:5: note: non-constexpr function 'WTFReportAssertionFailure' cannot be used in a constant expression ASSERT_UNDER_CONSTEXPR_CONTEXT(isSortedConstexpr(std::begin(array), std::end(array), [] (auto& a, auto b) { ^ In file included from /Volumes/Data/OpenSource/Source/WTF/wtf/SortedArrayMap.cpp:27: In file included from /Volumes/Data/OpenSource/Source/WTF/config.h:31: In file included from /Volumes/Data/OpenSource/WebKitBuild/Debug/usr/local/include/wtf/FastMalloc.h:26: In file included from /Volumes/Data/OpenSource/WebKitBuild/Debug/usr/local/include/wtf/StdLibExtras.h:32: /Volumes/Data/OpenSource/WebKitBuild/Debug/usr/local/include/wtf/Assertions.h:354:9: note: expanded from macro 'ASSERT_UNDER_CONSTEXPR_CONTEXT' WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \ ^ /Volumes/Data/OpenSource/Source/WTF/wtf/SortedArrayMap.cpp:44:33: note: in call to 'SortedArrayMap(test)' static constexpr SortedArrayMap mapping { test }; ^ In file included from /Volumes/Data/OpenSource/Source/WTF/wtf/SortedArrayMap.cpp:27: In file included from /Volumes/Data/OpenSource/Source/WTF/config.h:31: In file included from /Volumes/Data/OpenSource/WebKitBuild/Debug/usr/local/include/wtf/FastMalloc.h:26: In file included from /Volumes/Data/OpenSource/WebKitBuild/Debug/usr/local/include/wtf/StdLibExtras.h:32: /Volumes/Data/OpenSource/WebKitBuild/Debug/usr/local/include/wtf/Assertions.h:204:25: note: declared here WTF_EXPORT_PRIVATE void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion); ^ 1 error generated. ** BUILD FAILED **
Darin Adler
Comment 14
2021-04-19 09:24:54 PDT
Thanks for the encouragement, and for the constexpr implementations of is_sorted and adjacent_find.
Darin Adler
Comment 15
2021-04-19 10:02:38 PDT
Created
attachment 426438
[details]
Patch
Darin Adler
Comment 16
2021-04-19 14:46:14 PDT
Yusuke, took all your suggestions and now this seems ready to go! Would you be willing to review?
Yusuke Suzuki
Comment 17
2021-04-19 14:56:27 PDT
Comment on
attachment 426438
[details]
Patch r=me!
Darin Adler
Comment 18
2021-04-20 07:48:14 PDT
Committed
r276303
(
236785@main
): <
https://commits.webkit.org/236785@main
>
Ling Ho
Comment 19
2021-04-23 02:50:08 PDT
rdar://76898173
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug