1 /******************************************************************************* 2 * Copyright (c) 2015, 2016 Google, Inc and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * Stefan Xenos (Google) - Initial implementation 13 *******************************************************************************/ 14 package org.eclipse.jdt.internal.core.nd.java; 15 16 import java.util.HashMap; 17 import java.util.Map; 18 19 import org.eclipse.jdt.internal.core.nd.Nd; 20 import org.eclipse.jdt.internal.core.nd.db.Database; 21 import org.eclipse.jdt.internal.core.nd.db.IndexException; 22 23 public abstract class TagTreeReader { 24 public static final int[] UNUSED_RESULT = new int[1]; 25 26 public static abstract class TagHandler<T> { read(Nd nd, long address, TagTreeReader reader, int[] bytesRead)27 abstract public T read(Nd nd, long address, TagTreeReader reader, int[] bytesRead); write(Nd nd, long address, TagTreeReader reader, T toWrite, int[] bytesWritten)28 abstract public void write(Nd nd, long address, TagTreeReader reader, T toWrite, int[] bytesWritten); getSize(Nd nd, T object, TagTreeReader reader)29 abstract public int getSize(Nd nd, T object, TagTreeReader reader); destruct(Nd nd, long address, TagTreeReader reader)30 public void destruct(Nd nd, long address, TagTreeReader reader) { 31 // Nothing to do by default 32 } 33 } 34 35 public static abstract class FixedSizeTagHandler<T> extends TagHandler<T> { read(Nd nd, long address)36 protected abstract T read(Nd nd, long address); write(Nd nd, long address, T value)37 protected abstract void write(Nd nd, long address, T value); getSize()38 protected abstract int getSize(); destruct(Nd nd, long address)39 protected void destruct(Nd nd, long address) { 40 // Nothing to do by default 41 } 42 43 @Override read(Nd nd, long address, TagTreeReader reader, int[] bytesRead)44 public final T read(Nd nd, long address, TagTreeReader reader, int[] bytesRead) { 45 bytesRead[0] = getSize(); 46 return read(nd, address); 47 } 48 49 @Override write(Nd nd, long address, TagTreeReader reader, T value, int[] bytesWritten)50 public final void write(Nd nd, long address, TagTreeReader reader, T value, int[] bytesWritten) { 51 bytesWritten[0] = getSize(); 52 write(nd, address, value); 53 } 54 55 @Override getSize(Nd nd, T object, TagTreeReader reader)56 public final int getSize(Nd nd, T object, TagTreeReader reader) { 57 return getSize(); 58 } 59 60 @Override destruct(Nd nd, long address, TagTreeReader reader)61 public final void destruct(Nd nd, long address, TagTreeReader reader) { 62 destruct(nd, address); 63 } 64 } 65 66 private TagHandler<?> readers[] = new TagHandler[256]; 67 private Map<TagHandler<?>, Integer> values = new HashMap<>(); 68 add(byte key, TagHandler<?> reader)69 public final void add(byte key, TagHandler<?> reader) { 70 this.readers[key] = reader; 71 this.values.put(reader, (int) key); 72 } 73 read(Nd nd, long address)74 public final Object read(Nd nd, long address) { 75 return read(nd, address, UNUSED_RESULT); 76 } 77 read(Nd nd, long address, int[] bytesRead)78 public final Object read(Nd nd, long address, int[] bytesRead) { 79 long readAddress = address; 80 Database db = nd.getDB(); 81 byte nextByte = db.getByte(address); 82 readAddress += Database.BYTE_SIZE; 83 TagHandler<?> reader = this.readers[nextByte]; 84 if (reader == null) { 85 throw nd.describeProblem() 86 .addProblemAddress("tag", address, 1) //$NON-NLS-1$ 87 .build("Found unknown tag with value " + nextByte + " at address " + address); //$NON-NLS-1$//$NON-NLS-2$ 88 } 89 90 return reader.read(nd, readAddress, this, bytesRead); 91 } 92 getKeyFor(Object toWrite)93 protected abstract byte getKeyFor(Object toWrite); 94 write(Nd nd, long address, Object toWrite)95 public final void write(Nd nd, long address, Object toWrite) { 96 write(nd, address, toWrite, UNUSED_RESULT); 97 } 98 99 @SuppressWarnings("unchecked") write(Nd nd, long address, Object toWrite, int[] bytesWritten)100 public final void write(Nd nd, long address, Object toWrite, int[] bytesWritten) { 101 byte key = getKeyFor(toWrite); 102 103 @SuppressWarnings("rawtypes") 104 TagHandler handler = this.readers[key]; 105 106 if (handler == null) { 107 throw nd.describeProblem().build("Invalid key " + key + " returned from getKeyFor(...)"); //$NON-NLS-1$//$NON-NLS-2$ 108 } 109 110 handler.write(nd, address, this, toWrite, bytesWritten); 111 } 112 destruct(Nd nd, long address)113 public final void destruct(Nd nd, long address) { 114 Database db = nd.getDB(); 115 long readAddress = address; 116 byte nextByte = db.getByte(readAddress); 117 readAddress += Database.BYTE_SIZE; 118 119 TagHandler<?> handler = this.readers[nextByte]; 120 if (handler == null) { 121 throw nd.describeProblem() 122 .addProblemAddress("tag", address, 1) //$NON-NLS-1$ 123 .build("Found unknown tag with value " + nextByte + " at address " + address); //$NON-NLS-1$//$NON-NLS-2$ 124 } 125 126 handler.destruct(nd, readAddress, this); 127 } 128 129 @SuppressWarnings("unchecked") getSize(Nd nd, Object toMeasure)130 public final int getSize(Nd nd, Object toMeasure) { 131 byte key = getKeyFor(toMeasure); 132 133 @SuppressWarnings("rawtypes") 134 TagHandler handler = this.readers[key]; 135 if (handler == null) { 136 throw new IndexException("Attempted to get size of object " + toMeasure.toString() + " with unknown key " //$NON-NLS-1$//$NON-NLS-2$ 137 + key); 138 } 139 140 return handler.getSize(nd, toMeasure, this); 141 } 142 } 143