diff options
Diffstat (limited to 'testsuite/tests/dph/words/WordsVect.hs')
-rw-r--r-- | testsuite/tests/dph/words/WordsVect.hs | 123 |
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 + |