1/*
2 * Copyright 2013-present Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <memory>
20
21namespace folly {
22
23/** C++11 closures don't support move-in capture. Nor does std::bind.
24 facepalm.
25
26 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3610.html
27
28 "[...] a work-around that should make people's stomach crawl:
29 write a wrapper that performs move-on-copy, much like the deprecated
30 auto_ptr"
31
32 Unlike auto_ptr, this doesn't require a heap allocation.
33 */
34template <class T>
35class MoveWrapper {
36 public:
37 /** If value can be default-constructed, why not?
38 Then we don't have to move it in */
39 MoveWrapper() = default;
40
41 /// Move a value in.
42 explicit MoveWrapper(T&& t) : value(std::move(t)) {}
43
44 /// copy is move
45 MoveWrapper(const MoveWrapper& other) : value(std::move(other.value)) {}
46
47 /// move is also move
48 MoveWrapper(MoveWrapper&& other) : value(std::move(other.value)) {}
49
50 const T& operator*() const {
51 return value;
52 }
53 T& operator*() {
54 return value;
55 }
56
57 const T* operator->() const {
58 return &value;
59 }
60 T* operator->() {
61 return &value;
62 }
63
64 /// move the value out (sugar for std::move(*moveWrapper))
65 T&& move() {
66 return std::move(value);
67 }
68
69 // If you want these you're probably doing it wrong, though they'd be
70 // easy enough to implement
71 MoveWrapper& operator=(MoveWrapper const&) = delete;
72 MoveWrapper& operator=(MoveWrapper&&) = delete;
73
74 private:
75 mutable T value;
76};
77
78/// Make a MoveWrapper from the argument. Because the name "makeMoveWrapper"
79/// is already quite transparent in its intent, this will work for lvalues as
80/// if you had wrapped them in std::move.
81template <class T, class T0 = typename std::remove_reference<T>::type>
82MoveWrapper<T0> makeMoveWrapper(T&& t) {
83 return MoveWrapper<T0>(std::forward<T0>(t));
84}
85
86} // namespace folly
87