Skip to content

Commit 8bac901

Browse files
committed
zero copy split
1 parent 02f53c4 commit 8bac901

37 files changed

+188
-135
lines changed

iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.iab.gpp.encoder.section.EncodableSection;
1414
import com.iab.gpp.encoder.section.HeaderV1;
1515
import com.iab.gpp.encoder.section.Sections;
16+
import com.iab.gpp.encoder.section.SlicedCharSequence;
1617
import com.iab.gpp.encoder.section.TcfCaV1;
1718
import com.iab.gpp.encoder.section.TcfEuV2;
1819
import com.iab.gpp.encoder.section.UsCaV1;
@@ -285,14 +286,14 @@ protected Map<String, EncodableSection> decodeModel(String str) {
285286
Map<String, EncodableSection> sections = new HashMap<>();
286287

287288
if(str != null && !str.isEmpty()) {
288-
String[] encodedSections = str.split("~");
289-
HeaderV1 header = new HeaderV1(encodedSections[0]);
289+
List<CharSequence> encodedSections = SlicedCharSequence.split(str, '~');
290+
HeaderV1 header = new HeaderV1(encodedSections.get(0));
290291
sections.put(HeaderV1.NAME, header);
291292

292293
@SuppressWarnings("unchecked")
293294
List<Integer> sectionIds = (List<Integer>) header.getFieldValue("SectionIds");
294295
for (int i = 0; i < sectionIds.size(); i++) {
295-
String section = encodedSections[i + 1];
296+
CharSequence section = encodedSections.get(i + 1);
296297
switch (sectionIds.get(i)) {
297298
case TcfEuV2.ID:
298299
sections.put(TcfEuV2.NAME, new TcfEuV2(section));

iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/AbstractBase64UrlEncoder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public String encode(String bitString) {
4444
return str.toString();
4545
}
4646

47-
public BitString decode(String str) {
47+
public BitString decode(CharSequence str) {
4848
int length = str.length();
4949
BitStringBuilder sb = new BitStringBuilder(length * BASE64_BITS);
5050
for (int i = 0; i < length; i++) {

iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableSegmentedBitStringSection.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ private void decodeSegmentFromBitString(String[] segment, BitString segmentBitSt
105105
public abstract String encode() throws EncodingException;
106106

107107
@Override
108-
public abstract void decode(String encodedString) throws DecodingException;
108+
public abstract void decode(CharSequence encodedString) throws DecodingException;
109109

110110
@Override
111111
public abstract int getId();

iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractLazilyEncodableSection.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public abstract class AbstractLazilyEncodableSection implements EncodableSection
88

99
private List<EncodableSegment> segments;
1010

11-
private String encodedString = null;
11+
private CharSequence encodedString = null;
1212

1313
private boolean dirty = false;
1414
private boolean decoded = true;
@@ -21,7 +21,7 @@ public AbstractLazilyEncodableSection() {
2121

2222
protected abstract String encodeSection(List<EncodableSegment> segments);
2323

24-
protected abstract List<EncodableSegment> decodeSection(String encodedString);
24+
protected abstract List<EncodableSegment> decodeSection(CharSequence encodedString);
2525

2626
public boolean hasField(String fieldName) {
2727
if (!this.decoded) {
@@ -73,16 +73,16 @@ public void setFieldValue(String fieldName, Object value) {
7373
}
7474

7575
public String encode() {
76-
if (this.encodedString == null || this.encodedString.isEmpty() || this.dirty) {
76+
if (this.encodedString == null || this.encodedString.length() == 0 || this.dirty) {
7777
this.encodedString = this.encodeSection(this.segments);
7878
this.dirty = false;
7979
this.decoded = true;
8080
}
8181

82-
return this.encodedString;
82+
return this.encodedString.toString();
8383
}
8484

85-
public void decode(String encodedString) {
85+
public void decode(CharSequence encodedString) {
8686
this.encodedString = encodedString;
8787
this.dirty = false;
8888
this.decoded = false;

iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/EncodableSection.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ public interface EncodableSection {
1616

1717
String encode();
1818

19-
void decode(String encodedString);
19+
void decode(CharSequence encodedString);
2020
}

iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/HeaderV1.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public HeaderV1() {
1717
super();
1818
}
1919

20-
public HeaderV1(String encodedString) {
20+
public HeaderV1(CharSequence encodedString) {
2121
super();
2222
decode(encodedString);
2323
}
@@ -43,15 +43,15 @@ protected List<EncodableSegment> initializeSegments() {
4343
}
4444

4545
@Override
46-
protected List<EncodableSegment> decodeSection(String encodedString) {
46+
protected List<EncodableSegment> decodeSection(CharSequence encodedString) {
4747
List<EncodableSegment> segments = initializeSegments();
4848

49-
if(encodedString != null && !encodedString.isEmpty()) {
50-
String[] encodedSegments = encodedString.split("\\.");
49+
if(encodedString != null && encodedString.length() > 0) {
50+
List<CharSequence> encodedSegments = SlicedCharSequence.split(encodedString, '.');
5151

52-
for(int i=0; i<segments.size(); i++) {
53-
if(encodedSegments.length > i) {
54-
segments.get(i).decode(encodedSegments[i]);
52+
for (int i=0; i<segments.size(); i++) {
53+
if (encodedSegments.size() > i) {
54+
segments.get(i).decode(encodedSegments.get(i));
5555
}
5656
}
5757
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.iab.gpp.encoder.section;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
public final class SlicedCharSequence implements CharSequence {
7+
8+
private final CharSequence base;
9+
private final int start;
10+
private final int end;
11+
12+
private SlicedCharSequence(CharSequence base, int start, int end) {
13+
this.base = base;
14+
this.start = start;
15+
this.end = end;
16+
}
17+
18+
public static List<CharSequence> split(CharSequence charSequence, char splitter) {
19+
List<CharSequence> out = new ArrayList<>(1);
20+
int length = charSequence.length();
21+
int start = 0;
22+
for (int i = 0; i < length; i++) {
23+
if (charSequence.charAt(i) == splitter) {
24+
out.add(new SlicedCharSequence(charSequence, start, i));
25+
start = i + 1;
26+
}
27+
}
28+
out.add(new SlicedCharSequence(charSequence, start, length));
29+
return out;
30+
}
31+
32+
@Override
33+
public int length() {
34+
return end - start;
35+
}
36+
37+
@Override
38+
public char charAt(int index) {
39+
return base.charAt(start + index);
40+
}
41+
42+
@Override
43+
public CharSequence subSequence(int newStart, int newEnd) {
44+
return base.subSequence(start + newStart, start + newEnd);
45+
}
46+
47+
@Override
48+
public String toString() {
49+
return base.subSequence(start, end).toString();
50+
}
51+
52+
}

iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfCaV1.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public TcfCaV1() {
2424
super();
2525
}
2626

27-
public TcfCaV1(String encodedString) {
27+
public TcfCaV1(CharSequence encodedString) {
2828
super();
2929
decode(encodedString);
3030
}
@@ -50,12 +50,12 @@ protected List<EncodableSegment> initializeSegments() {
5050
}
5151

5252
@Override
53-
public List<EncodableSegment> decodeSection(String encodedString) {
53+
public List<EncodableSegment> decodeSection(CharSequence encodedString) {
5454
List<EncodableSegment> segments = initializeSegments();
5555

56-
if(encodedString != null && !encodedString.isEmpty()) {
57-
String[] encodedSegments = encodedString.split("\\.");
58-
for (int i = 0; i < encodedSegments.length; i++) {
56+
if (encodedString != null && encodedString.length() > 0) {
57+
List<CharSequence> encodedSegments = SlicedCharSequence.split(encodedString, '.');
58+
for (int i = 0; i < encodedSegments.size(); i++) {
5959

6060
/**
6161
* The first 3 bits contain the segment id. Rather than decode the entire string, just check the first character.
@@ -68,16 +68,16 @@ public List<EncodableSegment> decodeSection(String encodedString) {
6868
* for the encoding version which only coincidentally works here because the version value is less than 8.
6969
*/
7070

71-
String encodedSegment = encodedSegments[i];
72-
if(!encodedSegment.isEmpty()) {
71+
CharSequence encodedSegment = encodedSegments.get(i);
72+
if (encodedSegment.length() > 0) {
7373
char firstChar = encodedSegment.charAt(0);
7474

7575
if(firstChar >= 'A' && firstChar <= 'H') {
76-
segments.get(0).decode(encodedSegments[i]);
76+
segments.get(0).decode(encodedSegment);
7777
} else if(firstChar >= 'I' && firstChar <= 'P') {
78-
segments.get(2).decode(encodedSegments[i]);
78+
segments.get(2).decode(encodedSegment);
7979
} else if((firstChar >= 'Y' && firstChar <= 'Z') || (firstChar >= 'a' && firstChar <= 'f')) {
80-
segments.get(1).decode(encodedSegments[i]);
80+
segments.get(1).decode(encodedSegment);
8181
} else {
8282
throw new DecodingException("Invalid segment '" + encodedSegment + "'");
8383
}

iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public TcfEuV2() {
2525
super();
2626
}
2727

28-
public TcfEuV2(String encodedString) {
28+
public TcfEuV2(CharSequence encodedString) {
2929
super();
3030
decode(encodedString);
3131
}
@@ -51,12 +51,12 @@ protected List<EncodableSegment> initializeSegments() {
5151
}
5252

5353
@Override
54-
public List<EncodableSegment> decodeSection(String encodedString) {
54+
public List<EncodableSegment> decodeSection(CharSequence encodedString) {
5555
List<EncodableSegment> segments = initializeSegments();
5656

57-
if(encodedString != null && !encodedString.isEmpty()) {
58-
String[] encodedSegments = encodedString.split("\\.");
59-
for (int i = 0; i < encodedSegments.length; i++) {
57+
if (encodedString != null && encodedString.length() > 0) {
58+
List<CharSequence> encodedSegments = SlicedCharSequence.split(encodedString, '.');
59+
for (int i = 0; i < encodedSegments.size(); i++) {
6060

6161
/**
6262
* The first 3 bits contain the segment id. Rather than decode the entire string, just check the first character.
@@ -70,19 +70,19 @@ public List<EncodableSegment> decodeSection(String encodedString) {
7070
* for the encoding version which only coincidentally works here because the version value is less than 8.
7171
*/
7272

73-
String encodedSegment = encodedSegments[i];
74-
if(!encodedSegment.isEmpty()) {
73+
CharSequence encodedSegment = encodedSegments.get(i);
74+
if (encodedSegment.length() > 0) {
7575
char firstChar = encodedSegment.charAt(0);
7676

7777
// unfortunately, the segment ordering doesn't match the segment ids
7878
if(firstChar >= 'A' && firstChar <= 'H') {
79-
segments.get(0).decode(encodedSegments[i]);
79+
segments.get(0).decode(encodedSegment);
8080
} else if(firstChar >= 'I' && firstChar <= 'P') {
81-
segments.get(3).decode(encodedSegments[i]);
81+
segments.get(3).decode(encodedSegment);
8282
} else if(firstChar >= 'Q' && firstChar <= 'X') {
83-
segments.get(2).decode(encodedSegments[i]);
83+
segments.get(2).decode(encodedSegment);
8484
} else if((firstChar >= 'Y' && firstChar <= 'Z') || (firstChar >= 'a' && firstChar <= 'f')) {
85-
segments.get(1).decode(encodedSegments[i]);
85+
segments.get(1).decode(encodedSegment);
8686
} else {
8787
throw new DecodingException("Invalid segment '" + encodedSegment + "'");
8888
}

iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCaV1.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public UsCaV1() {
1818
super();
1919
}
2020

21-
public UsCaV1(String encodedString) {
21+
public UsCaV1(CharSequence encodedString) {
2222
super();
2323
decode(encodedString);
2424
}
@@ -44,19 +44,19 @@ protected List<EncodableSegment> initializeSegments() {
4444
}
4545

4646
@Override
47-
protected List<EncodableSegment> decodeSection(String encodedString) {
47+
protected List<EncodableSegment> decodeSection(CharSequence encodedString) {
4848
List<EncodableSegment> segments = initializeSegments();
4949

50-
if(encodedString != null && !encodedString.isEmpty()) {
51-
String[] encodedSegments = encodedString.split("\\.");
50+
if (encodedString != null && encodedString.length() > 0) {
51+
List<CharSequence> encodedSegments = SlicedCharSequence.split(encodedString, '.');
5252

53-
if(encodedSegments.length > 0) {
54-
segments.get(0).decode(encodedSegments[0]);
53+
if (encodedSegments.size() > 0) {
54+
segments.get(0).decode(encodedSegments.get(0));
5555
}
5656

57-
if(encodedSegments.length > 1) {
57+
if (encodedSegments.size() > 1) {
5858
segments.get(1).setFieldValue(UsCaV1Field.GPC_SEGMENT_INCLUDED, true);
59-
segments.get(1).decode(encodedSegments[1]);
59+
segments.get(1).decode(encodedSegments.get(1));
6060
} else {
6161
segments.get(1).setFieldValue(UsCaV1Field.GPC_SEGMENT_INCLUDED, false);
6262
}

0 commit comments

Comments
 (0)