country 0.2.1 → 0.2.2
raw patch · 15 files changed
+2303/−107 lines, 15 filesdep +bytebuilddep +bytehashdep +byteslicedep ~aesondep ~attoparsecdep ~base
Dependencies added: bytebuild, bytehash, byteslice, compact, contiguous, entropy, gauge, primitive-unlifted, text-short
Dependency ranges changed: aeson, attoparsec, base, bytestring, hashable, primitive, quickcheck-classes, text
Files
- bench/Main.hs +28/−0
- bench/Size.hs +29/−0
- country.cabal +64/−17
- src/Continent.hs +100/−0
- src/Continent/Unsafe.hs +59/−0
- src/Country.hs +53/−49
- src/Country/Identifier.hs +2/−2
- src/Country/Subdivision.hs +122/−0
- src/Country/Unexposed/Alias.hs +0/−5
- src/Country/Unexposed/AlphaTwoPtr.hs +1012/−0
- src/Country/Unexposed/Continents.hs +263/−0
- src/Country/Unexposed/Names.hs +86/−23
- src/Country/Unexposed/Subdivision.hs +331/−0
- src/Country/Unexposed/Util.hs +59/−0
- test/Spec.hs +95/−11
+ bench/Main.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE TypeApplications #-}++import Gauge.Main (defaultMain,bgroup,bench,whnf)+import Data.Text (Text)++import qualified Data.Bytes as Bytes+import qualified Data.List as List+import qualified Data.Text as Text+import qualified Country++main :: IO ()+main = defaultMain+ [ bench "decode" (whnf decodeManyCountries ex1)+ ]++ex1 :: Text+{-# noinline ex1 #-}+ex1 = Text.intercalate+ (Text.singleton '\n')+ (List.map Country.encodeEnglish [minBound..maxBound])++decodeManyCountries :: Text -> Word+{-# noinline decodeManyCountries #-}+decodeManyCountries txt = List.foldl'+ (\acc t -> acc + maybe 0 (fromIntegral . Country.encodeNumeric) (Country.decode t))+ (0 :: Word)+ (Text.split (=='\n') txt)
+ bench/Size.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE TypeApplications #-}++import Country (hashMapUtf8,hashMapUtf16)+import Data.Compact+import Data.Foldable++import qualified Data.List as List+import qualified Country+import qualified Data.Bytes.HashMap.Word as Map++main :: IO ()+main = do+ szUtf8 <- estimateHeapUse hashMapUtf8+ putStrLn ("UTF-8 HashMap Size: " ++ show szUtf8)+ szUtf16 <- estimateHeapUse hashMapUtf16+ putStrLn ("UTF-16 HashMap Size: " ++ show szUtf16)+ putStrLn "UTF-8 HashMap Distribution:"+ forM_ (Map.distribution hashMapUtf8) $ \(bktSz,ct) ->+ putStrLn (show bktSz ++ "," ++ show ct)+ putStrLn ("UTF-8 HashMap Distinct Entropies: " ++ show (Map.distinctEntropies hashMapUtf8))++-- I think this rounds to the nearest 4KB.+estimateHeapUse :: a -> IO Word+estimateHeapUse a = foldlM+ ( \lo i -> do+ w <- compactSized (i * 2000) True a >>= compactSize+ pure (min lo w)+ ) maxBound [1..50]
country.cabal view
@@ -1,5 +1,6 @@+cabal-version: 2.2 name: country-version: 0.2.1+version: 0.2.2 synopsis: Country data type and functions description: The `country` library provides a data type for dealing with@@ -30,7 +31,7 @@ Please open up an issue on github if there is anything you would like to see added. homepage: https://github.com/andrewthad/country#readme-license: BSD3+license: BSD-3-Clause license-file: LICENSE author: Andrew Martin maintainer: andrew.thaddeus@gmail.com@@ -38,47 +39,93 @@ category: Web build-type: Simple extra-source-files: README.md-cabal-version: >=1.10 tested-with: GHC==8.10.1, GHC==8.8.3, GHC==8.6.5, GHC==8.4.4 library hs-source-dirs: src exposed-modules:+ Continent+ Continent.Unsafe Country Country.Identifier+ Country.Subdivision Country.Unsafe other-modules:+ Country.Unexposed.Alias+ Country.Unexposed.AlphaTwoPtr+ Country.Unexposed.Continents Country.Unexposed.Encode.English Country.Unexposed.Names+ Country.Unexposed.Subdivision Country.Unexposed.Trie Country.Unexposed.TrieByte- Country.Unexposed.Alias+ Country.Unexposed.Util build-depends:- base >= 4.9.1.0 && < 4.15- , text >= 1.2 && < 1.3- , bytestring >= 0.10 && < 0.11- , deepseq >= 1.3.0.2 && < 1.5- , primitive >= 0.6.4 && < 0.8- , unordered-containers >= 0.2 && < 0.3- , hashable >= 1.2 && < 1.4- , aeson >= 0.11 && < 1.6- , scientific >= 0.3 && < 0.4- , attoparsec >= 0.13 && < 0.14+ , aeson >=1.2 && <2.1+ , attoparsec >=0.13 && <0.15+ , base >=4.12 && <5+ , bytebuild >=0.3.4 && <0.4+ , bytehash >=0.1 && <0.2+ , byteslice >=0.2.3 && <0.3+ , bytestring >= 0.10 && <0.12+ , contiguous >=0.6.1+ , deepseq >= 1.3.0.2 && <1.5+ , entropy >=0.4.1.5 && <0.5+ , hashable >=1.2 && <1.5+ , primitive >= 0.6.4 && <0.8+ , primitive-unlifted >= 0.1.3 && <1.0+ , scientific >=0.3 && <0.4+ , text >= 1.2 && <1.3+ , text-short >=0.1.3+ , unordered-containers >=0.2 && <0.3 default-language: Haskell2010+ ghc-options: -Wall -O2 test-suite test type: exitcode-stdio-1.0 hs-source-dirs: test main-is: Spec.hs build-depends:- base+ , QuickCheck+ , base+ , byteslice , country+ , primitive+ , quickcheck-classes >=0.6.4 , tasty , tasty-quickcheck- , quickcheck-classes- , QuickCheck+ , text+ , text-short ghc-options: -O2 default-language: Haskell2010++benchmark bench+ type: exitcode-stdio-1.0+ build-depends:+ , country+ , base+ , byteslice+ , bytestring+ , gauge+ , primitive+ , text >=1.2+ ghc-options: -Wall -O2+ default-language: Haskell2010+ hs-source-dirs: bench+ main-is: Main.hs++benchmark bench-size+ type: exitcode-stdio-1.0+ build-depends:+ , country+ , base+ , bytestring+ , compact+ , bytehash+ ghc-options: -Wall -O2+ default-language: Haskell2010+ hs-source-dirs: bench+ main-is: Size.hs source-repository head type: git
+ src/Continent.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-}++module Continent+ ( Continent+ , pattern Africa+ , pattern Asia+ , pattern Antarctica+ , pattern Europe+ , pattern NorthAmerica+ , pattern Oceania+ , pattern SouthAmerica+ -- * Continent Mapping+ , continent+ -- * Name+ , encodeEnglish+ , decodeEnglish+ -- * Two-letter Codes+ , alphaUpper+ , alphaLower+ , decodeAlpha+ ) where++import Continent.Unsafe++import Control.Monad (forM_)+import Control.Monad.ST (runST)+import Country.Unexposed.Continents (continentAList)+import Country.Unexposed.Util (mapTextArray,charToWord16,word16ToInt,timesTwo)+import Country.Unsafe (Country(Country))+import Data.Char (toLower)+import Data.Text (Text)+import Data.Word (Word8)++import qualified Data.Primitive as Prim+import qualified Data.Text as T+import qualified Data.Text.Array as TA+import qualified Data.Text.Internal as TI+++numberOfContinents :: Int+numberOfContinents = length continentNameDb+{-# NOINLINE numberOfContinents #-}+++alphaUpper :: Continent -> Text+alphaUpper (Continent n) = TI.text allAlphaUpper (timesTwo (fromIntegral n)) 2++allAlphaUpper :: TA.Array+allAlphaUpper = TA.run $ do+ m <- TA.new (timesTwo numberOfContinents)+ forM_ continentNameDb $ \(n,_,(a1,a2)) -> do+ let ix = timesTwo (fromIntegral n)+ TA.unsafeWrite m ix (charToWord16 a1)+ TA.unsafeWrite m (ix + 1) (charToWord16 a2)+ return m+{-# NOINLINE allAlphaUpper #-}++alphaLower :: Continent -> Text+alphaLower (Continent n) = TI.text allAlphaLower (timesTwo (fromIntegral n)) 2++allAlphaLower :: TA.Array+allAlphaLower = mapTextArray toLower allAlphaUpper+{-# NOINLINE allAlphaLower #-}++decodeAlpha :: Text -> Maybe Continent+decodeAlpha = fmap Continent . flip lookup tbl . T.toUpper+ where tbl = flip map continentNameDb $ \(n,_,(a,b)) -> ((T.toUpper . T.pack) [a,b], n)++encodeEnglish :: Continent -> Text+encodeEnglish (Continent n) = Prim.indexArray englishContinentNamesText (fromIntegral n)++englishContinentNamesText :: Prim.Array Text+englishContinentNamesText = runST $ do+ m <- Prim.newArray numberOfContinents unnamed+ mapM_ (\(ix,name,_) -> Prim.writeArray m (fromIntegral ix) name) continentNameDb+ Prim.unsafeFreezeArray m+{-# NOINLINE englishContinentNamesText #-}++decodeEnglish :: Text -> Maybe Continent+decodeEnglish = fmap Continent . flip lookup tbl+ where tbl = flip map continentNameDb $ \(n,name,_) -> (name, n)++continent :: Country -> Continent+continent (Country n) = Continent $ Prim.indexArray allContinents (word16ToInt n)++allContinents :: Prim.Array Word8+allContinents = runST $ do+ m <- Prim.newArray numberOfPossibleCodes 255+ forM_ continentAList $ \(ix,Continent n) ->+ Prim.writeArray m (word16ToInt ix) n+ Prim.unsafeFreezeArray m+{-# NOINLINE allContinents #-}++unnamed :: Text+unnamed = "Invalid Continent"+{-# NOINLINE unnamed #-}++numberOfPossibleCodes :: Int+numberOfPossibleCodes = 1000
+ src/Continent/Unsafe.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-}++module Continent.Unsafe+ ( Continent(..)+ , pattern Africa+ , pattern Asia+ , pattern Antarctica+ , pattern Europe+ , pattern NorthAmerica+ , pattern Oceania+ , pattern SouthAmerica+ , continentNameDb+ ) where++import Data.Text (Text)+import Data.Word (Word8)+++newtype Continent = Continent Word8+ deriving(Eq,Ord,Enum)+++{-# COMPLETE Africa, Asia, Antarctica, Europe, NorthAmerica, Oceania, SouthAmerica #-}+pattern Africa, Asia, Antarctica, Europe, NorthAmerica, Oceania, SouthAmerica :: Continent+pattern Africa = Continent 0+pattern Asia = Continent 1+pattern Antarctica = Continent 2+pattern Europe = Continent 3+pattern NorthAmerica = Continent 4+pattern Oceania = Continent 5+pattern SouthAmerica = Continent 6+++continentNameDb :: [(Word8,Text,(Char,Char))]+continentNameDb =+ [ (0, "Africa", ('A', 'F'))+ , (1, "Asia", ('A', 'N'))+ , (2, "Antarctica", ('A', 'S'))+ , (3, "Europe", ('E', 'U'))+ , (4, "North america", ('N', 'A'))+ , (5, "Oceania", ('O', 'C'))+ , (6, "South america", ('S', 'A'))+ ]++instance Bounded Continent where+ minBound = Continent 0+ maxBound = Continent 6++instance Show Continent where+ show Africa = "Africa"+ show Asia = "Asia"+ show Antarctica = "Antarctica"+ show Europe = "Europe"+ show NorthAmerica = "NorthAmerica"+ show Oceania = "Oceania"+ show SouthAmerica = "SouthAmerica"+ show (Continent n) = "Continent " ++ show n
src/Country.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE MagicHash #-} {-# OPTIONS_GHC -Wall #-}@@ -11,42 +12,56 @@ , decodeNumeric -- * Name , encodeEnglish+ , encodeEnglishShort , decode , decodeUtf8+ , decodeUtf8Bytes , parser , parserUtf8 -- * Alpha-2 and Alpha-3 , alphaTwoUpper+ , alphaTwoUpperUtf8Ptr+ , alphaTwoUpperUtf8BoundedBuilder , alphaThreeUpper , alphaThreeLower , alphaTwoLower , decodeAlphaTwo , decodeAlphaThree+ -- * Hash Maps for Decoding+ , hashMapUtf8+ , hashMapUtf16 ) where -import Country.Unsafe (Country(..))+import Control.Monad (forM_)+import Control.Monad.ST (runST)+import Country.Unexposed.AlphaTwoPtr (alphaTwoPtr) import Country.Unexposed.Encode.English (countryNameQuads)-import Country.Unexposed.Names (numberOfPossibleCodes,alphaTwoHashMap,alphaThreeHashMap,decodeMap,decodeMapUtf8,decodeNumeric,encodeEnglish)+import Country.Unexposed.Names (hashMapUtf16,hashMapUtf8)+import Country.Unexposed.Names (numberOfPossibleCodes,alphaTwoHashMap,alphaThreeHashMap,decodeMap,decodeMapUtf8,decodeNumeric,encodeEnglish,encodeEnglishShort) import Country.Unexposed.Trie (Trie,trieFromList,trieParser) import Country.Unexposed.TrieByte (TrieByte,trieByteFromList,trieByteParser)-import Data.Text (Text)+import Country.Unexposed.Util (mapTextArray,charToWord16,word16ToInt,timesTwo,timesThree)+import Country.Unsafe (Country(..))+import Data.Bytes.Types (Bytes(Bytes)) import Data.ByteString (ByteString)-import Data.Word (Word16)+import Data.Char (toLower)+import Data.Coerce (coerce) import Data.Primitive (writeByteArray,indexByteArray,unsafeFreezeByteArray,newByteArray) import Data.Primitive.ByteArray (ByteArray(..))-import GHC.Exts (sizeofByteArray#)-import GHC.Int (Int(..))-import Control.Monad.ST (runST)-import Control.Monad-import Data.Char (ord,chr,toLower)-import Data.Bits (unsafeShiftL,unsafeShiftR)-import Data.Coerce (coerce)+import Data.Primitive.Ptr (indexOffPtr)+import Data.Text (Text)+import Data.Word (Word16)+import Data.Word (Word8)+import Foreign.Ptr (Ptr,plusPtr)++import qualified Data.Attoparsec.ByteString as AB+import qualified Data.Attoparsec.Text as AT+import qualified Data.Bytes.Builder.Bounded.Unsafe as BBU+import qualified Data.Bytes.HashMap.Word as BytesHashMap import qualified Data.HashMap.Strict as HM import qualified Data.Text.Array as TA import qualified Data.Text.Encoding as TE import qualified Data.Text.Internal as TI-import qualified Data.Attoparsec.Text as AT-import qualified Data.Attoparsec.ByteString as AB -- | Convert a country to its numeric code. This is a -- three-digit number and will consequently be less than 1000.@@ -57,6 +72,21 @@ alphaTwoUpper :: Country -> Text alphaTwoUpper c = TI.text allAlphaTwoUpper (timesTwo (indexOfCountry c)) 2 +-- | The alpha-2 country code, uppercase. The resulting address always+-- has two bytes at it.+alphaTwoUpperUtf8Ptr :: Country -> Ptr Word8+alphaTwoUpperUtf8Ptr (Country c) =+ plusPtr alphaTwoPtr (2 * fromIntegral c)++alphaTwoUpperUtf8BoundedBuilder :: Country -> BBU.Builder 2+alphaTwoUpperUtf8BoundedBuilder !c = BBU.construct+ (\arr ix -> do+ let ptr = alphaTwoUpperUtf8Ptr c+ writeByteArray arr ix (indexOffPtr ptr 0)+ writeByteArray arr (ix + 1) (indexOffPtr ptr 1)+ pure (ix + 2)+ )+ -- | The alpha-3 country code, uppercase alphaThreeUpper :: Country -> Text alphaThreeUpper c = TI.text allAlphaThreeUpper (timesThree (indexOfCountry c)) 3@@ -77,29 +107,27 @@ decodeAlphaThree :: Text -> Maybe Country decodeAlphaThree = flip HM.lookup alphaThreeHashMap -half :: Int -> Int-half x = unsafeShiftR x 1 -timesTwo :: Int -> Int-timesTwo x = unsafeShiftL x 1--timesThree :: Int -> Int-timesThree x = x * 3-- -- | Parse a country from its name. This function is language-agnostic -- and is very generous with what it accepts. It handles official -- names, colloquial names, acroynms, and obsolete names for many -- countries. It strives to handle any source language. Open an--- issue on the issue tracker if their are names that are--- missing.+-- issue on the issue tracker if there are names that are missing. decode :: Text -> Maybe Country-decode = flip HM.lookup decodeMap+decode (TI.Text (TA.Array arr) off16 len16) =+ case (BytesHashMap.lookup (Bytes (ByteArray arr) (off16 * 2) (len16 * 2)) hashMapUtf16) of+ Nothing -> Nothing+ Just w -> Just (Country (fromIntegral w)) -- | Decode a 'Country' from a UTF-8-encoded 'ByteString'. decodeUtf8 :: ByteString -> Maybe Country decodeUtf8 = flip HM.lookup decodeMapUtf8 +decodeUtf8Bytes :: Bytes -> Maybe Country+decodeUtf8Bytes !bs = case (BytesHashMap.lookup bs hashMapUtf8) of+ Nothing -> Nothing+ Just w -> Just (Country (fromIntegral w))+ -- | Parse a country from its name using an attoparsec text parser. This -- function is language-agnostic and can handle any source language. -- In the case that one possible country name is a prefix of another@@ -112,15 +140,6 @@ parserUtf8 :: AB.Parser Country parserUtf8 = coerce (trieByteParser decodeTrieUtf8) -word16ToInt :: Word16 -> Int-word16ToInt = fromIntegral--charToWord16 :: Char -> Word16-charToWord16 = fromIntegral . ord--word16ToChar :: Word16 -> Char-word16ToChar = chr . fromIntegral- numberOfCountries :: Int numberOfCountries = length countryNameQuads @@ -169,19 +188,6 @@ allAlphaTwoLower = mapTextArray toLower allAlphaTwoUpper {-# NOINLINE allAlphaTwoLower #-} -mapTextArray :: (Char -> Char) -> TA.Array -> TA.Array-mapTextArray f a@(TA.Array inner) = TA.run $ do- let len = half (I# (sizeofByteArray# inner))- m <- TA.new len- TA.copyI m 0 a 0 len- let go !ix = if ix < len- then do- TA.unsafeWrite m ix (charToWord16 (f (word16ToChar (TA.unsafeIndex a ix))))- go (ix + 1)- else return ()- go 0- return m- decodeTrie :: Trie decodeTrie = trieFromList (map (\(a,Country x) -> (a,x)) (HM.toList decodeMap)) {-# NOINLINE decodeTrie #-}@@ -189,5 +195,3 @@ decodeTrieUtf8 :: TrieByte decodeTrieUtf8 = trieByteFromList (map (\(a,Country x) -> (TE.encodeUtf8 a,x)) (HM.toList decodeMap)) {-# NOINLINE decodeTrieUtf8 #-}--
src/Country/Identifier.hs view
@@ -596,7 +596,7 @@ mongolia :: Country mongolia = Country 496 --- | Montenegro; Republic of Singapore; Singapore; Singapura; Yugoslavia+-- | Montenegro; Yugoslavia montenegro :: Country montenegro = Country 499 @@ -800,7 +800,7 @@ sierraLeone :: Country sierraLeone = Country 694 --- | Montenegro; Republic of Singapore; Singapore; Singapura; Yugoslavia+-- | Republic of Singapore; Singapore; Singapura singapore :: Country singapore = Country 702
+ src/Country/Subdivision.hs view
@@ -0,0 +1,122 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UnboxedTuples #-}++module Country.Subdivision+ ( Subdivision+ -- * Accessors+ , encodeAlpha+ , encodeAlphaShort+ , encodeEnglish+ , encodeEnglishShort+ , category+ -- * Decoding+ , decodeAlpha+ , decodeEnglish+ , decodeEnglishUtf8Bytes+ ) where++import Data.Bytes (Bytes)+import Data.Hashable (Hashable)+import Data.HashMap.Strict (HashMap)+import Data.Primitive.Contiguous (index)+import Data.Primitive.Types (Prim)+import Data.Text (Text)+import Data.Text.Short (ShortText)+import Data.Text.Encoding (encodeUtf8)+import Data.Word (Word16)+import Foreign.Storable (Storable)++import qualified Country.Unexposed.Subdivision as Arrays+import qualified Data.Bytes.HashMap.Word as BytesHashMap+import qualified Data.ByteString as ByteString+import qualified Data.HashMap.Strict as HM+import qualified Data.Primitive.Contiguous as Arr+import qualified Data.Text as T+import qualified GHC.Exts as Exts++newtype Subdivision = Subdivision Word16+ deriving (Eq,Ord,Prim,Hashable,Storable)++instance Show Subdivision where+ show = show . encodeAlpha++instance Enum Subdivision where+ fromEnum (Subdivision w) = fromIntegral w+ toEnum number = if number >= 0 && number < Arrays.actualNumberOfSubdivisions+ then Subdivision (fromIntegral number)+ else error ("toEnum: cannot convert " ++ show number ++ " to Subdivision")+instance Bounded Subdivision where+ minBound = Subdivision 0+ maxBound = Subdivision (fromIntegral $ Arrays.actualNumberOfSubdivisions - 1)+++-- country :: Subdivision -> Country+-- country (Subdivision i) = index Arrays.countryArray i++encodeAlpha :: Subdivision -> Text+encodeAlpha (Subdivision i) = index Arrays.codeArray (fromIntegral @Word16 @Int i)++encodeAlphaShort :: Subdivision -> ShortText+encodeAlphaShort (Subdivision i) = index Arrays.codeArrayShort (fromIntegral @Word16 @Int i)++encodeEnglish :: Subdivision -> Text+encodeEnglish (Subdivision i) = index Arrays.nameArray (fromIntegral @Word16 @Int i)++encodeEnglishShort :: Subdivision -> ShortText+encodeEnglishShort (Subdivision i) = index Arrays.nameArrayShort (fromIntegral @Word16 @Int i)++category :: Subdivision -> Text+category (Subdivision i) = index Arrays.categoryArray (fromIntegral @Word16 @Int i)+++-- | Decode a 'Subdivision' using its ISO subdivision code.+decodeAlpha :: Text -> Maybe Subdivision+decodeAlpha = flip HM.lookup alphaHashMap++alphaHashMap :: HashMap Text Subdivision+alphaHashMap = Arr.ifoldl'+ (\hm i x ->+ HM.insert x (Subdivision $ fromIntegral i)+ -- $ HM.insert (T.pack [toLower c1, toLower c2, toLower c3]) (Country countryNum)+ $ hm+ )+ HM.empty Arrays.codeArray+{-# NOINLINE alphaHashMap #-}++-- | Decode a 'Subdivision' using its ISO subdivision English name+-- It's not terribly forgiving, accepting only the official(?) names I found on wiki.+decodeEnglish :: Text -> Maybe Subdivision+decodeEnglish = flip HM.lookup englishHashMap++englishHashMap :: HashMap Text Subdivision+englishHashMap = Arr.ifoldl'+ (\hm i x ->+ let place = Subdivision (fromIntegral i)+ in HM.insert x place+ $ HM.insert (T.toLower $ x) place+ $ hm+ )+ HM.empty Arrays.nameArray+{-# NOINLINE englishHashMap #-}++englishHashMapUtf8Bytes :: BytesHashMap.Map+{-# NOINLINE englishHashMapUtf8Bytes #-}+englishHashMapUtf8Bytes = BytesHashMap.fromTrustedList+ ( imap+ (\i t -> (Exts.fromList (ByteString.unpack (encodeUtf8 t)),fromIntegral i)+ ) (Exts.toList Arrays.nameArray)+ )++decodeEnglishUtf8Bytes :: Bytes -> Maybe Subdivision+decodeEnglishUtf8Bytes !bs = case BytesHashMap.lookup bs englishHashMapUtf8Bytes of+ Nothing -> Nothing+ Just w -> Just (Subdivision (fromIntegral w))++imap :: (Int -> a -> b) -> [a] -> [b]+imap f ls = go 0 ls+ where+ go !i (x:xs) = f i x : go (i + 1) xs+ go !_ [] = []
src/Country/Unexposed/Alias.hs view
@@ -349,9 +349,6 @@ , (492, T.pack "Principauté de Monaco") , (496, T.pack "Mongolia") , (499, T.pack "Montenegro")- , (499, T.pack "Republic of Singapore")- , (499, T.pack "Singapore")- , (499, T.pack "Singapura") , (499, T.pack "Yugoslavia") , (500, T.pack "Montserrat") , (504, T.pack "Morocco")@@ -455,10 +452,8 @@ , (690, T.pack "Seychelles") , (694, T.pack "Sierra Leone") , (702, T.pack "Singapore")- , (702, T.pack "Montenegro") , (702, T.pack "Republic of Singapore") , (702, T.pack "Singapura")- , (702, T.pack "Yugoslavia") , (534, T.pack "Sint Maarten (Dutch part)") , (534, T.pack "Sint Maarten") , (703, T.pack "Slovakia")
+ src/Country/Unexposed/AlphaTwoPtr.hs view
@@ -0,0 +1,1012 @@+{-# language MagicHash #-}+-- This module is autogenerated. Do not edit it by hand.+module Country.Unexposed.AlphaTwoPtr+ ( alphaTwoPtr+ ) where++import GHC.Exts (Ptr(Ptr))+import Data.Word (Word8)++alphaTwoPtr :: Ptr Word8+alphaTwoPtr = Ptr "\+\AA\+\AA\+\AA\+\AA\+\AF\+\AA\+\AA\+\AA\+\AL\+\AA\+\AQ\+\AA\+\DZ\+\AA\+\AA\+\AA\+\AS\+\AA\+\AA\+\AA\+\AD\+\AA\+\AA\+\AA\+\AO\+\AA\+\AA\+\AA\+\AG\+\AA\+\AA\+\AZ\+\AR\+\AA\+\AA\+\AA\+\AU\+\AA\+\AA\+\AA\+\AT\+\AA\+\AA\+\AA\+\BS\+\AA\+\AA\+\AA\+\BH\+\AA\+\BD\+\AM\+\BB\+\AA\+\AA\+\AA\+\BE\+\AA\+\AA\+\AA\+\BM\+\AA\+\AA\+\AA\+\BT\+\AA\+\AA\+\AA\+\BO\+\AA\+\BA\+\AA\+\BW\+\AA\+\BV\+\AA\+\BR\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\BZ\+\AA\+\IO\+\AA\+\AA\+\AA\+\SB\+\AA\+\VG\+\AA\+\AA\+\AA\+\BN\+\AA\+\AA\+\AA\+\BG\+\AA\+\AA\+\AA\+\MM\+\AA\+\AA\+\AA\+\BI\+\AA\+\AA\+\AA\+\BY\+\AA\+\AA\+\AA\+\KH\+\AA\+\AA\+\AA\+\CM\+\AA\+\AA\+\AA\+\CA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\CV\+\AA\+\AA\+\AA\+\KY\+\AA\+\AA\+\AA\+\CF\+\AA\+\AA\+\AA\+\LK\+\AA\+\AA\+\AA\+\TD\+\AA\+\AA\+\AA\+\CL\+\AA\+\AA\+\AA\+\CN\+\AA\+\TW\+\AA\+\AA\+\AA\+\CX\+\AA\+\AA\+\AA\+\CC\+\AA\+\AA\+\AA\+\CO\+\AA\+\AA\+\AA\+\KM\+\YT\+\AA\+\AA\+\CG\+\AA\+\CD\+\AA\+\AA\+\AA\+\CK\+\AA\+\AA\+\AA\+\CR\+\AA\+\AA\+\HR\+\CU\+\AA\+\AA\+\AA\+\CY\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\CZ\+\BJ\+\AA\+\AA\+\AA\+\DK\+\AA\+\AA\+\AA\+\DM\+\AA\+\DO\+\AA\+\AA\+\AA\+\EC\+\AA\+\AA\+\AA\+\SV\+\AA\+\AA\+\AA\+\GQ\+\AA\+\AA\+\AA\+\AA\+\ET\+\ER\+\EE\+\FO\+\AA\+\AA\+\AA\+\FK\+\GS\+\AA\+\AA\+\FJ\+\AA\+\AA\+\AA\+\FI\+\AA\+\AX\+\AA\+\FR\+\AA\+\AA\+\AA\+\GF\+\AA\+\AA\+\AA\+\PF\+\AA\+\TF\+\AA\+\DJ\+\AA\+\AA\+\AA\+\GA\+\AA\+\GE\+\AA\+\GM\+\AA\+\AA\+\AA\+\AA\+\PS\+\DE\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\GH\+\AA\+\AA\+\AA\+\GI\+\AA\+\AA\+\AA\+\KI\+\AA\+\AA\+\AA\+\GR\+\AA\+\AA\+\AA\+\GL\+\AA\+\AA\+\AA\+\GD\+\AA\+\AA\+\AA\+\GP\+\AA\+\AA\+\AA\+\GU\+\AA\+\AA\+\AA\+\GT\+\AA\+\AA\+\AA\+\GN\+\AA\+\AA\+\AA\+\GY\+\AA\+\AA\+\AA\+\HT\+\AA\+\HM\+\AA\+\VA\+\AA\+\AA\+\AA\+\HN\+\AA\+\AA\+\AA\+\HK\+\AA\+\AA\+\AA\+\HU\+\AA\+\AA\+\AA\+\IS\+\AA\+\AA\+\AA\+\IN\+\AA\+\AA\+\AA\+\ID\+\AA\+\AA\+\AA\+\IR\+\AA\+\AA\+\AA\+\IQ\+\AA\+\AA\+\AA\+\IE\+\AA\+\AA\+\AA\+\IL\+\AA\+\AA\+\AA\+\IT\+\AA\+\AA\+\XK\+\CI\+\AA\+\AA\+\AA\+\JM\+\AA\+\AA\+\AA\+\JP\+\AA\+\AA\+\AA\+\AA\+\AA\+\KZ\+\AA\+\JO\+\AA\+\AA\+\AA\+\KE\+\AA\+\AA\+\AA\+\KP\+\AA\+\KR\+\AA\+\AA\+\AA\+\KW\+\AA\+\AA\+\KG\+\LA\+\AA\+\AA\+\AA\+\LB\+\AA\+\AA\+\AA\+\LS\+\AA\+\LV\+\AA\+\LR\+\AA\+\AA\+\AA\+\LY\+\AA\+\AA\+\AA\+\LI\+\AA\+\LT\+\AA\+\LU\+\AA\+\AA\+\AA\+\MO\+\AA\+\AA\+\AA\+\MG\+\AA\+\AA\+\AA\+\MW\+\AA\+\AA\+\AA\+\MY\+\AA\+\AA\+\AA\+\MV\+\AA\+\AA\+\AA\+\ML\+\AA\+\AA\+\AA\+\MT\+\AA\+\AA\+\AA\+\MQ\+\AA\+\AA\+\AA\+\MR\+\AA\+\MU\+\AA\+\AA\+\AA\+\MX\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\MC\+\AA\+\AA\+\AA\+\MN\+\AA\+\MD\+\ME\+\MS\+\AA\+\AA\+\AA\+\MA\+\AA\+\AA\+\AA\+\MZ\+\AA\+\AA\+\AA\+\OM\+\AA\+\AA\+\AA\+\NA\+\AA\+\AA\+\AA\+\NR\+\AA\+\AA\+\AA\+\NP\+\AA\+\AA\+\AA\+\NL\+\AA\+\AA\+\CW\+\AA\+\AW\+\SX\+\BQ\+\AA\+\AA\+\AA\+\AA\+\NC\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\VU\+\AA\+\AA\+\AA\+\AA\+\AA\+\NZ\+\AA\+\AA\+\AA\+\NI\+\AA\+\AA\+\AA\+\NE\+\AA\+\AA\+\AA\+\NG\+\AA\+\AA\+\AA\+\NU\+\AA\+\AA\+\AA\+\NF\+\AA\+\AA\+\AA\+\NO\+\AA\+\MP\+\UM\+\AA\+\FM\+\MH\+\PW\+\PK\+\AA\+\AA\+\AA\+\AA\+\PA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\PG\+\AA\+\PY\+\AA\+\AA\+\AA\+\PE\+\AA\+\AA\+\AA\+\PH\+\AA\+\AA\+\AA\+\PN\+\AA\+\AA\+\AA\+\PL\+\AA\+\AA\+\AA\+\PT\+\AA\+\AA\+\AA\+\GW\+\AA\+\TL\+\AA\+\AA\+\AA\+\PR\+\AA\+\AA\+\AA\+\QA\+\AA\+\AA\+\AA\+\RE\+\AA\+\AA\+\AA\+\RO\+\RU\+\AA\+\AA\+\RW\+\AA\+\AA\+\AA\+\AA\+\AA\+\BL\+\AA\+\SH\+\AA\+\AA\+\AA\+\AA\+\KN\+\AI\+\AA\+\LC\+\MF\+\AA\+\AA\+\PM\+\AA\+\AA\+\AA\+\VC\+\AA\+\AA\+\AA\+\SM\+\AA\+\AA\+\AA\+\ST\+\AA\+\AA\+\AA\+\SA\+\AA\+\AA\+\AA\+\SN\+\AA\+\RS\+\AA\+\SC\+\AA\+\AA\+\AA\+\SL\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\SG\+\SK\+\VN\+\SI\+\SO\+\AA\+\AA\+\AA\+\ZA\+\AA\+\AA\+\AA\+\AA\+\AA\+\ZW\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\ES\+\AA\+\AA\+\AA\+\SS\+\SD\+\AA\+\AA\+\EH\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\SR\+\AA\+\AA\+\AA\+\SJ\+\AA\+\AA\+\AA\+\SZ\+\AA\+\AA\+\AA\+\SE\+\AA\+\AA\+\AA\+\CH\+\AA\+\AA\+\AA\+\SY\+\AA\+\TJ\+\AA\+\TH\+\AA\+\AA\+\AA\+\TG\+\AA\+\AA\+\AA\+\TK\+\AA\+\AA\+\AA\+\TO\+\AA\+\AA\+\AA\+\TT\+\AA\+\AA\+\AA\+\AE\+\AA\+\AA\+\AA\+\TN\+\AA\+\AA\+\AA\+\TR\+\AA\+\AA\+\TM\+\TC\+\AA\+\TV\+\AA\+\UG\+\AA\+\AA\+\AA\+\UA\+\AA\+\AA\+\MK\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\EG\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\GB\+\AA\+\AA\+\AA\+\AA\+\GG\+\JE\+\IM\+\TZ\+\AA\+\AA\+\AA\+\AA\+\AA\+\US\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\VI\+\AA\+\AA\+\AA\+\BF\+\AA\+\AA\+\AA\+\UY\+\AA\+\UZ\+\AA\+\VE\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\WF\+\AA\+\AA\+\AA\+\AA\+\AA\+\WS\+\AA\+\AA\+\AA\+\AA\+\YE\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\ZM\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\AA\+\"#
+ src/Country/Unexposed/Continents.hs view
@@ -0,0 +1,263 @@+-- This module is autogenerated. Do not edit it by hand.+module Country.Unexposed.Continents+ ( continentAList+ ) where++import Continent.Unsafe+import Data.Word (Word16)++-- first value is country code, second is the continent constructor+continentAList :: [(Word16,Continent)]+continentAList =+ [ (4,Asia)+ , (248,Europe)+ , (8,Europe)+ , (12,Africa)+ , (16,Oceania)+ , (20,Europe)+ , (24,Africa)+ , (660,NorthAmerica)+ , (10,Antarctica)+ , (28,NorthAmerica)+ , (32,SouthAmerica)+ , (51,Asia)+ , (533,NorthAmerica)+ , (36,Oceania)+ , (40,Europe)+ , (31,Asia)+ , (44,NorthAmerica)+ , (48,Asia)+ , (50,Asia)+ , (52,NorthAmerica)+ , (112,Europe)+ , (56,Europe)+ , (84,NorthAmerica)+ , (204,Africa)+ , (60,NorthAmerica)+ , (64,Asia)+ , (68,SouthAmerica)+ , (535,NorthAmerica)+ , (70,Europe)+ , (72,Africa)+ , (74,Antarctica)+ , (76,SouthAmerica)+ , (86,Oceania)+ , (96,Asia)+ , (100,Europe)+ , (854,Africa)+ , (108,Africa)+ , (116,Asia)+ , (120,Africa)+ , (124,NorthAmerica)+ , (132,Africa)+ , (136,NorthAmerica)+ , (140,Africa)+ , (148,Africa)+ , (152,SouthAmerica)+ , (156,Asia)+ , (162,Oceania)+ , (166,Oceania)+ , (170,SouthAmerica)+ , (174,Africa)+ , (178,Africa)+ , (180,Africa)+ , (184,Oceania)+ , (188,NorthAmerica)+ , (384,Africa)+ , (191,Europe)+ , (192,NorthAmerica)+ , (531,NorthAmerica)+ , (196,Asia)+ , (203,Europe)+ , (208,Europe)+ , (262,Africa)+ , (212,NorthAmerica)+ , (214,NorthAmerica)+ , (218,SouthAmerica)+ , (818,Africa)+ , (222,NorthAmerica)+ , (226,Africa)+ , (232,Africa)+ , (233,Europe)+ , (231,Africa)+ , (238,SouthAmerica)+ , (234,Europe)+ , (242,Oceania)+ , (246,Europe)+ , (250,Europe)+ , (254,SouthAmerica)+ , (258,Oceania)+ , (260,Antarctica)+ , (266,Africa)+ , (270,Africa)+ , (268,Asia)+ , (276,Europe)+ , (288,Africa)+ , (292,Europe)+ , (300,Europe)+ , (304,NorthAmerica)+ , (308,NorthAmerica)+ , (312,NorthAmerica)+ , (316,Oceania)+ , (320,NorthAmerica)+ , (831,Europe)+ , (324,Africa)+ , (624,Africa)+ , (328,SouthAmerica)+ , (332,NorthAmerica)+ , (334,Antarctica)+ , (336,Europe)+ , (340,NorthAmerica)+ , (344,Asia)+ , (348,Europe)+ , (352,Europe)+ , (356,Asia)+ , (360,Asia)+ , (364,Asia)+ , (368,Asia)+ , (372,Europe)+ , (833,Europe)+ , (376,Asia)+ , (380,Europe)+ , (388,NorthAmerica)+ , (392,Asia)+ , (832,Europe)+ , (400,Asia)+ , (398,Asia)+ , (404,Africa)+ , (296,Oceania)+ , (408,Asia)+ , (410,Asia)+ , (414,Asia)+ , (417,Asia)+ , (418,Asia)+ , (428,Europe)+ , (422,Asia)+ , (426,Africa)+ , (430,Africa)+ , (434,Africa)+ , (438,Europe)+ , (440,Europe)+ , (442,Europe)+ , (446,Asia)+ , (807,Europe)+ , (450,Africa)+ , (454,Africa)+ , (458,Asia)+ , (462,Asia)+ , (466,Africa)+ , (470,Europe)+ , (584,Oceania)+ , (474,NorthAmerica)+ , (478,Africa)+ , (480,Africa)+ , (175,Africa)+ , (484,NorthAmerica)+ , (583,Oceania)+ , (498,Europe)+ , (492,Europe)+ , (496,Asia)+ , (499,Europe)+ , (500,NorthAmerica)+ , (504,Africa)+ , (508,Africa)+ , (104,Asia)+ , (516,Africa)+ , (520,Oceania)+ , (524,Asia)+ , (528,Europe)+ , (540,Oceania)+ , (554,Oceania)+ , (558,NorthAmerica)+ , (562,Africa)+ , (566,Africa)+ , (570,Oceania)+ , (574,Oceania)+ , (580,Oceania)+ , (578,Europe)+ , (512,Asia)+ , (586,Asia)+ , (585,Oceania)+ , (275,Asia)+ , (591,NorthAmerica)+ , (598,Oceania)+ , (600,SouthAmerica)+ , (604,SouthAmerica)+ , (608,Asia)+ , (612,Oceania)+ , (616,Europe)+ , (620,Europe)+ , (630,NorthAmerica)+ , (634,Asia)+ , (638,Africa)+ , (642,Europe)+ , (643,Europe)+ , (646,Africa)+ , (652,NorthAmerica)+ , (654,Africa)+ , (659,NorthAmerica)+ , (662,NorthAmerica)+ , (663,NorthAmerica)+ , (666,NorthAmerica)+ , (670,NorthAmerica)+ , (882,Oceania)+ , (674,Europe)+ , (678,Africa)+ , (682,Asia)+ , (686,Africa)+ , (688,Europe)+ , (690,Africa)+ , (694,Africa)+ , (702,Asia)+ , (534,NorthAmerica)+ , (703,Europe)+ , (705,Europe)+ , (90,Oceania)+ , (706,Africa)+ , (710,Africa)+ , (239,Antarctica)+ , (728,Africa)+ , (724,Europe)+ , (144,Asia)+ , (729,Africa)+ , (740,SouthAmerica)+ , (744,Europe)+ , (748,Africa)+ , (752,Europe)+ , (756,Europe)+ , (760,Asia)+ , (158,Asia)+ , (762,Asia)+ , (834,Africa)+ , (764,Asia)+ , (626,Asia)+ , (768,Africa)+ , (772,Oceania)+ , (776,Oceania)+ , (780,NorthAmerica)+ , (788,Africa)+ , (792,Asia)+ , (795,Asia)+ , (796,NorthAmerica)+ , (798,Oceania)+ , (800,Africa)+ , (804,Europe)+ , (784,Asia)+ , (826,Europe)+ , (840,NorthAmerica)+ , (581,Oceania)+ , (858,SouthAmerica)+ , (860,Asia)+ , (548,Oceania)+ , (862,SouthAmerica)+ , (704,Asia)+ , (92,NorthAmerica)+ , (850,NorthAmerica)+ , (876,Oceania)+ , (732,Africa)+ , (887,Asia)+ , (894,Africa)+ , (716,Africa)+ , (383,Europe)+ ]+{-# NOINLINE continentAList #-}
src/Country/Unexposed/Names.hs view
@@ -14,48 +14,81 @@ , englishIdentifierNamesText , numberOfPossibleCodes , decodeMap+ , hashMapUtf8+ , hashMapUtf16 , decodeMapUtf8 , alphaTwoHashMap , alphaThreeHashMap , decodeNumeric , encodeEnglish+ , encodeEnglishShort , Country(..) ) where +import Control.Monad+import Control.Monad.ST+import Data.Word+ import Control.DeepSeq (NFData)-import Data.Word (Word16)+import Control.Exception (bracket)+import Country.Unexposed.Alias (aliases)+import Country.Unexposed.Encode.English (countryNameQuads)+import Data.Bytes.Types (Bytes(Bytes))+import Data.ByteString (ByteString)+import Data.Char (toLower,isAlpha,toUpper)+import Data.Data import Data.Hashable (Hashable)-import Data.Primitive.Types (Prim) import Data.HashMap.Strict (HashMap)-import Data.ByteString (ByteString)-import Data.Primitive (indexArray)+import Data.Primitive (Array,indexArray,newArray,unsafeFreezeArray,writeArray)+import Data.Primitive (sizeOf)+import Data.Primitive (writeByteArray,indexByteArray,unsafeFreezeByteArray,newByteArray) import Data.Primitive.Array (Array(..)) import Data.Primitive.ByteArray (ByteArray(..))-import Control.Monad+import Data.Primitive.Types (Prim)+import Data.Text (Text) import Data.Text.Encoding (encodeUtf8)-import Country.Unexposed.Alias (aliases)+import Data.Text.Short (ShortText)+import Data.Word (Word16)+import Foreign.Storable (Storable)+import GHC.Generics (Generic)+import System.Entropy (openHandle,closeHandle)+import System.IO.Unsafe (unsafePerformIO)+ import qualified Data.Text as T import qualified Data.Aeson as AE import qualified Data.Aeson.Types as AET import qualified Data.HashMap.Strict as HM import qualified Data.List as L-import Control.Monad.ST-import Foreign.Storable (Storable)-import Data.Text (Text)-import Data.Word-import Data.Char (toLower,isAlpha,toUpper)-import Country.Unexposed.Encode.English (countryNameQuads)-import Data.Primitive (Array,indexArray,newArray,unsafeFreezeArray,writeArray,- writeByteArray,indexByteArray,unsafeFreezeByteArray,newByteArray,sizeOf)+import qualified Data.Primitive.Unlifted.Array as PM import qualified Data.Text as T import qualified Data.Scientific as SCI-import GHC.Generics (Generic)-import Data.Data+import qualified GHC.Exts as Exts+import qualified System.IO as IO+import qualified Data.Bytes as Bytes+import qualified Data.Bytes.HashMap.Word as BytesHashMap+import qualified Data.Text.Internal as Text+import qualified Data.Text.Array as Text+import qualified Data.Text.Short as TS+import qualified Data.ByteString as ByteString -- | The name of a country given in English encodeEnglish :: Country -> Text+{-# inline encodeEnglish #-} encodeEnglish (Country n) = indexArray englishCountryNamesText (word16ToInt n) +-- | The name of a country given in English+encodeEnglishShort :: Country -> ShortText+{-# inline encodeEnglishShort #-}+encodeEnglishShort (Country n) =+ PM.indexUnliftedArray englishCountryNamesShortText (word16ToInt n)++englishCountryNamesShortText :: PM.UnliftedArray ShortText+englishCountryNamesShortText = runST $ do+ m <- PM.newUnliftedArray numberOfPossibleCodes unnamedShort+ mapM_ (\(ix,name,_,_) -> PM.writeUnliftedArray m (word16ToInt ix) (TS.fromText name)) countryNameQuads+ PM.unsafeFreezeUnliftedArray m+{-# NOINLINE englishCountryNamesShortText #-}+ englishCountryNamesText :: Array Text englishCountryNamesText = runST $ do m <- newArray numberOfPossibleCodes unnamed@@ -80,6 +113,10 @@ unnamed = T.pack "Invalid Country" {-# NOINLINE unnamed #-} +unnamedShort :: ShortText+unnamedShort = TS.pack "Invalid Country"+{-# NOINLINE unnamedShort #-}+ numberOfPossibleCodes :: Int numberOfPossibleCodes = 1000 @@ -87,14 +124,41 @@ word16ToInt = fromIntegral decodeMap :: HashMap Text Country-decodeMap =- let baseMap = HM.union alphaTwoHashMap alphaThreeHashMap- hm1 = L.foldl' (\hm (countryNum,name) -> HM.insert name (Country countryNum) hm) baseMap aliases- hm2 = L.foldl' (\hm (countryNum,name,_,_) -> HM.insert name (Country countryNum) hm) hm1 countryNameQuads- hm3 = HM.foldlWithKey' (\hm name cty -> HM.insert (T.toLower name) cty $ HM.insert (slowToTitle name) cty $ hm) hm2 hm2- in hm3 {-# NOINLINE decodeMap #-}+decodeMap = HM.fromList (map (\(a,b) -> (b,Country a)) countryPairs) +hashMapUtf8 :: BytesHashMap.Map+hashMapUtf8 = BytesHashMap.fromTrustedList+ ( map+ (\(a,t) -> (Exts.fromList (ByteString.unpack (encodeUtf8 t)),fromIntegral a)+ ) countryPairs+ )++-- It is a hack to pull from a source of randomness in here, but whatever.+-- Maybe I can get rid of this if GHC ever supports casing on values of+-- type ByteArray# along with good codegen for it.+hashMapUtf16 :: BytesHashMap.Map+hashMapUtf16 = BytesHashMap.fromTrustedList+ ( map+ (\(a,Text.Text (Text.Array arr) off16 len16) ->+ (Bytes (ByteArray arr) (off16 * 2) (len16 * 2),fromIntegral a)+ ) countryPairs+ )++countryPairs :: [(Word16,Text)]+{-# NOINLINE countryPairs #-}+countryPairs =+ let x = aliases ++ concatMap+ (\(num,name,(c2a,c2b),(c3a,c3b,c3c)) ->+ [ (num,name)+ , (num,T.pack [c2a,c2b])+ , (num,T.pack [c3a,c3b,c3c])+ , (num,T.pack [toLower c2a,toLower c2b])+ , (num,T.pack [toLower c3a,toLower c3b,toLower c3c])+ ]+ ) countryNameQuads+ in x ++ map (\(a,b) -> (a,slowToTitle b)) x+ -- This is only needed to support the reflex-platform fork of text. Fortunately, -- in all the places this is needed, it is only called to build CAFs. slowToTitle :: Text -> Text@@ -211,4 +275,3 @@ ) HM.empty countryNameQuads {-# NOINLINE alphaThreeHashMap #-}-
+ src/Country/Unexposed/Subdivision.hs view
@@ -0,0 +1,331 @@+{-# LANGUAGE OverloadedStrings #-}++-- This module is autogenerated. Do not edit it by hand.++module Country.Unexposed.Subdivision+ ( codeArray+ , codeArrayShort+ , nameArray+ , nameArrayShort+ , categoryArray+ , actualNumberOfSubdivisions+ ) where++import Data.Primitive.Contiguous (SmallArray)+import Data.Text (Text)+import Data.Text.Short (ShortText)+import Data.Primitive.Unlifted.Array (UnliftedArray)++import qualified Data.Primitive.Contiguous as Arr++codeArray :: SmallArray Text+codeArray = Arr.fromListN 57+ [ "US-AL"+ , "US-AK"+ , "US-AZ"+ , "US-AR"+ , "US-CA"+ , "US-CO"+ , "US-CT"+ , "US-DE"+ , "US-FL"+ , "US-GA"+ , "US-HI"+ , "US-ID"+ , "US-IL"+ , "US-IN"+ , "US-IA"+ , "US-KS"+ , "US-KY"+ , "US-LA"+ , "US-ME"+ , "US-MD"+ , "US-MA"+ , "US-MI"+ , "US-MN"+ , "US-MS"+ , "US-MO"+ , "US-MT"+ , "US-NE"+ , "US-NV"+ , "US-NH"+ , "US-NJ"+ , "US-NM"+ , "US-NY"+ , "US-NC"+ , "US-ND"+ , "US-OH"+ , "US-OK"+ , "US-OR"+ , "US-PA"+ , "US-RI"+ , "US-SC"+ , "US-SD"+ , "US-TN"+ , "US-TX"+ , "US-UT"+ , "US-VT"+ , "US-VA"+ , "US-WA"+ , "US-WV"+ , "US-WI"+ , "US-WY"+ , "US-DC"+ , "US-AS"+ , "US-GU"+ , "US-MP"+ , "US-PR"+ , "US-UM"+ , "US-VI"+ ]+{-# NOINLINE codeArray #-}++codeArrayShort :: UnliftedArray ShortText+codeArrayShort = Arr.fromListN 57+ [ "US-AL"+ , "US-AK"+ , "US-AZ"+ , "US-AR"+ , "US-CA"+ , "US-CO"+ , "US-CT"+ , "US-DE"+ , "US-FL"+ , "US-GA"+ , "US-HI"+ , "US-ID"+ , "US-IL"+ , "US-IN"+ , "US-IA"+ , "US-KS"+ , "US-KY"+ , "US-LA"+ , "US-ME"+ , "US-MD"+ , "US-MA"+ , "US-MI"+ , "US-MN"+ , "US-MS"+ , "US-MO"+ , "US-MT"+ , "US-NE"+ , "US-NV"+ , "US-NH"+ , "US-NJ"+ , "US-NM"+ , "US-NY"+ , "US-NC"+ , "US-ND"+ , "US-OH"+ , "US-OK"+ , "US-OR"+ , "US-PA"+ , "US-RI"+ , "US-SC"+ , "US-SD"+ , "US-TN"+ , "US-TX"+ , "US-UT"+ , "US-VT"+ , "US-VA"+ , "US-WA"+ , "US-WV"+ , "US-WI"+ , "US-WY"+ , "US-DC"+ , "US-AS"+ , "US-GU"+ , "US-MP"+ , "US-PR"+ , "US-UM"+ , "US-VI"+ ]+{-# NOINLINE codeArrayShort #-}++nameArray :: SmallArray Text+nameArray = Arr.fromListN 57+ [ "Alabama"+ , "Alaska"+ , "Arizona"+ , "Arkansas"+ , "California"+ , "Colorado"+ , "Connecticut"+ , "Delaware"+ , "Florida"+ , "Georgia"+ , "Hawaii"+ , "Idaho"+ , "Illinois"+ , "Indiana"+ , "Iowa"+ , "Kansas"+ , "Kentucky"+ , "Louisiana"+ , "Maine"+ , "Maryland"+ , "Massachusetts"+ , "Michigan"+ , "Minnesota"+ , "Mississippi"+ , "Missouri"+ , "Montana"+ , "Nebraska"+ , "Nevada"+ , "New Hampshire"+ , "New Jersey"+ , "New Mexico"+ , "New York"+ , "North Carolina"+ , "North Dakota"+ , "Ohio"+ , "Oklahoma"+ , "Oregon"+ , "Pennsylvania"+ , "Rhode Island"+ , "South Carolina"+ , "South Dakota"+ , "Tennessee"+ , "Texas"+ , "Utah"+ , "Vermont"+ , "Virginia"+ , "Washington"+ , "West Virginia"+ , "Wisconsin"+ , "Wyoming"+ , "District of Columbia"+ , "American Samoa"+ , "Guam"+ , "Northern Mariana Islands"+ , "Puerto Rico"+ , "United States Minor Outlying Islands"+ , "U.S. Virgin Islands"+ ]+{-# NOINLINE nameArray #-}++nameArrayShort :: UnliftedArray ShortText+nameArrayShort = Arr.fromListN 57+ [ "Alabama"+ , "Alaska"+ , "Arizona"+ , "Arkansas"+ , "California"+ , "Colorado"+ , "Connecticut"+ , "Delaware"+ , "Florida"+ , "Georgia"+ , "Hawaii"+ , "Idaho"+ , "Illinois"+ , "Indiana"+ , "Iowa"+ , "Kansas"+ , "Kentucky"+ , "Louisiana"+ , "Maine"+ , "Maryland"+ , "Massachusetts"+ , "Michigan"+ , "Minnesota"+ , "Mississippi"+ , "Missouri"+ , "Montana"+ , "Nebraska"+ , "Nevada"+ , "New Hampshire"+ , "New Jersey"+ , "New Mexico"+ , "New York"+ , "North Carolina"+ , "North Dakota"+ , "Ohio"+ , "Oklahoma"+ , "Oregon"+ , "Pennsylvania"+ , "Rhode Island"+ , "South Carolina"+ , "South Dakota"+ , "Tennessee"+ , "Texas"+ , "Utah"+ , "Vermont"+ , "Virginia"+ , "Washington"+ , "West Virginia"+ , "Wisconsin"+ , "Wyoming"+ , "District of Columbia"+ , "American Samoa"+ , "Guam"+ , "Northern Mariana Islands"+ , "Puerto Rico"+ , "United States Minor Outlying Islands"+ , "U.S. Virgin Islands"+ ]+{-# NOINLINE nameArrayShort #-}++categoryArray :: SmallArray Text+categoryArray = Arr.fromListN 57+ [ "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "state"+ , "district"+ , "outlying area"+ , "outlying area"+ , "outlying area"+ , "outlying area"+ , "outlying area"+ , "outlying area"+ ]+{-# NOINLINE categoryArray #-}+actualNumberOfSubdivisions :: Int+actualNumberOfSubdivisions = 57
+ src/Country/Unexposed/Util.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE MagicHash #-}++module Country.Unexposed.Util+ ( mapTextArray+ , charToWord16+ , word16ToChar+ , word16ToInt+ , timesTwo+ , timesThree+ , half+ ) where++import Data.Bits (unsafeShiftL,unsafeShiftR)+import Data.Char (chr,ord)+import Data.Word (Word16)+import GHC.Exts (sizeofByteArray#)+import GHC.Int (Int(I#))++import qualified Data.Text.Array as TA+++mapTextArray :: (Char -> Char) -> TA.Array -> TA.Array+mapTextArray f a@(TA.Array inner) = TA.run $ do+ let len = half (I# (sizeofByteArray# inner))+ m <- TA.new len+ TA.copyI m 0 a 0 len+ let go !ix = if ix < len+ then do+ TA.unsafeWrite m ix (charToWord16 (f (word16ToChar (TA.unsafeIndex a ix))))+ go (ix + 1)+ else return ()+ go 0+ return m+{-# INLINE mapTextArray #-}++word16ToChar :: Word16 -> Char+word16ToChar = chr . fromIntegral+{-# INLINE word16ToChar #-}++charToWord16 :: Char -> Word16+charToWord16 = fromIntegral . ord+{-# INLINE charToWord16 #-}++word16ToInt :: Word16 -> Int+word16ToInt = fromIntegral+{-# INLINE word16ToInt #-}++timesTwo :: Int -> Int+timesTwo x = unsafeShiftL x 1+{-# INLINE timesTwo #-}++timesThree :: Int -> Int+timesThree x = x + timesTwo x+{-# INLINE timesThree #-}++half :: Int -> Int+half x = unsafeShiftR x 1+{-# INLINE half #-}
test/Spec.hs view
@@ -1,30 +1,114 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}++import Continent (Continent) import Country (Country)+import Country.Subdivision (Subdivision)+import Data.Char (ord)+import Data.Maybe (fromJust)+import Data.Primitive.Ptr (indexOffPtr) import Data.Proxy (Proxy(..))+import Data.Word (Word8) import Test.Tasty (defaultMain,testGroup,TestTree)+import Test.Tasty.QuickCheck (testProperty,(===)) +import qualified Continent+import qualified Country+import qualified Country.Subdivision as Subdivision+import qualified Data.Bytes as Bytes+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import qualified Data.Text.Short as TS+import qualified Test.QuickCheck as QC import qualified Test.QuickCheck.Classes as QCC import qualified Test.QuickCheck.Classes.IsList as QCCL import qualified Test.Tasty.QuickCheck as TQC-import qualified Test.QuickCheck as QC main :: IO ()-main = defaultMain- $ testGroup "Country"- $ map lawsToTest- $ map ($ proxy)- $ [ QCC.boundedEnumLaws- , QCC.eqLaws- , QCC.ordLaws- , QCC.primLaws- , QCC.showLaws- , QCC.storableLaws+main = defaultMain $ testGroup "Country" $+ ( map lawsToTest+ $ map ($ proxy)+ $ [ QCC.boundedEnumLaws+ , QCC.eqLaws+ , QCC.ordLaws+ , QCC.primLaws+ , QCC.showLaws+ , QCC.storableLaws+ ]+ ) +++ ( map lawsToTest+ $ map ($ Proxy @Continent)+ $ [ -- QCC.boundedEnumLaws+ QCC.eqLaws+ , QCC.ordLaws+ -- , QCC.primLaws+ -- , QCC.showLaws+ -- , QCC.storableLaws+ ]+ ) +++ [ testProperty "encode-decode-english"+ (\x -> Just x === Country.decode (Country.encodeEnglish x))+ , testProperty "encode-decode-alpha-2-upper"+ (\x -> Just x === Country.decode (Country.alphaTwoUpper x))+ , testProperty "encode-decode-alpha-3-upper"+ (\x -> Just x === Country.decode (Country.alphaThreeUpper x))+ , testProperty "encode-decode-alpha-2-lower"+ (\x -> Just x === Country.decode (Country.alphaTwoLower x))+ , testProperty "encode-decode-alpha-3-lower"+ (\x -> Just x === Country.decode (Country.alphaThreeLower x))+ , testProperty "encode-alpha-two-upper"+ (\x ->+ let t = Country.alphaTwoUpper x+ ptr = Country.alphaTwoUpperUtf8Ptr x+ in+ (c2w (Text.index t 0), c2w (Text.index t 1))+ ===+ (indexOffPtr ptr 0 :: Word8, indexOffPtr ptr 1 :: Word8)+ )+ , testGroup "Continent"+ [ testProperty "encode-decode-alpha-upper" $ \x ->+ Just x === Continent.decodeAlpha (Continent.alphaUpper x)+ , testProperty "encode-decode-english" $ \x ->+ Just x === Continent.decodeEnglish (Continent.encodeEnglish x)+ , testProperty "country-continent-smoke-usa" $+ Continent.continent (fromJust $ Country.decodeAlphaTwo "US") === Continent.NorthAmerica+ , testProperty "country-continent-smoke-china" $+ Continent.continent (fromJust $ Country.decodeAlphaTwo "CN") === Continent.Asia ]+ , testGroup "Subdivision" $+ ( map lawsToTest+ $ map ($ Proxy @Subdivision)+ $ [ QCC.boundedEnumLaws+ , QCC.eqLaws+ , QCC.ordLaws+ , QCC.primLaws+ , QCC.showLaws+ , QCC.storableLaws+ ]+ ) +++ [ testProperty "encode-decode-alpha" $ \x ->+ Just x === Subdivision.decodeAlpha (Subdivision.encodeAlpha x)+ , testProperty "encode-short" $ \x ->+ Just x === Subdivision.decodeAlpha (TS.toText (Subdivision.encodeAlphaShort x))+ , testProperty "decode-utf8-bytes" $ \x ->+ Just x === Subdivision.decodeEnglishUtf8Bytes (Bytes.fromByteString (Text.encodeUtf8 (Subdivision.encodeEnglish x)))+ ]+ ] +c2w :: Char -> Word8+c2w = fromIntegral . ord+ proxy :: Proxy Country proxy = Proxy lawsToTest :: QCC.Laws -> TestTree lawsToTest (QCC.Laws name pairs) = testGroup name (map (uncurry TQC.testProperty) pairs) +instance QC.Arbitrary Continent where+ arbitrary = QC.arbitraryBoundedEnum+ instance QC.Arbitrary Country where+ arbitrary = QC.arbitraryBoundedEnum++instance QC.Arbitrary Subdivision where arbitrary = QC.arbitraryBoundedEnum