Skip to content

Commit

Permalink
src: replace CONTAINER_OF with type-safe function
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
bnoordhuis authored and indutny committed May 30, 2014
1 parent c7b0203 commit 820aaf5
Show file tree
Hide file tree
Showing 12 changed files with 61 additions and 34 deletions.
5 changes: 3 additions & 2 deletions src/cares_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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);
}

Expand Down
8 changes: 4 additions & 4 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -289,15 +289,15 @@ 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() {
return &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() {
Expand Down Expand Up @@ -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() {
Expand Down
4 changes: 2 additions & 2 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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();
Expand Down
16 changes: 6 additions & 10 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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);
}

Expand All @@ -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());
Expand Down Expand Up @@ -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:
Expand All @@ -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.
Expand Down Expand Up @@ -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());
Expand Down
4 changes: 2 additions & 2 deletions src/node_http_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,15 @@ 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##_()


#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)
Expand Down
2 changes: 1 addition & 1 deletion src/node_v8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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_);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/node_zlib.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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());
Expand Down
2 changes: 1 addition & 1 deletion src/signal_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
2 changes: 1 addition & 1 deletion src/stream_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
4 changes: 2 additions & 2 deletions src/tls_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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;
}
Expand Down
20 changes: 20 additions & 0 deletions src/util-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@

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,
Expand Down
24 changes: 17 additions & 7 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,6 @@

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))

Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 820aaf5

Please sign in to comment.