[project @ 2001-08-04 06:11:24 by ken]
[ghc-hetmet.git] / ghc / lib / std / PrelEnum.lhs
index 4651f0c..c0874a3 100644 (file)
@@ -1,6 +1,9 @@
+% -----------------------------------------------------------------------------
+% $Id: PrelEnum.lhs,v 1.14 2001/07/24 06:31:35 ken Exp $
 %
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
+% (c) The University of Glasgow, 1992-2000
 %
+
 \section[PrelBounded]{Module @PrelBounded@}
 
 Instances of Bounded for various datatypes.
@@ -10,7 +13,7 @@ Instances of Bounded for various datatypes.
 
 module PrelEnum(
        Bounded(..), Enum(..),
-       enumFromBounded, enumFromThenBounded,
+       boundedEnumFrom, boundedEnumFromThen,
 
        -- Instances for Bounded and Eum: (), Char, Int
 
@@ -19,6 +22,8 @@ module PrelEnum(
 import {-# SOURCE #-} PrelErr ( error )
 import PrelBase
 import PrelTup ()      -- To make sure we look for the .hi file
+
+default ()             -- Double isn't available yet
 \end{code}
 
 
@@ -43,15 +48,22 @@ class  Enum a       where
 
     succ                  = toEnum . (`plusInt` oneInt)  . fromEnum
     pred                  = toEnum . (`minusInt` oneInt) . fromEnum
-    enumFromTo n m         = map toEnum [fromEnum n .. fromEnum m]
-    enumFromThenTo n1 n2 m = map toEnum [fromEnum n1, fromEnum n2 .. fromEnum m]
+    enumFrom x            = map toEnum [fromEnum x ..]
+    enumFromThen x y      = map toEnum [fromEnum x, fromEnum y ..]
+    enumFromTo x y         = map toEnum [fromEnum x .. fromEnum y]
+    enumFromThenTo x1 x2 y = map toEnum [fromEnum x1, fromEnum x2 .. fromEnum y]
 
 -- Default methods for bounded enumerations
-enumFromBounded :: (Enum a, Bounded a) => a -> [a]
-enumFromBounded n        = enumFromTo n maxBound
+boundedEnumFrom :: (Enum a, Bounded a) => a -> [a]
+boundedEnumFrom n = map toEnum [fromEnum n .. fromEnum (maxBound `asTypeOf` n)]
 
-enumFromThenBounded :: (Enum a, Bounded a) => a -> a -> [a]
-enumFromThenBounded n1 n2 = enumFromThenTo n1 n2 maxBound
+boundedEnumFromThen :: (Enum a, Bounded a) => a -> a -> [a]
+boundedEnumFromThen n1 n2 
+  | i_n2 >= i_n1  = map toEnum [i_n1, i_n2 .. fromEnum (maxBound `asTypeOf` n1)]
+  | otherwise     = map toEnum [i_n1, i_n2 .. fromEnum (minBound `asTypeOf` n1)]
+  where
+    i_n1 = fromEnum n1
+    i_n2 = fromEnum n2
 \end{code}
 
 
@@ -67,8 +79,8 @@ instance Bounded () where
     maxBound = ()
 
 instance Enum () where
-    succ x      = error "Prelude.Enum.().succ: bad argment"
-    pred x      = error "Prelude.Enum.().pred: bad argument"
+    succ _      = error "Prelude.Enum.().succ: bad argment"
+    pred _      = error "Prelude.Enum.().pred: bad argument"
 
     toEnum x | x == zeroInt = ()
              | otherwise    = error "Prelude.Enum.().toEnum: bad argument"
@@ -121,8 +133,8 @@ instance Enum Bool where
   fromEnum True  = oneInt
 
   -- Use defaults for the rest
-  enumFrom     = enumFromBounded
-  enumFromThen = enumFromThenBounded
+  enumFrom     = boundedEnumFrom
+  enumFromThen = boundedEnumFromThen
 \end{code}
 
 %*********************************************************
@@ -148,15 +160,15 @@ instance Enum Ordering where
   toEnum n | n == zeroInt = LT
           | n == oneInt  = EQ
           | n == twoInt  = GT
-  toEnum n = error "Prelude.Enum.Ordering.toEnum: bad argment"
+  toEnum _ = error "Prelude.Enum.Ordering.toEnum: bad argment"
 
   fromEnum LT = zeroInt
   fromEnum EQ = oneInt
   fromEnum GT = twoInt
 
   -- Use defaults for the rest
-  enumFrom     = enumFromBounded
-  enumFromThen = enumFromThenBounded
+  enumFrom     = boundedEnumFrom
+  enumFromThen = boundedEnumFromThen
 \end{code}
 
 %*********************************************************
@@ -168,13 +180,13 @@ instance Enum Ordering where
 \begin{code}
 instance  Bounded Char  where
     minBound =  '\0'
-    maxBound =  '\255'
+    maxBound =  '\x10FFFF'
 
 instance  Enum Char  where
-    succ     c@(C# c#)
-       | not (ord# c# ==# 255#) = C# (chr# (ord# c# +# 1#))
+    succ (C# c#)
+       | not (ord# c# ==# 0x10FFFF#) = C# (chr# (ord# c# +# 1#))
        | otherwise             = error ("Prelude.Enum.Char.succ: bad argument")
-    pred     c@(C# c#)
+    pred (C# c#)
        | not (ord# c# ==# 0#)   = C# (chr# (ord# c# -# 1#))
        | otherwise             = error ("Prelude.Enum.Char.pred: bad argument")
 
@@ -182,17 +194,32 @@ instance  Enum Char  where
     fromEnum = ord
 
     {-# INLINE enumFrom #-}
-    enumFrom (C# x) = build (\ c n -> eftCharFB c n (ord# x) 255#)
+    enumFrom (C# x) = eftChar (ord# x) 0x10FFFF#
        -- Blarg: technically I guess enumFrom isn't strict!
 
     {-# INLINE enumFromTo #-}
-    enumFromTo (C# x) (C# y) = build (\ c n -> eftCharFB c n (ord# x) (ord# y))
-
+    enumFromTo (C# x) (C# y) = eftChar (ord# x) (ord# y)
+    
     {-# INLINE enumFromThen #-}
-    enumFromThen (C# x1) (C# x2) = build (\ c n -> efdtCharFB c n (ord# x1) (ord# x2) 255#)
-
+    enumFromThen (C# x1) (C# x2) = efdChar (ord# x1) (ord# x2)
+    
     {-# INLINE enumFromThenTo #-}
-    enumFromThenTo (C# x1) (C# x2) (C# y) = build (\ c n -> efdtCharFB c n (ord# x1) (ord# x2) (ord# y))
+    enumFromThenTo (C# x1) (C# x2) (C# y) = efdtChar (ord# x1) (ord# x2) (ord# y)
+
+eftChar  = eftCharList
+efdChar  = efdCharList
+efdtChar = efdtCharList
+
+
+{-# RULES
+"eftChar"      forall x y.     eftChar x y       = build (\c n -> eftCharFB c n x y)
+"efdChar"      forall x1 x2.   efdChar x1 x2     = build (\ c n -> efdCharFB c n x1 x2)
+"efdtChar"     forall x1 x2 l. efdtChar x1 x2 l  = build (\ c n -> efdtCharFB c n x1 x2 l)
+"eftCharList"  eftCharFB  (:) [] = eftCharList
+"efdCharList"  efdCharFB  (:) [] = efdCharList
+"efdtCharList" efdtCharFB (:) [] = efdtCharList
+ #-}
+
 
 -- We can do better than for Ints because we don't
 -- have hassles about arithmetic overflow at maxBound
@@ -207,31 +234,53 @@ eftCharList x y | x ># y    = []
 
 
 -- For enumFromThenTo we give up on inlining
-efdtCharFB c n x1 x2 y
-  | delta >=# 0# = go_up x1
-  | otherwise    = go_dn x1
+efdCharFB c n x1 x2
+  | delta >=# 0# = go_up_char_fb c n x1 delta 0x10FFFF#
+  | otherwise    = go_dn_char_fb c n x1 delta 0#
+  where
+    delta = x2 -# x1
+
+efdCharList x1 x2
+  | delta >=# 0# = go_up_char_list x1 delta 0x10FFFF#
+  | otherwise    = go_dn_char_list x1 delta 0#
   where
     delta = x2 -# x1
-    go_up x | x ># y    = n
+
+efdtCharFB c n x1 x2 lim
+  | delta >=# 0# = go_up_char_fb c n x1 delta lim
+  | otherwise    = go_dn_char_fb c n x1 delta lim
+  where
+    delta = x2 -# x1
+
+efdtCharList x1 x2 lim
+  | delta >=# 0# = go_up_char_list x1 delta lim
+  | otherwise    = go_dn_char_list x1 delta lim
+  where
+    delta = x2 -# x1
+
+go_up_char_fb c n x delta lim
+  = go_up x
+  where
+    go_up x | x ># lim  = n
            | otherwise = C# (chr# x) `c` go_up (x +# delta)
-    go_dn x | x <# y    = n
+
+go_dn_char_fb c n x delta lim
+  = go_dn x
+  where
+    go_dn x | x <# lim  = n
            | otherwise = C# (chr# x) `c` go_dn (x +# delta)
 
-efdtCharList x1 x2 y
-  | delta >=# 0# = go_up x1
-  | otherwise    = go_dn x1
+go_up_char_list x delta lim
+  = go_up x
   where
-    delta = x2 -# x1
-    go_up x | x ># y    = []
+    go_up x | x ># lim  = []
            | otherwise = C# (chr# x) : go_up (x +# delta)
-    go_dn x | x <# y    = []
-           | otherwise = C# (chr# x) : go_dn (x +# delta)
 
-
-{-# RULES
-"eftCharList"  eftCharFB  (:) [] = eftCharList
-"efdtCharList" efdtCharFB (:) [] = efdtCharList
- #-}
+go_dn_char_list x delta lim
+  = go_dn x
+  where
+    go_dn x | x <# lim  = []
+           | otherwise = C# (chr# x) : go_dn (x +# delta)
 \end{code}
 
 
@@ -241,6 +290,13 @@ efdtCharList x1 x2 y
 %*                                                     *
 %*********************************************************
 
+Be careful about these instances.  
+       (a) remember that you have to count down as well as up e.g. [13,12..0]
+       (b) be careful of Int overflow
+       (c) remember that Int is bounded, so [1..] terminates at maxInt
+
+Also NB that the Num class isn't available in this module.
+       
 \begin{code}
 instance  Bounded Int where
     minBound =  minInt
@@ -258,17 +314,32 @@ instance  Enum Int  where
     fromEnum x = x
 
     {-# INLINE enumFrom #-}
-    enumFrom (I# x) = build (\ c n -> eftIntFB c n x 2147483647#)
+    enumFrom (I# x) = case maxInt of I# y -> eftInt x y
        -- Blarg: technically I guess enumFrom isn't strict!
 
     {-# INLINE enumFromTo #-}
-    enumFromTo (I# x) (I# y) = build (\ c n -> eftIntFB c n x y)
+    enumFromTo (I# x) (I# y) = eftInt x y
 
     {-# INLINE enumFromThen #-}
-    enumFromThen (I# x1) (I# x2) = build (\ c n -> efdtIntFB c n x1 x2 2147483647#)
+    enumFromThen (I# x1) (I# x2) = efdInt x1 x2
 
     {-# INLINE enumFromThenTo #-}
-    enumFromThenTo (I# x1) (I# x2) (I# y) = build (\ c n -> efdtIntFB c n x1 x2 y)
+    enumFromThenTo (I# x1) (I# x2) (I# y) = efdtInt x1 x2 y
+
+eftInt         = eftIntList
+efdInt         = efdIntList
+efdtInt = efdtIntList
+
+{-# RULES
+"eftInt"       forall x y.     eftInt x y       = build (\ c n -> eftIntFB c n x y)
+"efdInt"       forall x1 x2.   efdInt x1 x2     = build (\ c n -> efdIntFB c n x1 x2)
+"efdtInt"      forall x1 x2 l. efdtInt x1 x2 l  = build (\ c n -> efdtIntFB c n x1 x2 l)
+
+"eftIntList"   eftIntFB  (:) [] = eftIntList
+"efdIntList"   efdIntFB  (:) [] = efdIntList
+"efdtIntList"  efdtIntFB (:) [] = efdtIntList
+ #-}
+
 
 {-# INLINE eftIntFB #-}
 eftIntFB c n x y | x ># y    = n       
@@ -289,29 +360,55 @@ eftIntList x y | x ># y    = []
 -- For enumFromThenTo we give up on inlining; so we don't worry
 -- about duplicating occurrences of "c"
 efdtIntFB c n x1 x2 y
-  | delta >=# 0# = if x1 ># y then n else go_up x1
-  | otherwise    = if x1 <# y then n else go_dn x1
+  | delta >=# 0# = if x1 ># y then n else go_up_int_fb c n x1 delta lim
+  | otherwise    = if x1 <# y then n else go_dn_int_fb c n x1 delta lim 
   where
     delta = x2 -# x1
-    go_up x | y -# x <# delta = I# x `c` n
-           | otherwise       = I# x `c` go_up (x +# delta)
-    go_dn x | y -# x ># delta = I# x `c` n
-           | otherwise       = I# x `c` go_dn (x +# delta)
+    lim   = y -# delta
 
 efdtIntList x1 x2 y
-  | delta >=# 0# = if x1 ># y then [] else go_up x1
-  | otherwise    = if x1 <# y then [] else go_dn x1
+  | delta >=# 0# = if x1 ># y then [] else go_up_int_list x1 delta lim
+  | otherwise    = if x1 <# y then [] else go_dn_int_list x1 delta lim
+  where
+    delta = x2 -# x1
+    lim   = y -# delta
+
+efdIntFB c n x1 x2
+  | delta >=# 0# = case maxInt of I# y -> go_up_int_fb c n x1 delta (y -# delta)
+  | otherwise    = case minInt of I# y -> go_dn_int_fb c n x1 delta (y -# delta)
   where
     delta = x2 -# x1
-    go_up x | y -# x <# delta = [I# x]
-           | otherwise       = I# x : go_up (x +# delta)
-    go_dn x | y -# x ># delta = [I# x]
-           | otherwise       = I# x : go_dn (x +# delta)
 
+efdIntList x1 x2
+  | delta >=# 0# = case maxInt of I# y -> go_up_int_list x1 delta (y -# delta)
+  | otherwise    = case minInt of I# y -> go_dn_int_list x1 delta (y -# delta)
+  where
+    delta = x2 -# x1
 
-{-# RULES
-"eftIntList"   eftIntFB  (:) [] = eftIntList
-"efdtIntList"  efdtIntFB (:) [] = efdtIntList
- #-}
+-- In all of these, the (x +# delta) is guaranteed not to overflow
+
+go_up_int_fb c n x delta lim
+  = go_up x
+  where
+    go_up x | x ># lim  = I# x `c` n
+           | otherwise = I# x `c` go_up (x +# delta)
+
+go_dn_int_fb c n x delta lim 
+  = go_dn x
+  where
+    go_dn x | x <# lim  = I# x `c` n
+           | otherwise = I# x `c` go_dn (x +# delta)
+
+go_up_int_list x delta lim
+  = go_up x
+  where
+    go_up x | x ># lim  = [I# x]
+           | otherwise = I# x : go_up (x +# delta)
+
+go_dn_int_list x delta lim 
+  = go_dn x
+  where
+    go_dn x | x <# lim  = [I# x]
+           | otherwise = I# x : go_dn (x +# delta)
 \end{code}