diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,8 @@
+# ChangeLog
+
+## 0.1.4
+
+* `toUpper` and `toTitle` no longer convert `ÿ` (0xFF) to `ß` (0xDF).
+* `isPunctuation` and `isSymbol` are now implemented with bitmaps.
+* Dropped support for base < 4.9.
+* Fixed documentation.
diff --git a/Data/Char8.hs b/Data/Char8.hs
--- a/Data/Char8.hs
+++ b/Data/Char8.hs
@@ -1,162 +1,201 @@
-{-# LANGUAGE MagicHash, CPP #-}
+{-# LANGUAGE MagicHash #-}
 
--- | Char8 library to be used with Data.ByteString.Char8.
--- All function assumes that only 8bit part of 'Char' is used
--- and it is encoded in Latin-1 (ISO-8859-1).
--- All utility functions are supposed to work as if
--- those of 'Data.Char'. Exceptions are described in
+-- | Char8 library to be used with "Data.ByteString.Char8".
+-- All functions assume that 'Char' is in the Latin-1 range (ISO-8859-1).
+-- All utility functions are supposed to work like
+-- those of "Data.Char". Exceptions are described in
 -- the function documentations.
---
--- Base library 4.7 (GHC 7.8) or earlier is based on Unicode 6.
--- Base library 4.8 (GHC 7.10) or later is based on Unicode 7.
--- 'isLower', 'isSymbol' and 'isPunctuation' behave differently.
-
 module Data.Char8 (
-  -- * Character classification
-    isControl, isSpace, isLower, isUpper
-  , isAlpha, isAlphaNum, isPrint, isDigit, isOctDigit, isHexDigit
-  , isLetter, isMark, isNumber, isPunctuation, isSymbol, isSeparator
-  -- * Subranges
-  , isAscii, isLatin1, isAsciiUpper, isAsciiLower
-  -- * Case conversion
-  , toUpper, toLower, toTitle
-  ) where
+    -- * Character classification
+    isControl,
+    isSpace,
+    isLower,
+    isUpper,
+    isAlpha,
+    isAlphaNum,
+    isPrint,
+    isDigit,
+    isOctDigit,
+    isHexDigit,
+    isLetter,
+    isMark,
+    isNumber,
+    isPunctuation,
+    isSymbol,
+    isSeparator,
 
+    -- * Subranges
+    isAscii,
+    isLatin1,
+    isAsciiUpper,
+    isAsciiLower,
+
+    -- * Case conversion
+    toUpper,
+    toLower,
+    toTitle,
+) where
+
 import GHC.Base
+
+import qualified Data.Word8 as W
+
 ----------------------------------------------------------------
 
+-- | Is it a control character
 isControl :: Char -> Bool
-isControl c = _nul <= c && c <= '\x1f'
-           || _del <= c && c <= '\x9f'
+isControl c =
+    c <= '\x1f'
+        || _del <= c && c <= '\x9f'
 
+-- | Is it white space
 isSpace :: Char -> Bool
-isSpace c = c == _space
-         || c == _tab
-         || c == _lf
-         || c == _cr
-         || c == _np
-         || c == _vt
-         || c == _nbsp
+isSpace c =
+    c == _space
+        || c == _tab
+        || c == _lf
+        || c == _cr
+        || c == _np
+        || c == _vt
+        || c == _nbsp
 
--- | This function returns 'True' for 170 and 186 in Unicode 6.
---   But it returns 'False' in Unicode 7.
+-- | Is it a lower case character
+--
+-- This function returns 'False' for 170 (ª) and 186 (º).
 isLower :: Char -> Bool
-isLower c = isLower' c
-         || c == _mu
-#if !MIN_VERSION_base(4,8,0)
-         || c == _ordfeminine
-         || c == _ordmasculine
-#endif
+isLower c =
+    isLower' c
+        || c == _mu
 
 isLowerCommon :: Char -> Bool
-isLowerCommon c = isLower' c
-         || c == _mu
-         || c == _ordfeminine
-         || c == _ordmasculine
+isLowerCommon c =
+    isLower' c
+        || c == _mu
+        || c == _ordfeminine
+        || c == _ordmasculine
 
 isLower' :: Char -> Bool
-isLower' c = isAsciiLower c
-          || _germandbls <= c && c <= _odieresis
-          || _oslash     <= c && c <= _ydieresis
+isLower' c =
+    isAsciiLower c
+        || _germandbls <= c && c <= _ydieresis && c /= '\xf7'
 
+-- | Is it an upper case character
 isUpper :: Char -> Bool
-isUpper c = isAsciiUpper c
-         || _Agrave <= c && c <= _Odieresis
-         || _Oslash <= c && c <= _Thorn
+isUpper c =
+    isAsciiUpper c
+        || _Agrave <= c && c <= _Thorn && c /= '\xd7'
 
+-- | Is it an alphabet letter
+--
+-- Synonym for 'isLetter'
 isAlpha :: Char -> Bool
 isAlpha c = isLowerCommon c || isUpper c
 
+-- | Is it an alphabet letter or a number
 isAlphaNum :: Char -> Bool
 isAlphaNum c = isAlpha c || isNumber c
 
+-- | Is the character printable
 isPrint :: Char -> Bool
 isPrint c
-  | c == _softhyphen = False
-isPrint c = _space <= c && c <= '~'
-         || _nbsp  <= c && c <= _ydieresis
+    | c == _softhyphen = False
+isPrint c =
+    _space <= c && c <= _tilde
+        || _nbsp <= c && c <= _ydieresis
 
+-- | Is the character a digit (@0-9@)
 isDigit :: Char -> Bool
 isDigit c = '0' <= c && c <= '9'
 
+-- | Is the character an octal digit (@0-7@)
 isOctDigit :: Char -> Bool
 isOctDigit c = '0' <= c && c <= '7'
 
+-- | Is the character a hexadecimal digit (@0-9a-fA-F@)
 isHexDigit :: Char -> Bool
-isHexDigit c = isDigit c
-            || 'A' <= c && c <= 'F'
-            || 'a' <= c && c <= 'f'
+isHexDigit c =
+    isDigit c
+        || 'A' <= c && c <= 'F'
+        || 'a' <= c && c <= 'f'
 
+-- | Is it an alphabet letter
+--
+-- Synonym for 'isAlpha'
 isLetter :: Char -> Bool
 isLetter c = isLowerCommon c || isUpper c
 
+-- | A Latin-1 character is never a mark
+--
+-- Synonymous with @const False@
 isMark :: Char -> Bool
 isMark _ = False
 
+-- | Is the character a number
 isNumber :: Char -> Bool
-isNumber c = isDigit c
-          || c == _s1
-          || c == _s2
-          || c == _s3
-          || c == _1'4
-          || c == _1'2
-          || c == _3'4
+isNumber c =
+    isDigit c
+        || c == _s1
+        || c == _s2
+        || c == _s3
+        || c == _1'4
+        || c == _1'2
+        || c == _3'4
 
--- | This function returns 'False' for 167 and 182 in Unicode 6.
---   But it returns 'True' in Unicode 7.
+-- | Is it a punctuation character
+--
+-- This function returns 'True' for 167 (§) and 182 (¶).
 isPunctuation :: Char -> Bool
-#if MIN_VERSION_base(4,8,0)
-isPunctuation c = c `elem` ['\x21','\x22','\x23','\x25','\x26','\x27','\x28','\x29','\x2a','\x2c','\x2d','\x2e','\x2f','\x3a','\x3b','\x3f','\x40','\x5b','\x5c','\x5d','\x5f','\x7b','\x7d','\xa1','\xa7','\xab','\xb6','\xb7','\xbb','\xbf']
-#else
-isPunctuation c = c `elem` ['\x21','\x22','\x23','\x25','\x26','\x27','\x28','\x29','\x2a','\x2c','\x2d','\x2e','\x2f','\x3a','\x3b','\x3f','\x40','\x5b','\x5c','\x5d','\x5f','\x7b','\x7d','\xa1','\xab','\xb7','\xbb','\xbf']
-#endif
+isPunctuation c = isLatin1 c && W.isPunctuation (fromIntegral (ord c))
 
--- | This function returns 'True' for 167 and 182 in Unicode 6.
---   But it returns 'False' in Unicode 7.
+-- | Is it a symbol character
+--
+-- This function returns 'False' for 167 (§) and 182 (¶).
 isSymbol :: Char -> Bool
-#if MIN_VERSION_base(4,8,0)
-isSymbol c = c `elem` ['\x24','\x2b','\x3c','\x3d','\x3e','\x5e','\x60','\x7c','\x7e','\xa2','\xa3','\xa4','\xa5','\xa6','\xa8','\xa9','\xac','\xae','\xaf','\xb0','\xb1','\xb4','\xb8','\xd7','\xf7']
-#else
-isSymbol c = c `elem` ['\x24','\x2b','\x3c','\x3d','\x3e','\x5e','\x60','\x7c','\x7e','\xa2','\xa3','\xa4','\xa5','\xa6','\xa7','\xa8','\xa9','\xac','\xae','\xaf','\xb0','\xb1','\xb4','\xb6','\xb8','\xd7','\xf7']
-#endif
+isSymbol c = isLatin1 c && W.isSymbol (fromIntegral (ord c))
 
+-- | Is it a (non-breaking) space
 isSeparator :: Char -> Bool
-isSeparator c = c == _space
-             || c == _nbsp
+isSeparator c =
+    c == _space
+        || c == _nbsp
 
 ----------------------------------------------------------------
 
+-- | Is the character in the ASCII range
 isAscii :: Char -> Bool
-isAscii c = _nul <= c && c <= _del
+isAscii c = c <= '\x7f'
 
+-- | Is the character in the Latin-1 range
 isLatin1 :: Char -> Bool
-#if __GLASGOW_HASKELL__ >= 707
-isLatin1 (C# c#) = isTrue# (ord# c# <=# 0xff#)
-#else
-isLatin1 (C# c#) = ord# c# <=# 0xff#
-#endif
+isLatin1 c = c <= '\xff'
 
+-- | Is the character an upper case ASCII letter (@A-Z@)
 isAsciiUpper :: Char -> Bool
 isAsciiUpper c = 'A' <= c && c <= 'Z'
 
+-- | Is the character a lower case ASCII letter (@a-z@)
 isAsciiLower :: Char -> Bool
 isAsciiLower c = 'a' <= c && c <= 'z'
 
 ----------------------------------------------------------------
 
--- | Micro sign/mu (0xb5) and small letter Y with diaeresis (0xff) remain the same.
+-- | Changes the character to the upper case variant, if possible.
+--
+-- Micro sign/mu (µ) and small letter Y with diaeresis (ÿ) remain the same.
 toUpper :: Char -> Char
 toUpper c@(C# c#)
-  | c == _germandbls = c
-  | isLower' c       = C# (chr# (ord# c# -# 32#))
-  | otherwise        = c
+    | c == _germandbls = c
+    | c == _ydieresis = c
+    | isLower' c = C# (chr# (ord# c# -# 32#))
+    | otherwise = c
 
+-- | Changes the character to the lower case variant, if possible.
 toLower :: Char -> Char
 toLower c@(C# c#)
-  | isUpper c = C# (chr# (ord# c# +# 32#))
-  | otherwise = c
+    | isUpper c = C# (chr# (ord# c# +# 32#))
+    | otherwise = c
 
--- | Micro sign/mu (0xb5) and small letter Y with diaeresis (0xff) remain the same.
+-- | Synonym for 'toUpper'
 toTitle :: Char -> Char
 toTitle = toUpper
 
@@ -165,23 +204,24 @@
 _nul, _tab, _lf, _vt, _np, _cr :: Char
 _nul = '\x00'
 _tab = '\x09'
-_lf  = '\x0a'
-_vt  = '\x0b'
-_np  = '\x0c'
-_cr  = '\x0d'
+_lf = '\x0a'
+_vt = '\x0b'
+_np = '\x0c'
+_cr = '\x0d'
 
-_space, _del, _nbsp :: Char
+_space, _tilde, _del, _nbsp :: Char
 _space = '\x20'
-_del   = '\x7f'
-_nbsp  = '\xa0'
+_tilde = '\x7e'
+_del = '\x7f'
+_nbsp = '\xa0'
 
 _ordfeminine, _softhyphen, _mu, _ordmasculine :: Char
-_ordfeminine  = '\xaa'
-_softhyphen   = '\xad'
-_mu           = '\xb5'
+_ordfeminine = '\xaa'
+_softhyphen = '\xad'
+_mu = '\xb5'
 _ordmasculine = '\xba'
 
-_s2, _s3, _s1, _1'4, _1'2, _3'4  :: Char
+_s2, _s3, _s1, _1'4, _1'2, _3'4 :: Char
 _s2 = '\xb2'
 _s3 = '\xb3'
 _s1 = '\xb9'
@@ -189,16 +229,10 @@
 _1'2 = '\xbd'
 _3'4 = '\xbe'
 
-_Agrave, _Odieresis, _Oslash, _Thorn :: Char
-_Agrave    = '\xc0'
-_Odieresis = '\xd6'
-_Oslash    = '\xd8'
-_Thorn     = '\xde'
+_Agrave, _Thorn :: Char
+_Agrave = '\xc0'
+_Thorn = '\xde'
 
-_germandbls, _agrave, _odieresis, _oslash, _thorn, _ydieresis :: Char
+_germandbls, _ydieresis :: Char
 _germandbls = '\xdf'
-_agrave     = '\xe0'
-_odieresis  = '\xf6'
-_oslash     = '\xf8'
-_thorn      = '\xfe'
-_ydieresis  = '\xff'
+_ydieresis = '\xff'
diff --git a/Data/Word8.hs b/Data/Word8.hs
--- a/Data/Word8.hs
+++ b/Data/Word8.hs
@@ -1,329 +1,1707 @@
-{-# LANGUAGE CPP #-}
-
--- | Word8 library to be used with Data.ByteString.
--- All function assumes that 'Word8' is encoded in Latin-1 (ISO-8859-1).
--- All utility functions are supposed to work as if
--- those of 'Data.Char'. Exceptions are described in
--- the function documentations.
---
--- Base library 4.7 (GHC 7.8) or earlier is based on Unicode 6.
--- Base library 4.8 (GHC 7.10) or later is based on Unicode 7.
--- 'isLower', 'isSymbol' and 'isPunctuation' behave differently.
-
-module Data.Word8 (
-  -- * Re-exporting
-    Word8
-  -- * Character classification
-  , isControl, isSpace, isLower, isUpper
-  , isAlpha, isAlphaNum, isPrint, isDigit, isOctDigit, isHexDigit
-  , isLetter, isMark, isNumber, isPunctuation, isSymbol, isSeparator
-  -- * Subranges
-  , isAscii, isLatin1, isAsciiUpper, isAsciiLower
-  -- * Case conversion
-  , toUpper, toLower, toTitle
-  -- * ASCII charactors
-  , _nul, _tab, _lf, _vt, _np, _cr
-  , _space, _exclam, _quotedbl, _numbersign, _dollar, _percent, _ampersand, _quotesingle, _parenleft, _parenright, _asterisk, _plus, _comma, _hyphen, _period, _slash
-  , _0, _1, _2, _3, _4, _5, _6, _7, _8, _9
-  , _colon, _semicolon, _less, _equal, _greater, _question, _at
-  , _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z
-  , _bracketleft, _backslash, _bracketright, _circum, _underscore, _grave
-  , _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z
-  , _braceleft, _bar, _braceright, _tilde, _del
-  -- * Some Latin-1 charactors
-  , _nbsp
-  , _ordfeminine, _softhyphen, _mu, _ordmasculine
-  , _s2, _s3, _s1, _1'4, _1'2, _3'4
-  , _Agrave, _Odieresis, _Oslash, _Thorn
-  , _germandbls, _agrave, _odieresis, _oslash, _thorn, _ydieresis
-  ) where
-
-import Data.Word (Word8)
-
-#ifndef MIN_VERSION_base
-#define MIN_VERSION_base(x,y,z) 1
-#endif
-
-----------------------------------------------------------------
-
-isControl :: Word8 -> Bool
-isControl w = _nul <= w && w <= 0x1f
-           || _del <= w && w <= 0x9f
-
-isSpace :: Word8 -> Bool
-isSpace w = w == _space
-         || w == _tab
-         || w == _lf
-         || w == _cr
-         || w == _np
-         || w == _vt
-         || w == _nbsp
-
--- | This function returns 'True' for 170 and 186 in Unicode 6.
---   But it returns 'False' in Unicode 7.
-isLower :: Word8 -> Bool
-isLower w = isLower' w
-         || w == _mu
-#if !MIN_VERSION_base(4,8,0)
-         || w == _ordfeminine
-         || w == _ordmasculine
-#endif
-
-isLowerCommon :: Word8 -> Bool
-isLowerCommon w = isLower' w
-         || w == _mu
-         || w == _ordfeminine
-         || w == _ordmasculine
-
-isLower' :: Word8 -> Bool
-isLower' w = isAsciiLower w
-          || _germandbls <= w && w <= _odieresis
-          || _oslash     <= w && w <= _ydieresis
-
-isUpper :: Word8 -> Bool
-isUpper w = isAsciiUpper w
-         || _Agrave <= w && w <= _Odieresis
-         || _Oslash <= w && w <= _Thorn
-
-isAlpha :: Word8 -> Bool
-isAlpha w = isLowerCommon w || isUpper w
-
-isAlphaNum :: Word8 -> Bool
-isAlphaNum w = isAlpha w || isNumber w
-
-isPrint :: Word8 -> Bool
-isPrint w
-  | w == _softhyphen = False
-isPrint w = _space <= w && w <= _tilde
-         || _nbsp  <= w && w <= _ydieresis
-
-isDigit :: Word8 -> Bool
-isDigit w = _0 <= w && w <= _9
-
-isOctDigit :: Word8 -> Bool
-isOctDigit w = _0 <= w && w <= _7
-
-isHexDigit :: Word8 -> Bool
-isHexDigit w = isDigit w
-            || _A <= w && w <= _F
-            || _a <= w && w <= _f
-
-isLetter :: Word8 -> Bool
-isLetter w = isLowerCommon w || isUpper w
-
-isMark :: Word8 -> Bool
-isMark _ = False
-
-isNumber :: Word8 -> Bool
-isNumber w = isDigit w
-          || w == _s1
-          || w == _s2
-          || w == _s3
-          || w == _1'4
-          || w == _1'2
-          || w == _3'4
-
--- | This function returns 'False' for 167 and 182 in Unicode 6.
---   But it returns 'True' in Unicode 7.
-isPunctuation :: Word8 -> Bool
-#if MIN_VERSION_base(4,8,0)
-isPunctuation w = w `elem` [0x21,0x22,0x23,0x25,0x26,0x27,0x28,0x29,0x2a,0x2c,0x2d,0x2e,0x2f,0x3a,0x3b,0x3f,0x40,0x5b,0x5c,0x5d,0x5f,0x7b,0x7d,0xa1,0xa7,0xab,0xb6,0xb7,0xbb,0xbf]
-#else
-isPunctuation w = w `elem` [0x21,0x22,0x23,0x25,0x26,0x27,0x28,0x29,0x2a,0x2c,0x2d,0x2e,0x2f,0x3a,0x3b,0x3f,0x40,0x5b,0x5c,0x5d,0x5f,0x7b,0x7d,0xa1,0xab,0xb7,0xbb,0xbf]
-#endif
-
--- | This function returns 'True' for 167 and 182 in Unicode 6.
---   But it returns 'False' in Unicode 7.
-isSymbol :: Word8 -> Bool
-#if MIN_VERSION_base(4,8,0)
-isSymbol w = w `elem` [0x24,0x2b,0x3c,0x3d,0x3e,0x5e,0x60,0x7c,0x7e,0xa2,0xa3,0xa4,0xa5,0xa6,0xa8,0xa9,0xac,0xae,0xaf,0xb0,0xb1,0xb4,0xb8,0xd7,0xf7]
-#else
-isSymbol w = w `elem` [0x24,0x2b,0x3c,0x3d,0x3e,0x5e,0x60,0x7c,0x7e,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xac,0xae,0xaf,0xb0,0xb1,0xb4,0xb6,0xb8,0xd7,0xf7]
-#endif
-
-isSeparator :: Word8 -> Bool
-isSeparator w = w == _space
-             || w == _nbsp
-
-----------------------------------------------------------------
-
-isAscii :: Word8 -> Bool
-isAscii w = _nul <= w && w <= _del
-
-isLatin1 :: Word8 -> Bool
-isLatin1 _ = True
-
-isAsciiUpper :: Word8 -> Bool
-isAsciiUpper w = _A <= w && w <= _Z
-
-isAsciiLower :: Word8 -> Bool
-isAsciiLower w = _a <= w && w <= _z
-
-----------------------------------------------------------------
-
--- | Micro sign/mu (0xb5) and small letter Y with diaeresis (0xff) remain the same.
-toUpper :: Word8 -> Word8
-toUpper w
-  | w == _germandbls = w
-  | isLower' w       = w - _space
-  | otherwise        = w
-
-toLower :: Word8 -> Word8
-toLower w
-  | isUpper w = w + _space
-  | otherwise = w
-
--- | Micro sign/mu (0xb5) and small letter Y with diaeresis (0xff) remain the same.
-toTitle :: Word8 -> Word8
-toTitle = toUpper
-
-----------------------------------------------------------------
-
-_nul, _tab, _lf, _vt, _np, _cr :: Word8
-_nul = 0x00
-_tab = 0x09
-_lf  = 0x0a
-_vt  = 0x0b
-_np  = 0x0c
-_cr  = 0x0d
-
-_space, _exclam, _quotedbl, _numbersign, _dollar, _percent, _ampersand, _quotesingle, _parenleft, _parenright, _asterisk, _plus, _comma, _hyphen, _period, _slash :: Word8
-_space       = 0x20
-_exclam      = 0x21
-_quotedbl    = 0x22
-_numbersign  = 0x23
-_dollar      = 0x24
-_percent     = 0x25
-_ampersand   = 0x26
-_quotesingle = 0x27
-_parenleft   = 0x28
-_parenright  = 0x29
-_asterisk    = 0x2a
-_plus        = 0x2b
-_comma       = 0x2c
-_hyphen      = 0x2d
-_period      = 0x2e
-_slash       = 0x2f
-
-_0, _1, _2, _3, _4, _5, _6, _7, _8, _9 :: Word8
-_0 = 0x30
-_1 = 0x31
-_2 = 0x32
-_3 = 0x33
-_4 = 0x34
-_5 = 0x35
-_6 = 0x36
-_7 = 0x37
-_8 = 0x38
-_9 = 0x39
-
-_colon, _semicolon, _less, _equal, _greater, _question, _at :: Word8
-_colon      = 0x3a
-_semicolon  = 0x3b
-_less       = 0x3c
-_equal      = 0x3d
-_greater    = 0x3e
-_question   = 0x3f
-_at         = 0x40
-
-_A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z :: Word8
-_A = 0x41
-_B = 0x42
-_C = 0x43
-_D = 0x44
-_E = 0x45
-_F = 0x46
-_G = 0x47
-_H = 0x48
-_I = 0x49
-_J = 0x4a
-_K = 0x4b
-_L = 0x4c
-_M = 0x4d
-_N = 0x4e
-_O = 0x4f
-_P = 0x50
-_Q = 0x51
-_R = 0x52
-_S = 0x53
-_T = 0x54
-_U = 0x55
-_V = 0x56
-_W = 0x57
-_X = 0x58
-_Y = 0x59
-_Z = 0x5a
-
-_bracketleft, _backslash, _bracketright, _circum, _underscore, _grave :: Word8
-_bracketleft   = 0x5b
-_backslash    = 0x5c
-_bracketright = 0x5d
-_circum       = 0x5e
-_underscore   = 0x5f
-_grave        = 0x60
-
-_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z :: Word8
-_a = 0x61
-_b = 0x62
-_c = 0x63
-_d = 0x64
-_e = 0x65
-_f = 0x66
-_g = 0x67
-_h = 0x68
-_i = 0x69
-_j = 0x6a
-_k = 0x6b
-_l = 0x6c
-_m = 0x6d
-_n = 0x6e
-_o = 0x6f
-_p = 0x70
-_q = 0x71
-_r = 0x72
-_s = 0x73
-_t = 0x74
-_u = 0x75
-_v = 0x76
-_w = 0x77
-_x = 0x78
-_y = 0x79
-_z = 0x7a
-
-_braceleft, _bar, _braceright, _tilde, _del :: Word8
-_braceleft  = 0x7b
-_bar        = 0x7c
-_braceright = 0x7d
-_tilde      = 0x7e
-_del        = 0x7f
-
-_nbsp :: Word8
-_nbsp = 0xa0
-
-_ordfeminine, _softhyphen, _mu, _ordmasculine :: Word8
-_ordfeminine  = 0xaa
-_softhyphen   = 0xad
-_mu           = 0xb5
-_ordmasculine = 0xba
-
-_s2, _s3, _s1, _1'4, _1'2, _3'4  :: Word8
-_s2 = 0xb2
-_s3 = 0xb3
-_s1 = 0xb9
-_1'4 = 0xbc
-_1'2 = 0xbd
-_3'4 = 0xbe
-
-_Agrave, _Odieresis, _Oslash, _Thorn :: Word8
-_Agrave    = 0xc0
-_Odieresis = 0xd6
-_Oslash    = 0xd8
-_Thorn     = 0xde
-
-_germandbls, _agrave, _odieresis, _oslash, _thorn, _ydieresis :: Word8
-_germandbls = 0xdf
-_agrave     = 0xe0
-_odieresis  = 0xf6
-_oslash     = 0xf8
-_thorn      = 0xfe
-_ydieresis  = 0xff
+-- | Word8 library to be used with "Data.ByteString".
+-- All functions assume that the 'Word8' is encoded in Latin-1 (ISO-8859-1).
+-- All utility functions are supposed to work like those of "Data.Char".
+-- Exceptions are described in the function documentations.
+module Data.Word8 (
+    -- * Re-exporting
+    Word8,
+
+    -- * Functions on bytes
+
+    -- ** Character classification
+    isControl,
+    isSpace,
+    isLower,
+    isUpper,
+    isAlpha,
+    isAlphaNum,
+    isPrint,
+    isDigit,
+    isOctDigit,
+    isHexDigit,
+    isLetter,
+    isMark,
+    isNumber,
+    isPunctuation,
+    isSymbol,
+    isSeparator,
+
+    -- ** Subranges
+    isAscii,
+    isLatin1,
+    isAsciiUpper,
+    isAsciiLower,
+
+    -- ** Case conversion
+    toUpper,
+    toLower,
+    toTitle,
+
+    -- * Byte constants
+
+    -- ** ASCII characters
+    _nul,
+    _tab,
+    _lf,
+    _vt,
+    _np,
+    _cr,
+    _space,
+    _exclam,
+    _quotedbl,
+    _numbersign,
+    _dollar,
+    _percent,
+    _ampersand,
+    _quotesingle,
+    _parenleft,
+    _parenright,
+    _asterisk,
+    _plus,
+    _comma,
+    _hyphen,
+    _period,
+    _slash,
+    _0,
+    _1,
+    _2,
+    _3,
+    _4,
+    _5,
+    _6,
+    _7,
+    _8,
+    _9,
+    _colon,
+    _semicolon,
+    _less,
+    _equal,
+    _greater,
+    _question,
+    _at,
+    _A,
+    _B,
+    _C,
+    _D,
+    _E,
+    _F,
+    _G,
+    _H,
+    _I,
+    _J,
+    _K,
+    _L,
+    _M,
+    _N,
+    _O,
+    _P,
+    _Q,
+    _R,
+    _S,
+    _T,
+    _U,
+    _V,
+    _W,
+    _X,
+    _Y,
+    _Z,
+    _bracketleft,
+    _backslash,
+    _bracketright,
+    _circum,
+    _underscore,
+    _grave,
+    _a,
+    _b,
+    _c,
+    _d,
+    _e,
+    _f,
+    _g,
+    _h,
+    _i,
+    _j,
+    _k,
+    _l,
+    _m,
+    _n,
+    _o,
+    _p,
+    _q,
+    _r,
+    _s,
+    _t,
+    _u,
+    _v,
+    _w,
+    _x,
+    _y,
+    _z,
+    _braceleft,
+    _bar,
+    _braceright,
+    _tilde,
+    _del,
+
+    -- ** Some Latin-1 characters
+    _nbsp,
+    _ordfeminine,
+    _softhyphen,
+    _mu,
+    _ordmasculine,
+    _s2,
+    _s3,
+    _s1,
+    _1'4,
+    _1'2,
+    _3'4,
+    _Agrave,
+    _Odieresis,
+    _Oslash,
+    _Thorn,
+    _germandbls,
+    _agrave,
+    _odieresis,
+    _oslash,
+    _thorn,
+    _ydieresis,
+) where
+
+import Data.Bits (unsafeShiftR, (.&.))
+import Data.Word (Word64, Word8)
+
+----------------------------------------------------------------
+
+-- | Is the byte a control character
+isControl :: Word8 -> Bool
+isControl w =
+    w <= 0x1f
+        || _del <= w && w <= 0x9f
+
+-- | Is the byte white space
+isSpace :: Word8 -> Bool
+isSpace w =
+    w == _space
+        || w == _tab
+        || w == _lf
+        || w == _cr
+        || w == _np
+        || w == _vt
+        || w == _nbsp
+
+-- | Is the byte a lower case character
+--
+-- This function returns 'False' for 170 (ª) and 186 (º).
+isLower :: Word8 -> Bool
+isLower w =
+    isLower' w
+        || w == _mu
+
+isLowerCommon :: Word8 -> Bool
+isLowerCommon w =
+    isLower' w
+        || w == _mu
+        || w == _ordfeminine
+        || w == _ordmasculine
+
+isLower' :: Word8 -> Bool
+isLower' w =
+    isAsciiLower w
+        || _germandbls <= w && w <= _ydieresis && w /= 0xf7
+
+-- | Is the byte an upper case character
+isUpper :: Word8 -> Bool
+isUpper w =
+    isAsciiUpper w
+        || _Agrave <= w && w <= _Thorn && w /= 0xd7
+
+-- | Is the byte an alphabet letter
+--
+-- Synonym for 'isLetter'
+isAlpha :: Word8 -> Bool
+isAlpha w = isLowerCommon w || isUpper w
+
+-- | Is the byte an alphabet letter or a number
+isAlphaNum :: Word8 -> Bool
+isAlphaNum w = isAlpha w || isNumber w
+
+-- | Is the byte printable
+isPrint :: Word8 -> Bool
+isPrint w
+    | w == _softhyphen = False
+isPrint w =
+    _space <= w && w <= _tilde
+        || _nbsp <= w && w <= _ydieresis
+
+-- | Is the byte a digit (@0-9@)
+isDigit :: Word8 -> Bool
+isDigit w = _0 <= w && w <= _9
+
+-- | Is the byte an octal digit (@0-7@)
+isOctDigit :: Word8 -> Bool
+isOctDigit w = _0 <= w && w <= _7
+
+-- | Is the byte a hexadecimal digit (@0-9a-fA-F@)
+isHexDigit :: Word8 -> Bool
+isHexDigit w =
+    isDigit w
+        || _A <= w && w <= _F
+        || _a <= w && w <= _f
+
+-- | Is the byte an alphabet letter
+--
+-- Synonym for 'isAlpha'
+isLetter :: Word8 -> Bool
+isLetter w = isLowerCommon w || isUpper w
+
+-- | A byte is never a mark
+--
+-- Synonymous with @const False@
+isMark :: Word8 -> Bool
+isMark _ = False
+
+-- | Is the byte a number
+isNumber :: Word8 -> Bool
+isNumber w =
+    isDigit w
+        || w == _s1
+        || w == _s2
+        || w == _s3
+        || w == _1'4
+        || w == _1'2
+        || w == _3'4
+
+-- | Is the byte a punctuation character
+--
+-- This function returns 'True' for 167 (§) and 182 (¶).
+isPunctuation :: Word8 -> Bool
+-- Bitmap of !"#%&'()*,-./:;?@[\]_{} and ¡§«¶·»¿
+{-# INLINE isPunctuation #-}
+isPunctuation w =
+    inBitmap 0x8c00f7ee00000000 0x28000000b8000001 0x88c0088200000000 0 w
+
+-- | Is the byte a symbol character
+--
+-- This function returns 'False' for 167 (§) and 182 (¶).
+isSymbol :: Word8 -> Bool
+-- Bitmap of $+<=>^`|~ and ¢£¤¥¦¨©¬®¯°±´¸×÷
+{-# INLINE isSymbol #-}
+isSymbol w =
+    inBitmap
+        0x7000081000000000
+        0x5000000140000000
+        0x0113d37c00000000
+        0x0080000000800000
+        w
+
+-- Membership test for a 256-bit set given as four 64-bit words.
+inBitmap :: Word64 -> Word64 -> Word64 -> Word64 -> Word8 -> Bool
+inBitmap b0 b1 b2 b3 w = (b `unsafeShiftR` fromIntegral (w .&. 63)) .&. 1 /= 0
+  where
+    b = case w `unsafeShiftR` 6 of
+        0 -> b0
+        1 -> b1
+        2 -> b2
+        _ -> b3
+{-# INLINE inBitmap #-}
+
+-- | Is the byte a (non-breaking) space
+isSeparator :: Word8 -> Bool
+isSeparator w =
+    w == _space
+        || w == _nbsp
+
+----------------------------------------------------------------
+
+-- | Is the byte in the ASCII range
+isAscii :: Word8 -> Bool
+isAscii w = w .&. 0x80 == 0
+
+-- | Every byte is in the Latin-1 range
+--
+-- Synonymous with @const True@
+isLatin1 :: Word8 -> Bool
+isLatin1 _ = True
+
+-- | Is the byte an upper case ASCII letter (@A-Z@)
+isAsciiUpper :: Word8 -> Bool
+isAsciiUpper w = _A <= w && w <= _Z
+
+-- | Is the byte a lower case ASCII letter (@a-z@)
+isAsciiLower :: Word8 -> Bool
+isAsciiLower w = _a <= w && w <= _z
+
+----------------------------------------------------------------
+
+-- | Changes the byte to the upper case variant, if possible.
+--
+-- Micro sign/mu ('_mu') and small letter Y with diaeresis ('_ydieresis') remain the same.
+toUpper :: Word8 -> Word8
+toUpper w
+    | w == _germandbls = w
+    | w == _ydieresis = w
+    | isLower' w = w - _space
+    | otherwise = w
+
+-- | Changes the byte to the lower case variant, if possible.
+toLower :: Word8 -> Word8
+toLower w
+    | isUpper w = w + _space
+    | otherwise = w
+
+-- | Synonym for 'toUpper'
+toTitle :: Word8 -> Word8
+toTitle = toUpper
+
+----------------------------------------------------------------
+
+-- | Null character
+--
+-- > BIN:  0b00000000
+-- > OCT:  0o000
+-- > DEC:  0
+-- > HEX:  0x00
+-- > HTML: &#00;
+-- > Char: '\NUL'
+_nul :: Word8
+_nul = 0x00
+
+-- | Horizontal Tab
+--
+-- > BIN:  0b00001001
+-- > OCT:  0o011
+-- > DEC:  9
+-- > HEX:  0x09
+-- > HTML: &#09;
+-- > Char: '\HT' or '\t'
+_tab :: Word8
+_tab = 0x09
+
+-- | Line Feed
+--
+-- > BIN:  0b00001010
+-- > OCT:  0o012
+-- > DEC:  10
+-- > HEX:  0x0A
+-- > HTML: &#10;
+-- > Char: '\LF' or '\n'
+_lf :: Word8
+_lf = 0x0a
+
+-- | Vertical Tabulation
+--
+-- > BIN:  0b00001011
+-- > OCT:  0o013
+-- > DEC:  11
+-- > HEX:  0x0B
+-- > HTML: &#11;
+-- > Char: '\VT'
+_vt :: Word8
+_vt = 0x0b
+
+-- | Form Feed (New Page)
+--
+-- > BIN:  0b00001100
+-- > OCT:  0o014
+-- > DEC:  12
+-- > HEX:  0x0C
+-- > HTML: &#12;
+-- > Char: '\FF'
+_np :: Word8
+_np = 0x0c
+
+-- | Carriage Return
+--
+-- > BIN:  0b00001101
+-- > OCT:  0o015
+-- > DEC:  13
+-- > HEX:  0x0D
+-- > HTML: &#13;
+-- > Char: '\CR' or '\r'
+_cr :: Word8
+_cr = 0x0d
+
+-- | Space
+--
+-- > BIN:  0b00100000
+-- > OCT:  0o040
+-- > DEC:  32
+-- > HEX:  0x20
+-- > HTML: &#32;
+-- > Char: '\SP' or ' '
+_space :: Word8
+_space = 0x20
+
+-- | Exclamation mark
+--
+-- > BIN:  0b00100001
+-- > OCT:  0o041
+-- > DEC:  33
+-- > HEX:  0x21
+-- > HTML: &#33; or &excl;
+-- > Char: '!'
+_exclam :: Word8
+_exclam = 0x21
+
+-- | Double quotes (or speech marks)
+--
+-- > BIN:  0b00100010
+-- > OCT:  0o042
+-- > DEC:  34
+-- > HEX:  0x22
+-- > HTML: &#34; or &quot;
+-- > Char: '"'
+_quotedbl :: Word8
+_quotedbl = 0x22
+
+-- | Number sign (or hash sign, or pound sign)
+--
+-- > BIN:  0b00100011
+-- > OCT:  0o043
+-- > DEC:  35
+-- > HEX:  0x23
+-- > HTML: &#35; or &num;
+-- > Char: '#'
+_numbersign :: Word8
+_numbersign = 0x23
+
+-- | Dollar
+--
+-- > BIN:  0b00100100
+-- > OCT:  0o044
+-- > DEC:  36
+-- > HEX:  0x24
+-- > HTML: &#36; or &dollar;
+-- > Char: '$'
+_dollar :: Word8
+_dollar = 0x24
+
+-- | Per cent sign
+--
+-- > BIN:  0b00100101
+-- > OCT:  0o045
+-- > DEC:  37
+-- > HEX:  0x25
+-- > HTML: &#37; or &percnt;
+-- > Char: '%'
+_percent :: Word8
+_percent = 0x25
+
+-- | Ampersand
+--
+-- > BIN:  0b00100110
+-- > OCT:  0o046
+-- > DEC:  38
+-- > HEX:  0x26
+-- > HTML: &#38; or &amp;
+-- > Char: '&'
+_ampersand :: Word8
+_ampersand = 0x26
+
+-- | Single quote
+--
+-- > BIN:  0b00100111
+-- > OCT:  0o047
+-- > DEC:  39
+-- > HEX:  0x27
+-- > HTML: &#39; or &apos;
+-- > Char: '\''
+_quotesingle :: Word8
+_quotesingle = 0x27
+
+-- | Open parenthesis (or open bracket)
+--
+-- > BIN:  0b00101000
+-- > OCT:  0o050
+-- > DEC:  40
+-- > HEX:  0x28
+-- > HTML: &#40; or &lparen;
+-- > Char: '('
+_parenleft :: Word8
+_parenleft = 0x28
+
+-- | Close parenthesis (or close bracket)
+--
+-- > BIN:  0b00101001
+-- > OCT:  0o051
+-- > DEC:  41
+-- > HEX:  0x29
+-- > HTML: &#41; or &rparen;
+-- > Char: ')'
+_parenright :: Word8
+_parenright = 0x29
+
+-- | Asterisk
+--
+-- > BIN:  0b00101010
+-- > OCT:  0o052
+-- > DEC:  42
+-- > HEX:  0x2A
+-- > HTML: &#42; or &ast;
+-- > Char: '*'
+_asterisk :: Word8
+_asterisk = 0x2a
+
+-- | Plus
+--
+-- > BIN:  0b00101011
+-- > OCT:  0o053
+-- > DEC:  43
+-- > HEX:  0x2B
+-- > HTML: &#43; or &plus;
+-- > Char: '+'
+_plus :: Word8
+_plus = 0x2b
+
+-- | Comma
+--
+-- > BIN:  0b00101100
+-- > OCT:  0o054
+-- > DEC:  44
+-- > HEX:  0x2C
+-- > HTML: &#44; or &comma;
+-- > Char: ','
+_comma :: Word8
+_comma = 0x2c
+
+-- | Hyphen (or minus, or dash)
+--
+-- > BIN:  0b00101101
+-- > OCT:  0o055
+-- > DEC:  45
+-- > HEX:  0x2D
+-- > HTML: &#45;
+-- > Char: '-'
+_hyphen :: Word8
+_hyphen = 0x2d
+
+-- | Period (or dot, or full stop)
+--
+-- > BIN:  0b00101110
+-- > OCT:  0o056
+-- > DEC:  46
+-- > HEX:  0x2E
+-- > HTML: &#46; or &period;
+-- > Char: '.'
+_period :: Word8
+_period = 0x2e
+
+-- | Slash (or divide)
+--
+-- > BIN:  0b00101111
+-- > OCT:  0o057
+-- > DEC:  47
+-- > HEX:  0x2F
+-- > HTML: &#47; or &sol;
+-- > Char: '/'
+_slash :: Word8
+_slash = 0x2f
+
+-- | Zero
+--
+-- > BIN:  0b00110000
+-- > OCT:  0o060
+-- > DEC:  48
+-- > HEX:  0x30
+-- > HTML: &#48;
+-- > Char: '0'
+_0 :: Word8
+_0 = 0x30
+
+-- | One
+--
+-- > BIN:  0b00110001
+-- > OCT:  0o061
+-- > DEC:  49
+-- > HEX:  0x31
+-- > HTML: &#49;
+-- > Char: '1'
+_1 :: Word8
+_1 = 0x31
+
+-- | Two
+--
+-- > BIN:  0b00110010
+-- > OCT:  0o062
+-- > DEC:  50
+-- > HEX:  0x32
+-- > HTML: &#50;
+-- > Char: '2'
+_2 :: Word8
+_2 = 0x32
+
+-- | Three
+--
+-- > BIN:  0b00110011
+-- > OCT:  0o063
+-- > DEC:  51
+-- > HEX:  0x33
+-- > HTML: &#51;
+-- > Char: '3'
+_3 :: Word8
+_3 = 0x33
+
+-- | Four
+--
+-- > BIN:  0b00110100
+-- > OCT:  0o064
+-- > DEC:  52
+-- > HEX:  0x34
+-- > HTML: &#52;
+-- > Char: '4'
+_4 :: Word8
+_4 = 0x34
+
+-- | Five
+--
+-- > BIN:  0b00110101
+-- > OCT:  0o065
+-- > DEC:  53
+-- > HEX:  0x35
+-- > HTML: &#53;
+-- > Char: '5'
+_5 :: Word8
+_5 = 0x35
+
+-- | Six
+--
+-- > BIN:  0b00110110
+-- > OCT:  0o066
+-- > DEC:  54
+-- > HEX:  0x36
+-- > HTML: &#54;
+-- > Char: '6'
+_6 :: Word8
+_6 = 0x36
+
+-- | Seven
+--
+-- > BIN:  0b00110111
+-- > OCT:  0o067
+-- > DEC:  55
+-- > HEX:  0x37
+-- > HTML: &#55;
+-- > Char: '7'
+_7 :: Word8
+_7 = 0x37
+
+-- | Eight
+--
+-- > BIN:  0b00111000
+-- > OCT:  0o070
+-- > DEC:  56
+-- > HEX:  0x38
+-- > HTML: &#56;
+-- > Char: '8'
+_8 :: Word8
+_8 = 0x38
+
+-- | Nine
+--
+-- > BIN:  0b00111001
+-- > OCT:  0o071
+-- > DEC:  57
+-- > HEX:  0x39
+-- > HTML: &#57;
+-- > Char: '9'
+_9 :: Word8
+_9 = 0x39
+
+-- | Colon
+--
+-- > BIN:  0b00111010
+-- > OCT:  0o072
+-- > DEC:  58
+-- > HEX:  0x3A
+-- > HTML: &#58; or &colon;
+-- > Char: ':'
+_colon :: Word8
+_colon = 0x3a
+
+-- | Semicolon
+--
+-- > BIN:  0b00111011
+-- > OCT:  0o073
+-- > DEC:  59
+-- > HEX:  0x3B
+-- > HTML: &#59; or &semi;
+-- > Char: ';'
+_semicolon :: Word8
+_semicolon = 0x3b
+
+-- | Less than (or open angled bracket)
+--
+-- > BIN:  0b00111100
+-- > OCT:  0o074
+-- > DEC:  60
+-- > HEX:  0x3C
+-- > HTML: &#60; or &lt;
+-- > Char: '<'
+_less :: Word8
+_less = 0x3c
+
+-- | Equals
+--
+-- > BIN:  0b00111101
+-- > OCT:  0o075
+-- > DEC:  61
+-- > HEX:  0x3D
+-- > HTML: &#61; or &equals;
+-- > Char: '='
+_equal :: Word8
+_equal = 0x3d
+
+-- | Greater than (or close angled bracket)
+--
+-- > BIN:  0b00111110
+-- > OCT:  0o076
+-- > DEC:  62
+-- > HEX:  0x3E
+-- > HTML: &#62; or &gt;
+-- > Char: '>'
+_greater :: Word8
+_greater = 0x3e
+
+-- | Question mark
+--
+-- > BIN:  0b00111111
+-- > OCT:  0o077
+-- > DEC:  63
+-- > HEX:  0x3F
+-- > HTML: &#63; or &quest;
+-- > Char: '?'
+_question :: Word8
+_question = 0x3f
+
+-- | At sign
+--
+-- > BIN:  0b01000000
+-- > OCT:  0o100
+-- > DEC:  64
+-- > HEX:  0x40
+-- > HTML: &#64; or &commat;
+-- > Char: '@'
+_at :: Word8
+_at = 0x40
+
+-- | Uppercase A
+--
+-- > BIN:  0b01000001
+-- > OCT:  0o101
+-- > DEC:  65
+-- > HEX:  0x41
+-- > HTML: &#65;
+-- > Char: 'A'
+_A :: Word8
+_A = 0x41
+
+-- | Uppercase B
+--
+-- > BIN:  0b01000010
+-- > OCT:  0o102
+-- > DEC:  66
+-- > HEX:  0x42
+-- > HTML: &#66;
+-- > Char: 'B'
+_B :: Word8
+_B = 0x42
+
+-- | Uppercase C
+--
+-- > BIN:  0b01000011
+-- > OCT:  0o103
+-- > DEC:  67
+-- > HEX:  0x43
+-- > HTML: &#67;
+-- > Char: 'C'
+_C :: Word8
+_C = 0x43
+
+-- | Uppercase D
+--
+-- > BIN:  0b01000100
+-- > OCT:  0o104
+-- > DEC:  68
+-- > HEX:  0x44
+-- > HTML: &#68;
+-- > Char: 'D'
+_D :: Word8
+_D = 0x44
+
+-- | Uppercase E
+--
+-- > BIN:  0b01000101
+-- > OCT:  0o105
+-- > DEC:  69
+-- > HEX:  0x45
+-- > HTML: &#69;
+-- > Char: 'E'
+_E :: Word8
+_E = 0x45
+
+-- | Uppercase F
+--
+-- > BIN:  0b01000110
+-- > OCT:  0o106
+-- > DEC:  70
+-- > HEX:  0x46
+-- > HTML: &#70;
+-- > Char: 'F'
+_F :: Word8
+_F = 0x46
+
+-- | Uppercase G
+--
+-- > BIN:  0b01000111
+-- > OCT:  0o107
+-- > DEC:  71
+-- > HEX:  0x47
+-- > HTML: &#71;
+-- > Char: 'G'
+_G :: Word8
+_G = 0x47
+
+-- | Uppercase H
+--
+-- > BIN:  0b01001000
+-- > OCT:  0o110
+-- > DEC:  72
+-- > HEX:  0x48
+-- > HTML: &#72;
+-- > Char: 'H'
+_H :: Word8
+_H = 0x48
+
+-- | Uppercase I
+--
+-- > BIN:  0b01001001
+-- > OCT:  0o111
+-- > DEC:  73
+-- > HEX:  0x49
+-- > HTML: &#73;
+-- > Char: 'I'
+_I :: Word8
+_I = 0x49
+
+-- | Uppercase J
+--
+-- > BIN:  0b01001010
+-- > OCT:  0o112
+-- > DEC:  74
+-- > HEX:  0x4A
+-- > HTML: &#74;
+-- > Char: 'J'
+_J :: Word8
+_J = 0x4a
+
+-- | Uppercase K
+--
+-- > BIN:  0b01001011
+-- > OCT:  0o113
+-- > DEC:  75
+-- > HEX:  0x4B
+-- > HTML: &#75;
+-- > Char: 'K'
+_K :: Word8
+_K = 0x4b
+
+-- | Uppercase L
+--
+-- > BIN:  0b01001100
+-- > OCT:  0o114
+-- > DEC:  76
+-- > HEX:  0x4C
+-- > HTML: &#76;
+-- > Char: 'L'
+_L :: Word8
+_L = 0x4c
+
+-- | Uppercase M
+--
+-- > BIN:  0b01001101
+-- > OCT:  0o115
+-- > DEC:  77
+-- > HEX:  0x4D
+-- > HTML: &#77;
+-- > Char: 'M'
+_M :: Word8
+_M = 0x4d
+
+-- | Uppercase N
+--
+-- > BIN:  0b01001110
+-- > OCT:  0o116
+-- > DEC:  78
+-- > HEX:  0x4E
+-- > HTML: &#78;
+-- > Char: 'N'
+_N :: Word8
+_N = 0x4e
+
+-- | Uppercase O
+--
+-- > BIN:  0b01001111
+-- > OCT:  0o117
+-- > DEC:  79
+-- > HEX:  0x4F
+-- > HTML: &#79;
+-- > Char: 'O'
+_O :: Word8
+_O = 0x4f
+
+-- | Uppercase P
+--
+-- > BIN:  0b01010000
+-- > OCT:  0o120
+-- > DEC:  80
+-- > HEX:  0x50
+-- > HTML: &#80;
+-- > Char: 'P'
+_P :: Word8
+_P = 0x50
+
+-- | Uppercase Q
+--
+-- > BIN:  0b01010001
+-- > OCT:  0o121
+-- > DEC:  81
+-- > HEX:  0x51
+-- > HTML: &#81;
+-- > Char: 'Q'
+_Q :: Word8
+_Q = 0x51
+
+-- | Uppercase R
+--
+-- > BIN:  0b01010010
+-- > OCT:  0o122
+-- > DEC:  82
+-- > HEX:  0x52
+-- > HTML: &#82;
+-- > Char: 'R'
+_R :: Word8
+_R = 0x52
+
+-- | Uppercase S
+--
+-- > BIN:  0b01010011
+-- > OCT:  0o123
+-- > DEC:  83
+-- > HEX:  0x53
+-- > HTML: &#83;
+-- > Char: 'S'
+_S :: Word8
+_S = 0x53
+
+-- | Uppercase T
+--
+-- > BIN:  0b01010100
+-- > OCT:  0o124
+-- > DEC:  84
+-- > HEX:  0x54
+-- > HTML: &#84;
+-- > Char: 'T'
+_T :: Word8
+_T = 0x54
+
+-- | Uppercase U
+--
+-- > BIN:  0b01010101
+-- > OCT:  0o125
+-- > DEC:  85
+-- > HEX:  0x55
+-- > HTML: &#85;
+-- > Char: 'U'
+_U :: Word8
+_U = 0x55
+
+-- | Uppercase V
+--
+-- > BIN:  0b01010110
+-- > OCT:  0o126
+-- > DEC:  86
+-- > HEX:  0x56
+-- > HTML: &#86;
+-- > Char: 'V'
+_V :: Word8
+_V = 0x56
+
+-- | Uppercase W
+--
+-- > BIN:  0b01010111
+-- > OCT:  0o127
+-- > DEC:  87
+-- > HEX:  0x57
+-- > HTML: &#87;
+-- > Char: 'W'
+_W :: Word8
+_W = 0x57
+
+-- | Uppercase X
+--
+-- > BIN:  0b01011000
+-- > OCT:  0o130
+-- > DEC:  88
+-- > HEX:  0x58
+-- > HTML: &#88;
+-- > Char: 'X'
+_X :: Word8
+_X = 0x58
+
+-- | Uppercase Y
+--
+-- > BIN:  0b01011001
+-- > OCT:  0o131
+-- > DEC:  89
+-- > HEX:  0x59
+-- > HTML: &#89;
+-- > Char: 'Y'
+_Y :: Word8
+_Y = 0x59
+
+-- | Uppercase Z
+--
+-- > BIN:  0b01011010
+-- > OCT:  0o132
+-- > DEC:  90
+-- > HEX:  0x5A
+-- > HTML: &#90;
+-- > Char: 'Z'
+_Z :: Word8
+_Z = 0x5a
+
+-- | Opening bracket
+--
+-- > BIN:  0b01011011
+-- > OCT:  0o133
+-- > DEC:  91
+-- > HEX:  0x5B
+-- > HTML: &#91; or &lsqb;
+-- > Char: '['
+_bracketleft :: Word8
+_bracketleft = 0x5b
+
+-- | Backslash
+--
+-- > BIN:  0b01011100
+-- > OCT:  0o134
+-- > DEC:  92
+-- > HEX:  0x5C
+-- > HTML: &#92; or &bsol;
+-- > Char: '\'
+_backslash :: Word8
+_backslash = 0x5c
+
+-- | Closing bracket
+--
+-- > BIN:  0b01011101
+-- > OCT:  0o135
+-- > DEC:  93
+-- > HEX:  0x5D
+-- > HTML: &#93; or &rsqb;
+-- > Char: ']'
+_bracketright :: Word8
+_bracketright = 0x5d
+
+-- | Caret - circumflex
+--
+-- > BIN:  0b01011110
+-- > OCT:  0o136
+-- > DEC:  94
+-- > HEX:  0x5E
+-- > HTML: &#94; or &Hat;
+-- > Char: '^'
+_circum :: Word8
+_circum = 0x5e
+
+-- | Underscore
+--
+-- > BIN:  0b01011111
+-- > OCT:  0o137
+-- > DEC:  95
+-- > HEX:  0x5F
+-- > HTML: &#95; or &lowbar;
+-- > Char: '_'
+_underscore :: Word8
+_underscore = 0x5f
+
+-- | Grave accent
+--
+-- > BIN:  0b01100000
+-- > OCT:  0o140
+-- > DEC:  96
+-- > HEX:  0x60
+-- > HTML: &#96; or &grave;
+-- > Char: '`'
+_grave :: Word8
+_grave = 0x60
+
+-- | Lowercase a
+--
+-- > BIN:  0b01100001
+-- > OCT:  0o141
+-- > DEC:  97
+-- > HEX:  0x61
+-- > HTML: &#97;
+-- > Char: 'a'
+_a :: Word8
+_a = 0x61
+
+-- | Lowercase b
+--
+-- > BIN:  0b01100010
+-- > OCT:  0o142
+-- > DEC:  98
+-- > HEX:  0x62
+-- > HTML: &#98;
+-- > Char: 'b'
+_b :: Word8
+_b = 0x62
+
+-- | Lowercase c
+--
+-- > BIN:  0b01100011
+-- > OCT:  0o143
+-- > DEC:  99
+-- > HEX:  0x63
+-- > HTML: &#99;
+-- > Char: 'c'
+_c :: Word8
+_c = 0x63
+
+-- | Lowercase d
+--
+-- > BIN:  0b01100100
+-- > OCT:  0o144
+-- > DEC:  100
+-- > HEX:  0x64
+-- > HTML: &#100;
+-- > Char: 'd'
+_d :: Word8
+_d = 0x64
+
+-- | Lowercase e
+--
+-- > BIN:  0b01100101
+-- > OCT:  0o145
+-- > DEC:  101
+-- > HEX:  0x65
+-- > HTML: &#101;
+-- > Char: 'e'
+_e :: Word8
+_e = 0x65
+
+-- | Lowercase f
+--
+-- > BIN:  0b01100110
+-- > OCT:  0o146
+-- > DEC:  102
+-- > HEX:  0x66
+-- > HTML: &#102;
+-- > Char: 'f'
+_f :: Word8
+_f = 0x66
+
+-- | Lowercase g
+--
+-- > BIN:  0b01100111
+-- > OCT:  0o147
+-- > DEC:  103
+-- > HEX:  0x67
+-- > HTML: &#103;
+-- > Char: 'g'
+_g :: Word8
+_g = 0x67
+
+-- | Lowercase h
+--
+-- > BIN:  0b01101000
+-- > OCT:  0o150
+-- > DEC:  104
+-- > HEX:  0x68
+-- > HTML: &#104;
+-- > Char: 'h'
+_h :: Word8
+_h = 0x68
+
+-- | Lowercase i
+--
+-- > BIN:  0b01101001
+-- > OCT:  0o151
+-- > DEC:  105
+-- > HEX:  0x69
+-- > HTML: &#105;
+-- > Char: 'i'
+_i :: Word8
+_i = 0x69
+
+-- | Lowercase j
+--
+-- > BIN:  0b01101010
+-- > OCT:  0o152
+-- > DEC:  106
+-- > HEX:  0x6A
+-- > HTML: &#106;
+-- > Char: 'j'
+_j :: Word8
+_j = 0x6a
+
+-- | Lowercase k
+--
+-- > BIN:  0b01101011
+-- > OCT:  0o153
+-- > DEC:  107
+-- > HEX:  0x6B
+-- > HTML: &#107;
+-- > Char: 'k'
+_k :: Word8
+_k = 0x6b
+
+-- | Lowercase l
+--
+-- > BIN:  0b01101100
+-- > OCT:  0o154
+-- > DEC:  108
+-- > HEX:  0x6C
+-- > HTML: &#108;
+-- > Char: 'l'
+_l :: Word8
+_l = 0x6c
+
+-- | Lowercase m
+--
+-- > BIN:  0b01101101
+-- > OCT:  0o155
+-- > DEC:  109
+-- > HEX:  0x6D
+-- > HTML: &#109;
+-- > Char: 'm'
+_m :: Word8
+_m = 0x6d
+
+-- | Lowercase n
+--
+-- > BIN:  0b01101110
+-- > OCT:  0o156
+-- > DEC:  110
+-- > HEX:  0x6E
+-- > HTML: &#110;
+-- > Char: 'n'
+_n :: Word8
+_n = 0x6e
+
+-- | Lowercase o
+--
+-- > BIN:  0b01101111
+-- > OCT:  0o157
+-- > DEC:  111
+-- > HEX:  0x6F
+-- > HTML: &#111;
+-- > Char: 'o'
+_o :: Word8
+_o = 0x6f
+
+-- | Lowercase p
+--
+-- > BIN:  0b01110000
+-- > OCT:  0o160
+-- > DEC:  112
+-- > HEX:  0x70
+-- > HTML: &#112;
+-- > Char: 'p'
+_p :: Word8
+_p = 0x70
+
+-- | Lowercase q
+--
+-- > BIN:  0b01110001
+-- > OCT:  0o161
+-- > DEC:  113
+-- > HEX:  0x71
+-- > HTML: &#113;
+-- > Char: 'q'
+_q :: Word8
+_q = 0x71
+
+-- | Lowercase r
+--
+-- > BIN:  0b01110010
+-- > OCT:  0o162
+-- > DEC:  114
+-- > HEX:  0x72
+-- > HTML: &#114;
+-- > Char: 'r'
+_r :: Word8
+_r = 0x72
+
+-- | Lowercase s
+--
+-- > BIN:  0b01110011
+-- > OCT:  0o163
+-- > DEC:  115
+-- > HEX:  0x73
+-- > HTML: &#115;
+-- > Char: 's'
+_s :: Word8
+_s = 0x73
+
+-- | Lowercase t
+--
+-- > BIN:  0b01110100
+-- > OCT:  0o164
+-- > DEC:  116
+-- > HEX:  0x74
+-- > HTML: &#116;
+-- > Char: 't'
+_t :: Word8
+_t = 0x74
+
+-- | Lowercase u
+--
+-- > BIN:  0b01110101
+-- > OCT:  0o165
+-- > DEC:  117
+-- > HEX:  0x75
+-- > HTML: &#117;
+-- > Char: 'u'
+_u :: Word8
+_u = 0x75
+
+-- | Lowercase v
+--
+-- > BIN:  0b01110110
+-- > OCT:  0o166
+-- > DEC:  118
+-- > HEX:  0x76
+-- > HTML: &#118;
+-- > Char: 'v'
+_v :: Word8
+_v = 0x76
+
+-- | Lowercase w
+--
+-- > BIN:  0b01110111
+-- > OCT:  0o167
+-- > DEC:  119
+-- > HEX:  0x77
+-- > HTML: &#119;
+-- > Char: 'w'
+_w :: Word8
+_w = 0x77
+
+-- | Lowercase x
+--
+-- > BIN:  0b01111000
+-- > OCT:  0o170
+-- > DEC:  120
+-- > HEX:  0x78
+-- > HTML: &#120;
+-- > Char: 'x'
+_x :: Word8
+_x = 0x78
+
+-- | Lowercase y
+--
+-- > BIN:  0b01111001
+-- > OCT:  0o171
+-- > DEC:  121
+-- > HEX:  0x79
+-- > HTML: &#121;
+-- > Char: 'y'
+_y :: Word8
+_y = 0x79
+
+-- | Lowercase z
+--
+-- > BIN:  0b01111010
+-- > OCT:  0o172
+-- > DEC:  122
+-- > HEX:  0x7A
+-- > HTML: &#122;
+-- > Char: 'z'
+_z :: Word8
+_z = 0x7a
+
+-- | Opening brace
+--
+-- > BIN:  0b01111011
+-- > OCT:  0o173
+-- > DEC:  123
+-- > HEX:  0x7B
+-- > HTML: &#123; or &lcub;
+-- > Char: '{'
+_braceleft :: Word8
+_braceleft = 0x7b
+
+-- | Vertical bar
+--
+-- > BIN:  0b01111100
+-- > OCT:  0o174
+-- > DEC:  124
+-- > HEX:  0x7C
+-- > HTML: &#124; or &verbar;
+-- > Char: '|'
+_bar :: Word8
+_bar = 0x7c
+
+-- | Closing brace
+--
+-- > BIN:  0b01111101
+-- > OCT:  0o175
+-- > DEC:  125
+-- > HEX:  0x7D
+-- > HTML: &#125; or &rcub;
+-- > Char: '}'
+_braceright :: Word8
+_braceright = 0x7d
+
+-- | Equivalency sign - tilde
+--
+-- > BIN:  0b01111110
+-- > OCT:  0o176
+-- > DEC:  126
+-- > HEX:  0x7E
+-- > HTML: &#126; or &tilde;
+-- > Char: '~'
+_tilde :: Word8
+_tilde = 0x7e
+
+-- | Delete
+--
+-- > BIN:  0b01111111
+-- > OCT:  0o177
+-- > DEC:  127
+-- > HEX:  0x7F
+-- > HTML: &#127;
+-- > Char: '\DEL'
+_del :: Word8
+_del = 0x7f
+
+-- | Non-breaking space
+--
+-- > BIN:  0b10100000
+-- > OCT:  0o240
+-- > DEC:  160
+-- > HEX:  0xA0
+-- > HTML: &#160; or &nbsp;
+_nbsp :: Word8
+_nbsp = 0xa0
+
+-- | Feminine ordinal indicator
+--
+-- > BIN:  0b10101010
+-- > OCT:  0o252
+-- > DEC:  170
+-- > HEX:  0xAA
+-- > HTML: &#170; or &ordf;
+-- > Char: 'ª'
+_ordfeminine :: Word8
+_ordfeminine = 0xaa
+
+-- | Soft hyphen
+--
+-- > BIN:  0b10101101
+-- > OCT:  0o255
+-- > DEC:  173
+-- > HEX:  0xAD
+-- > HTML: &#173; or &shy;
+_softhyphen :: Word8
+_softhyphen = 0xad
+
+-- | Micro sign (or greek letter mu)
+--
+-- > BIN:  0b10110101
+-- > OCT:  0o265
+-- > DEC:  181
+-- > HEX:  0xB5
+-- > HTML: &#181; or &micro;
+-- > Char: 'µ'
+_mu :: Word8
+_mu = 0xb5
+
+-- | Masculine ordinal indicator
+--
+-- > BIN:  0b10111010
+-- > OCT:  0o272
+-- > DEC:  186
+-- > HEX:  0xBA
+-- > HTML: &#186; or &ordm;
+-- > Char: 'º'
+_ordmasculine :: Word8
+_ordmasculine = 0xba
+
+-- | Superscript two - squared
+--
+-- > BIN:  0b10110010
+-- > OCT:  0o262
+-- > DEC:  178
+-- > HEX:  0xB2
+-- > HTML: &#178; or &sup2;
+-- > Char: '²'
+_s2 :: Word8
+_s2 = 0xb2
+
+-- | Superscript three - cubed
+--
+-- > BIN:  0b10110011
+-- > OCT:  0o263
+-- > DEC:  179
+-- > HEX:  0xB3
+-- > HTML: &#179; or &sup3;
+-- > Char: '³'
+_s3 :: Word8
+_s3 = 0xb3
+
+-- | Superscript one
+--
+-- > BIN:  0b10111001
+-- > OCT:  0o271
+-- > DEC:  185
+-- > HEX:  0xB9
+-- > HTML: &#185; or &sup1;
+-- > Char: '¹'
+_s1 :: Word8
+_s1 = 0xb9
+
+-- | Fraction one quarter
+--
+-- > BIN:  0b10111100
+-- > OCT:  0o274
+-- > DEC:  188
+-- > HEX:  0xBC
+-- > HTML: &#188; or &frac14;
+-- > Char: '¼'
+_1'4 :: Word8
+_1'4 = 0xbc
+
+-- | Fraction one half
+--
+-- > BIN:  0b10111101
+-- > OCT:  0o275
+-- > DEC:  189
+-- > HEX:  0xBD
+-- > HTML: &#189; or &frac12;
+-- > Char: '½'
+_1'2 :: Word8
+_1'2 = 0xbd
+
+-- | Fraction three quarters
+--
+-- > BIN:  0b10111110
+-- > OCT:  0o276
+-- > DEC:  190
+-- > HEX:  0xBE
+-- > HTML: &#190; or &frac34;
+-- > Char: '¾'
+_3'4 :: Word8
+_3'4 = 0xbe
+
+-- | Latin capital letter A with grave
+--
+-- > BIN:  0b11000000
+-- > OCT:  0o300
+-- > DEC:  192
+-- > HEX:  0xC0
+-- > HTML: &#192; or &Agrave;
+-- > Char: 'À'
+_Agrave :: Word8
+_Agrave = 0xc0
+
+-- | Latin capital letter O with diaeresis
+--
+-- > BIN:  0b11010110
+-- > OCT:  0o326
+-- > DEC:  214
+-- > HEX:  0xD6
+-- > HTML: &#214; or &Ouml;
+-- > Char: 'Ö'
+_Odieresis :: Word8
+_Odieresis = 0xd6
+
+-- | Latin capital letter O with slash
+--
+-- > BIN:  0b11011000
+-- > OCT:  0o330
+-- > DEC:  216
+-- > HEX:  0xD8
+-- > HTML: &#216; or &Oslash;
+-- > Char: 'Ø'
+_Oslash :: Word8
+_Oslash = 0xd8
+
+-- | Latin capital letter THORN
+--
+-- > BIN:  0b11011110
+-- > OCT:  0o336
+-- > DEC:  222
+-- > HEX:  0xDE
+-- > HTML: &#222; or &THORN;
+-- > Char: 'Þ'
+_Thorn :: Word8
+_Thorn = 0xde
+
+-- | Latin small letter sharp s - ess-zed
+--
+-- > BIN:  0b11011111
+-- > OCT:  0o337
+-- > DEC:  223
+-- > HEX:  0xDF
+-- > HTML: &#223; or &szlig;
+-- > Char: 'ß'
+_germandbls :: Word8
+_germandbls = 0xdf
+
+-- | Latin small letter a with grave
+--
+-- > BIN:  0b11100000
+-- > OCT:  0o340
+-- > DEC:  224
+-- > HEX:  0xE0
+-- > HTML: &#224; or &agrave;
+-- > Char: 'à'
+_agrave :: Word8
+_agrave = 0xe0
+
+-- | Latin small letter o with diaeresis
+--
+-- > BIN:  0b11110110
+-- > OCT:  0o366
+-- > DEC:  246
+-- > HEX:  0xF6
+-- > HTML: &#246; or &ouml;
+-- > Char: 'ö'
+_odieresis :: Word8
+_odieresis = 0xf6
+
+-- | Latin small letter o with slash
+--
+-- > BIN:  0b11111000
+-- > OCT:  0o370
+-- > DEC:  248
+-- > HEX:  0xF8
+-- > HTML: &#248; or &oslash;
+-- > Char: 'ø'
+_oslash :: Word8
+_oslash = 0xf8
+
+-- | Latin small letter thorn
+--
+-- > BIN:  0b11111110
+-- > OCT:  0o376
+-- > DEC:  254
+-- > HEX:  0xFE
+-- > HTML: &#254; or &thorn;
+-- > Char: 'þ'
+_thorn :: Word8
+_thorn = 0xfe
+
+-- | Latin small letter y with diaeresis
+--
+-- > BIN:  0b11111111
+-- > OCT:  0o377
+-- > DEC:  255
+-- > HEX:  0xFF
+-- > HTML: &#255; or &yuml;
+-- > Char: 'ÿ'
+_ydieresis :: Word8
+_ydieresis = 0xff
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,2 +1,3 @@
 import Distribution.Simple
+
 main = defaultMain
diff --git a/bench/Bench.hs b/bench/Bench.hs
--- a/bench/Bench.hs
+++ b/bench/Bench.hs
@@ -7,11 +7,23 @@
 import qualified Data.Char8
 import qualified Data.Word8
 
+import Bench.Extra
+
 main :: IO ()
 main = do
-    input <- S.readFile "bench/Bench.hs"
-    defaultMain [ 
-        bench "Data.Char"  $ whnf (S8.map Data.Char.toLower) input
-      , bench "Data.Char8" $ whnf (S8.map Data.Char8.toLower) input
-      , bench "Data.Word8" $ whnf (S.map Data.Word8.toLower) input
-      ]
+    let input = S.concat $ replicate 64 $ S.pack [0 .. 255]
+    defaultMain
+        [ bench "Data.Char.toLower" $ whnf (S8.map Data.Char.toLower) input
+        , bench "Data.Char8.toLower" $ whnf (S8.map Data.Char8.toLower) input
+        , bench "Data.Word8.toLower" $ whnf (S.map Data.Word8.toLower) input
+        , bench "oldIsAscii" $ whnf (S.all oldIsAscii) input
+        , bench "newIsAscii" $ whnf (S.all Data.Word8.isAscii) input
+        , bench "baseline" $ whnf (count' (const False)) input
+        , bench "oldIsPunctuation" $ whnf (count' oldIsPunctuation) input
+        , bench "newIsPunctuation" $ whnf (count' Data.Word8.isPunctuation) input
+        , bench "oldIsSymbol" $ whnf (count' oldIsSymbol) input
+        , bench "newIsSymbol" $ whnf (count' Data.Word8.isSymbol) input
+        ]
+  where
+    -- count bytes satisfying a predicate
+    count' p = S.foldl' (\n w -> if p w then n + 1 else n) (0 :: Int)
diff --git a/bench/Bench/Extra.hs b/bench/Bench/Extra.hs
new file mode 100644
--- /dev/null
+++ b/bench/Bench/Extra.hs
@@ -0,0 +1,71 @@
+module Bench.Extra where
+
+import Data.Word8
+
+oldIsAscii :: Word8 -> Bool
+oldIsAscii w = _nul <= w && w <= _del
+
+oldIsPunctuation :: Word8 -> Bool
+oldIsPunctuation w =
+    w
+        `elem` [ 0x21
+               , 0x22
+               , 0x23
+               , 0x25
+               , 0x26
+               , 0x27
+               , 0x28
+               , 0x29
+               , 0x2a
+               , 0x2c
+               , 0x2d
+               , 0x2e
+               , 0x2f
+               , 0x3a
+               , 0x3b
+               , 0x3f
+               , 0x40
+               , 0x5b
+               , 0x5c
+               , 0x5d
+               , 0x5f
+               , 0x7b
+               , 0x7d
+               , 0xa1
+               , 0xa7
+               , 0xb6
+               , 0xab
+               , 0xb7
+               , 0xbb
+               , 0xbf
+               ]
+
+oldIsSymbol :: Word8 -> Bool
+oldIsSymbol w =
+    w
+        `elem` [ 0x24
+               , 0x2b
+               , 0x3c
+               , 0x3d
+               , 0x3e
+               , 0x5e
+               , 0x60
+               , 0x7c
+               , 0x7e
+               , 0xa2
+               , 0xa3
+               , 0xa4
+               , 0xa5
+               , 0xa6
+               , 0xa8
+               , 0xa9
+               , 0xac
+               , 0xae
+               , 0xaf
+               , 0xb0
+               , 0xb1
+               , 0xb4
+               , 0xb8
+               , 0xd7
+               , 0xf7
+               ]
diff --git a/test/Char8Spec.hs b/test/Char8Spec.hs
--- a/test/Char8Spec.hs
+++ b/test/Char8Spec.hs
@@ -2,122 +2,128 @@
 
 import qualified Data.Char as C
 import Data.Char8
-import Data.Word (Word8)
-import Word8Spec (word8ToChar)
 import Test.Hspec
-import Test.Hspec.QuickCheck
 
+allChar8 :: String
+allChar8 = ['\0' .. '\255']
+
 spec :: Spec
 spec = do
     describe "isControl" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isControl c == C.isControl c
+        it "behaves like model" $
+            (isControl <$> allChar8)
+                == (C.isControl <$> allChar8)
 
     describe "isSpace" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isSpace c == C.isSpace c
+        it "behaves like model" $
+            (isSpace <$> allChar8)
+                == (C.isSpace <$> allChar8)
 
     describe "isLower" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isLower c == C.isLower c
+        it "behaves like model" $
+            (isLower <$> allChar8)
+                == (C.isLower <$> allChar8)
 
     describe "isUpper" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isUpper c == C.isUpper c
+        it "behaves like model" $
+            (isUpper <$> allChar8)
+                == (C.isUpper <$> allChar8)
 
     describe "isAlpha" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isAlpha c == C.isAlpha c
+        it "behaves like model" $
+            (isAlpha <$> allChar8)
+                == (C.isAlpha <$> allChar8)
 
     describe "isAlphaNum" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isAlphaNum c == C.isAlphaNum c
+        it "behaves like model" $
+            (isAlphaNum <$> allChar8)
+                == (C.isAlphaNum <$> allChar8)
 
     describe "isPrint" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isPrint c == C.isPrint c
+        it "behaves like model" $
+            (isPrint <$> allChar8)
+                == (C.isPrint <$> allChar8)
 
     describe "isDigit" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isDigit c == C.isDigit c
+        it "behaves like model" $
+            (isDigit <$> allChar8)
+                == (C.isDigit <$> allChar8)
 
     describe "isOctDigit" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isOctDigit c == C.isOctDigit c
+        it "behaves like model" $
+            (isOctDigit <$> allChar8)
+                == (C.isOctDigit <$> allChar8)
 
     describe "isHexDigit" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isHexDigit c == C.isHexDigit c
+        it "behaves like model" $
+            (isHexDigit <$> allChar8)
+                == (C.isHexDigit <$> allChar8)
 
     describe "isLetter" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isLetter c == C.isLetter c
+        it "behaves like model" $
+            (isLetter <$> allChar8)
+                == (C.isLetter <$> allChar8)
 
     describe "isMark" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isMark c == C.isMark c
+        it "behaves like model" $
+            (isMark <$> allChar8)
+                == (C.isMark <$> allChar8)
 
     describe "isNumber" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isNumber c == C.isNumber c
+        it "behaves like model" $
+            (isNumber <$> allChar8)
+                == (C.isNumber <$> allChar8)
 
     describe "isPunctuation" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isPunctuation c == C.isPunctuation c
+        it "behaves like model" $
+            (isPunctuation <$> allChar8)
+                == (C.isPunctuation <$> allChar8)
 
     describe "isSymbol" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isSymbol c == C.isSymbol c
+        it "behaves like model" $
+            (isSymbol <$> allChar8)
+                == (C.isSymbol <$> allChar8)
 
     describe "isSeparator" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isSeparator c == C.isSeparator c
+        it "behaves like model" $
+            (isSeparator <$> allChar8)
+                == (C.isSeparator <$> allChar8)
 
     describe "isAscii" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isAscii c == C.isAscii c
+        it "behaves like model" $
+            (isAscii <$> allChar8)
+                == (C.isAscii <$> allChar8)
 
     describe "isLatin1" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isLatin1 c == C.isLatin1 c
+        it "behaves like model" $
+            (isLatin1 <$> allChar8)
+                == (C.isLatin1 <$> allChar8)
 
     describe "isAsciiUpper" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isAsciiUpper c == C.isAsciiUpper c
+        it "behaves like model" $
+            (isAsciiUpper <$> allChar8)
+                == (C.isAsciiUpper <$> allChar8)
 
     describe "isAsciiLower" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            isAsciiLower c == C.isAsciiLower c
+        it "behaves like model" $
+            (isAsciiLower <$> allChar8)
+                == (C.isAsciiLower <$> allChar8)
 
     describe "toUpper" $ do
-        prop "behaves like model" $ ensure $ prop_toUpper
+        it "behaves like model" $
+            (toUpper <$> allChar8)
+                == (latin1Model C.toUpper <$> allChar8)
 
     describe "toLower" $ do
-        prop "behaves like model" $ ensure $ \c ->
-            toLower c == C.toLower c
+        it "behaves like model" $
+            (toLower <$> allChar8)
+                == (latin1Model C.toLower <$> allChar8)
 
     describe "toTitle" $ do
-        prop "behaves like model" $ ensure $ prop_toTitle
-
-prop_toUpper :: Char -> Bool
-prop_toUpper c
-  | c == _mu        = True
-  | c == _ydieresis = True
-  | otherwise       = toUpper c == C.toUpper c
-
-prop_toTitle :: Char -> Bool
-prop_toTitle c
-  | c == _mu  = True
-  | c == _ydieresis = True
-  | otherwise = toTitle c == C.toTitle c
-
-----------------------------------------------------------------
-
-_mu, _ydieresis :: Char
-_mu        = '\xb5'
-_ydieresis = '\xff'
-
-----------------------------------------------------------------
+        it "behaves like model" $
+            (toTitle <$> allChar8)
+                == (latin1Model C.toTitle <$> allChar8)
 
-ensure :: (Char -> Bool) -> Word8 -> Bool
-ensure body w = body (word8ToChar w)
+-- Characters mapped outside Latin-1 by Data.Char must remain unchanged.
+latin1Model :: (Char -> Char) -> Char -> Char
+latin1Model f c = let c' = f c in if C.isLatin1 c' then c' else c
diff --git a/test/Word8Spec.hs b/test/Word8Spec.hs
--- a/test/Word8Spec.hs
+++ b/test/Word8Spec.hs
@@ -3,113 +3,132 @@
 import qualified Data.Char as C
 import Data.Word8
 import Test.Hspec
-import Test.Hspec.QuickCheck
 
+allWord8 :: [Word8]
+allWord8 = [0 .. 255]
+
 spec :: Spec
 spec = do
     describe "isControl" $ do
-        prop "behaves like model" $ \w ->
-            isControl w == C.isControl (word8ToChar w)
+        it "behaves like model" $
+            (isControl <$> allWord8)
+                == (C.isControl . word8ToChar <$> allWord8)
 
     describe "isSpace" $ do
-        prop "behaves like model" $ \w ->
-            isSpace w == C.isSpace (word8ToChar w)
+        it "behaves like model" $
+            (isSpace <$> allWord8)
+                == (C.isSpace . word8ToChar <$> allWord8)
 
     describe "isLower" $ do
-        prop "behaves like model" $ \w ->
-            isLower w == C.isLower (word8ToChar w)
+        it "behaves like model" $
+            (isLower <$> allWord8)
+                == (C.isLower . word8ToChar <$> allWord8)
 
     describe "isUpper" $ do
-        prop "behaves like model" $ \w ->
-            isUpper w == C.isUpper (word8ToChar w)
+        it "behaves like model" $
+            (isUpper <$> allWord8)
+                == (C.isUpper . word8ToChar <$> allWord8)
 
     describe "isAlpha" $ do
-        prop "behaves like model" $ \w ->
-            isAlpha w == C.isAlpha (word8ToChar w)
+        it "behaves like model" $
+            (isAlpha <$> allWord8)
+                == (C.isAlpha . word8ToChar <$> allWord8)
 
     describe "isAlphaNum" $ do
-        prop "behaves like model" $ \w ->
-            isAlphaNum w == C.isAlphaNum (word8ToChar w)
+        it "behaves like model" $
+            (isAlphaNum <$> allWord8)
+                == (C.isAlphaNum . word8ToChar <$> allWord8)
 
     describe "isPrint" $ do
-        prop "behaves like model" $ \w ->
-            isPrint w == C.isPrint (word8ToChar w)
+        it "behaves like model" $
+            (isPrint <$> allWord8)
+                == (C.isPrint . word8ToChar <$> allWord8)
 
     describe "isDigit" $ do
-        prop "behaves like model" $ \w ->
-            isDigit w == C.isDigit (word8ToChar w)
+        it "behaves like model" $
+            (isDigit <$> allWord8)
+                == (C.isDigit . word8ToChar <$> allWord8)
 
     describe "isOctDigit" $ do
-        prop "behaves like model" $ \w ->
-            isOctDigit w == C.isOctDigit (word8ToChar w)
+        it "behaves like model" $
+            (isOctDigit <$> allWord8)
+                == (C.isOctDigit . word8ToChar <$> allWord8)
 
     describe "isHexDigit" $ do
-        prop "behaves like model" $ \w ->
-            isHexDigit w == C.isHexDigit (word8ToChar w)
+        it "behaves like model" $
+            (isHexDigit <$> allWord8)
+                == (C.isHexDigit . word8ToChar <$> allWord8)
 
     describe "isLetter" $ do
-        prop "behaves like model" $ \w ->
-            isLetter w == C.isLetter (word8ToChar w)
+        it "behaves like model" $
+            (isLetter <$> allWord8)
+                == (C.isLetter . word8ToChar <$> allWord8)
 
     describe "isMark" $ do
-        prop "behaves like model" $ \w ->
-            isMark w == C.isMark (word8ToChar w)
+        it "behaves like model" $
+            (isMark <$> allWord8)
+                == (C.isMark . word8ToChar <$> allWord8)
 
     describe "isNumber" $ do
-        prop "behaves like model" $ \w ->
-            isNumber w == C.isNumber (word8ToChar w)
+        it "behaves like model" $
+            (isNumber <$> allWord8)
+                == (C.isNumber . word8ToChar <$> allWord8)
 
     describe "isPunctuation" $ do
-        prop "behaves like model" $ \w ->
-            isPunctuation w == C.isPunctuation (word8ToChar w)
+        it "behaves like model" $
+            (isPunctuation <$> allWord8)
+                == (C.isPunctuation . word8ToChar <$> allWord8)
 
     describe "isSymbol" $ do
-        prop "behaves like model" $ \w ->
-            isSymbol w == C.isSymbol (word8ToChar w)
+        it "behaves like model" $
+            (isSymbol <$> allWord8)
+                == (C.isSymbol . word8ToChar <$> allWord8)
 
     describe "isSeparator" $ do
-        prop "behaves like model" $ \w ->
-            isSeparator w == C.isSeparator (word8ToChar w)
+        it "behaves like model" $
+            (isSeparator <$> allWord8)
+                == (C.isSeparator . word8ToChar <$> allWord8)
 
     describe "isAscii" $ do
-        prop "behaves like model" $ \w ->
-            isAscii w == C.isAscii (word8ToChar w)
+        it "behaves like model" $
+            (isAscii <$> allWord8)
+                == (C.isAscii . word8ToChar <$> allWord8)
 
     describe "isLatin1" $ do
-        prop "behaves like model" $ \w ->
-            isLatin1 w == C.isLatin1 (word8ToChar w)
+        it "behaves like model" $
+            (isLatin1 <$> allWord8)
+                == (C.isLatin1 . word8ToChar <$> allWord8)
 
     describe "isAsciiUpper" $ do
-        prop "behaves like model" $ \w ->
-            isAsciiUpper w == C.isAsciiUpper (word8ToChar w)
+        it "behaves like model" $
+            (isAsciiUpper <$> allWord8)
+                == (C.isAsciiUpper . word8ToChar <$> allWord8)
 
     describe "isAsciiLower" $ do
-        prop "behaves like model" $ \w ->
-            isAsciiLower w == C.isAsciiLower (word8ToChar w)
+        it "behaves like model" $
+            (isAsciiLower <$> allWord8)
+                == (C.isAsciiLower . word8ToChar <$> allWord8)
 
     describe "toUpper" $ do
-        prop "behaves like model" $ prop_toUpper
+        it "behaves like model" $
+            (word8ToChar . toUpper <$> allWord8)
+                == (latin1Model C.toUpper . word8ToChar <$> allWord8)
 
     describe "toLower" $ do
-        prop "behaves like model" $ \w ->
-            word8ToChar (toLower w) == C.toLower (word8ToChar w)
+        it "behaves like model" $
+            (word8ToChar . toLower <$> allWord8)
+                == (latin1Model C.toLower . word8ToChar <$> allWord8)
 
     describe "toTitle" $ do
-        prop "behaves like model" $ prop_toTitle
-
-prop_toUpper :: Word8 -> Bool
-prop_toUpper w
-  | w == _mu        = True
-  | w == _ydieresis = True
-  | otherwise       = word8ToChar (toUpper w) == C.toUpper (word8ToChar w)
-
-prop_toTitle :: Word8 -> Bool
-prop_toTitle w
-  | w == _mu  = True
-  | w == _ydieresis = True
-  | otherwise = word8ToChar (toTitle w) == C.toTitle (word8ToChar w)
+        it "behaves like model" $
+            (word8ToChar . toTitle <$> allWord8)
+                == (latin1Model C.toTitle . word8ToChar <$> allWord8)
 
 ----------------------------------------------------------------
 
 word8ToChar :: Word8 -> Char
 word8ToChar = C.chr . fromIntegral
+
+-- Characters mapped outside Latin-1 by Data.Char must remain unchanged.
+latin1Model :: (Char -> Char) -> Char -> Char
+latin1Model f c = let c' = f c in if C.isLatin1 c' then c' else c
diff --git a/word8.cabal b/word8.cabal
--- a/word8.cabal
+++ b/word8.cabal
@@ -1,21 +1,29 @@
+Cabal-Version:          3.0
 Name:                   word8
-Version:                0.1.3
+Version:                0.1.4
 Author:                 Kazu Yamamoto <kazu@iij.ad.jp>
 Maintainer:             Kazu Yamamoto <kazu@iij.ad.jp>
-License:                BSD3
+License:                BSD-3-Clause
 License-File:           LICENSE
 Synopsis:               Word8 library
 Description:            Word8 library to be used with Data.ByteString
 Category:               Data
-Cabal-Version:          >= 1.10
 Build-Type:             Simple
+Extra-Doc-Files:        ChangeLog.md
+Tested-With:            GHC == 9.2.8
+                      , GHC == 9.4.8
+                      , GHC == 9.6.7
+                      , GHC == 9.8.4
+                      , GHC == 9.10.2
+                      , GHC == 9.12.4
+                      , GHC == 9.14.1
 
 Library
   Default-Language:     Haskell2010
   GHC-Options:          -Wall
   Exposed-Modules:      Data.Char8
                         Data.Word8
-  Build-Depends:        base >= 4 && < 5
+  Build-Depends:        base >= 4.9 && < 5
 
 Test-Suite spec
   Type:                 exitcode-stdio-1.0
@@ -23,6 +31,7 @@
   Hs-Source-Dirs:       test
   Ghc-Options:          -Wall
   Main-Is:              Spec.hs
+  Build-Tool-Depends:   hspec-discover:hspec-discover
   Other-Modules:        Char8Spec
                         Word8Spec
   Build-Depends:        base
@@ -35,6 +44,7 @@
   Hs-Source-Dirs:       bench
   Ghc-Options:          -Wall
   Main-Is:              Bench.hs
+  Other-Modules:        Bench.Extra
   Build-Depends:        base
                       , bytestring
                       , criterion
