All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.scudata.dm.cursor.MergeCursor Maven / Gradle / Ivy

Go to download

SPL(Structured Process Language) A programming language specially for structured data computing.

There is a newer version: 20241126
Show newest version
package com.scudata.dm.cursor;

import java.util.ArrayList;

import com.scudata.dm.BaseRecord;
import com.scudata.dm.Context;
import com.scudata.dm.DataStruct;
import com.scudata.dm.Sequence;
import com.scudata.dm.op.Operable;
import com.scudata.dm.op.Operation;
import com.scudata.expression.Expression;
import com.scudata.expression.Function;
import com.scudata.util.LoserTree;
import com.scudata.util.LoserTreeNode_CS;
import com.scudata.util.LoserTreeNode_CS1;
import com.scudata.util.Variant;

/**
 * ???ṹ?Ķ???α???????鲢?????γɵ??α?
 * CS.mergex(xi,??)
 * @author RunQian
 *
 */
public class MergeCursor extends ICursor {
	private ICursor []cursors; // ?α????????Ѿ????鲢?ֶ?????????
	private int []fields; // ?鲢?ֶ?
	private boolean isNullMin = true; // null?Ƿ???Сֵ
	
	private LoserTree loserTree; // ÿһ·?α???Ϊ???Ľڵ㰴?鲢?ֶ?ֵ???ɰ?????
	
	// һ???????????α???????Ĵ???
	private Sequence []tables;	// ???ݻ??????????ڻ???????α?
	private int []seqs;	// ??ǰ???????????ڸ??Ի???????????
	private int groupFieldCount; // ?????ֶ???
	private Sequence resultCache; // ??????
	private boolean isEnd = false; // ?Ƿ?ȡ?????
	private boolean isGroupOne; // ÿ???Ƿ?ֻȡһ??
	
	private boolean doGroupOpt = false; // ?Ƿ?Ժ????ķ??????????Ż?
	
	/**
	 * ??????Ч?鲢?α?
	 * @param cursors ?α?????
	 * @param fields ?????ֶ?????
	 * @param opt ѡ??
	 * @param ctx ??????????
	 */
	public MergeCursor(ICursor []cursors, int []fields, String opt, Context ctx) {
		this.cursors = cursors;
		this.fields = fields;
		this.ctx = ctx;
		dataStruct = cursors[0].getDataStruct();
		
		if (opt != null) {
			if (opt.indexOf('g') !=-1) {
				doGroupOpt = true;
			}
			
			if (opt.indexOf('0') != -1) {
				isNullMin = false;
			}
		}
	}
	
	/**
	 * ȡ?ֶ??α????ʼֵ??????зֶ??ֶ??򷵻طֶ??ֶε?ֵ??û???򷵻?ά?ֶε?ֵ
	 * @return ?ֶ??α???????¼?ķֶ??ֶε?ֵ???????ǰ????Ϊ0?򷵻?null
	 */
	public Object[] getSegmentStartValues(String option) {
		return cursors[0].getSegmentStartValues(option);
	}
	
	/**
	 * ???????????????
	 * @param function ??Ӧ?ĺ???
	 * @param exps ???????ʽ????
	 * @param opt ѡ??
	 * @param ctx ??????????
	 * @return Operable
	 */
	public Operable group(Function function, Expression []exps, String opt, Context ctx) {
		// ????Ѿ????????????򲻽????Ż?
		if (!doGroupOpt || (opList != null && opList.size() > 0)) {
			return super.group(function, exps, opt, ctx);
		}
		
		// ????????ֶ??ǹ鲢?ֶε?ǰ?벿????ѷ???鲢ͬʱ????
		int groupFieldCount = exps.length;
		if (groupFieldCount <= fields.length) {
			DataStruct ds = cursors[0].dataStruct;
			if (ds == null) {
				return super.group(function, exps, opt, ctx);
			}
			
			for (int i = 0; i < groupFieldCount; ++i) {
				int findex = exps[i].getFieldIndex(ds);
				if (findex != fields[i]) {
					return super.group(function, exps, opt, ctx);
				}
			}
			
			if (fields.length > groupFieldCount) {
				int []tmp = new int[groupFieldCount];
				System.arraycopy(fields, 0, tmp, 0, groupFieldCount);
				fields = tmp;
			}
			
			//groupOption = opt;
			this.groupFieldCount = groupFieldCount;
			isGroupOne = opt != null && opt.indexOf('1') != -1;
			return this;
		} else {
			return super.group(function, exps, opt, ctx);
		}
	}
	
	// ???м???ʱ??Ҫ?ı???????
	// ?̳???????õ??˱???ʽ????Ҫ?????????????½???????ʽ
	public void resetContext(Context ctx) {
		if (this.ctx != ctx) {
			for (ICursor cursor : cursors) {
				cursor.resetContext(ctx);
			}

			super.resetContext(ctx);
		}
	}
	/**
	 * ???????α?Ļ?????????????????????????ֱ?ӷ??ء?
	 */
	private void init() {
		if (groupFieldCount < 1) {
			if (loserTree != null) {
				return;
			}
			
			int count = cursors.length;
			if (fields.length == 1) {
				LoserTreeNode_CS1 []nodes = new LoserTreeNode_CS1[count];
				for (int i = 0; i < count; ++i) {
					nodes[i] = new LoserTreeNode_CS1(cursors[i], fields[0], isNullMin);
				}
				
				loserTree = new LoserTree(nodes);
			} else {
				LoserTreeNode_CS []nodes = new LoserTreeNode_CS[count];
				for (int i = 0; i < count; ++i) {
					nodes[i] = new LoserTreeNode_CS(cursors[i], fields, isNullMin);
				}
				
				loserTree = new LoserTree(nodes);
			}
		} else {
			if (tables != null) {
				return;
			}
	
			int tcount = cursors.length;
			tables = new Sequence[tcount];
			seqs = new int[tcount];
			isEnd = true;
			
			for (int i = 0; i < tcount; ++i) {
				Sequence table = cursors[i].fuzzyFetch(FETCHCOUNT_M);
				if (table != null && table.length() > 0) {
					tables[i] = table;
					seqs[i] = 1;
					isEnd = false;
				}
			}
		}
	}
	
	private void getGroupData(int path, Sequence result) {
		Sequence table = tables[path];
		int len = table.length();
		int seq = seqs[path];
		
		int []mergeFields = this.fields;
		int mergeFieldCount = mergeFields.length;
		
		if (mergeFieldCount == 1) {
			int field = mergeFields[0];
			BaseRecord r = (BaseRecord)table.getMem(seq);
			result.add(r);
			Object value = r.getNormalFieldValue(field);
			
			for (int i = seq + 1; i <= len; ++i) {
				r = (BaseRecord)table.getMem(i);
				if (Variant.isEquals(value, r.getNormalFieldValue(field))) {
					result.add(r);
				} else {
					seqs[path] = i;
					return;
				}
			}
			
			table = cursors[path].fuzzyFetch(FETCHCOUNT_M);
			if (table != null && table.length() > 0) {
				tables[path] = table;
				seqs[path] = 1;
				r = (BaseRecord)table.getMem(1);
				
				if (Variant.isEquals(value, r.getNormalFieldValue(field))) {
					getGroupData(path, result);
				}
			} else {
				tables[path] = null;
				seqs[path] = 0;
			}
		} else {
			BaseRecord r1 = (BaseRecord)table.getMem(seq);
			result.add(r1);
			
			for (int i = seq + 1; i <= len; ++i) {
				BaseRecord r = (BaseRecord)table.getMem(i);
				if (r1.isEquals(r, mergeFields)) {
					result.add(r);
				} else {
					seqs[path] = i;
					return;
				}
			}
						
			table = cursors[path].fuzzyFetch(FETCHCOUNT_M);
			if (table != null && table.length() > 0) {
				tables[path] = table;
				seqs[path] = 1;
				BaseRecord r = (BaseRecord)table.getMem(1);
				
				if (r1.isEquals(r, mergeFields)) {
					getGroupData(path, result);
				}
			} else {
				tables[path] = null;
				seqs[path] = 0;
			}
		}
	}
	
	// ?ݹ??ȡ????·?ķ???ֵ??ͬ???飬??????ֵ??С????
	private void fetchGroups(int path, Sequence group) {
		int nextPath = path + 1;
		if (group == null) {
			group = new Sequence();
			getGroupData(path, group);
			
			if (nextPath < seqs.length) {
				fetchGroups(nextPath, group);
			}
			
			if (isGroupOne) {
				resultCache.add(group.getMem(1));
			} else {
				resultCache.add(group);
			}
			
			return;
		}
		
		while (seqs[path] > 0) {
			BaseRecord r1 = (BaseRecord)group.getMem(1);
			BaseRecord r2 = (BaseRecord)tables[path].getMem(seqs[path]);
			
			// ?ȽϷ????ֶ?ֵ?Ƿ????
			int cmp = r2.compare(r1, fields);
			if (cmp == 0) {
				getGroupData(path, group);
				break;
			} else if (cmp > 0) {
				break;
			} else {
				Sequence newGroup = new Sequence();
				getGroupData(path, newGroup);
				
				if (nextPath < seqs.length) {
					fetchGroups(nextPath, newGroup);
				}
				
				if (isGroupOne) {
					resultCache.add(newGroup.getMem(1));
				} else {
					resultCache.add(newGroup);
				}
			}
		}
		
		if (nextPath < seqs.length) {
			fetchGroups(nextPath, group);
		}
	}
	
	private void fetchGroupsToCache(int n) {
		int pathCount = seqs.length;
		if (resultCache == null) {
			int size;
			if (n > FETCHCOUNT && n < MAXSIZE) {
				size = n;
			} else {
				size = FETCHCOUNT;
			}
			
			resultCache = new Sequence(size);
		}
		
		Next:
		while (resultCache.length() < n) {
			for (int i = 0; i < pathCount; ++i) {
				if (seqs[i] > 0) {
					fetchGroups(i, null);
					continue Next;
				}
			}
			
			isEnd = true;
			break;
		}
	}
	
	/**
	 * ģ??ȡ??¼?????صļ?¼?????Բ??????????????ͬ
	 * @param n Ҫȡ?ļ?¼??
	 * @return Sequence
	 */
	protected Sequence fuzzyGet(int n) {
		if (n < 1) {
			return null;
		} else if (isEnd) {
			Sequence result = resultCache;
			resultCache = null;
			return result;
		}

		init();
		
		if (groupFieldCount > 0) {
			fetchGroupsToCache(n);
			if (resultCache == null || resultCache.length() == 0) {
				return null;
			} else {
				Sequence result = resultCache;
				resultCache = null;
				return result;
			}
		} else {
			LoserTree loserTree = this.loserTree;
			Sequence table;
			if (n > INITSIZE) {
				table = new Sequence(INITSIZE);
			} else {
				table = new Sequence(n);
			}

			// ѭ??ȡ??????仺??????ѭ???????жԸ?·?α??ȡ???????????鲢??
			for (int i = 0; i < n && loserTree.hasNext(); ++i) {
				table.add(loserTree.pop());
			}
			
			if (table.length() < n) {
				isEnd = true;
			}

			if (table.length() > 0) {
				return table;
			} else {
				return null;
			}
		}
	}
	
	/**
	 * ??ȡָ???????????ݷ???
	 * @param n ????
	 * @return Sequence
	 */
	protected Sequence get(int n) {
		Sequence result = fuzzyGet(n);
		
		if (result == null) {
			return null;
		} else if (result.length() > n) {
			resultCache = result.split(n + 1);
		}

		return result;
	}

	private Sequence fuzzyGet() {
		if (isEnd) {
			Sequence result = resultCache;
			resultCache = null;
			return result;
		}

		init();
		
		int pathCount = seqs.length;
		if (resultCache == null) {
			resultCache = new Sequence(32);
		}
		
		int q = 1;
		int totalCount = 0;
		
		Next:
		while (totalCount < ICursor.FETCHCOUNT) {
			for (int i = 0; i < pathCount; ++i) {
				if (seqs[i] > 0) {
					fetchGroups(i, null);
					int len = resultCache.length();
					for (; q <= len; ++q) {
						Sequence group = (Sequence)resultCache.getMem(q);
						totalCount += group.length();
					}
					
					continue Next;
				}
			}
			
			isEnd = true;
			break;
		}
		
		if (resultCache.length() == 0) {
			return null;
		} else {
			Sequence result = resultCache;
			resultCache = null;
			return result;
		}
	}

	/**
	 * ???ػ??෽??????????????ʱ??ȡ?ļ?¼????ȡ̫???????׵????ڴ????
	 * @return Sequence
	 */
	public Sequence fetch() {
		ArrayList opList = this.opList;
		if (groupFieldCount > 0 && opList != null) {
			Sequence result = cache;
			cache = null;

			while (true) {
				Sequence cur = fuzzyGet();
				if (cur == null) {
					Sequence tmp = finish(opList, ctx);
					if (tmp != null) {
						if (result == null) {
							result = tmp;
						} else {
							result = append(result, tmp);
						}
					}
					
					close();
					return result;
				} else {
					cur = doOperation(cur, opList, ctx);
					if (result == null) {
						result = cur;
					} else if (cur != null) {
						result = append(result, cur);
					}
				}
			}
		} else {
			return fetch(MAXSIZE);
		}
	}
	
	/**
	 * ???ػ??෽??????????????ʱ??ȡ?ļ?¼????ȡ̫???????׵????ڴ????
	 * @param n ????????????Բ???ȷ
	 * @return Sequence
	 */
	public Sequence fuzzyFetch(int n) {
		if (cache != null) {
			Sequence result = cache;
			cache = null;
			return result;
		} else if (groupFieldCount > 0 && opList != null) {
			Sequence cur = fuzzyGet();
			if (cur == null) {
				cur = finish(opList, ctx);
				close();
				
				if (cur != null && cur.length() > 0) {
					return cur;
				} else {
					return null;
				}
			} else {
				return doOperation(cur, opList, ctx);
			}
		} else {
			Sequence result = null;
			ArrayList opList = this.opList;
			
			do {
				Sequence cur = fuzzyGet(n);
				if (cur != null) {
					if (opList != null) {
						cur = doOperation(cur, opList, ctx);
						if (result == null) {
							result = cur;
						} else if (cur != null) {
							result = append(result, cur);
						}
					} else {
						if (result == null) {
							result = cur;
						} else {
							result = append(result, cur);
						}
					}
				} else {
					if (opList != null) {
						Sequence tmp = finish(opList, ctx);
						if (tmp != null) {
							if (result == null) {
								result = tmp;
							} else {
								result = append(result, tmp);
							}
						}
					}

					close();
					return result;
				}
			} while (result == null || result.length() < n);
			
			return result;
		}
	}
	
	/**
	 * ????ָ????????????
	 * @param n ????
	 * @return long ʵ????????????
	 */
	protected long skipOver(long n) {
		if (n == MAXSKIPSIZE && groupFieldCount < 1 && loserTree == null && !isEnd) {
			// ???????в?ʵ?????鲢
			long count = 0;
			for (ICursor cs : cursors) {
				if (cs != null) {
					count += cs.skip();
				}
			}
			
			isEnd = true;
			return count;
		}
		
		if (isEnd) {
			if (resultCache == null) {
				return 0;
			}

			int count = resultCache.length();
			if (count <= n) {
				resultCache = null;
				return count;
			} else {
				resultCache = resultCache.split((int)(n - count) + 1);
				return n;
			}
		}
		
		init();
		
		if (groupFieldCount > 0) {
			long count = 0;
			while (count < n) {
				Sequence seq = fuzzyGet(FETCHCOUNT);
				if (seq == null) {
					break;
				}
				
				int len = seq.length();
				if (count + len > n) {
					resultCache = seq.split((int)(n - count) + 1);
					return n;
				}
			}
			
			return count;
		} else {
			LoserTree loserTree = this.loserTree;
			if (loserTree == null || n < 1) return 0;
			
			long i = 0;
			for (; i < n && loserTree.hasNext(); ++i) {
				loserTree.pop();
			}
	
			if (i < n) {
				isEnd = true;
			}
			
			return i;
		}
	}

	/**
	 * ?ر??α?
	 */
	public synchronized void close() {
		super.close();
		if (cursors != null) {
			for (int i = 0, count = cursors.length; i < count; ++i) {
				cursors[i].close();
			}

			loserTree = null;
			tables = null;
			seqs = null;
			resultCache = null;
			isEnd = true;
		}
	}
	
	/**
	 * ?????α?
	 * @return ?????Ƿ?ɹ???true???α???Դ?ͷ????ȡ????false???????Դ?ͷ????ȡ??
	 */
	public boolean reset() {
		close();
		
		ICursor []cursors = this.cursors;
		int count = cursors.length;
		for (int i = 0; i < count; ++i) {
			if (!cursors[i].reset()) {
				return false;
			}
		}
		
		isEnd = false;
		return true;
	}
	
	/**
	 * ȡ?????ֶ???
	 * @return ?ֶ???????
	 */
	public String[] getSortFields() {
		return cursors[0].getSortFields();
	}
	
	public ICursor[] getCursors() {
		return cursors;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy