#ifndef ACE_STRING_BASE_CPP #define ACE_STRING_BASE_CPP #include "ace/ACE.h" #include "ace/Malloc_Base.h" #include "ace/String_Base.h" #include "ace/OS_NS_string.h" #include // For std::swap<> #if !defined (__ACE_INLINE__) #include "ace/String_Base.inl" #endif /* __ACE_INLINE__ */ ACE_BEGIN_VERSIONED_NAMESPACE_DECL ACE_ALLOC_HOOK_DEFINE_Tc(ACE_String_Base) template ACE_CHAR_T ACE_String_Base::NULL_String_ = 0; // Default constructor. template ACE_String_Base::ACE_String_Base (ACE_Allocator *the_allocator) : allocator_ (the_allocator ? the_allocator : ACE_Allocator::instance ()), len_ (0), buf_len_ (0), rep_ (&ACE_String_Base::NULL_String_), release_ (false) { ACE_TRACE ("ACE_String_Base::ACE_String_Base"); } // Constructor that actually copies memory. template ACE_String_Base::ACE_String_Base (const ACE_CHAR_T *s, ACE_Allocator *the_allocator, bool release) : allocator_ (the_allocator ? the_allocator : ACE_Allocator::instance ()), len_ (0), buf_len_ (0), rep_ (0), release_ (false) { ACE_TRACE ("ACE_String_Base::ACE_String_Base"); this->set (s, release); } template ACE_String_Base::ACE_String_Base (ACE_CHAR_T c, ACE_Allocator *the_allocator) : allocator_ (the_allocator ? the_allocator : ACE_Allocator::instance ()), len_ (0), buf_len_ (0), rep_ (0), release_ (false) { ACE_TRACE ("ACE_String_Base::ACE_String_Base"); this->set (&c, 1, true); } // Constructor that actually copies memory. template ACE_String_Base::ACE_String_Base ( const ACE_CHAR_T *s, typename ACE_String_Base::size_type len, ACE_Allocator *the_allocator, bool release) : allocator_ (the_allocator ? the_allocator : ACE_Allocator::instance ()), len_ (0), buf_len_ (0), rep_ (nullptr), release_ (false) { ACE_TRACE ("ACE_String_Base::ACE_String_Base"); this->set (s, len, release); } // Copy constructor. template ACE_String_Base::ACE_String_Base (const ACE_String_Base &s) : allocator_ (s.allocator_ ? s.allocator_ : ACE_Allocator::instance ()), len_ (0), buf_len_ (0), rep_ (nullptr), release_ (false) { ACE_TRACE ("ACE_String_Base::ACE_String_Base"); this->set (s.rep_, s.len_, true); } template ACE_String_Base::ACE_String_Base ( typename ACE_String_Base::size_type len, ACE_CHAR_T c, ACE_Allocator *the_allocator) : allocator_ (the_allocator ? the_allocator : ACE_Allocator::instance ()), len_ (0), buf_len_ (0), rep_ (nullptr), release_ (false) { ACE_TRACE ("ACE_String_Base::ACE_String_Base"); this->resize (len, c); } template ACE_String_Base::~ACE_String_Base () { ACE_TRACE ("ACE_String_Base::~ACE_String_Base"); if (this->buf_len_ != 0 && this->release_) this->allocator_->free (this->rep_); } // this method might benefit from a little restructuring. template void ACE_String_Base::set (const ACE_CHAR_T *s, typename ACE_String_Base::size_type len, bool release) { // Case 1. Going from memory to more memory size_type const new_buf_len = len + 1; if (s != 0 && len != 0 && release && this->buf_len_ < new_buf_len) { ACE_CHAR_T *temp = nullptr; ACE_ALLOCATOR (temp, (ACE_CHAR_T *) this->allocator_->malloc (new_buf_len * sizeof (ACE_CHAR_T))); if (this->buf_len_ != 0 && this->release_) this->allocator_->free (this->rep_); this->rep_ = temp; this->buf_len_ = new_buf_len; this->release_ = true; this->len_ = len; ACE_OS::memcpy (this->rep_, s, len * sizeof (ACE_CHAR_T)); this->rep_[len] = 0; } else // Case 2. No memory allocation is necessary. { // Free memory if necessary and figure out future ownership if (!release || s == 0 || len == 0) { if (this->buf_len_ != 0 && this->release_) { this->allocator_->free (this->rep_); this->release_ = false; } } // Populate data. if (s == 0 || len == 0) { this->buf_len_ = 0; this->len_ = 0; this->rep_ = &ACE_String_Base::NULL_String_; this->release_ = false; } else if (!release) // Note: No guarantee that rep_ is null terminated. { this->buf_len_ = len; this->len_ = len; this->rep_ = const_cast (s); this->release_ = false; } else { ACE_OS::memcpy (this->rep_, s, len * sizeof (ACE_CHAR_T)); this->rep_[len] = 0; this->len_ = len; } } } // Return substring. template ACE_String_Base ACE_String_Base::substring ( typename ACE_String_Base::size_type offset, typename ACE_String_Base::size_type length) const { ACE_String_Base nill; size_type count = length; // case 1. empty string if (this->len_ == 0) return nill; // case 2. start pos past our end if (offset >= this->len_) return nill; // No length == empty string. else if (length == 0) return nill; // Get all remaining bytes. else if (length == npos || count > (this->len_ - offset)) count = this->len_ - offset; return ACE_String_Base (&this->rep_[offset], count, this->allocator_); } template ACE_String_Base & ACE_String_Base::append (const ACE_CHAR_T* s, typename ACE_String_Base::size_type slen) { ACE_TRACE ("ACE_String_Base::append(const ACE_CHAR_T*, size_type)"); if (slen > 0 && slen != npos) { // case 1. No memory allocation needed. if (this->buf_len_ >= this->len_ + slen + 1) { // Copy in data from new string. ACE_OS::memcpy (this->rep_ + this->len_, s, slen * sizeof (ACE_CHAR_T)); } else // case 2. Memory reallocation is needed { const size_type new_buf_len = ace_max(this->len_ + slen + 1, this->buf_len_ + this->buf_len_ / 2); ACE_CHAR_T *t = 0; ACE_ALLOCATOR_RETURN (t, (ACE_CHAR_T *) this->allocator_->malloc (new_buf_len * sizeof (ACE_CHAR_T)), *this); // Copy memory from old string into new string. ACE_OS::memcpy (t, this->rep_, this->len_ * sizeof (ACE_CHAR_T)); ACE_OS::memcpy (t + this->len_, s, slen * sizeof (ACE_CHAR_T)); if (this->buf_len_ != 0 && this->release_) this->allocator_->free (this->rep_); this->release_ = true; this->rep_ = t; this->buf_len_ = new_buf_len; } this->len_ += slen; this->rep_[this->len_] = 0; } return *this; } template u_long ACE_String_Base::hash () const { return ACE::hash_pjw (reinterpret_cast ( const_cast (this->rep_)), this->len_ * sizeof (ACE_CHAR_T)); } template void ACE_String_Base::resize (typename ACE_String_Base::size_type len, ACE_CHAR_T c) { ACE_TRACE ("ACE_String_Base::resize"); fast_resize(len); ACE_OS::memset (this->rep_, c, this->buf_len_ * sizeof (ACE_CHAR_T)); } template void ACE_String_Base::fast_resize (size_t len) { ACE_TRACE ("ACE_String_Base::fast_resize"); // Only reallocate if we don't have enough space... if (this->buf_len_ <= len) { if (this->buf_len_ != 0 && this->release_) this->allocator_->free (this->rep_); this->rep_ = static_cast (this->allocator_->malloc ((len + 1) * sizeof (ACE_CHAR_T))); this->buf_len_ = len + 1; this->release_ = true; } this->len_ = 0; if (len > 0) this->rep_[0] = 0; } template void ACE_String_Base::clear (bool release) { // This can't use set(), because that would free memory if release=false if (release) { if (this->buf_len_ != 0 && this->release_) this->allocator_->free (this->rep_); this->rep_ = &ACE_String_Base::NULL_String_; this->len_ = 0; this->buf_len_ = 0; this->release_ = false; } else { this->fast_clear (); } } // Assignment operator (does copy memory). template ACE_String_Base & ACE_String_Base::operator= (const ACE_CHAR_T *s) { ACE_TRACE ("ACE_String_Base::operator="); if (s != 0) this->set (s, true); return *this; } // Assignment operator (does copy memory). template ACE_String_Base & ACE_String_Base::operator= (const ACE_String_Base &s) { ACE_TRACE ("ACE_String_Base::operator="); // Check for self-assignment. if (this != &s) { this->set (s.rep_, s.len_, true); } return *this; } template void ACE_String_Base::set (const ACE_CHAR_T *s, bool release) { size_t length = 0; if (s != 0) length = ACE_OS::strlen (s); this->set (s, length, release); } template void ACE_String_Base::fast_clear () { this->len_ = 0; if (this->release_) { // String retains the original buffer. if (this->rep_ != &ACE_String_Base::NULL_String_) this->rep_[0] = 0; } else { // External buffer: string relinquishes control of it. this->buf_len_ = 0; this->rep_ = &ACE_String_Base::NULL_String_; } } // Get a copy of the underlying representation. template ACE_CHAR_T * ACE_String_Base::rep () const { ACE_TRACE ("ACE_String_Base::rep"); ACE_CHAR_T *new_string; #if defined (ACE_HAS_ALLOC_HOOKS) ACE_ALLOCATOR_RETURN (new_string, static_cast(ACE_Allocator::instance()->malloc(sizeof(ACE_CHAR_T) * (this->len_ + 1))), 0); #else ACE_NEW_RETURN (new_string, ACE_CHAR_T[this->len_ + 1], 0); #endif ACE_OS::strsncpy (new_string, this->rep_, this->len_+1); return new_string; } template int ACE_String_Base::compare (const ACE_String_Base &s) const { ACE_TRACE ("ACE_String_Base::compare"); if (this->rep_ == s.rep_) return 0; // Pick smaller of the two lengths and perform the comparison. size_type smaller_length = ace_min (this->len_, s.len_); int result = ACE_OS::memcmp (this->rep_, s.rep_, smaller_length * sizeof (ACE_CHAR_T)); if (result == 0 && this->len_ != s.len_) result = this->len_ > s.len_ ? 1 : -1; return result; } // Comparison operator. template bool ACE_String_Base::operator== (const ACE_String_Base &s) const { return this->len_ == s.len_ && ACE_OS::memcmp (this->rep_, s.rep_, this->len_ * sizeof (ACE_CHAR_T)) == 0; } template bool ACE_String_Base::operator== (const ACE_CHAR_T *s) const { size_t len = ACE_OS::strlen (s); return this->len_ == len && ACE_OS::memcmp (this->rep_, s, len * sizeof (ACE_CHAR_T)) == 0; } template typename ACE_String_Base::size_type ACE_String_Base::find ( const ACE_CHAR_T *s, typename ACE_String_Base::size_type pos) const { ACE_CHAR_T *substr = this->rep_ + pos; size_t len = ACE_OS::strlen (s); ACE_CHAR_T *pointer = ACE_OS::strnstr (substr, s, len); if (pointer == 0) return ACE_String_Base::npos; else return pointer - this->rep_; } template typename ACE_String_Base::size_type ACE_String_Base::find ( ACE_CHAR_T c, typename ACE_String_Base::size_type pos) const { ACE_CHAR_T *substr = this->rep_ + pos; ACE_CHAR_T *pointer = ACE_OS::strnchr (substr, c, this->len_ - pos); if (pointer == 0) return ACE_String_Base::npos; else return pointer - this->rep_; } template typename ACE_String_Base::size_type ACE_String_Base::rfind ( ACE_CHAR_T c, typename ACE_String_Base::size_type pos) const { if (pos == npos || pos > this->len_) pos = this->len_; // Do not change to prefix operator! Proper operation of this loop // depends on postfix decrement behavior. for (size_type i = pos; i-- != 0; ) if (this->rep_[i] == c) return i; return ACE_String_Base::npos; } template void ACE_String_Base::swap (ACE_String_Base & str) { std::swap (this->allocator_ , str.allocator_); std::swap (this->len_ , str.len_); std::swap (this->buf_len_ , str.buf_len_); std::swap (this->rep_ , str.rep_); std::swap (this->release_ , str.release_); } // ---------------------------------------------- template int ACE_String_Base_Iterator ::next (ACE_CHAR_T * & ch) const { ACE_TRACE ("ACE_String_Base_Iterator::next"); if (0 == this->done ()) { ch = &this->str_->rep_[this->index_]; return 1; } else { ch = 0; return 0; } } template int ACE_String_Base_Iterator ::advance () { ACE_TRACE ("ACE_String_Base_Iterator::advance"); if (this->index_ < this->str_->length ()) { ++ this->index_; return 1; } else { return 0; } } template const ACE_String_Base_Iterator & ACE_String_Base_Iterator :: operator = (const ACE_String_Base_Iterator & rhs) { ACE_TRACE ("ACE_String_Base_Iterator::operator ="); if (this == &rhs) return *this; this->str_ = rhs.str_; this->index_ = rhs.index_; return *this; } // ---------------------------------------------- template int ACE_String_Base_Const_Iterator ::next (const ACE_CHAR_T * & ch) const { ACE_TRACE ("ACE_String_Base_Const_Iterator::next"); if (0 == this->done ()) { ch = &this->str_->rep_[this->index_]; return 1; } else { ch = 0; return 0; } } template int ACE_String_Base_Const_Iterator ::advance () { ACE_TRACE ("ACE_String_Base_Const_Iterator::advance"); if (this->index_ < this->str_->length ()) { ++ this->index_; return 1; } else { return 0; } } template const ACE_String_Base_Const_Iterator & ACE_String_Base_Const_Iterator :: operator = (const ACE_String_Base_Const_Iterator & rhs) { ACE_TRACE ("ACE_String_Base_Const_Iterator::operator ="); if (this == &rhs) return *this; this->str_ = rhs.str_; this->index_ = rhs.index_; return *this; } // ---------------------------------------------- template ACE_String_Base operator+ (const ACE_String_Base &s, const ACE_String_Base &t) { ACE_String_Base temp (s.length () + t.length ()); temp += s; temp += t; return temp; } template ACE_String_Base operator+ (const ACE_CHAR_T *s, const ACE_String_Base &t) { size_t slen = 0; if (s != 0) slen = ACE_OS::strlen (s); ACE_String_Base temp (slen + t.length ()); if (slen > 0) temp.append (s, slen); temp += t; return temp; } template ACE_String_Base operator+ (const ACE_String_Base &s, const ACE_CHAR_T *t) { size_t tlen = 0; if (t != 0) tlen = ACE_OS::strlen (t); ACE_String_Base temp (s.length () + tlen); temp += s; if (tlen > 0) temp.append (t, tlen); return temp; } template ACE_String_Base operator + (const ACE_String_Base &t, const ACE_CHAR_T c) { ACE_String_Base temp (t.length () + 1); temp += t; temp += c; return temp; } template ACE_String_Base operator + (const ACE_CHAR_T c, const ACE_String_Base &t) { ACE_String_Base temp (t.length () + 1); temp += c; temp += t; return temp; } template ACE_String_Base & ACE_String_Base::operator+= (const ACE_CHAR_T* s) { size_t slen = 0; if (s != 0) slen = ACE_OS::strlen (s); return this->append (s, slen); } template ACE_String_Base & ACE_String_Base::operator+= (const ACE_String_Base &s) { ACE_TRACE ("ACE_String_Base::operator+=(const ACE_String_Base &)"); return this->append (s.rep_, s.len_); } template ACE_String_Base & ACE_String_Base::operator+= (const ACE_CHAR_T c) { ACE_TRACE ("ACE_String_Base::operator+=(const ACE_CHAR_T)"); const size_type slen = 1; // This temp is silly but it quiets an optimizer warning in IBM XL C++ 10. ACE_String_Base& r = this->append (&c, slen); return r; } ACE_END_VERSIONED_NAMESPACE_DECL #endif /* ACE_STRING_BASE_CPP */