001/** 002 * 003 * Copyright 2014 Florian Schmaus 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smack.util; 018 019import java.util.ArrayList; 020import java.util.Collections; 021import java.util.List; 022 023public class LazyStringBuilder implements Appendable, CharSequence { 024 025 private final List<CharSequence> list; 026 027 private String cache; 028 029 private void invalidateCache() { 030 cache = null; 031 } 032 033 public LazyStringBuilder() { 034 list = new ArrayList<CharSequence>(20); 035 } 036 037 public LazyStringBuilder append(LazyStringBuilder lsb) { 038 list.addAll(lsb.list); 039 invalidateCache(); 040 return this; 041 } 042 043 @Override 044 public LazyStringBuilder append(CharSequence csq) { 045 assert csq != null; 046 list.add(csq); 047 invalidateCache(); 048 return this; 049 } 050 051 @Override 052 public LazyStringBuilder append(CharSequence csq, int start, int end) { 053 CharSequence subsequence = csq.subSequence(start, end); 054 list.add(subsequence); 055 invalidateCache(); 056 return this; 057 } 058 059 @Override 060 public LazyStringBuilder append(char c) { 061 list.add(Character.toString(c)); 062 invalidateCache(); 063 return this; 064 } 065 066 @Override 067 public int length() { 068 if (cache != null) { 069 return cache.length(); 070 } 071 int length = 0; 072 for (CharSequence csq : list) { 073 length += csq.length(); 074 } 075 return length; 076 } 077 078 @Override 079 public char charAt(int index) { 080 if (cache != null) { 081 return cache.charAt(index); 082 } 083 for (CharSequence csq : list) { 084 if (index < csq.length()) { 085 return csq.charAt(index); 086 } else { 087 index -= csq.length(); 088 } 089 } 090 throw new IndexOutOfBoundsException(); 091 } 092 093 @Override 094 public CharSequence subSequence(int start, int end) { 095 return toString().subSequence(start, end); 096 } 097 098 @Override 099 public String toString() { 100 if (cache == null) { 101 StringBuilder sb = new StringBuilder(length()); 102 for (CharSequence csq : list) { 103 sb.append(csq); 104 } 105 cache = sb.toString(); 106 } 107 return cache; 108 } 109 110 /** 111 * Get the List of CharSequences representation of this instance. The list is unmodifiable. If 112 * the resulting String was already cached, a list with a single String entry will be returned. 113 * 114 * @return a List of CharSequences representing this instance. 115 */ 116 public List<CharSequence> getAsList() { 117 if (cache != null) { 118 return Collections.singletonList((CharSequence) cache); 119 } 120 return Collections.unmodifiableList(list); 121 } 122}