Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(224)

Unified Diff: src/foreach.h

Issue 433813002: Add iteration macros. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: No rvalues with MSVC Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | src/utils.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/foreach.h
diff --git a/src/foreach.h b/src/foreach.h
new file mode 100644
index 0000000000000000000000000000000000000000..01d52a5de70ebfd3505b16585c0d72af90abe342
--- /dev/null
+++ b/src/foreach.h
@@ -0,0 +1,336 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This code is heavily based on Eric Niebler's article "Conditional Love:
+// FOREACH Redux" in the "The C++ Source" journal (February 17, 2005,
+// http://www.artima.com/cppsource/foreach.html) plus some snippets from its
+// Boost incarnation, see http://www.boost.org/doc/libs/release/libs/foreach/.
+//
+// NOTE: Boost's foreach macro is much more powerful, but the header
+// transitively pulls in roughly 250 other headers. To keep things (relatively)
+// simple, we don't support iteration over arrays and C strings, and we have
+// different macros for const and non-const iteration. This can probably be
+// fixed incrementally later, but it's good enough for now.
+
+#ifndef V8_FOREACH_H_
+#define V8_FOREACH_H_
+
+#include "include/v8config.h"
+
+// VisualStudio's typing for ternaries seems to be broken, we can't handle
+// rvalues in this case.
+#if V8_CC_MSVC
+#define V8_FOREACH_RVALUE_BROKEN 1
+#endif
+
+namespace v8 {
+namespace internal {
+
+// -----------------------------------------------------------------------------
+
+// A mechanism for putting an object of unknown type in automatic storage.
+struct auto_any_base {
+ // auto_any_base must evaluate to false in boolean context so that they can be
+ // declared in if statements.
+ operator bool() const { return false; }
+};
+
+template <class T>
+struct auto_any : auto_any_base {
+ auto_any(T const& t) : item(t) {} // NOLINT
+ mutable T item;
+};
+
+// Extract a reference to the internally stored item.
+template <class T>
+T& auto_any_cast(auto_any_base const& base) {
+ return static_cast<auto_any<T> const&>(base).item;
+}
+
+// -----------------------------------------------------------------------------
+
+// Holds either a T or a T const*.
+template <typename T>
+struct simple_variant {
+ simple_variant(T const* t) : is_rvalue(false) { // NOLINT
+ *static_cast<T const**>(this->address()) = t;
+ }
+
+ simple_variant(T const& t) : is_rvalue(true) { // NOLINT
+ ::new (this->address()) T(t);
+ }
+
+ simple_variant(simple_variant const& that) : is_rvalue(that.is_rvalue) {
+ if (this->is_rvalue) {
+ ::new (this->address()) T(*that.get_c());
+ } else {
+ *static_cast<T const**>(this->address()) = that.get_c();
+ }
+ }
+
+ ~simple_variant() {
+ if (this->is_rvalue) this->get_c()->~T();
+ }
+
+ T const* get_c() const {
+ if (this->is_rvalue) {
+ return static_cast<T const*>(this->address());
+ } else {
+ return *static_cast<T const* const*>(this->address());
+ }
+ }
+
+ T* get() {
+ if (this->is_rvalue) {
+ return static_cast<T*>(this->address());
+ } else {
+ return *static_cast<T**>(this->address());
+ }
+ }
+
+ private:
+ const void* address() const { return buf; }
+ void* address() { return buf; }
+ enum size_type { size = sizeof(T) > sizeof(T*) ? sizeof(T) : sizeof(T*) };
+ simple_variant& operator=(simple_variant const&);
+ char buf[size]; // NOLINT
+ bool const is_rvalue;
+};
+
+// -----------------------------------------------------------------------------
+
+// A simple type wrapper.
+template <class T>
+struct type2type {};
+
+// Convert an expression of type T to an expression of type type2type<T>.
+template <class T>
+type2type<T> encode_type(T const& t) {
+ return type2type<T>();
+}
+
+// Convertible to type2type<T> for any T.
+struct any_type {
+ template <class T>
+ operator type2type<T>() const {
+ return type2type<T>();
+ }
+};
+
+// Convert an expression of type T to an expression of type type2type<T>
+// without evaluating the expression.
+#define V8_TYPEOF(x) (true ? any_type() : encode_type(x))
+
+// -----------------------------------------------------------------------------
+
+struct rvalue_probe {
+ template <class T>
+ rvalue_probe(T const& t, bool& b) // NOLINT
+ : ptemp(const_cast<T*>(&t)),
+ is_rvalue(b) {}
+
+ template <class R>
+ operator R() {
+ is_rvalue = true;
+ return *static_cast<R*>(ptemp);
+ }
+
+ template <class L>
+ operator L&() const {
+ is_rvalue = false;
+ return *static_cast<L*>(ptemp);
+ }
+
+ void* ptemp;
+ bool& is_rvalue;
+};
+
+#if V8_FOREACH_RVALUE_BROKEN
+#define V8_EVAL(x, is_rvalue) (x)
+#else
+// Evaluation and rvalue detection.
+#define V8_EVAL(x, is_rvalue) (true ? rvalue_probe((x), is_rvalue) : (x))
+#endif
+
+// -----------------------------------------------------------------------------
+
+// Returns a C or a C*.
+template <class C>
+auto_any<simple_variant<C> > contain(C const& t, bool const& is_rvalue) {
+ // Return either a C or a C* depending on whether the container is an rvalue
+ // or not.
+ return is_rvalue ? simple_variant<C>(t) : simple_variant<C>(&t);
+}
+
+// -----------------------------------------------------------------------------
+
+template <class C>
+auto_any<typename C::iterator> begin(auto_any_base const& container,
+ type2type<C>) {
+ return auto_any_cast<simple_variant<C> >(container).get()->begin();
+}
+
+template <class C>
+auto_any<typename C::iterator> end(auto_any_base const& container,
+ type2type<C>) {
+ return auto_any_cast<simple_variant<C> >(container).get()->end();
+}
+
+template <typename C>
+bool done(auto_any_base const& cur, auto_any_base const& end, type2type<C>) {
+ typedef typename C::iterator iter_type;
+ return auto_any_cast<iter_type>(cur) == auto_any_cast<iter_type>(end);
+}
+
+template <class C>
+void next(auto_any_base const& iter, type2type<C>) {
+ ++auto_any_cast<typename C::iterator>(iter);
+}
+
+template <class C>
+typename C::reference deref(auto_any_base const& iter, type2type<C>) {
+ return *auto_any_cast<typename C::iterator>(iter);
+}
+
+// non-const forward iteration.
+#define V8_FOREACH(VAR, COL) \
+ if (bool _rval = false) {} else \
+ if (auto_any_base const& _col = contain(V8_EVAL(COL, _rval), _rval)) {} else \
+ if (auto_any_base const& _cur = begin(_col, V8_TYPEOF(COL))) {} else \
+ if (auto_any_base const& _end = end(_col, V8_TYPEOF(COL))) {} else \
+ for (bool _continue = true; \
+ _continue && !done(_cur, _end, V8_TYPEOF(COL)); \
+ _continue ? next(_cur, V8_TYPEOF(COL)) : (void)0) \
+ if ((_continue = false)) {} else \
+ for (VAR = deref(_cur, V8_TYPEOF(COL)); !_continue; _continue = true)
+
+// -----------------------------------------------------------------------------
+
+template <class C>
+auto_any<typename C::reverse_iterator> rbegin(auto_any_base const& container,
+ type2type<C>) {
+ return auto_any_cast<simple_variant<C> >(container).get()->rbegin();
+}
+
+template <class C>
+auto_any<typename C::reverse_iterator> rend(auto_any_base const& container,
+ type2type<C>) {
+ return auto_any_cast<simple_variant<C> >(container).get()->rend();
+}
+
+template <typename C>
+bool rdone(auto_any_base const& cur, auto_any_base const& end, type2type<C>) {
+ typedef typename C::reverse_iterator iter_type;
+ return auto_any_cast<iter_type>(cur) == auto_any_cast<iter_type>(end);
+}
+
+template <class C>
+void rnext(auto_any_base const& iter, type2type<C>) {
+ ++auto_any_cast<typename C::reverse_iterator>(iter);
+}
+
+template <class C>
+typename C::reference rderef(auto_any_base const& iter, type2type<C>) {
+ return *auto_any_cast<typename C::reverse_iterator>(iter);
+}
+
+// non-const reverse iteration.
+#define V8_FOREACH_REV(VAR, COL) \
+ if (bool _rval = false) {} else \
+ if (auto_any_base const& _col = contain(V8_EVAL(COL, _rval), _rval)) {} else \
+ if (auto_any_base const& _cur = rbegin(_col, V8_TYPEOF(COL))) {} else \
+ if (auto_any_base const& _end = rend(_col, V8_TYPEOF(COL))) {} else \
+ for (bool _continue = true; \
+ _continue && !rdone(_cur, _end, V8_TYPEOF(COL)); \
+ _continue ? rnext(_cur, V8_TYPEOF(COL)) : (void)0) \
+ if ((_continue = false)) {} else \
+ for (VAR = rderef(_cur, V8_TYPEOF(COL)); !_continue; _continue = true)
+
+// -----------------------------------------------------------------------------
+
+template <class C>
+auto_any<typename C::const_iterator> cbegin(auto_any_base const& container,
+ type2type<C>) {
+ return auto_any_cast<simple_variant<C> >(container).get_c()->begin();
+}
+
+template <class C>
+auto_any<typename C::const_iterator> cend(auto_any_base const& container,
+ type2type<C>) {
+ return auto_any_cast<simple_variant<C> >(container).get_c()->end();
+}
+
+template <typename C>
+bool cdone(auto_any_base const& cur, auto_any_base const& end, type2type<C>) {
+ typedef typename C::const_iterator iter_type;
+ return auto_any_cast<iter_type>(cur) == auto_any_cast<iter_type>(end);
+}
+
+template <class C>
+void cnext(auto_any_base const& iter, type2type<C>) {
+ ++auto_any_cast<typename C::const_iterator>(iter);
+}
+
+template <class C>
+typename C::const_reference cderef(auto_any_base const& iter, type2type<C>) {
+ return *auto_any_cast<typename C::const_iterator>(iter);
+}
+
+// const forward iteration.
+#define V8_FOREACH_C(VAR, COL) \
+ if (bool _rval = false) {} else \
+ if (auto_any_base const& _col = contain(V8_EVAL(COL, _rval), _rval)) {} else \
+ if (auto_any_base const& _cur = cbegin(_col, V8_TYPEOF(COL))) {} else \
+ if (auto_any_base const& _end = cend(_col, V8_TYPEOF(COL))) {} else \
+ for (bool _continue = true; \
+ _continue && !cdone(_cur, _end, V8_TYPEOF(COL)); \
+ _continue ? cnext(_cur, V8_TYPEOF(COL)) : (void)0) \
+ if ((_continue = false)) {} else \
+ for (VAR = cderef(_cur, V8_TYPEOF(COL)); !_continue; _continue = true)
+
+// -----------------------------------------------------------------------------
+
+template <class C>
+auto_any<typename C::const_reverse_iterator> rcbegin(
+ auto_any_base const& container, type2type<C>) {
+ return auto_any_cast<simple_variant<C> >(container).get_c()->rbegin();
+}
+
+template <class C>
+auto_any<typename C::const_reverse_iterator> rcend(
+ auto_any_base const& container, type2type<C>) {
+ return auto_any_cast<simple_variant<C> >(container).get_c()->rend();
+}
+
+template <typename C>
+bool rcdone(auto_any_base const& cur, auto_any_base const& end, type2type<C>) {
+ typedef typename C::const_reverse_iterator iter_type;
+ return auto_any_cast<iter_type>(cur) == auto_any_cast<iter_type>(end);
+}
+
+template <class C>
+void rcnext(auto_any_base const& iter, type2type<C>) {
+ ++auto_any_cast<typename C::const_reverse_iterator>(iter);
+}
+
+template <class C>
+typename C::const_reference rcderef(auto_any_base const& iter, type2type<C>) {
+ return *auto_any_cast<typename C::const_reverse_iterator>(iter);
+}
+
+// const reverse iteration.
+#define V8_FOREACH_C_REV(VAR, COL) \
+ if (bool _rval = false) {} else \
+ if (auto_any_base const& _col = contain(V8_EVAL(COL, _rval), _rval)) {} else \
+ if (auto_any_base const& _cur = rcbegin(_col, V8_TYPEOF(COL))) {} else \
+ if (auto_any_base const& _end = rcend(_col, V8_TYPEOF(COL))) {} else \
+ for (bool _continue = true; \
+ _continue && !rcdone(_cur, _end, V8_TYPEOF(COL)); \
+ _continue ? rcnext(_cur, V8_TYPEOF(COL)) : (void)0) \
+ if ((_continue = false)) {} else \
+ for (VAR = rcderef(_cur, V8_TYPEOF(COL)); !_continue; _continue = true)
+
+} } // namespace v8::internal
+
+#endif // V8_H_
« no previous file with comments | « no previous file | src/utils.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698