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

net.sf.saxon.om.LargeAttributeMap Maven / Gradle / Ivy

There is a newer version: 12.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018-2022 Saxonica Limited
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.om;


import net.sf.saxon.ma.trie.ImmutableHashTrieMap;
import net.sf.saxon.transpile.CSharpReplaceBody;


import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * An implementation of AttributeMap suitable for larger collections of attributes (say, more than five).
 * This provides direct access to an attribute by name, avoiding the cost of a sequential search. The
 * map preserves the order of insertion of attributes: this is done by maintaining a doubly-linked list
 * of attributes in insertion order (when an attribute is replaced by another with the same name, it
 * currently occupies the position of the original; but this is not guaranteed).
 */

public class LargeAttributeMap implements AttributeMap {

    private static class AttributeInfoLink {
        AttributeInfo payload;
        NodeName prior;
        NodeName next;
    }

    private ImmutableHashTrieMap attributes;
    private NodeName first = null;
    private NodeName last = null;
    private int _size;

    private LargeAttributeMap() {}

    public LargeAttributeMap(List atts) {
        assert !atts.isEmpty();
        this.attributes = emptyMap();
        this._size = atts.size();
        AttributeInfoLink current = null;
        for (AttributeInfo att : atts) {
            if (attributes.get(att.getNodeName()) != null) {
                throw new IllegalArgumentException("Attribute map contains duplicates");
            }
            AttributeInfoLink link = new AttributeInfoLink();
            link.payload = att;
            if (current == null) {
                first = att.getNodeName();
            } else {
                current.next = att.getNodeName();
                link.prior = current.payload.getNodeName();
            }
            current = link;
            attributes = attributes.put(att.getNodeName(), link);
        }
        last = current.payload.getNodeName();
    }

    private LargeAttributeMap(ImmutableHashTrieMap attributes, int size, NodeName first, NodeName last) {
        this.attributes = attributes;
        this._size = size;
        this.first = first;
        this.last = last;
    }

    @CSharpReplaceBody(code="return System.Collections.Immutable.ImmutableDictionary.Create();")
    private ImmutableHashTrieMap emptyMap() {
        return ImmutableHashTrieMap.empty();
    }

    /**
     * Return the number of attributes in the map.
     *
     * @return The number of attributes in the map.
     */

    @Override
    public int size() {
        return _size;
    }

    @Override
    public AttributeInfo get(NodeName name) {
        AttributeInfoLink link = attributes.get(name);
        return link == null ? null : link.payload;
    }

    @Override
    public AttributeInfo get(String uri, String local) {
        NodeName name = new FingerprintedQName("", uri, local);
        return get(name);
    }

    @Override
    public AttributeInfo getByFingerprint(int fingerprint, NamePool namePool) {
        NodeName name = new FingerprintedQName(namePool.getStructuredQName(fingerprint), fingerprint);
        return get(name);
    }

    @Override
    public AttributeMap put(AttributeInfo att) {
        AttributeInfoLink existing = attributes.get(att.getNodeName());
        AttributeInfoLink link = new AttributeInfoLink();
        NodeName last2 = last;
        link.payload = att;
        if (existing == null) {
            link.prior = last;
            last2 = att.getNodeName();
            AttributeInfoLink oldLast = attributes.get(last);
            AttributeInfoLink penult = new AttributeInfoLink();
            penult.payload = oldLast.payload;
            penult.next = att.getNodeName();
            penult.prior = oldLast.prior;
            attributes = attributes.put(last, penult);
        } else {
            link.prior = existing.prior;
            link.next = existing.next;
        }
        ImmutableHashTrieMap att2 = attributes.put(att.getNodeName(), link);
        int size2 = existing == null ? _size + 1 : _size;
        return new LargeAttributeMap(att2, size2, first, last2);
    }

    @Override
    public AttributeMap remove(NodeName name) {
        // Not actually used (or tested)
        if (attributes.get(name) == null) {
            return this;
        } else {
            NodeName first2 = first;
            NodeName last2 = last;
            ImmutableHashTrieMap att2 = attributes.remove(name);
            AttributeInfoLink existing = attributes.get(name);
            if (existing.prior != null) {
                AttributeInfoLink priorLink = attributes.get(existing.prior);
                AttributeInfoLink priorLink2 = new AttributeInfoLink();
                priorLink2.payload = priorLink.payload;
                priorLink2.prior = priorLink.prior;
                priorLink2.next = existing.next;
                att2 = att2.put(existing.prior, priorLink2);
            } else {
                first2 = existing.next;
            }
            if (existing.next != null) {
                AttributeInfoLink nextLink = attributes.get(existing.next);
                AttributeInfoLink nextLink2 = new AttributeInfoLink();
                nextLink2.payload = nextLink.payload;
                nextLink2.next = nextLink.next;
                nextLink2.prior = existing.prior;
                att2 = att2.put(existing.next, nextLink2);
            } else {
                last2 = existing.prior;
            }
            return new LargeAttributeMap(att2, _size - 1, first2, last2);
        }
    }

    @Override
    public Iterator iterator() {
        return new Iterator() {

            NodeName current = first;
            @Override
            public boolean hasNext() {
                return current != null;
            }

            @Override
            public AttributeInfo next() {
                AttributeInfoLink link = attributes.get(current);
                current = link.next;
                return link.payload;
            }
        };

    }

    @Override
    public synchronized ArrayList asList() {
        ArrayList result = new ArrayList<>(_size);
        for (AttributeInfo att : this) {
            result.add(att);
        }
        return result;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(256);
        for (AttributeInfo att : this) {
            sb.append(att.getNodeName().getDisplayName()).append("=\"").append(att.getValue()).append("\" ");
        }
        return sb.toString().trim();
    }

}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy