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

net.sf.saxon.expr.sort.CodepointMatchKey Maven / Gradle / Ivy

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2015 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.expr.sort;

import net.sf.saxon.tree.tiny.CharSlice;
import net.sf.saxon.tree.util.FastStringBuffer;
import net.sf.saxon.value.AtomicValue;
import net.sf.saxon.value.StringValue;

/**
 * A match key for comparing strings (represented as an array of characters) using codepoint collation.
 */
public class CodepointMatchKey implements Comparable, AtomicMatchKey {

    private char[] value;
    private int hash = 0; // cached hash key: compatible with String.hashCode()

    public CodepointMatchKey(char[] in) {
        value = in;
    }

    public CodepointMatchKey(CharSequence in) {
        if (in instanceof String) {
            value = ((String) in).toCharArray();
        } else if (in instanceof CharSlice) {
            value = ((CharSlice)in).toCharArray();
        } else if (in instanceof FastStringBuffer) {
            value = ((FastStringBuffer)in).toCharArray();
        } else {
            value = in.toString().toCharArray();
        }
    }

    public int compareTo(Object o) {
        if (o instanceof CodepointMatchKey) {
            char[] a = value;
            char[] b = ((CodepointMatchKey) o).value;
            int alen = a.length;
            int blen = b.length;
            int i = 0;
            int j = 0;
            while (true) {
                if (i == alen) {
                    if (j == blen) {
                        return 0;
                    } else {
                        return -1;
                    }
                }
                if (j == blen) {
                    return +1;
                }
                // Following code is needed when comparing a BMP character against a surrogate pair
                // Note: we could do this comparison without fully computing the codepoint, but it's a very rare case
                int nexta = (int) a[i++];
                if (nexta >= 55296 && nexta <= 56319) {
                    nexta = ((nexta - 55296) * 1024) + ((int) a[i++] - 56320) + 65536;
                }
                int nextb = (int) b[j++];
                if (nextb >= 55296 && nextb <= 56319) {
                    nextb = ((nextb - 55296) * 1024) + ((int) b[j++] - 56320) + 65536;
                }
                int c = nexta - nextb;
                if (c != 0) {
                    return c;
                }
            }
        } else {
            throw new ClassCastException();
        }
    }

    @Override
    public int hashCode() {
        int h = hash;
        if (h == 0) {
            char val[] = value;
            int len = val.length;

            for (int i = 0; i < len; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o instanceof CodepointMatchKey) {
            char[] a = value;
            char[] b = ((CodepointMatchKey) o).value;
            int alen = a.length;
            if (alen != b.length) {
                return false;
            }
            while (--alen >= 0) {
                if (a[alen] != b[alen]) {
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    }

    @Override
    public String toString() {
        return new String(value);
    }

    /**
     * Get an atomic value that encapsulates this match key. Needed to support the collation-key() function.
     *
     * @return an atomic value that encapsulates this match key
     */
    public AtomicValue asAtomic() {
        return new StringValue(toString());
    }
}






© 2015 - 2025 Weber Informatics LLC | Privacy Policy