package origen.common;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import xoc.dta.datatypes.MultiSiteBoolean;
import xoc.dta.datatypes.MultiSiteLong;
import xoc.dta.datatypes.MultiSiteLongArray;
import xoc.dta.resultaccess.datatypes.BitSequence.BitOrder;
/**
* Generic data holder class
*
*
Can be used for example to store data before patching. Data elements are of type long. The
* implementation class is responsible for mapping this data to the right format
*
*
Use: It's basically a key-value pair per data point. This format is efficient for large arrays
* with little set data. It's not so efficient for a small array with many datapoints set. The key
* is the address and the value is called data. Everything is stored in a multisitelongarray for
* efficient patching.
*
*
Usage example:
*
*
{@code
* OrigenData mem = new OrigenData();
* mem.setData(10, 0x55);
* mem.setData(12, 0x55);
* println("The same? " + mem.allSitesTheSame(10));
* mem.setDataOnSite(1, 10, 11);
* println("The same? " + mem.allSitesTheSame(10));
*
* mem.setDataOnSite(4, 100, 44);
* mem.setDataOnSite(4, 200, 44);
* mem.setDataOnSite(4, 300, 44);
* mem.setData(60, 60);
* mem.printData();
*
* println("Addr 10 site 1 set? : " + mem.addrIsSet(1, 10));
* int addr = 60;
* if (mem.allSitesTheSame(addr)) {
* println(mem.getDataCommon(addr));
* } else {
* println(mem.getDataMSL(addr));
* }
* }
*/
public class OrigenData {
private MultiSiteLongArray mem_addr;
private MultiSiteLongArray mem_data;
private ArrayList _sortedUniqueElements;
// For printing purposes only
public int bitPerDataElement = 32;
private boolean _anythingSet = false;
/** Constructor, initialized empty address and data arrays */
public OrigenData() {
mem_addr = new MultiSiteLongArray();
mem_data = new MultiSiteLongArray();
_anythingSet = false;
}
public ArrayList getUniqueAddressList() {
ArrayList list = new ArrayList();
for (int site : mem_data.getActiveSites()) {
long[] a = mem_addr.get(site);
for (int i = 0; i < a.length; i++) {
if (!list.contains(a[i])) {
list.add(a[i]);
}
}
}
Collections.sort(list);
return list;
}
public MultiSiteBoolean getActiveSitesOnAddr(long addr) {
MultiSiteBoolean MSB = new MultiSiteBoolean();
for (int site : mem_data.getActiveSites()) {
MSB.set(site, addrIsSet(site, addr));
}
return MSB;
}
public int getUniqueAddr(int index) {
_sortedUniqueElements = getUniqueAddressList();
return _sortedUniqueElements.get(index).intValue();
}
public int getNumUniqueAddr() {
_sortedUniqueElements = getUniqueAddressList();
return _sortedUniqueElements.size();
}
public static > List sortIndex(final List in) {
ArrayList index = new ArrayList<>();
for (int i = 0; i < in.size(); i++) {
index.add(i);
}
Collections.sort(
index,
new Comparator() {
@Override
public int compare(Integer idx1, Integer idx2) {
return in.get(idx1).compareTo(in.get(idx2));
}
});
return index;
}
public void sort() {
for (int site : mem_data.getActiveSites()) {
long[] a = mem_addr.get(site);
long[] d = mem_data.get(site);
List list = new ArrayList(a.length);
for (long n : a) {
list.add(n);
}
List idx = sortIndex(list);
long[] newA = a.clone();
long[] newD = d.clone();
for (int i = 0; i < a.length; i++) {
newA[i] = a[idx.get(i)];
newD[i] = d[idx.get(i)];
}
mem_addr.set(site, newA);
mem_data.set(site, newD);
}
}
public boolean memEmpty() {
return _anythingSet;
}
/**
* Set data on 1 specific site for 1 address
*
* @param site
* @param addr
* @param data
*/
public void setDataOnSite(int site, long addr, long data) {
long[] a = mem_addr.get(site);
long[] d = mem_data.get(site);
if (a == null) {
a = new long[0];
}
if (d == null) {
d = new long[0];
}
int loc = valInAddr(a, addr);
if (loc == d.length) {
d = expand(d);
a = expand(a);
}
d[loc] = data;
a[loc] = addr;
mem_data.set(site, d);
mem_addr.set(site, a);
_anythingSet = true;
}
/**
* Set the data for a certain 32bit addr
*
* @param addr
* @param data
*/
public void setData(long addr, long data) {
for (int site : mem_data.getActiveSites()) {
setDataOnSite(site, addr, data);
}
}
/**
* Returns true if a certain address is set on ANY site
*
* @param addr
* @return
*/
public boolean addrIsSetAnySite(long addr) {
for (int site : mem_data.getActiveSites()) {
if (addrIsSet(site, addr)) {
return true;
}
}
return false;
}
/**
* Returns true if a certain address is set on a specific site
*
* @param site
* @param addr
* @return
*/
public boolean addrIsSet(int site, long addr) {
long[] a = mem_addr.get(site);
int loc = valInAddr(a, addr);
return loc != a.length;
}
/**
* Returns the common data for all sites. Throws an error if this specific address is
* site-specific
*
* @param addr
* @return
*/
public long getDataCommon(long addr) {
int sites[] = mem_data.getActiveSites();
if (allSitesTheSame(addr)) {
return getDataPerSite(sites[0], addr);
}
throw new Error(
"Not all sites have the same data, cannot give common data for this addr: " + addr);
}
/**
* Returns the site specific data for an address, returning -1 for the data if it has not been
* previously set
*
* @param addr
* @return
*/
public MultiSiteLong getDataMSL(long addr) {
return getDataMSL(addr, false, "");
}
/**
* Returns the site specific data for an address, but raising and error with the given message if
* the data has not been previously set
*
* @param addr
* @return
*/
public MultiSiteLong getDataMSL(long addr, String errorMsg) {
return getDataMSL(addr, true, errorMsg);
}
private MultiSiteLong getDataMSL(long addr, boolean errorOnNotSet, String errorMsg) {
MultiSiteLong result = new MultiSiteLong();
for (int site : mem_data.getActiveSites()) {
if (addrIsSet(site, addr)) {
result.set(site, getDataPerSite(site, addr));
} else {
if (errorOnNotSet) {
throw new Error(errorMsg);
}
result.set(site, -1);
}
}
return result;
}
/**
* Returns whether or not all the sites have the same data for this addr
*
* @param addr
* @return
*/
public boolean allSitesTheSame(long addr) {
long commonData = -1;
boolean addrFound = false, addrNotFound = false;
for (int site : mem_data.getActiveSites()) {
long[] d = mem_data.get(site);
long[] a = mem_addr.get(site);
int loc = valInAddr(a, addr);
if (loc != a.length) {
if (addrNotFound) {
return false;
}
// Addr is found
addrFound = true;
if (commonData == -1) {
commonData = d[loc];
} else {
if (commonData != d[loc]) {
// Not all data the same for this addr over all sits
return false;
}
}
} else {
addrNotFound = true;
// Addr is found on one site but not the other
if (addrFound) {
return false;
}
}
}
return true;
}
/** Print all set data for all sites */
public void printData() {
sort();
System.out.println(getUniqueAddressList());
for (int site : mem_data.getActiveSites()) {
System.out.println("Site: " + site);
long[] d = mem_data.get(site);
long[] a = mem_addr.get(site);
for (int i = 0; i < d.length; i++) {
System.out.println(
a[i]
+ "\t"
+ OrigenHelpers.longToPaddedHexString(
d[i], bitPerDataElement / 4, BitOrder.RIGHT_TO_LEFT));
}
}
}
/** Clears all data on all sites */
public void clearAllData() {
// Lazy man's approach: Basically just throwing the reference to the old MSLarray away
// Let's hope the garbage collector removes the old references nicely
mem_addr = new MultiSiteLongArray();
mem_data = new MultiSiteLongArray();
_anythingSet = false;
}
// Some private helper functions
/**
* Returns the location in the array for a certain address. Returns the last+1 location of the
* array if addr is not found
*
* @param arr
* @param val
* @return
*/
private int valInAddr(long[] arr, long val) {
if (arr != null) {
for (int i = 0; i < arr.length; i++) {
if (val == arr[i]) {
return i;
}
}
return arr.length;
}
return 0;
}
/**
* Get the data for a specific site. This is private because the testmethod should call
* getDataMSL()
*
* @param site
* @param addr
* @return
*/
private long getDataPerSite(int site, long addr) {
long[] d = mem_data.get(site);
long[] a = mem_addr.get(site);
int loc = valInAddr(a, addr);
return d[loc];
}
/**
* Expand the array by 1
*
* @param origArray
* @return
*/
private long[] expand(long[] origArray) {
long[] newArray = new long[origArray.length + 1];
System.arraycopy(origArray, 0, newArray, 0, origArray.length);
return newArray;
}
}
class DataPair {
private final T addr;
private final T data;
public DataPair(T first, T second) {
addr = first;
data = second;
}
public T addr() {
return addr;
}
public T second() {
return data;
}
}