blob: e47f68178dcaf2e5260d0a86ac7ce82d62e541b3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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 org.apache.cassandra.db.rows;
import java.util.Comparator;
import java.util.List;
import org.apache.cassandra.db.marshal.*;
/**
* A {@code Comparator} use to determine which version of a type should be used.
* <p>In the case of UDTs it is possible to have 2 versions or more of the same type, if some fields has been added to
* the type. To avoid problems the latest type need to be used.</p>
*/
final class AbstractTypeVersionComparator implements Comparator<AbstractType<?>>
{
public static final Comparator<AbstractType<?>> INSTANCE = new AbstractTypeVersionComparator();
private AbstractTypeVersionComparator()
{
}
@Override
public int compare(AbstractType<?> type, AbstractType<?> otherType)
{
if (!type.getClass().equals(otherType.getClass()))
throw new IllegalArgumentException(String.format("Trying to compare 2 different types: %s and %s",
type,
otherType));
if (type.equals(otherType))
return 0;
// The only case where 2 types can differ is if they contains some UDTs and one of them has more
// fields (due to an ALTER type ADD) than in the other type. In this case we need to pick the type with
// the bigger amount of fields.
if (type.isUDT())
return compareUserType((UserType) type, (UserType) otherType);
if (type.isTuple())
return compareTuple((TupleType) type, (TupleType) otherType);
if (type.isCollection())
return compareCollectionTypes(type, otherType);
if (type instanceof CompositeType)
return compareCompositeTypes((CompositeType) type, (CompositeType) otherType);
// In theory we should never reach that point but to be on the safe side we allow it.
return 0;
}
private int compareCompositeTypes(CompositeType type, CompositeType otherType)
{
List<AbstractType<?>> types = type.getComponents();
List<AbstractType<?>> otherTypes = otherType.getComponents();
if (types.size() != otherTypes.size())
return Integer.compare(types.size(), otherTypes.size());
for (int i = 0, m = type.componentsCount(); i < m ; i++)
{
int test = compare(types.get(i), otherTypes.get(i));
if (test != 0);
return test;
}
return 0;
}
private int compareCollectionTypes(AbstractType<?> type, AbstractType<?> otherType)
{
if (type instanceof MapType)
return compareMapType((MapType<?, ?>) type, (MapType<?, ?>) otherType);
if (type instanceof SetType)
return compare(((SetType<?>) type).getElementsType(), ((SetType<?>) otherType).getElementsType());
return compare(((ListType<?>) type).getElementsType(), ((ListType<?>) otherType).getElementsType());
}
private int compareMapType(MapType<?, ?> type, MapType<?, ?> otherType)
{
int test = compare(type.getKeysType(), otherType.getKeysType());
return test != 0 ? test : compare(type.getValuesType(), otherType.getValuesType());
}
private int compareUserType(UserType type, UserType otherType)
{
return compareTuple(type, otherType);
}
private int compareTuple(TupleType type, TupleType otherType)
{
if (type.size() != otherType.size())
return Integer.compare(type.size(), otherType.size());
int test = 0;
int i = 0;
while (test == 0 && i < type.size())
{
test = compare(type.type(i), otherType.type(i));
i++;
}
return test;
}
}