blob: 8de719762a7bb3bbba7e0febab1fc6811b5b953d [file] [log] [blame]
// Lucene version compatibility level 4.8.1
using J2N.Text;
using Lucene.Net.Support;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using WritableArrayAttribute = Lucene.Net.Support.WritableArrayAttribute;
namespace Lucene.Net.Analysis.Util
{
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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.
*/
/// <summary>
/// A StringBuilder that allows one to access the array.
/// </summary>
public class OpenStringBuilder : IAppendable, ISpanAppendable, ICharSequence // LUCENENET specific - implemented ISpanAppendable to support ReadOnlySpan<char>
{
protected char[] m_buf;
protected int m_len;
public OpenStringBuilder()
: this(32)
{
}
bool ICharSequence.HasValue => m_buf != null;
public OpenStringBuilder(int size)
{
m_buf = new char[size];
}
public OpenStringBuilder(char[] arr, int len)
{
// LUCENENET specific - calling private method instead of public virtual
SetInternal(arr, len);
}
public virtual int Length
{
get => m_len;
set => m_len = value;
}
public virtual void Set(char[] arr, int end) => SetInternal(arr, end);
// LUCENENET specific - S1699 - introduced this to allow the constructor to
// still call "Set" functionality without having to call the virtual method
// that could be overridden by a subclass and don't have the state it expects
private void SetInternal(char[] arr, int end)
{
this.m_buf = arr;
this.m_len = end;
}
[WritableArray]
[SuppressMessage("Microsoft.Performance", "CA1819", Justification = "Lucene's design requires some writable array properties")]
public virtual char[] Array => m_buf;
// LUCENENE NOTE: This is essentially a duplicate of Length (except that property can be set).
// .NET uses Length for StringBuilder anyway, so that property is preferable to this one.
//public virtual int Count // LUCENENET NOTE: This was size() in Lucene.
//{
// get{ return m_len; }
//}
public virtual int Capacity => m_buf.Length;
public virtual OpenStringBuilder Append(ICharSequence csq)
{
return Append(csq, 0, csq.Length);
}
public virtual OpenStringBuilder Append(ICharSequence csq, int startIndex, int count) // LUCENENET specific: changed to startIndex/length to match .NET
{
EnsureCapacity(count);
UnsafeWrite(csq, startIndex, count);
return this;
}
public virtual OpenStringBuilder Append(ReadOnlySpan<char> value) // LUCENENET specific - added to support ReadOnlySpan<char>
{
EnsureCapacity(value.Length);
UnsafeWrite(value);
return this;
}
// LUCENENET specific - overload for string (more common in .NET than ICharSequence)
public virtual OpenStringBuilder Append(string csq)
{
return Append(csq, 0, csq.Length);
}
// LUCENENET specific - overload for string (more common in .NET than ICharSequence)
public virtual OpenStringBuilder Append(string csq, int startIndex, int count) // LUCENENET specific: changed to startIndex/length to match .NET
{
EnsureCapacity(count);
UnsafeWrite(csq, startIndex, count);
return this;
}
// LUCENENET specific - char sequence overload for StringBuilder
public virtual OpenStringBuilder Append(StringBuilder csq)
{
return Append(csq, 0, csq.Length);
}
// LUCENENET specific - char sequence overload for StringBuilder
public virtual OpenStringBuilder Append(StringBuilder csq, int startIndex, int count) // LUCENENET specific: changed to startIndex/length to match .NET
{
EnsureCapacity(count);
UnsafeWrite(csq, startIndex, count);
return this;
}
// LUCENENET specific - char sequence overload for char[]
public virtual OpenStringBuilder Append(char[] value)
{
Write(value);
return this;
}
// LUCENENET specific - char sequence overload for char[]
public virtual OpenStringBuilder Append(char[] value, int startIndex, int count)
{
EnsureCapacity(count);
UnsafeWrite(value, startIndex, count);
return this;
}
public virtual OpenStringBuilder Append(char c)
{
Write(c);
return this;
}
// LUCENENET specific - removed (replaced with this[])
//public virtual char CharAt(int index)
//{
// return m_buf[index];
//}
// LUCENENET specific - removed (replaced with this[])
//public virtual void SetCharAt(int index, char ch)
//{
// m_buf[index] = ch;
//}
// LUCENENET specific - added to .NETify
public virtual char this[int index]
{
get => m_buf[index];
set => m_buf[index] = value;
}
public virtual ICharSequence Subsequence(int startIndex, int length)
{
// From Apache Harmony String class
if (m_buf is null || (startIndex == 0 && length == m_buf.Length))
{
return new CharArrayCharSequence(m_buf);
}
if (startIndex < 0)
throw new ArgumentOutOfRangeException(nameof(startIndex));
if (length < 0)
throw new ArgumentOutOfRangeException(nameof(length), $"{nameof(length)} may not be negative.");
if (startIndex > m_buf.Length - length) // LUCENENET: Checks for int overflow
throw new ArgumentOutOfRangeException(nameof(length), $"Index and length must refer to a location within the string. For example {nameof(startIndex)} + {nameof(length)} <= {nameof(Length)}.");
char[] result = new char[length];
for (int i = 0, j = startIndex; i < length; i++, j++)
result[i] = m_buf[j];
return new CharArrayCharSequence(result);
}
public virtual void UnsafeWrite(char b)
{
m_buf[m_len++] = b;
}
public virtual void UnsafeWrite(int b)
{
UnsafeWrite((char)b);
}
public virtual void UnsafeWrite(ReadOnlySpan<char> b) // LUCENENET specific - added to support ReadOnlySpan<char>
{
int len = b.Length;
b.CopyTo(m_buf.AsSpan(this.m_len, len));
this.m_len += len;
}
public virtual void UnsafeWrite(char[] b, int off, int len)
{
Arrays.Copy(b, off, m_buf, this.m_len, len);
this.m_len += len;
}
// LUCENENET specific overload for StringBuilder
public virtual void UnsafeWrite(StringBuilder b, int off, int len)
{
b.CopyTo(off, m_buf, this.m_len, len);
this.m_len += len;
}
// LUCENENET specific overload for string
public virtual void UnsafeWrite(string b, int off, int len)
{
b.CopyTo(off, m_buf, this.m_len, len);
this.m_len += len;
}
// LUCENENET specific overload for ICharSequence
public virtual void UnsafeWrite(ICharSequence b, int off, int len)
{
if (!b.HasValue) return;
if (b is StringBuilderCharSequence sb)
{
UnsafeWrite(sb.Value, off, len);
return;
}
if (b is StringCharSequence str)
{
UnsafeWrite(str.Value, off, len);
return;
}
if (b is CharArrayCharSequence chars)
{
UnsafeWrite(chars.Value, off, len);
return;
}
for (int i = off; i < off + len; i++)
{
UnsafeWrite(b[i]);
}
}
protected virtual void Resize(int len)
{
char[] newbuf = new char[Math.Max(m_buf.Length << 1, len)];
Arrays.Copy(m_buf, 0, newbuf, 0, Length);
m_buf = newbuf;
}
public virtual void EnsureCapacity(int capacity) // LUCENENET NOTE: renamed from reserve() in Lucene to match .NET StringBuilder
{
if (m_len + capacity > m_buf.Length)
{
Resize(m_len + capacity);
}
}
public virtual void Write(char b)
{
if (m_len >= m_buf.Length)
{
Resize(m_len + 1);
}
UnsafeWrite(b);
}
public virtual void Write(int b)
{
Write((char)b);
}
public void Write(char[] b)
{
Write(b, 0, b.Length);
}
public virtual void Write(char[] b, int off, int len)
{
EnsureCapacity(len);
UnsafeWrite(b, off, len);
}
public void Write(OpenStringBuilder arr)
{
Write(arr.m_buf, 0, arr.Length); // LUCENENET specific - changed to arr.m_len (original was just len - appears to be a bug)
}
// LUCENENET specific overload for StringBuilder
public void Write(StringBuilder arr)
{
EnsureCapacity(arr.Length);
UnsafeWrite(arr, 0, arr.Length);
}
public virtual void Write(string s)
{
EnsureCapacity(s.Length);
s.CopyTo(0, m_buf, m_len, s.Length - 0);
m_len += s.Length;
}
//public virtual void Flush() // LUCENENET specific - removed because this doesn't make much sense on a StringBuilder in .NET, and it is not used
//{
//}
public void Reset()
{
m_len = 0;
}
public virtual char[] ToCharArray()
{
char[] newbuf = new char[Length];
Arrays.Copy(m_buf, 0, newbuf, 0, Length);
return newbuf;
}
public override string ToString()
{
return new string(m_buf, 0, Length);
}
public virtual OpenStringBuilder Remove(int startIndex, int length) // LUCENENET specific - added missing remove method
{
if (m_len == length && startIndex == 0)
{
m_len = 0;
return this;
}
if (length > 0)
{
int endIndex = startIndex + length;
m_buf.AsSpan(endIndex).CopyTo(m_buf.AsSpan(startIndex));
m_len -= length;
}
return this;
}
#region IAppendable Members
IAppendable IAppendable.Append(char value)
{
return Append(value);
}
IAppendable IAppendable.Append(string value)
{
return Append(value);
}
IAppendable IAppendable.Append(string value, int startIndex, int count)
{
return Append(value, startIndex, count);
}
IAppendable IAppendable.Append(StringBuilder value)
{
return Append(value);
}
IAppendable IAppendable.Append(StringBuilder value, int startIndex, int count)
{
return Append(value, startIndex, count);
}
IAppendable IAppendable.Append(char[] value)
{
return Append(value);
}
IAppendable IAppendable.Append(char[] value, int startIndex, int count)
{
return Append(value, startIndex, count);
}
IAppendable IAppendable.Append(ICharSequence value)
{
return Append(value);
}
IAppendable IAppendable.Append(ICharSequence value, int startIndex, int count)
{
return Append(value, startIndex, count);
}
ISpanAppendable ISpanAppendable.Append(ReadOnlySpan<char> value) => Append(value);
#endregion IAppendable Members
}
}