diff options
Diffstat (limited to 'runtime/base/out.h')
| -rw-r--r-- | runtime/base/out.h | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/runtime/base/out.h b/runtime/base/out.h new file mode 100644 index 0000000000..7b4bc1216c --- /dev/null +++ b/runtime/base/out.h @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_BASE_OUT_H_ +#define ART_RUNTIME_BASE_OUT_H_ + +#include <base/macros.h> +#include <base/logging.h> + +#include <memory> +// A zero-overhead abstraction marker that means this value is meant to be used as an out +// parameter for functions. It mimics semantics of a pointer that the function will +// dereference and output its value into. +// +// Inspired by the 'out' language keyword in C#. +// +// Declaration example: +// int do_work(size_t args, out<int> result); +// // returns 0 on success, sets result, otherwise error code +// +// Use-site example: +// // (1) -- out of a local variable or field +// int res; +// if (do_work(1, outof(res)) { +// cout << "success: " << res; +// } +// // (2) -- out of an iterator +// std::vector<int> list = {1}; +// std::vector<int>::iterator it = list.begin(); +// if (do_work(2, outof_iterator(*it)) { +// cout << "success: " << list[0]; +// } +// // (3) -- out of a pointer +// int* array = &some_other_value; +// if (do_work(3, outof_ptr(array))) { +// cout << "success: " << *array; +// } +// +// The type will also automatically decay into a C-style pointer for compatibility +// with calling legacy code that expect pointers. +// +// Declaration example: +// void write_data(int* res) { *res = 5; } +// +// Use-site example: +// int data; +// write_data(outof(res)); +// // data is now '5' +// (The other outof_* functions can be used analogously when the target is a C-style pointer). +// +// --------------- +// +// Other typical pointer operations such as addition, subtraction, etc are banned +// since there is exactly one value being output. +// +namespace art { + +// Forward declarations. See below for specific functions. +template <typename T> +struct out_convertible; // Implicitly converts to out<T> or T*. + +// Helper function that automatically infers 'T' +// +// Returns a type that is implicitly convertible to either out<T> or T* depending +// on the call site. +// +// Example: +// int do_work(size_t args, out<int> result); +// // returns 0 on success, sets result, otherwise error code +// +// Usage: +// int res; +// if (do_work(1, outof(res)) { +// cout << "success: " << res; +// } +template <typename T> +out_convertible<T> outof(T& param) ALWAYS_INLINE; + +// Helper function that automatically infers 'T' from a container<T>::iterator. +// To use when the argument is already inside an iterator. +// +// Returns a type that is implicitly convertible to either out<T> or T* depending +// on the call site. +// +// Example: +// int do_work(size_t args, out<int> result); +// // returns 0 on success, sets result, otherwise error code +// +// Usage: +// std::vector<int> list = {1}; +// std::vector<int>::iterator it = list.begin(); +// if (do_work(2, outof_iterator(*it)) { +// cout << "success: " << list[0]; +// } +template <typename It> +auto ALWAYS_INLINE outof_iterator(It iter) + -> out_convertible<typename std::remove_reference<decltype(*iter)>::type>; + +// Helper function that automatically infers 'T'. +// To use when the argument is already a pointer. +// +// ptr must be not-null, else a DCHECK failure will occur. +// +// Returns a type that is implicitly convertible to either out<T> or T* depending +// on the call site. +// +// Example: +// int do_work(size_t args, out<int> result); +// // returns 0 on success, sets result, otherwise error code +// +// Usage: +// int* array = &some_other_value; +// if (do_work(3, outof_ptr(array))) { +// cout << "success: " << *array; +// } +template <typename T> +out_convertible<T> outof_ptr(T* ptr) ALWAYS_INLINE; + +// Zero-overhead wrapper around a non-null non-const pointer meant to be used to output +// the result of parameters. There are no other extra guarantees. +// +// The most common use case is to treat this like a typical pointer argument, for example: +// +// void write_out_5(out<int> x) { +// *x = 5; +// } +// +// The following operations are supported: +// operator* -> use like a pointer (guaranteed to be non-null) +// == and != -> compare against other pointers for (in)equality +// begin/end -> use in standard C++ algorithms as if it was an iterator +template <typename T> +struct out { + // Has to be mutable lref. Otherwise how would you write something as output into it? + explicit inline out(T& param) + : param_(param) {} + + // Model a single-element iterator (or pointer) to the parameter. + inline T& operator *() { + return param_; + } + + // Model dereferencing fields/methods on a pointer. + inline T* operator->() { + return std::addressof(param_); + } + + // + // Comparison against this or other pointers. + // + template <typename T2> + inline bool operator==(const T2* other) const { + return std::addressof(param_) == other; + } + + template <typename T2> + inline bool operator==(const out<T>& other) const { + return std::addressof(param_) == std::addressof(other.param_); + } + + // An out-parameter is never null. + inline bool operator==(std::nullptr_t) const { + return false; + } + + template <typename T2> + inline bool operator!=(const T2* other) const { + return std::addressof(param_) != other; + } + + template <typename T2> + inline bool operator!=(const out<T>& other) const { + return std::addressof(param_) != std::addressof(other.param_); + } + + // An out-parameter is never null. + inline bool operator!=(std::nullptr_t) const { + return true; + } + + // + // Iterator interface implementation. Use with standard algorithms. + // TODO: (add items in iterator_traits if this is truly useful). + // + + inline T* begin() { + return std::addressof(param_); + } + + inline const T* begin() const { + return std::addressof(param_); + } + + inline T* end() { + return std::addressof(param_) + 1; + } + + inline const T* end() const { + return std::addressof(param_) + 1; + } + + private: + T& param_; +}; + +// +// IMPLEMENTATION DETAILS +// + +// +// This intermediate type should not be used directly by user code. +// +// It enables 'outof(x)' to be passed into functions that expect either +// an out<T> **or** a regular C-style pointer (T*). +// +template <typename T> +struct out_convertible { + explicit inline out_convertible(T& param) + : param_(param) { + } + + // Implicitly convert into an out<T> for standard usage. + inline operator out<T>() { + return out<T>(param_); + } + + // Implicitly convert into a '*' for legacy usage. + inline operator T*() { + return std::addressof(param_); + } + private: + T& param_; +}; + +// Helper function that automatically infers 'T' +template <typename T> +inline out_convertible<T> outof(T& param) { + return out_convertible<T>(param); +} + +// Helper function that automatically infers 'T'. +// To use when the argument is already inside an iterator. +template <typename It> +inline auto outof_iterator(It iter) + -> out_convertible<typename std::remove_reference<decltype(*iter)>::type> { + return outof(*iter); +} + +// Helper function that automatically infers 'T'. +// To use when the argument is already a pointer. +template <typename T> +inline out_convertible<T> outof_ptr(T* ptr) { + DCHECK(ptr != nullptr); + return outof(*ptr); +} + +// Helper function that automatically infers 'T'. +// Forwards an out parameter from one function into another. +template <typename T> +inline out_convertible<T> outof_forward(out<T>& out_param) { + T& param = *out_param; + return out_convertible<T>(param); +} + +} // namespace art +#endif // ART_RUNTIME_BASE_OUT_H_ |