blob: 05ca44bd4fd3780e3c94743e5f90a98050504716 [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* one or more patents listed at http://www.pivotal.io/patents.
*=========================================================================
*/
#include "CacheableString.hpp"
#include "DataOutput.hpp"
#include "DataInput.hpp"
#include "ExceptionTypes.hpp"
#include "GemfireTypeIds.hpp"
#include "impl/Utils.hpp"
#include <cwchar>
#include <cstdlib>
#include <ace/ACE.h>
#include <ace/OS.h>
using namespace gemfire;
void CacheableString::toData(DataOutput& output) const
{
if (m_type == GF_STRING) {
output.writeASCII((const char*) m_str, m_len);
}
else if (m_type == GF_WIDESTRING) {
output.writeUTF((const wchar_t*) m_str, m_len);
}
else if (m_type == GF_STRING_HUGE) {
output.writeASCIIHuge((const char*) m_str, m_len);
}
else if (m_type == GF_WIDESTRING_HUGE) {
output.writeUTFHuge((const wchar_t*) m_str, m_len);
}
}
Serializable* CacheableString::fromData(DataInput& input)
{
uint16_t shortLen = 0;
if (m_type == GF_STRING) {
input.readASCII((char**) &m_str, &shortLen);
m_len = shortLen;
}
else if (m_type == GF_WIDESTRING) {
input.readUTF((wchar_t**) &m_str, &shortLen);
m_len = shortLen;
}
else if (m_type == GF_STRING_HUGE) {
input.readASCIIHuge((char**) &m_str, &m_len);
}
else if (m_type == GF_WIDESTRING_HUGE) {
input.readUTFHuge((wchar_t**) &m_str, &m_len);
}
return this;
}
Serializable* CacheableString::createDeserializable()
{
return new CacheableString(GF_STRING);
}
Serializable* CacheableString::createDeserializableHuge()
{
return new CacheableString(GF_STRING_HUGE);
}
Serializable* CacheableString::createUTFDeserializable()
{
return new CacheableString(GF_WIDESTRING);
}
Serializable* CacheableString::createUTFDeserializableHuge()
{
return new CacheableString(GF_WIDESTRING_HUGE);
}
int32_t CacheableString::classId() const
{
return 0;
}
int8_t CacheableString::typeId() const
{
return m_type;
}
// assumes that the lengths are equal
template <typename TChar1, typename TChar2>
bool compareStrings(const TChar1* str1, const TChar2* str2)
{
TChar1 wc;
while ((wc = *str1) != 0) {
if (wc != *str2) {
return false;
}
++str1, ++str2;
}
return true;
}
bool CacheableString::operator == ( const CacheableKey& other ) const
{
// use typeId() call instead of m_type to work correctly with derived
// classes like CacheableFileName
int8_t thisType = typeId();
int8_t otherType = other.typeId();
if (thisType != otherType) {
if (!(thisType == GF_STRING || thisType == GF_WIDESTRING || thisType == GF_STRING_HUGE || thisType == GF_WIDESTRING_HUGE) ||
!(otherType == GF_STRING || otherType == GF_WIDESTRING || otherType == GF_STRING_HUGE || otherType == GF_WIDESTRING_HUGE)) {
return false;
}
}
const CacheableString& otherStr = static_cast<const CacheableString&>(other);
// check for lengths first
if (m_len != otherStr.m_len) {
return false;
}
if (m_str == NULL) {
return true;
}
else if (thisType == GF_STRING || thisType == GF_STRING_HUGE) {
if (otherType == GF_STRING || otherType == GF_STRING_HUGE) {
return compareStrings((const char*)m_str, (const char*)otherStr.m_str);
}
else {
return compareStrings((const char*)m_str, (const wchar_t*)otherStr.m_str);
}
}
else {
if (otherType == GF_STRING || otherType == GF_STRING_HUGE) {
return compareStrings((const wchar_t*)m_str, (const char*)otherStr.m_str);
}
else {
return compareStrings((const wchar_t*)m_str, (const wchar_t*)otherStr.m_str);
}
}
}
uint32_t CacheableString::hashcode() const
{
if (m_str == NULL) {
return 0;
}
int localHash = 0;
if (m_hashcode == 0) {
uint32_t prime = 31;
if (isCString()) {
const char *data = (const char*)m_str;
for (uint32_t i = 0; i < m_len; i++) {
localHash = prime*localHash + data[i];
}
}
else {
GF_DEV_ASSERT(isWideString());
const wchar_t *data = (const wchar_t*)m_str;
for (uint32_t i = 0; i < m_len; i++) {
localHash = prime*localHash + data[i];
}
}
m_hashcode = localHash;
}
return m_hashcode;
}
/** Private method to get ASCII char for wide-char if possible */
inline char getASCIIChar(const wchar_t wc, bool& isASCII, int32_t& encodedLen)
{
if (wc & 0xfc00) {
// three bytes required.
encodedLen += 3;
isASCII = false;
}
else if (wc & 0x0380) {
// two byte.
encodedLen += 2;
isASCII = false;
}
else {
// one byte.
++encodedLen;
return (wc & 0x7f);
}
return 0;
}
char* CacheableString::getASCIIString(const wchar_t* value, int32_t& len,
int32_t& encodedLen)
{
wchar_t currentChar;
char* buf = NULL;
bool isASCII = true;
char c;
if (len > 0) {
int32_t clen = len;
buf = new char[clen + 1];
while (clen > 0 && (currentChar = *value) != 0) {
c = getASCIIChar(currentChar, isASCII, encodedLen);
if (isASCII) {
buf[encodedLen - 1] = c;
}
++value, --clen;
}
if (isASCII) {
buf[encodedLen] = '\0';
}
else {
delete[] buf;
buf = NULL;
}
len -= clen;
}
else {
DataOutput out;
const wchar_t* pvalue = value;
while ((currentChar = *pvalue) != 0) {
c = getASCIIChar(currentChar, isASCII, encodedLen);
if (isASCII) {
out.write((int8_t) c);
}
++pvalue;
}
len = static_cast<int32_t> (pvalue - value);
if (isASCII) {
uint32_t sz;
const uint8_t* outBuf = out.getBuffer(&sz);
buf = new char[sz + 1];
memcpy(buf, outBuf, sz);
buf[sz] = '\0';
}
}
return buf;
}
void CacheableString::copyString(const char* value, int32_t len)
{
GF_NEW(m_str, char[len + 1]);
memcpy(m_str, value, len * sizeof(char));
((char*) m_str)[len] = '\0';
}
void CacheableString::copyString(const wchar_t* value, int32_t len)
{
GF_NEW(m_str, wchar_t[len + 1]);
memcpy(m_str, value, len * sizeof(wchar_t));
((wchar_t*) m_str)[len] = L'\0';
}
void CacheableString::initString(const char* value, int32_t len)
{
if (value != NULL) {
if (len <= 0) {
len = static_cast<int32_t> (strlen(value));
}
if (len > 0xFFFF) {
m_type = GF_STRING_HUGE;
}
m_len = len;
copyString(value, len);
}
}
void CacheableString::initStringNoCopy(char* value, int32_t len)
{
if (value != NULL) {
if (len <= 0) {
len = static_cast<int32_t> (strlen(value));
}
if (len > 0xFFFF) {
m_type = GF_STRING_HUGE;
}
m_len = len;
m_str = value;
}
}
void CacheableString::initString(const wchar_t* value, int32_t len)
{
if (value == NULL) {
m_type = GF_STRING;
}
else {
int32_t encodedLen = 0;
getASCIIString(value, len, encodedLen);
copyString(value, len);
if (encodedLen > 0xFFFF) {
m_type = GF_WIDESTRING_HUGE;
}
else {
m_type = GF_WIDESTRING;
}
m_len = len;
}
}
void CacheableString::initStringNoCopy(wchar_t* value, int32_t len)
{
if (value == NULL) {
m_type = GF_STRING;
}
else {
int32_t encodedLen = DataOutput::getEncodedLength(value, len, &m_len);
if (encodedLen > 0xFFFF) {
m_type = GF_WIDESTRING_HUGE;
}
else {
m_type = GF_WIDESTRING;
}
m_str = value;
}
}
CacheableString::~CacheableString()
{
if (isCString()) {
delete [] (char*)m_str;
}
else {
GF_DEV_ASSERT(isWideString());
delete [] (wchar_t*)m_str;
}
}
int32_t CacheableString::logString(char* buffer, int32_t maxLength) const
{
if (isCString()) {
return ACE_OS::snprintf(buffer, maxLength, "%s( %s )", className(), (m_str
!= NULL ? (const char*)m_str : "null"));
}
else {
GF_DEV_ASSERT(isWideString());
int32_t numChars = ACE_OS::snprintf(buffer, maxLength, "%s( ", className());
if (numChars >= (int) maxLength || numChars <= 0) {
return numChars;
}
const char* bufStart = buffer;
buffer += numChars;
maxLength -= numChars;
numChars = Utils::logWideString(buffer, maxLength, (const wchar_t*) m_str);
if (numChars >= (int) maxLength || numChars <= 0) {
return numChars + static_cast<int32_t> (buffer - bufStart);
}
buffer += numChars;
maxLength -= numChars;
numChars = ACE_OS::snprintf(buffer, maxLength, " )");
return numChars + static_cast<int32_t> (buffer - bufStart);
}
}
uint32_t CacheableString::objectSize() const
{
uint32_t size = sizeof(CacheableString);
if (isCString()) {
size += (sizeof(char) * m_len);
}
else {
GF_DEV_ASSERT(isWideString());
size += (sizeof(wchar_t) * m_len);
}
return size;
}