summaryrefslogtreecommitdiff
path: root/testsuite/tests/dph/words/WordsVect.hs
diff options
context:
space:
mode:
Diffstat (limited to 'testsuite/tests/dph/words/WordsVect.hs')
-rw-r--r--testsuite/tests/dph/words/WordsVect.hs123
1 files changed, 123 insertions, 0 deletions
diff --git a/testsuite/tests/dph/words/WordsVect.hs b/testsuite/tests/dph/words/WordsVect.hs
new file mode 100644
index 0000000000..abf416e763
--- /dev/null
+++ b/testsuite/tests/dph/words/WordsVect.hs
@@ -0,0 +1,123 @@
+
+-- Break up a string into words in parallel.
+-- Based on the presentation "Breaking Sequential Habits of Thought", Guy Steele.
+-- http://groups.csail.mit.edu/mac/users/gjs/6.945/readings/MITApril2009Steele.pdf
+--
+-- NOTE: This is a naive implementation, and I haven't benchmarked it.
+-- Using parallel arrays in Seg probably isn't helpful for performance,
+-- but it's a stress test for the vectoriser.
+--
+-- If we actually cared about performance we wouldn't want to recursively
+-- subdivide the string right down to individual characters.
+--
+{-# LANGUAGE ParallelArrays, ParallelListComp #-}
+{-# OPTIONS -fvectorise #-}
+
+module WordsVect
+ ( wordsOfPArray
+ , wordCountOfPArray )
+where
+import qualified Data.Array.Parallel.Prelude.Word8 as W
+import Data.Array.Parallel.Prelude.Word8 (Word8)
+import Data.Array.Parallel.Prelude.Int
+import Data.Array.Parallel
+
+import qualified Prelude as Prel
+
+
+-- We can't use the Prelude Char and String types in vectorised code yet..
+type Char = Word8
+char_space = W.fromInt 32
+
+type String = [: Char :]
+
+
+-- | Word state
+data State
+ = Chunk String
+ | Seg String -- initial word chunk
+ [:String:] -- complete words in the middle of the segment
+ String -- final word chunk
+
+
+-- | Compose two wordstates.
+plusState :: State -> State -> State
+plusState str1 str2
+ = case (str1, str2) of
+ (Chunk as, Chunk bs) -> Chunk (as +:+ bs)
+ (Chunk as, Seg bl bss br) -> Seg (as +:+ bl) bss br
+ (Seg al ass ar, Chunk bs) -> Seg al ass (ar +:+ bs)
+ (Seg al ass ar, Seg bl bss br) -> Seg al (ass +:+ joinEmpty [:ar +:+ bl:] +:+ bss) br
+
+joinEmpty :: [:[:Word8:]:] -> [:[:Word8:]:]
+joinEmpty ws
+ | lengthP ws == 1 && lengthP (ws !: 0) == 0 = [::]
+ | otherwise = ws
+
+
+-- | Convert a single char to a wordstate.
+stateOfChar :: Char -> State
+stateOfChar c
+ | c W.== char_space = Seg [::] [::] [::]
+ | otherwise = Chunk [:c:]
+
+
+-- | Break this string into words.
+stateOfString :: String -> State
+stateOfString str
+ = let len = lengthP str
+ result
+ | len == 0 = Chunk [::]
+ | len == 1 = stateOfChar (str !: 0)
+ | otherwise
+ = let half = len `div` 2
+ s1 = sliceP 0 half str
+ s2 = sliceP half (len-half) str
+ in plusState (stateOfString s1) (stateOfString s2)
+ in result
+
+
+-- | Count the number of words in a string.
+countWordsOfState :: State -> Int
+countWordsOfState state
+ = case state of
+ Chunk c -> wordsInChunkArr c
+ Seg c1 ws c2 -> wordsInChunkArr c1 + lengthP ws + wordsInChunkArr c2
+
+wordsInChunkArr :: [:Word8:] -> Int
+wordsInChunkArr arr
+ | lengthP arr == 0 = 0
+ | otherwise = 1
+
+
+-- | Flatten a state back to an array of Word8s,
+-- inserting spaces between the words.
+flattenState :: State -> [:Word8:]
+flattenState ss
+ = case ss of
+ Chunk s -> s
+
+ Seg w1 ws w2
+ -> w1
+ +:+ [:char_space:]
+ +:+ concatP [: w +:+ [:char_space:] | w <- ws :]
+ +:+ w2
+
+-- Interface ------------------------------------------------------------------
+
+-- | Break up an array of chars into words then flatten it back.
+wordsOfPArray :: PArray Word8 -> PArray Word8
+wordsOfPArray arr
+ = let str = fromPArrayP arr
+ state = stateOfString str
+ strOut = flattenState state
+ in toPArrayP strOut
+
+
+-- | Count the number of words in an array
+wordCountOfPArray :: PArray Word8 -> Int
+wordCountOfPArray arr
+ = let str = fromPArrayP arr
+ state = stateOfString str
+ in countWordsOfState state
+