Files
android_external_libcxx/src/string.cpp
Eric Fiselier 41af64afad [libc++] Refactor Windows support headers.
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
2017-05-10 20:57:45 +00:00

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