Index: src/base/macros.h |
diff --git a/src/base/macros.h b/src/base/macros.h |
index 50828db57ff95420fe2ab386c8ed69dec197f56b..c8a140849dcf3e370c7e845929c25ebf3409ca0c 100644 |
--- a/src/base/macros.h |
+++ b/src/base/macros.h |
@@ -20,13 +20,74 @@ |
(reinterpret_cast<intptr_t>(&(reinterpret_cast<type*>(4)->field)) - 4) |
-// The expression ARRAY_SIZE(a) is a compile-time constant of type |
-// size_t which represents the number of elements of the given |
-// array. You should only use ARRAY_SIZE on statically allocated |
-// arrays. |
-#define ARRAY_SIZE(a) \ |
- ((sizeof(a) / sizeof(*(a))) / \ |
- static_cast<size_t>(!(sizeof(a) % sizeof(*(a))))) |
+// The arraysize(arr) macro returns the # of elements in an array arr. |
+// The expression is a compile-time constant, and therefore can be |
+// used in defining new arrays, for example. If you use arraysize on |
+// a pointer by mistake, you will get a compile-time error. |
+// |
+// One caveat is that arraysize() doesn't accept any array of an |
+// anonymous type or a type defined inside a function. In these rare |
+// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is |
+// due to a limitation in C++'s template system. The limitation might |
+// eventually be removed, but it hasn't happened yet. |
+#define arraysize(array) (sizeof(ArraySizeHelper(array))) |
+ |
+ |
+// This template function declaration is used in defining arraysize. |
+// Note that the function doesn't need an implementation, as we only |
+// use its type. |
+template <typename T, size_t N> |
+char (&ArraySizeHelper(T (&array)[N]))[N]; |
+ |
+ |
+#if V8_CC_GNU |
+// That gcc wants both of these prototypes seems mysterious. VC, for |
+// its part, can't decide which to use (another mystery). Matching of |
+// template overloads: the final frontier. |
+template <typename T, size_t N> |
+char (&ArraySizeHelper(const T (&array)[N]))[N]; |
+#endif |
+ |
+ |
+// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize, |
+// but can be used on anonymous types or types defined inside |
+// functions. It's less safe than arraysize as it accepts some |
+// (although not all) pointers. Therefore, you should use arraysize |
+// whenever possible. |
+// |
+// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type |
+// size_t. |
+// |
+// ARRAYSIZE_UNSAFE catches a few type errors. If you see a compiler error |
+// |
+// "warning: division by zero in ..." |
+// |
+// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer. |
+// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays. |
+// |
+// The following comments are on the implementation details, and can |
+// be ignored by the users. |
+// |
+// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in |
+// the array) and sizeof(*(arr)) (the # of bytes in one array |
+// element). If the former is divisible by the latter, perhaps arr is |
+// indeed an array, in which case the division result is the # of |
+// elements in the array. Otherwise, arr cannot possibly be an array, |
+// and we generate a compiler error to prevent the code from |
+// compiling. |
+// |
+// Since the size of bool is implementation-defined, we need to cast |
+// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final |
+// result has type size_t. |
+// |
+// This macro is not perfect as it wrongfully accepts certain |
+// pointers, namely where the pointer size is divisible by the pointee |
+// size. Since all our code has to go through a 32-bit compiler, |
+// where a pointer is 4 bytes, this means all pointers to a type whose |
+// size is 3 or greater than 4 will be (righteously) rejected. |
+#define ARRAYSIZE_UNSAFE(a) \ |
Yang
2014/08/26 09:17:22
Do we actually need this?
|
+ ((sizeof(a) / sizeof(*(a))) / \ |
+ static_cast<size_t>(!(sizeof(a) % sizeof(*(a))))) // NOLINT |
// A macro to disallow the evil copy constructor and operator= functions |