Skip to content

Commit 93107e5

Browse files
nitzanjAmir Tocker
authored andcommitted
Improve performance of url.generate() method.
* Replace regular expression with custom string methods, where possible. * Pre-compile regular expression patterns. * Replace `SortedMap` with `HashMap`, and sort once after `put` calls. * Add tests for new string methods.
1 parent 3ef9eba commit 93107e5

File tree

8 files changed

+427
-123
lines changed

8 files changed

+427
-123
lines changed

cloudinary-core/src/main/java/com/cloudinary/Transformation.java

Lines changed: 80 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import com.cloudinary.utils.StringUtils;
1313

1414
@SuppressWarnings({"rawtypes", "unchecked"})
15-
public class Transformation<T extends Transformation> implements Serializable{
15+
public class Transformation<T extends Transformation> implements Serializable {
1616
public static final String VAR_NAME_RE = "^\\$[a-zA-Z][a-zA-Z0-9]+$";
1717
protected Map transformation;
1818
protected List<Map> transformations;
@@ -27,6 +27,27 @@ public class Transformation<T extends Transformation> implements Serializable{
2727
protected static Map responsiveWidthTransformation = null;
2828
private static final Pattern RANGE_VALUE_RE = Pattern.compile("^((?:\\d+\\.)?\\d+)([%pP])?$");
2929
private static final Pattern RANGE_RE = Pattern.compile("^(\\d+\\.)?\\d+[%pP]?\\.\\.(\\d+\\.)?\\d+[%pP]?$");
30+
private static final String[] SIMPLE_PARAMS = new String[]{
31+
"ac", "audio_codec",
32+
"af", "audio_frequency",
33+
"bo", "border",
34+
"br", "bit_rate",
35+
"cs", "color_space",
36+
"d", "default_image",
37+
"dl", "delay",
38+
"dn", "density",
39+
"f", "fetch_format",
40+
"fn", "custom_action",
41+
"fps", "fps",
42+
"g", "gravity",
43+
"l", "overlay",
44+
"p", "prefix",
45+
"pg", "page",
46+
"u", "underlay",
47+
"vs", "video_sampling",
48+
"sp", "streaming_profile",
49+
"ki", "keyframe_interval"
50+
};
3051

3152
public Transformation(Transformation transformation) {
3253
this(dup(transformation.transformations));
@@ -94,7 +115,7 @@ public T border(String value) {
94115
}
95116

96117
public T border(int width, String color) {
97-
return param("border", "" + width + "px_solid_" + color.replaceFirst("^#", "rgb:"));
118+
return param("border", "" + width + "px_solid_" + replaceColorPrefix(color));
98119
}
99120

100121
public T x(Object value) {
@@ -123,6 +144,7 @@ public T gravity(String value) {
123144

124145
/**
125146
* Set the keyframe interval parameter
147+
*
126148
* @param value Interval in seconds
127149
* @return The transformation for chaining
128150
*/
@@ -132,6 +154,7 @@ public T keyframeInterval(float value) {
132154

133155
/**
134156
* Set the keyframe interval parameter
157+
*
135158
* @param value Interval in seconds.
136159
* @return The transformation for chaining
137160
*/
@@ -371,6 +394,7 @@ public T responsiveWidth(boolean value) {
371394

372395
/**
373396
* Start defining a condition, which will be completed with a call {@link Condition#then()}
397+
*
374398
* @return condition
375399
*/
376400
public Condition ifCondition() {
@@ -379,6 +403,7 @@ public Condition ifCondition() {
379403

380404
/**
381405
* Define a conditional transformation defined by the condition string
406+
*
382407
* @param condition a condition string
383408
* @return the transformation for chaining
384409
*/
@@ -389,6 +414,7 @@ public T ifCondition(String condition) {
389414

390415
/**
391416
* Define a conditional transformation
417+
*
392418
* @param expression a condition
393419
* @return the transformation for chaining
394420
*/
@@ -398,6 +424,7 @@ public T ifCondition(Expression expression) {
398424

399425
/**
400426
* Define a conditional transformation
427+
*
401428
* @param condition a condition
402429
* @return the transformation for chaining
403430
*/
@@ -434,6 +461,7 @@ public T endIf() {
434461

435462
/**
436463
* fps (frames per second) parameter for video
464+
*
437465
* @param value Either a single value int or float or a range in the format <code>&lt;start&gt;[-&lt;end&gt;]</code>. <br>
438466
* For example, <code>23-29.7</code>
439467
* @return the transformation for chaining
@@ -444,6 +472,7 @@ public T fps(String value) {
444472

445473
/**
446474
* fps (frames per second) parameter for video
475+
*
447476
* @param value the desired fps
448477
* @return the transformation for chaining
449478
*/
@@ -453,14 +482,15 @@ public T fps(double value) {
453482

454483
/**
455484
* fps (frames per second) parameter for video
485+
*
456486
* @param value the desired fps
457487
* @return the transformation for chaining
458488
*/
459489
public T fps(int value) {
460490
return param("fps", new Integer(value));
461491
}
462492

463-
public T streamingProfile(String value){
493+
public T streamingProfile(String value) {
464494
return param("streaming_profile", value);
465495
}
466496

@@ -515,7 +545,7 @@ public String toString() {
515545
public String generate(Iterable<Map> optionsList) {
516546
List<String> components = new ArrayList<String>();
517547
for (Map options : optionsList) {
518-
if(options.size() > 0){
548+
if (options.size() > 0) {
519549
components.add(generate(options));
520550
}
521551
}
@@ -549,12 +579,12 @@ public String generate(Map options) {
549579

550580
String background = (String) options.get("background");
551581
if (background != null) {
552-
background = background.replaceFirst("^#", "rgb:");
582+
background = replaceColorPrefix(background);
553583
}
554584

555585
String color = (String) options.get("color");
556586
if (color != null) {
557-
color = color.replaceFirst("^#", "rgb:");
587+
color = replaceColorPrefix(color);
558588
}
559589

560590
List transformations = ObjectUtils.asArray(options.get("transformation"));
@@ -600,66 +630,18 @@ public String generate(Map options) {
600630
String videoCodec = processVideoCodecParam(options.get("video_codec"));
601631
String dpr = ObjectUtils.asString(options.get("dpr"), null == defaultDPR ? null : defaultDPR.toString());
602632

603-
SortedMap<String, String> params = new TreeMap<String, String>();
604633

605-
params.put("a", Expression.normalize(angle));
606-
params.put("ar", Expression.normalize( options.get("aspect_ratio")));
607-
params.put("b", background);
608-
params.put("c", crop);
609-
params.put("co", color);
610-
params.put("dpr", Expression.normalize(dpr));
611-
params.put("du", duration);
612-
params.put("e", Expression.normalize( options.get("effect")));
613-
params.put("eo", endOffset);
614-
params.put("fl", flags);
615-
params.put("h", Expression.normalize(height));
616-
params.put("o", Expression.normalize( options.get("opacity")));
617-
params.put("q", Expression.normalize( options.get("quality")));
618-
params.put("r", Expression.normalize( options.get("radius")));
619-
params.put("so", startOffset);
620-
params.put("t", namedTransformation);
621-
params.put("vc", videoCodec);
622-
params.put("w", Expression.normalize(width));
623-
params.put("x", Expression.normalize( options.get("x")));
624-
params.put("y", Expression.normalize( options.get("y")));
625-
params.put("z", Expression.normalize( options.get("zoom")));
626-
627-
String[] simple_params = new String[]{
628-
"ac", "audio_codec",
629-
"af", "audio_frequency",
630-
"bo", "border",
631-
"br", "bit_rate",
632-
"cs", "color_space",
633-
"d", "default_image",
634-
"dl", "delay",
635-
"dn", "density",
636-
"f", "fetch_format",
637-
"fn", "custom_action",
638-
"fps", "fps",
639-
"g", "gravity",
640-
"l", "overlay",
641-
"p", "prefix",
642-
"pg", "page",
643-
"u", "underlay",
644-
"vs", "video_sampling",
645-
"sp", "streaming_profile",
646-
"ki", "keyframe_interval"
647-
};
648-
649-
for (int i = 0; i < simple_params.length; i += 2) {
650-
params.put(simple_params[i], ObjectUtils.asString(options.get(simple_params[i + 1])));
651-
}
652634
List<String> components = new ArrayList<String>();
653635

654636
String ifValue = (String) options.get("if");
655-
if(ifValue != null){
637+
if (ifValue != null) {
656638
components.add(0, "if_" + Expression.normalize(ifValue));
657639
}
658640

659641
SortedSet<String> varParams = new TreeSet<String>();
660-
for( Object k: options.keySet()) {
642+
for (Object k : options.keySet()) {
661643
String key = (String) k;
662-
if(key.matches(VAR_NAME_RE)) {
644+
if (StringUtils.isVariable(key)) {
663645
varParams.add(key + "_" + ObjectUtils.asString(options.get(k)));
664646
}
665647
}
@@ -673,6 +655,36 @@ public String generate(Map options) {
673655
components.add(variables);
674656
}
675657

658+
Map<String, String> params = new HashMap<>(64);
659+
660+
params.put("a", Expression.normalize(angle));
661+
params.put("ar", Expression.normalize(options.get("aspect_ratio")));
662+
params.put("b", background);
663+
params.put("c", crop);
664+
params.put("co", color);
665+
params.put("dpr", Expression.normalize(dpr));
666+
params.put("du", duration);
667+
params.put("e", Expression.normalize(options.get("effect")));
668+
params.put("eo", endOffset);
669+
params.put("fl", flags);
670+
params.put("h", Expression.normalize(height));
671+
params.put("o", Expression.normalize(options.get("opacity")));
672+
params.put("q", Expression.normalize(options.get("quality")));
673+
params.put("r", Expression.normalize(options.get("radius")));
674+
params.put("so", startOffset);
675+
params.put("t", namedTransformation);
676+
params.put("vc", videoCodec);
677+
params.put("w", Expression.normalize(width));
678+
params.put("x", Expression.normalize(options.get("x")));
679+
params.put("y", Expression.normalize(options.get("y")));
680+
params.put("z", Expression.normalize(options.get("zoom")));
681+
682+
for (int i = 0; i < SIMPLE_PARAMS.length; i += 2) {
683+
params.put(SIMPLE_PARAMS[i], ObjectUtils.asString(options.get(SIMPLE_PARAMS[i + 1])));
684+
}
685+
686+
params = new TreeMap<>(params);
687+
676688
for (Map.Entry<String, String> param : params.entrySet()) {
677689
if (StringUtils.isNotBlank(param.getValue())) {
678690
components.add(param.getKey() + "_" + param.getValue());
@@ -702,19 +714,24 @@ public String generate(Map options) {
702714
return StringUtils.join(transformations, "/");
703715
}
704716

717+
private String replaceColorPrefix(String color) {
718+
return StringUtils.replaceIfFirstChar(color, '#', "rgb:");
719+
}
720+
705721
private String processVar(Expression[] variables) {
706-
if(variables == null) {
722+
if (variables == null) {
707723
return null;
708724
}
709725
List<String> s = new ArrayList<String>(variables.length);
710-
for(Expression variable: variables) {
726+
for (Expression variable : variables) {
711727
s.add(variable.toString());
712728
}
713729
return StringUtils.join(s, ",");
714730
}
715731

716732
/**
717733
* Check if the value is a float >= 1
734+
*
718735
* @param value
719736
* @return true if the value is a float >= 1
720737
*/
@@ -825,7 +842,8 @@ private static String processVideoCodecParam(Object param) {
825842

826843
/**
827844
* Add a variable assignment. Each call to this method will add a new variable assignments, but the order of the assignments may change. To enforce a particular order, use {@link #variables(Expression...)}
828-
* @param name the name of the variable
845+
*
846+
* @param name the name of the variable
829847
* @param value the value to assign to the variable
830848
* @return this for chaining
831849
*/
@@ -835,10 +853,11 @@ public T variable(String name, Object value) {
835853

836854
/**
837855
* Add a sequence of variable assignments. The order of the assignments will be honored.
856+
*
838857
* @param variables variable expressions
839858
* @return this for chaining
840859
*/
841-
public T variables(Expression...variables) {
860+
public T variables(Expression... variables) {
842861
return param("variables", variables);
843862
}
844863

0 commit comments

Comments
 (0)