001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2011-2011 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.calc.impl; 011 012import mondrian.calc.*; 013import mondrian.olap.Evaluator; 014import mondrian.olap.Member; 015 016import java.util.*; 017 018/** 019 * Implementation of {@link TupleList} where the tuples are unary (each tuple 020 * consists of just one {@link Member}). 021 * 022 * <p>It is implemented as a straightforward wrapper on a backing list. You 023 * can provide the backing list explicitly using the 024 * {@link #UnaryTupleList(java.util.List)} constructor, and you can access the 025 * backing list by calling {@link #slice}(0). 026 * 027 * @author jhyde 028*/ 029public class UnaryTupleList 030 extends AbstractList<List<Member>> 031 implements TupleList 032{ 033 final List<Member> list; 034 035 /** 036 * Creates an empty UnaryTupleList. 037 */ 038 public UnaryTupleList() { 039 this(new ArrayList<Member>()); 040 } 041 042 /** 043 * Creates a UnaryTupleList with a given backing list. 044 * 045 * @param list Backing list 046 */ 047 public UnaryTupleList(List<Member> list) { 048 this.list = list; 049 } 050 051 public Member get(int slice, int index) { 052 assert slice == 0; 053 return list.get(index); 054 } 055 056 @Override 057 public List<Member> get(int index) { 058 return Collections.singletonList(list.get(index)); 059 } 060 061 @Override 062 public void add(int index, List<Member> element) { 063 list.add(index, element.get(0)); 064 } 065 066 @Override 067 public boolean add(List<Member> element) { 068 return list.add(element.get(0)); 069 } 070 071 public TupleList fix() { 072 return this; 073 } 074 075 @Override 076 public List<Member> set(int index, List<Member> element) { 077 final Member member = list.set(index, element.get(0)); 078 return member == null 079 ? null 080 : Collections.singletonList(member); 081 } 082 083 @Override 084 public List<Member> remove(int index) { 085 final Member member = list.remove(index); 086 return member == null 087 ? null 088 : Collections.singletonList(member); 089 } 090 091 @Override 092 public void clear() { 093 list.clear(); 094 } 095 096 @Override 097 public int size() { 098 return list.size(); 099 } 100 101 public int getArity() { 102 return 1; 103 } 104 105 public List<Member> slice(int column) { 106 return list; 107 } 108 109 public TupleList cloneList(int capacity) { 110 return new UnaryTupleList( 111 capacity < 0 112 ? new ArrayList<Member>(list) 113 : new ArrayList<Member>(capacity)); 114 } 115 116 public TupleCursor tupleCursor() { 117 return tupleIterator(); 118 } 119 120 public TupleIterator tupleIterator() { 121 return new UnaryIterator(); 122 } 123 124 public final Iterator<List<Member>> iterator() { 125 return tupleIterator(); 126 } 127 128 public TupleList project(int[] destIndices) { 129 // REVIEW: Is 0-ary valid? 130 assert destIndices.length == 1; 131 assert destIndices[0] == 0; 132 return this; 133 } 134 135 public void addTuple(Member... members) { 136 assert members.length == 1; 137 list.add(members[0]); 138 } 139 140 public void addCurrent(TupleCursor tupleIter) { 141 list.add(tupleIter.member(0)); 142 } 143 144 @Override 145 public TupleList subList(int fromIndex, int toIndex) { 146 return new ListTupleList( 147 1, 148 list.subList(fromIndex, toIndex)); 149 } 150 151 public TupleList withPositionCallback( 152 final PositionCallback positionCallback) 153 { 154 return new UnaryTupleList( 155 new AbstractList<Member>() { 156 public Member get(int index) { 157 positionCallback.onPosition(index); 158 return list.get(index); 159 } 160 161 public int size() { 162 return list.size(); 163 } 164 165 public Member set(int index, Member element) { 166 positionCallback.onPosition(index); 167 return list.set(index, element); 168 } 169 170 public void add(int index, Member element) { 171 positionCallback.onPosition(index); 172 list.add(index, element); 173 } 174 175 public Member remove(int index) { 176 positionCallback.onPosition(index); 177 return list.remove(index); 178 } 179 } 180 ); 181 } 182 183 /** 184 * Implementation of {@link mondrian.calc.TupleIterator} for {@link UnaryTupleList}. 185 * Based upon AbstractList.Itr, but with concurrent modification checking 186 * removed. 187 */ 188 private class UnaryIterator implements TupleIterator { 189 /** 190 * Index of element to be returned by subsequent call to next. 191 */ 192 int cursor = 0; 193 194 /** 195 * Index of element returned by most recent call to next or 196 * previous. Reset to -1 if this element is deleted by a call 197 * to remove. 198 */ 199 int lastRet = -1; 200 201 public boolean hasNext() { 202 return cursor != size(); 203 } 204 205 public List<Member> next() { 206 try { 207 List<Member> next = get(cursor); 208 lastRet = cursor++; 209 return next; 210 } catch (IndexOutOfBoundsException e) { 211 throw new NoSuchElementException(); 212 } 213 } 214 215 public void currentToArray(Member[] members, int offset) { 216 members[offset] = list.get(lastRet); 217 } 218 219 public boolean forward() { 220 if (cursor == size()) { 221 return false; 222 } 223 lastRet = cursor++; 224 return true; 225 } 226 227 public List<Member> current() { 228 return get(lastRet); 229 } 230 231 public int getArity() { 232 return 1; 233 } 234 235 public void remove() { 236 if (lastRet == -1) { 237 throw new IllegalStateException(); 238 } 239 try { 240 UnaryTupleList.this.remove(lastRet); 241 if (lastRet < cursor) { 242 cursor--; 243 } 244 lastRet = -1; 245 } catch (IndexOutOfBoundsException e) { 246 throw new ConcurrentModificationException(); 247 } 248 } 249 250 public void setContext(Evaluator evaluator) { 251 evaluator.setContext(list.get(lastRet)); 252 } 253 254 public Member member(int column) { 255 assert column == 0; 256 return list.get(lastRet); 257 } 258 } 259} 260 261// End UnaryTupleList.java