on master help sign in
Another attempt at toUpper
commit049edb65afd9a6277cc48c5a563a7aba4687e4ea authorBryan O'Sullivan <bos@serpentine.com> dateThu 7 May 2015, 08:40 (11 years ago) parent33cfd89
3 files changed+51−1
Data/Text/Internal/CaseMapping.hs+48 Data/Text/Internal/Fusion/Common.hs+2−1 text.cabal+1
Data/Text/Internal/CaseMapping.hsnew file+48
@@ -0,0 +1,48 @@
1+{-# LANGUAGE ForeignFunctionInterface #-}
2+
3+module Data.Text.Internal.CaseMapping
4+ (
5+ toUpper
6+ ) where
7+
8+import Data.Text.Internal.Unsafe.Char (ord, unsafeChr)
9+import Data.Text.Internal.Unsafe (inlinePerformIO)
10+import Data.Word (Word16)
11+import Foreign.Ptr (Ptr, plusPtr)
12+import Foreign.C.Types (CSize)
13+import Data.Text.Internal.Fusion.Types
14+import Foreign.Storable (peek)
15+import qualified Data.Char as Char
16+
17+search :: Ptr Word16 -> Int -> Word16 -> (Int -> IO a) -> IO a
18+search table len key cont = go 0 (len - 1)
19+ where
20+ go lo hi
21+ | hi < lo = cont (-1)
22+ | otherwise = do
23+ let mid = lo + (hi - lo) `quot` 2
24+ val <- peek (table `plusPtr` mid)
25+ case undefined of
26+ _ | val == key -> cont mid
27+ | val < key -> go (mid + 1) hi
28+ | otherwise -> go lo (mid - 1)
29+
30+toUpper :: Char -> s -> Step (CC s) Char
31+toUpper c s
32+ | c > '\xffff' = Yield (Char.toUpper c) (CC s '\0' '\0')
33+ | otherwise = inlinePerformIO $ do
34+ len <- fromIntegral `fmap` peek toUpperLen
35+ search toUpperKeys len (fromIntegral (ord c)) $ \idx -> do
36+ if (idx == -1)
37+ then return $ Yield (Char.toUpper c) (CC s '\0' '\0')
38+ else do
39+ let ptr = toUpperValues `plusPtr` (idx * 12)
40+ x <- unsafeChr `fmap` peek ptr
41+ y <- unsafeChr `fmap` peek (ptr `plusPtr` 2)
42+ z <- unsafeChr `fmap` peek (ptr `plusPtr` 4)
43+ return $ Yield x (CC s y z)
44+
45+
46+foreign import ccall "&_hs_text_to_upper_keys" toUpperKeys :: Ptr Word16
47+foreign import ccall "&_hs_text_to_upper_len" toUpperLen :: Ptr CSize
48+foreign import ccall "&_hs_text_to_upper_values" toUpperValues :: Ptr Word16
Data/Text/Internal/Fusion/Common.hs+2−1
@@ -121,6 +121,7 @@ import GHC.Prim (Addr#, chr#, indexCharOffAddr#, ord#)
121121import GHC.Types (Char(..), Int(..))
122122import qualified Data.Char as Char
123123import qualified Data.List as L
124+import qualified Data.Text.Internal.CaseMapping as CaseMapping
124125import qualified Prelude as P
125126
126127singleton :: Char -> Stream Char
@@ -447,7 +448,7 @@ toCaseFold = caseConvert (convert to_case_fold Char.toLower)
447448-- For instance, the German eszett (U+00DF) maps to the two-letter
448449-- sequence SS.
449450toUpper :: Stream Char -> Stream Char
450−toUpper = caseConvert (convert to_upper Char.toUpper)
451+toUpper = caseConvert CaseMapping.toUpper
451452{-# INLINE [0] toUpper #-}
452453
453454-- | /O(n)/ Convert a string to lower case, using simple case
text.cabal+1
@@ -88,6 +88,7 @@ library
8888 Data.Text.Internal.Builder.Functions
8989 Data.Text.Internal.Builder.Int.Digits
9090 Data.Text.Internal.Builder.RealFloat.Functions
91+ Data.Text.Internal.CaseMapping
9192 Data.Text.Internal.Encoding.Fusion
9293 Data.Text.Internal.Encoding.Fusion.Common
9394 Data.Text.Internal.Encoding.Utf16