Rename AtomicString to AtomString
[WebKit-https.git] / Source / WTF / wtf / text / LineBreakIteratorPoolICU.h
1 /*
2  * Copyright (C) 2011 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #include <unicode/uloc.h>
29 #include <wtf/HashMap.h>
30 #include <wtf/NeverDestroyed.h>
31 #include <wtf/ThreadSpecific.h>
32 #include <wtf/text/AtomString.h>
33
34 namespace WTF {
35
36 class LineBreakIteratorPool {
37     WTF_MAKE_NONCOPYABLE(LineBreakIteratorPool);
38 public:
39     LineBreakIteratorPool() = default;
40
41     static LineBreakIteratorPool& sharedPool()
42     {
43         static NeverDestroyed<WTF::ThreadSpecific<LineBreakIteratorPool>> pool;
44         return *pool.get();
45     }
46
47     static AtomString makeLocaleWithBreakKeyword(const AtomString& locale, LineBreakIteratorMode mode)
48     {
49         // The uloc functions model locales as char*, so we have to downconvert our AtomString.
50         auto utf8Locale = locale.string().utf8();
51         if (!utf8Locale.length())
52             return locale;
53         Vector<char> scratchBuffer(utf8Locale.length() + 11, 0);
54         memcpy(scratchBuffer.data(), utf8Locale.data(), utf8Locale.length());
55
56         const char* keywordValue = nullptr;
57         switch (mode) {
58         case LineBreakIteratorMode::Default:
59             // nullptr will cause any existing values to be removed.
60             break;
61         case LineBreakIteratorMode::Loose:
62             keywordValue = "loose";
63             break;
64         case LineBreakIteratorMode::Normal:
65             keywordValue = "normal";
66             break;
67         case LineBreakIteratorMode::Strict:
68             keywordValue = "strict";
69             break;
70         }
71
72         UErrorCode status = U_ZERO_ERROR;
73         int32_t lengthNeeded = uloc_setKeywordValue("lb", keywordValue, scratchBuffer.data(), scratchBuffer.size(), &status);
74         if (U_SUCCESS(status))
75             return AtomString::fromUTF8(scratchBuffer.data(), lengthNeeded);
76         if (status == U_BUFFER_OVERFLOW_ERROR) {
77             scratchBuffer.grow(lengthNeeded + 1);
78             memset(scratchBuffer.data() + utf8Locale.length(), 0, scratchBuffer.size() - utf8Locale.length());
79             status = U_ZERO_ERROR;
80             int32_t lengthNeeded2 = uloc_setKeywordValue("lb", keywordValue, scratchBuffer.data(), scratchBuffer.size(), &status);
81             if (!U_SUCCESS(status) || lengthNeeded != lengthNeeded2)
82                 return locale;
83             return AtomString::fromUTF8(scratchBuffer.data(), lengthNeeded);
84         }
85         return locale;
86     }
87
88     UBreakIterator* take(const AtomString& locale, LineBreakIteratorMode mode)
89     {
90         auto localeWithOptionalBreakKeyword = makeLocaleWithBreakKeyword(locale, mode);
91
92         UBreakIterator* iterator = nullptr;
93         for (size_t i = 0; i < m_pool.size(); ++i) {
94             if (m_pool[i].first == localeWithOptionalBreakKeyword) {
95                 iterator = m_pool[i].second;
96                 m_pool.remove(i);
97                 break;
98             }
99         }
100
101         if (!iterator) {
102             iterator = openLineBreakIterator(localeWithOptionalBreakKeyword);
103             if (!iterator)
104                 return nullptr;
105         }
106
107         ASSERT(!m_vendedIterators.contains(iterator));
108         m_vendedIterators.add(iterator, localeWithOptionalBreakKeyword);
109         return iterator;
110     }
111
112     void put(UBreakIterator* iterator)
113     {
114         ASSERT(m_vendedIterators.contains(iterator));
115         if (m_pool.size() == capacity) {
116             closeLineBreakIterator(m_pool[0].second);
117             m_pool.remove(0);
118         }
119         m_pool.uncheckedAppend({ m_vendedIterators.take(iterator), iterator });
120     }
121
122 private:
123     static constexpr size_t capacity = 4;
124
125     Vector<std::pair<AtomString, UBreakIterator*>, capacity> m_pool;
126     HashMap<UBreakIterator*, AtomString> m_vendedIterators;
127
128     friend WTF::ThreadSpecific<LineBreakIteratorPool>::operator LineBreakIteratorPool*();
129 };
130
131 }