00001 /* 00002 * Copyright (c) 2000, 2020, Oracle and/or its affiliates. 00003 * 00004 * Licensed under the Universal Permissive License v 1.0 as shown at 00005 * http://oss.oracle.com/licenses/upl. 00006 */ 00007 #ifndef COH_STRING_HPP 00008 #define COH_STRING_HPP 00009 00010 #include "coherence/lang/compatibility.hpp" 00011 00012 #include "coherence/lang/Array.hpp" 00013 #include "coherence/lang/Comparable.hpp" 00014 #include "coherence/lang/Object.hpp" 00015 00016 #include <memory> 00017 00018 #include <sstream> 00019 #include <string> 00020 00021 COH_OPEN_NAMESPACE2(coherence,lang) 00022 00023 /** 00024 * @internal 00025 * 00026 * Used to protect protected inheritance of Array<octet_t> by String, as 00027 * spec based class definitions don't have a notion of protected 00028 * inheritance. 00029 */ 00030 class COH_EXPORT_SPEC ProtectedOctetArray 00031 : protected Array<octet_t> 00032 { 00033 public: 00034 typedef Array<octet_t>::super super; 00035 typedef Array<octet_t>::alias alias; 00036 00037 protected: 00038 ProtectedOctetArray(size32_t cb, octet_t* ab) 00039 : Array<octet_t>(cb, ab) 00040 {} 00041 00042 ProtectedOctetArray(ProtectedOctetArray::View vThat, 00043 size32_t iFrom, size32_t iTo) 00044 : Array<octet_t>(vThat, iFrom, iTo) 00045 {} 00046 00047 virtual ~ProtectedOctetArray() 00048 {} 00049 }; 00050 00051 00052 /** 00053 * A managed C-style (NUL terminated) string. 00054 * 00055 * In addition to exposing the underlying char array, the String class 00056 * supports transformations to and from Unicode code points within the Basic 00057 * Multilingual Plane (BMP): 00058 * 00059 * <ul> 00060 * <li>UTF-8 BMP char array</li> 00061 * <li>UTF-16 BMP wchar_t array (on platforms where wchar_t is >= 16 bits)</li> 00062 * <li>UTF-8 BMP octet_t array</li> 00063 * <li>UTF-16 BMP wchar16_t array</li> 00064 * </ul> 00065 * 00066 * Note: the ASCII character set is a subset of UTF-8 BMP. 00067 * 00068 * Unlike most managed types in the Coherence class hierarchy, Strings are 00069 * auto-boxable by default. That is a String::Handle or String::View can be 00070 * directly assigned from or to common string representations. For example 00071 * the following code is legal: 00072 * @code 00073 * String::Handle hs = "hello world"; 00074 * @endcode 00075 * as is 00076 * @code 00077 * void someFunction(String::View vs); 00078 * 00079 * someFunction("some value"); 00080 * @endcode 00081 * 00082 * @see StringHandle for details 00083 * 00084 * @author mf/jh/djl 2007.07.05 00085 */ 00086 class COH_EXPORT String 00087 : public cloneable_spec<String, 00088 extends<ProtectedOctetArray>, 00089 implements<Comparable> > 00090 { 00091 friend class factory<String>; 00092 00093 // ----- constants ------------------------------------------------------ 00094 00095 public: 00096 /** 00097 * The largest possible value of type size32_t. 00098 */ 00099 static const size32_t npos = size32_t(-1); 00100 00101 00102 // ----- typedefs ------------------------------------------------------- 00103 00104 public: 00105 /** 00106 * While StringHandle boxes a number of common string types, String is 00107 * still compatible with BoxHandle, and when used with it can box to 00108 * only one type. By default Strings are boxable from a number of 00109 * types, see StringHandle for details. 00110 */ 00111 typedef std::string BoxedType; 00112 00113 00114 // ----- nested class: StringHandle ------------------------------------- 00115 00116 public: 00117 /** 00118 * StringHandle provides standard TypedHandle features as well as 00119 * auto-boxing support for standard string types including: 00120 * 00121 * <ul> 00122 * <li>char[] C-style NUL terminated char array</li> 00123 * <li>std::string STL string</li> 00124 * <li>std::wstring STL wide string</li> 00125 * </ul> 00126 * 00127 * Boxing from wchar_t[] is supported, but requires an explicit 00128 * constructor call in order to avoid ambiguity when assigning a 00129 * String handle/view to NULL. 00130 * 00131 * Unboxing to char[] and wchar[] is not supported as it is unsafe to 00132 * maintain a reference to the underlying character array without 00133 * holding a reference to the String. Unboxing to std::string, and 00134 * std::wstring is both supported and safe. 00135 */ 00136 template<class T> class StringHandle 00137 : public TypedHandle<T> 00138 { 00139 // ----- constructors --------------------------------------- 00140 00141 public: 00142 /** 00143 * Create an empty StringHandle. 00144 */ 00145 StringHandle() 00146 : TypedHandle<T>() 00147 { 00148 } 00149 00150 /** 00151 * Create a new StringHandle from a boxable type. 00152 */ 00153 StringHandle(const char* ach) 00154 : TypedHandle<T>() 00155 { 00156 if (NULL != ach) 00157 { 00158 TypedHandle<T>::operator=(T::create(ach)); 00159 } 00160 } 00161 00162 /** 00163 * Create a new StringHandle from a boxable type. 00164 */ 00165 explicit StringHandle(const wchar_t* ach) 00166 : TypedHandle<T>() 00167 { 00168 if (NULL != ach) 00169 { 00170 TypedHandle<T>::operator=(T::create(ach)); 00171 } 00172 } 00173 00174 /** 00175 * Create a new StringHandle from a boxable type. 00176 */ 00177 template<class C, class R, class A> COH_INLINE 00178 StringHandle(const std::basic_string<C, R, A>& s) 00179 : TypedHandle<T>(T::create(s)) 00180 { 00181 } 00182 00183 /** 00184 * Create a new StringHandle from the TypedHandle with a type 00185 * conversion. 00186 */ 00187 template<class O> StringHandle<T>(const TypedHandle<O>& that) 00188 : TypedHandle<T>(that) 00189 { 00190 } 00191 00192 /** 00193 * The copy constructor. 00194 */ 00195 StringHandle(const StringHandle& that) 00196 : TypedHandle<T>(that) 00197 { 00198 } 00199 00200 /** 00201 * Create a new StringHandle from the raw pointer. 00202 */ 00203 explicit StringHandle(T* o) 00204 : TypedHandle<T>(o) 00205 { 00206 } 00207 00208 // ----- operators ------------------------------------------ 00209 00210 public: 00211 /** 00212 * The assignment operator. 00213 */ 00214 template<class O> 00215 StringHandle& operator=(const TypedHandle<O>& that) 00216 { 00217 TypedHandle<T>::operator=(that); 00218 return *this; 00219 } 00220 00221 /** 00222 * The "boxing" operator. 00223 */ 00224 StringHandle& operator=(const char* ach) 00225 { 00226 if (NULL == ach) 00227 { 00228 TypedHandle<T>::operator=(NULL); 00229 } 00230 else 00231 { 00232 TypedHandle<T>::operator=(T::create(ach)); 00233 } 00234 return *this; 00235 } 00236 00237 /** 00238 * The "boxing" operator. 00239 */ 00240 template<class C, class R, class A> COH_INLINE 00241 StringHandle& operator=(const std::basic_string<C, R, A>& s) 00242 { 00243 TypedHandle<T>::operator=(T::create(s)); 00244 return *this; 00245 } 00246 00247 /** 00248 * The "unboxing" operator. 00249 * 00250 * @return a copy of the referenced Object 00251 */ 00252 template<class C, class R, class A> COH_INLINE 00253 operator std::basic_string<C, R, A>() const 00254 { 00255 const T* pT = TypedHandle<T>::get(); 00256 if (NULL == pT) 00257 { 00258 coh_throw_npe(typeid(T)); 00259 } 00260 return (std::basic_string<C, R, A>) *pT; 00261 } 00262 }; 00263 00264 // ----- handle definitions --------------------------------------------- 00265 00266 public: 00267 /** 00268 * Handle definition. 00269 */ 00270 typedef StringHandle<String> Handle; 00271 00272 /** 00273 * View definition. 00274 */ 00275 typedef StringHandle<const String> View; 00276 00277 00278 // ----- factory methods ------------------------------------------------ 00279 00280 public: 00281 /** 00282 * Create a String from a C-style NUL terminated char array. 00283 * 00284 * @param ach the NUL terminated string of chars to copy 00285 * @param cch the number of chars to copy; if npos, until NUL 00286 * 00287 * @throws IllegalArgumentException if any of the elements in the 00288 * array are not UTF-8 BMP 00289 */ 00290 static String::Handle create(const char* achSrc = "", size32_t cch = npos); 00291 00292 /** 00293 * Create a String from a C-style NUL terminated wide char array. 00294 * 00295 * @param ach the NUL terminated string of wide chars to copy 00296 * @param cch the number of chars to copy; if npos, copy until NUL 00297 * 00298 * @throws IllegalArgumentException if any of the elements in the 00299 * array are not UTF-16 BMP 00300 */ 00301 static String::Handle create(const wchar_t* achSrc, size32_t cch = npos); 00302 00303 /** 00304 * Create a String from an STL string. 00305 * 00306 * @param s the STL string to copy 00307 * 00308 * @throws IllegalArgumentException if any of the elements in the 00309 * array are not UTF-8 BMP 00310 */ 00311 template<class C, class R, class A> static COH_INLINE 00312 String::Handle create(const std::basic_string<C, R, A>& s) 00313 { 00314 size_t cch = s.size(); 00315 if (cch >= npos) // for 64b 00316 { 00317 coh_throw_illegal_argument("maximum String length exceeded"); 00318 } 00319 return String::create(s.data(), size32_t(cch)); 00320 } 00321 00322 /** 00323 * Create a String from a char array. 00324 * 00325 * @param vach the array of chars to copy 00326 * @param of the offset at which to start copying 00327 * @param cch the number of chars to copy; if npos, copy all 00328 * subsequent chars in the array 00329 * 00330 * @throws IndexOutOfBoundsException if of > vach->length or if 00331 * cch < npos and of + cch > vach->length 00332 * @throws IllegalArgumentException if any of the elements in the 00333 * array are not UTF-8 BMP 00334 */ 00335 static String::Handle create(Array<char>::View vachSrc, 00336 size32_t of = 0, size32_t cch = npos); 00337 00338 /** 00339 * Create a String from a wide char array. 00340 * 00341 * @param vach the array of chars to copy 00342 * @param of the offset at which to start copying 00343 * @param cch the number of chars to copy; if npos, copy all 00344 * subsequent chars in the array 00345 * 00346 * @throws IndexOutOfBoundsException if of > vach->length or if 00347 * cch < npos and of + cch > vach->length 00348 * @throws IllegalArgumentException if any of the elements in the 00349 * array are not UTF-16 BMP 00350 * @throws UnsupportedOperationException if sizeof(wchar_t) < 00351 * sizeof(wchar16_t) 00352 */ 00353 static String::Handle create(Array<wchar_t>::View vachSrc, 00354 size32_t of = 0, size32_t cch = npos); 00355 00356 /** 00357 * Create a String from an octet array. 00358 * 00359 * @param vab the array of octets to copy 00360 * @param of the offset at which to start copying 00361 * @param cb the number of octets to copy; if npos, copy all 00362 * subsequent octets in the array 00363 * 00364 * @throws IndexOutOfBoundsException if of > vab->length or if 00365 * cb < npos and of + cb > vab->length 00366 * @throws IllegalArgumentException if any of the elements in the 00367 * array are not UTF-8 BMP 00368 */ 00369 static String::Handle create(Array<octet_t>::View vabSrc, 00370 size32_t of = 0, size32_t cb = npos); 00371 00372 /** 00373 * Create a String from a 16-bit char array. 00374 * 00375 * @param vach the array of chars to copy 00376 * @param of the offset at which to start copying 00377 * @param cch the number of chars to copy; if npos, copy all 00378 * subsequent chars in the array 00379 * 00380 * @throws IndexOutOfBoundsException if of > vach->length or if 00381 * cch < npos and of + cch > vach->length 00382 * @throws IllegalArgumentException if any of the elements in the 00383 * array are not UTF-16 BMP 00384 */ 00385 static String::Handle create(Array<wchar16_t>::View vachSrc, 00386 size32_t of = 0, size32_t cch = npos); 00387 00388 /** 00389 * Create a String from another String. 00390 * 00391 * Needed for clone(). 00392 * 00393 * @param that the String to copy 00394 * 00395 * @since Coherence 3.7.1.8 00396 */ 00397 static String::Handle create(const String& that); 00398 00399 00400 // ----- constructors --------------------------------------------------- 00401 00402 private: 00403 /** 00404 * Constructor. 00405 * 00406 * @param ccp the number of code points in the string 00407 * @param cb the number of octets in the string 00408 * @param ab the String's octets 00409 * @param fCs true if ab represents a c string 00410 */ 00411 String(size32_t ccp, size32_t cb, octet_t* ab, bool fCs); 00412 00413 /** 00414 * Copy constructor. 00415 */ 00416 String(const String& that); 00417 00418 00419 // ----- String interface ----------------------------------------------- 00420 00421 public: 00422 /** 00423 * Return true iff the String contains only ASCII (ISO-8859-1) 00424 * characters. In this case each character is represented by a single 00425 * char, otherwise a character can take between one and three chars. 00426 * 00427 * @return true iff the String contains only ASCII characters 00428 */ 00429 virtual bool isASCII() const; 00430 00431 /** 00432 * Return true if the String is ASCII and does not contain embedded nuls. 00433 * 00434 * @return true if the String is a C string. 00435 */ 00436 virtual bool isCString() const; 00437 00438 /** 00439 * Return the number of unicode code points (characters) in this String. 00440 * 00441 * @return the number of characters in this String 00442 */ 00443 virtual size32_t length() const; 00444 00445 /** 00446 * Returns true if, and only if, length() is 0. 00447 * 00448 * @return true if length() is 0, otherwise false 00449 * 00450 * @since 12.2.1 00451 */ 00452 virtual bool isEmpty() const; 00453 00454 /** 00455 * Return the String as a C-style NUL terminated char array. 00456 * 00457 * If the String is non-ASCII then the String::next() method may be 00458 * used to expand the char array into a sequence of wchar16_t unicode 00459 * characters. 00460 * 00461 * The returned array's lifetime is bound to the lifetime of the 00462 * String which it was returned from. Specifically it is unsafe to use 00463 * the returned char* while not holding a handle to the String. 00464 * 00465 * @return the char array representing the String. 00466 */ 00467 virtual const char* getCString() const; 00468 00469 /** 00470 * Compare this String against the supplied C-style string. 00471 * 00472 * @param ach the NUL terminated C-style string to compare to this 00473 * String 00474 * @param cch the length of the supplied string, or npos to rely on 00475 * NUL terminator 00476 * 00477 * @return true iff the two strings are identical 00478 */ 00479 virtual bool equals(const char* ach, size32_t cch = npos) const; 00480 00481 /** 00482 * Compare this String against the supplied C-style wide char string. 00483 * 00484 * @param ach the NUL terminated C-style string to compare to this 00485 * String 00486 * @param cch the length of the supplied string, or npos to rely on 00487 * NUL terminator 00488 * 00489 * @return true iff the two strings are identical 00490 * 00491 * @throws UnsupportedOperationException if sizeof(wchar_t) < sizeof(wchar16_t) 00492 */ 00493 virtual bool equals(const wchar_t* ach, size32_t cch = npos) const; 00494 00495 /** 00496 * Compare this String against the supplied STL string or wstring. 00497 * 00498 * @param s the STL string to compare to this String 00499 * 00500 * @return true iff the two strings are identical 00501 */ 00502 template<class C, class R, class A> COH_INLINE 00503 bool equalsStd(const std::basic_string<C, R, A>& s) const 00504 { 00505 size_t cch = s.size(); 00506 return cch < npos && equals(s.data(), size32_t(cch)); 00507 } 00508 00509 /** 00510 * Convert the String to any of the types supported by StringHandle, 00511 * namely an STL string or wstring. 00512 * 00513 * @return the std::string/wstring representation 00514 */ 00515 template<class C, class R, class A> COH_INLINE 00516 operator std::basic_string<C, R, A>() const 00517 { 00518 if (sizeof(C) == sizeof(octet_t)) 00519 { 00520 return std::basic_string<C, R, A>((const C*) getCString(), 00521 super::length - 1); 00522 } 00523 00524 if (sizeof(C) < sizeof(wchar16_t)) 00525 { 00526 coh_throw_unsupported_operation("unsupported string type"); 00527 } 00528 00529 typename std::basic_string<C, R, A>::size_type cch = 00530 typename std::basic_string<C, R, A>::size_type(length()); 00531 const char* iter = getCString(); 00532 std::basic_string<C, R, A> ws; 00533 ws.reserve(cch); 00534 for (typename std::basic_string<C, R, A>::size_type 00535 i = 0; i < cch; ++i) 00536 { 00537 ws.push_back((C) String::next(iter)); 00538 } 00539 return ws; 00540 } 00541 00542 /** 00543 * Return the index of a substring within this String. 00544 * 00545 * @param vsSearch the substring to search for in vsSource 00546 * @param iBegin the location in the string to start searching 00547 * 00548 * @return the index of the substring found within this String or npos 00549 */ 00550 virtual size32_t indexOf(String::View vsSearch, 00551 size32_t iBegin = 0) const; 00552 00553 /** 00554 * Return the index of a character within this String. 00555 * 00556 * @param chSearch the character to search for in this String 00557 * @param iBegin the location in this String to start searching 00558 * 00559 * @return the index of the character found within this String or npos 00560 */ 00561 virtual size32_t indexOf(wchar16_t chSearch, 00562 size32_t iBegin = 0) const; 00563 00564 /** 00565 * Return the index of a substring within this String by searching 00566 * backward from the given beginning index. 00567 * 00568 * @param vsSearh the substring to search for within this String 00569 * @param iBegin the location in this String to start searching 00570 * 00571 * @return the index of the substring found within this String or npos 00572 */ 00573 virtual size32_t lastIndexOf(String::View vsSearch, 00574 size32_t iBegin = npos) const; 00575 00576 /** 00577 * Return the index of a substring within this String by searching 00578 * backward from the given beginning index. 00579 * 00580 * @param chSearch the character to search for in this String 00581 * @param iBegin the location in this String to start searching 00582 * 00583 * @return the index of the character found within this String or npos 00584 */ 00585 virtual size32_t lastIndexOf(wchar16_t chSearch, 00586 size32_t iBegin = npos) const; 00587 00588 /** 00589 * Return a new String that is a substring of this string. The substring 00590 * begins at the specified iBegin and extends to the character at 00591 * index iEnd - 1. Thus the length of the substring is iEnd-iBegin. 00592 * 00593 * @param iBegin the starting index from which to create the string 00594 * @param iEnd the index of where the substring should stop 00595 * in this String or npos for end of string 00596 * 00597 * @throws IndexOutOfBoundsException if iEnd is larger than the length 00598 * of this String object, or if iBegin 00599 * is larger than iEnd. 00600 * 00601 * @return the new substring created from this String 00602 */ 00603 virtual String::View substring(size32_t iBegin, 00604 size32_t iEnd = npos) const; 00605 00606 /** 00607 * Return true if this String starts with the supplied String. 00608 * 00609 * @param vsSearch the string to search for 00610 * 00611 * @return true if this String starts with vsSearch 00612 */ 00613 virtual bool startsWith(String::View vsSearch) const; 00614 00615 /** 00616 * Return true if this String ends with the supplied String. 00617 * 00618 * @param vsSearch the string to search for 00619 * 00620 * @return true if this String ends with vsSearch 00621 */ 00622 virtual bool endsWith(String::View vsSearch) const; 00623 00624 /** 00625 * A substring of this String is compared to a substring of a supplied 00626 * String. 00627 * 00628 * @param ofSource the offset in this String where comparison begins 00629 * @param vsOther the String whose substring is compared against 00630 * this String 00631 * @param ofOther the offset in vsOther where comparison begins 00632 * @param cch the count of characters to compare, or npos for 00633 * (vsOther->length - ofOther) 00634 * 00635 * @return the result of the two substrings 00636 */ 00637 virtual bool regionMatches(size32_t ofSourse, 00638 String::View vsOther, size32_t ofOther = 0, 00639 size32_t cch = npos) const; 00640 00641 /** 00642 * Return a String that is the result of removing all leading and 00643 * trailing white space. 00644 * 00645 * @return a trimmed copy of this String 00646 */ 00647 String::View trim() const; 00648 00649 /** 00650 * Return the underlying UTF-8 BMP NUL terminated Array<octet_t>. 00651 * 00652 * For performance reasons the returned Array may not support cloning. 00653 * If clone() is called the result will a String, which depending on 00654 * the compiler's handling of dynamic_cast to a private super class may 00655 * fail to be castable to an Array<octet_t>. 00656 * 00657 * @return the Array<octet_t> 00658 */ 00659 virtual Array<octet_t>::View getOctets() const; 00660 00661 // ----- static methods ------------------------------------------------- 00662 00663 public: 00664 /** 00665 * Returns the string representation of the {@code v} argument. 00666 * 00667 * @param v an Object. 00668 * 00669 * @return if the argument is {@code NULL}, then a string equal to 00670 * {@code "NULL"}; otherwise, the value of 00671 * {@code v->toString()} is returned 00672 * 00673 * @see Object#toString() 00674 * 00675 * @since 12.2.1 00676 */ 00677 static String::View valueOf(Object::View v); 00678 00679 // ----- Array interface ------------------------------------------------ 00680 00681 protected: 00682 using Array<octet_t>::regionMatches; 00683 00684 00685 // ----- Comparable interface ------------------------------------------- 00686 00687 public: 00688 /** 00689 * {@inheritDoc} 00690 */ 00691 virtual int32_t compareTo(Object::View v) const; 00692 00693 00694 // ----- Object interface ----------------------------------------------- 00695 00696 public: 00697 /** 00698 * {@inheritDoc} 00699 */ 00700 virtual size32_t hashCode() const; 00701 00702 /** 00703 * {@inheritDoc} 00704 */ 00705 virtual TypedHandle<const String> toString() const; 00706 00707 /** 00708 * {@inheritDoc} 00709 */ 00710 virtual bool isImmutable() const; 00711 00712 /** 00713 * {@inheritDoc} 00714 */ 00715 virtual bool equals(Object::View v) const; 00716 00717 /** 00718 * {@inheritDoc} 00719 */ 00720 virtual size64_t sizeOf(bool fDeep = false) const; 00721 00722 // ----- static helpers ------------------------------------------------- 00723 00724 public: 00725 /** 00726 * Return the Unicode character as UTF-16 from the char array, and 00727 * increment the pointer such that it references the start of the 00728 * next Unicode character. 00729 * 00730 * @param ach pointer to the start of the next UTF-8 code point. 00731 * 00732 * @return the next Unicode character 00733 * 00734 * @throws IllegalArgumentException if a non UTF-8 BMP sequence is 00735 * encountered 00736 */ 00737 static wchar16_t next(const char*& ach); 00738 00739 00740 // ----- data members --------------------------------------------------- 00741 00742 protected: 00743 /** 00744 * The number of unicode code points (characters) in the String. 00745 */ 00746 size32_t m_ccp; 00747 00748 /** 00749 * True iff the String is a C string. 00750 */ 00751 bool m_fCString; 00752 00753 00754 // ----- constants ------------------------------------------------------ 00755 00756 public: 00757 /** 00758 * String referencing NULL. 00759 * 00760 * This constant is generally only needed for defining a default 00761 * value for a function parameter: 00762 * 00763 * @code 00764 * void function(String::View vs = String::null_string) 00765 * @endcode 00766 * 00767 * Simply passing NULL as a default is not allowable for Strings as due 00768 * to auto-boxing the compiler is unable to determine if NULL indicates 00769 * a String* or a char*. For all other uses of NULL with String the 00770 * literal NULL is preferred. 00771 */ 00772 static const char* const null_string; 00773 }; 00774 00775 00776 // ----- non-member operators and functions --------------------------------- 00777 00778 /** 00779 * Output a human-readable description of the specified Object to the given 00780 * stream. 00781 * 00782 * @param out the stream used to output the description 00783 * @param o the Object to describe 00784 * 00785 * @return the supplied stream 00786 */ 00787 COH_INLINE std::ostream& operator<<(std::ostream& out, const Object& o) 00788 { 00789 // legacy support for deprecated toStream method, test if toStream or toString has been overridden 00790 // this is relatively expensive and will be removed in a future release when toStream is removed 00791 std::stringstream ss; 00792 o.toStream(ss); // no-op on Object 00793 if (ss.tellp() <= 0) // common case - on empty stream STLport returns -1; others return 0 00794 { 00795 // toStream has not been overridden, use toString 00796 String::View vs = o.toString(); // ensure String stays alive while working with the c string 00797 if (vs->isCString()) // NUL terminated ASCII 00798 { 00799 out << vs->getCString(); 00800 } 00801 else if (vs->isASCII()) // ASCII with embedded NULs 00802 { 00803 const char* pch = vs->getCString(); 00804 for (size32_t i = 0, c = vs->length(); i < c; ++i) 00805 { 00806 out << pch[i]; 00807 } 00808 } 00809 else // unicode, "inherit" however std::string outputs embedded unicode to an ostream 00810 { 00811 std::string s = vs; 00812 out << s; 00813 } 00814 } 00815 else // toStream wrote output (was overridden) 00816 { 00817 out << ss.str(); 00818 } 00819 return out; 00820 } 00821 00822 /** 00823 * Output a human-readable description of the specified Object to the given 00824 * stream. 00825 * 00826 * @param out the stream used to output the description 00827 * @param o the Object to describe 00828 * 00829 * @return the supplied stream 00830 */ 00831 COH_INLINE std::wostream& operator<<(std::wostream& out, const Object& o) 00832 { 00833 String::View vs = o.toString(); // ensure String stays alive while working with the c string 00834 const char* pch = vs->getCString(); 00835 if (vs->isCString()) // NUL terminated ASCII 00836 { 00837 out << pch; 00838 } 00839 else if (vs->isASCII()) // ASCII with embedded NULs 00840 { 00841 for (size32_t i = 0, c = vs->length(); i < c; ++i) 00842 { 00843 out << pch[i]; 00844 } 00845 } 00846 else // unicode, decode to wchars 00847 { 00848 for (size32_t i = 0, c = vs->length(); i < c; ++i) 00849 { 00850 out << wchar_t(String::next(pch)); 00851 } 00852 } 00853 return out; 00854 } 00855 00856 // ----- helper macros ------------------------------------------------------ 00857 00858 /** 00859 * This macro will take any set of wstreamable contents and turn them into a 00860 * coherence#lang#String instance. 00861 * 00862 * @param CONTENTS the contents to use in constructing the String. 00863 * 00864 * Usage example: 00865 * @code 00866 * String::Handle hsFoo = COH_TO_WIDE_STRING("This value: " << 5 << " is my value"); 00867 * @endcode 00868 */ 00869 #define COH_TO_WIDE_STRING(CONTENTS) \ 00870 coherence::lang::String::create(((std::wstringstream&) \ 00871 (*(COH_AUTO_PTR<std::wstringstream>(new std::wstringstream())) \ 00872 << CONTENTS)).str()) 00873 00874 /** 00875 * This macro will take any set of streamable contents and turn them into a 00876 * coherence#lang#String instance. 00877 * 00878 * @param CONTENTS the contents to use in constructing the String. 00879 * 00880 * Usage example: 00881 * @code 00882 * String::Handle hsFoo = COH_TO_NARROW_STRING("This value: " << 5 << " is my value"); 00883 * @endcode 00884 */ 00885 #define COH_TO_NARROW_STRING(CONTENTS) \ 00886 coherence::lang::String::create(((std::stringstream&) \ 00887 (*(COH_AUTO_PTR<std::stringstream>(new std::stringstream())) \ 00888 << CONTENTS)).str()) 00889 00890 /** 00891 * Compile time option to select the default operator<< to use. If COH_DEFAULT_NARROW_TO_STRING 00892 * is defined then the COH_TO_STRING macro will only require operator<< to be defined 00893 * for std::ostream, alternatively if COH_DEFAULT_WIDE_TO_STRING is then operator<< must be 00894 * defined for std::wostream. The preferable choice is to implement them both via a single template 00895 * based implementation: 00896 * 00897 * template <typename Char, typename Traits> std::basic_ostream<Char, Traits>& 00898 * operator<<(std::basic_ostream<Char, Traits>& out, const your_class& v) 00899 * 00900 * Note all managed classes deriving from Object (including Managed) are already compatible 00901 * with both stream types, the above operators only need be defined for non-managed 00902 * classes. 00903 */ 00904 #if defined(COH_DEFAULT_NARROW_TO_STRING) 00905 #define COH_TO_STRING(CONTENTS) COH_TO_NARROW_STRING(CONTENTS) 00906 #elif defined(COH_DEFAULT_WIDE_TO_STRING) 00907 #define COH_TO_STRING(CONTENTS) COH_TO_WIDE_STRING(CONTENTS) 00908 #elif defined(COH_BUILD) // default coherence internals build to wide 00909 #define COH_TO_STRING(CONTENTS) COH_TO_WIDE_STRING(CONTENTS) 00910 #else // default users to narrow not all types (includeing std::string) are compatible with std::wostream 00911 #define COH_TO_STRING(CONTENTS) COH_TO_NARROW_STRING(CONTENTS) 00912 #endif 00913 00914 COH_CLOSE_NAMESPACE2 00915 00916 #endif // COH_STRING_HPP