Skip to content

Commit

Permalink
Polish gh-4959 (#5692)
Browse files Browse the repository at this point in the history
  • Loading branch information
izeye authored Nov 20, 2024
1 parent 4f95a23 commit e074c11
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class KeyValuesMergeBenchmark {

static final KeyValues left = KeyValues.of("key", "value", "key2", "value2", "key6", "value6", "key7", "value7",
"key8", "value8", "keyA", "valueA", "keyC", "valueC", "keyE", "valueE", "keyF", "valueF", "keyG", "valueG",
"keyG", "valueG", "keyG", "valueG", "keyH", "valueH");
"keyH", "valueH");

static final KeyValues right = KeyValues.of("key", "value", "key1", "value1", "key2", "value2", "key3", "value3",
"key4", "value4", "key5", "value5", "keyA", "valueA", "keyB", "valueB", "keyD", "valueD");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
public class TagsMergeBenchmark {

static final Tags left = Tags.of("key", "value", "key2", "value2", "key6", "value6", "key7", "value7", "key8",
"value8", "keyA", "valueA", "keyC", "valueC", "keyE", "valueE", "keyF", "valueF", "keyG", "valueG", "keyG",
"valueG", "keyG", "valueG", "keyH", "valueH");
"value8", "keyA", "valueA", "keyC", "valueC", "keyE", "valueE", "keyF", "valueF", "keyG", "valueG", "keyH",
"valueH");

static final Tags right = Tags.of("key", "value", "key1", "value1", "key2", "value2", "key3", "value3", "key4",
"value4", "key5", "value5", "keyA", "valueA", "keyB", "valueB", "keyD", "valueD");
Expand Down
113 changes: 61 additions & 52 deletions micrometer-commons/src/main/java/io/micrometer/common/KeyValues.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,37 +36,39 @@
*/
public final class KeyValues implements Iterable<KeyValue> {

private static final KeyValues EMPTY = new KeyValues(new KeyValue[] {}, 0);
private static final KeyValue[] EMPTY_KEY_VALUE_ARRAY = new KeyValue[0];

private static final KeyValues EMPTY = new KeyValues(EMPTY_KEY_VALUE_ARRAY, 0);

/**
* A private array of {@code KeyValue} objects containing the sorted and deduplicated
* tags.
* An array of {@code KeyValue} objects containing the sorted and deduplicated
* key-values.
*/
private final KeyValue[] sortedSet;

/**
* The number of valid tags present in the {@link #sortedSet} array.
* The number of valid key-values present in the {@link #sortedSet} array.
*/
private final int length;

/**
* A private constructor that initializes a {@code KeyValues} object with a sorted set
* of keyvalues and its length.
* @param sortedSet an ordered set of unique keyvalues by key
* @param length the number of valid tags in the {@code sortedSet}
* A constructor that initializes a {@code KeyValues} object with a sorted set of
* key-values and its length.
* @param sortedSet an ordered set of unique key-values by key
* @param length the number of valid key-values in the {@code sortedSet}
*/
private KeyValues(KeyValue[] sortedSet, int length) {
this.sortedSet = sortedSet;
this.length = length;
}

/**
* Checks if the first {@code length} elements of the {@code keyvalues} array form an
* ordered set of keyvalues.
* @param keyValues an array of keyvalues.
* @param length the number of items to check.
* @return {@code true} if the first {@code length} items of {@code keyvalues} form an
* ordered set; otherwise {@code false}.
* Checks if the first {@code length} elements of the {@code keyValues} array form an
* ordered set of key-values.
* @param keyValues an array of key-values.
* @param length the number of elements to check.
* @return {@code true} if the first {@code length} elements of {@code keyValues} form
* an ordered set; otherwise {@code false}.
*/
private static boolean isSortedSet(KeyValue[] keyValues, int length) {
if (length > keyValues.length) {
Expand All @@ -82,12 +84,13 @@ private static boolean isSortedSet(KeyValue[] keyValues, int length) {
}

/**
* Constructs a {@code Tags} collection from the provided array of tags.
* @param keyValues an array of {@code Tag} objects, possibly unordered and/or
* Constructs a {@code KeyValues} collection from the provided array of key-values.
* @param keyValues an array of {@code KeyValue} objects, possibly unordered and/or
* containing duplicates.
* @return a {@code Tags} instance with a deduplicated and ordered set of tags.
* @return a {@code KeyValues} instance with a deduplicated and ordered set of
* key-values.
*/
private static KeyValues make(KeyValue[] keyValues) {
private static KeyValues toKeyValues(KeyValue[] keyValues) {
int len = keyValues.length;
if (!isSortedSet(keyValues, len)) {
Arrays.sort(keyValues);
Expand All @@ -97,10 +100,10 @@ private static KeyValues make(KeyValue[] keyValues) {
}

/**
* Removes duplicate tags from an ordered array of tags.
* @param keyValues an ordered array of {@code Tag} objects.
* @return the number of unique tags in the {@code tags} array after removing
* duplicates.
* Removes duplicate key-values from an ordered array of key-values.
* @param keyValues an ordered array of {@code KeyValue} objects.
* @return the number of unique key-values in the {@code keyValues} array after
* removing duplicates.
*/
private static int dedup(KeyValue[] keyValues) {
int n = keyValues.length;
Expand All @@ -121,49 +124,55 @@ private static int dedup(KeyValue[] keyValues) {
}

/**
* Constructs a {@code Tags} instance by merging two sets of tags in time proportional
* to the sum of their sizes.
* @param other the set of tags to merge with this one.
* @return a {@code Tags} instance with the merged sets of tags.
* Constructs a {@code KeyValues} instance by merging two sets of key-values in time
* proportional to the sum of their sizes.
* @param other the set of key-values to merge with this one.
* @return a {@code KeyValues} instance with the merged sets of key-values.
*/
private KeyValues merged(KeyValues other) {
private KeyValues merge(KeyValues other) {
if (other.length == 0) {
return this;
}
if (Objects.equals(this, other)) {
return this;
}
KeyValue[] sortedSet = new KeyValue[this.length + other.length];
int sortedIdx = 0, thisIdx = 0, otherIdx = 0;
while (thisIdx < this.length && otherIdx < other.length) {
int cmp = this.sortedSet[thisIdx].compareTo(other.sortedSet[otherIdx]);
int sortedIndex = 0;
int thisIndex = 0;
int otherIndex = 0;
while (thisIndex < this.length && otherIndex < other.length) {
KeyValue thisKeyValue = this.sortedSet[thisIndex];
KeyValue otherKeyValue = other.sortedSet[otherIndex];
int cmp = thisKeyValue.compareTo(otherKeyValue);
if (cmp > 0) {
sortedSet[sortedIdx] = other.sortedSet[otherIdx];
otherIdx++;
sortedSet[sortedIndex] = otherKeyValue;
otherIndex++;
}
else if (cmp < 0) {
sortedSet[sortedIdx] = this.sortedSet[thisIdx];
thisIdx++;
sortedSet[sortedIndex] = thisKeyValue;
thisIndex++;
}
else {
// In case of key conflict prefer tag from other set
sortedSet[sortedIdx] = other.sortedSet[otherIdx];
thisIdx++;
otherIdx++;
// In case of key conflict prefer key-value from other set
sortedSet[sortedIndex] = otherKeyValue;
thisIndex++;
otherIndex++;
}
sortedIdx++;
sortedIndex++;
}
int thisRemaining = this.length - thisIdx;
int thisRemaining = this.length - thisIndex;
if (thisRemaining > 0) {
System.arraycopy(this.sortedSet, thisIdx, sortedSet, sortedIdx, thisRemaining);
sortedIdx += thisRemaining;
System.arraycopy(this.sortedSet, thisIndex, sortedSet, sortedIndex, thisRemaining);
sortedIndex += thisRemaining;
}
int otherRemaining = other.length - otherIdx;
if (otherIdx < other.sortedSet.length) {
System.arraycopy(other.sortedSet, otherIdx, sortedSet, sortedIdx, otherRemaining);
sortedIdx += otherRemaining;
else {
int otherRemaining = other.length - otherIndex;
if (otherRemaining > 0) {
System.arraycopy(other.sortedSet, otherIndex, sortedSet, sortedIndex, otherRemaining);
sortedIndex += otherRemaining;
}
}
return new KeyValues(sortedSet, sortedIdx);
return new KeyValues(sortedSet, sortedIndex);
}

/**
Expand Down Expand Up @@ -200,7 +209,7 @@ public KeyValues and(@Nullable KeyValue... keyValues) {
if (blankVarargs(keyValues)) {
return this;
}
return and(make(keyValues));
return and(toKeyValues(keyValues));
}

/**
Expand Down Expand Up @@ -237,7 +246,7 @@ public KeyValues and(@Nullable Iterable<? extends KeyValue> keyValues) {
return KeyValues.of(keyValues);
}

return merged(KeyValues.of(keyValues));
return merge(KeyValues.of(keyValues));
}

@Override
Expand Down Expand Up @@ -362,10 +371,10 @@ else if (keyValues instanceof KeyValues) {
}
else if (keyValues instanceof Collection) {
Collection<? extends KeyValue> keyValuesCollection = (Collection<? extends KeyValue>) keyValues;
return make(keyValuesCollection.toArray(new KeyValue[0]));
return toKeyValues(keyValuesCollection.toArray(EMPTY_KEY_VALUE_ARRAY));
}
else {
return make(StreamSupport.stream(keyValues.spliterator(), false).toArray(KeyValue[]::new));
return toKeyValues(StreamSupport.stream(keyValues.spliterator(), false).toArray(KeyValue[]::new));
}
}

Expand Down Expand Up @@ -397,7 +406,7 @@ public static KeyValues of(@Nullable String... keyValues) {
for (int i = 0; i < keyValues.length; i += 2) {
keyValueArray[i / 2] = KeyValue.of(keyValues[i], keyValues[i + 1]);
}
return make(keyValueArray);
return toKeyValues(keyValueArray);
}

private static boolean blankVarargs(@Nullable Object[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@
*/
public final class Tags implements Iterable<Tag> {

private static final Tags EMPTY = new Tags(new Tag[] {}, 0);
private static final Tag[] EMPTY_TAG_ARRAY = new Tag[0];

private static final Tags EMPTY = new Tags(EMPTY_TAG_ARRAY, 0);

/**
* A private array of {@code Tag} objects containing the sorted and deduplicated tags.
* An array of {@code Tag} objects containing the sorted and deduplicated tags.
*/
private final Tag[] sortedSet;

Expand All @@ -47,8 +49,8 @@ public final class Tags implements Iterable<Tag> {
private final int length;

/**
* A private constructor that initializes a {@code Tags} object with a sorted set of
* tags and its length.
* A constructor that initializes a {@code Tags} object with a sorted set of tags and
* its length.
* @param sortedSet an ordered set of unique tags by key
* @param length the number of valid tags in the {@code sortedSet}
*/
Expand All @@ -61,8 +63,8 @@ private Tags(Tag[] sortedSet, int length) {
* Checks if the first {@code length} elements of the {@code tags} array form an
* ordered set of tags.
* @param tags an array of tags.
* @param length the number of items to check.
* @return {@code true} if the first {@code length} items of {@code tags} form an
* @param length the number of elements to check.
* @return {@code true} if the first {@code length} elements of {@code tags} form an
* ordered set; otherwise {@code false}.
*/
private static boolean isSortedSet(Tag[] tags, int length) {
Expand All @@ -84,7 +86,7 @@ private static boolean isSortedSet(Tag[] tags, int length) {
* duplicates.
* @return a {@code Tags} instance with a deduplicated and ordered set of tags.
*/
private static Tags make(Tag[] tags) {
private static Tags toTags(Tag[] tags) {
int len = tags.length;
if (!isSortedSet(tags, len)) {
Arrays.sort(tags);
Expand Down Expand Up @@ -123,44 +125,50 @@ private static int dedup(Tag[] tags) {
* @param other the set of tags to merge with this one.
* @return a {@code Tags} instance with the merged sets of tags.
*/
private Tags merged(Tags other) {
private Tags merge(Tags other) {
if (other.length == 0) {
return this;
}
if (Objects.equals(this, other)) {
return this;
}
Tag[] sortedSet = new Tag[this.length + other.length];
int sortedIdx = 0, thisIdx = 0, otherIdx = 0;
while (thisIdx < this.length && otherIdx < other.length) {
int cmp = this.sortedSet[thisIdx].compareTo(other.sortedSet[otherIdx]);
int sortedIndex = 0;
int thisIndex = 0;
int otherIndex = 0;
while (thisIndex < this.length && otherIndex < other.length) {
Tag thisTag = this.sortedSet[thisIndex];
Tag otherTag = other.sortedSet[otherIndex];
int cmp = thisTag.compareTo(otherTag);
if (cmp > 0) {
sortedSet[sortedIdx] = other.sortedSet[otherIdx];
otherIdx++;
sortedSet[sortedIndex] = otherTag;
otherIndex++;
}
else if (cmp < 0) {
sortedSet[sortedIdx] = this.sortedSet[thisIdx];
thisIdx++;
sortedSet[sortedIndex] = thisTag;
thisIndex++;
}
else {
// In case of key conflict prefer tag from other set
sortedSet[sortedIdx] = other.sortedSet[otherIdx];
thisIdx++;
otherIdx++;
sortedSet[sortedIndex] = otherTag;
thisIndex++;
otherIndex++;
}
sortedIdx++;
sortedIndex++;
}
int thisRemaining = this.length - thisIdx;
int thisRemaining = this.length - thisIndex;
if (thisRemaining > 0) {
System.arraycopy(this.sortedSet, thisIdx, sortedSet, sortedIdx, thisRemaining);
sortedIdx += thisRemaining;
System.arraycopy(this.sortedSet, thisIndex, sortedSet, sortedIndex, thisRemaining);
sortedIndex += thisRemaining;
}
int otherRemaining = other.length - otherIdx;
if (otherIdx < other.sortedSet.length) {
System.arraycopy(other.sortedSet, otherIdx, sortedSet, sortedIdx, otherRemaining);
sortedIdx += otherRemaining;
else {
int otherRemaining = other.length - otherIndex;
if (otherRemaining > 0) {
System.arraycopy(other.sortedSet, otherIndex, sortedSet, sortedIndex, otherRemaining);
sortedIndex += otherRemaining;
}
}
return new Tags(sortedSet, sortedIdx);
return new Tags(sortedSet, sortedIndex);
}

/**
Expand Down Expand Up @@ -197,7 +205,7 @@ public Tags and(@Nullable Tag... tags) {
if (blankVarargs(tags)) {
return this;
}
return and(make(tags));
return and(toTags(tags));
}

/**
Expand All @@ -214,7 +222,7 @@ public Tags and(@Nullable Iterable<? extends Tag> tags) {
if (this.length == 0) {
return Tags.of(tags);
}
return merged(Tags.of(tags));
return merge(Tags.of(tags));
}

@Override
Expand Down Expand Up @@ -323,10 +331,10 @@ else if (tags instanceof Tags) {
}
else if (tags instanceof Collection) {
Collection<? extends Tag> tagsCollection = (Collection<? extends Tag>) tags;
return make(tagsCollection.toArray(new Tag[0]));
return toTags(tagsCollection.toArray(EMPTY_TAG_ARRAY));
}
else {
return make(StreamSupport.stream(tags.spliterator(), false).toArray(Tag[]::new));
return toTags(StreamSupport.stream(tags.spliterator(), false).toArray(Tag[]::new));
}
}

Expand Down Expand Up @@ -358,7 +366,7 @@ public static Tags of(@Nullable String... keyValues) {
for (int i = 0; i < keyValues.length; i += 2) {
tags[i / 2] = Tag.of(keyValues[i], keyValues[i + 1]);
}
return make(tags);
return toTags(tags);
}

private static boolean blankVarargs(@Nullable Object[] args) {
Expand Down

0 comments on commit e074c11

Please sign in to comment.