/*
* 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.cql3.statements;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.cassandra.db.Column;
import org.apache.cassandra.db.marshal.CompositeType;
import org.apache.cassandra.utils.Pair;
public class ColumnGroupMap
{
private final ByteBuffer[] fullPath;
private final Map<ByteBuffer, Value> map = new HashMap<ByteBuffer, Value>();
private ColumnGroupMap(ByteBuffer[] fullPath)
{
this.fullPath = fullPath;
}
private void add(ByteBuffer[] fullName, int idx, Column column)
{
ByteBuffer columnName = fullName[idx];
if (fullName.length == idx + 2)
{
// It's a collection
Value v = map.get(columnName);
if (v == null)
{
v = new Collection();
map.put(columnName, v);
}
assert v instanceof Collection;
((Collection)v).add(Pair.create(fullName[idx + 1], column));
}
else
{
assert !map.containsKey(columnName);
map.put(columnName, new Simple(column));
}
}
public ByteBuffer getKeyComponent(int pos)
{
return fullPath[pos];
}
public Column getSimple(ByteBuffer key)
{
Value v = map.get(key);
if (v == null)
return null;
assert v instanceof Simple;
return ((Simple)v).column;
}
public List<Pair<ByteBuffer, Column>> getCollection(ByteBuffer key)
{
Value v = map.get(key);
if (v == null)
return null;
assert v instanceof Collection;
return (List<Pair<ByteBuffer, Column>>)v;
}
private interface Value {};
private static class Simple implements Value
{
public final Column column;
Simple(Column column)
{
this.column = column;
}
}
private static class Collection extends ArrayList<Pair<ByteBuffer, Column>> implements Value {}
public static class Builder
{
private final CompositeType composite;
private final int idx;
private final long now;
private ByteBuffer[] previous;
private final List<ColumnGroupMap> groups = new ArrayList<ColumnGroupMap>();
private ColumnGroupMap currentGroup;
public Builder(CompositeType composite, boolean hasCollections, long now)
{
this.composite = composite;
this.idx = composite.types.size() - (hasCollections ? 2 : 1);
this.now = now;
}
public void add(Column c)
{
if (c.isMarkedForDelete(now))
return;
ByteBuffer[] current = composite.split(c.name());
if (currentGroup == null)
{
currentGroup = new ColumnGroupMap(current);
currentGroup.add(current, idx, c);
previous = current;
return;
}
if (!isSameGroup(current))
{
groups.add(currentGroup);
currentGroup = new ColumnGroupMap(current);
}
currentGroup.add(current, idx, c);
previous = current;
}
/**
* For sparse composite, returns wheter the column belong to the same
* cqlRow than the previously added, based on the full list of component
* in the name.
* Two columns do belong together if they differ only by the last
* component.
*/
private boolean isSameGroup(ByteBuffer[] c)
{
for (int i = 0; i < idx; i++)
{
if (!c[i].equals(previous[i]))
return false;
}
return true;
}
public List<ColumnGroupMap> groups()
{
if (currentGroup != null)
{
groups.add(currentGroup);
currentGroup = null;
}
return groups;
}
}
}