1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650
|
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
module Basement.UArray.Base
( MUArray(..)
, UArray(..)
, MUArrayBackend(..)
, UArrayBackend(..)
-- * New mutable array creation
, newUnpinned
, newPinned
, newNative
, newNative_
, new
-- * Pinning status
, isPinned
, isMutablePinned
-- * Mutable array accessor
, unsafeRead
, unsafeWrite
-- * Freezing routines
, unsafeFreezeShrink
, unsafeFreeze
, unsafeThaw
, thaw
, copy
-- * Array accessor
, unsafeIndex
, unsafeIndexer
, onBackend
, onBackendPure
, onBackendPure'
, onBackendPrim
, onMutableBackend
, unsafeDewrap
, unsafeDewrap2
-- * Basic lowlevel functions
, vFromListN
, empty
, length
, offset
, ValidRange(..)
, offsetsValidRange
, equal
, equalMemcmp
, compare
, copyAt
, unsafeCopyAtRO
, toBlock
-- * temporary
, pureST
) where
import GHC.Prim
import GHC.Types
import GHC.Ptr
import GHC.ST
import Basement.Compat.Primitive
import Basement.Monad
import Basement.PrimType
import Basement.Compat.Base
import Basement.Compat.C.Types
import Basement.Compat.Semigroup
import qualified Basement.Runtime as Runtime
import Data.Proxy
import qualified Basement.Compat.ExtList as List
import qualified Basement.Alg.Class as Alg
import Basement.Types.OffsetSize
import Basement.FinalPtr
import Basement.NormalForm
import Basement.Block (MutableBlock(..), Block(..))
import qualified Basement.Block as BLK
import qualified Basement.Block.Mutable as MBLK
import Basement.Numerical.Additive
import Basement.Bindings.Memory
import System.IO.Unsafe (unsafeDupablePerformIO)
-- | A Mutable array of types built on top of GHC primitive.
--
-- Element in this array can be modified in place.
data MUArray ty st = MUArray {-# UNPACK #-} !(Offset ty)
{-# UNPACK #-} !(CountOf ty)
!(MUArrayBackend ty st)
data MUArrayBackend ty st = MUArrayMBA (MutableBlock ty st) | MUArrayAddr (FinalPtr ty)
instance PrimType ty => Alg.Indexable (Ptr ty) ty where
index (Ptr addr) = primAddrIndex addr
instance Alg.Indexable (Ptr Word8) Word64 where
index (Ptr addr) = primAddrIndex addr
instance (PrimMonad prim, PrimType ty) => Alg.RandomAccess (Ptr ty) prim ty where
read (Ptr addr) = primAddrRead addr
write (Ptr addr) = primAddrWrite addr
-- | An array of type built on top of GHC primitive.
--
-- The elements need to have fixed sized and the representation is a
-- packed contiguous array in memory that can easily be passed
-- to foreign interface
data UArray ty = UArray {-# UNPACK #-} !(Offset ty)
{-# UNPACK #-} !(CountOf ty)
!(UArrayBackend ty)
deriving (Typeable)
data UArrayBackend ty = UArrayBA !(Block ty) | UArrayAddr !(FinalPtr ty)
deriving (Typeable)
instance Data ty => Data (UArray ty) where
dataTypeOf _ = arrayType
toConstr _ = error "toConstr"
gunfold _ _ = error "gunfold"
arrayType :: DataType
arrayType = mkNoRepType "Basement.UArray"
instance NormalForm (UArray ty) where
toNormalForm (UArray _ _ !_) = ()
instance (PrimType ty, Show ty) => Show (UArray ty) where
show v = show (toList v)
instance (PrimType ty, Eq ty) => Eq (UArray ty) where
(==) = equal
instance (PrimType ty, Ord ty) => Ord (UArray ty) where
{-# SPECIALIZE instance Ord (UArray Word8) #-}
compare = vCompare
instance PrimType ty => Semigroup (UArray ty) where
(<>) = append
instance PrimType ty => Monoid (UArray ty) where
mempty = empty
mconcat = concat
instance PrimType ty => IsList (UArray ty) where
type Item (UArray ty) = ty
fromList = vFromList
fromListN len = vFromListN (CountOf len)
toList = vToList
length :: UArray ty -> CountOf ty
length (UArray _ len _) = len
{-# INLINE[1] length #-}
offset :: UArray ty -> Offset ty
offset (UArray ofs _ _) = ofs
{-# INLINE[1] offset #-}
data ValidRange ty = ValidRange {-# UNPACK #-} !(Offset ty) {-# UNPACK #-} !(Offset ty)
offsetsValidRange :: UArray ty -> ValidRange ty
offsetsValidRange (UArray ofs len _) = ValidRange ofs (ofs `offsetPlusE` len)
-- | Return if the array is pinned in memory
--
-- note that Foreign array are considered pinned
isPinned :: UArray ty -> PinnedStatus
isPinned (UArray _ _ (UArrayAddr {})) = Pinned
isPinned (UArray _ _ (UArrayBA blk)) = BLK.isPinned blk
-- | Return if a mutable array is pinned in memory
isMutablePinned :: MUArray ty st -> PinnedStatus
isMutablePinned (MUArray _ _ (MUArrayAddr {})) = Pinned
isMutablePinned (MUArray _ _ (MUArrayMBA mb)) = BLK.isMutablePinned mb
-- | Create a new pinned mutable array of size @n.
--
-- all the cells are uninitialized and could contains invalid values.
--
-- All mutable arrays are allocated on a 64 bits aligned addresses
newPinned :: forall prim ty . (PrimMonad prim, PrimType ty) => CountOf ty -> prim (MUArray ty (PrimState prim))
newPinned n = MUArray 0 n . MUArrayMBA <$> MBLK.newPinned n
-- | Create a new unpinned mutable array of size @n elements.
--
-- If the size exceeds a GHC-defined threshold, then the memory will be
-- pinned. To be certain about pinning status with small size, use 'newPinned'
newUnpinned :: forall prim ty . (PrimMonad prim, PrimType ty) => CountOf ty -> prim (MUArray ty (PrimState prim))
newUnpinned n = MUArray 0 n . MUArrayMBA <$> MBLK.new n
newNative :: (PrimMonad prim, PrimType ty)
=> CountOf ty
-> (MutableBlock ty (PrimState prim) -> prim a)
-> prim (a, MUArray ty (PrimState prim))
newNative n f = do
mb <- MBLK.new n
a <- f mb
pure (a, MUArray 0 n (MUArrayMBA mb))
-- | Same as newNative but expect no extra return value from f
newNative_ :: (PrimMonad prim, PrimType ty)
=> CountOf ty
-> (MutableBlock ty (PrimState prim) -> prim ())
-> prim (MUArray ty (PrimState prim))
newNative_ n f = do
mb <- MBLK.new n
f mb
pure (MUArray 0 n (MUArrayMBA mb))
-- | Create a new mutable array of size @n.
--
-- When memory for a new array is allocated, we decide if that memory region
-- should be pinned (will not be copied around by GC) or unpinned (can be
-- moved around by GC) depending on its size.
--
-- You can change the threshold value used by setting the environment variable
-- @HS_FOUNDATION_UARRAY_UNPINNED_MAX@.
new :: (PrimMonad prim, PrimType ty) => CountOf ty -> prim (MUArray ty (PrimState prim))
new sz
| sizeRecast sz <= maxSizeUnpinned = newUnpinned sz
| otherwise = newPinned sz
where
-- Safe to use here: If the value changes during runtime, this will only
-- have an impact on newly created arrays.
maxSizeUnpinned = Runtime.unsafeUArrayUnpinnedMaxSize
{-# INLINE new #-}
-- | read from a cell in a mutable array without bounds checking.
--
-- Reading from invalid memory can return unpredictable and invalid values.
-- use 'read' if unsure.
unsafeRead :: (PrimMonad prim, PrimType ty) => MUArray ty (PrimState prim) -> Offset ty -> prim ty
unsafeRead (MUArray start _ (MUArrayMBA (MutableBlock mba))) i = primMbaRead mba (start + i)
unsafeRead (MUArray start _ (MUArrayAddr fptr)) i = withFinalPtr fptr $ \(Ptr addr) -> primAddrRead addr (start + i)
{-# INLINE unsafeRead #-}
-- | write to a cell in a mutable array without bounds checking.
--
-- Writing with invalid bounds will corrupt memory and your program will
-- become unreliable. use 'write' if unsure.
unsafeWrite :: (PrimMonad prim, PrimType ty) => MUArray ty (PrimState prim) -> Offset ty -> ty -> prim ()
unsafeWrite (MUArray start _ (MUArrayMBA mb)) i v = MBLK.unsafeWrite mb (start+i) v
unsafeWrite (MUArray start _ (MUArrayAddr fptr)) i v = withFinalPtr fptr $ \(Ptr addr) -> primAddrWrite addr (start+i) v
{-# INLINE unsafeWrite #-}
-- | Return the element at a specific index from an array without bounds checking.
--
-- Reading from invalid memory can return unpredictable and invalid values.
-- use 'index' if unsure.
unsafeIndex :: forall ty . PrimType ty => UArray ty -> Offset ty -> ty
unsafeIndex (UArray start _ (UArrayBA ba)) n = BLK.unsafeIndex ba (start + n)
unsafeIndex (UArray start _ (UArrayAddr fptr)) n = withUnsafeFinalPtr fptr (\(Ptr addr) -> return (primAddrIndex addr (start+n)) :: IO ty)
{-# INLINE unsafeIndex #-}
unsafeIndexer :: (PrimMonad prim, PrimType ty) => UArray ty -> ((Offset ty -> ty) -> prim a) -> prim a
unsafeIndexer (UArray start _ (UArrayBA ba)) f = f (\n -> BLK.unsafeIndex ba (start + n))
unsafeIndexer (UArray start _ (UArrayAddr fptr)) f = withFinalPtr fptr $ \(Ptr addr) -> f (\n -> primAddrIndex addr (start + n))
{-# INLINE unsafeIndexer #-}
-- | Freeze a mutable array into an array.
--
-- the MUArray must not be changed after freezing.
unsafeFreeze :: PrimMonad prim => MUArray ty (PrimState prim) -> prim (UArray ty)
unsafeFreeze (MUArray start len (MUArrayMBA mba)) =
UArray start len . UArrayBA <$> MBLK.unsafeFreeze mba
unsafeFreeze (MUArray start len (MUArrayAddr fptr)) =
pure $ UArray start len (UArrayAddr fptr)
{-# INLINE unsafeFreeze #-}
unsafeFreezeShrink :: (PrimType ty, PrimMonad prim) => MUArray ty (PrimState prim) -> CountOf ty -> prim (UArray ty)
unsafeFreezeShrink (MUArray start _ backend) n = unsafeFreeze (MUArray start n backend)
{-# INLINE unsafeFreezeShrink #-}
-- | Thaw an immutable array.
--
-- The UArray must not be used after thawing.
unsafeThaw :: (PrimType ty, PrimMonad prim) => UArray ty -> prim (MUArray ty (PrimState prim))
unsafeThaw (UArray start len (UArrayBA blk)) = MUArray start len . MUArrayMBA <$> BLK.unsafeThaw blk
unsafeThaw (UArray start len (UArrayAddr fptr)) = pure $ MUArray start len (MUArrayAddr fptr)
{-# INLINE unsafeThaw #-}
-- | Thaw an array to a mutable array.
--
-- the array is not modified, instead a new mutable array is created
-- and every values is copied, before returning the mutable array.
thaw :: (PrimMonad prim, PrimType ty) => UArray ty -> prim (MUArray ty (PrimState prim))
thaw array = do
ma <- new (length array)
unsafeCopyAtRO ma azero array (Offset 0) (length array)
pure ma
{-# INLINE thaw #-}
-- | Copy every cells of an existing array to a new array
copy :: PrimType ty => UArray ty -> UArray ty
copy array = runST (thaw array >>= unsafeFreeze)
onBackend :: (Block ty -> a)
-> (FinalPtr ty -> Ptr ty -> ST s a)
-> UArray ty
-> a
onBackend onBa _ (UArray _ _ (UArrayBA ba)) = onBa ba
onBackend _ onAddr (UArray _ _ (UArrayAddr fptr)) = withUnsafeFinalPtr fptr $ \ptr@(Ptr !_) ->
onAddr fptr ptr
{-# INLINE onBackend #-}
onBackendPure :: (Block ty -> a)
-> (Ptr ty -> a)
-> UArray ty
-> a
onBackendPure goBA goAddr arr = onBackend goBA (\_ -> pureST . goAddr) arr
{-# INLINE onBackendPure #-}
onBackendPure' :: forall ty a . PrimType ty
=> UArray ty
-> (forall container. Alg.Indexable container ty
=> container -> Offset ty -> Offset ty -> a)
-> a
onBackendPure' arr f = onBackendPure f' f' arr
where f' :: Alg.Indexable container ty => container -> a
f' c = f c start end
where (ValidRange !start !end) = offsetsValidRange arr
{-# INLINE onBackendPure' #-}
onBackendPrim :: PrimMonad prim
=> (Block ty -> prim a)
-> (FinalPtr ty -> prim a)
-> UArray ty
-> prim a
onBackendPrim onBa _ (UArray _ _ (UArrayBA ba)) = onBa ba
onBackendPrim _ onAddr (UArray _ _ (UArrayAddr fptr)) = onAddr fptr
{-# INLINE onBackendPrim #-}
onMutableBackend :: PrimMonad prim
=> (MutableBlock ty (PrimState prim) -> prim a)
-> (FinalPtr ty -> prim a)
-> MUArray ty (PrimState prim)
-> prim a
onMutableBackend onMba _ (MUArray _ _ (MUArrayMBA mba)) = onMba mba
onMutableBackend _ onAddr (MUArray _ _ (MUArrayAddr fptr)) = onAddr fptr
{-# INLINE onMutableBackend #-}
unsafeDewrap :: (Block ty -> Offset ty -> a)
-> (Ptr ty -> Offset ty -> ST s a)
-> UArray ty
-> a
unsafeDewrap _ g (UArray start _ (UArrayAddr fptr)) = withUnsafeFinalPtr fptr $ \ptr -> g ptr start
unsafeDewrap f _ (UArray start _ (UArrayBA ba)) = f ba start
{-# INLINE unsafeDewrap #-}
unsafeDewrap2 :: (ByteArray# -> ByteArray# -> a)
-> (Ptr ty -> Ptr ty -> ST s a)
-> (ByteArray# -> Ptr ty -> ST s a)
-> (Ptr ty -> ByteArray# -> ST s a)
-> UArray ty
-> UArray ty
-> a
unsafeDewrap2 f g h i (UArray _ _ back1) (UArray _ _ back2) =
case (back1, back2) of
(UArrayBA (Block ba1), UArrayBA (Block ba2)) -> f ba1 ba2
(UArrayAddr fptr1, UArrayAddr fptr2) -> withUnsafeFinalPtr fptr1 $ \ptr1 -> withFinalPtr fptr2 $ \ptr2 -> g ptr1 ptr2
(UArrayBA (Block ba1), UArrayAddr fptr2) -> withUnsafeFinalPtr fptr2 $ \ptr2 -> h ba1 ptr2
(UArrayAddr fptr1, UArrayBA (Block ba2)) -> withUnsafeFinalPtr fptr1 $ \ptr1 -> i ptr1 ba2
{-# INLINE [2] unsafeDewrap2 #-}
pureST :: a -> ST s a
pureST = pure
-- | make an array from a list of elements.
vFromList :: forall ty . PrimType ty => [ty] -> UArray ty
vFromList l = runST $ do
a <- newNative_ len copyList
unsafeFreeze a
where
len = List.length l
copyList :: MutableBlock ty s -> ST s ()
copyList mb = loop 0 l
where
loop _ [] = pure ()
loop !i (x:xs) = MBLK.unsafeWrite mb i x >> loop (i+1) xs
-- | Make an array from a list of elements with a size hint.
--
-- The list should be of the same size as the hint, as otherwise:
--
-- * The length of the list is smaller than the hint:
-- the array allocated is of the size of the hint, but is sliced
-- to only represent the valid bits
-- * The length of the list is bigger than the hint:
-- The allocated array is the size of the hint, and the list is truncated to
-- fit.
vFromListN :: forall ty . PrimType ty => CountOf ty -> [ty] -> UArray ty
vFromListN len l = runST $ do
(sz, ma) <- newNative len copyList
unsafeFreezeShrink ma sz
where
copyList :: MutableBlock ty s -> ST s (CountOf ty)
copyList mb = loop 0 l
where
loop !i [] = pure (offsetAsSize i)
loop !i (x:xs)
| i .==# len = pure (offsetAsSize i)
| otherwise = MBLK.unsafeWrite mb i x >> loop (i+1) xs
-- | transform an array to a list.
vToList :: forall ty . PrimType ty => UArray ty -> [ty]
vToList a
| len == 0 = []
| otherwise = unsafeDewrap goBa goPtr a
where
!len = length a
goBa (Block ba) start = loop start
where
!end = start `offsetPlusE` len
loop !i | i == end = []
| otherwise = primBaIndex ba i : loop (i+1)
goPtr (Ptr addr) start = pureST (loop start)
where
!end = start `offsetPlusE` len
loop !i | i == end = []
| otherwise = primAddrIndex addr i : loop (i+1)
-- | Check if two vectors are identical
equal :: (PrimType ty, Eq ty) => UArray ty -> UArray ty -> Bool
equal a b
| la /= lb = False
| otherwise = unsafeDewrap2 goBaBa goPtrPtr goBaPtr goPtrBa a b
where
!start1 = offset a
!start2 = offset b
!end = start1 `offsetPlusE` la
!la = length a
!lb = length b
goBaBa ba1 ba2 = loop start1 start2
where
loop !i !o | i == end = True
| otherwise = primBaIndex ba1 i == primBaIndex ba2 o && loop (i+o1) (o+o1)
goPtrPtr (Ptr addr1) (Ptr addr2) = pureST (loop start1 start2)
where
loop !i !o | i == end = True
| otherwise = primAddrIndex addr1 i == primAddrIndex addr2 o && loop (i+o1) (o+o1)
goBaPtr ba1 (Ptr addr2) = pureST (loop start1 start2)
where
loop !i !o | i == end = True
| otherwise = primBaIndex ba1 i == primAddrIndex addr2 o && loop (i+o1) (o+o1)
goPtrBa (Ptr addr1) ba2 = pureST (loop start1 start2)
where
loop !i !o | i == end = True
| otherwise = primAddrIndex addr1 i == primBaIndex ba2 o && loop (i+o1) (o+o1)
o1 = Offset (I# 1#)
{-# RULES "UArray/Eq/Word8" [3] equal = equalBytes #-}
{-# INLINEABLE [2] equal #-}
equalBytes :: UArray Word8 -> UArray Word8 -> Bool
equalBytes a b
| la /= lb = False
| otherwise = memcmp a b (sizeInBytes la) == 0
where
!la = length a
!lb = length b
equalMemcmp :: PrimType ty => UArray ty -> UArray ty -> Bool
equalMemcmp a b
| la /= lb = False
| otherwise = memcmp a b (sizeInBytes la) == 0
where
!la = length a
!lb = length b
-- | Compare 2 vectors
vCompare :: (Ord ty, PrimType ty) => UArray ty -> UArray ty -> Ordering
vCompare a@(UArray start1 la _) b@(UArray start2 lb _) = unsafeDewrap2 goBaBa goPtrPtr goBaPtr goPtrBa a b
where
!end = start1 `offsetPlusE` min la lb
o1 = Offset (I# 1#)
goBaBa ba1 ba2 = loop start1 start2
where
loop !i !o | i == end = la `compare` lb
| v1 == v2 = loop (i + o1) (o + o1)
| otherwise = v1 `compare` v2
where v1 = primBaIndex ba1 i
v2 = primBaIndex ba2 o
goPtrPtr (Ptr addr1) (Ptr addr2) = pureST (loop start1 start2)
where
loop !i !o | i == end = la `compare` lb
| v1 == v2 = loop (i + o1) (o + o1)
| otherwise = v1 `compare` v2
where v1 = primAddrIndex addr1 i
v2 = primAddrIndex addr2 o
goBaPtr ba1 (Ptr addr2) = pureST (loop start1 start2)
where
loop !i !o | i == end = la `compare` lb
| v1 == v2 = loop (i + o1) (o + o1)
| otherwise = v1 `compare` v2
where v1 = primBaIndex ba1 i
v2 = primAddrIndex addr2 o
goPtrBa (Ptr addr1) ba2 = pureST (loop start1 start2)
where
loop !i !o | i == end = la `compare` lb
| v1 == v2 = loop (i + o1) (o + o1)
| otherwise = v1 `compare` v2
where v1 = primAddrIndex addr1 i
v2 = primBaIndex ba2 o
-- {-# SPECIALIZE [3] vCompare :: UArray Word8 -> UArray Word8 -> Ordering = vCompareBytes #-}
{-# RULES "UArray/Ord/Word8" [3] vCompare = vCompareBytes #-}
{-# INLINEABLE [2] vCompare #-}
vCompareBytes :: UArray Word8 -> UArray Word8 -> Ordering
vCompareBytes = vCompareMemcmp
vCompareMemcmp :: (Ord ty, PrimType ty) => UArray ty -> UArray ty -> Ordering
vCompareMemcmp a b = cintToOrdering $ memcmp a b sz
where
la = length a
lb = length b
sz = sizeInBytes $ min la lb
cintToOrdering :: CInt -> Ordering
cintToOrdering 0 = la `compare` lb
cintToOrdering r | r < 0 = LT
| otherwise = GT
{-# SPECIALIZE [3] vCompareMemcmp :: UArray Word8 -> UArray Word8 -> Ordering #-}
memcmp :: PrimType ty => UArray ty -> UArray ty -> CountOf Word8 -> CInt
memcmp a@(UArray (offsetInBytes -> o1) _ _) b@(UArray (offsetInBytes -> o2) _ _) sz = unsafeDewrap2
(\s1 s2 -> unsafeDupablePerformIO $ sysHsMemcmpBaBa s1 o1 s2 o2 sz)
(\s1 s2 -> unsafePrimToST $ sysHsMemcmpPtrPtr s1 o1 s2 o2 sz)
(\s1 s2 -> unsafePrimToST $ sysHsMemcmpBaPtr s1 o1 s2 o2 sz)
(\s1 s2 -> unsafePrimToST $ sysHsMemcmpPtrBa s1 o1 s2 o2 sz)
a b
{-# SPECIALIZE [3] memcmp :: UArray Word8 -> UArray Word8 -> CountOf Word8 -> CInt #-}
-- | Copy a number of elements from an array to another array with offsets
copyAt :: forall prim ty . (PrimMonad prim, PrimType ty)
=> MUArray ty (PrimState prim) -- ^ destination array
-> Offset ty -- ^ offset at destination
-> MUArray ty (PrimState prim) -- ^ source array
-> Offset ty -- ^ offset at source
-> CountOf ty -- ^ number of elements to copy
-> prim ()
copyAt (MUArray dstStart _ (MUArrayMBA (MutableBlock dstMba))) ed (MUArray srcStart _ (MUArrayMBA (MutableBlock srcBa))) es n =
primitive $ \st -> (# copyMutableByteArray# srcBa os dstMba od nBytes st, () #)
where
!sz = primSizeInBytes (Proxy :: Proxy ty)
!(Offset (I# os)) = offsetOfE sz (srcStart + es)
!(Offset (I# od)) = offsetOfE sz (dstStart + ed)
!(CountOf (I# nBytes)) = sizeOfE sz n
copyAt (MUArray dstStart _ (MUArrayMBA (MutableBlock dstMba))) ed (MUArray srcStart _ (MUArrayAddr srcFptr)) es n =
withFinalPtr srcFptr $ \srcPtr ->
let !(Ptr srcAddr) = srcPtr `plusPtr` os
in primitive $ \s -> (# copyAddrToByteArray# srcAddr dstMba od nBytes s, () #)
where
!sz = primSizeInBytes (Proxy :: Proxy ty)
!(Offset os) = offsetOfE sz (srcStart + es)
!(Offset (I# od)) = offsetOfE sz (dstStart + ed)
!(CountOf (I# nBytes)) = sizeOfE sz n
copyAt dst od src os n = loop od os
where
!endIndex = os `offsetPlusE` n
loop !d !i
| i == endIndex = return ()
| otherwise = unsafeRead src i >>= unsafeWrite dst d >> loop (d+1) (i+1)
-- TODO Optimise with copyByteArray#
-- | Copy @n@ sequential elements from the specified offset in a source array
-- to the specified position in a destination array.
--
-- This function does not check bounds. Accessing invalid memory can return
-- unpredictable and invalid values.
unsafeCopyAtRO :: forall prim ty . (PrimMonad prim, PrimType ty)
=> MUArray ty (PrimState prim) -- ^ destination array
-> Offset ty -- ^ offset at destination
-> UArray ty -- ^ source array
-> Offset ty -- ^ offset at source
-> CountOf ty -- ^ number of elements to copy
-> prim ()
unsafeCopyAtRO (MUArray dstStart _ (MUArrayMBA (MutableBlock dstMba))) ed (UArray srcStart _ (UArrayBA (Block srcBa))) es n =
primitive $ \st -> (# copyByteArray# srcBa os dstMba od nBytes st, () #)
where
sz = primSizeInBytes (Proxy :: Proxy ty)
!(Offset (I# os)) = offsetOfE sz (srcStart+es)
!(Offset (I# od)) = offsetOfE sz (dstStart+ed)
!(CountOf (I# nBytes)) = sizeOfE sz n
unsafeCopyAtRO (MUArray dstStart _ (MUArrayMBA (MutableBlock dstMba))) ed (UArray srcStart _ (UArrayAddr srcFptr)) es n =
withFinalPtr srcFptr $ \srcPtr ->
let !(Ptr srcAddr) = srcPtr `plusPtr` os
in primitive $ \s -> (# copyAddrToByteArray# srcAddr dstMba od nBytes s, () #)
where
sz = primSizeInBytes (Proxy :: Proxy ty)
!(Offset os) = offsetOfE sz (srcStart+es)
!(Offset (I# od)) = offsetOfE sz (dstStart+ed)
!(CountOf (I# nBytes)) = sizeOfE sz n
unsafeCopyAtRO dst od src os n = loop od os
where
!endIndex = os `offsetPlusE` n
loop d i
| i == endIndex = return ()
| otherwise = unsafeWrite dst d (unsafeIndex src i) >> loop (d+1) (i+1)
empty_ :: Block ()
empty_ = runST $ primitive $ \s1 ->
case newByteArray# 0# s1 of { (# s2, mba #) ->
case unsafeFreezeByteArray# mba s2 of { (# s3, ba #) ->
(# s3, Block ba #) }}
empty :: UArray ty
empty = UArray 0 0 (UArrayBA $ Block ba) where !(Block ba) = empty_
-- | Append 2 arrays together by creating a new bigger array
append :: PrimType ty => UArray ty -> UArray ty -> UArray ty
append a b
| la == azero = b
| lb == azero = a
| otherwise = runST $ do
r <- new (la+lb)
ma <- unsafeThaw a
mb <- unsafeThaw b
copyAt r (Offset 0) ma (Offset 0) la
copyAt r (sizeAsOffset la) mb (Offset 0) lb
unsafeFreeze r
where
!la = length a
!lb = length b
concat :: forall ty . PrimType ty => [UArray ty] -> UArray ty
concat original = runST $ do
r <- new total
goCopy r 0 original
unsafeFreeze r
where
!total = size 0 original
-- size
size !sz [] = sz
size !sz (x:xs) = size (length x + sz) xs
zero = Offset 0
goCopy r = loop
where
loop _ [] = pure ()
loop !i (x:xs) = do
unsafeCopyAtRO r i x zero lx
loop (i `offsetPlusE` lx) xs
where !lx = length x
-- | Create a Block from a UArray.
--
-- Note that because of the slice, the destination block
-- is re-allocated and copied, unless the slice point
-- at the whole array
toBlock :: PrimType ty => UArray ty -> Block ty
toBlock arr@(UArray start len (UArrayBA blk))
| start == 0 && BLK.length blk == len = blk
| otherwise = toBlock $ copy arr
toBlock arr = toBlock $ copy arr
|