1 #include "./wrapped_re2.h"
2 #include "./util.h"
3 
4 #include <algorithm>
5 #include <limits>
6 #include <vector>
7 
NAN_METHOD(WrappedRE2::Split)8 NAN_METHOD(WrappedRE2::Split)
9 {
10 
11 	auto result = Nan::New<v8::Array>();
12 
13 	// unpack arguments
14 
15 	auto re2 = Nan::ObjectWrap::Unwrap<WrappedRE2>(info.This());
16 	if (!re2)
17 	{
18 		Nan::Set(result, 0, info[0]);
19 		info.GetReturnValue().Set(result);
20 		return;
21 	}
22 
23 	StrVal a = info[0];
24 	if (!a.data)
25 	{
26 		return;
27 	}
28 
29 	re2::StringPiece str = a;
30 
31 	size_t limit = std::numeric_limits<size_t>::max();
32 	if (info.Length() > 1 && info[1]->IsNumber())
33 	{
34 		size_t lim = info[1]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0);
35 		if (lim > 0)
36 		{
37 			limit = lim;
38 		}
39 	}
40 
41 	// actual work
42 
43 	std::vector<re2::StringPiece> groups(re2->regexp.NumberOfCapturingGroups() + 1), pieces;
44 	const auto &match = groups[0];
45 	size_t lastIndex = 0;
46 
47 	while (lastIndex < a.size && re2->regexp.Match(str, lastIndex, a.size, RE2::UNANCHORED, &groups[0], groups.size()))
48 	{
49 		if (match.size())
50 		{
51 			pieces.push_back(re2::StringPiece(a.data + lastIndex, match.data() - a.data - lastIndex));
52 			lastIndex = match.data() - a.data + match.size();
53 			pieces.insert(pieces.end(), groups.begin() + 1, groups.end());
54 		}
55 		else
56 		{
57 			size_t sym_size = getUtf8CharSize(a.data[lastIndex]);
58 			pieces.push_back(re2::StringPiece(a.data + lastIndex, sym_size));
59 			lastIndex += sym_size;
60 		}
61 		if (pieces.size() >= limit)
62 		{
63 			break;
64 		}
65 	}
66 	if (pieces.size() < limit && (lastIndex < a.size || (lastIndex == a.size && match.size())))
67 	{
68 		pieces.push_back(re2::StringPiece(a.data + lastIndex, a.size - lastIndex));
69 	}
70 
71 	if (pieces.empty())
72 	{
73 		Nan::Set(result, 0, info[0]);
74 		info.GetReturnValue().Set(result);
75 		return;
76 	}
77 
78 	// form a result
79 
80 	if (a.isBuffer)
81 	{
82 		for (size_t i = 0, n = std::min(pieces.size(), limit); i < n; ++i)
83 		{
84 			const auto &item = pieces[i];
85 			Nan::Set(result, i, Nan::CopyBuffer(item.data(), item.size()).ToLocalChecked());
86 		}
87 	}
88 	else
89 	{
90 		for (size_t i = 0, n = std::min(pieces.size(), limit); i < n; ++i)
91 		{
92 			const auto &item = pieces[i];
93 			Nan::Set(result, i, Nan::New(item.data(), item.size()).ToLocalChecked());
94 		}
95 	}
96 
97 	info.GetReturnValue().Set(result);
98 }
99