001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  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.apache.wicket.util.string;
018
019/**
020 * This is a prepending stringbuffer optimized for constantly prepending strings to the front of the
021 * buffer.
022 * 
023 * @author jcompagner
024 */
025public class PrependingStringBuffer
026{
027        private int size;
028        private int position;
029
030        private char[] buffer;
031
032        /**
033         * Default constructor, the internal initial buffer size will be 16
034         */
035        public PrependingStringBuffer()
036        {
037                this(16);
038        }
039
040        /**
041         * Constructs this PrependingStringBuffer with the given buffer size.
042         * 
043         * @param size
044         *            The initial size of the buffer.
045         */
046        public PrependingStringBuffer(final int size)
047        {
048                buffer = new char[size];
049                position = size;
050                this.size = 0;
051        }
052
053        /**
054         * Constructs and direct inserts the given string. The buffer size will be string.length+16
055         * 
056         * @param start
057         *            The string that is directly inserted.
058         */
059        public PrependingStringBuffer(final String start)
060        {
061                this(start.length() + 16);
062                prepend(start);
063        }
064
065        /**
066         * Prepends one char to this PrependingStringBuffer
067         * 
068         * @param ch
069         *            The char that will be prepended
070         * @return this
071         */
072        public PrependingStringBuffer prepend(final char ch)
073        {
074                int len = 1;
075                if (position < len)
076                {
077                        expandCapacity(size + len);
078                }
079                position -= len;
080                buffer[position] = ch;
081                size += len;
082                return this;
083        }
084
085        /**
086         * Prepends the string to this PrependingStringBuffer
087         * 
088         * @param str
089         *            The string that will be prepended
090         * @return this
091         */
092        public PrependingStringBuffer prepend(final String str)
093        {
094                int len = str.length();
095                if (position < len)
096                {
097                        expandCapacity(size + len);
098                }
099                str.getChars(0, len, buffer, position - len);
100                position -= len;
101                size += len;
102                return this;
103        }
104
105        private void expandCapacity(final int minimumCapacity)
106        {
107                int newCapacity = (buffer.length + 1) * 2;
108                if (newCapacity < 0)
109                {
110                        newCapacity = Integer.MAX_VALUE;
111                }
112                else if (minimumCapacity > newCapacity)
113                {
114                        newCapacity = minimumCapacity;
115                }
116
117                char newValue[] = new char[newCapacity];
118                System.arraycopy(buffer, position, newValue, newCapacity - size, size);
119                buffer = newValue;
120                position = newCapacity - size;
121        }
122
123        /**
124         * Returns the size of this PrependingStringBuffer
125         * 
126         * @return The size
127         */
128        public int length()
129        {
130                return size;
131        }
132
133        /**
134         * @see java.lang.Object#toString()
135         */
136        @Override
137        public String toString()
138        {
139                return new String(buffer, position, size);
140        }
141
142        @Override
143        public boolean equals(final Object obj)
144        {
145                if (obj == this)
146                {
147                        return true;
148                }
149                else if (obj == null)
150                {
151                        return false;
152                }
153                else
154                {
155                        return toString().equals(obj.toString());
156                }
157        }
158
159        @Override
160        public int hashCode()
161        {
162                return toString().hashCode();
163        }
164}