Comments (9)
perhaps this is relevant?
http://stackoverflow.com/questions/12920891/std-linker-error-with-apple-llvm-4-1
from folly.
this is the homebrew formula: https://github.com/mcuadros/homebrew-hhvm
from folly.
To get to this point, this patch needed to be applied:
from folly.
Lines 915 to 2427 in 32a9723
/** | |
* This is the basic_string replacement. For conformity, | |
* basic_fbstring takes the same template parameters, plus the last | |
* one which is the core. | |
*/ | |
#ifdef _LIBSTDCXX_FBSTRING | |
template <typename E, class T, class A, class Storage> | |
#else | |
template <typename E, | |
class T = std::char_traits<E>, | |
class A = std::allocator<E>, | |
class Storage = fbstring_core<E> > | |
#endif | |
class basic_fbstring { | |
static void enforce( | |
bool condition, | |
void (*throw_exc)(const char*), | |
const char* msg) { | |
if (!condition) throw_exc(msg); | |
} | |
bool isSane() const { | |
return | |
begin() <= end() && | |
empty() == (size() == 0) && | |
empty() == (begin() == end()) && | |
size() <= max_size() && | |
capacity() <= max_size() && | |
size() <= capacity() && | |
begin()[size()] == '\0'; | |
} | |
struct Invariant; | |
friend struct Invariant; | |
struct Invariant { | |
#ifndef NDEBUG | |
explicit Invariant(const basic_fbstring& s) : s_(s) { | |
assert(s_.isSane()); | |
} | |
~Invariant() { | |
assert(s_.isSane()); | |
} | |
private: | |
const basic_fbstring& s_; | |
#else | |
explicit Invariant(const basic_fbstring&) {} | |
#endif | |
Invariant& operator=(const Invariant&); | |
}; | |
public: | |
// types | |
typedef T traits_type; | |
typedef typename traits_type::char_type value_type; | |
typedef A allocator_type; | |
typedef typename A::size_type size_type; | |
typedef typename A::difference_type difference_type; | |
typedef typename A::reference reference; | |
typedef typename A::const_reference const_reference; | |
typedef typename A::pointer pointer; | |
typedef typename A::const_pointer const_pointer; | |
typedef E* iterator; | |
typedef const E* const_iterator; | |
typedef std::reverse_iterator<iterator | |
#ifdef NO_ITERATOR_TRAITS | |
, value_type | |
#endif | |
> reverse_iterator; | |
typedef std::reverse_iterator<const_iterator | |
#ifdef NO_ITERATOR_TRAITS | |
, const value_type | |
#endif | |
> const_reverse_iterator; | |
static const size_type npos; // = size_type(-1) | |
private: | |
static void procrustes(size_type& n, size_type nmax) { | |
if (n > nmax) n = nmax; | |
} | |
public: | |
// C++11 21.4.2 construct/copy/destroy | |
explicit basic_fbstring(const A& a = A()) noexcept { | |
} | |
basic_fbstring(const basic_fbstring& str) | |
: store_(str.store_) { | |
} | |
// Move constructor | |
basic_fbstring(basic_fbstring&& goner) noexcept | |
: store_(std::move(goner.store_)) { | |
} | |
#ifndef _LIBSTDCXX_FBSTRING | |
// This is defined for compatibility with std::string | |
/* implicit */ basic_fbstring(const std::string& str) | |
: store_(str.data(), str.size()) { | |
} | |
#endif | |
basic_fbstring(const basic_fbstring& str, size_type pos, | |
size_type n = npos, const A& a = A()) { | |
assign(str, pos, n); | |
} | |
/* implicit */ basic_fbstring(const value_type* s, const A& a = A()) | |
: store_(s, s | |
? traits_type::length(s) | |
: (std::__throw_logic_error( | |
"basic_fbstring: null pointer initializer not valid"), | |
0)) { | |
} | |
basic_fbstring(const value_type* s, size_type n, const A& a = A()) | |
: store_(s, n) { | |
} | |
basic_fbstring(size_type n, value_type c, const A& a = A()) { | |
auto const data = store_.expand_noinit(n); | |
fbstring_detail::pod_fill(data, data + n, c); | |
store_.writeTerminator(); | |
} | |
template <class InIt> | |
basic_fbstring(InIt begin, InIt end, | |
typename std::enable_if< | |
!std::is_same<typename std::remove_const<InIt>::type, | |
value_type*>::value, const A>::type & a = A()) { | |
assign(begin, end); | |
} | |
// Specialization for const char*, const char* | |
basic_fbstring(const value_type* b, const value_type* e) | |
: store_(b, e - b) { | |
} | |
// Nonstandard constructor | |
basic_fbstring(value_type *s, size_type n, size_type c, | |
AcquireMallocatedString a) | |
: store_(s, n, c, a) { | |
} | |
// Construction from initialization list | |
basic_fbstring(std::initializer_list<value_type> il) { | |
assign(il.begin(), il.end()); | |
} | |
~basic_fbstring() noexcept { | |
} | |
basic_fbstring& operator=(const basic_fbstring& lhs) { | |
if (FBSTRING_UNLIKELY(&lhs == this)) { | |
return *this; | |
} | |
auto const oldSize = size(); | |
auto const srcSize = lhs.size(); | |
if (capacity() >= srcSize && !store_.isShared()) { | |
// great, just copy the contents | |
if (oldSize < srcSize) | |
store_.expand_noinit(srcSize - oldSize); | |
else | |
store_.shrink(oldSize - srcSize); | |
assert(size() == srcSize); | |
fbstring_detail::pod_copy(lhs.begin(), lhs.end(), begin()); | |
store_.writeTerminator(); | |
} else { | |
// need to reallocate, so we may as well create a brand new string | |
basic_fbstring(lhs).swap(*this); | |
} | |
return *this; | |
} | |
// Move assignment | |
basic_fbstring& operator=(basic_fbstring&& goner) noexcept { | |
if (FBSTRING_UNLIKELY(&goner == this)) { | |
// Compatibility with std::basic_string<>, | |
// C++11 21.4.2 [string.cons] / 23 requires self-move-assignment support. | |
return *this; | |
} | |
// No need of this anymore | |
this->~basic_fbstring(); | |
// Move the goner into this | |
new(&store_) fbstring_core<E>(std::move(goner.store_)); | |
return *this; | |
} | |
#ifndef _LIBSTDCXX_FBSTRING | |
// Compatibility with std::string | |
basic_fbstring & operator=(const std::string & rhs) { | |
return assign(rhs.data(), rhs.size()); | |
} | |
// Compatibility with std::string | |
std::string toStdString() const { | |
return std::string(data(), size()); | |
} | |
#else | |
// A lot of code in fbcode still uses this method, so keep it here for now. | |
const basic_fbstring& toStdString() const { | |
return *this; | |
} | |
#endif | |
basic_fbstring& operator=(const value_type* s) { | |
return assign(s); | |
} | |
basic_fbstring& operator=(value_type c) { | |
if (empty()) { | |
store_.expand_noinit(1); | |
} else if (store_.isShared()) { | |
basic_fbstring(1, c).swap(*this); | |
return *this; | |
} else { | |
store_.shrink(size() - 1); | |
} | |
*store_.mutable_data() = c; | |
store_.writeTerminator(); | |
return *this; | |
} | |
basic_fbstring& operator=(std::initializer_list<value_type> il) { | |
return assign(il.begin(), il.end()); | |
} | |
// C++11 21.4.3 iterators: | |
iterator begin() { return store_.mutable_data(); } | |
const_iterator begin() const { return store_.data(); } | |
const_iterator cbegin() const { return begin(); } | |
iterator end() { | |
return store_.mutable_data() + store_.size(); | |
} | |
const_iterator end() const { | |
return store_.data() + store_.size(); | |
} | |
const_iterator cend() const { return end(); } | |
reverse_iterator rbegin() { | |
return reverse_iterator(end()); | |
} | |
const_reverse_iterator rbegin() const { | |
return const_reverse_iterator(end()); | |
} | |
const_reverse_iterator crbegin() const { return rbegin(); } | |
reverse_iterator rend() { | |
return reverse_iterator(begin()); | |
} | |
const_reverse_iterator rend() const { | |
return const_reverse_iterator(begin()); | |
} | |
const_reverse_iterator crend() const { return rend(); } | |
// Added by C++11 | |
// C++11 21.4.5, element access: | |
const value_type& front() const { return *begin(); } | |
const value_type& back() const { | |
assert(!empty()); | |
// Should be begin()[size() - 1], but that branches twice | |
return *(end() - 1); | |
} | |
value_type& front() { return *begin(); } | |
value_type& back() { | |
assert(!empty()); | |
// Should be begin()[size() - 1], but that branches twice | |
return *(end() - 1); | |
} | |
void pop_back() { | |
assert(!empty()); | |
store_.shrink(1); | |
} | |
// C++11 21.4.4 capacity: | |
size_type size() const { return store_.size(); } | |
size_type length() const { return size(); } | |
size_type max_size() const { | |
return std::numeric_limits<size_type>::max(); | |
} | |
void resize(const size_type n, const value_type c = value_type()) { | |
auto size = this->size(); | |
if (n <= size) { | |
store_.shrink(size - n); | |
} else { | |
// Do this in two steps to minimize slack memory copied (see | |
// smartRealloc). | |
auto const capacity = this->capacity(); | |
assert(capacity >= size); | |
if (size < capacity) { | |
auto delta = std::min(n, capacity) - size; | |
store_.expand_noinit(delta); | |
fbstring_detail::pod_fill(begin() + size, end(), c); | |
size += delta; | |
if (size == n) { | |
store_.writeTerminator(); | |
return; | |
} | |
assert(size < n); | |
} | |
auto const delta = n - size; | |
store_.expand_noinit(delta); | |
fbstring_detail::pod_fill(end() - delta, end(), c); | |
store_.writeTerminator(); | |
} | |
assert(this->size() == n); | |
} | |
size_type capacity() const { return store_.capacity(); } | |
void reserve(size_type res_arg = 0) { | |
enforce(res_arg <= max_size(), std::__throw_length_error, ""); | |
store_.reserve(res_arg); | |
} | |
void shrink_to_fit() { | |
// Shrink only if slack memory is sufficiently large | |
if (capacity() < size() * 3 / 2) { | |
return; | |
} | |
basic_fbstring(cbegin(), cend()).swap(*this); | |
} | |
void clear() { resize(0); } | |
bool empty() const { return size() == 0; } | |
// C++11 21.4.5 element access: | |
const_reference operator[](size_type pos) const { | |
return *(begin() + pos); | |
} | |
reference operator[](size_type pos) { | |
return *(begin() + pos); | |
} | |
const_reference at(size_type n) const { | |
enforce(n <= size(), std::__throw_out_of_range, ""); | |
return (*this)[n]; | |
} | |
reference at(size_type n) { | |
enforce(n < size(), std::__throw_out_of_range, ""); | |
return (*this)[n]; | |
} | |
// C++11 21.4.6 modifiers: | |
basic_fbstring& operator+=(const basic_fbstring& str) { | |
return append(str); | |
} | |
basic_fbstring& operator+=(const value_type* s) { | |
return append(s); | |
} | |
basic_fbstring& operator+=(const value_type c) { | |
push_back(c); | |
return *this; | |
} | |
basic_fbstring& operator+=(std::initializer_list<value_type> il) { | |
append(il); | |
return *this; | |
} | |
basic_fbstring& append(const basic_fbstring& str) { | |
#ifndef NDEBUG | |
auto desiredSize = size() + str.size(); | |
#endif | |
append(str.data(), str.size()); | |
assert(size() == desiredSize); | |
return *this; | |
} | |
basic_fbstring& append(const basic_fbstring& str, const size_type pos, | |
size_type n) { | |
const size_type sz = str.size(); | |
enforce(pos <= sz, std::__throw_out_of_range, ""); | |
procrustes(n, sz - pos); | |
return append(str.data() + pos, n); | |
} | |
basic_fbstring& append(const value_type* s, size_type n) { | |
#ifndef NDEBUG | |
Invariant checker(*this); | |
(void) checker; | |
#endif | |
if (FBSTRING_UNLIKELY(!n)) { | |
// Unlikely but must be done | |
return *this; | |
} | |
auto const oldSize = size(); | |
auto const oldData = data(); | |
// Check for aliasing (rare). We could use "<=" here but in theory | |
// those do not work for pointers unless the pointers point to | |
// elements in the same array. For that reason we use | |
// std::less_equal, which is guaranteed to offer a total order | |
// over pointers. See discussion at http://goo.gl/Cy2ya for more | |
// info. | |
std::less_equal<const value_type*> le; | |
if (FBSTRING_UNLIKELY(le(oldData, s) && !le(oldData + oldSize, s))) { | |
assert(le(s + n, oldData + oldSize)); | |
const size_type offset = s - oldData; | |
store_.reserve(oldSize + n); | |
// Restore the source | |
s = data() + offset; | |
} | |
// Warning! Repeated appends with short strings may actually incur | |
// practically quadratic performance. Avoid that by pushing back | |
// the first character (which ensures exponential growth) and then | |
// appending the rest normally. Worst case the append may incur a | |
// second allocation but that will be rare. | |
push_back(*s++); | |
--n; | |
memcpy(store_.expand_noinit(n), s, n * sizeof(value_type)); | |
assert(size() == oldSize + n + 1); | |
return *this; | |
} | |
basic_fbstring& append(const value_type* s) { | |
return append(s, traits_type::length(s)); | |
} | |
basic_fbstring& append(size_type n, value_type c) { | |
resize(size() + n, c); | |
return *this; | |
} | |
template<class InputIterator> | |
basic_fbstring& append(InputIterator first, InputIterator last) { | |
insert(end(), first, last); | |
return *this; | |
} | |
basic_fbstring& append(std::initializer_list<value_type> il) { | |
return append(il.begin(), il.end()); | |
} | |
void push_back(const value_type c) { // primitive | |
store_.push_back(c); | |
} | |
basic_fbstring& assign(const basic_fbstring& str) { | |
if (&str == this) return *this; | |
return assign(str.data(), str.size()); | |
} | |
basic_fbstring& assign(basic_fbstring&& str) { | |
return *this = std::move(str); | |
} | |
basic_fbstring& assign(const basic_fbstring& str, const size_type pos, | |
size_type n) { | |
const size_type sz = str.size(); | |
enforce(pos <= sz, std::__throw_out_of_range, ""); | |
procrustes(n, sz - pos); | |
return assign(str.data() + pos, n); | |
} | |
basic_fbstring& assign(const value_type* s, const size_type n) { | |
Invariant checker(*this); | |
(void) checker; | |
if (size() >= n) { | |
std::copy(s, s + n, begin()); | |
resize(n); | |
assert(size() == n); | |
} else { | |
const value_type *const s2 = s + size(); | |
std::copy(s, s2, begin()); | |
append(s2, n - size()); | |
assert(size() == n); | |
} | |
store_.writeTerminator(); | |
assert(size() == n); | |
return *this; | |
} | |
basic_fbstring& assign(const value_type* s) { | |
return assign(s, traits_type::length(s)); | |
} | |
basic_fbstring& assign(std::initializer_list<value_type> il) { | |
return assign(il.begin(), il.end()); | |
} | |
template <class ItOrLength, class ItOrChar> | |
basic_fbstring& assign(ItOrLength first_or_n, ItOrChar last_or_c) { | |
return replace(begin(), end(), first_or_n, last_or_c); | |
} | |
basic_fbstring& insert(size_type pos1, const basic_fbstring& str) { | |
return insert(pos1, str.data(), str.size()); | |
} | |
basic_fbstring& insert(size_type pos1, const basic_fbstring& str, | |
size_type pos2, size_type n) { | |
enforce(pos2 <= str.length(), std::__throw_out_of_range, ""); | |
procrustes(n, str.length() - pos2); | |
return insert(pos1, str.data() + pos2, n); | |
} | |
basic_fbstring& insert(size_type pos, const value_type* s, size_type n) { | |
enforce(pos <= length(), std::__throw_out_of_range, ""); | |
insert(begin() + pos, s, s + n); | |
return *this; | |
} | |
basic_fbstring& insert(size_type pos, const value_type* s) { | |
return insert(pos, s, traits_type::length(s)); | |
} | |
basic_fbstring& insert(size_type pos, size_type n, value_type c) { | |
enforce(pos <= length(), std::__throw_out_of_range, ""); | |
insert(begin() + pos, n, c); | |
return *this; | |
} | |
iterator insert(const_iterator p, const value_type c) { | |
const size_type pos = p - begin(); | |
insert(p, 1, c); | |
return begin() + pos; | |
} | |
private: | |
template <int i> class Selector {}; | |
iterator insertImplDiscr(const_iterator p, | |
size_type n, value_type c, Selector<1>) { | |
Invariant checker(*this); | |
(void) checker; | |
auto const pos = p - begin(); | |
assert(p >= begin() && p <= end()); | |
if (capacity() - size() < n) { | |
const size_type sz = p - begin(); | |
reserve(size() + n); | |
p = begin() + sz; | |
} | |
const iterator oldEnd = end(); | |
if (n < size_type(oldEnd - p)) { | |
append(oldEnd - n, oldEnd); | |
//std::copy( | |
// reverse_iterator(oldEnd - n), | |
// reverse_iterator(p), | |
// reverse_iterator(oldEnd)); | |
fbstring_detail::pod_move(&*p, &*oldEnd - n, | |
begin() + pos + n); | |
std::fill(begin() + pos, begin() + pos + n, c); | |
} else { | |
append(n - (end() - p), c); | |
append(iterator(p), oldEnd); | |
std::fill(iterator(p), oldEnd, c); | |
} | |
store_.writeTerminator(); | |
return begin() + pos; | |
} | |
template<class InputIter> | |
iterator insertImplDiscr(const_iterator i, | |
InputIter b, InputIter e, Selector<0>) { | |
return insertImpl(i, b, e, | |
typename std::iterator_traits<InputIter>::iterator_category()); | |
} | |
template <class FwdIterator> | |
iterator insertImpl(const_iterator i, | |
FwdIterator s1, FwdIterator s2, std::forward_iterator_tag) { | |
Invariant checker(*this); | |
(void) checker; | |
const size_type pos = i - begin(); | |
const typename std::iterator_traits<FwdIterator>::difference_type n2 = | |
std::distance(s1, s2); | |
assert(n2 >= 0); | |
using namespace fbstring_detail; | |
assert(pos <= size()); | |
const typename std::iterator_traits<FwdIterator>::difference_type maxn2 = | |
capacity() - size(); | |
if (maxn2 < n2) { | |
// realloc the string | |
reserve(size() + n2); | |
i = begin() + pos; | |
} | |
if (pos + n2 <= size()) { | |
const iterator tailBegin = end() - n2; | |
store_.expand_noinit(n2); | |
fbstring_detail::pod_copy(tailBegin, tailBegin + n2, end() - n2); | |
std::copy(const_reverse_iterator(tailBegin), const_reverse_iterator(i), | |
reverse_iterator(tailBegin + n2)); | |
std::copy(s1, s2, begin() + pos); | |
} else { | |
FwdIterator t = s1; | |
const size_type old_size = size(); | |
std::advance(t, old_size - pos); | |
const size_t newElems = std::distance(t, s2); | |
store_.expand_noinit(n2); | |
std::copy(t, s2, begin() + old_size); | |
fbstring_detail::pod_copy(data() + pos, data() + old_size, | |
begin() + old_size + newElems); | |
std::copy(s1, t, begin() + pos); | |
} | |
store_.writeTerminator(); | |
return begin() + pos; | |
} | |
template <class InputIterator> | |
iterator insertImpl(const_iterator i, | |
InputIterator b, InputIterator e, | |
std::input_iterator_tag) { | |
const auto pos = i - begin(); | |
basic_fbstring temp(begin(), i); | |
for (; b != e; ++b) { | |
temp.push_back(*b); | |
} | |
temp.append(i, cend()); | |
swap(temp); | |
return begin() + pos; | |
} | |
public: | |
template <class ItOrLength, class ItOrChar> | |
iterator insert(const_iterator p, ItOrLength first_or_n, ItOrChar last_or_c) { | |
Selector<std::numeric_limits<ItOrLength>::is_specialized> sel; | |
return insertImplDiscr(p, first_or_n, last_or_c, sel); | |
} | |
iterator insert(const_iterator p, std::initializer_list<value_type> il) { | |
return insert(p, il.begin(), il.end()); | |
} | |
basic_fbstring& erase(size_type pos = 0, size_type n = npos) { | |
Invariant checker(*this); | |
(void) checker; | |
enforce(pos <= length(), std::__throw_out_of_range, ""); | |
procrustes(n, length() - pos); | |
std::copy(begin() + pos + n, end(), begin() + pos); | |
resize(length() - n); | |
return *this; | |
} | |
iterator erase(iterator position) { | |
const size_type pos(position - begin()); | |
enforce(pos <= size(), std::__throw_out_of_range, ""); | |
erase(pos, 1); | |
return begin() + pos; | |
} | |
iterator erase(iterator first, iterator last) { | |
const size_type pos(first - begin()); | |
erase(pos, last - first); | |
return begin() + pos; | |
} | |
// Replaces at most n1 chars of *this, starting with pos1 with the | |
// content of str | |
basic_fbstring& replace(size_type pos1, size_type n1, | |
const basic_fbstring& str) { | |
return replace(pos1, n1, str.data(), str.size()); | |
} | |
// Replaces at most n1 chars of *this, starting with pos1, | |
// with at most n2 chars of str starting with pos2 | |
basic_fbstring& replace(size_type pos1, size_type n1, | |
const basic_fbstring& str, | |
size_type pos2, size_type n2) { | |
enforce(pos2 <= str.length(), std::__throw_out_of_range, ""); | |
return replace(pos1, n1, str.data() + pos2, | |
std::min(n2, str.size() - pos2)); | |
} | |
// Replaces at most n1 chars of *this, starting with pos, with chars from s | |
basic_fbstring& replace(size_type pos, size_type n1, const value_type* s) { | |
return replace(pos, n1, s, traits_type::length(s)); | |
} | |
// Replaces at most n1 chars of *this, starting with pos, with n2 | |
// occurrences of c | |
// | |
// consolidated with | |
// | |
// Replaces at most n1 chars of *this, starting with pos, with at | |
// most n2 chars of str. str must have at least n2 chars. | |
template <class StrOrLength, class NumOrChar> | |
basic_fbstring& replace(size_type pos, size_type n1, | |
StrOrLength s_or_n2, NumOrChar n_or_c) { | |
Invariant checker(*this); | |
(void) checker; | |
enforce(pos <= size(), std::__throw_out_of_range, ""); | |
procrustes(n1, length() - pos); | |
const iterator b = begin() + pos; | |
return replace(b, b + n1, s_or_n2, n_or_c); | |
} | |
basic_fbstring& replace(iterator i1, iterator i2, const basic_fbstring& str) { | |
return replace(i1, i2, str.data(), str.length()); | |
} | |
basic_fbstring& replace(iterator i1, iterator i2, const value_type* s) { | |
return replace(i1, i2, s, traits_type::length(s)); | |
} | |
private: | |
basic_fbstring& replaceImplDiscr(iterator i1, iterator i2, | |
const value_type* s, size_type n, | |
Selector<2>) { | |
assert(i1 <= i2); | |
assert(begin() <= i1 && i1 <= end()); | |
assert(begin() <= i2 && i2 <= end()); | |
return replace(i1, i2, s, s + n); | |
} | |
basic_fbstring& replaceImplDiscr(iterator i1, iterator i2, | |
size_type n2, value_type c, Selector<1>) { | |
const size_type n1 = i2 - i1; | |
if (n1 > n2) { | |
std::fill(i1, i1 + n2, c); | |
erase(i1 + n2, i2); | |
} else { | |
std::fill(i1, i2, c); | |
insert(i2, n2 - n1, c); | |
} | |
assert(isSane()); | |
return *this; | |
} | |
template <class InputIter> | |
basic_fbstring& replaceImplDiscr(iterator i1, iterator i2, | |
InputIter b, InputIter e, | |
Selector<0>) { | |
replaceImpl(i1, i2, b, e, | |
typename std::iterator_traits<InputIter>::iterator_category()); | |
return *this; | |
} | |
private: | |
template <class FwdIterator> | |
bool replaceAliased(iterator i1, iterator i2, | |
FwdIterator s1, FwdIterator s2, std::false_type) { | |
return false; | |
} | |
template <class FwdIterator> | |
bool replaceAliased(iterator i1, iterator i2, | |
FwdIterator s1, FwdIterator s2, std::true_type) { | |
static const std::less_equal<const value_type*> le = | |
std::less_equal<const value_type*>(); | |
const bool aliased = le(&*begin(), &*s1) && le(&*s1, &*end()); | |
if (!aliased) { | |
return false; | |
} | |
// Aliased replace, copy to new string | |
basic_fbstring temp; | |
temp.reserve(size() - (i2 - i1) + std::distance(s1, s2)); | |
temp.append(begin(), i1).append(s1, s2).append(i2, end()); | |
swap(temp); | |
return true; | |
} | |
template <class FwdIterator> | |
void replaceImpl(iterator i1, iterator i2, | |
FwdIterator s1, FwdIterator s2, std::forward_iterator_tag) { | |
Invariant checker(*this); | |
(void) checker; | |
// Handle aliased replace | |
if (replaceAliased(i1, i2, s1, s2, | |
std::integral_constant<bool, | |
std::is_same<FwdIterator, iterator>::value || | |
std::is_same<FwdIterator, const_iterator>::value>())) { | |
return; | |
} | |
auto const n1 = i2 - i1; | |
assert(n1 >= 0); | |
auto const n2 = std::distance(s1, s2); | |
assert(n2 >= 0); | |
if (n1 > n2) { | |
// shrinks | |
std::copy(s1, s2, i1); | |
erase(i1 + n2, i2); | |
} else { | |
// grows | |
fbstring_detail::copy_n(s1, n1, i1); | |
std::advance(s1, n1); | |
insert(i2, s1, s2); | |
} | |
assert(isSane()); | |
} | |
template <class InputIterator> | |
void replaceImpl(iterator i1, iterator i2, | |
InputIterator b, InputIterator e, std::input_iterator_tag) { | |
basic_fbstring temp(begin(), i1); | |
temp.append(b, e).append(i2, end()); | |
swap(temp); | |
} | |
public: | |
template <class T1, class T2> | |
basic_fbstring& replace(iterator i1, iterator i2, | |
T1 first_or_n_or_s, T2 last_or_c_or_n) { | |
const bool | |
num1 = std::numeric_limits<T1>::is_specialized, | |
num2 = std::numeric_limits<T2>::is_specialized; | |
return replaceImplDiscr( | |
i1, i2, first_or_n_or_s, last_or_c_or_n, | |
Selector<num1 ? (num2 ? 1 : -1) : (num2 ? 2 : 0)>()); | |
} | |
size_type copy(value_type* s, size_type n, size_type pos = 0) const { | |
enforce(pos <= size(), std::__throw_out_of_range, ""); | |
procrustes(n, size() - pos); | |
fbstring_detail::pod_copy( | |
data() + pos, | |
data() + pos + n, | |
s); | |
return n; | |
} | |
void swap(basic_fbstring& rhs) { | |
store_.swap(rhs.store_); | |
} | |
const value_type* c_str() const { | |
return store_.c_str(); | |
} | |
const value_type* data() const { return c_str(); } | |
allocator_type get_allocator() const { | |
return allocator_type(); | |
} | |
size_type find(const basic_fbstring& str, size_type pos = 0) const { | |
return find(str.data(), pos, str.length()); | |
} | |
size_type find(const value_type* needle, const size_type pos, | |
const size_type nsize) const { | |
if (!nsize) return pos; | |
auto const size = this->size(); | |
// nsize + pos can overflow (eg pos == npos), guard against that by checking | |
// that nsize + pos does not wrap around. | |
if (nsize + pos > size || nsize + pos < pos) return npos; | |
// Don't use std::search, use a Boyer-Moore-like trick by comparing | |
// the last characters first | |
auto const haystack = data(); | |
auto const nsize_1 = nsize - 1; | |
auto const lastNeedle = needle[nsize_1]; | |
// Boyer-Moore skip value for the last char in the needle. Zero is | |
// not a valid value; skip will be computed the first time it's | |
// needed. | |
size_type skip = 0; | |
const E * i = haystack + pos; | |
auto iEnd = haystack + size - nsize_1; | |
while (i < iEnd) { | |
// Boyer-Moore: match the last element in the needle | |
while (i[nsize_1] != lastNeedle) { | |
if (++i == iEnd) { | |
// not found | |
return npos; | |
} | |
} | |
// Here we know that the last char matches | |
// Continue in pedestrian mode | |
for (size_t j = 0; ; ) { | |
assert(j < nsize); | |
if (i[j] != needle[j]) { | |
// Not found, we can skip | |
// Compute the skip value lazily | |
if (skip == 0) { | |
skip = 1; | |
while (skip <= nsize_1 && needle[nsize_1 - skip] != lastNeedle) { | |
++skip; | |
} | |
} | |
i += skip; | |
break; | |
} | |
// Check if done searching | |
if (++j == nsize) { | |
// Yay | |
return i - haystack; | |
} | |
} | |
} | |
return npos; | |
} | |
size_type find(const value_type* s, size_type pos = 0) const { | |
return find(s, pos, traits_type::length(s)); | |
} | |
size_type find (value_type c, size_type pos = 0) const { | |
return find(&c, pos, 1); | |
} | |
size_type rfind(const basic_fbstring& str, size_type pos = npos) const { | |
return rfind(str.data(), pos, str.length()); | |
} | |
size_type rfind(const value_type* s, size_type pos, size_type n) const { | |
if (n > length()) return npos; | |
pos = std::min(pos, length() - n); | |
if (n == 0) return pos; | |
const_iterator i(begin() + pos); | |
for (; ; --i) { | |
if (traits_type::eq(*i, *s) | |
&& traits_type::compare(&*i, s, n) == 0) { | |
return i - begin(); | |
} | |
if (i == begin()) break; | |
} | |
return npos; | |
} | |
size_type rfind(const value_type* s, size_type pos = npos) const { | |
return rfind(s, pos, traits_type::length(s)); | |
} | |
size_type rfind(value_type c, size_type pos = npos) const { | |
return rfind(&c, pos, 1); | |
} | |
size_type find_first_of(const basic_fbstring& str, size_type pos = 0) const { | |
return find_first_of(str.data(), pos, str.length()); | |
} | |
size_type find_first_of(const value_type* s, | |
size_type pos, size_type n) const { | |
if (pos > length() || n == 0) return npos; | |
const_iterator i(begin() + pos), | |
finish(end()); | |
for (; i != finish; ++i) { | |
if (traits_type::find(s, n, *i) != 0) { | |
return i - begin(); | |
} | |
} | |
return npos; | |
} | |
size_type find_first_of(const value_type* s, size_type pos = 0) const { | |
return find_first_of(s, pos, traits_type::length(s)); | |
} | |
size_type find_first_of(value_type c, size_type pos = 0) const { | |
return find_first_of(&c, pos, 1); | |
} | |
size_type find_last_of (const basic_fbstring& str, | |
size_type pos = npos) const { | |
return find_last_of(str.data(), pos, str.length()); | |
} | |
size_type find_last_of (const value_type* s, size_type pos, | |
size_type n) const { | |
if (!empty() && n > 0) { | |
pos = std::min(pos, length() - 1); | |
const_iterator i(begin() + pos); | |
for (;; --i) { | |
if (traits_type::find(s, n, *i) != 0) { | |
return i - begin(); | |
} | |
if (i == begin()) break; | |
} | |
} | |
return npos; | |
} | |
size_type find_last_of (const value_type* s, | |
size_type pos = npos) const { | |
return find_last_of(s, pos, traits_type::length(s)); | |
} | |
size_type find_last_of (value_type c, size_type pos = npos) const { | |
return find_last_of(&c, pos, 1); | |
} | |
size_type find_first_not_of(const basic_fbstring& str, | |
size_type pos = 0) const { | |
return find_first_not_of(str.data(), pos, str.size()); | |
} | |
size_type find_first_not_of(const value_type* s, size_type pos, | |
size_type n) const { | |
if (pos < length()) { | |
const_iterator | |
i(begin() + pos), | |
finish(end()); | |
for (; i != finish; ++i) { | |
if (traits_type::find(s, n, *i) == 0) { | |
return i - begin(); | |
} | |
} | |
} | |
return npos; | |
} | |
size_type find_first_not_of(const value_type* s, | |
size_type pos = 0) const { | |
return find_first_not_of(s, pos, traits_type::length(s)); | |
} | |
size_type find_first_not_of(value_type c, size_type pos = 0) const { | |
return find_first_not_of(&c, pos, 1); | |
} | |
size_type find_last_not_of(const basic_fbstring& str, | |
size_type pos = npos) const { | |
return find_last_not_of(str.data(), pos, str.length()); | |
} | |
size_type find_last_not_of(const value_type* s, size_type pos, | |
size_type n) const { | |
if (!this->empty()) { | |
pos = std::min(pos, size() - 1); | |
const_iterator i(begin() + pos); | |
for (;; --i) { | |
if (traits_type::find(s, n, *i) == 0) { | |
return i - begin(); | |
} | |
if (i == begin()) break; | |
} | |
} | |
return npos; | |
} | |
size_type find_last_not_of(const value_type* s, | |
size_type pos = npos) const { | |
return find_last_not_of(s, pos, traits_type::length(s)); | |
} | |
size_type find_last_not_of (value_type c, size_type pos = npos) const { | |
return find_last_not_of(&c, pos, 1); | |
} | |
basic_fbstring substr(size_type pos = 0, size_type n = npos) const { | |
enforce(pos <= size(), std::__throw_out_of_range, ""); | |
return basic_fbstring(data() + pos, std::min(n, size() - pos)); | |
} | |
int compare(const basic_fbstring& str) const { | |
// FIX due to Goncalo N M de Carvalho July 18, 2005 | |
return compare(0, size(), str); | |
} | |
int compare(size_type pos1, size_type n1, | |
const basic_fbstring& str) const { | |
return compare(pos1, n1, str.data(), str.size()); | |
} | |
int compare(size_type pos1, size_type n1, | |
const value_type* s) const { | |
return compare(pos1, n1, s, traits_type::length(s)); | |
} | |
int compare(size_type pos1, size_type n1, | |
const value_type* s, size_type n2) const { | |
enforce(pos1 <= size(), std::__throw_out_of_range, ""); | |
procrustes(n1, size() - pos1); | |
// The line below fixed by Jean-Francois Bastien, 04-23-2007. Thanks! | |
const int r = traits_type::compare(pos1 + data(), s, std::min(n1, n2)); | |
return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0; | |
} | |
int compare(size_type pos1, size_type n1, | |
const basic_fbstring& str, | |
size_type pos2, size_type n2) const { | |
enforce(pos2 <= str.size(), std::__throw_out_of_range, ""); | |
return compare(pos1, n1, str.data() + pos2, | |
std::min(n2, str.size() - pos2)); | |
} | |
// Code from Jean-Francois Bastien (03/26/2007) | |
int compare(const value_type* s) const { | |
// Could forward to compare(0, size(), s, traits_type::length(s)) | |
// but that does two extra checks | |
const size_type n1(size()), n2(traits_type::length(s)); | |
const int r = traits_type::compare(data(), s, std::min(n1, n2)); | |
return r != 0 ? r : n1 > n2 ? 1 : n1 < n2 ? -1 : 0; | |
} | |
private: | |
// Data | |
Storage store_; | |
}; | |
// non-member functions | |
// C++11 21.4.8.1/2 | |
template <typename E, class T, class A, class S> | |
inline | |
basic_fbstring<E, T, A, S> operator+(const basic_fbstring<E, T, A, S>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
basic_fbstring<E, T, A, S> result; | |
result.reserve(lhs.size() + rhs.size()); | |
result.append(lhs).append(rhs); | |
return std::move(result); | |
} | |
// C++11 21.4.8.1/2 | |
template <typename E, class T, class A, class S> | |
inline | |
basic_fbstring<E, T, A, S> operator+(basic_fbstring<E, T, A, S>&& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return std::move(lhs.append(rhs)); | |
} | |
// C++11 21.4.8.1/3 | |
template <typename E, class T, class A, class S> | |
inline | |
basic_fbstring<E, T, A, S> operator+(const basic_fbstring<E, T, A, S>& lhs, | |
basic_fbstring<E, T, A, S>&& rhs) { | |
if (rhs.capacity() >= lhs.size() + rhs.size()) { | |
// Good, at least we don't need to reallocate | |
return std::move(rhs.insert(0, lhs)); | |
} | |
// Meh, no go. Forward to operator+(const&, const&). | |
auto const& rhsC = rhs; | |
return lhs + rhsC; | |
} | |
// C++11 21.4.8.1/4 | |
template <typename E, class T, class A, class S> | |
inline | |
basic_fbstring<E, T, A, S> operator+(basic_fbstring<E, T, A, S>&& lhs, | |
basic_fbstring<E, T, A, S>&& rhs) { | |
return std::move(lhs.append(rhs)); | |
} | |
template <typename E, class T, class A, class S> | |
inline | |
basic_fbstring<E, T, A, S> operator+( | |
const typename basic_fbstring<E, T, A, S>::value_type* lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
// | |
basic_fbstring<E, T, A, S> result; | |
const typename basic_fbstring<E, T, A, S>::size_type len = | |
basic_fbstring<E, T, A, S>::traits_type::length(lhs); | |
result.reserve(len + rhs.size()); | |
result.append(lhs, len).append(rhs); | |
return result; | |
} | |
template <typename E, class T, class A, class S> | |
inline | |
basic_fbstring<E, T, A, S> operator+( | |
typename basic_fbstring<E, T, A, S>::value_type lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
basic_fbstring<E, T, A, S> result; | |
result.reserve(1 + rhs.size()); | |
result.push_back(lhs); | |
result.append(rhs); | |
return result; | |
} | |
template <typename E, class T, class A, class S> | |
inline | |
basic_fbstring<E, T, A, S> operator+( | |
const basic_fbstring<E, T, A, S>& lhs, | |
const typename basic_fbstring<E, T, A, S>::value_type* rhs) { | |
typedef typename basic_fbstring<E, T, A, S>::size_type size_type; | |
typedef typename basic_fbstring<E, T, A, S>::traits_type traits_type; | |
basic_fbstring<E, T, A, S> result; | |
const size_type len = traits_type::length(rhs); | |
result.reserve(lhs.size() + len); | |
result.append(lhs).append(rhs, len); | |
return result; | |
} | |
template <typename E, class T, class A, class S> | |
inline | |
basic_fbstring<E, T, A, S> operator+( | |
const basic_fbstring<E, T, A, S>& lhs, | |
typename basic_fbstring<E, T, A, S>::value_type rhs) { | |
basic_fbstring<E, T, A, S> result; | |
result.reserve(lhs.size() + 1); | |
result.append(lhs); | |
result.push_back(rhs); | |
return result; | |
} | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator==(const basic_fbstring<E, T, A, S>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator==(const typename basic_fbstring<E, T, A, S>::value_type* lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return rhs == lhs; } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator==(const basic_fbstring<E, T, A, S>& lhs, | |
const typename basic_fbstring<E, T, A, S>::value_type* rhs) { | |
return lhs.compare(rhs) == 0; } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator!=(const basic_fbstring<E, T, A, S>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(lhs == rhs); } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator!=(const typename basic_fbstring<E, T, A, S>::value_type* lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(lhs == rhs); } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator!=(const basic_fbstring<E, T, A, S>& lhs, | |
const typename basic_fbstring<E, T, A, S>::value_type* rhs) { | |
return !(lhs == rhs); } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator<(const basic_fbstring<E, T, A, S>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return lhs.compare(rhs) < 0; } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator<(const basic_fbstring<E, T, A, S>& lhs, | |
const typename basic_fbstring<E, T, A, S>::value_type* rhs) { | |
return lhs.compare(rhs) < 0; } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator<(const typename basic_fbstring<E, T, A, S>::value_type* lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return rhs.compare(lhs) > 0; } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator>(const basic_fbstring<E, T, A, S>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return rhs < lhs; } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator>(const basic_fbstring<E, T, A, S>& lhs, | |
const typename basic_fbstring<E, T, A, S>::value_type* rhs) { | |
return rhs < lhs; } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator>(const typename basic_fbstring<E, T, A, S>::value_type* lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return rhs < lhs; } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator<=(const basic_fbstring<E, T, A, S>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(rhs < lhs); } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator<=(const basic_fbstring<E, T, A, S>& lhs, | |
const typename basic_fbstring<E, T, A, S>::value_type* rhs) { | |
return !(rhs < lhs); } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator<=(const typename basic_fbstring<E, T, A, S>::value_type* lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(rhs < lhs); } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator>=(const basic_fbstring<E, T, A, S>& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(lhs < rhs); } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator>=(const basic_fbstring<E, T, A, S>& lhs, | |
const typename basic_fbstring<E, T, A, S>::value_type* rhs) { | |
return !(lhs < rhs); } | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator>=(const typename basic_fbstring<E, T, A, S>::value_type* lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(lhs < rhs); | |
} | |
// C++11 21.4.8.8 | |
template <typename E, class T, class A, class S> | |
void swap(basic_fbstring<E, T, A, S>& lhs, basic_fbstring<E, T, A, S>& rhs) { | |
lhs.swap(rhs); | |
} | |
// TODO: make this faster. | |
template <typename E, class T, class A, class S> | |
inline | |
std::basic_istream< | |
typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type>& | |
operator>>( | |
std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type>& is, | |
basic_fbstring<E, T, A, S>& str) { | |
typename std::basic_istream<E, T>::sentry sentry(is); | |
typedef std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type> | |
__istream_type; | |
typedef typename __istream_type::ios_base __ios_base; | |
size_t extracted = 0; | |
auto err = __ios_base::goodbit; | |
if (sentry) { | |
auto n = is.width(); | |
if (n == 0) { | |
n = str.max_size(); | |
} | |
str.erase(); | |
auto got = is.rdbuf()->sgetc(); | |
for (; extracted != n && got != T::eof() && !isspace(got); ++extracted) { | |
// Whew. We get to store this guy | |
str.push_back(got); | |
got = is.rdbuf()->snextc(); | |
} | |
if (got == T::eof()) { | |
err |= __ios_base::eofbit; | |
is.width(0); | |
} | |
} | |
if (!extracted) { | |
err |= __ios_base::failbit; | |
} | |
if (err) { | |
is.setstate(err); | |
} | |
return is; | |
} | |
template <typename E, class T, class A, class S> | |
inline | |
std::basic_ostream<typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type>& | |
operator<<( | |
std::basic_ostream<typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type>& os, | |
const basic_fbstring<E, T, A, S>& str) { | |
#if _LIBCPP_VERSION | |
typename std::basic_ostream< | |
typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type>::sentry __s(os); | |
if (__s) { | |
typedef std::ostreambuf_iterator< | |
typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type> _Ip; | |
size_t __len = str.size(); | |
bool __left = | |
(os.flags() & std::ios_base::adjustfield) == std::ios_base::left; | |
if (__pad_and_output(_Ip(os), | |
str.data(), | |
__left ? str.data() + __len : str.data(), | |
str.data() + __len, | |
os, | |
os.fill()).failed()) { | |
os.setstate(std::ios_base::badbit | std::ios_base::failbit); | |
} | |
} | |
#else | |
std::__ostream_insert(os, str.data(), str.size()); | |
#endif | |
return os; | |
} | |
#ifndef _LIBSTDCXX_FBSTRING | |
template <typename E, class T, class A, class S> | |
inline | |
std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type>& | |
getline( | |
std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type>& is, | |
basic_fbstring<E, T, A, S>& str, | |
typename basic_fbstring<E, T, A, S>::value_type delim) { | |
// Use the nonstandard getdelim() | |
char * buf = nullptr; | |
size_t size = 0; | |
for (;;) { | |
// This looks quadratic but it really depends on realloc | |
auto const newSize = size + 128; | |
buf = static_cast<char*>(checkedRealloc(buf, newSize)); | |
is.getline(buf + size, newSize - size, delim); | |
if (is.bad() || is.eof() || !is.fail()) { | |
// done by either failure, end of file, or normal read | |
size += std::strlen(buf + size); | |
break; | |
} | |
// Here we have failed due to too short a buffer | |
// Minus one to discount the terminating '\0' | |
size = newSize - 1; | |
assert(buf[size] == 0); | |
// Clear the error so we can continue reading | |
is.clear(); | |
} | |
basic_fbstring<E, T, A, S> result(buf, size, size + 1, | |
AcquireMallocatedString()); | |
result.swap(str); | |
return is; | |
} | |
template <typename E, class T, class A, class S> | |
inline | |
std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type>& | |
getline( | |
std::basic_istream<typename basic_fbstring<E, T, A, S>::value_type, | |
typename basic_fbstring<E, T, A, S>::traits_type>& is, | |
basic_fbstring<E, T, A, S>& str) { | |
// Just forward to the version with a delimiter | |
return getline(is, str, '\n'); | |
} | |
#endif | |
template <typename E1, class T, class A, class S> | |
const typename basic_fbstring<E1, T, A, S>::size_type | |
basic_fbstring<E1, T, A, S>::npos = | |
static_cast<typename basic_fbstring<E1, T, A, S>::size_type>(-1); | |
#ifndef _LIBSTDCXX_FBSTRING | |
// basic_string compatibility routines | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator==(const basic_fbstring<E, T, A, S>& lhs, | |
const std::string& rhs) { | |
return lhs.compare(0, lhs.size(), rhs.data(), rhs.size()) == 0; | |
} | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator==(const std::string& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return rhs == lhs; | |
} | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator!=(const basic_fbstring<E, T, A, S>& lhs, | |
const std::string& rhs) { | |
return !(lhs == rhs); | |
} | |
template <typename E, class T, class A, class S> | |
inline | |
bool operator!=(const std::string& lhs, | |
const basic_fbstring<E, T, A, S>& rhs) { | |
return !(lhs == rhs); | |
} | |
#if !defined(_LIBSTDCXX_FBSTRING) | |
typedef basic_fbstring<char> fbstring; | |
#endif | |
// fbstring is relocatable | |
template <class T, class R, class A, class S> | |
FOLLY_ASSUME_RELOCATABLE(basic_fbstring<T, R, A, S>); | |
#else | |
_GLIBCXX_END_NAMESPACE_VERSION | |
#endif | |
} // namespace folly | |
#ifndef _LIBSTDCXX_FBSTRING | |
// Hash functions to make fbstring usable with e.g. hash_map | |
// | |
// Handle interaction with different C++ standard libraries, which | |
// expect these types to be in different namespaces. | |
#define FOLLY_FBSTRING_HASH1(T) \ | |
template <> \ | |
struct hash< ::folly::basic_fbstring<T> > { \ | |
size_t operator()(const ::folly::fbstring& s) const { \ | |
return ::folly::hash::fnv32_buf(s.data(), s.size()); \ | |
} \ | |
}; |
from folly.
Thank you for reporting this issue and appreciate your patience. We've notified the core team for an update on this issue. We're looking for a response within the next 30 days or the issue may be closed.
from folly.
Thank you for your patience. We're going to close out this issue. If you're still experiencing the problem described, please reopen the issue - thanks!
from folly.
Hello! This is a human. My previous comment on this issue was a robot running amok. I apologize that the issue was closed, and am re-opening it. Thanks for your help with our folly project and for your understanding about rogue robots trying to take over the world.
from folly.
Hello human. I haven't tried rebuilding in many months - I was left with the impression that folly would never run on OSx, and so I was unsurprised that the ticket was closed.
Perhaps interest will increase with the next release of OSx whose clang compiler may support thread_local, although I suspect more incompatibilities will just surface and we'll be in the same spot.
from folly.
The newest homebrew formula should work fine now.
Homebrew/legacy-homebrew@3ef948b
from folly.
Related Issues (20)
- folly & double-conversion: Unable to build surround360_render
- Spawning contexts that form non converging sequences in a non deterministic way, missing data, and memory problems.
- Issue with folly & double-conversion: Unable to build surround360_render HOT 2
- comment about encodeZigZag in Varint.h is wrong.
- complie erron on windows msvc
- How to compile folly easily?
- V11.14.0 HOT 1
- sorted_vector_map::insert_or_assign() returns the wrong type
- ViaIfAsync issue HOT 1
- error: use of deleted function 'folly::f14::detail::ValueContainerPolicy' HOT 1
- Unable to build "main" branch HOT 2
- crc32 : the calculation result of folly is inconsistent with the calculation result of ISAL
- use folly library failed HOT 1
- À
- Proxygen Linux compilation breaking in folly io_uring
- Compilation error HOT 2
- CommandLineTools 15 possible bug
- coroutine stack overflows
- use of Expected triggers warning
- MPMCQueue blockingRead() doesn't return even with a subsequent write() HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from folly.