blob: 66fe9de9132e23dfbdd10605d9bb8084ed83d7fa [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "HexStringParser.h"
#include <decaf/lang/Character.h>
#include <decaf/lang/Integer.h>
#include <decaf/lang/Long.h>
#include <decaf/lang/Double.h>
#include <decaf/lang/Float.h>
#include <decaf/util/StringTokenizer.h>
#include <decaf/lang/exceptions/NumberFormatException.h>
#include <apr_pools.h>
#include <apr_strmatch.h>
using namespace decaf;
using namespace decaf::util;
using namespace decaf::lang;
using namespace decaf::lang::exceptions;
using namespace decaf::internal;
using namespace decaf::internal::util;
////////////////////////////////////////////////////////////////////////////////
const std::string HexStringParser::HEX_SIGNIFICANT =
"0[xX](\\p{XDigit}+\\.?|\\p{XDigit}*\\.\\p{XDigit}+)";
const std::string HexStringParser::BINARY_EXPONENT =
"[pP]([+-]?\\d+)";
const std::string HexStringParser::FLOAT_TYPE_SUFFIX =
"[fFdD]?";
const std::string HexStringParser::HEX_PATTERN =
"[\\x00-\\x20]*([+-]?)" + HEX_SIGNIFICANT + BINARY_EXPONENT + FLOAT_TYPE_SUFFIX + "[\\x00-\\x20]*";
////////////////////////////////////////////////////////////////////////////////
HexStringParser::HexStringParser( int exponentWidth, int mantissaWidth ) {
this->EXPONENT_WIDTH = exponentWidth;
this->MANTISSA_WIDTH = mantissaWidth;
this->EXPONENT_BASE = ~( -1 << (exponentWidth - 1) );
this->MAX_EXPONENT = ~( -1 << exponentWidth );
this->MIN_EXPONENT = -( MANTISSA_WIDTH + 1 );
this->MANTISSA_MASK = ~( -1 << mantissaWidth );
}
////////////////////////////////////////////////////////////////////////////////
double HexStringParser::parseDouble( const std::string& hexString ) {
HexStringParser parser( DOUBLE_EXPONENT_WIDTH, DOUBLE_MANTISSA_WIDTH );
long long result = parser.parse( hexString );
return Double::longBitsToDouble( result );
}
////////////////////////////////////////////////////////////////////////////////
float HexStringParser::parseFloat( const std::string& hexString ) {
HexStringParser parser( FLOAT_EXPONENT_WIDTH, FLOAT_MANTISSA_WIDTH );
int result = (int)parser.parse( hexString );
return Float::intBitsToFloat( result );
}
////////////////////////////////////////////////////////////////////////////////
long long HexStringParser::parse( const std::string& hexString ) {
std::string* hexSegments = getSegmentsFromHexString( hexString );
std::string signStr = hexSegments[0];
std::string significantStr = hexSegments[1];
std::string exponentStr = hexSegments[2];
delete hexSegments;
parseHexSign( signStr );
parseExponent( exponentStr );
parseMantissa( significantStr );
sign <<= ( MANTISSA_WIDTH + EXPONENT_WIDTH );
exponent <<= MANTISSA_WIDTH;
return sign | exponent | mantissa;
}
////////////////////////////////////////////////////////////////////////////////
std::string* HexStringParser::getSegmentsFromHexString( const std::string& hexString ) {
// apr_pool_t* thePool = NULL;
// apr_pool_create( &thePool, NULL );
// apr_strmatch_pattern* pattern =
// apr_strmatch_precompile( thePool, HEX_PATTERN.c_str(), 0 );
//
// std::vector<std::string> hexSegments;
//
// TODO
// Matcher matcher = PATTERN.matcher(hexString);
// if( !matcher.matches() ) {
// throw NumberFormatException(
// __FILE__, __LINE__,
// "HexStringParser::getSegmentsFromHexString"
// "Invalid hex string:", hexString.c_str() );
// }
//
// std::string* hexSegments = new std::string[3];
// hexSegments[0] = matcher.group(1);
// hexSegments[1] = matcher.group(2);
// hexSegments[2] = matcher.group(3);
//
// return hexSegments;
return NULL;
}
////////////////////////////////////////////////////////////////////////////////
void HexStringParser::parseExponent(const std::string& exponentStr) {
std::string newExponentStr = exponentStr;
char leadingChar = newExponentStr.at(0);
int expSign = ( leadingChar == '-' ? -1 : 1 );
if( !Character::isDigit( leadingChar ) ) {
newExponentStr = newExponentStr.substr( 1, newExponentStr.size() );
}
try {
exponent = expSign * Long::parseLong( exponentStr );
checkedAddExponent( EXPONENT_BASE );
} catch( exceptions::NumberFormatException& e ) {
exponent = expSign * Long::MAX_VALUE;
}
}
////////////////////////////////////////////////////////////////////////////////
void HexStringParser::parseMantissa(const std::string& significantStr) {
StringTokenizer tokenizer( significantStr, "\\." );
std::vector<std::string> strings;
tokenizer.toArray( strings );
std::string strIntegerPart = strings[0];
std::string strDecimalPart = strings.size() > 1 ? strings[1] : "";
std::string significand =
getNormalizedSignificand( strIntegerPart, strDecimalPart) ;
if( significand == "0" ) {
setZero();
return;
}
int offset = getOffset( strIntegerPart, strDecimalPart );
checkedAddExponent( offset );
if( exponent >= MAX_EXPONENT ) {
setInfinite();
return;
}
if( exponent <= MIN_EXPONENT ) {
setZero();
return;
}
if( significand.length() > MAX_SIGNIFICANT_LENGTH ) {
abandonedNumber = significand.substr( MAX_SIGNIFICANT_LENGTH );
significand = significand.substr( 0, MAX_SIGNIFICANT_LENGTH );
}
mantissa = Long::parseLong( significand, HEX_RADIX );
if( exponent >= 1 ) {
processNormalNumber();
} else{
processSubNormalNumber();
}
}
////////////////////////////////////////////////////////////////////////////////
void HexStringParser::checkedAddExponent( long long offset ) {
long long result = exponent + offset;
int expSign = Long::signum( exponent );
if( expSign * Long::signum( offset ) > 0 &&
expSign * Long::signum( result ) < 0 ) {
exponent = expSign * Long::MAX_VALUE;
} else {
exponent = result;
}
}
////////////////////////////////////////////////////////////////////////////////
void HexStringParser::processNormalNumber() {
int desiredWidth = MANTISSA_WIDTH + 2;
fitMantissaInDesiredWidth( desiredWidth );
round();
mantissa = mantissa & MANTISSA_MASK;
}
////////////////////////////////////////////////////////////////////////////////
void HexStringParser::processSubNormalNumber() {
int desiredWidth = MANTISSA_WIDTH + 1;
desiredWidth += (int)exponent;//lends bit from mantissa to exponent
exponent = 0;
fitMantissaInDesiredWidth( desiredWidth );
round();
mantissa = mantissa & MANTISSA_MASK;
}
////////////////////////////////////////////////////////////////////////////////
void HexStringParser::fitMantissaInDesiredWidth(int desiredWidth){
int bitLength = countBitsLength( mantissa );
if( bitLength > desiredWidth ) {
discardTrailingBits( bitLength - desiredWidth );
} else {
mantissa <<= ( desiredWidth - bitLength );
}
}
////////////////////////////////////////////////////////////////////////////////
void HexStringParser::discardTrailingBits( long long num ) {
long long mask = ~( -1L << num );
abandonedNumber += ( mantissa & mask );
mantissa >>= num;
}
////////////////////////////////////////////////////////////////////////////////
void HexStringParser::round() {
std::string result = abandonedNumber;
replaceAll( result, "0+", "" );
bool moreThanZero = ( result.length() > 0 ? true : false );
int lastDiscardedBit = (int)( mantissa & 1L );
mantissa >>= 1;
int tailBitInMantissa = (int)( mantissa & 1L );
if( lastDiscardedBit == 1 && ( moreThanZero || tailBitInMantissa == 1 ) ) {
int oldLength = countBitsLength( mantissa );
mantissa += 1L;
int newLength = countBitsLength( mantissa );
//Rounds up to exponent when whole bits of mantissa are one-bits.
if( oldLength >= MANTISSA_WIDTH && newLength > oldLength ) {
checkedAddExponent( 1 );
}
}
}
////////////////////////////////////////////////////////////////////////////////
std::string HexStringParser::getNormalizedSignificand(
const std::string& strIntegerPart, const std::string& strDecimalPart ) {
std::string significand = strIntegerPart + strDecimalPart;
replaceFirst( significand, "^0x", "" );
if( significand.length() == 0 ) {
significand = "0";
}
return significand;
}
////////////////////////////////////////////////////////////////////////////////
int HexStringParser::getOffset(
const std::string& strIntegerPart, const std::string& strDecimalPart ) {
std::string strIntegerPart2 = strIntegerPart;
replaceFirst( strIntegerPart2, "^0+", "" );
//If the Interger part is a nonzero number.
if( strIntegerPart.length() != 0 ) {
std::string leadingNumber = strIntegerPart.substr( 0, 1 );
return ( strIntegerPart.length() - 1) * 4 +
countBitsLength(Long::parseLong( leadingNumber,HEX_RADIX ) ) - 1;
}
//If the Interger part is a zero number.
int i;
for( i = 0; (std::size_t)i < strDecimalPart.length() && strDecimalPart.at(i) == '0'; i++ );
if( (std::size_t)i == strDecimalPart.length() ) {
return 0;
}
std::string leadingNumber = strDecimalPart.substr( i,i + 1 );
return (-i - 1) * 4 +
countBitsLength( Long::parseLong( leadingNumber, HEX_RADIX) ) - 1;
}
////////////////////////////////////////////////////////////////////////////////
int HexStringParser::countBitsLength(long long value) {
int leadingZeros = Long::numberOfLeadingZeros( value );
return Long::SIZE - leadingZeros;
}