{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Data.Rg
( Rg(..)
, RgCoreMethods
, rgCoreMethodsBE
, RgText(..)
, BE(..)
, Range
, newStartOfRangeFromList
, newStartOfRangeFromVector
, extractRange
) where
import Data.Array
import Data.Coerce
import qualified Data.HashMap.Strict as HM
import Data.Maybe
import Data.Possibly
import qualified Data.Text as T
import qualified Data.Vector as V
import Fmt
class Rg rg where
sizeRg :: rg -> Int
sizeRg = _rcm_sizeRg rgCoreMethods
toRg :: rg -> Int -> Maybe rg
toRg = _rcm_toRg rgCoreMethods
fromRg :: rg -> Int
fromRg = _rcm_fromRg rgCoreMethods
rgCoreMethods :: RgCoreMethods rg
rgCoreMethods =
RgCoreMethods
{ _rcm_sizeRg = sizeRg
, _rcm_toRg = toRg
, _rcm_fromRg = fromRg
}
{-# MINIMAL sizeRg, toRg, fromRg | rgCoreMethods #-}
minRg :: rg -> rg
minRg = fromMaybe oops . flip toRg 0
where
oops = error "minRg: no minimum value in range"
maxRg :: rg -> rg
maxRg rg = fromMaybe oops $ toRg rg n
where
n = sizeRg rg - 1
oops = error "maxRg: no maximum value in range"
succRg :: rg -> Maybe rg
succRg rg = toRg rg $ fromRg rg + 1
predRg :: rg -> Maybe rg
predRg rg = toRg rg $ fromRg rg - 1
allListRg :: rg -> [rg]
allListRg rg = listRg rg [0..]
listRg :: rg -> [Int] -> [rg]
listRg rg is = catMaybes $ takeWhile isJust [ toRg rg i | i<-is ]
allVectorRg :: rg -> [rg]
allVectorRg rg = listRg rg [0..]
vectorRg :: rg -> [Int] -> V.Vector rg
vectorRg rg is = V.fromList $ listRg rg is
data RgCoreMethods rg =
RgCoreMethods
{ _rcm_sizeRg :: rg -> Int
, _rcm_toRg :: rg -> Int -> Maybe rg
, _rcm_fromRg :: rg -> Int
}
rgCoreMethodsBE :: forall rg . (Bounded rg, Enum rg) => RgCoreMethods rg
rgCoreMethodsBE =
RgCoreMethods
{ _rcm_sizeRg = coerce (sizeRg :: BE rg -> Int)
, _rcm_toRg = coerce (toRg :: BE rg -> Int -> Maybe (BE rg))
, _rcm_fromRg = coerce (fromRg :: BE rg -> Int)
}
class (Rg e, Buildable e, Eq e, Ord e, Show e) => RgText e where
parseRgText :: e -> T.Text -> Possibly e
parseRgText e txt = maybe (Left msg) Right $ HM.lookup txt $ hashmap_t e
where
msg = "parseRgText: enumeration not recognised: "++show txt
newtype BE a = BE { _BE :: a }
deriving (Eq,Ord,Bounded,Enum,Show)
instance (Bounded i,Enum i) => Rg (BE i) where
sizeRg be = (1 +) $ fromEnum $ maxBound `asTypeOf` _BE be
toRg be i = case 0 <= i && i < sizeRg be of
True -> Just $ BE $ toEnum i
False -> Nothing
fromRg = fromEnum . _BE
data Range a =
Range
{ _rg_size :: Int
, _rg_elem :: Int
, _rg_array :: Array Int a
}
deriving (Show)
instance Rg (Range a) where
sizeRg = _rg_size
toRg rg i = case 0 <= i && i < _rg_size rg of
False -> Nothing
True -> Just rg { _rg_elem = i }
fromRg = _rg_elem
newStartOfRangeFromList :: [a] -> Range a
newStartOfRangeFromList xs =
Range
{ _rg_size = sz
, _rg_elem = 0
, _rg_array = listArray (0,sz-1) xs
}
where
sz = length xs
newStartOfRangeFromVector :: V.Vector a -> Range a
newStartOfRangeFromVector v =
Range
{ _rg_size = sz
, _rg_elem = 0
, _rg_array = listArray (0,sz-1) $ V.toList v
}
where
sz = V.length v
extractRange :: Range a -> a
extractRange Range{..} = _rg_array ! _rg_elem
hashmap_t :: RgText e => e -> HM.HashMap T.Text e
hashmap_t x = HM.fromList
[ (fmt $ build c,c)
| c <- allListRg x
]