Merge lp:~linaro-graphics-wg/libmatrix/split-refactor into lp:~jesse-barker/libmatrix/trunk

Proposed by Alexandros Frantzis
Status: Merged
Merged at revision: 39
Proposed branch: lp:~linaro-graphics-wg/libmatrix/split-refactor
Merge into: lp:~jesse-barker/libmatrix/trunk
Diff against target: 523 lines (+396/-26)
7 files modified
Makefile (+2/-0)
shader-source.cc (+1/-1)
test/libmatrix_test.cc (+4/-0)
test/util_split_test.cc (+180/-0)
test/util_split_test.h (+31/-0)
util.cc (+160/-19)
util.h (+18/-6)
To merge this branch: bzr merge lp:~linaro-graphics-wg/libmatrix/split-refactor
Reviewer Review Type Date Requested Status
Jesse Barker Approve
Review via email: mp+118059@code.launchpad.net

Description of the change

Refactor Util::split() interface and and support for splitting quoted strings using bash-like rules.

Note that I didn't add tests for SplitModeFuzzy as I haven't understood it's purpose and mechanism completely.

To post a comment you must log in.
Revision history for this message
Jesse Barker (jesse-barker) wrote :

With tests and everything, fantastic! You left your name off the author credits on the new stuff. Was that intentional (placing the blame on me ;-)?

review: Approve
42. By Alexandros Frantzis

Correct contributors section for util split test files.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Makefile'
--- Makefile 2012-05-02 21:36:04 +0000
+++ Makefile 2012-08-06 15:06:24 +0000
@@ -9,6 +9,7 @@
9 $(TESTDIR)/inverse_test.cc \9 $(TESTDIR)/inverse_test.cc \
10 $(TESTDIR)/transpose_test.cc \10 $(TESTDIR)/transpose_test.cc \
11 $(TESTDIR)/shader_source_test.cc \11 $(TESTDIR)/shader_source_test.cc \
12 $(TESTDIR)/util_split_test.cc \
12 $(TESTDIR)/libmatrix_test.cc13 $(TESTDIR)/libmatrix_test.cc
13TESTOBJS = $(TESTSRCS:.cc=.o)14TESTOBJS = $(TESTSRCS:.cc=.o)
1415
@@ -32,6 +33,7 @@
32$(TESTDIR)/inverse_test.o: $(TESTDIR)/inverse_test.cc $(TESTDIR)/inverse_test.h $(TESTDIR)/libmatrix_test.h mat.h33$(TESTDIR)/inverse_test.o: $(TESTDIR)/inverse_test.cc $(TESTDIR)/inverse_test.h $(TESTDIR)/libmatrix_test.h mat.h
33$(TESTDIR)/transpose_test.o: $(TESTDIR)/transpose_test.cc $(TESTDIR)/transpose_test.h $(TESTDIR)/libmatrix_test.h mat.h34$(TESTDIR)/transpose_test.o: $(TESTDIR)/transpose_test.cc $(TESTDIR)/transpose_test.h $(TESTDIR)/libmatrix_test.h mat.h
34$(TESTDIR)/shader_source_test.o: $(TESTDIR)/shader_source_test.cc $(TESTDIR)/shader_source_test.h $(TESTDIR)/libmatrix_test.h shader-source.h35$(TESTDIR)/shader_source_test.o: $(TESTDIR)/shader_source_test.cc $(TESTDIR)/shader_source_test.h $(TESTDIR)/libmatrix_test.h shader-source.h
36$(TESTDIR)/util_split_test.o: $(TESTDIR)/util_split_test.cc $(TESTDIR)/util_split_test.h $(TESTDIR)/libmatrix_test.h util.h
35$(TESTDIR)/libmatrix_test: $(TESTOBJS) libmatrix.a37$(TESTDIR)/libmatrix_test: $(TESTOBJS) libmatrix.a
36 $(CXX) -o $@ $^38 $(CXX) -o $@ $^
37run_tests: $(LIBMATRIX_TESTS)39run_tests: $(LIBMATRIX_TESTS)
3840
=== modified file 'shader-source.cc'
--- shader-source.cc 2012-01-26 16:12:35 +0000
+++ shader-source.cc 2012-08-06 15:06:24 +0000
@@ -589,7 +589,7 @@
589{589{
590 std::vector<std::string> elems;590 std::vector<std::string> elems;
591591
592 Util::split(precision_values, ',', elems);592 Util::split(precision_values, ',', elems, Util::SplitModeNormal);
593593
594 for (size_t i = 0; i < elems.size() && i < 4; i++) {594 for (size_t i = 0; i < elems.size() && i < 4; i++) {
595 const std::string& pstr(elems[i]);595 const std::string& pstr(elems[i]);
596596
=== modified file 'test/libmatrix_test.cc'
--- test/libmatrix_test.cc 2012-01-23 19:18:34 +0000
+++ test/libmatrix_test.cc 2012-08-06 15:06:24 +0000
@@ -8,6 +8,7 @@
8//8//
9// Contributors:9// Contributors:
10// Jesse Barker - original implementation.10// Jesse Barker - original implementation.
11// Alexandros Frantzis - Util::split tests
11//12//
12#include <iostream>13#include <iostream>
13#include <string>14#include <string>
@@ -17,6 +18,7 @@
17#include "transpose_test.h"18#include "transpose_test.h"
18#include "const_vec_test.h"19#include "const_vec_test.h"
19#include "shader_source_test.h"20#include "shader_source_test.h"
21#include "util_split_test.h"
2022
21using std::cerr;23using std::cerr;
22using std::cout;24using std::cout;
@@ -42,6 +44,8 @@
42 testVec.push_back(new MatrixTest3x3Transpose());44 testVec.push_back(new MatrixTest3x3Transpose());
43 testVec.push_back(new MatrixTest4x4Transpose());45 testVec.push_back(new MatrixTest4x4Transpose());
44 testVec.push_back(new ShaderSourceBasic());46 testVec.push_back(new ShaderSourceBasic());
47 testVec.push_back(new UtilSplitTestNormal());
48 testVec.push_back(new UtilSplitTestQuoted());
4549
46 for (vector<MatrixTest*>::iterator testIt = testVec.begin();50 for (vector<MatrixTest*>::iterator testIt = testVec.begin();
47 testIt != testVec.end();51 testIt != testVec.end();
4852
=== added file 'test/util_split_test.cc'
--- test/util_split_test.cc 1970-01-01 00:00:00 +0000
+++ test/util_split_test.cc 2012-08-06 15:06:24 +0000
@@ -0,0 +1,180 @@
1//
2// Copyright (c) 2012 Linaro Limited
3//
4// All rights reserved. This program and the accompanying materials
5// are made available under the terms of the MIT License which accompanies
6// this distribution, and is available at
7// http://www.opensource.org/licenses/mit-license.php
8//
9// Contributors:
10// Alexandros Frantzis - original implementation.
11//
12#include <iostream>
13#include <string>
14#include <vector>
15#include "libmatrix_test.h"
16#include "util_split_test.h"
17#include "../util.h"
18
19using std::cout;
20using std::endl;
21using std::string;
22using std::vector;
23
24template <typename T> static bool
25areVectorsEqual(vector<T>& vec1, vector<T>& vec2)
26{
27 if (vec1.size() != vec2.size())
28 return false;
29
30 for (unsigned int i = 0; i < vec1.size(); i++)
31 {
32 if (vec1[i] != vec2[i])
33 return false;
34 }
35
36 return true;
37}
38
39template <typename T> static void
40printVector(vector<T>& vec)
41{
42 cout << "[";
43 for (unsigned int i = 0; i < vec.size(); i++)
44 {
45 cout << '"' << vec[i] << '"';
46 if (i < vec.size() - 1)
47 cout << ", ";
48 }
49 cout << "]";
50}
51
52void
53UtilSplitTestNormal::run(const Options& options)
54{
55 const string test1("abc def ghi");
56 const string test2(" abc: def :ghi ");
57 vector<string> expected1;
58 vector<string> expected2;
59 vector<string> results;
60
61 expected1.push_back("abc");
62 expected1.push_back("def");
63 expected1.push_back("ghi");
64
65 expected2.push_back(" abc");
66 expected2.push_back(" def ");
67 expected2.push_back("ghi ");
68
69 if (options.beVerbose())
70 {
71 cout << "Testing string \"" << test1 << "\"" << endl;
72 }
73
74 Util::split(test1, ' ', results, Util::SplitModeNormal);
75
76 if (options.beVerbose())
77 {
78 cout << "Split result: ";
79 printVector(results);
80 cout << endl << "Expected: ";
81 printVector(expected1);
82 cout << endl;
83 }
84
85 if (!areVectorsEqual(results, expected1))
86 {
87 return;
88 }
89
90 results.clear();
91
92 if (options.beVerbose())
93 {
94 cout << "Testing string \"" << test2 << "\"" << endl;
95 }
96
97 Util::split(test2, ':', results, Util::SplitModeNormal);
98
99 if (options.beVerbose())
100 {
101 cout << "Split result: ";
102 printVector(results);
103 cout << endl << "Expected: ";
104 printVector(expected2);
105 cout << endl;
106 }
107
108 if (!areVectorsEqual(results, expected2))
109 {
110 return;
111 }
112
113 pass_ = true;
114}
115
116void
117UtilSplitTestQuoted::run(const Options& options)
118{
119 const string test1("abc \"def' ghi\" klm\\ nop -b qr:title='123 \"456'");
120 const string test2("abc: def='1:2:3:'ghi : \":jk\"");
121 vector<string> expected1;
122 vector<string> expected2;
123 vector<string> results;
124
125 expected1.push_back("abc");
126 expected1.push_back("def' ghi");
127 expected1.push_back("klm nop");
128 expected1.push_back("-b");
129 expected1.push_back("qr:title=123 \"456");
130
131 expected2.push_back("abc");
132 expected2.push_back(" def=1:2:3:ghi ");
133 expected2.push_back(" :jk");
134
135 if (options.beVerbose())
136 {
137 cout << "Testing string \"" << test1 << "\"" << endl;
138 }
139
140 Util::split(test1, ' ', results, Util::SplitModeQuoted);
141
142 if (options.beVerbose())
143 {
144 cout << "Split result: ";
145 printVector(results);
146 cout << endl << "Expected: ";
147 printVector(expected1);
148 cout << endl;
149 }
150
151 if (!areVectorsEqual(results, expected1))
152 {
153 return;
154 }
155
156 results.clear();
157
158 if (options.beVerbose())
159 {
160 cout << "Testing string \"" << test2 << "\"" << endl;
161 }
162
163 Util::split(test2, ':', results, Util::SplitModeQuoted);
164
165 if (options.beVerbose())
166 {
167 cout << "Split result: ";
168 printVector(results);
169 cout << endl << "Expected: ";
170 printVector(expected2);
171 cout << endl;
172 }
173
174 if (!areVectorsEqual(results, expected2))
175 {
176 return;
177 }
178
179 pass_ = true;
180}
0181
=== added file 'test/util_split_test.h'
--- test/util_split_test.h 1970-01-01 00:00:00 +0000
+++ test/util_split_test.h 2012-08-06 15:06:24 +0000
@@ -0,0 +1,31 @@
1//
2// Copyright (c) 2012 Linaro Limited
3//
4// All rights reserved. This program and the accompanying materials
5// are made available under the terms of the MIT License which accompanies
6// this distribution, and is available at
7// http://www.opensource.org/licenses/mit-license.php
8//
9// Contributors:
10// Alexandros Frantzis - original implementation.
11//
12#ifndef UTIL_SPLIT_TEST_H_
13#define UTIL_SPLIT_TEST_H_
14
15class MatrixTest;
16class Options;
17
18class UtilSplitTestNormal : public MatrixTest
19{
20public:
21 UtilSplitTestNormal() : MatrixTest("Util::split::normal") {}
22 virtual void run(const Options& options);
23};
24
25class UtilSplitTestQuoted : public MatrixTest
26{
27public:
28 UtilSplitTestQuoted() : MatrixTest("Util::split::quoted") {}
29 virtual void run(const Options& options);
30};
31#endif // UTIL_SPLIT_TEST_H_
032
=== modified file 'util.cc'
--- util.cc 2012-05-02 21:36:04 +0000
+++ util.cc 2012-08-06 15:06:24 +0000
@@ -25,25 +25,102 @@
25using std::string;25using std::string;
26using std::vector;26using std::vector;
2727
28void28/*
29Util::split(const string& src, char delim, vector<string>& elementVec, bool fuzzy)29 * State machine for bash-like quoted string escaping:
30{30 *
31 // Trivial rejection31 * \
32 if (src.empty())32 * -----------> +---------+
33 {33 * | ---------- | Escaped |
34 return;34 * | | *,ESC +---------+
35 }35 * | |
3636 * | v '
37 // Simple case: we want to enforce the value of 'delim' strictly 37 * +--------+ ---> +--------------+ -----
38 if (!fuzzy)38 * | Normal | <--- | SingleQuoted | | *, ESC
39 {39 * +--------+ ' +--------------+ <----
40 std::stringstream ss(src);40 * | ^
41 string item;41 * | |
42 while(std::getline(ss, item, delim))42 * | | " +--------------+ ----
43 elementVec.push_back(item);43 * | ---------- | DoubleQuoted | | *, ESC
44 return;44 * -----------> +--------------+ <---
45 }45 * " | ^
4646 * \ | | *, ESC
47 * v |
48 * +---------------------+
49 * | DoubleQuotedEscaped |
50 * +---------------------+
51 *
52 * ESC: Mark character as Escaped
53 */
54static void
55fill_escape_vector(const string &str, vector<bool> &esc_vec)
56{
57 enum State {
58 StateNormal,
59 StateEscaped,
60 StateDoubleQuoted,
61 StateDoubleQuotedEscaped,
62 StateSingleQuoted
63 };
64
65 State state = StateNormal;
66
67 for (string::const_iterator iter = str.begin();
68 iter != str.end();
69 iter++)
70 {
71 const char c(*iter);
72 bool esc = false;
73
74 switch (state) {
75 case StateNormal:
76 if (c == '"')
77 state = StateDoubleQuoted;
78 else if (c == '\\')
79 state = StateEscaped;
80 else if (c == '\'')
81 state = StateSingleQuoted;
82 break;
83 case StateEscaped:
84 esc = true;
85 state = StateNormal;
86 break;
87 case StateDoubleQuoted:
88 if (c == '"')
89 state = StateNormal;
90 else if (c == '\\')
91 state = StateDoubleQuotedEscaped;
92 else
93 esc = true;
94 break;
95 case StateDoubleQuotedEscaped:
96 esc = true;
97 state = StateDoubleQuoted;
98 break;
99 case StateSingleQuoted:
100 if (c == '\'')
101 state = StateNormal;
102 else
103 esc = true;
104 default:
105 break;
106 }
107
108 esc_vec.push_back(esc);
109 }
110}
111
112static void
113split_normal(const string& src, char delim, vector<string>& elementVec)
114{
115 std::stringstream ss(src);
116 string item;
117 while(std::getline(ss, item, delim))
118 elementVec.push_back(item);
119}
120
121static void
122split_fuzzy(const string& src, char delim, vector<string>& elementVec)
123{
47 // Fuzzy case: Initialize our delimiter string based upon the caller's plus124 // Fuzzy case: Initialize our delimiter string based upon the caller's plus
48 // a space to allow for more flexibility.125 // a space to allow for more flexibility.
49 string delimiter(" ");126 string delimiter(" ");
@@ -76,6 +153,70 @@
76 elementVec.push_back(str);153 elementVec.push_back(str);
77}154}
78155
156static void
157split_quoted(const string& src, char delim, vector<string>& elementVec)
158{
159 std::stringstream ss;
160 vector<bool> escVec;
161
162 /* Mark characters in the string as escaped or not */
163 fill_escape_vector(src, escVec);
164
165 /* Sanity check... */
166 if (src.length() != escVec.size())
167 return;
168
169 for (vector<bool>::const_iterator iter = escVec.begin();
170 iter != escVec.end();
171 iter++)
172 {
173 bool escaped = static_cast<bool>(*iter);
174 char c = src[iter - escVec.begin()];
175
176 /* Output all characters, except unescaped ",\,' */
177 if ((c != '"' && c != '\\' && c != '\'') || escaped) {
178 /* If we reach an unescaped delimiter character, do a split */
179 if (c == delim && !escaped) {
180 elementVec.push_back(ss.str());
181 ss.str("");
182 ss.clear();
183 }
184 else {
185 ss << c;
186 }
187 }
188
189 }
190
191 /* Handle final element, delimited by end of string */
192 const string &finalElement(ss.str());
193 if (!finalElement.empty())
194 elementVec.push_back(finalElement);
195}
196
197void
198Util::split(const string& src, char delim, vector<string>& elementVec,
199 Util::SplitMode mode)
200{
201 // Trivial rejection
202 if (src.empty())
203 {
204 return;
205 }
206
207 switch (mode)
208 {
209 case Util::SplitModeNormal:
210 return split_normal(src, delim, elementVec);
211 case Util::SplitModeFuzzy:
212 return split_fuzzy(src, delim, elementVec);
213 case Util::SplitModeQuoted:
214 return split_quoted(src, delim, elementVec);
215 default:
216 break;
217 }
218}
219
79uint64_t220uint64_t
80Util::get_timestamp_us()221Util::get_timestamp_us()
81{222{
82223
=== modified file 'util.h'
--- util.h 2012-05-02 21:36:04 +0000
+++ util.h 2012-08-06 15:06:24 +0000
@@ -25,21 +25,33 @@
2525
26struct Util {26struct Util {
27 /**27 /**
28 * How to perform the split() operation
29 */
30 enum SplitMode {
31 /** Normal split operation */
32 SplitModeNormal,
33 /** Allow for spaces and multiple consecutive occurences of the delimiter */
34 SplitModeFuzzy,
35 /** Take into account bash-like quoting and escaping rules */
36 SplitModeQuoted
37 };
38
39 /**
28 * split() - Splits a string into elements using a provided delimiter40 * split() - Splits a string into elements using a provided delimiter
29 *41 *
30 * @s: the string to split42 * @s: the string to split
31 * @delim: the delimiter to use43 * @delim: the delimiter to use
32 * @elems: the string vector to populate44 * @elems: the string vector to populate
33 * @fuzzy: (optional) enable/disable strict handling of @delim45 * @mode: the SplitMode to use
34 *46 *
35 * Using @delim to determine field boundaries, splits @s into separate47 * Using @delim to determine field boundaries, splits @s into separate
36 * string elements. These elements are returned in the string vector48 * string elements. These elements are returned in the string vector
37 * @elems. If @fuzzy is true, then the handling of @delim allows for49 * @elems. As long as @s is non-empty, there will be at least one
38 * spaces and multiple consecutive occurences of @delim in determining50 * element in @elems.
39 * field boundaries. As long as @s is non-empty, there will be at least
40 * one element in @elems.
41 */51 */
42 static void split(const std::string &s, char delim, std::vector<std::string> &elems, bool fuzzy = false);52 static void split(const std::string& src, char delim,
53 std::vector<std::string>& elems,
54 Util::SplitMode mode);
43 /**55 /**
44 * get_timestamp_us() - Returns the current time in microseconds56 * get_timestamp_us() - Returns the current time in microseconds
45 */57 */

Subscribers

People subscribed via source and target branches