/*
- * Copyright 2012 Facebook, Inc.
+ * Copyright 2013 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <cassert>
#include "folly/Traits.h"
-#include "folly/Likely.h"
#include "folly/Malloc.h"
#include "folly/Hash.h"
#endif
+// We defined these here rather than including Likely.h to avoid
+// redefinition errors when fbstring is imported into libstdc++.
+#define FBSTRING_LIKELY(x) (__builtin_expect((x), 1))
+#define FBSTRING_UNLIKELY(x) (__builtin_expect((x), 0))
+
#include <atomic>
#include <limits>
#include <type_traits>
* gcc-4.7 throws what appears to be some false positive uninitialized
* warnings for the members of the MediumLarge struct. So, mute them here.
*/
+#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wuninitialized"
+#endif
/**
* This is the core of the string. The code should work on 32- and
fbstring_core() {
// Only initialize the tag, will set the MSBs (i.e. the small
// string size) to zero too
- ml_.capacity_ = maxSmallSize << (8 * (sizeof(size_t) - 1));
+ ml_.capacity_ = maxSmallSize << (8 * (sizeof(size_t) - sizeof(Char)));
// or: setSmallSize(0);
writeTerminator();
assert(category() == isSmall && size() == 0);
void push_back(Char c) {
assert(capacity() >= size());
- size_t sz, cp;
+ size_t sz;
if (category() == isSmall) {
sz = smallSize();
if (sz < maxSmallSize) {
reserve(maxSmallSize * 2);
} else {
sz = ml_.size_;
- cp = capacity(); // != ml_.capacity() for isShared()
- if (sz == cp) reserve(cp * 3 / 2);
+ if (sz == capacity()) { // always true for isShared()
+ reserve(sz * 3 / 2); // ensures not shared
+ }
}
+ assert(!isShared());
assert(capacity() >= sz + 1);
// Category can't be small - we took care of that above
assert(category() == isMedium || category() == isLarge);
ml_.size_ = sz + 1;
- mutable_data()[sz] = c;
+ ml_.data_[sz] = c;
writeTerminator();
}
return static_cast<RefCounted*>(
static_cast<void*>(
static_cast<unsigned char*>(static_cast<void*>(p))
- - offsetof(RefCounted, data_)));
+ - sizeof(refCount_)));
}
static size_t refs(Char * p) {
}
};
+#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic pop
+#endif
#ifndef _LIBSTDCXX_FBSTRING
/**
~basic_fbstring() {
}
- basic_fbstring& operator=(const basic_fbstring & lhs) {
- if (&lhs == this) {
+ basic_fbstring& operator=(const basic_fbstring& lhs) {
+ if (FBSTRING_UNLIKELY(&lhs == this)) {
return *this;
}
auto const oldSize = size();
// Move assignment
basic_fbstring& operator=(basic_fbstring&& goner) {
+ if (FBSTRING_UNLIKELY(&goner == this)) {
+ // Compatibility with std::basic_string<>,
+ // 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
Invariant checker(*this);
(void) checker;
#endif
- if (UNLIKELY(!n)) {
+ if (FBSTRING_UNLIKELY(!n)) {
// Unlikely but must be done
return *this;
}
// std::less_equal, which is guaranteed to offer a total order
// over pointers. See discussion at http://goo.gl/Cy2ya for more
// info.
- static const std::less_equal<const value_type*> le;
- if (UNLIKELY(le(oldData, s) && !le(oldData + oldSize, s))) {
+ 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);
inline
bool operator==(const basic_fbstring<E, T, A, S>& lhs,
const basic_fbstring<E, T, A, S>& rhs) {
- return lhs.compare(rhs) == 0; }
+ return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; }
template <typename E, class T, class A, class S>
inline
#endif // _LIBSTDCXX_FBSTRING
+#undef FBSTRING_LIKELY
+#undef FBSTRING_UNLIKELY
+
#endif // FOLLY_BASE_FBSTRING_H_