2005/5/9

     
 

Number.h

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// 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 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/lang/Number.h,v 1.20 2005/04/09 19:26:48 kommer Exp $
#ifndef acdk_lang_Number_h
#define acdk_lang_Number_h

#include <acdk.h>
#include <acdk/io/Serializable.h>
#include <acdk/util/Locale.h>

namespace acdk {
namespace lang {

ACDK_DECL_CLASS(Number);


/**
  defines if number will be stored
  as Big or LittleEndian 
*/
enum Endian
{
  BigEndian = 0,
  LittleEndian = 1
};
ACDK_DEF_LIB_ENUM(ACDK_CORE_PUBLIC, Endian);

/**
  This class provides some extended number parsing routines
  which also supports the extended unicode code character set
  and localization.
  API: Java + ACDK<br>

  @author Roger Rene Kommer
  @version $Revision: 1.20 $
  @date $Date: 2005/04/09 19:26:48 $
*/  
class ACDK_CORE_PUBLIC Number
: extends acdk::lang::Object
, implements acdk::io::Serializable
{
  ACDK_WITH_METAINFO(Number)
public:
  Number() {}
  virtual byte byteValue() = 0;
  virtual short shortValue() = 0;
  virtual int intValue() = 0;
  virtual jlong longValue() = 0;
  virtual float floatValue() = 0;
  virtual double doubleValue() = 0;
  
  virtual int hashCode() { return intValue(); }

  static jlong decodeIntegerNumber(IN(RString) str, INOUT(bool) tryOnly, INOUT(char) typeChar, INOUT(int) ignoreaTrailing, bool ignoreLeadingWs = false) THROWS1(RNumberFormatException);
  /**
    @param tryOnly if true, method doesn't throws RNumberFormatException
           In this case method set tryOnly = false and return error information in 
           return value:
           0 -> general number format error
           -1 -> over/underflow
    @param typeChar 
      'b' or 'B' -> byte
      's' or 'S' -> short
      'i' or 'I' -> integer
      'l' or 'L' -> long
      'f' or 'F' -> float
      'd' or 'D' -> double
      if typeChar == 0 no asumption of type is given. If the postfix value is set in String, it will be set by this method
  */
  static jlong parseIntegerNumber(IN(RString) str, int radix, INOUT(bool) tryOnly, INOUT(char) typeChar, 
                                  INOUT(int) ignoreTrailing, bool ignoreLeadingSpaces = false) THROWS1(RNumberFormatException);
  /**
    working method
    @param str the string to parse
    @param tryOnly if parsing and the float cannot be parsed it does not throw an exception
           otherwise this param will be set to false if parsing failed
    @param typeChar hint which type was parsed
    @param ignoreLeadingSpaces ignore leading spaces
    @param ignoreTrailing if this is 0 it the method only succeed if the complete string was parsed
           otherwise it return the index position into the string where parsing was stopped
    @param locale if locale is Nil it uses the C / en_US locale otherwise the 
           given locale to parse the float number
    see also decodeIntegerNumber
  */
  static double parseFloatNumber(IN(RString) str, INOUT(bool) tryOnly, INOUT(char) typeChar, 
                                 INOUT(int) ignoreTrailing, bool ignoreLeadingSpaces = false, 
                                 IN(acdk::util::RLocale) locale = Nil) THROWS1(RNumberFormatException);
  /**
    return one of the typeChar which fits this number
  */
  static char getSmallestTypeChar(jlong number);
  /**
    return one of the float type char, in which this number fits
  */
  static char getSmallestTypeChar(double number);
  /**
    creates a number instance of given value. If typeChar is not given (= 0)
    it returns a class, which the value fits in
  */
  static RNumber getNumber(jlong value, char typeChar = 0) THROWS1(RNumberFormatException);
  /**
    creates a number instance of given value. If typeChar is not given (= 0)
    it returns a class, which the value fits in
  */
  static RNumber getNumber(double value, char typeChar = 0) THROWS1(RNumberFormatException);
  /**
    Parses a number from a unicode string
    if the string is a decimal string (radix = 10) all unicode character are allowed, which are digits (not limited to 0 - 9)

    @param str the string to parse
    @param tryOnly if tryOnly is true this method does'nt throw a RNumberFormatException, but only returns Nil
           if the string cannot be decoded to a number
    @param ignoreLeadingWs ignore leading white spaces
    @param locale if locale is Nil it uses the C / en_US locale otherwise the 
           given locale to parse the float number
  */
  static RNumber decodeToNumber(IN(RString) str, bool tryOnly = false, bool ignoreLeadingWs = false, 
                                IN(acdk::util::RLocale) locale = Nil) THROWS1(RNumberFormatException);
  /**
    parses a string to given integer number
  */
  static RNumber parseToIntegerNumber(IN(RString) str, int radix, bool tryOnly = false, bool ignoreLeadingSpaces = false) THROWS1(RNumberFormatException);
  /**
    @param locale may be Nil
    @param fraction if locale is Nil it returns '.'
    @param exponent if locle is Nil it returns 'e'
  */
  static void getFractionAndExponentSignFromLocale(IN(acdk::util::RLocale) locale, OUT(ucchar) fraction, OUT(ucchar) exponent);
  foreign virtual dmi::ScriptVar toScriptVar();
  /** group to convert plattform pendig bit order to or from BigEndian
      which will be used in Serialization and network
  */
  template <class T> template_static T toBigEndian(T t)
  {
#if defined(ACDK_BIGENDIAN)
    return t;
#else
/FONT>
    return swapBits(t);
#endif
/FONT>
  }
  template <class T> template_static T fromBigEndian(T t)
  {
#if defined(ACDK_BIGENDIAN)
    return t;
#else
/FONT>
    return swapBits(t);
#endif
/FONT>
  }
  template <class T> template_static T fromLittleEndian(T t)
  {
#if !defined(ACDK_BIGENDIAN)
    return t;
#else
/FONT>
    return swapBits(t);
#endif
/FONT>
  }
  template <class T> template_static T toLittleEndian(T t)
  {
#if !defined(ACDK_BIGENDIAN)
    return t;
#else
/FONT>
    return swapBits(t);
#endif
/FONT>
  }
  foreign static void swap2(char* ptr);
  foreign static void swap4(char* ptr);
  foreign static void swap8(char* ptr);
  template <class T> template_static T swapBits(T t)
  {
    if (sizeof(T) == 1)
      return t;
    if (sizeof(T) == 2)
      swap2((char*)&t);
    else if (sizeof(T) == 4)
      swap4((char*)&t);
    else if (sizeof(T) == 8)
      swap8((char*)&t);
    return t;
  }
  
  template <class T> template_static
  int getBitCountOf(T )
  {
    return sizeof(T) * 8;
  }
  template <class T> template_static
  int  bitCount(T val)
  {
    int count;
    int bitcount = getBitCountOf(val);
    for (count = 0; count != bitcount; val >>= 1)
      if (val & 1 )
        ++count;
    return count;
  }
  template <class T> template_static
  T rotateLeft(T val, int count)
  {
    int bitcount = getBitCountOf(val);
    if (count >= bitcount)
		  count %= 64;
    return (val << count) |  (val >> (bitcount - count));
  }
  template <class T> template_static
  T rotateRight(T val, int count)
  {
    int bitcount = getBitCountOf(val);
  	if (count >= bitcount)
		  count %= bitcount;
    return (val >> count) | (val << (64 - count));
  }
};

//static 
inline
void 
Number::swap2(char* ptr)
{
  char t1 = ptr[0];
  ptr[0] = ptr[1];
  ptr[1] = t1;
}

//static 
inline
void 
Number::swap4(char* ptr)
{
  char t0 = ptr[0];
  char t1 = ptr[1];
  ptr[0] = ptr[3];
  ptr[1] = ptr[2];
  ptr[3] = t0;
  ptr[2] = t1;
}

//static 
inline
void 
Number::swap8(char* ptr)
{
  char t0 = ptr[0];
  char t1 = ptr[1];
  char t2 = ptr[2];
  char t3 = ptr[3];
  ptr[0] = ptr[7];
  ptr[1] = ptr[6];
  ptr[2] = ptr[5];
  ptr[3] = ptr[4];
  ptr[7] = t0;
  ptr[6] = t1;
  ptr[5] = t2;
  ptr[4] = t3;
}




} // lang
} // acdk

#endif //acdk_lang_Number_h