You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

640 lines
19 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: winstl/conversion/int_to_string.hpp
  3. *
  4. * Purpose: WinSTL integer to string conversions.
  5. *
  6. * Created: 31st July 2002
  7. * Updated: 10th August 2009
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2002-2009, Matthew Wilson and Synesis Software
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright notice, this
  18. * list of conditions and the following disclaimer.
  19. * - Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  23. * any contributors may be used to endorse or promote products derived from
  24. * this software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * ////////////////////////////////////////////////////////////////////// */
  39. /** \file winstl/conversion/int_to_string.hpp
  40. *
  41. * \brief [C++ only] Very efficient integer to string conversion functions
  42. * for the Windows platform
  43. * (\ref group__library__conversion "Conversion" Library).
  44. */
  45. #ifndef WINSTL_INCL_WINSTL_CONVERSION_HPP_INT_TO_STRING
  46. #define WINSTL_INCL_WINSTL_CONVERSION_HPP_INT_TO_STRING
  47. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  48. # define _WINSTL_VER_WINSTL_CONVERSION_HPP_INT_TO_STRING_MAJOR 2
  49. # define _WINSTL_VER_WINSTL_CONVERSION_HPP_INT_TO_STRING_MINOR 1
  50. # define _WINSTL_VER_WINSTL_CONVERSION_HPP_INT_TO_STRING_REVISION 4
  51. # define _WINSTL_VER_WINSTL_CONVERSION_HPP_INT_TO_STRING_EDIT 41
  52. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  53. /* /////////////////////////////////////////////////////////////////////////
  54. * Compatibility
  55. */
  56. /*
  57. [Incompatibilies-start]
  58. STLSOFT_COMPILER_IS_BORLAND: __BORLANDC__<0x0560
  59. [Incompatibilies-end]
  60. */
  61. /* /////////////////////////////////////////////////////////////////////////
  62. * Includes
  63. */
  64. #ifndef WINSTL_INCL_WINSTL_H_WINSTL
  65. # include <winstl/winstl.h>
  66. #endif /* !WINSTL_INCL_WINSTL_H_WINSTL */
  67. #ifndef STLSOFT_INCL_STLSOFT_CONVERSION_HPP_INT_TO_STRING
  68. # include <stlsoft/conversion/integer_to_string.hpp>
  69. #endif /* !STLSOFT_INCL_STLSOFT_CONVERSION_HPP_INT_TO_STRING */
  70. #ifndef WINSTL_INCL_WINSTL_SYNCH_HPP_THREAD_MUTEX
  71. # include <winstl/synch/thread_mutex.hpp>
  72. #endif /* !WINSTL_INCL_WINSTL_SYNCH_HPP_THREAD_MUTEX */
  73. #ifndef WINSTL_INCL_WINSTL_SYNCH_HPP_SPIN_MUTEX
  74. # include <winstl/synch/spin_mutex.hpp>
  75. #endif /* !WINSTL_INCL_WINSTL_SYNCH_HPP_SPIN_MUTEX */
  76. #ifndef STLSOFT_INCL_STLSOFT_SYNCH_HPP_LOCK_SCOPE
  77. # include <stlsoft/synch/lock_scope.hpp>
  78. #endif /* !STLSOFT_INCL_STLSOFT_SYNCH_HPP_LOCK_SCOPE */
  79. #ifndef STLSOFT_INCL_STLSOFT_CONVERSION_HPP_SAP_CAST
  80. # include <stlsoft/conversion/sap_cast.hpp>
  81. #endif /* !STLSOFT_INCL_STLSOFT_CONVERSION_HPP_SAP_CAST */
  82. /* /////////////////////////////////////////////////////////////////////////
  83. * Namespace
  84. */
  85. #ifndef _WINSTL_NO_NAMESPACE
  86. # if defined(_STLSOFT_NO_NAMESPACE) || \
  87. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  88. /* There is no stlsoft namespace, so must define ::winstl */
  89. namespace winstl
  90. {
  91. # else
  92. /* Define stlsoft::winstl_project */
  93. namespace stlsoft
  94. {
  95. namespace winstl_project
  96. {
  97. # endif /* _STLSOFT_NO_NAMESPACE */
  98. #endif /* !_WINSTL_NO_NAMESPACE */
  99. /* /////////////////////////////////////////////////////////////////////////
  100. * Pre-processor options
  101. */
  102. #if defined(_WINSTL_INT_TO_STRING_USE_DECLSPECTHREAD_FOR_EXES)
  103. # if defined(_DLL) || \
  104. defined(__DLL__) || \
  105. defined(_WINDLL) || \
  106. defined(_USRDLL) || \
  107. defined(_AFXDLL)
  108. # pragma message("Using _WINSTL_INT_TO_STRING_USE_DECLSPECTHREAD_FOR_EXES when building DLLs will result in their not being loadable dynamically (via LoadLibrary())")
  109. # endif /* dll */
  110. #endif /* _WINSTL_INT_TO_STRING_USE_DECLSPECTHREAD_FOR_EXES */
  111. /* /////////////////////////////////////////////////////////////////////////
  112. * Functions
  113. */
  114. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  115. #ifdef STLSOFT_CF_NAMESPACE_SUPPORT
  116. namespace int_to_string_tls
  117. {
  118. #endif /* STLSOFT_CF_NAMESPACE_SUPPORT */
  119. // NOTE: This class had to be moved out of line to prevent VC++
  120. // from emitting multiple definitions. Silly billy!
  121. struct thread_mx_
  122. : public thread_mutex
  123. {
  124. public:
  125. thread_mx_()
  126. {}
  127. void* operator new(ws_size_t , void* p)
  128. {
  129. return p;
  130. }
  131. #if !defined(STLSOFT_COMPILER_IS_BORLAND) && \
  132. ( !defined(STLSOFT_COMPILER_IS_MSVC) || \
  133. _MSC_VER >= 1200)
  134. void operator delete(void* , void* )
  135. {}
  136. #endif /* compiler */
  137. void operator delete(void*)
  138. {}
  139. };
  140. template< ss_typename_param_k C
  141. , ws_size_t CCH
  142. >
  143. struct Slot
  144. {
  145. Slot(Slot* next)
  146. : next(next)
  147. {}
  148. ~Slot() stlsoft_throw_0()
  149. {
  150. delete next;
  151. }
  152. // Use the process heap because:
  153. //
  154. // 1. Don't want to worry about thread-specificity, since
  155. // deallocation will occur in a different thread to allocation
  156. // 2. Don't want to worry about linkage to any specific CRT or
  157. // other library
  158. // 3. Doesn't matter how fast it is
  159. // 4. Want it to be *highly* unlikely that allocation will fail,
  160. // which is indeed pretty unheard of when using the Win32
  161. // process heap.
  162. // 5. Want a C++-exception free solution, so use the Win32-system
  163. // out-of-memory exception, and not have to worry about any
  164. // linkage pains.
  165. void* operator new(ws_size_t cb)
  166. {
  167. return ::HeapAlloc(::GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, cb);
  168. }
  169. void operator delete(void* pv)
  170. {
  171. ::HeapFree(::GetProcessHeap(), 0, pv);
  172. }
  173. C buff[CCH];
  174. Slot* next;
  175. };
  176. template< ss_typename_param_k C
  177. , ws_size_t CCH
  178. >
  179. struct Key
  180. {
  181. typedef Slot<C, CCH> Slot;
  182. // This is admittedly totally gross, but it works and will be portable
  183. // across different compilers. The reason it works is that s_index is
  184. // static, and therefore all its members will be 0. This facilitates
  185. // using interlocking and spin-locks in order to manage the lifetime
  186. // correctly, and control access to the instance's constructor.
  187. //
  188. // Note that no members are initialised in a constructor member
  189. // initialisation list (MIL). They are initialised within the
  190. // constructor body
  191. Key()
  192. {
  193. // Since multiple threads could get into here before they
  194. // are all eventually blocked out by the static controller
  195. // variable, we must guard against such multiple
  196. // construction. Hence, if this is the only thread currently
  197. // engaged in construction, we can proceed to initialisation.
  198. // otherwise we must spin.
  199. //
  200. // We can start off by incrementing m_ctor, since it will have
  201. // been initialised to 0 by the load-time initialisation of
  202. // all static memory
  203. // Wrap the constructor count in a spin-mutex, and then lock it
  204. spin_mutex smx(&m_ctor);
  205. stlsoft_ns_qual(lock_scope)<spin_mutex, spin_mutex_lock_traits> lock(smx);
  206. if(0 == m_init++) // The test on this variable is always guarded by m_ctor
  207. {
  208. // Initialisation.
  209. // The construction thread could be suspended after a
  210. // successful completion of the constructor, but before
  211. // the hidden boolean managing static creation was
  212. // updated. Therefore, we need to reference-count the
  213. // construction, which is done via another interlocked
  214. // count, this time on m_init.
  215. // The constructor has not yet been called through
  216. // to this point
  217. new (&mx()) thread_mx_();
  218. m_index = ::TlsAlloc();
  219. // Use Win32 exception because:
  220. //
  221. // 1. Process cannot recover from this error in any
  222. // meaningful way
  223. // 2. Do not want to couple to C++ exception-handling
  224. // and there is no graceful way to allow this to be
  225. // parameterisable. (May allow a pp-discriminated
  226. // mechanism in next version.)
  227. if(TLS_OUT_OF_INDEXES == m_index)
  228. {
  229. ::RaiseException(STATUS_NO_MEMORY, EXCEPTION_NONCONTINUABLE, 0, 0);
  230. }
  231. }
  232. }
  233. ~Key() stlsoft_throw_0()
  234. {
  235. if(0 == ::InterlockedDecrement((LPLONG)&m_init))
  236. {
  237. // Walk the slot list and free. This can be as slow as
  238. // you like, since performance is not important here
  239. delete m_top;
  240. // Now release the index
  241. ::TlsFree(m_index);
  242. // Need to explicitly destroy the mutex.
  243. mx().~thread_mutex();
  244. }
  245. }
  246. Slot* GetSlot()
  247. {
  248. // NOTE: This does not need to be thread-safe
  249. return sap_cast<Slot*>(::TlsGetValue(m_index));
  250. }
  251. Slot* AllocSlot()
  252. {
  253. Slot* next;
  254. { // Protect linked-list manipulation
  255. stlsoft_ns_qual(lock_scope)<thread_mutex, thread_mutex_lock_traits> lock(mx());
  256. m_top = next = new Slot(m_top);
  257. }
  258. ::TlsSetValue(m_index, next);
  259. return next;
  260. }
  261. // Implementation
  262. private:
  263. thread_mutex &mx()
  264. {
  265. return *static_cast<thread_mutex*>(static_cast<void*>(&m__mx.bytes[0]));
  266. }
  267. private:
  268. #if 0
  269. // In an ideal world the member layout would be as follows:
  270. ws_dword_t m_index;
  271. Slot* m_top;
  272. thread_mutex m_mx;
  273. #else /* ? 0 */
  274. // But we're not in an ideal world, so it is like this
  275. ws_dword_t m_index;
  276. Slot* m_top;
  277. union
  278. {
  279. ws_byte_t bytes[sizeof(thread_mutex)];
  280. long double ld;
  281. } m__mx;
  282. ws_sint32_t m_init; // Construction count
  283. ws_sint32_t m_ctor; // Ctor entry count
  284. #endif /* 0 */
  285. };
  286. #ifdef STLSOFT_CF_NAMESPACE_SUPPORT
  287. } /* namespace int_to_string_tls */
  288. #endif /* STLSOFT_CF_NAMESPACE_SUPPORT */
  289. template< ss_typename_param_k C
  290. , ws_size_t CCH
  291. >
  292. inline C* i2str_get_tss_buffer()
  293. {
  294. #if defined(_WINSTL_INT_TO_STRING_USE_DECLSPECTHREAD_FOR_EXES)
  295. __declspec(thread) static C s_buffer[CCH];
  296. return s_buffer;
  297. #else
  298. #ifdef STLSOFT_CF_NAMESPACE_SUPPORT
  299. typedef int_to_string_tls::Key<C, CCH> Key;
  300. typedef int_to_string_tls::Slot<C, CCH> Slot;
  301. #else
  302. typedef Key<C, CCH> Key;
  303. typedef Slot<C, CCH> Slot;
  304. #endif /* STLSOFT_CF_NAMESPACE_SUPPORT */
  305. static Key s_index;
  306. Slot* slot = s_index.GetSlot();
  307. if(NULL == slot)
  308. {
  309. slot = s_index.AllocSlot();
  310. }
  311. return slot->buff;
  312. #endif /* dll */
  313. }
  314. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  315. /** Converts a signed 8-bit integer to a character string
  316. *
  317. * For example:
  318. \code
  319. signed char v = 13;
  320. assert(0 == ::strcmp(winstl::int_to_string<char>(v), "13"));
  321. assert(0 == ::wcscmp(winstl::int_to_string<wchar_t>(v), L"13"));
  322. \endcode
  323. *
  324. * \ingroup group__library__conversion
  325. *
  326. * \warning This function is *not* re-entrant. You must ensure that
  327. * it is only invoked once in a statement. This includes possible
  328. * invocations by other functions in the same statement.
  329. */
  330. template<ss_typename_param_k C>
  331. inline C const* int_to_string(ws_sint8_t value)
  332. {
  333. const ws_size_t CCH = 21; // 5 fits 8-bit + sign
  334. C* buffer = i2str_get_tss_buffer<C, CCH>();
  335. return stlsoft::integer_to_string(buffer, CCH, value);
  336. }
  337. /** Converts a unsigned 8-bit integer to a character string
  338. *
  339. * For example:
  340. \code
  341. unsigned char v = 14;
  342. assert(0 == ::strcmp(winstl::int_to_string<char>(v), "14"));
  343. assert(0 == ::wcscmp(winstl::int_to_string<wchar_t>(v), L"14"));
  344. \endcode
  345. *
  346. * \ingroup group__library__conversion
  347. *
  348. * \warning This function is *not* re-entrant. You must ensure that
  349. * it is only invoked once in a statement. This includes possible
  350. * invocations by other functions in the same statement.
  351. */
  352. template<ss_typename_param_k C>
  353. inline C const* int_to_string(ws_uint8_t value)
  354. {
  355. const ws_size_t CCH = 21; // 4 fits 8-bit
  356. C* buffer = i2str_get_tss_buffer<C, CCH>();
  357. return stlsoft::integer_to_string(buffer, CCH, value);
  358. }
  359. /** Converts a signed 16-bit integer to a character string
  360. *
  361. * For example:
  362. \code
  363. signed char v = 15;
  364. assert(0 == ::strcmp(winstl::int_to_string<char>(v), "15"));
  365. assert(0 == ::wcscmp(winstl::int_to_string<wchar_t>(v), L"15"));
  366. \endcode
  367. *
  368. * \ingroup group__library__conversion
  369. *
  370. * \warning This function is *not* re-entrant. You must ensure that
  371. * it is only invoked once in a statement. This includes possible
  372. * invocations by other functions in the same statement.
  373. */
  374. template<ss_typename_param_k C>
  375. inline C const* int_to_string(ws_sint16_t value)
  376. {
  377. const ws_size_t CCH = 21; // 7 fits 16-bit + sign
  378. C* buffer = i2str_get_tss_buffer<C, CCH>();
  379. return stlsoft::integer_to_string(buffer, CCH, value);
  380. }
  381. /** Converts a unsigned 16-bit integer to a character string
  382. *
  383. * For example:
  384. \code
  385. unsigned char v = 16;
  386. assert(0 == ::strcmp(winstl::int_to_string<char>(v), "16"));
  387. assert(0 == ::wcscmp(winstl::int_to_string<wchar_t>(v), L"16"));
  388. \endcode
  389. *
  390. * \ingroup group__library__conversion
  391. *
  392. * \warning This function is *not* re-entrant. You must ensure that
  393. * it is only invoked once in a statement. This includes possible
  394. * invocations by other functions in the same statement.
  395. */
  396. template<ss_typename_param_k C>
  397. inline C const* int_to_string(ws_uint16_t value)
  398. {
  399. const ws_size_t CCH = 21; // 6 fits 16-bit
  400. C* buffer = i2str_get_tss_buffer<C, CCH>();
  401. return stlsoft::integer_to_string(buffer, CCH, value);
  402. }
  403. /** Converts a signed 32-bit integer to a character string
  404. *
  405. * For example:
  406. \code
  407. signed char v = 17;
  408. assert(0 == ::strcmp(winstl::int_to_string<char>(v), "17"));
  409. assert(0 == ::wcscmp(winstl::int_to_string<wchar_t>(v), L"17"));
  410. \endcode
  411. *
  412. * \ingroup group__library__conversion
  413. *
  414. * \warning This function is *not* re-entrant. You must ensure that
  415. * it is only invoked once in a statement. This includes possible
  416. * invocations by other functions in the same statement.
  417. */
  418. template<ss_typename_param_k C>
  419. inline C const* int_to_string(ws_sint32_t value)
  420. {
  421. const ws_size_t CCH = 21; // 12 fits 32-bit + sign
  422. C* buffer = i2str_get_tss_buffer<C, CCH>();
  423. return stlsoft::integer_to_string(buffer, CCH, value);
  424. }
  425. /** Converts a unsigned 32-bit integer to a character string
  426. *
  427. * For example:
  428. \code
  429. unsigned char v = 18;
  430. assert(0 == ::strcmp(winstl::int_to_string<char>(v), "18"));
  431. assert(0 == ::wcscmp(winstl::int_to_string<wchar_t>(v), L"18"));
  432. \endcode
  433. *
  434. * \ingroup group__library__conversion
  435. *
  436. * \warning This function is *not* re-entrant. You must ensure that
  437. * it is only invoked once in a statement. This includes possible
  438. * invocations by other functions in the same statement.
  439. */
  440. template<ss_typename_param_k C>
  441. inline C const* int_to_string(ws_uint32_t value)
  442. {
  443. const ws_size_t CCH = 21; // 11 fits 32-bit
  444. C* buffer = i2str_get_tss_buffer<C, CCH>();
  445. return stlsoft::integer_to_string(buffer, CCH, value);
  446. }
  447. /** Converts a signed 64-bit integer to a character string
  448. *
  449. * For example:
  450. \code
  451. signed char v = 19;
  452. assert(0 == ::strcmp(winstl::int_to_string<char>(v), "19"));
  453. assert(0 == ::wcscmp(winstl::int_to_string<wchar_t>(v), L"19"));
  454. \endcode
  455. *
  456. * \ingroup group__library__conversion
  457. *
  458. * \warning This function is *not* re-entrant. You must ensure that
  459. * it is only invoked once in a statement. This includes possible
  460. * invocations by other functions in the same statement.
  461. */
  462. template<ss_typename_param_k C>
  463. inline C const* int_to_string(ws_sint64_t const& value)
  464. {
  465. const ws_size_t CCH = 21; // fits 64-bit + sign
  466. C* buffer = i2str_get_tss_buffer<C, CCH>();
  467. return stlsoft::integer_to_string(buffer, CCH, value);
  468. }
  469. /** Converts a unsigned 64-bit integer to a character string
  470. *
  471. * For example:
  472. \code
  473. unsigned char v = 20;
  474. assert(0 == ::strcmp(winstl::int_to_string<char>(v), "20"));
  475. assert(0 == ::wcscmp(winstl::int_to_string<wchar_t>(v), L"20"));
  476. \endcode
  477. *
  478. * \ingroup group__library__conversion
  479. *
  480. * \warning This function is *not* re-entrant. You must ensure that
  481. * it is only invoked once in a statement. This includes possible
  482. * invocations by other functions in the same statement.
  483. */
  484. template<ss_typename_param_k C>
  485. inline C const* int_to_string(ws_uint64_t const& value)
  486. {
  487. const ws_size_t CCH = 21; // fits 64-bit
  488. C* buffer = i2str_get_tss_buffer<C, CCH>();
  489. return stlsoft::integer_to_string(buffer, CCH, value);
  490. }
  491. #ifdef STLSOFT_CF_INT_DISTINCT_INT_TYPE
  492. template<ss_typename_param_k C>
  493. inline C const* int_to_string(int const& value)
  494. {
  495. const ws_size_t CCH = 21; // fits 64-bit
  496. C* buffer = i2str_get_tss_buffer<C, CCH>();
  497. return stlsoft::integer_to_string(buffer, CCH, value);
  498. }
  499. template<ss_typename_param_k C>
  500. inline C const* int_to_string(unsigned int const& value)
  501. {
  502. const ws_size_t CCH = 21; // fits 64-bit
  503. C* buffer = i2str_get_tss_buffer<C, CCH>();
  504. return stlsoft::integer_to_string(buffer, CCH, value);
  505. }
  506. #endif /* !STLSOFT_CF_INT_DISTINCT_INT_TYPE */
  507. #ifdef STLSOFT_CF_LONG_DISTINCT_INT_TYPE
  508. template<ss_typename_param_k C>
  509. inline C const* int_to_string(long const& value)
  510. {
  511. const ws_size_t CCH = 21; // fits 64-bit
  512. C* buffer = i2str_get_tss_buffer<C, CCH>();
  513. return stlsoft::integer_to_string(buffer, CCH, value);
  514. }
  515. template<ss_typename_param_k C>
  516. inline C const* int_to_string(unsigned long const& value)
  517. {
  518. const ws_size_t CCH = 21; // fits 64-bit
  519. C* buffer = i2str_get_tss_buffer<C, CCH>();
  520. return stlsoft::integer_to_string(buffer, CCH, value);
  521. }
  522. #endif /* !STLSOFT_CF_LONG_DISTINCT_INT_TYPE */
  523. ////////////////////////////////////////////////////////////////////////////
  524. // Unit-testing
  525. #ifdef STLSOFT_UNITTEST
  526. # include "./unittest/int_to_string_unittest_.h"
  527. #endif /* STLSOFT_UNITTEST */
  528. /* ////////////////////////////////////////////////////////////////////// */
  529. #ifndef _WINSTL_NO_NAMESPACE
  530. # if defined(_STLSOFT_NO_NAMESPACE) || \
  531. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  532. } /* namespace winstl */
  533. # else
  534. } /* namespace winstl_project */
  535. } /* namespace stlsoft */
  536. # endif /* _STLSOFT_NO_NAMESPACE */
  537. #endif /* !_WINSTL_NO_NAMESPACE */
  538. /* ////////////////////////////////////////////////////////////////////// */
  539. #endif /* !WINSTL_INCL_WINSTL_CONVERSION_HPP_INT_TO_STRING */
  540. /* ///////////////////////////// end of file //////////////////////////// */