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
|
module TestDataParser (
parse_testdata, -- Read a => FilePath -> IO (TestData a)
write_testdata -- Show a => TestData -> IO ()
) where
import TestData
-- Parser for parsing TestData. The following is a sample of a test data:
--
--
-- Name: sample
-- Threads: 4
-- Modes: ["CAS","IO","BACK"]
-- Repeat: 6
-- Initial-List:
-- [4,5,6,7,8,4,5,754,345,23432,6547,4]
-- Tasks:
-- [Find 3,Delete 4,Insert 34,Find 45]
-- [Delete 34,Insert 43,Delete 3,Delete 45,Find 87]
-- [Insert 3 , Find 6]
-- [Find 3,Find 67, Insert 3]
--
--
-- Some assumptions:
-- - Number of tasks must correspond to number of threads.
-- - Fields must come in the exact sequence specified above.
-- Auxiliary Functions
partitionAt :: Eq a => (a -> Bool) -> [a] -> [[a]]
partitionAt f as =
filter (/=[]) (partitionAt' f as)
where
partitionAt' _ [] = []
partitionAt' f as = let (v,rest) = span f as
in v:(partitionAt' f (drop 1 rest))
is_delimit :: Char -> Bool
is_delimit ' ' = True
is_delimit '\n' = True
is_delimit _ = False
not_delimit :: Char -> Bool
not_delimit x = not (is_delimit x)
-- Parsing Functions
parse_token :: String -> (String,String)
parse_token str = let str' = dropWhile is_delimit str
in span not_delimit str'
parse_list :: String -> ([String],String)
parse_list str =
let str' = dropWhile is_delimit str
in parse_list (tail str')
where
parse_list str = let comma x = x == ','
close x = x == ']'
commaOrClose x = or [comma x,close x]
(a,rest) = span (\x -> not $ commaOrClose x) str
in case head rest of
',' -> let (as,rest') = parse_list (tail rest)
in (a:as,rest')
']' -> ([a],tail rest)
parse_list_many :: Int -> String -> ([[String]],String)
parse_list_many 0 str = ([],str)
parse_list_many n str = let (a,rest) = parse_list str
(as,rest') = parse_list_many (n-1) rest
in (a:as,rest')
drop_token :: String -> String
drop_token str = let (_,rest) = parse_token str
in rest
-- Main function for parseing testcases from file
parse_testdata :: Read a => FilePath -> IO (TestData a)
parse_testdata fname = do
{ input <- readFile fname
; let (name,input1) = parse_token (drop_token input)
(t,input2) = parse_token (drop_token input1)
(list,input3) = parse_list (drop_token input2)
(ops,_) = parse_list_many (read t) (drop_token input3)
; return $ TestData { t_name = name
, t_threads = read t
, t_init_list = map read list
, t_tasks = map readops ops } }
where
readops (s:ss) = let (oper,rest) = parse_token s
(arg,_) = parse_token rest
x = read arg
op = case oper of
"Find" -> Find x
"Delete" -> Delete x
"Insert" -> Insert x
_ -> error ("parse_testdata: " ++ oper ++ "\n" ++ rest ++ "\n" ++ arg)
in op:(readops ss)
readops [] = []
-- Main function for writing test data to file
write_testdata :: Show a => TestData a -> IO ()
write_testdata tc = writeFile (t_name tc) (show tc)
|