| 130 | } |
| 131 | |
| 132 | absl::StatusOr<Value> ListDistinct( |
| 133 | const ListValue& list, |
| 134 | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
| 135 | google::protobuf::MessageFactory* absl_nonnull message_factory, |
| 136 | google::protobuf::Arena* absl_nonnull arena) { |
| 137 | CEL_ASSIGN_OR_RETURN(size_t size, list.Size()); |
| 138 | // If the list is empty or has a single element, we can return it as is. |
| 139 | if (size < 2) { |
| 140 | return list; |
| 141 | } |
| 142 | |
| 143 | // We need a set to keep track of the seen values. |
| 144 | // |
| 145 | // By default, for unhashable types, this set is implemented as a vector of |
| 146 | // all the seen values, which means that we will perform O(n^2) comparisons |
| 147 | // between the values. |
| 148 | // |
| 149 | // For efficiency purposes, if the first element of the list is hashable, we |
| 150 | // will use a specialized implementation that is faster for homogeneous lists |
| 151 | // of hashable types. |
| 152 | // If the list is not homogeneous, we will fall back to the slow |
| 153 | // implementation. |
| 154 | // |
| 155 | // The total runtime cost is O(n) for homogeneous lists of hashable types, and |
| 156 | // O(n^2) for all other cases. |
| 157 | auto builder = NewListValueBuilder(arena); |
| 158 | CEL_ASSIGN_OR_RETURN(Value first, |
| 159 | list.Get(0, descriptor_pool, message_factory, arena)); |
| 160 | switch (first.kind()) { |
| 161 | case ValueKind::kInt: { |
| 162 | CEL_RETURN_IF_ERROR(ListDistinctHomogeneousHashableImpl<IntValue>( |
| 163 | list, descriptor_pool, message_factory, arena, builder.get())); |
| 164 | break; |
| 165 | } |
| 166 | case ValueKind::kUint: { |
| 167 | CEL_RETURN_IF_ERROR(ListDistinctHomogeneousHashableImpl<UintValue>( |
| 168 | list, descriptor_pool, message_factory, arena, builder.get())); |
| 169 | break; |
| 170 | } |
| 171 | case ValueKind::kBool: { |
| 172 | CEL_RETURN_IF_ERROR(ListDistinctHomogeneousHashableImpl<BoolValue>( |
| 173 | list, descriptor_pool, message_factory, arena, builder.get())); |
| 174 | break; |
| 175 | } |
| 176 | case ValueKind::kString: { |
| 177 | CEL_RETURN_IF_ERROR(ListDistinctHomogeneousHashableImpl<StringValue>( |
| 178 | list, descriptor_pool, message_factory, arena, builder.get())); |
| 179 | break; |
| 180 | } |
| 181 | default: { |
| 182 | CEL_RETURN_IF_ERROR(ListDistinctHeterogeneousImpl( |
| 183 | list, descriptor_pool, message_factory, arena, builder.get())); |
| 184 | break; |
| 185 | } |
| 186 | } |
| 187 | return std::move(*builder).Build(); |
| 188 | } |
| 189 |
nothing calls this directly
no test coverage detected