blob: ba6383cf3f9d04a4b17c853eed1eefb6342da8ff [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 "Long.h"
#include <decaf/lang/Character.h>
#include <sstream>
using namespace decaf;
using namespace decaf::lang;
////////////////////////////////////////////////////////////////////////////////
const int Long::SIZE = 64;
const long long Long::MAX_VALUE = (long long) 0x7FFFFFFFFFFFFFFFLL;
const long long Long::MIN_VALUE = (long long) 0x8000000000000000LL;
////////////////////////////////////////////////////////////////////////////////
Long::Long(long long value) : value(value) {
}
////////////////////////////////////////////////////////////////////////////////
Long::Long(const String& value) : value(0) {
this->value = parseLong(value);
}
////////////////////////////////////////////////////////////////////////////////
Long::~Long() {
}
////////////////////////////////////////////////////////////////////////////////
int Long::compareTo(const Long& l) const {
return this->value < l.value ? -1 : this->value == l.value ? 0 : 1;
}
////////////////////////////////////////////////////////////////////////////////
int Long::compareTo(const long long& l) const {
return this->value < l ? -1 : this->value == l ? 0 : 1;
}
////////////////////////////////////////////////////////////////////////////////
int Long::bitCount(long long value) {
if (value == 0) {
return 0;
}
unsigned long long uvalue = (unsigned long long) value;
uvalue = (uvalue & 0x5555555555555555LL) + ((uvalue >> 1) & 0x5555555555555555LL);
uvalue = (uvalue & 0x3333333333333333LL) + ((uvalue >> 2) & 0x3333333333333333LL);
// adjust for 64-bit integer
unsigned int i = (unsigned int) ((uvalue >> 32) + uvalue);
i = (i & 0x0F0F0F0F) + ((i >> 4) & 0x0F0F0F0F);
i = (i & 0x00FF00FF) + ((i >> 8) & 0x00FF00FF);
i = (i & 0x0000FFFF) + ((i >> 16) & 0x0000FFFF);
return i;
}
////////////////////////////////////////////////////////////////////////////////
Long Long::decode(const String& value) {
int length = (int) value.length(), i = 0;
if (length == 0) {
throw exceptions::NumberFormatException(__FILE__, __LINE__, "Long::decode - Zero length string given.");
}
char firstDigit = value.charAt(i);
bool negative = firstDigit == '-';
if (negative) {
if (length == 1) {
throw exceptions::NumberFormatException(__FILE__, __LINE__, "Long::decode - Invalid length string given.", value.c_str());
}
firstDigit = value.charAt(++i);
}
int base = 10;
if (firstDigit == '0') {
if (++i == length) {
return valueOf(0LL);
}
if ((firstDigit = value.charAt(i)) == 'x' || firstDigit == 'X') {
if (i == length) {
throw exceptions::NumberFormatException(__FILE__, __LINE__, "Long::decode - Invalid length string given.", value.c_str());
}
i++;
base = 16;
} else {
base = 8;
}
} else if (firstDigit == '#') {
if (i == length) {
throw exceptions::NumberFormatException(__FILE__, __LINE__, "Long::decode - Invalid length string given.", value.c_str());
}
i++;
base = 16;
}
long long result = parse(value, i, base, negative);
return valueOf(result);
}
////////////////////////////////////////////////////////////////////////////////
long long Long::highestOneBit(long long value) {
if (value == 0) {
return 0;
}
unsigned long long uvalue = (unsigned long long) value;
uvalue |= (uvalue >> 1);
uvalue |= (uvalue >> 2);
uvalue |= (uvalue >> 4);
uvalue |= (uvalue >> 8);
uvalue |= (uvalue >> 16);
uvalue |= (uvalue >> 32);
return (uvalue & ~(uvalue >> 1));
}
////////////////////////////////////////////////////////////////////////////////
long long Long::lowestOneBit(long long value) {
if (value == 0) {
return 0;
}
unsigned long long uvalue = (unsigned long long) value;
return (uvalue & (-1 * uvalue));
}
////////////////////////////////////////////////////////////////////////////////
int Long::numberOfLeadingZeros(long long value) {
if (value == 0) {
return 0;
}
unsigned long long uvalue = (unsigned long long) value;
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
value |= value >> 32;
return Long::bitCount(~uvalue);
}
////////////////////////////////////////////////////////////////////////////////
int Long::numberOfTrailingZeros(long long value) {
if (value == 0) {
return 0;
}
unsigned long long uvalue = (unsigned long long) value;
return Long::bitCount((uvalue & (-1 * uvalue)) - 1);
}
////////////////////////////////////////////////////////////////////////////////
long long Long::parseLong(const String& value) {
return Long::parseLong(value, 10);
}
////////////////////////////////////////////////////////////////////////////////
long long Long::parseLong(const String& value, int radix) {
if (radix < Character::MIN_RADIX || radix > Character::MAX_RADIX) {
throw exceptions::NumberFormatException(__FILE__, __LINE__, "Long::parseLong - Given Radix is out of range.");
}
int length = (int) value.length();
int i = 0;
if (length == 0) {
throw exceptions::NumberFormatException(__FILE__, __LINE__, "Long::parseLong - Zero length string is illegal.");
}
bool negative = value.charAt(i) == '-';
if (negative && ++i == length) {
throw exceptions::NumberFormatException(__FILE__, __LINE__, "Long::parseLong - Only a minus given, string is invalid.");
}
return Long::parse(value, i, radix, negative);
}
////////////////////////////////////////////////////////////////////////////////
long long Long::parse(const String& value, int offset, int radix, bool negative) {
long long max = Long::MIN_VALUE / radix;
long long result = 0;
long long length = value.length();
while (offset < length) {
int digit = Character::digit(value.charAt(offset++), radix);
if (digit == -1) {
throw exceptions::NumberFormatException(__FILE__, __LINE__,
"Long::parseLong - String contains no digit characters.");
}
if (max > result) {
throw exceptions::NumberFormatException(__FILE__, __LINE__,
"Long::parseLong - Parsed value greater than max for radix.");
}
long long next = result * radix - digit;
if (next > result) {
throw exceptions::NumberFormatException(__FILE__, __LINE__,
"Long::parseLong - Only a minus given, string is invalid.");
}
result = next;
}
if (!negative) {
result = -result;
if (result < 0) {
throw exceptions::NumberFormatException(__FILE__, __LINE__,
"Long::parseLong - Value less than zero, but no minus sign.");
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
long long Long::reverseBytes(long long value) {
if (value == 0) {
return 0;
}
unsigned long long uvalue = (unsigned long long) value;
long long b7 = (uvalue >> 56);
long long b6 = (uvalue >> 40) & 0xFF00ULL;
long long b5 = (uvalue >> 24) & 0xFF0000ULL;
long long b4 = (uvalue >> 8) & 0xFF000000ULL;
long long b3 = (uvalue & 0xFF000000ULL) << 8;
long long b2 = (uvalue & 0xFF0000ULL) << 24;
long long b1 = (uvalue & 0xFF00ULL) << 40;
long long b0 = (uvalue << 56);
return (b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7);
}
////////////////////////////////////////////////////////////////////////////////
long long Long::reverse(long long value) {
if (value == 0) {
return 0;
}
unsigned long long uvalue = (unsigned long long) value;
// From Hacker's Delight, 7-1, Figure 7-1
uvalue = ((uvalue & 0x5555555555555555ULL) << 1) | ((uvalue >> 1) & 0x5555555555555555ULL);
uvalue = ((uvalue & 0x3333333333333333ULL) << 2) | ((uvalue >> 2) & 0x3333333333333333ULL);
uvalue = ((uvalue & 0x0F0F0F0F0F0F0F0FULL) << 4) | ((uvalue >> 4) & 0x0F0F0F0F0F0F0F0FULL);
return reverseBytes(uvalue);
}
////////////////////////////////////////////////////////////////////////////////
long long Long::rotateLeft(long long value, int distance) {
unsigned long long i = (unsigned long long) value;
int j = distance & 0x1F;
return (i << j) | (i >> (-j & 0x1F));
}
////////////////////////////////////////////////////////////////////////////////
long long Long::rotateRight(long long value, int distance) {
unsigned long long i = (unsigned long long) value;
int j = distance & 0x1F;
return (i >> j) | (i << (-j & 0x1F));
}
////////////////////////////////////////////////////////////////////////////////
int Long::signum(long long value) {
return (value == 0 ? 0 : (value < 0 ? -1 : 1));
}
////////////////////////////////////////////////////////////////////////////////
std::string Long::toString() const {
return Long::toString(this->value, 10);
}
////////////////////////////////////////////////////////////////////////////////
std::string Long::toString(long long value) {
return Long::toString(value, 10);
}
////////////////////////////////////////////////////////////////////////////////
std::string Long::toString(long long value, int radix) {
if (radix < Character::MIN_RADIX || radix > Character::MAX_RADIX) {
radix = 10;
}
if (value == 0) {
return "0";
}
int count = 2;
long long j = value;
bool negative = value < 0;
if (!negative) {
count = 1;
j = -value;
}
while ((value /= radix) != 0) {
count++;
}
// Save length and allocate a new buffer for the string, add one
// more for the null character.
int length = count;
char* buffer = new char[length + 1];
do {
int ch = (int) (0 - (j % radix));
if (ch > 9) {
ch = ch - 10 + 'a';
} else {
ch += '0';
}
buffer[--count] = (char) ch;
} while ((j /= radix) != 0);
if (negative) {
buffer[0] = '-';
}
// Ensure there's a null
buffer[length] = 0;
std::string result(&buffer[0]);
delete[] buffer;
return result;
}
////////////////////////////////////////////////////////////////////////////////
std::string Long::toBinaryString(long long value) {
int count = 1;
long long j = value;
if (value < 0) {
count = 64; // 8 * sizeof(long long);
} else {
while ((j >>= 1) != 0) {
count++;
}
}
// Save length and allocate a new buffer for the string, add one
// more for the null character.
int length = count;
char* buffer = new char[length + 1];
do {
buffer[--count] = (char) ((value & 1) + '0');
value >>= 1;
} while (count > 0);
// Ensure there's a null
buffer[length] = 0;
std::string result(&buffer[0]);
delete[] buffer;
return result;
}
////////////////////////////////////////////////////////////////////////////////
std::string Long::toOctalString(long long value) {
int count = 1;
long long j = value;
unsigned long long uvalue = (unsigned long long) value;
if (value < 0) {
count = 22; // (8 * sizeof(long long) + 2) / 3;
} else {
while ((j >>= 3) != 0) {
count++;
}
}
// Save length and allocate a new buffer for the string, add one
// more for the null character.
int length = count;
char* buffer = new char[length + 1];
do {
buffer[--count] = (char) ((uvalue & 7) + '0');
uvalue >>= 3;
} while (count > 0);
// Ensure there's a null
buffer[length] = 0;
std::string result(&buffer[0]);
delete[] buffer;
return result;
}
////////////////////////////////////////////////////////////////////////////////
std::string Long::toHexString(long long value) {
int count = 1;
long long j = value;
if (value < 0) {
count = 16; // 8 * sizeof(long long) / 4
} else {
while ((j >>= 4) != 0) {
count++;
}
}
// Save length and allocate a new buffer for the string, add one
// more for the null character.
int length = count;
char* buffer = new char[length + 1];
do {
int t = (int) (value & 15);
if (t > 9) {
t = t - 10 + 'a';
} else {
t += '0';
}
buffer[--count] = (char) t;
value >>= 4;
} while (count > 0);
// Ensure there's a null
buffer[length] = 0;
std::string result(&buffer[0]);
delete[] buffer;
return result;
}
////////////////////////////////////////////////////////////////////////////////
Long Long::valueOf(const String& value) {
return Long(Long::parseLong(value));
}
////////////////////////////////////////////////////////////////////////////////
Long Long::valueOf(const String& value, int radix) {
return Long(Long::parseLong(value, radix));
}