| /******************************************************************************* |
| * Copyright (c) 2015, 2016 Google, Inc and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Stefan Xenos (Google) - Initial implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.core.nd.java; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.eclipse.jdt.internal.core.nd.Nd; |
| import org.eclipse.jdt.internal.core.nd.db.Database; |
| import org.eclipse.jdt.internal.core.nd.db.IndexException; |
| |
| public abstract class TagTreeReader { |
| public static final int[] UNUSED_RESULT = new int[1]; |
| |
| public static abstract class TagHandler<T> { |
| abstract public T read(Nd nd, long address, TagTreeReader reader, int[] bytesRead); |
| abstract public void write(Nd nd, long address, TagTreeReader reader, T toWrite, int[] bytesWritten); |
| abstract public int getSize(Nd nd, T object, TagTreeReader reader); |
| public void destruct(Nd nd, long address, TagTreeReader reader) { |
| // Nothing to do by default |
| } |
| } |
| |
| public static abstract class FixedSizeTagHandler<T> extends TagHandler<T> { |
| protected abstract T read(Nd nd, long address); |
| protected abstract void write(Nd nd, long address, T value); |
| protected abstract int getSize(); |
| protected void destruct(Nd nd, long address) { |
| // Nothing to do by default |
| } |
| |
| public final T read(Nd nd, long address, TagTreeReader reader, int[] bytesRead) { |
| bytesRead[0] = getSize(); |
| return read(nd, address); |
| } |
| |
| @Override |
| public final void write(Nd nd, long address, TagTreeReader reader, T value, int[] bytesWritten) { |
| bytesWritten[0] = getSize(); |
| write(nd, address, value); |
| } |
| |
| @Override |
| public final int getSize(Nd nd, T object, TagTreeReader reader) { |
| return getSize(); |
| } |
| |
| @Override |
| public final void destruct(Nd nd, long address, TagTreeReader reader) { |
| destruct(nd, address); |
| } |
| } |
| |
| private TagHandler<?> readers[] = new TagHandler[256]; |
| private Map<TagHandler<?>, Integer> values = new HashMap<>(); |
| |
| public final void add(byte key, TagHandler<?> reader) { |
| this.readers[key] = reader; |
| this.values.put(reader, (int) key); |
| } |
| |
| public final Object read(Nd nd, long address) { |
| return read(nd, address, UNUSED_RESULT); |
| } |
| |
| public final Object read(Nd nd, long address, int[] bytesRead) { |
| long readAddress = address; |
| Database db = nd.getDB(); |
| byte nextByte = db.getByte(address); |
| readAddress += Database.BYTE_SIZE; |
| TagHandler<?> reader = this.readers[nextByte]; |
| if (reader == null) { |
| throw new IndexException("Found unknown tag with value " + nextByte + " at address " + address); //$NON-NLS-1$//$NON-NLS-2$ |
| } |
| |
| return reader.read(nd, readAddress, this, bytesRead); |
| } |
| |
| protected abstract byte getKeyFor(Object toWrite); |
| |
| public final void write(Nd nd, long address, Object toWrite) { |
| write(nd, address, toWrite, UNUSED_RESULT); |
| } |
| |
| @SuppressWarnings("unchecked") |
| public final void write(Nd nd, long address, Object toWrite, int[] bytesWritten) { |
| byte key = getKeyFor(toWrite); |
| |
| @SuppressWarnings("rawtypes") |
| TagHandler handler = this.readers[key]; |
| |
| if (handler == null) { |
| throw new IndexException("Invalid key " + key + " returned from getKeyFor(...)"); //$NON-NLS-1$//$NON-NLS-2$ |
| } |
| |
| handler.write(nd, address, this, toWrite, bytesWritten); |
| } |
| |
| public final void destruct(Nd nd, long address) { |
| Database db = nd.getDB(); |
| long readAddress = address; |
| byte nextByte = db.getByte(readAddress); |
| readAddress += Database.BYTE_SIZE; |
| |
| TagHandler<?> handler = this.readers[nextByte]; |
| if (handler == null) { |
| throw new IndexException("Found unknown tag with value " + nextByte + " at address " + address); //$NON-NLS-1$//$NON-NLS-2$ |
| } |
| |
| handler.destruct(nd, readAddress, this); |
| } |
| |
| @SuppressWarnings("unchecked") |
| public final int getSize(Nd nd, Object toMeasure) { |
| byte key = getKeyFor(toMeasure); |
| |
| @SuppressWarnings("rawtypes") |
| TagHandler handler = this.readers[key]; |
| if (handler == null) { |
| throw new IndexException("Attempted to get size of object " + toMeasure.toString() + " with unknown key " //$NON-NLS-1$//$NON-NLS-2$ |
| + key); |
| } |
| |
| return handler.getSize(nd, toMeasure, this); |
| } |
| } |