#region CPL License
/*
Nuclex Framework
Copyright (C) 2002-2017 Nuclex Development Labs
This library is free software; you can redistribute it and/or
modify it under the terms of the IBM Common Public License as
published by the IBM Corporation; either version 1.0 of the
License, or (at your option) any later version.
This library 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
IBM Common Public License for more details.
You should have received a copy of the IBM Common Public
License along with this library
*/
#endregion
using System;
using System.Runtime.InteropServices;
namespace Nuclex.Support {
/// Delimits a section of a string
///
///
/// The design of this class pretty much mirrors that of the
/// class found in the .NET framework, but is
/// specialized to be used for strings, which can not be expressed as arrays but
/// share a lot of the characteristics of an array.
///
///
/// In certain situations, passing a StringSegment instead of the the actual
/// section from a string is useful. For example, the caller might want to know
/// from which index of the original string the substring was taken. Used internally
/// in parsers, it can also prevent needless string copying and garbage generation.
///
///
#if !NO_SERIALIZATION
[Serializable, StructLayout(LayoutKind.Sequential)]
#endif
public struct StringSegment {
///
/// Initializes a new instance of the class that delimits
/// all the elements in the specified string
///
/// String that will be wrapped
/// String is null
public StringSegment(string text) {
if(text == null) { // questionable, but matches behavior of ArraySegment class
throw new ArgumentNullException("text", "Text must not be null");
}
this.text = text;
this.offset = 0;
this.count = text.Length;
}
///
/// Initializes a new instance of the class that delimits
/// the specified range of the elements in the specified string
///
/// The string containing the range of elements to delimit
/// The zero-based index of the first element in the range
/// The number of elements in the range
///
/// Offset or count is less than 0
///
///
/// Offset and count do not specify a valid range in array
///
/// String is null
public StringSegment(string text, int offset, int count) {
if(text == null) { // questionable, but matches behavior of ArraySegment class
throw new ArgumentNullException("text");
}
if(offset < 0) {
throw new ArgumentOutOfRangeException(
"offset", "Argument out of range, non-negative number required"
);
}
if(count < 0) {
throw new ArgumentOutOfRangeException(
"count", "Argument out of range, non-negative number required"
);
}
if(count > (text.Length - offset)) {
throw new ArgumentException(
"Invalid argument, specified offset and count exceed string length"
);
}
this.text = text;
this.offset = offset;
this.count = count;
}
///
/// Gets the original string containing the range of elements that the string
/// segment delimits
///
///
/// The original array that was passed to the constructor, and that contains the range
/// delimited by the
///
public string Text {
get { return this.text; }
}
///
/// Gets the position of the first element in the range delimited by the array segment,
/// relative to the start of the original array
///
///
/// The position of the first element in the range delimited by the
/// , relative to the start of the original array
///
public int Offset {
get { return this.offset; }
}
///
/// Gets the number of elements in the range delimited by the array segment
///
///
/// The number of elements in the range delimited by the
///
public int Count {
get { return this.count; }
}
/// Returns the hash code for the current instance
/// A 32-bit signed integer hash code
public override int GetHashCode() {
return this.text.GetHashCode() ^ this.offset ^ this.count;
}
///
/// Determines whether the specified object is equal to the current instance
///
///
/// True if the specified object is a structure and is
/// equal to the current instance; otherwise, false
///
/// The object to be compared with the current instance
public override bool Equals(object other) {
return
(other is StringSegment) &&
this.Equals((StringSegment)other);
}
///
/// Determines whether the specified structure is equal
/// to the current instance
///
///
/// True if the specified structure is equal to the
/// current instance; otherwise, false
///
///
/// The structure to be compared with the current instance
///
public bool Equals(StringSegment other) {
return
(other.text == this.text) &&
(other.offset == this.offset) &&
(other.count == this.count);
}
///
/// Indicates whether two structures are equal
///
/// True if a is equal to b; otherwise, false
///
/// The structure on the left side of the
/// equality operator
///
///
/// The structure on the right side of the
/// equality operator
///
public static bool operator ==(StringSegment left, StringSegment right) {
return left.Equals(right);
}
///
/// Indicates whether two structures are unequal
///
/// True if a is not equal to b; otherwise, false
///
/// The structure on the left side of the
/// inequality operator
///
///
/// The structure on the right side of the
/// inequality operator
///
public static bool operator !=(StringSegment left, StringSegment right) {
return !(left == right);
}
/// Returns a string representation of the string segment
/// The string representation of the string segment
public override string ToString() {
return this.text.Substring(this.offset, this.count);
}
/// String wrapped by the string segment
private string text;
/// Offset in the original string the segment begins at
private int offset;
/// Number of characters in the segment
private int count;
}
} // namespace Nuclex.Support