src: replace CONTAINER_OF with type-safe function
authorBen Noordhuis <info@bnoordhuis.nl>
Tue, 27 May 2014 21:31:31 +0000 (23:31 +0200)
committerFedor Indutny <fedor@indutny.com>
Fri, 30 May 2014 10:45:37 +0000 (11:45 +0100)
Replace the CONTAINER_OF macro with a template function that is as
type-safe as a reinterpret_cast<> of an arbitrary pointer can be made.

Signed-off-by: Fedor Indutny <fedor@indutny.com>
12 files changed:
src/cares_wrap.cc
src/env-inl.h
src/node.cc
src/node_crypto.cc
src/node_http_parser.cc
src/node_v8.cc
src/node_zlib.cc
src/signal_wrap.cc
src/stream_wrap.cc
src/tls_wrap.cc
src/util-inl.h
src/util.h

index 0f5987b..f762f2a 100644 (file)
@@ -88,7 +88,7 @@ static void ares_timeout(uv_timer_t* handle) {
 
 
 static void ares_poll_cb(uv_poll_t* watcher, int status, int events) {
-  ares_task_t* task = CONTAINER_OF(watcher, ares_task_t, poll_watcher);
+  ares_task_t* task = ContainerOf(&ares_task_t::poll_watcher, watcher);
   Environment* env = task->env;
 
   /* Reset the idle timer */
@@ -109,7 +109,8 @@ static void ares_poll_cb(uv_poll_t* watcher, int status, int events) {
 
 
 static void ares_poll_close_cb(uv_handle_t* watcher) {
-  ares_task_t* task = CONTAINER_OF(watcher, ares_task_t, poll_watcher);
+  ares_task_t* task = ContainerOf(&ares_task_t::poll_watcher,
+                                  reinterpret_cast<uv_poll_t*>(watcher));
   free(task);
 }
 
index 890ddd2..90fc77c 100644 (file)
@@ -276,7 +276,7 @@ inline bool Environment::in_domain() const {
 
 inline Environment* Environment::from_immediate_check_handle(
     uv_check_t* handle) {
-  return CONTAINER_OF(handle, Environment, immediate_check_handle_);
+  return ContainerOf(&Environment::immediate_check_handle_, handle);
 }
 
 inline uv_check_t* Environment::immediate_check_handle() {
@@ -289,7 +289,7 @@ inline uv_idle_t* Environment::immediate_idle_handle() {
 
 inline Environment* Environment::from_idle_prepare_handle(
     uv_prepare_t* handle) {
-  return CONTAINER_OF(handle, Environment, idle_prepare_handle_);
+  return ContainerOf(&Environment::idle_prepare_handle_, handle);
 }
 
 inline uv_prepare_t* Environment::idle_prepare_handle() {
@@ -297,7 +297,7 @@ inline uv_prepare_t* Environment::idle_prepare_handle() {
 }
 
 inline Environment* Environment::from_idle_check_handle(uv_check_t* handle) {
-  return CONTAINER_OF(handle, Environment, idle_check_handle_);
+  return ContainerOf(&Environment::idle_check_handle_, handle);
 }
 
 inline uv_check_t* Environment::idle_check_handle() {
@@ -345,7 +345,7 @@ inline void Environment::set_printed_error(bool value) {
 }
 
 inline Environment* Environment::from_cares_timer_handle(uv_timer_t* handle) {
-  return CONTAINER_OF(handle, Environment, cares_timer_handle_);
+  return ContainerOf(&Environment::cares_timer_handle_, handle);
 }
 
 inline uv_timer_t* Environment::cares_timer_handle() {
index 7a4a090..5d13e8b 100644 (file)
@@ -1523,7 +1523,7 @@ static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) {
   int i = 0;
 
   QUEUE_FOREACH(q, &req_wrap_queue) {
-    ReqWrap<uv_req_t>* w = CONTAINER_OF(q, ReqWrap<uv_req_t>, req_wrap_queue_);
+    ReqWrap<uv_req_t>* w = ContainerOf(&ReqWrap<uv_req_t>::req_wrap_queue_, q);
     if (w->persistent().IsEmpty())
       continue;
     ary->Set(i++, w->object());
@@ -1546,7 +1546,7 @@ void GetActiveHandles(const FunctionCallbackInfo<Value>& args) {
   Local<String> owner_sym = env->owner_string();
 
   QUEUE_FOREACH(q, &handle_wrap_queue) {
-    HandleWrap* w = CONTAINER_OF(q, HandleWrap, handle_wrap_queue_);
+    HandleWrap* w = ContainerOf(&HandleWrap::handle_wrap_queue_, q);
     if (w->persistent().IsEmpty() || (w->flags_ & HandleWrap::kUnref))
       continue;
     Local<Object> object = w->object();
index af92870..4201040 100644 (file)
@@ -4027,7 +4027,6 @@ class PBKDF2Request : public AsyncWrap {
     error_ = err;
   }
 
-  // TODO(trevnorris): Make private and make work with CONTAINER_OF macro.
   uv_work_t work_req_;
 
  private:
@@ -4059,7 +4058,7 @@ void EIO_PBKDF2(PBKDF2Request* req) {
 
 
 void EIO_PBKDF2(uv_work_t* work_req) {
-  PBKDF2Request* req = CONTAINER_OF(work_req, PBKDF2Request, work_req_);
+  PBKDF2Request* req = ContainerOf(&PBKDF2Request::work_req_, work_req);
   EIO_PBKDF2(req);
 }
 
@@ -4078,7 +4077,7 @@ void EIO_PBKDF2After(PBKDF2Request* req, Local<Value> argv[2]) {
 
 void EIO_PBKDF2After(uv_work_t* work_req, int status) {
   assert(status == 0);
-  PBKDF2Request* req = CONTAINER_OF(work_req, PBKDF2Request, work_req_);
+  PBKDF2Request* req = ContainerOf(&PBKDF2Request::work_req_, work_req);
   Environment* env = req->env();
   HandleScope handle_scope(env->isolate());
   Context::Scope context_scope(env->context());
@@ -4257,7 +4256,6 @@ class RandomBytesRequest : public AsyncWrap {
     error_ = err;
   }
 
-  // TODO(trevnorris): Make private and make work with CONTAINER_OF macro.
   uv_work_t work_req_;
 
  private:
@@ -4269,9 +4267,8 @@ class RandomBytesRequest : public AsyncWrap {
 
 template <bool pseudoRandom>
 void RandomBytesWork(uv_work_t* work_req) {
-  RandomBytesRequest* req = CONTAINER_OF(work_req,
-                                         RandomBytesRequest,
-                                         work_req_);
+  RandomBytesRequest* req =
+      ContainerOf(&RandomBytesRequest::work_req_, work_req);
   int r;
 
   // Ensure that OpenSSL's PRNG is properly seeded.
@@ -4317,9 +4314,8 @@ void RandomBytesCheck(RandomBytesRequest* req, Local<Value> argv[2]) {
 
 void RandomBytesAfter(uv_work_t* work_req, int status) {
   assert(status == 0);
-  RandomBytesRequest* req = CONTAINER_OF(work_req,
-                                         RandomBytesRequest,
-                                         work_req_);
+  RandomBytesRequest* req =
+      ContainerOf(&RandomBytesRequest::work_req_, work_req);
   Environment* env = req->env();
   HandleScope handle_scope(env->isolate());
   Context::Scope context_scope(env->context());
index 3739437..911fec3 100644 (file)
@@ -77,7 +77,7 @@ const uint32_t kOnMessageComplete = 3;
 
 #define HTTP_CB(name)                                                         \
   static int name(http_parser* p_) {                                          \
-    Parser* self = CONTAINER_OF(p_, Parser, parser_);                         \
+    Parser* self = ContainerOf(&Parser::parser_, p_);                         \
     return self->name##_();                                                   \
   }                                                                           \
   int name##_()
@@ -85,7 +85,7 @@ const uint32_t kOnMessageComplete = 3;
 
 #define HTTP_DATA_CB(name)                                                    \
   static int name(http_parser* p_, const char* at, size_t length) {           \
-    Parser* self = CONTAINER_OF(p_, Parser, parser_);                         \
+    Parser* self = ContainerOf(&Parser::parser_, p_);                         \
     return self->name##_(at, length);                                         \
   }                                                                           \
   int name##_(const char* at, size_t length)
index 6652f61..b71b2a3 100644 (file)
@@ -83,7 +83,7 @@ void Environment::IsolateData::AfterGarbageCollection(GCType type,
     q = QUEUE_HEAD(&queue);
     QUEUE_REMOVE(q);
     QUEUE_INSERT_TAIL(&gc_tracker_queue_, q);
-    Environment* env = CONTAINER_OF(q, Environment, gc_tracker_queue_);
+    Environment* env = ContainerOf(&Environment::gc_tracker_queue_, q);
     env->AfterGarbageCollectionCallback(&gc_info_before_, &gc_info_after_);
   }
 }
index 4453d82..4f0c938 100644 (file)
@@ -246,7 +246,7 @@ class ZCtx : public AsyncWrap {
   // for a single write() call, until all of the input bytes have
   // been consumed.
   static void Process(uv_work_t* work_req) {
-    ZCtx *ctx = CONTAINER_OF(work_req, ZCtx, work_req_);
+    ZCtx *ctx = ContainerOf(&ZCtx::work_req_, work_req);
 
     // If the avail_out is left at 0, then it means that it ran out
     // of room.  If there was avail_out left over, then it means
@@ -320,7 +320,7 @@ class ZCtx : public AsyncWrap {
   static void After(uv_work_t* work_req, int status) {
     assert(status == 0);
 
-    ZCtx* ctx = CONTAINER_OF(work_req, ZCtx, work_req_);
+    ZCtx* ctx = ContainerOf(&ZCtx::work_req_, work_req);
     Environment* env = ctx->env();
 
     HandleScope handle_scope(env->isolate());
index e1ec2fd..a50340d 100644 (file)
@@ -105,7 +105,7 @@ class SignalWrap : public HandleWrap {
   }
 
   static void OnSignal(uv_signal_t* handle, int signum) {
-    SignalWrap* wrap = CONTAINER_OF(handle, SignalWrap, handle_);
+    SignalWrap* wrap = ContainerOf(&SignalWrap::handle_, handle);
     Environment* env = wrap->env();
     HandleScope handle_scope(env->isolate());
     Context::Scope context_scope(env->context());
index 069d17b..026e204 100644 (file)
@@ -510,7 +510,7 @@ void StreamWrap::SetBlocking(const FunctionCallbackInfo<Value>& args) {
 }
 
 void StreamWrap::AfterWrite(uv_write_t* req, int status) {
-  WriteWrap* req_wrap = CONTAINER_OF(req, WriteWrap, req_);
+  WriteWrap* req_wrap = ContainerOf(&WriteWrap::req_, req);
   StreamWrap* wrap = req_wrap->wrap();
   Environment* env = wrap->env();
 
index 2f63dfc..b0200a8 100644 (file)
@@ -114,7 +114,7 @@ TLSCallbacks::~TLSCallbacks() {
     QUEUE* q = QUEUE_HEAD(&pending_write_items_);
     QUEUE_REMOVE(q);
 
-    WriteItem* wi = QUEUE_DATA(q, WriteItem, member_);
+    WriteItem* wi = ContainerOf(&WriteItem::member_, q);
     delete wi;
   }
 }
@@ -145,7 +145,7 @@ bool TLSCallbacks::InvokeQueued(int status) {
     QUEUE* q = QUEUE_HEAD(&pending_write_items_);
     QUEUE_REMOVE(q);
 
-    WriteItem* wi = QUEUE_DATA(q, WriteItem, member_);
+    WriteItem* wi = ContainerOf(&WriteItem::member_, q);
     wi->cb_(&wi->w_->req_, status);
     delete wi;
   }
index 76015cc..3709208 100644 (file)
 
 namespace node {
 
+template <typename Inner, typename Outer>
+ContainerOfHelper<Inner, Outer>::ContainerOfHelper(Inner Outer::*field,
+                                                   Inner* pointer)
+    : pointer_(reinterpret_cast<Outer*>(
+          reinterpret_cast<uintptr_t>(pointer) -
+          reinterpret_cast<uintptr_t>(&(static_cast<Outer*>(0)->*field)))) {
+}
+
+template <typename Inner, typename Outer>
+template <typename TypeName>
+ContainerOfHelper<Inner, Outer>::operator TypeName*() const {
+  return static_cast<TypeName*>(pointer_);
+}
+
+template <typename Inner, typename Outer>
+inline ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::*field,
+                                                   Inner* pointer) {
+  return ContainerOfHelper<Inner, Outer>(field, pointer);
+}
+
 template <class TypeName>
 inline v8::Local<TypeName> PersistentToLocal(
     v8::Isolate* isolate,
index 05a7dae..3dcfa55 100644 (file)
 
 namespace node {
 
-#define OFFSET_OF(TypeName, Field)                                            \
-  (reinterpret_cast<uintptr_t>(&(reinterpret_cast<TypeName*>(8)->Field)) - 8)
-
-#define CONTAINER_OF(Pointer, TypeName, Field)                                \
-  reinterpret_cast<TypeName*>(                                                \
-      reinterpret_cast<uintptr_t>(Pointer) - OFFSET_OF(TypeName, Field))
-
 #define FIXED_ONE_BYTE_STRING(isolate, string)                                \
   (node::OneByteString((isolate), (string), sizeof(string) - 1))
 
@@ -63,6 +56,23 @@ namespace node {
 
 #define UNREACHABLE() abort()
 
+// The helper is for doing safe downcasts from base types to derived types.
+template <typename Inner, typename Outer>
+class ContainerOfHelper {
+ public:
+  inline ContainerOfHelper(Inner Outer::*field, Inner* pointer);
+  template <typename TypeName>
+  inline operator TypeName*() const;
+ private:
+  Outer* const pointer_;
+};
+
+// Calculate the address of the outer (i.e. embedding) struct from
+// the interior pointer to a data member.
+template <typename Inner, typename Outer>
+inline ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::*field,
+                                                   Inner* pointer);
+
 // If persistent.IsWeak() == false, then do not call persistent.Reset()
 // while the returned Local<T> is still in scope, it will destroy the
 // reference to the object.