// -*- c++ -*- /* * Jakelib2 - General purpose C++ library * Copyright (C) 2001 Florian Wolff (florian@donuz.de) * * 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 library 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. * * 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 * * $Id: ChoiceFormat.jlc,v 1.13 2003/09/27 08:10:28 florian Exp $ */ #include "jakelib2.h" #include "jakelib2/text/ChoiceFormat.h" #include "jakelib2/util/Vector.h" #include "jakelib2/lang/Double.h" using namespace jakelib::lang; using namespace jakelib::text; using namespace jakelib::util; JAKELIB_IMPLEMENT_CLASS("jakelib.text.ChoiceFormat", ChoiceFormat, NumberFormat); JAKELIB_IMPLEMENT_ARRAY(ChoiceFormat); #pragma javasyntax const jint ChoiceFormat::mantissaBits = 52; const jint ChoiceFormat::exponentBits = 11; /*****************************************************************************\ * ChoiceFormat | *****************************************************************************/ ChoiceFormat::ChoiceFormat(String * newPattern) :NumberFormat() { applyPattern(newPattern); } ChoiceFormat::ChoiceFormat(jdoubles * choiceLimits, Strings * choiceFormats) :NumberFormat() { setChoices(choiceLimits, choiceFormats); } /*****************************************************************************\ * applyPattern | *****************************************************************************/ void ChoiceFormat::applyPattern(String * newPattern) { jint index = 0; jint max = newPattern->length(); Vector *stringVec = new Vector(); Vector *limitVec = new Vector(); StringBuffer *buf = new StringBuffer(); while (true) { jint dstart = index; while (index < max) { jchar c = newPattern->charAt(index); if ((c == '#') || (c == 0x2064) || (c == '<')) break; ++index; } if (index == max) throw new IllegalArgumentException("unexpected end of text" .. JAKELIB_AT2("jakelib.text.ChoiceFormat.applyPattern")); Double *d = new Double(newPattern->substring(dstart, index)); if (newPattern->charAt(index) == '<') d = new Double(nextDouble(d->doubleValue())); limitVec->addElement(d); ++index; buf->setLength(0); while (index < max) { jchar c = newPattern->charAt(index); if (c == '\'' && index < max + 1 && newPattern->charAt(index + 1) == '\'') { buf->append(c); ++index; } else if (c == '\'' && index < max + 2) { buf->append(newPattern->charAt(index + 1)); index = index + 2; } else if (c == '|') break; else buf->append(c); ++index; } stringVec->addElement(buf->toString()); if (index == max) break; ++index; } choiceFormats = new Strings(stringVec->size()); stringVec->copyInto(choiceFormats); choiceLimits = new jdoubles(limitVec->size()); for (jint i = 0; i < choiceLimits->length(); ++i) { Double *d = (Double *) (limitVec->elementAt(i)); choiceLimits->set(i, d->doubleValue()); } } /*****************************************************************************\ * equals | *****************************************************************************/ jboolean ChoiceFormat::equals(Object * obj) { if (!(obj != null)) return false; ChoiceFormat *cf = (ChoiceFormat*) obj; if (choiceLimits->length() != cf->choiceLimits->length()) return false; for (jint idx = choiceLimits->length() - 1; idx >= 0; --idx) { if (choiceLimits->get(idx) != cf->choiceLimits->get(idx) || !choiceFormats->get(idx)->equals(cf->choiceFormats->get(idx))) return false; } return true; } /*****************************************************************************\ * format | *****************************************************************************/ StringBuffer *ChoiceFormat::format(jlong num, StringBuffer *appendBuf, FieldPosition *pos) { return format(static_cast < jdouble > (num), appendBuf, pos); } StringBuffer *ChoiceFormat::format(jdouble num, StringBuffer *appendBuf, FieldPosition *pos) { if (choiceLimits->length() == 0) return appendBuf; jint index = 0; if (!Double::isNaN(num) && (num >= choiceLimits->get(0))) for (; index < choiceLimits->length() - 1; ++index) if ((choiceLimits->get(index) <= num) && (num < choiceLimits->get(index + 1))) break; return appendBuf->append(choiceFormats->get(index)); } /*****************************************************************************\ * getFormats | *****************************************************************************/ Objects *ChoiceFormat::getFormats() { return (Objects *) (choiceFormats->clone()); } /*****************************************************************************\ * getLimits | *****************************************************************************/ jdoubles *ChoiceFormat::getLimits() { jdoubles *jdbl = new jdoubles(choiceLimits); return (jdoubles *) (jdbl); } /*****************************************************************************\ * hashCode | *****************************************************************************/ jint ChoiceFormat::hashCode() { jint hash = 0; for (jint i = 0; i < choiceLimits->length(); ++i) { jlong v = Double::doubleToLongBits(choiceLimits->get(i)); hash = (jint) (hash ^ (v ^ (v >> 32))); hash = (jint) (hash ^ choiceFormats->get(i)->hashCode()); } return hash; } /*****************************************************************************\ * nextDouble | *****************************************************************************/ jdouble ChoiceFormat::nextDouble(jdouble d) { return nextDouble(d, true); } jdouble ChoiceFormat::nextDouble(jdouble d, jboolean next) { if (Double::isInfinite(d) || Double::isNaN(d)) return d; jlong bits = Double::doubleToLongBits(d); // FIXME: warning on gcc: "warning: left shift count >= width of type" //AlFa: believed to be fixed but has to eb tested yet jlong mantMask = (LL(1) << mantissaBits) - 1; jlong mantissa = bits & mantMask; jlong expMask = (LL(1) << exponentBits) - 1; jlong exponent = (bits >> mantissaBits) & expMask; if (next ^ (bits < 0)) if (mantissa == (LL(1) << mantissaBits) - 1) { mantissa = 0l; exponent++; if (exponent >= (LL(1) << mantissaBits)) return (bits > 0) ? Double::POSITIVE_INFINITY : Double::NEGATIVE_INFINITY; } else mantissa++; else if (exponent == 0l && mantissa == 0l) return next ? Double::MIN_VALUE : -Double::MIN_VALUE; else if (mantissa == 0l) { mantissa = (LL(1) << mantissaBits) - 1; exponent--; } else mantissa--; jlong result = bits < 0 ? 1 : 0; result = (result << exponentBits) | exponent; result = (result << mantissaBits) | mantissa; return Double::longBitsToDouble(result); } /*****************************************************************************\ * parse | *****************************************************************************/ Number *ChoiceFormat::parse(String * sourceStr, ParsePosition * pos) { jint index = pos->getIndex(); for (jint i = 0; i < choiceLimits->length(); ++i) if (sourceStr->startsWith(choiceFormats->get(i), index)) { pos->setIndex(index + choiceFormats->get(i)->length()); return new Double(choiceLimits->get(i)); } pos->setErrorIndex(index); return new Double(Double::NaN); } /*****************************************************************************\ * previousDouble | *****************************************************************************/ jdouble ChoiceFormat::previousDouble(jdouble d) { return nextDouble(d, false); } /*****************************************************************************\ * setChoices | *****************************************************************************/ void ChoiceFormat::setChoices(jdoubles * choiceLimits, Strings * choiceFormats) { if (choiceLimits == null || choiceFormats == null) throw new NullPointerException(); if (choiceLimits->length() != choiceFormats->length()) throw new IllegalArgumentException(); this->choiceFormats = (Strings *) (choiceFormats->clone()); this->choiceLimits = (jdoubles *) (choiceLimits->clone()); } /*****************************************************************************\ * quoteString | *****************************************************************************/ void ChoiceFormat::quoteString(StringBuffer * dest, String * text) { jint max = text->length(); for (jint i = 0; i < max; ++i) { jchar c = text->charAt(i); if (c == '\'') { dest->append(c); dest->append(c); } else if ((c == '#') || (c == '|') || (c == 0x2064) || (c == '<')) { dest->append('\''); dest->append(c); dest->append('\''); } else dest->append(c); } } /*****************************************************************************\ * toPattern | *****************************************************************************/ String *ChoiceFormat::toPattern() { StringBuffer *result = new StringBuffer(); for (jint i = 0; i < choiceLimits->length(); ++i) { result->append(choiceLimits->get(i)); result->append('#'); quoteString(result, choiceFormats->get(i)); } return result->toString(); }