diff --git a/src/base_object-inl.h b/src/base_object-inl.h index 61f30b3cfbdb0f..6f731b17fe0b84 100644 --- a/src/base_object-inl.h +++ b/src/base_object-inl.h @@ -250,6 +250,17 @@ BaseObjectPtrImpl& BaseObjectPtrImpl::operator=( return *new (this) BaseObjectPtrImpl(std::move(other)); } +template +BaseObjectPtrImpl::BaseObjectPtrImpl(std::nullptr_t) + : BaseObjectPtrImpl() {} + +template +BaseObjectPtrImpl& BaseObjectPtrImpl::operator=( + std::nullptr_t) { + this->~BaseObjectPtrImpl(); + return *new (this) BaseObjectPtrImpl(); +} + template void BaseObjectPtrImpl::reset(T* ptr) { *this = BaseObjectPtrImpl(ptr); @@ -289,6 +300,16 @@ bool BaseObjectPtrImpl::operator !=( return get() != other.get(); } +template +bool operator==(const BaseObjectPtrImpl ptr, const std::nullptr_t) { + return ptr.get() == nullptr; +} + +template +bool operator==(const std::nullptr_t, const BaseObjectPtrImpl ptr) { + return ptr.get() == nullptr; +} + template BaseObjectPtr MakeBaseObject(Args&&... args) { return BaseObjectPtr(new T(std::forward(args)...)); diff --git a/src/base_object.h b/src/base_object.h index a266daa00a7329..f5b791187ec4d9 100644 --- a/src/base_object.h +++ b/src/base_object.h @@ -288,6 +288,9 @@ class BaseObjectPtrImpl final { inline BaseObjectPtrImpl(BaseObjectPtrImpl&& other); inline BaseObjectPtrImpl& operator=(BaseObjectPtrImpl&& other); + inline BaseObjectPtrImpl(std::nullptr_t); + inline BaseObjectPtrImpl& operator=(std::nullptr_t); + inline void reset(T* ptr = nullptr); inline T* get() const; inline T& operator*() const; @@ -309,6 +312,13 @@ class BaseObjectPtrImpl final { inline BaseObject::PointerData* pointer_data() const; }; +template +inline static bool operator==(const BaseObjectPtrImpl, + const std::nullptr_t); +template +inline static bool operator==(const std::nullptr_t, + const BaseObjectPtrImpl); + template using BaseObjectPtr = BaseObjectPtrImpl; template diff --git a/src/histogram.cc b/src/histogram.cc index 22300a65a2378c..afedb5cefe83d2 100644 --- a/src/histogram.cc +++ b/src/histogram.cc @@ -226,7 +226,7 @@ BaseObjectPtr HistogramBase::Create( ->InstanceTemplate() ->NewInstance(env->context()) .ToLocal(&obj)) { - return BaseObjectPtr(); + return nullptr; } return MakeBaseObject(env, obj, options); @@ -240,7 +240,7 @@ BaseObjectPtr HistogramBase::Create( ->InstanceTemplate() ->NewInstance(env->context()) .ToLocal(&obj)) { - return BaseObjectPtr(); + return nullptr; } return MakeBaseObject(env, obj, std::move(histogram)); } @@ -394,7 +394,7 @@ BaseObjectPtr IntervalHistogram::Create( if (!GetConstructorTemplate(env) ->InstanceTemplate() ->NewInstance(env->context()).ToLocal(&obj)) { - return BaseObjectPtr(); + return nullptr; } return MakeBaseObject( diff --git a/src/node_blob.cc b/src/node_blob.cc index 8afc6d3aa0d76f..5ba7137be62946 100644 --- a/src/node_blob.cc +++ b/src/node_blob.cc @@ -169,11 +169,10 @@ BaseObjectPtr Blob::Create(Environment* env, Local ctor; if (!GetConstructorTemplate(env)->GetFunction(env->context()).ToLocal(&ctor)) - return BaseObjectPtr(); + return nullptr; Local obj; - if (!ctor->NewInstance(env->context()).ToLocal(&obj)) - return BaseObjectPtr(); + if (!ctor->NewInstance(env->context()).ToLocal(&obj)) return nullptr; return MakeBaseObject(env, obj, data_queue); } @@ -319,7 +318,7 @@ BaseObjectPtr Blob::Reader::Create(Environment* env, ->InstanceTemplate() ->NewInstance(env->context()) .ToLocal(&obj)) { - return BaseObjectPtr(); + return nullptr; } return MakeBaseObject(env, obj, std::move(blob)); diff --git a/src/node_http2.cc b/src/node_http2.cc index b23f4080a6d4e4..f2e6ef71c14159 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -843,7 +843,7 @@ void Http2Session::Close(uint32_t code, bool socket_closed) { // but this is faster and does not fail if the stream is not found. BaseObjectPtr Http2Session::FindStream(int32_t id) { auto s = streams_.find(id); - return s != streams_.end() ? s->second : BaseObjectPtr(); + return s != streams_.end() ? s->second : nullptr; } bool Http2Session::CanAddStream() { diff --git a/src/node_sockaddr.cc b/src/node_sockaddr.cc index 8cfef3726def8c..f45c77cb60dd0c 100644 --- a/src/node_sockaddr.cc +++ b/src/node_sockaddr.cc @@ -553,7 +553,7 @@ BaseObjectPtr SocketAddressBlockListWrap::New( if (!env->blocklist_constructor_template() ->InstanceTemplate() ->NewInstance(env->context()).ToLocal(&obj)) { - return BaseObjectPtr(); + return nullptr; } BaseObjectPtr wrap = MakeBaseObject(env, obj); @@ -568,7 +568,7 @@ BaseObjectPtr SocketAddressBlockListWrap::New( if (!env->blocklist_constructor_template() ->InstanceTemplate() ->NewInstance(env->context()).ToLocal(&obj)) { - return BaseObjectPtr(); + return nullptr; } BaseObjectPtr wrap = MakeBaseObject( @@ -775,7 +775,7 @@ BaseObjectPtr SocketAddressBase::Create( if (!GetConstructorTemplate(env) ->InstanceTemplate() ->NewInstance(env->context()).ToLocal(&obj)) { - return BaseObjectPtr(); + return nullptr; } return MakeBaseObject(env, obj, std::move(address)); diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc index 0b8f7ef2a21763..f49babf48237eb 100644 --- a/src/node_sqlite.cc +++ b/src/node_sqlite.cc @@ -1588,7 +1588,7 @@ BaseObjectPtr StatementSync::Create(Environment* env, ->InstanceTemplate() ->NewInstance(env->context()) .ToLocal(&obj)) { - return BaseObjectPtr(); + return nullptr; } return MakeBaseObject(env, obj, db, stmt); @@ -1616,7 +1616,7 @@ BaseObjectPtr Session::Create(Environment* env, ->InstanceTemplate() ->NewInstance(env->context()) .ToLocal(&obj)) { - return BaseObjectPtr(); + return nullptr; } return MakeBaseObject(env, obj, std::move(database), session); diff --git a/src/quic/session.h b/src/quic/session.h index be59a6ed7dec9d..d6383f2d59c077 100644 --- a/src/quic/session.h +++ b/src/quic/session.h @@ -135,11 +135,11 @@ class Session final : public AsyncWrap, private SessionTicket::AppData::Source { const CID::Factory* cid_factory = &CID::Factory::random(); // If the CID::Factory is a base object, we keep a reference to it // so that it cannot be garbage collected. - BaseObjectPtr cid_factory_ref = {}; + BaseObjectPtr cid_factory_ref; // If the application provider is specified, it will be used to create // the underlying Application instance for the session. - BaseObjectPtr application_provider = {}; + BaseObjectPtr application_provider; // When true, QLog output will be enabled for the session. bool qlog = false; diff --git a/test/cctest/test_base_object_ptr.cc b/test/cctest/test_base_object_ptr.cc index c25a267a446096..d54b2942a803ed 100644 --- a/test/cctest/test_base_object_ptr.cc +++ b/test/cctest/test_base_object_ptr.cc @@ -155,6 +155,42 @@ TEST_F(BaseObjectPtrTest, Moveable) { EXPECT_EQ(realm->base_object_created_after_bootstrap(), 0); } +TEST_F(BaseObjectPtrTest, Nullptr) { + const HandleScope handle_scope(isolate_); + const Argv argv; + Env env_{handle_scope, argv}; + Environment* env = *env_; + Realm* realm = env->principal_realm(); + + BaseObjectPtr ptr = nullptr; + EXPECT_EQ(nullptr, ptr); + EXPECT_EQ(ptr, nullptr); + EXPECT_EQ(nullptr, ptr.get()); + + // Implicit constructor. + BaseObjectPtr ptr2 = []() -> BaseObjectPtr { + return nullptr; + }(); + EXPECT_EQ(nullptr, ptr2); + EXPECT_EQ(ptr2, nullptr); + EXPECT_EQ(nullptr, ptr2.get()); + + BaseObjectWeakPtr weak_ptr{ptr}; + EXPECT_EQ(nullptr, weak_ptr); + EXPECT_EQ(weak_ptr, nullptr); + EXPECT_EQ(nullptr, weak_ptr.get()); + ptr.reset(); + EXPECT_EQ(weak_ptr.get(), nullptr); + + // No object creation with nullptr. + EXPECT_EQ(realm->base_object_created_after_bootstrap(), 0); + + BaseObjectPtr ptr4 = DummyBaseObject::NewDetached(env); + EXPECT_NE(nullptr, ptr4); + EXPECT_NE(ptr4, nullptr); + EXPECT_EQ(realm->base_object_created_after_bootstrap(), 1); +} + TEST_F(BaseObjectPtrTest, NestedClasses) { class ObjectWithPtr : public BaseObject { public: