Summary: This patch refactors and tries to remove as much of the Windows support headers as possible. This is needed because they currently introduce super weird include cycles and dependencies between STL and libc headers. The changes in this patch are: * remove `support/win32/support.h` completely. The required parts have either been moved into `support/win32/msvc_support.h` (for `MSVC` only helpers not needed by Clang), or directly into their respective `foo.h` headers. * Combine `locale_win32.h` and `locale_mgmt_win32.h` into a single headers, this header should only be included within `__locale` or `locale` to avoid include cycles. * Remove the unneeded parts of `limits_win32.h` and re-name it to `limits_msvc_win32.h` since it's only needed by Clang. I've tested this patch using Clang on Windows, but I suspect it might technically regress our non-existent support for MSVC. Is somebody able to double check? This refactor is needed to support upcoming fixes to `<locale>` on Windows. Reviewers: bcraig, rmaprath, compnerd, EricWF Reviewed By: EricWF Subscribers: majnemer, cfe-commits Differential Revision: https://reviews.llvm.org/D32988 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@302727 91177308-0d34-0410-b5e6-96231b3b80d8
526 lines
12 KiB
C++
526 lines
12 KiB
C++
//===------------------------- string.cpp ---------------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is dual licensed under the MIT and the University of Illinois Open
|
|
// Source Licenses. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "string"
|
|
#include "cstdlib"
|
|
#include "cwchar"
|
|
#include "cerrno"
|
|
#include "limits"
|
|
#include "stdexcept"
|
|
#include <stdio.h>
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>;
|
|
|
|
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<char>;
|
|
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<wchar_t>;
|
|
|
|
template
|
|
string
|
|
operator+<char, char_traits<char>, allocator<char> >(char const*, string const&);
|
|
|
|
namespace
|
|
{
|
|
|
|
template<typename T>
|
|
inline
|
|
void throw_helper( const string& msg )
|
|
{
|
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
|
throw T( msg );
|
|
#else
|
|
fprintf(stderr, "%s\n", msg.c_str());
|
|
_VSTD::abort();
|
|
#endif
|
|
}
|
|
|
|
inline
|
|
void throw_from_string_out_of_range( const string& func )
|
|
{
|
|
throw_helper<out_of_range>(func + ": out of range");
|
|
}
|
|
|
|
inline
|
|
void throw_from_string_invalid_arg( const string& func )
|
|
{
|
|
throw_helper<invalid_argument>(func + ": no conversion");
|
|
}
|
|
|
|
// as_integer
|
|
|
|
template<typename V, typename S, typename F>
|
|
inline
|
|
V
|
|
as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f)
|
|
{
|
|
typename S::value_type* ptr = nullptr;
|
|
const typename S::value_type* const p = str.c_str();
|
|
typename remove_reference<decltype(errno)>::type errno_save = errno;
|
|
errno = 0;
|
|
V r = f(p, &ptr, base);
|
|
swap(errno, errno_save);
|
|
if (errno_save == ERANGE)
|
|
throw_from_string_out_of_range(func);
|
|
if (ptr == p)
|
|
throw_from_string_invalid_arg(func);
|
|
if (idx)
|
|
*idx = static_cast<size_t>(ptr - p);
|
|
return r;
|
|
}
|
|
|
|
template<typename V, typename S>
|
|
inline
|
|
V
|
|
as_integer(const string& func, const S& s, size_t* idx, int base);
|
|
|
|
// string
|
|
template<>
|
|
inline
|
|
int
|
|
as_integer(const string& func, const string& s, size_t* idx, int base )
|
|
{
|
|
// Use long as no Standard string to integer exists.
|
|
long r = as_integer_helper<long>( func, s, idx, base, strtol );
|
|
if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
|
|
throw_from_string_out_of_range(func);
|
|
return static_cast<int>(r);
|
|
}
|
|
|
|
template<>
|
|
inline
|
|
long
|
|
as_integer(const string& func, const string& s, size_t* idx, int base )
|
|
{
|
|
return as_integer_helper<long>( func, s, idx, base, strtol );
|
|
}
|
|
|
|
template<>
|
|
inline
|
|
unsigned long
|
|
as_integer( const string& func, const string& s, size_t* idx, int base )
|
|
{
|
|
return as_integer_helper<unsigned long>( func, s, idx, base, strtoul );
|
|
}
|
|
|
|
template<>
|
|
inline
|
|
long long
|
|
as_integer( const string& func, const string& s, size_t* idx, int base )
|
|
{
|
|
return as_integer_helper<long long>( func, s, idx, base, strtoll );
|
|
}
|
|
|
|
template<>
|
|
inline
|
|
unsigned long long
|
|
as_integer( const string& func, const string& s, size_t* idx, int base )
|
|
{
|
|
return as_integer_helper<unsigned long long>( func, s, idx, base, strtoull );
|
|
}
|
|
|
|
// wstring
|
|
template<>
|
|
inline
|
|
int
|
|
as_integer( const string& func, const wstring& s, size_t* idx, int base )
|
|
{
|
|
// Use long as no Stantard string to integer exists.
|
|
long r = as_integer_helper<long>( func, s, idx, base, wcstol );
|
|
if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
|
|
throw_from_string_out_of_range(func);
|
|
return static_cast<int>(r);
|
|
}
|
|
|
|
template<>
|
|
inline
|
|
long
|
|
as_integer( const string& func, const wstring& s, size_t* idx, int base )
|
|
{
|
|
return as_integer_helper<long>( func, s, idx, base, wcstol );
|
|
}
|
|
|
|
template<>
|
|
inline
|
|
unsigned long
|
|
as_integer( const string& func, const wstring& s, size_t* idx, int base )
|
|
{
|
|
return as_integer_helper<unsigned long>( func, s, idx, base, wcstoul );
|
|
}
|
|
|
|
template<>
|
|
inline
|
|
long long
|
|
as_integer( const string& func, const wstring& s, size_t* idx, int base )
|
|
{
|
|
return as_integer_helper<long long>( func, s, idx, base, wcstoll );
|
|
}
|
|
|
|
template<>
|
|
inline
|
|
unsigned long long
|
|
as_integer( const string& func, const wstring& s, size_t* idx, int base )
|
|
{
|
|
return as_integer_helper<unsigned long long>( func, s, idx, base, wcstoull );
|
|
}
|
|
|
|
// as_float
|
|
|
|
template<typename V, typename S, typename F>
|
|
inline
|
|
V
|
|
as_float_helper(const string& func, const S& str, size_t* idx, F f )
|
|
{
|
|
typename S::value_type* ptr = nullptr;
|
|
const typename S::value_type* const p = str.c_str();
|
|
typename remove_reference<decltype(errno)>::type errno_save = errno;
|
|
errno = 0;
|
|
V r = f(p, &ptr);
|
|
swap(errno, errno_save);
|
|
if (errno_save == ERANGE)
|
|
throw_from_string_out_of_range(func);
|
|
if (ptr == p)
|
|
throw_from_string_invalid_arg(func);
|
|
if (idx)
|
|
*idx = static_cast<size_t>(ptr - p);
|
|
return r;
|
|
}
|
|
|
|
template<typename V, typename S>
|
|
inline
|
|
V as_float( const string& func, const S& s, size_t* idx = nullptr );
|
|
|
|
template<>
|
|
inline
|
|
float
|
|
as_float( const string& func, const string& s, size_t* idx )
|
|
{
|
|
return as_float_helper<float>( func, s, idx, strtof );
|
|
}
|
|
|
|
template<>
|
|
inline
|
|
double
|
|
as_float(const string& func, const string& s, size_t* idx )
|
|
{
|
|
return as_float_helper<double>( func, s, idx, strtod );
|
|
}
|
|
|
|
template<>
|
|
inline
|
|
long double
|
|
as_float( const string& func, const string& s, size_t* idx )
|
|
{
|
|
return as_float_helper<long double>( func, s, idx, strtold );
|
|
}
|
|
|
|
template<>
|
|
inline
|
|
float
|
|
as_float( const string& func, const wstring& s, size_t* idx )
|
|
{
|
|
return as_float_helper<float>( func, s, idx, wcstof );
|
|
}
|
|
|
|
template<>
|
|
inline
|
|
double
|
|
as_float( const string& func, const wstring& s, size_t* idx )
|
|
{
|
|
return as_float_helper<double>( func, s, idx, wcstod );
|
|
}
|
|
|
|
template<>
|
|
inline
|
|
long double
|
|
as_float( const string& func, const wstring& s, size_t* idx )
|
|
{
|
|
return as_float_helper<long double>( func, s, idx, wcstold );
|
|
}
|
|
|
|
} // unnamed namespace
|
|
|
|
int
|
|
stoi(const string& str, size_t* idx, int base)
|
|
{
|
|
return as_integer<int>( "stoi", str, idx, base );
|
|
}
|
|
|
|
int
|
|
stoi(const wstring& str, size_t* idx, int base)
|
|
{
|
|
return as_integer<int>( "stoi", str, idx, base );
|
|
}
|
|
|
|
long
|
|
stol(const string& str, size_t* idx, int base)
|
|
{
|
|
return as_integer<long>( "stol", str, idx, base );
|
|
}
|
|
|
|
long
|
|
stol(const wstring& str, size_t* idx, int base)
|
|
{
|
|
return as_integer<long>( "stol", str, idx, base );
|
|
}
|
|
|
|
unsigned long
|
|
stoul(const string& str, size_t* idx, int base)
|
|
{
|
|
return as_integer<unsigned long>( "stoul", str, idx, base );
|
|
}
|
|
|
|
unsigned long
|
|
stoul(const wstring& str, size_t* idx, int base)
|
|
{
|
|
return as_integer<unsigned long>( "stoul", str, idx, base );
|
|
}
|
|
|
|
long long
|
|
stoll(const string& str, size_t* idx, int base)
|
|
{
|
|
return as_integer<long long>( "stoll", str, idx, base );
|
|
}
|
|
|
|
long long
|
|
stoll(const wstring& str, size_t* idx, int base)
|
|
{
|
|
return as_integer<long long>( "stoll", str, idx, base );
|
|
}
|
|
|
|
unsigned long long
|
|
stoull(const string& str, size_t* idx, int base)
|
|
{
|
|
return as_integer<unsigned long long>( "stoull", str, idx, base );
|
|
}
|
|
|
|
unsigned long long
|
|
stoull(const wstring& str, size_t* idx, int base)
|
|
{
|
|
return as_integer<unsigned long long>( "stoull", str, idx, base );
|
|
}
|
|
|
|
float
|
|
stof(const string& str, size_t* idx)
|
|
{
|
|
return as_float<float>( "stof", str, idx );
|
|
}
|
|
|
|
float
|
|
stof(const wstring& str, size_t* idx)
|
|
{
|
|
return as_float<float>( "stof", str, idx );
|
|
}
|
|
|
|
double
|
|
stod(const string& str, size_t* idx)
|
|
{
|
|
return as_float<double>( "stod", str, idx );
|
|
}
|
|
|
|
double
|
|
stod(const wstring& str, size_t* idx)
|
|
{
|
|
return as_float<double>( "stod", str, idx );
|
|
}
|
|
|
|
long double
|
|
stold(const string& str, size_t* idx)
|
|
{
|
|
return as_float<long double>( "stold", str, idx );
|
|
}
|
|
|
|
long double
|
|
stold(const wstring& str, size_t* idx)
|
|
{
|
|
return as_float<long double>( "stold", str, idx );
|
|
}
|
|
|
|
// to_string
|
|
|
|
namespace
|
|
{
|
|
|
|
// as_string
|
|
|
|
template<typename S, typename P, typename V >
|
|
inline
|
|
S
|
|
as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a)
|
|
{
|
|
typedef typename S::size_type size_type;
|
|
size_type available = s.size();
|
|
while (true)
|
|
{
|
|
int status = sprintf_like(&s[0], available + 1, fmt, a);
|
|
if ( status >= 0 )
|
|
{
|
|
size_type used = static_cast<size_type>(status);
|
|
if ( used <= available )
|
|
{
|
|
s.resize( used );
|
|
break;
|
|
}
|
|
available = used; // Assume this is advice of how much space we need.
|
|
}
|
|
else
|
|
available = available * 2 + 1;
|
|
s.resize(available);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
template <class S, class V, bool = is_floating_point<V>::value>
|
|
struct initial_string;
|
|
|
|
template <class V, bool b>
|
|
struct initial_string<string, V, b>
|
|
{
|
|
string
|
|
operator()() const
|
|
{
|
|
string s;
|
|
s.resize(s.capacity());
|
|
return s;
|
|
}
|
|
};
|
|
|
|
template <class V>
|
|
struct initial_string<wstring, V, false>
|
|
{
|
|
wstring
|
|
operator()() const
|
|
{
|
|
const size_t n = (numeric_limits<unsigned long long>::digits / 3)
|
|
+ ((numeric_limits<unsigned long long>::digits % 3) != 0)
|
|
+ 1;
|
|
wstring s(n, wchar_t());
|
|
s.resize(s.capacity());
|
|
return s;
|
|
}
|
|
};
|
|
|
|
template <class V>
|
|
struct initial_string<wstring, V, true>
|
|
{
|
|
wstring
|
|
operator()() const
|
|
{
|
|
wstring s(20, wchar_t());
|
|
s.resize(s.capacity());
|
|
return s;
|
|
}
|
|
};
|
|
|
|
typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...);
|
|
|
|
inline
|
|
wide_printf
|
|
get_swprintf()
|
|
{
|
|
#ifndef _LIBCPP_MSVCRT
|
|
return swprintf;
|
|
#else
|
|
return static_cast<int (__cdecl*)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...)>(_snwprintf);
|
|
#endif
|
|
}
|
|
|
|
} // unnamed namespace
|
|
|
|
string to_string(int val)
|
|
{
|
|
return as_string(snprintf, initial_string<string, int>()(), "%d", val);
|
|
}
|
|
|
|
string to_string(unsigned val)
|
|
{
|
|
return as_string(snprintf, initial_string<string, unsigned>()(), "%u", val);
|
|
}
|
|
|
|
string to_string(long val)
|
|
{
|
|
return as_string(snprintf, initial_string<string, long>()(), "%ld", val);
|
|
}
|
|
|
|
string to_string(unsigned long val)
|
|
{
|
|
return as_string(snprintf, initial_string<string, unsigned long>()(), "%lu", val);
|
|
}
|
|
|
|
string to_string(long long val)
|
|
{
|
|
return as_string(snprintf, initial_string<string, long long>()(), "%lld", val);
|
|
}
|
|
|
|
string to_string(unsigned long long val)
|
|
{
|
|
return as_string(snprintf, initial_string<string, unsigned long long>()(), "%llu", val);
|
|
}
|
|
|
|
string to_string(float val)
|
|
{
|
|
return as_string(snprintf, initial_string<string, float>()(), "%f", val);
|
|
}
|
|
|
|
string to_string(double val)
|
|
{
|
|
return as_string(snprintf, initial_string<string, double>()(), "%f", val);
|
|
}
|
|
|
|
string to_string(long double val)
|
|
{
|
|
return as_string(snprintf, initial_string<string, long double>()(), "%Lf", val);
|
|
}
|
|
|
|
wstring to_wstring(int val)
|
|
{
|
|
return as_string(get_swprintf(), initial_string<wstring, int>()(), L"%d", val);
|
|
}
|
|
|
|
wstring to_wstring(unsigned val)
|
|
{
|
|
return as_string(get_swprintf(), initial_string<wstring, unsigned>()(), L"%u", val);
|
|
}
|
|
|
|
wstring to_wstring(long val)
|
|
{
|
|
return as_string(get_swprintf(), initial_string<wstring, long>()(), L"%ld", val);
|
|
}
|
|
|
|
wstring to_wstring(unsigned long val)
|
|
{
|
|
return as_string(get_swprintf(), initial_string<wstring, unsigned long>()(), L"%lu", val);
|
|
}
|
|
|
|
wstring to_wstring(long long val)
|
|
{
|
|
return as_string(get_swprintf(), initial_string<wstring, long long>()(), L"%lld", val);
|
|
}
|
|
|
|
wstring to_wstring(unsigned long long val)
|
|
{
|
|
return as_string(get_swprintf(), initial_string<wstring, unsigned long long>()(), L"%llu", val);
|
|
}
|
|
|
|
wstring to_wstring(float val)
|
|
{
|
|
return as_string(get_swprintf(), initial_string<wstring, float>()(), L"%f", val);
|
|
}
|
|
|
|
wstring to_wstring(double val)
|
|
{
|
|
return as_string(get_swprintf(), initial_string<wstring, double>()(), L"%f", val);
|
|
}
|
|
|
|
wstring to_wstring(long double val)
|
|
{
|
|
return as_string(get_swprintf(), initial_string<wstring, long double>()(), L"%Lf", val);
|
|
}
|
|
_LIBCPP_END_NAMESPACE_STD
|