jcckit.util.FormatElement Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of plantuml Show documentation
Show all versions of plantuml Show documentation
PlantUML is a component that allows to quickly write :
* sequence diagram,
* use case diagram,
* class diagram,
* activity diagram,
* component diagram,
* state diagram
* object diagram
/*
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program 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
* GNU Lesser General Public License for more details
* (http://www.gnu.org/copyleft/lesser.html).
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcckit.util;
/**
*
*
* @author Franz-Josef Elmer
*/
class FormatElement {
/** All descriptor characters. */
static final String DESCRIPTORS = "doxfeEgG";
private static final String INT_DESCRIPTORS = "dox";
private static final int INT_DESCRIPTOR = 0;
private static final int FLOAT_DESCRIPTOR = 1;
/**
* Calculate the integer power of a floating point number.
* @param n Exponent.
* @param x Number.
* @return x^n.
*/
private static final double power(double x, int n) {
return n < 0 ? 1.0 / power2(x, -n) : power2(x, n);
}
/** Calculate x^n recursively assuming n > 0. */
private static final double power2(double x, int n) {
switch (n) {
case 0: return 1;
case 1: return x;
default:
double p = power2(x, n / 2);
return p * p * power2(x, n % 2);
}
}
private final char _descriptor;
private final int _descriptorType;
private final double _tenToPrecision;
private boolean _decimalPoint;
private boolean _flushLeft;
private boolean _leadingZeros;
private boolean _alwaysSign;
private int _width;
private int _precision;
/** Creates an instance for the specified format string. */
FormatElement(String formatString) {
int len = formatString.length() - 1;
_descriptor = formatString.charAt(len);
if (DESCRIPTORS.indexOf(_descriptor) < 0) {
throw new IllegalArgumentException("Format element '" + formatString
+ "' does not ends with one of the following characters: "
+ DESCRIPTORS);
}
_descriptorType = INT_DESCRIPTORS.indexOf(_descriptor) >= 0
? INT_DESCRIPTOR : FLOAT_DESCRIPTOR;
if (formatString.length() > 1) {
switch (formatString.charAt(0)) {
case '-':
_flushLeft = true;
formatString = formatString.substring(1);
break;
case '0':
_leadingZeros = true;
formatString = formatString.substring(1);
break;
case '+':
_alwaysSign = true;
formatString = formatString.substring(1);
break;
}
len = formatString.length() - 1;
int index = formatString.indexOf('.');
_decimalPoint = index >= 0;
int last = _decimalPoint ? index : len;
if (last > 0) {
_width = Integer.parseInt(formatString.substring(0, last));
}
if (_decimalPoint) {
index++;
if (index < len) {
_precision = Integer.parseInt(formatString.substring(index, len));
}
}
}
_tenToPrecision = power(10, _precision);
}
/**
* Format a number in accordance of the format string
* given at the initialisation of this instance.
* @param buffer Buffer to which the formated output will be appended.
* @param number Number to be formated.
*/
public void form(StringBuffer buffer, long number) {
if (_descriptorType == FLOAT_DESCRIPTOR) {
form(buffer, (double) number);
} else {
// Format absolut value in the right base
buffer.append(form(number < 0,
Long.toString(Math.abs(number),
_descriptor == 'o' ? 8
: (_descriptor == 'x' ? 16 : 10)),
""));
}
}
/**
* Format a number in accordance of the format string
* given at the initialisation of this instance.
* @param buffer Buffer to which the formated output will be appended.
* @param number Number to be formated.
*/
public void form(StringBuffer buffer, double number) {
if (_descriptorType == INT_DESCRIPTOR) {
form(buffer, (long) Math.floor(number + 0.5));
} else if (_descriptor == 'f') {
buffer.append(formF(number));
} else if (_descriptor == 'e' || _descriptor == 'E') {
buffer.append(formE(number));
} else if (_descriptor == 'g' || _descriptor == 'G') {
String formF = formF(number);
String formE = formE(number);
buffer.append(formF.length() > formE.length() ? formE : formF);
}
}
private String form(boolean negativeValue, String intPart, String fracPart) {
int len = intPart.length() + fracPart.length();
// Buffer holding the result
StringBuffer result = new StringBuffer();
int count = 0;
// add sign if necessary
if (_alwaysSign || negativeValue) {
result.append(negativeValue ? '-' : '+');
count++;
}
// add zeros if necessary
if (_leadingZeros) {
for (int i = count + len; i < _width; i++) {
result.append('0');
count++;
}
}
// add number
result.append(intPart).append(fracPart);
count += len;
// add spaces if necessary
if (_flushLeft) {
for (; count < _width; count++) {
result.append(' ');
}
} else {
for (; count < _width; count++) {
result.insert(0, ' ');
}
}
return new String(result);
}
/** Format floating point number with exponent. */
private String formE(double number) {
// format absolute mantisse
int exponent = 0;
String zeros = "00000000000000000000000".substring(0, _precision + 1);
if (number != 0) {
exponent = (int) Math.floor(Math.log(Math.abs(number)) / Math.log(10));
double mantisse = Math.floor(Math.abs(number * power(10.0,
_precision - exponent)) + 0.5);
if (mantisse >= 10 * _tenToPrecision) {
exponent++;
mantisse = Math.floor(Math.abs(number * power(10.0,
_precision - exponent)) + 0.5);
}
zeros = Long.toString((long) mantisse);
}
// make fractional part
StringBuffer fracPart = new StringBuffer();
if (_decimalPoint) {
fracPart.append('.').append(zeros.substring(1));
}
// make exponent
fracPart.append(Character.isLowerCase(_descriptor) ? 'e': 'E')
.append(exponent < 0 ? '-' : '+');
exponent = Math.abs(exponent);
for (int i = 0, n = fracPart.length(); i < 3; i++) {
fracPart.insert(n, Character.forDigit(exponent % 10, 10));
exponent /= 10;
}
return form(number < 0, zeros.substring(0, 1), new String(fracPart));
}
/** Format floating point number. */
private String formF(double number) {
// Format absolut value
double multiplier = number < 0 ? - _tenToPrecision : _tenToPrecision;
String digits
= Long.toString((long) Math.floor(number * multiplier + 0.5));
String intPart = digits;
StringBuffer fracPart = new StringBuffer();
if (_decimalPoint) {
int len = digits.length() - _precision;
fracPart.append('.').append(digits.substring(Math.max(0, len)));
if (len > 0) {
intPart = digits.substring(0, len);
} else {
intPart = "0";
for (; len < 0; len++) {
fracPart.insert(1, '0');
}
}
}
return form(number < 0, intPart, new String(fracPart));
}
}