packages feed

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 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