Skip to content

Commit

Permalink
Implement ListValue, MapValue and OptionalValue
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 584654587
  • Loading branch information
l46kok authored and copybara-github committed Nov 22, 2023
1 parent 7cd0d73 commit f645749
Show file tree
Hide file tree
Showing 9 changed files with 1,124 additions and 0 deletions.
6 changes: 6 additions & 0 deletions common/src/main/java/dev/cel/common/values/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@ CEL_VALUES_SOURCES = [
"DoubleValue.java",
"DurationValue.java",
"EnumValue.java",
"ImmutableListValue.java",
"ImmutableMapValue.java",
"IntValue.java",
"ListValue.java",
"MapValue.java",
"NullValue.java",
"OptionalValue.java",
"StringValue.java",
"StructValue.java",
"TimestampValue.java",
Expand Down Expand Up @@ -46,6 +51,7 @@ java_library(
"//common/types:type_providers",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
"@maven//:org_jspecify_jspecify",
],
)

Expand Down
134 changes: 134 additions & 0 deletions common/src/main/java/dev/cel/common/values/ImmutableListValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dev.cel.common.values;

import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.Immutable;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

/**
* ImmutableListValue is a representation of an immutable list containing zero or more {@link
* CelValue}.
*/
@Immutable
@SuppressWarnings(
"PreferredInterfaceType") // We intentionally store List type to avoid copying on instantiation
public final class ImmutableListValue<E extends CelValue> extends ListValue<E> {

@SuppressWarnings("Immutable") // ListValue APIs prohibit mutation.
private final List<E> originalList;

@SuppressWarnings("Immutable") // The value is lazily populated only once via synchronization.
private volatile ImmutableList<E> cachedImmutableList = null;

public static <E extends CelValue> ImmutableListValue<E> create(List<E> value) {
return new ImmutableListValue<>(value);
}

private ImmutableListValue(List<E> originalList) {
this.originalList = ImmutableList.copyOf(originalList);
}

@Override
public ImmutableList<E> value() {
if (cachedImmutableList == null) {
synchronized (this) {
if (cachedImmutableList == null) {
cachedImmutableList = ImmutableList.copyOf(originalList);
}
}
}

return cachedImmutableList;
}

@Override
public int size() {
return originalList.size();
}

@Override
public boolean isEmpty() {
return originalList.isEmpty();
}

@Override
public boolean contains(Object o) {
return originalList.contains(o);
}

@Override
public Iterator<E> iterator() {
return originalList.iterator();
}

@Override
public Object[] toArray() {
return originalList.toArray();
}

@Override
public <T> T[] toArray(T[] a) {
return originalList.toArray(a);
}

@Override
public boolean containsAll(Collection<?> c) {
return originalList.containsAll(c);
}

@Override
public E get(int index) {
return originalList.get(index);
}

@Override
public int indexOf(Object o) {
return originalList.indexOf(o);
}

@Override
public int lastIndexOf(Object o) {
return originalList.lastIndexOf(o);
}

@Override
public ListIterator<E> listIterator() {
return originalList.listIterator();
}

@Override
public ListIterator<E> listIterator(int index) {
return originalList.listIterator(index);
}

@Override
public List<E> subList(int fromIndex, int toIndex) {
return originalList.subList(fromIndex, toIndex);
}

@Override
public int hashCode() {
return originalList.hashCode();
}

@Override
public boolean equals(Object obj) {
return originalList.equals(obj);
}
}
109 changes: 109 additions & 0 deletions common/src/main/java/dev/cel/common/values/ImmutableMapValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dev.cel.common.values;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.errorprone.annotations.Immutable;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

/**
* MapValue is an abstract representation of an immutable map containing {@link CelValue} as keys
* and values.
*/
@Immutable(containerOf = {"K", "V"})
@SuppressWarnings(
"PreferredInterfaceType") // We intentionally store List type to avoid copying on instantiation
public final class ImmutableMapValue<K extends CelValue, V extends CelValue>
extends MapValue<K, V> {

@SuppressWarnings("Immutable") // MapValue APIs prohibit mutation.
private final Map<K, V> originalMap;

@SuppressWarnings("Immutable") // The value is lazily populated only once via synchronization.
private volatile ImmutableMap<K, V> cachedImmutableMap = null;

public static <K extends CelValue, V extends CelValue> ImmutableMapValue<K, V> create(
Map<K, V> value) {
return new ImmutableMapValue<>(value);
}

private ImmutableMapValue(Map<K, V> originalMap) {
Preconditions.checkNotNull(originalMap);
this.originalMap = originalMap;
}

@Override
public ImmutableMap<K, V> value() {
if (cachedImmutableMap == null) {
synchronized (this) {
if (cachedImmutableMap == null) {
cachedImmutableMap = ImmutableMap.copyOf(originalMap);
}
}
}

return cachedImmutableMap;
}

@Override
public int size() {
return originalMap.size();
}

@Override
public boolean isEmpty() {
return originalMap.isEmpty();
}

@Override
public boolean containsKey(Object key) {
return originalMap.containsKey(key);
}

@Override
public boolean containsValue(Object val) {
return originalMap.containsValue(val);
}

@Override
public int hashCode() {
return originalMap.hashCode();
}

@Override
public boolean equals(Object obj) {
return originalMap.equals(obj);
}

// Note that the following three methods are produced from the immutable map to avoid key/value
// mutation.
@Override
public Set<K> keySet() {
return value().keySet();
}

@Override
public Collection<V> values() {
return value().values();
}

@Override
public Set<Entry<K, V>> entrySet() {
return value().entrySet();
}
}
Loading

0 comments on commit f645749

Please sign in to comment.