1d86ed7fbStbbdev /*
2*b15aabb3Stbbdev     Copyright (c) 2005-2021 Intel Corporation
3d86ed7fbStbbdev 
4d86ed7fbStbbdev     Licensed under the Apache License, Version 2.0 (the "License");
5d86ed7fbStbbdev     you may not use this file except in compliance with the License.
6d86ed7fbStbbdev     You may obtain a copy of the License at
7d86ed7fbStbbdev 
8d86ed7fbStbbdev         http://www.apache.org/licenses/LICENSE-2.0
9d86ed7fbStbbdev 
10d86ed7fbStbbdev     Unless required by applicable law or agreed to in writing, software
11d86ed7fbStbbdev     distributed under the License is distributed on an "AS IS" BASIS,
12d86ed7fbStbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d86ed7fbStbbdev     See the License for the specific language governing permissions and
14d86ed7fbStbbdev     limitations under the License.
15d86ed7fbStbbdev */
16d86ed7fbStbbdev 
17d86ed7fbStbbdev #include <iostream>
18d86ed7fbStbbdev #include <string>
19d86ed7fbStbbdev #include <vector>
20d86ed7fbStbbdev #include <algorithm> // std::max
21d86ed7fbStbbdev 
22d86ed7fbStbbdev #include "oneapi/tbb/parallel_for.h"
23d86ed7fbStbbdev #include "oneapi/tbb/blocked_range.h"
24d86ed7fbStbbdev #include "oneapi/tbb/tick_count.h"
25d86ed7fbStbbdev 
26d86ed7fbStbbdev static const std::size_t N = 22;
27d86ed7fbStbbdev 
SerialSubStringFinder(const std::string & str,std::vector<std::size_t> & max_array,std::vector<std::size_t> & pos_array)28d86ed7fbStbbdev void SerialSubStringFinder(const std::string &str,
29d86ed7fbStbbdev                            std::vector<std::size_t> &max_array,
30d86ed7fbStbbdev                            std::vector<std::size_t> &pos_array) {
31d86ed7fbStbbdev     for (std::size_t i = 0; i < str.size(); ++i) {
32d86ed7fbStbbdev         std::size_t max_size = 0, max_pos = 0;
33d86ed7fbStbbdev         for (std::size_t j = 0; j < str.size(); ++j)
34d86ed7fbStbbdev             if (j != i) {
35d86ed7fbStbbdev                 std::size_t limit = str.size() - (std::max)(i, j);
36d86ed7fbStbbdev                 for (std::size_t k = 0; k < limit; ++k) {
37d86ed7fbStbbdev                     if (str[i + k] != str[j + k])
38d86ed7fbStbbdev                         break;
39d86ed7fbStbbdev                     if (k > max_size) {
40d86ed7fbStbbdev                         max_size = k;
41d86ed7fbStbbdev                         max_pos = j;
42d86ed7fbStbbdev                     }
43d86ed7fbStbbdev                 }
44d86ed7fbStbbdev             }
45d86ed7fbStbbdev         max_array[i] = max_size;
46d86ed7fbStbbdev         pos_array[i] = max_pos;
47d86ed7fbStbbdev     }
48d86ed7fbStbbdev }
49d86ed7fbStbbdev 
50d86ed7fbStbbdev class SubStringFinder {
51d86ed7fbStbbdev     const char *str;
52d86ed7fbStbbdev     const std::size_t len;
53d86ed7fbStbbdev     std::size_t *max_array;
54d86ed7fbStbbdev     std::size_t *pos_array;
55d86ed7fbStbbdev 
56d86ed7fbStbbdev public:
operator ()(const oneapi::tbb::blocked_range<std::size_t> & r) const57d86ed7fbStbbdev     void operator()(const oneapi::tbb::blocked_range<std::size_t> &r) const {
58d86ed7fbStbbdev         for (std::size_t i = r.begin(); i != r.end(); ++i) {
59d86ed7fbStbbdev             std::size_t max_size = 0, max_pos = 0;
60d86ed7fbStbbdev             for (std::size_t j = 0; j < len; ++j) {
61d86ed7fbStbbdev                 if (j != i) {
62d86ed7fbStbbdev                     std::size_t limit = len - (std::max)(i, j);
63d86ed7fbStbbdev                     for (std::size_t k = 0; k < limit; ++k) {
64d86ed7fbStbbdev                         if (str[i + k] != str[j + k])
65d86ed7fbStbbdev                             break;
66d86ed7fbStbbdev                         if (k > max_size) {
67d86ed7fbStbbdev                             max_size = k;
68d86ed7fbStbbdev                             max_pos = j;
69d86ed7fbStbbdev                         }
70d86ed7fbStbbdev                     }
71d86ed7fbStbbdev                 }
72d86ed7fbStbbdev             }
73d86ed7fbStbbdev             max_array[i] = max_size;
74d86ed7fbStbbdev             pos_array[i] = max_pos;
75d86ed7fbStbbdev         }
76d86ed7fbStbbdev     }
77d86ed7fbStbbdev     // We do not use std::vector for compatibility with offload execution
SubStringFinder(const char * s,const std::size_t s_len,std::size_t * m,std::size_t * p)78d86ed7fbStbbdev     SubStringFinder(const char *s, const std::size_t s_len, std::size_t *m, std::size_t *p)
79d86ed7fbStbbdev             : str(s),
80d86ed7fbStbbdev               len(s_len),
81d86ed7fbStbbdev               max_array(m),
82d86ed7fbStbbdev               pos_array(p) {}
83d86ed7fbStbbdev };
84d86ed7fbStbbdev 
main()85d86ed7fbStbbdev int main() {
86d86ed7fbStbbdev     std::string str[N] = { std::string("a"), std::string("b") };
87d86ed7fbStbbdev     for (std::size_t i = 2; i < N; ++i)
88d86ed7fbStbbdev         str[i] = str[i - 1] + str[i - 2];
89d86ed7fbStbbdev     std::string &to_scan = str[N - 1];
90d86ed7fbStbbdev     const std::size_t num_elem = to_scan.size();
91d86ed7fbStbbdev 
92d86ed7fbStbbdev     std::vector<std::size_t> max1(num_elem);
93d86ed7fbStbbdev     std::vector<std::size_t> pos1(num_elem);
94d86ed7fbStbbdev     std::vector<std::size_t> max2(num_elem);
95d86ed7fbStbbdev     std::vector<std::size_t> pos2(num_elem);
96d86ed7fbStbbdev 
97d86ed7fbStbbdev     std::cout << " Done building string."
98d86ed7fbStbbdev               << "\n";
99d86ed7fbStbbdev 
100d86ed7fbStbbdev     oneapi::tbb::tick_count serial_t0 = oneapi::tbb::tick_count::now();
101d86ed7fbStbbdev     SerialSubStringFinder(to_scan, max2, pos2);
102d86ed7fbStbbdev     oneapi::tbb::tick_count serial_t1 = oneapi::tbb::tick_count::now();
103d86ed7fbStbbdev     std::cout << " Done with serial version."
104d86ed7fbStbbdev               << "\n";
105d86ed7fbStbbdev 
106d86ed7fbStbbdev     oneapi::tbb::tick_count parallel_t0 = oneapi::tbb::tick_count::now();
107d86ed7fbStbbdev     oneapi::tbb::parallel_for(oneapi::tbb::blocked_range<std::size_t>(0, num_elem, 100),
108d86ed7fbStbbdev                               SubStringFinder(to_scan.c_str(), num_elem, &max1[0], &pos1[0]));
109d86ed7fbStbbdev     oneapi::tbb::tick_count parallel_t1 = oneapi::tbb::tick_count::now();
110d86ed7fbStbbdev     std::cout << " Done with parallel version."
111d86ed7fbStbbdev               << "\n";
112d86ed7fbStbbdev 
113d86ed7fbStbbdev     for (std::size_t i = 0; i < num_elem; ++i) {
114d86ed7fbStbbdev         if (max1[i] != max2[i] || pos1[i] != pos2[i]) {
115d86ed7fbStbbdev             std::cout << "ERROR: Serial and Parallel Results are Different!"
116d86ed7fbStbbdev                       << "\n";
117d86ed7fbStbbdev             break;
118d86ed7fbStbbdev         }
119d86ed7fbStbbdev     }
120d86ed7fbStbbdev     std::cout << " Done validating results."
121d86ed7fbStbbdev               << "\n";
122d86ed7fbStbbdev 
123d86ed7fbStbbdev     std::cout << "Serial version ran in " << (serial_t1 - serial_t0).seconds() << " seconds"
124d86ed7fbStbbdev               << "\n"
125d86ed7fbStbbdev               << "Parallel version ran in " << (parallel_t1 - parallel_t0).seconds() << " seconds"
126d86ed7fbStbbdev               << "\n"
127d86ed7fbStbbdev               << "Resulting in a speedup of "
128d86ed7fbStbbdev               << (serial_t1 - serial_t0).seconds() / (parallel_t1 - parallel_t0).seconds() << "\n";
129d86ed7fbStbbdev 
130d86ed7fbStbbdev     return 0;
131d86ed7fbStbbdev }
132