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

com.amazon.ion.impl.lite.IonSymbolLite Maven / Gradle / Ivy

There is a newer version: 1.11.9
Show newest version
/*
 * Copyright 2007-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package com.amazon.ion.impl.lite;

import static com.amazon.ion.SymbolTable.UNKNOWN_SYMBOL_ID;
import static com.amazon.ion.SystemSymbols.ION_1_0;
import static com.amazon.ion.SystemSymbols.ION_1_0_SID;

import com.amazon.ion.IonType;
import com.amazon.ion.IonWriter;
import com.amazon.ion.NullValueException;
import com.amazon.ion.SymbolTable;
import com.amazon.ion.SymbolToken;
import com.amazon.ion.UnknownSymbolException;
import com.amazon.ion.ValueVisitor;
import com.amazon.ion.impl._Private_IonSymbol;
import com.amazon.ion.impl._Private_Utils;
import java.io.IOException;


final class IonSymbolLite
    extends IonTextLite
    implements _Private_IonSymbol
{
    private static final int HASH_SIGNATURE =
        IonType.SYMBOL.toString().hashCode();

    private int _sid = UNKNOWN_SYMBOL_ID;

    /**
     * @param isNull if {@code true}, constructs a {@code null.symbol} value.
     */
    IonSymbolLite(ContainerlessContext context, boolean isNull)
    {
        super(context, isNull);
    }

    IonSymbolLite(IonSymbolLite existing, IonContext context) throws UnknownSymbolException
    {
        super(existing, context);
    }

    IonSymbolLite(ContainerlessContext context, SymbolToken sym)
    {
        super(context, sym == null);
        if (sym != null)
        {
            String text = sym.getText();
            int sid = sym.getSid();
            assert text != null || sid >= 0;

            if (text != null)
            {
                super.setValue(text);
                // TODO [amzn/ion-java/issues/27] - needs consistent handling, when to retain SID's vs ignore
            }
            else
            {
                // TODO [amzn/ion-java/issues/223] - needs consistent handling, resolution against context symbol table
                _sid = sid;
                // there *is* an encoding present so we must update
                _isSymbolIdPresent(true);
            }
        }
    }

    @Override
    IonSymbolLite clone(IonContext context)
    {
        IonSymbolLite clone = new IonSymbolLite(this, context);
        if(this._sid == 0) {
            clone._sid = 0;
        }
        return clone;
    }

    @Override
    public IonSymbolLite clone() throws UnknownSymbolException
    {
        // If this symbol has unknown text but known Sid, this symbol has no
        // semantic meaning, as such cloning should throw an exception.
        if (!isNullValue()
            && _sid != UNKNOWN_SYMBOL_ID && _sid != 0
            && _stringValue() == null) {
            throw new UnknownSymbolException(_sid);
        }
        return clone(ContainerlessContext.wrap(getSystem()));
    }

    @Override
    int hashCode(SymbolTableProvider symbolTableProvider)
    {
        final int sidHashSalt   = 127;      // prime to salt sid
        final int textHashSalt  = 31;       // prime to salt text
        int result = HASH_SIGNATURE;

        if (!isNullValue())
        {
            SymbolToken token = symbolValue(symbolTableProvider);
            String text = token.getText();

            int tokenHashCode = text == null
                ? token.getSid()  * sidHashSalt
                : text.hashCode() * textHashSalt;

            // mixing to account for small text and sid deltas
            tokenHashCode ^= (tokenHashCode << 29) ^ (tokenHashCode >> 3);

            result ^= tokenHashCode;
        }

        return hashTypeAnnotations(result, symbolTableProvider);
    }

    @Override
    public IonType getType()
    {
        return IonType.SYMBOL;
    }

    @Deprecated
    public int getSymbolId()
        throws NullValueException
    {
        return getSymbolId(null);
    }

    private int getSymbolId(SymbolTableProvider symbolTableProvider)
        throws NullValueException
    {
        validateThisNotNull();

        if (_sid != UNKNOWN_SYMBOL_ID || isReadOnly()) {
            return _sid;
        }

        SymbolTable symtab =
                symbolTableProvider != null ? symbolTableProvider.getSymbolTable()
                                            : getSymbolTable();
        if (symtab == null) {
            symtab = getSystem().getSystemSymbolTable();
        }
        assert(symtab != null);

        String name = _get_value();
        // TODO [amzn/ion-java/issues/27] - needs consistent handling, when to retain SID's vs ignore (here memoizing SID on read)
        if (!symtab.isLocalTable())
        {
            setSID(symtab.findSymbol(name));
            if (_sid > 0 || isReadOnly()) {
                return _sid;
            }
        }
        SymbolToken tok = symtab.find(name);
        if (tok != null)
        {
            setSID(tok.getSid());
            _set_value(tok.getText()); // Use the interned instance of the text
        }
        return _sid;
    }

    private void setSID(int sid)
    {
        _sid = sid;
        if (_sid > 0)
        {
            cascadeSIDPresentToContextRoot();
        }
    }


    /**
     * Get's the text of this NON-NULL symbol, finding it from our symbol
     * table if it's not yet known (and caching the result if possible).
     * 

* Caller must check {@link #isNullValue()} * * @return null if symbol text is unknown. */ private String _stringValue() { return _stringValue(new LazySymbolTableProvider(this)); } private String _stringValue(SymbolTableProvider symbolTableProvider) { String name = _get_value(); if (name == null) { assert _sid >= 0; SymbolTable symbols = symbolTableProvider.getSymbolTable(); name = symbols.findKnownSymbol(_sid); if (name != null) { // if this is a mutable value we'll hang onto // our now known symbol table so we don't have // to look it up again. // If the value is immutable, honor that contract. if (_isLocked() == false) { _set_value(name); } } } return name; } public SymbolToken symbolValue() { return symbolValue(new LazySymbolTableProvider(this)); } public SymbolToken symbolValue(SymbolTableProvider symbolTableProvider) { if (isNullValue()) return null; int sid = getSymbolId(symbolTableProvider); String text = _stringValue(symbolTableProvider); return _Private_Utils.newSymbolToken(text, sid); } @Override public void setValue(String value) { super.setValue(value); // Calls checkForLock and _isNullValue _sid = UNKNOWN_SYMBOL_ID; } protected boolean isIonVersionMarker() { return _isIVM(); } @Override boolean attemptClearSymbolIDValues() { boolean allSymbolIDsCleared = super.attemptClearSymbolIDValues(); // if there is no value, or there is already no SID - there is no clear action if (isNullValue() || _sid == UNKNOWN_SYMBOL_ID) { // no behavior required - value has no SID value to clear } // if there is text, clear the SID else if (_stringValue() != null) { _sid = UNKNOWN_SYMBOL_ID; } else { // TODO [amzn/ion-java/issues/223] - needs consistent handling, resolution against context symbol table // there is not text, so we can't clear the SID. allSymbolIDsCleared = false; } return allSymbolIDsCleared; } protected void setIsIonVersionMarker(boolean isIVM) { assert (ION_1_0.equals(this._get_value()) == isIVM); //_is_IonVersionMarker = isIVM; _isIVM(isIVM); _isSystemValue(isIVM); _sid = ION_1_0_SID; } @Override final void writeBodyTo(IonWriter writer, SymbolTableProvider symbolTableProvider) throws IOException { // TODO amzn/ion-java/issues/27 Fix symbol handling // A million-dollar question is - if text is missing, do // we throw (cannot serialize) or do we pass the sid thru??? // NB! This will throw if symbol is not set writer.writeSymbolToken(symbolValue(symbolTableProvider)); } @Override public String stringValue() throws UnknownSymbolException { return stringValue(new LazySymbolTableProvider(this)); } private String stringValue(SymbolTableProvider symbolTableProvider) throws UnknownSymbolException { if (isNullValue()) { return null; } String name = _stringValue(symbolTableProvider); if (name == null) { assert(_sid >= 0); throw new UnknownSymbolException(_sid); } return name; } @Override public void accept(ValueVisitor visitor) throws Exception { visitor.visit(this); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy