[commit: packages/binary] master: Add instance for Natural. (74b2c01)

git at git.haskell.org git at git.haskell.org
Thu Jan 22 22:36:09 UTC 2015


Repository : ssh://git@git.haskell.org/binary

On branch  : master
Link       : http://git.haskell.org/packages/binary.git/commitdiff/74b2c01c64709ccdb4df2103cf931f1390f6b632

>---------------------------------------------------------------

commit 74b2c01c64709ccdb4df2103cf931f1390f6b632
Author: Lennart Kolmodin <kolmodin at gmail.com>
Date:   Thu Jan 1 21:26:18 2015 +0300

    Add instance for Natural.
    
    Natural is a new data type that comes with base-4.8 (GHC 7.10).
    We serialize it in the same way as we do with Integer.
    Since this is a new data type there are some ugly CPPs to handle whether
    Natural is there or not.
    Serialization tests have been added as well. Since QuickCheck doesn't yet
    implement instance Arbitrary Natural we do a workaround here.
    This fixes #63.


>---------------------------------------------------------------

74b2c01c64709ccdb4df2103cf931f1390f6b632
 src/Data/Binary/Class.hs | 37 +++++++++++++++++++++++++++++++++++--
 tests/Arbitrary.hs       | 23 +++++++++++++++++++++++
 tests/QC.hs              | 20 ++++++++++++++++++--
 3 files changed, 76 insertions(+), 4 deletions(-)

diff --git a/src/Data/Binary/Class.hs b/src/Data/Binary/Class.hs
index e5e59e8..8a4bc25 100644
--- a/src/Data/Binary/Class.hs
+++ b/src/Data/Binary/Class.hs
@@ -5,6 +5,11 @@
 #ifdef GENERICS
 {-# LANGUAGE DefaultSignatures #-}
 #endif
+
+#if MIN_VERSION_base(4,8,0)
+#define HAS_NATURAL
+#endif
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      : Data.Binary.Class
@@ -61,6 +66,9 @@ import Data.Array.Unboxed
 import GHC.Generics
 #endif
 
+#ifdef HAS_NATURAL
+import Numeric.Natural
+#endif
 --
 -- This isn't available in older Hugs or older GHC
 --
@@ -225,17 +233,42 @@ instance Binary Integer where
 --
 -- Fold and unfold an Integer to and from a list of its bytes
 --
-unroll :: Integer -> [Word8]
+unroll :: (Integral a, Num a, Bits a) => a -> [Word8]
 unroll = unfoldr step
   where
     step 0 = Nothing
     step i = Just (fromIntegral i, i `shiftR` 8)
 
-roll :: [Word8] -> Integer
+roll :: (Integral a, Num a, Bits a) => [Word8] -> a
 roll   = foldr unstep 0
   where
     unstep b a = a `shiftL` 8 .|. fromIntegral b
 
+#ifdef HAS_NATURAL
+-- Fixed-size type for a subset of Natural
+type NaturalWord = Word64
+
+instance Binary Natural where
+    {-# INLINE put #-}
+    put n | n <= hi = do
+        putWord8 0
+        put (fromIntegral n :: NaturalWord)  -- fast path
+     where
+        hi = fromIntegral (maxBound :: NaturalWord) :: Natural
+
+    put n = do
+        putWord8 1
+        put (unroll (abs n))         -- unroll the bytes
+
+    {-# INLINE get #-}
+    get = do
+        tag <- get :: Get Word8
+        case tag of
+            0 -> liftM fromIntegral (get :: Get NaturalWord)
+            _ -> do bytes <- get
+                    return $! roll bytes
+#endif
+
 {-
 
 --
diff --git a/tests/Arbitrary.hs b/tests/Arbitrary.hs
index 99725af..c19a192 100644
--- a/tests/Arbitrary.hs
+++ b/tests/Arbitrary.hs
@@ -1,5 +1,10 @@
+{-# LANGUAGE CPP #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
+#if MIN_VERSION_base(4,8,0)
+#define HAS_NATURAL
+#endif
+
 module Arbitrary where
 
 import Test.QuickCheck
@@ -7,6 +12,10 @@ import Test.QuickCheck
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as L
 
+#ifdef HAS_NATURAL
+import Numeric.Natural
+#endif
+
 instance Arbitrary L.ByteString where
   arbitrary = fmap L.fromChunks arbitrary
 
@@ -52,3 +61,17 @@ instance (Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d, Arbitrary e,
     (a,b,c,d,e) <- arbitrary
     (f,g,h,i,j) <- arbitrary
     return (a,b,c,d,e,f,g,h,i,j)
+
+
+#ifdef HAS_NATURAL
+-- | Generates a natural number. The number must be positive
+-- and its maximum value depends on the size parameter.
+arbitrarySizedNatural :: Gen Natural
+arbitrarySizedNatural =
+  sized $ \n0 ->
+  let n = toInteger n0 in
+  inBounds fromInteger (choose (0, n*n))
+
+inBounds :: Integral a => (Integer -> a) -> Gen Integer -> Gen a
+inBounds fi g = fmap fi (g `suchThat` (\x -> toInteger (fi x) == x))
+#endif
\ No newline at end of file
diff --git a/tests/QC.hs b/tests/QC.hs
index fbaded1..2a08b3b 100644
--- a/tests/QC.hs
+++ b/tests/QC.hs
@@ -1,6 +1,10 @@
-{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE CPP, ScopedTypeVariables #-}
 module Main ( main ) where
 
+#if MIN_VERSION_base(4,8,0)
+#define HAS_NATURAL
+#endif
+
 import           Control.Applicative
 import           Control.Exception                    as C (SomeException,
                                                             catch, evaluate)
@@ -17,7 +21,7 @@ import           Test.Framework.Providers.QuickCheck2
 import           Test.QuickCheck
 
 import qualified Action                               (tests)
-import           Arbitrary                            ()
+import           Arbitrary                            (arbitrarySizedNatural)
 import           Data.Binary
 import           Data.Binary.Get
 import           Data.Binary.Put
@@ -349,6 +353,15 @@ main = defaultMain tests
 
 ------------------------------------------------------------------------
 
+#ifdef HAS_NATURAL
+-- | Until the QuickCheck library implements instance Arbitrary Natural,
+-- we need this test.
+prop_test_Natural :: Property
+prop_test_Natural = forAll arbitrarySizedNatural test
+#endif
+
+------------------------------------------------------------------------
+
 type T a = a -> Property
 type B a = a -> Bool
 
@@ -426,6 +439,9 @@ tests =
             , ("Word",       p (test :: T Word                   ))
             , ("Int",        p (test :: T Int                    ))
             , ("Integer",    p (test :: T Integer                ))
+#ifdef HAS_NATURAL
+            , ("Natural",      (prop_test_Natural :: Property    ))
+#endif
 
             , ("Float",      p (test :: T Float                  ))
             , ("Double",     p (test :: T Double                 ))



More information about the ghc-commits mailing list