| /* |
| * 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. |
| */ |
| package org.apache.iotdb.tsfile.utils; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * this class is used to concatenate Strings effectively.It contains a StringBuilder and initialize |
| * it until {@code toString} is called. Note:it's not thread safety |
| */ |
| public class StringContainer { |
| |
| // while call toString, all substrings are jointed with joinSeparator |
| private final String joinSeparator; |
| private StringBuilder stringBuilder; |
| private ArrayList<String> sequenceList; |
| private ArrayList<String> reverseList; |
| /** the summation length of all string segments. */ |
| private int totalLength = 0; |
| /** the count of string segments. */ |
| private int count = 0; |
| |
| private boolean isUpdated = true; |
| private String cache; |
| |
| /** defines the constructor function for the class. */ |
| public StringContainer() { |
| sequenceList = new ArrayList<>(); |
| reverseList = new ArrayList<>(); |
| joinSeparator = null; |
| } |
| |
| /** defines the constructor function for the class. */ |
| public StringContainer(String joinSeparator) { |
| sequenceList = new ArrayList<>(); |
| reverseList = new ArrayList<>(); |
| this.joinSeparator = joinSeparator; |
| } |
| |
| public StringContainer(String[] strings) { |
| this(); |
| addTail(strings); |
| } |
| |
| public StringContainer(String[] strings, String joinSeparator) { |
| this(joinSeparator); |
| addTail(strings); |
| } |
| |
| public int size() { |
| return count; |
| } |
| |
| public int length() { |
| return totalLength; |
| } |
| |
| public List<String> getSequenceList() { |
| return sequenceList; |
| } |
| |
| public List<String> getReverseList() { |
| return reverseList; |
| } |
| |
| /** |
| * add a objects array at this container's tail. |
| * |
| * @param objs -to be added |
| * @return another string contains objs as tail |
| */ |
| public StringContainer addTail(Object... objs) { |
| isUpdated = true; |
| count += objs.length; |
| for (int i = 0; i < objs.length; i++) { |
| String str = objs[i].toString(); |
| totalLength += str.length(); |
| sequenceList.add(str); |
| } |
| return this; |
| } |
| |
| /** |
| * add a Strings array at this container's tail.<br> |
| * strings:"a","b","c",<br> |
| * StringContainer this:["d","e","f"],<br> |
| * result:this:["d","e","f","a","b","c"],<br> |
| * |
| * @param strings - to be added |
| * @return - this object |
| */ |
| public StringContainer addTail(String... strings) { |
| isUpdated = true; |
| count += strings.length; |
| for (int i = 0; i < strings.length; i++) { |
| totalLength += strings[i].length(); |
| sequenceList.add(strings[i]); |
| } |
| return this; |
| } |
| |
| /** |
| * add a StringContainer at this container's tail.<br> |
| * param StringContainer:["a","b","c"],<br> |
| * this StringContainer :["d","e","f"],<br> |
| * result:this:["d","e","f","a","b","c"],<br> |
| * |
| * @param myContainer - to be added |
| * @return - this object |
| */ |
| public StringContainer addTail(StringContainer myContainer) { |
| isUpdated = true; |
| List<String> mySeqList = myContainer.getSequenceList(); |
| List<String> myRevList = myContainer.getReverseList(); |
| count += myRevList.size() + mySeqList.size(); |
| String temp; |
| for (int i = myRevList.size() - 1; i >= 0; i--) { |
| temp = myRevList.get(i); |
| sequenceList.add(temp); |
| totalLength += temp.length(); |
| } |
| for (int i = 0; i < mySeqList.size(); i++) { |
| temp = mySeqList.get(i); |
| sequenceList.add(temp); |
| totalLength += temp.length(); |
| } |
| return this; |
| } |
| |
| /** |
| * add a Strings array from this container's header.<br> |
| * strings:"a","b","c",<br> |
| * StringContainer this:["d","e","f"],<br> |
| * result:this:["a","b","c","d","e","f"],<br> |
| * |
| * @param strings - to be added |
| * @return - this object |
| */ |
| public StringContainer addHead(String... strings) { |
| isUpdated = true; |
| count += strings.length; |
| for (int i = strings.length - 1; i >= 0; i--) { |
| totalLength += strings[i].length(); |
| reverseList.add(strings[i]); |
| } |
| return this; |
| } |
| |
| /** |
| * add a StringContainer from this container's header.<br> |
| * StringContainer m:["a","b","c"],<br> |
| * StringContainer this:["d","e","f"],<br> |
| * result:this:["a","b","c","d","e","f"],<br> |
| * |
| * @param myContainer - given StringContainer to be add in head |
| * @return - this object |
| */ |
| public StringContainer addHead(StringContainer myContainer) { |
| isUpdated = true; |
| List<String> mySeqList = myContainer.getSequenceList(); |
| List<String> myRevList = myContainer.getReverseList(); |
| count += myRevList.size() + mySeqList.size(); |
| String temp; |
| for (int i = mySeqList.size() - 1; i >= 0; i--) { |
| temp = mySeqList.get(i); |
| reverseList.add(temp); |
| totalLength += temp.length(); |
| } |
| for (int i = 0; i < myRevList.size(); i++) { |
| temp = myRevList.get(i); |
| reverseList.add(temp); |
| totalLength += temp.length(); |
| } |
| return this; |
| } |
| |
| @Override |
| public String toString() { |
| if (!isUpdated) { |
| return cache; |
| } |
| if (totalLength <= 0) { |
| return ""; |
| } |
| if (joinSeparator == null) { |
| stringBuilder = new StringBuilder(totalLength); |
| for (int i = reverseList.size() - 1; i >= 0; i--) { |
| stringBuilder.append(reverseList.get(i)); |
| } |
| for (int i = 0; i < sequenceList.size(); i++) { |
| stringBuilder.append(sequenceList.get(i)); |
| } |
| cache = stringBuilder.toString(); |
| } else { |
| cache = join(joinSeparator); |
| } |
| isUpdated = false; |
| return cache; |
| } |
| |
| /** |
| * for all string in rev and seq, concat them with separator and return String. |
| * |
| * @param separator separator of string |
| * @return - result joined in type of String with parameter |
| */ |
| public String join(String separator) { |
| if (totalLength <= 0) { |
| return ""; |
| } |
| stringBuilder = new StringBuilder(totalLength + (count - 1) * separator.length()); |
| for (int i = reverseList.size() - 1; i >= 1; i--) { |
| stringBuilder.append(reverseList.get(i)); |
| stringBuilder.append(separator); |
| } |
| if (!reverseList.isEmpty()) { |
| stringBuilder.append(reverseList.get(0)); |
| if (!sequenceList.isEmpty()) { |
| stringBuilder.append(separator); |
| } |
| } |
| int i; |
| for (i = 0; i < sequenceList.size() - 1; i++) { |
| stringBuilder.append(sequenceList.get(i)); |
| stringBuilder.append(separator); |
| } |
| if (!sequenceList.isEmpty()) { |
| stringBuilder.append(sequenceList.get(i)); |
| } |
| return stringBuilder.toString(); |
| } |
| |
| /** |
| * return a sub-string in this container.<br> |
| * e.g. this container is ["aa","bbb","cc","d","ee"]; this.getSubString(0) = "a"; |
| * this.getSubString(2) ="c";this.getSubString(-1) = "ee"; |
| * |
| * @param index - the index of wanted sub-string |
| * @return - substring result |
| */ |
| public String getSubString(int index) { |
| int realIndex = index >= 0 ? index : count + index; |
| if (realIndex < 0 || realIndex >= count) { |
| throw new IndexOutOfBoundsException( |
| String.format("Index: %d, Real Index: %d, Size: %d", index, realIndex, count)); |
| } |
| if (realIndex < reverseList.size()) { |
| return reverseList.get(reverseList.size() - 1 - realIndex); |
| } else { |
| return sequenceList.get(realIndex - reverseList.size()); |
| } |
| } |
| |
| /** |
| * /** return a sub-container consist of several continuous strings in this {@code container.If |
| * start <= end, return a empty container} e.g. this container is ["aa","bbb","cc","d","ee"]; |
| * this.getSubString(0,0) = ["aa"]<br> |
| * this.getSubString(1,3) = ["bbb","cc","d"]<br> |
| * this.getSubString(1,-1) = ["bbb","cc","d", "ee"]<br> |
| * |
| * @param start - the start index of wanted sub-string |
| * @param end - the end index of wanted sub-string |
| * @return - substring result |
| */ |
| public StringContainer getSubStringContainer(int start, int end) { |
| int realStartIndex = start >= 0 ? start : count + start; |
| int realEndIndex = end >= 0 ? end : count + end; |
| if (realStartIndex < 0 || realStartIndex >= count) { |
| throw new IndexOutOfBoundsException( |
| String.format( |
| "start Index: %d, Real start Index: %d, Size: %d", start, realStartIndex, count)); |
| } |
| if (realEndIndex < 0 || realEndIndex >= count) { |
| throw new IndexOutOfBoundsException( |
| String.format("end Index: %d, Real end Index: %d, Size: %d", end, realEndIndex, count)); |
| } |
| StringContainer ret = new StringContainer(joinSeparator); |
| if (realStartIndex < reverseList.size()) { |
| for (int i = reverseList.size() - 1 - realStartIndex; |
| i >= Math.max(0, reverseList.size() - 1 - realEndIndex); |
| i--) { |
| ret.addTail(this.reverseList.get(i)); |
| } |
| } |
| if (realEndIndex >= reverseList.size()) { |
| for (int i = Math.max(0, realStartIndex - reverseList.size()); |
| i <= realEndIndex - reverseList.size(); |
| i++) { |
| ret.addTail(this.sequenceList.get(i)); |
| } |
| } |
| return ret; |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| if (joinSeparator != null) { |
| result = prime * result + joinSeparator.hashCode(); |
| } |
| for (String string : reverseList) { |
| result = prime * result + ((string == null) ? 0 : string.hashCode()); |
| } |
| for (String string : sequenceList) { |
| result = prime * result + ((string == null) ? 0 : string.hashCode()); |
| } |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object sc) { |
| if (sc == null) { |
| return false; |
| } |
| if (this.getClass() != sc.getClass()) { |
| return false; |
| } |
| return this.equals((StringContainer) sc); |
| } |
| |
| /** |
| * judge whether the param is equal to this container. |
| * |
| * @param sc -StringContainer Object to judge whether the object is equal to this container |
| * @return boolean value to judge whether is equal |
| */ |
| public boolean equals(StringContainer sc) { |
| if (sc == this) { |
| return true; |
| } |
| if (count != sc.count) { |
| return false; |
| } |
| if (totalLength != sc.totalLength) { |
| return false; |
| } |
| if (!joinSeparator.equals(sc.joinSeparator)) { |
| return false; |
| } |
| if (sequenceList.size() != sc.sequenceList.size()) { |
| return false; |
| } |
| for (int i = 0; i < sequenceList.size(); i++) { |
| if (!sequenceList.get(i).equals(sc.sequenceList.get(i))) { |
| return false; |
| } |
| } |
| if (reverseList.size() != sc.reverseList.size()) { |
| return false; |
| } |
| for (int i = 0; i < reverseList.size(); i++) { |
| if (!reverseList.get(i).equals(sc.reverseList.get(i))) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public StringContainer clone() { |
| StringContainer ret = new StringContainer(joinSeparator); |
| for (String s : sequenceList) { |
| ret.sequenceList.add(s); |
| } |
| for (String s : reverseList) { |
| ret.reverseList.add(s); |
| } |
| ret.totalLength = totalLength; |
| ret.count = count; |
| ret.isUpdated = isUpdated; |
| ret.cache = cache; |
| return ret; |
| } |
| } |