public StringManager(string str) { _internalString = str; _ropeString = new RopeString(str); }
/// <summary> /// Append another rope string to back of current. /// </summary> /// <param name="ropeString">Another rope string.</param> /// <param name="fromIndex">Index in another string from we append.</param> public void AppendToBack(RopeString ropeString, int fromIndex) { AppendToBack(ropeString, fromIndex, ropeString.Length - fromIndex); }
private int SearchSectorByGlobalIndex(RopeString ropeString, int fromIndex) { var estimateSectorIndex = fromIndex / RopeSector.SectorSize; int stepSign; if (ropeString._descriptors[estimateSectorIndex].FirstIndexInGlobal > fromIndex) stepSign = -1; else { stepSign = 1; } while (estimateSectorIndex >= 0 && estimateSectorIndex < ropeString._descriptors.Count) { if (ropeString._descriptors[estimateSectorIndex].FirstIndexInGlobal <= fromIndex && ropeString._descriptors[estimateSectorIndex].FirstIndexInGlobal + ropeString._descriptors[estimateSectorIndex].Sector.Length > fromIndex && ropeString._descriptors[estimateSectorIndex].Sector.Length > 0) return estimateSectorIndex; estimateSectorIndex += stepSign; } return -1; }
private void AppendToBack(RopeString ropeString, int fromIndex, int length) { if (length == 0) return; // First we search sector with lesser or equals first index to fromIndex int anotherStringSectorIndex = SearchSectorByGlobalIndex(ropeString, fromIndex); if (anotherStringSectorIndex == -1) throw new InvalidOperationException("fromIndex ouside of bounds"); // Cope from found sector from fromIndex to end to another new sector. var firstNewSector = new RopeSector(); var firstOldSector = ropeString._descriptors[anotherStringSectorIndex].Sector; var indexInsideFirstSector = fromIndex - ropeString._descriptors[anotherStringSectorIndex].FirstIndexInGlobal; // If index inside sector is zero --- just copy full sector. if (indexInsideFirstSector > 0) { while (indexInsideFirstSector < firstOldSector.Length && firstNewSector.Length < length) { firstNewSector.AppendToBack(firstOldSector[indexInsideFirstSector++]); } // Add new first sector to back of current string. _descriptors.Add( new RopeSectorDescriptor { FirstIndexInGlobal = Length, Sector = firstNewSector }); Length += firstNewSector.Length; ++anotherStringSectorIndex; } int lastIndex = fromIndex + length - 1; // First we search sector with lesser or equals first index to fromIndex int anotherStringSectorFinishIndex = SearchSectorByGlobalIndex(ropeString, lastIndex); if (anotherStringSectorFinishIndex == -1) throw new InvalidOperationException("fromIndex + length ouside of bounds"); // Batch add all next sectors to back of currect string. while (anotherStringSectorIndex < anotherStringSectorFinishIndex) { RopeSector sector = ropeString._descriptors[anotherStringSectorIndex++].Sector; _descriptors.Add( new RopeSectorDescriptor { FirstIndexInGlobal = Length, Sector = sector }); Length += sector.Length; } // Add last sector if needed. if (anotherStringSectorFinishIndex >= anotherStringSectorIndex && anotherStringSectorFinishIndex < ropeString._descriptors.Count && ropeString._descriptors[anotherStringSectorFinishIndex].FirstIndexInGlobal <= lastIndex) { var lastSector = ropeString._descriptors[anotherStringSectorFinishIndex].Sector; int countOfCopiedChars = lastIndex - ropeString._descriptors[anotherStringSectorFinishIndex].FirstIndexInGlobal + 1; var newSector = new RopeSector(); for (int indexInsideSector = 0; indexInsideSector < countOfCopiedChars; ++indexInsideSector) newSector.AppendToBack(lastSector[indexInsideSector]); _descriptors.Add(new RopeSectorDescriptor { FirstIndexInGlobal = Length, Sector = newSector }); Length += newSector.Length; } }
private static RopeString ConvertFromRegularString(string regularString) { var ropeString = new RopeString(); int currentIndex = 0; while (currentIndex < regularString.Length) { var sector = new RopeSector(); while (sector.Length < RopeSector.SectorSize && currentIndex < regularString.Length) { sector.AppendToBack(regularString[currentIndex++]); } ropeString.PushSectorToBack(sector); } return ropeString; }
/// <summary> /// Returns substring of current string. /// </summary> /// <param name="fromIndex">Index of substring start.</param> /// <param name="length">Length of substring.</param> /// <returns>Substring.</returns> public RopeString Substring(int fromIndex, int length) { var result = new RopeString(); result.AppendToBack(this, fromIndex, length); return result; }