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

org.neo4j.values.storable.StringWrappingStringValue Maven / Gradle / Ivy

There is a newer version: 5.25.1
Show newest version
/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [http://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.values.storable;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.neo4j.hashing.HashFunction;

import static org.neo4j.memory.HeapEstimator.shallowSizeOfInstance;
import static org.neo4j.memory.HeapEstimator.sizeOf;
import static org.neo4j.values.utils.ValueMath.HASH_CONSTANT;

/**
 * Implementation of StringValue that wraps a `java.lang.String` and
 * delegates methods to that instance.
 */
final class StringWrappingStringValue extends StringValue
{
    private static final long SHALLOW_SIZE = shallowSizeOfInstance( StringWrappingStringValue.class );

    private final String value;

    StringWrappingStringValue( String value )
    {
        assert value != null;
        this.value = value;
    }

    @Override
    String value()
    {
        return value;
    }

    @Override
    public int length()
    {
        return value.codePointCount( 0, value.length() );
    }

    @Override
    public boolean isEmpty()
    {
        return value.isEmpty();
    }

    @Override
    protected int computeHashToMemoize()
    {
        //NOTE that we are basing the hash code on code points instead of char[] values.
        if ( value.isEmpty() )
        {
            return 0;
        }
        int h = 1, length = value.length();
        for ( int offset = 0, codePoint; offset < length; offset += Character.charCount( codePoint ) )
        {
            codePoint = value.codePointAt( offset );
            h = HASH_CONSTANT * h + codePoint;
        }
        return h;
    }

    @Override
    public long updateHash( HashFunction hashFunction, long hash )
    {
        return updateHash( hashFunction, hash, value );
    }

    public static long updateHash( HashFunction hashFunction, long hash, String value )
    {
        //NOTE that we are basing the hash code on code points instead of char[] values.
        int length = value.length();
        int codePointCount = 0;
        for ( int offset = 0; offset < length; )
        {
            int codePointA = value.codePointAt( offset );
            int codePointB = 0;
            offset += Character.charCount( codePointA );
            codePointCount++;
            if ( offset < length )
            {
                codePointB = value.codePointAt( offset );
                offset += Character.charCount( codePointB );
                codePointCount++;
            }
            hash = hashFunction.update( hash, ((long) codePointA << 32) + codePointB );
        }
        return hashFunction.update( hash, codePointCount );
    }

    @Override
    public TextValue substring( int start, int length )
    {
        int s = Math.min( start, length() );
        int e = Math.min( s + length, length() );
        int codePointStart = value.offsetByCodePoints( 0, s );
        int codePointEnd = value.offsetByCodePoints( 0, e );

        return Values.stringValue( value.substring( codePointStart, codePointEnd ) );
    }

    @Override
    public TextValue trim()
    {
        int start = ltrimIndex( value );
        int end = rtrimIndex( value );
        return Values.stringValue( value.substring( start, Math.max( end, start ) ) );
    }

    @Override
    public TextValue ltrim()
    {
        int start = ltrimIndex( value );
        return Values.stringValue( value.substring( start ) );
    }

    @Override
    public TextValue rtrim()
    {
        int end = rtrimIndex( value );
        return Values.stringValue( value.substring( 0, end ) );
    }

    @Override
    public TextValue reverse()
    {
        StringBuilder stringBuilder = new StringBuilder( value() );
        return Values.stringValue( stringBuilder.reverse().toString() );
    }

    @Override
    public TextValue plus( TextValue other )
    {
        return new StringWrappingStringValue( value + other.stringValue() );
    }

    @Override
    public boolean startsWith( TextValue other )
    {
        return value.startsWith( other.stringValue() );
    }

    @Override
    public boolean endsWith( TextValue other )
    {
        return value.endsWith( other.stringValue() );
    }

    @Override
    public boolean contains( TextValue other )
    {
        return value.contains( other.stringValue() );
    }

    @Override
    Matcher matcher( Pattern pattern )
    {
        return pattern.matcher( value );
    }

    @Override
    public long estimatedHeapUsage()
    {
        return SHALLOW_SIZE + sizeOf( value );
    }

    @Override
    public ValueRepresentation valueRepresentation()
    {
        return ValueRepresentation.UTF16_TEXT;
    }

    private static int ltrimIndex( String value )
    {
        int start = 0, length = value.length();
        while ( start < length )
        {
            int codePoint = value.codePointAt( start );
            if ( !Character.isWhitespace( codePoint ) )
            {
                break;
            }
            start += Character.charCount( codePoint );
        }

        return start;
    }

    private static int rtrimIndex( String value )
    {
        int end = value.length();
        while ( end > 0 )
        {
            int codePoint = value.codePointBefore( end );
            if ( !Character.isWhitespace( codePoint ) )
            {
                break;
            }
            end--;
        }
        return end;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy