fix ASAN build
[folly.git] / folly / Padded.h
index 6de44a3bc13feef8768361e63c791616171e44b9..f30e22265bb9dd9dd91edc72beaaebf2b2aae0b4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#ifndef FOLLY_PADDED_H_
-#define FOLLY_PADDED_H_
+#pragma once
 
+#include <algorithm>
 #include <cassert>
 #include <cstdint>
 #include <cstring>
@@ -27,7 +27,8 @@
 
 #include <boost/iterator/iterator_adaptor.hpp>
 
-#include "folly/Portability.h"
+#include <folly/Portability.h>
+#include <folly/Traits.h>
 
 /**
  * Code that aids in storing data aligned on block (possibly cache-line)
@@ -66,7 +67,7 @@ struct NodeValid<T, NS,
                      NS % alignof(T) == 0)>::type> {
   typedef void type;
 };
-}  // namespace detail
+} // namespace detail
 
 template <class T, size_t NS>
 class Node<T, NS, typename detail::NodeValid<T,NS>::type> {
@@ -144,6 +145,33 @@ template <class Iter> class Iterator;
 
 namespace detail {
 
+template <typename Void, typename Container, typename... Args>
+struct padded_emplace_back_or_push_back_ {
+  static decltype(auto) go(Container& container, Args&&... args) {
+    using Value = typename Container::value_type;
+    return container.push_back(Value(std::forward<Args>(args)...));
+  }
+};
+
+template <typename Container, typename... Args>
+struct padded_emplace_back_or_push_back_<
+    void_t<decltype(
+        std::declval<Container&>().emplace_back(std::declval<Args>()...))>,
+    Container,
+    Args...> {
+  static decltype(auto) go(Container& container, Args&&... args) {
+    return container.emplace_back(std::forward<Args>(args)...);
+  }
+};
+
+template <typename Container, typename... Args>
+decltype(auto) padded_emplace_back_or_push_back(
+    Container& container,
+    Args&&... args) {
+  using impl = padded_emplace_back_or_push_back_<void, Container, Args...>;
+  return impl::go(container, std::forward<Args>(args)...);
+}
+
 // Helper class to transfer the constness from From (a lvalue reference)
 // and create a lvalue reference to To.
 //
@@ -189,7 +217,7 @@ struct IteratorBase {
   > type;
 };
 
-}  // namespace detail
+} // namespace detail
 
 /**
  * Wrapper around iterators to Node to return iterators to the underlying
@@ -344,13 +372,14 @@ class Adaptor {
       lastCount_(lastCount) {
   }
   explicit Adaptor(size_t n, const value_type& value = value_type())
-    : c_(Node::nodeCount(n), fullNode(value)),
-      lastCount_(n % Node::kElementCount ?: Node::kElementCount) {
+    : c_(Node::nodeCount(n), fullNode(value)) {
+    const auto count = n % Node::kElementCount;
+    lastCount_ = count != 0 ? count : Node::kElementCount;
   }
 
   Adaptor(const Adaptor&) = default;
   Adaptor& operator=(const Adaptor&) = default;
-  Adaptor(Adaptor&& other)
+  Adaptor(Adaptor&& other) noexcept
     : c_(std::move(other.c_)),
       lastCount_(other.lastCount_) {
     other.lastCount_ = Node::kElementCount;
@@ -383,7 +412,7 @@ class Adaptor {
   iterator end() {
     auto it = iterator(c_.end());
     if (lastCount_ != Node::kElementCount) {
-      it -= (Node::kElementCount - lastCount_);
+      it -= difference_type(Node::kElementCount - lastCount_);
     }
     return it;
   }
@@ -424,12 +453,13 @@ class Adaptor {
     return c_.back().data()[lastCount_ - 1];
   }
 
+  template <typename... Args>
+  void emplace_back(Args&&... args) {
+    new (allocate_back()) value_type(std::forward<Args>(args)...);
+  }
+
   void push_back(value_type x) {
-    if (lastCount_ == Node::kElementCount) {
-      c_.push_back(Node());
-      lastCount_ = 0;
-    }
-    c_.back().data()[lastCount_++] = std::move(x);
+    emplace_back(std::move(x));
   }
 
   void pop_back() {
@@ -490,6 +520,14 @@ class Adaptor {
   }
 
  private:
+  value_type* allocate_back() {
+    if (lastCount_ == Node::kElementCount) {
+      detail::padded_emplace_back_or_push_back(c_);
+      lastCount_ = 0;
+    }
+    return &c_.back().data()[lastCount_++];
+  }
+
   static Node fullNode(const value_type& value) {
     Node n;
     std::fill(n.data(), n.data() + kElementsPerNode, value);
@@ -499,8 +537,5 @@ class Adaptor {
   size_t lastCount_;  // number of elements in last Node
 };
 
-}  // namespace padded
-}  // namespace folly
-
-#endif /* FOLLY_PADDED_H_ */
-
+} // namespace padded
+} // namespace folly