![JAR search and dependency download from the Maven repository](/logo.png)
com.github.krukow.clj_lang.PersistentStructMap Maven / Gradle / Ivy
/**
* Copyright (c) Rich Hickey. All rights reserved.
* The use and distribution terms for this software are covered by the
* Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
* which can be found in the file epl-v10.html at the root of this distribution.
* By using this software in any fashion, you are agreeing to be bound by
* the terms of this license.
* You must not remove this notice, or any other, from this software.
**/
/* rich Dec 16, 2007 */
package com.github.krukow.clj_lang;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;
public class PersistentStructMap extends APersistentMap implements IObj{
public static class Def implements Serializable{
final ISeq keys;
final IPersistentMap keyslots;
Def(ISeq keys, IPersistentMap keyslots){
this.keys = keys;
this.keyslots = keyslots;
}
}
final Def def;
final Object[] vals;
final IPersistentMap ext;
final IPersistentMap _meta;
static public Def createSlotMap(ISeq keys){
if(keys == null)
throw new IllegalArgumentException("Must supply keys");
int c = RT.count(keys);
Object[] v = new Object[2*c];
int i = 0;
for(ISeq s = keys; s != null; s = s.next(), i++)
{
v[2*i] = s.first();
v[2*i+1] = i;
}
return new Def(keys, map(v));
}
static public IPersistentMap map(Object... init){
if(init == null)
return PersistentArrayMap.EMPTY;
else if(init.length <= PersistentArrayMap.HASHTABLE_THRESHOLD)
return PersistentArrayMap.createWithCheck(init);
return PersistentHashMap.create(init);
}
static public PersistentStructMap create(Def def, ISeq keyvals){
Object[] vals = new Object[def.keyslots.count()];
IPersistentMap ext = PersistentHashMap.EMPTY;
for(; keyvals != null; keyvals = keyvals.next().next())
{
if(keyvals.next() == null)
throw new IllegalArgumentException(String.format("No value supplied for key: %s", keyvals.first()));
K k = (K) keyvals.first();
V v = (V) RT.second(keyvals);
Map.Entry e = def.keyslots.entryAt(k);
if(e != null)
vals[e.getValue()] = v;
else
ext = ext.assoc(k, v);
}
return new PersistentStructMap(null, def, vals, ext);
}
static public PersistentStructMap construct(Def def, ISeq valseq){
Object[] vals = new Object[def.keyslots.count()];
IPersistentMap ext = PersistentHashMap.EMPTY;
for(int i = 0; i < vals.length && valseq != null; valseq = valseq.next(), i++)
{
vals[i] = valseq.first();
}
if(valseq != null)
throw new IllegalArgumentException("Too many arguments to struct constructor");
return new PersistentStructMap(null, def, vals, ext);
}
static public IFn getAccessor(final Def def, K key){
Map.Entry e = def.keyslots.entryAt(key);
if(e != null)
{
final int i = e.getValue();
return new AFn(){
public Object invoke(Object arg1) {
PersistentStructMap m = (PersistentStructMap) arg1;
if(m.def != def)
throw Util.runtimeException("Accessor/struct mismatch");
return m.vals[i];
}
};
}
throw new IllegalArgumentException("Not a key of struct");
}
protected PersistentStructMap(IPersistentMap meta, Def def, Object[] vals, IPersistentMap ext){
this._meta = meta;
this.ext = ext;
this.def = def;
this.vals = vals;
}
/**
* Returns a new instance of PersistentStructMap using the given parameters.
* This function is used instead of the PersistentStructMap constructor by
* all methods that return a new PersistentStructMap. This is done so as to
* allow subclasses to return instances of their class from all
* PersistentStructMap methods.
*/
protected PersistentStructMap makeNew(IPersistentMap meta, Def def, Object[] vals, IPersistentMap ext){
return new PersistentStructMap(meta, def, vals, ext);
}
public IObj withMeta(IPersistentMap meta){
if(meta == _meta)
return this;
return makeNew(meta, def, vals, ext);
}
public IPersistentMap meta(){
return _meta;
}
public boolean containsKey(Object key){
return def.keyslots.containsKey(key) || ((Map)ext).containsKey(key);
}
public IMapEntry entryAt(K key){
Map.Entry e = def.keyslots.entryAt(key);
if(e != null)
{
return new MapEntry(e.getKey(), (V) vals[e.getValue()]);
}
return ext.entryAt(key);
}
public IPersistentMap assoc(K key, V val){
Map.Entry e = def.keyslots.entryAt(key);
if(e != null)
{
int i = e.getValue();
Object[] newVals = vals.clone();
newVals[i] = val;
return makeNew(_meta, def, newVals, ext);
}
return makeNew(_meta, def, vals, ext.assoc(key, val));
}
public V valAt(K key){
Integer i = (Integer) def.keyslots.valAt(key);
if(i != null)
{
return (V) vals[i];
}
return ext.valAt(key);
}
public V valAt(K key, V notFound){
Integer i = (Integer) def.keyslots.valAt(key);
if(i != null)
{
return (V) vals[i];
}
return ext.valAt(key, notFound);
}
public IPersistentMap assocEx(K key, V val) {
if(containsKey(key))
throw Util.runtimeException("Key already present");
return assoc(key, val);
}
public IPersistentMap without(K key) {
Map.Entry e = def.keyslots.entryAt(key);
if(e != null)
throw Util.runtimeException("Can't remove struct key");
IPersistentMap newExt = ext.without(key);
if(newExt == ext)
return this;
return makeNew(_meta, def, vals, newExt);
}
public Iterator> iterator(){
return new Iterator>() {
ISeq> seq = seq();
public boolean hasNext() {
return seq != null;
}
public java.util.Map.Entry next() {
Entry first = seq.first();
seq = seq.next();
return first;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public Iterator> reverseIterator(){
return new Iterator>() {
Iterator> mapIter = ext.reverseIterator();
Object[] keys = RT.seqToArray(def.keys);
int index = keys.length;
public boolean hasNext() {
return mapIter.hasNext() || index > 0;
}
public java.util.Map.Entry next() {
if (mapIter.hasNext()) {
return mapIter.next();
}
index -= 1;
return new MapEntry(keys[index],vals[index]);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public Iterator> iteratorFrom(K key) {
Map.Entry e = def.keyslots.entryAt(key);
if(e != null) {
final int start = e.getValue();
return new Iterator>() {
int index = start;
final Object[] keys = RT.seqToArray(def.keys);
Iterator> extIt = ext.iterator();
public boolean hasNext() {
return index < vals.length || extIt.hasNext();
}
public java.util.Map.Entry next() {
if (index < vals.length) {
return new MapEntry(keys[index], vals[index++]);
}
return extIt.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
} else {
return ext.iteratorFrom(key);
}
}
public int count(){
return vals.length + RT.count(ext);
}
public ISeq> seq(){
return new Seq(null, def.keys, vals, 0, ext);
}
public IPersistentCollection empty(){
return construct(def, null);
}
static class Seq extends ASeq{
final int i;
final ISeq keys;
final Object[] vals;
final IPersistentMap ext;
public Seq(IPersistentMap meta, ISeq keys, Object[] vals, int i, IPersistentMap ext){
super(meta);
this.i = i;
this.keys = keys;
this.vals = vals;
this.ext = ext;
}
public Obj withMeta(IPersistentMap meta){
if(meta != _meta)
return new Seq(meta, keys, vals, i, ext);
return this;
}
public Object first(){
return new MapEntry(keys.first(), vals[i]);
}
public ISeq next(){
if(i + 1 < vals.length)
return new Seq(_meta, keys.next(), vals, i + 1, ext);
return ext.seq();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy