diff options
author | Luis Hector Chavez <lhchavez@google.com> | 2016-07-22 11:23:39 -0700 |
---|---|---|
committer | Luis Hector Chavez <lhchavez@google.com> | 2016-07-22 11:23:39 -0700 |
commit | 7aaba044607c7c4f6a649d2001d6ac213683e8b8 (patch) | |
tree | 8d10ef44dd15c9ec6ccb3785599895e6835e8f0c | |
parent | 83db8f75afbb37010450a6a5607764dedf20db6b (diff) | |
parent | 17f710e0eccdb78996c6e3ee65b03d43c18e1d8b (diff) | |
download | libweave-7aaba044607c7c4f6a649d2001d6ac213683e8b8.tar.gz |
Merge remote-tracking branch 'weave/master' into 'weave/aosp-master'upstream-master
17f710e libweave: Update libchrome APIs to r405848
48 files changed, 1880 insertions, 1650 deletions
diff --git a/file_lists.mk b/file_lists.mk index 6345939..7d9b5c6 100644 --- a/file_lists.mk +++ b/file_lists.mk @@ -93,7 +93,7 @@ EXAMPLES_PROVIDER_SRC_FILES := \ THIRD_PARTY_CHROMIUM_BASE_SRC_FILES := \ third_party/chromium/base/bind_helpers.cc \ third_party/chromium/base/callback_internal.cc \ - third_party/chromium/base/guid_posix.cc \ + third_party/chromium/base/guid.cc \ third_party/chromium/base/json/json_parser.cc \ third_party/chromium/base/json/json_reader.cc \ third_party/chromium/base/json/json_writer.cc \ diff --git a/src/access_revocation_manager_impl_unittest.cc b/src/access_revocation_manager_impl_unittest.cc index afc63fe..cd5887f 100644 --- a/src/access_revocation_manager_impl_unittest.cc +++ b/src/access_revocation_manager_impl_unittest.cc @@ -75,7 +75,8 @@ TEST_F(AccessRevocationManagerImplTest, Init) { TEST_F(AccessRevocationManagerImplTest, Block) { bool callback_called = false; manager_->AddEntryAddedCallback( - base::Bind([&callback_called]() { callback_called = true; })); + base::Bind([](bool* callback_called) { *callback_called = true; }, + base::Unretained(&callback_called))); EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) .WillOnce(testing::WithArgs<1, 2>(testing::Invoke( [](const std::string& json, const DoneCallback& callback) { @@ -132,10 +133,10 @@ TEST_F(AccessRevocationManagerImplTest, BlockListOverflow) { {8, 8, 8}, base::Time::FromTimeT(1419970000 + i), base::Time::FromTimeT(1419990000)}, - base::Bind([&callback_called](ErrorPtr error) { - callback_called = true; + base::Bind([](bool* callback_called, ErrorPtr error) { + *callback_called = true; EXPECT_FALSE(error); - })); + }, base::Unretained(&callback_called))); EXPECT_TRUE(callback_called); } EXPECT_EQ(manager_->GetCapacity(), manager_->GetSize()); diff --git a/src/commands/command_queue_unittest.cc b/src/commands/command_queue_unittest.cc index 1e2e0ac..a590a36 100644 --- a/src/commands/command_queue_unittest.cc +++ b/src/commands/command_queue_unittest.cc @@ -151,10 +151,13 @@ TEST_F(CommandQueueTest, CleanupMultipleCommands) { queue_.Add(CreateDummyCommandInstance("base.reboot", id1)); queue_.Add(CreateDummyCommandInstance("base.reboot", id2)); - auto remove_task = [this](const std::string& id) { queue_.RemoveLater(id); }; - remove_task(id1); - task_runner_.PostDelayedTask(FROM_HERE, base::Bind(remove_task, id2), - base::TimeDelta::FromSeconds(10)); + auto remove_task = [](CommandQueue* queue, const std::string& id) { + queue->RemoveLater(id); + }; + remove_task(&queue_, id1); + task_runner_.PostDelayedTask( + FROM_HERE, base::Bind(remove_task, base::Unretained(&queue_), id2), + base::TimeDelta::FromSeconds(10)); EXPECT_EQ(2u, queue_.GetCount()); ASSERT_EQ(2u, task_runner_.GetTaskQueueSize()); task_runner_.RunOnce(); // Executes "remove_task(id2) @ T+10s". diff --git a/src/component_manager_impl.cc b/src/component_manager_impl.cc index 805e57a..91567c0 100644 --- a/src/component_manager_impl.cc +++ b/src/component_manager_impl.cc @@ -68,7 +68,7 @@ void RemoveInaccessibleState(const ComponentManagerImpl* manager, if (sub_component->GetType() == base::Value::TYPE_LIST) { base::ListValue* component_array = nullptr; CHECK(sub_component->GetAsList(&component_array)); - for (base::Value* item : *component_array) { + for (const auto& item : *component_array) { CHECK(item->GetAsDictionary(&component)); RemoveInaccessibleState(manager, component, role); } @@ -320,7 +320,7 @@ std::unique_ptr<CommandInstance> ComponentManagerImpl::ParseCommandInstance( bool trait_supported = false; const base::ListValue* supported_traits = nullptr; if (component->GetList("traits", &supported_traits)) { - for (const base::Value* value : *supported_traits) { + for (const auto& value : *supported_traits) { std::string trait; CHECK(value->GetAsString(&trait)); if (trait == pair.first) { @@ -598,7 +598,7 @@ std::string ComponentManagerImpl::FindComponentWithTrait( const base::DictionaryValue* component = nullptr; CHECK(it.value().GetAsDictionary(&component)); if (component->GetList("traits", &supported_traits)) { - for (const base::Value* value : *supported_traits) { + for (const auto& value : *supported_traits) { std::string supported_trait; CHECK(value->GetAsString(&supported_trait)); if (trait == supported_trait) diff --git a/src/component_manager_unittest.cc b/src/component_manager_unittest.cc index cdd089e..180baf0 100644 --- a/src/component_manager_unittest.cc +++ b/src/component_manager_unittest.cc @@ -27,7 +27,7 @@ bool HasTrait(const base::DictionaryValue& comp, const std::string& trait) { const base::ListValue* list = nullptr; if (!comp.GetList("traits", &list)) return false; - for (const base::Value* item : *list) { + for (const auto& item : *list) { std::string value; if (item->GetAsString(&value) && value == trait) return true; @@ -241,8 +241,11 @@ TEST_F(ComponentManagerTest, LoadTraitsDuplicateOverride) { TEST_F(ComponentManagerTest, AddTraitDefChangedCallback) { int count = 0; int count2 = 0; - manager_.AddTraitDefChangedCallback(base::Bind([&count]() { count++; })); - manager_.AddTraitDefChangedCallback(base::Bind([&count2]() { count2++; })); + auto handler = [](int* count) { (*count)++; }; + manager_.AddTraitDefChangedCallback( + base::Bind(handler, base::Unretained(&count))); + manager_.AddTraitDefChangedCallback( + base::Bind(handler, base::Unretained(&count2))); EXPECT_EQ(1, count); EXPECT_EQ(1, count2); // New definitions. @@ -626,9 +629,11 @@ TEST_F(ComponentManagerTest, AddComponentDoesNotExist) { TEST_F(ComponentManagerTest, AddComponentTreeChangedCallback) { int count = 0; int count2 = 0; - manager_.AddComponentTreeChangedCallback(base::Bind([&count]() { count++; })); + auto handler = [](int* count) { (*count)++; }; manager_.AddComponentTreeChangedCallback( - base::Bind([&count2]() { count2++; })); + base::Bind(handler, base::Unretained(&count))); + manager_.AddComponentTreeChangedCallback( + base::Bind(handler, base::Unretained(&count2))); EXPECT_EQ(1, count); EXPECT_EQ(1, count2); EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr)); @@ -849,18 +854,22 @@ TEST_F(ComponentManagerTest, AddCommandHandler) { manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr)); std::string last_tags; - auto handler = [&last_tags](int tag, const std::weak_ptr<Command>& command) { - if (!last_tags.empty()) - last_tags += ','; - last_tags += std::to_string(tag); + auto handler = [](std::string* last_tags, int tag, + const std::weak_ptr<Command>& command) { + if (!last_tags->empty()) + *last_tags += ','; + *last_tags += std::to_string(tag); }; - manager_.AddCommandHandler("comp1", "trait1.command1", - base::Bind(handler, 1)); - manager_.AddCommandHandler("comp2", "trait1.command1", - base::Bind(handler, 2)); - manager_.AddCommandHandler("comp2", "trait2.command2", - base::Bind(handler, 3)); + manager_.AddCommandHandler( + "comp1", "trait1.command1", + base::Bind(handler, base::Unretained(&last_tags), 1)); + manager_.AddCommandHandler( + "comp2", "trait1.command1", + base::Bind(handler, base::Unretained(&last_tags), 2)); + manager_.AddCommandHandler( + "comp2", "trait2.command2", + base::Bind(handler, base::Unretained(&last_tags), 3)); EXPECT_TRUE(last_tags.empty()); const char kCommand1[] = R"({ @@ -919,11 +928,11 @@ TEST_F(ComponentManagerTest, AddDefaultCommandHandler) { ASSERT_TRUE(manager_.AddComponent("", "comp", {"trait1", "trait2"}, nullptr)); int count = 0; - auto handler = [&count](int tag, const std::weak_ptr<Command>& command) { - count++; - }; + auto handler = [](int* count, int tag, + const std::weak_ptr<Command>& command) { (*count)++; }; - manager_.AddCommandHandler("", "", base::Bind(handler, 1)); + manager_.AddCommandHandler("", "", + base::Bind(handler, base::Unretained(&count), 1)); EXPECT_EQ(0, count); const char kCommand1[] = R"({ @@ -1169,8 +1178,11 @@ TEST_F(ComponentManagerTest, AddStateChangedCallback) { int count = 0; int count2 = 0; - manager_.AddStateChangedCallback(base::Bind([&count]() { count++; })); - manager_.AddStateChangedCallback(base::Bind([&count2]() { count2++; })); + auto handler = [](int* count) { (*count)++; }; + manager_.AddStateChangedCallback( + base::Bind(handler, base::Unretained(&count))); + manager_.AddStateChangedCallback( + base::Bind(handler, base::Unretained(&count2))); EXPECT_EQ(1, count); EXPECT_EQ(1, count2); EXPECT_EQ(0u, manager_.GetLastStateChangeId()); @@ -1216,11 +1228,13 @@ TEST_F(ComponentManagerTest, ComponentStateUpdates) { manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr)); std::vector<ComponentManager::UpdateID> updates1; - auto callback1 = [&updates1](ComponentManager::UpdateID id) { - updates1.push_back(id); + auto callback = [](std::vector<ComponentManager::UpdateID>* updates, + ComponentManager::UpdateID id) { + updates->push_back(id); }; // State change queue is empty, callback should be called immediately. - auto token1 = manager_.AddServerStateUpdatedCallback(base::Bind(callback1)); + auto token1 = manager_.AddServerStateUpdatedCallback( + base::Bind(callback, base::Unretained(&updates1))); ASSERT_EQ(1u, updates1.size()); EXPECT_EQ(manager_.GetLastStateChangeId(), updates1.front()); updates1.clear(); @@ -1236,11 +1250,9 @@ TEST_F(ComponentManagerTest, ComponentStateUpdates) { ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", foo, nullptr)); std::vector<ComponentManager::UpdateID> updates2; - auto callback2 = [&updates2](ComponentManager::UpdateID id) { - updates2.push_back(id); - }; // State change queue is not empty, so callback will be called later. - auto token2 = manager_.AddServerStateUpdatedCallback(base::Bind(callback2)); + auto token2 = manager_.AddServerStateUpdatedCallback( + base::Bind(callback, base::Unretained(&updates2))); EXPECT_TRUE(updates2.empty()); base::StringValue bar("bar"); diff --git a/src/device_registration_info.cc b/src/device_registration_info.cc index 20fd9c0..8cf24a7 100644 --- a/src/device_registration_info.cc +++ b/src/device_registration_info.cc @@ -1115,7 +1115,7 @@ void DeviceRegistrationInfo::ProcessInitialCommandList( ErrorPtr error) { if (error) return; - for (const base::Value* command : commands) { + for (const auto& command : commands) { const base::DictionaryValue* command_dict{nullptr}; if (!command->GetAsDictionary(&command_dict)) { LOG(WARNING) << "Not a command dictionary: " << *command; @@ -1152,7 +1152,7 @@ void DeviceRegistrationInfo::PublishCommands(const base::ListValue& commands, ErrorPtr error) { if (error) return; - for (const base::Value* command : commands) { + for (const auto& command : commands) { const base::DictionaryValue* command_dict{nullptr}; if (!command->GetAsDictionary(&command_dict)) { LOG(WARNING) << "Not a command dictionary: " << *command; diff --git a/src/device_registration_info_unittest.cc b/src/device_registration_info_unittest.cc index ff32c3d..b1976f2 100644 --- a/src/device_registration_info_unittest.cc +++ b/src/device_registration_info_unittest.cc @@ -178,14 +178,15 @@ class DeviceRegistrationInfoTest : public ::testing::Test { bool RefreshAccessToken(ErrorPtr* error) const { bool succeeded = false; - auto callback = [&succeeded, &error](ErrorPtr in_error) { + auto callback = [](bool* succeeded, ErrorPtr* error, ErrorPtr in_error) { if (error) { *error = std::move(in_error); return; } - succeeded = true; + *succeeded = true; }; - dev_reg_->RefreshAccessToken(base::Bind(callback)); + dev_reg_->RefreshAccessToken(base::Bind( + callback, base::Unretained(&succeeded), base::Unretained(error))); return succeeded; } @@ -369,15 +370,15 @@ TEST_F(DeviceRegistrationInfoTest, GetDeviceInfo) { }))); bool succeeded = false; - auto callback = [&succeeded, this](const base::DictionaryValue& info, - ErrorPtr error) { + auto callback = [](bool* succeeded, const base::DictionaryValue& info, + ErrorPtr error) { EXPECT_FALSE(error); std::string id; EXPECT_TRUE(info.GetString("id", &id)); EXPECT_EQ(test_data::kCloudId, id); - succeeded = true; + *succeeded = true; }; - dev_reg_->GetDeviceInfo(base::Bind(callback)); + dev_reg_->GetDeviceInfo(base::Bind(callback, base::Unretained(&succeeded))); EXPECT_TRUE(succeeded); } @@ -386,20 +387,24 @@ TEST_F(DeviceRegistrationInfoTest, ReRegisterDevice) { bool done = false; dev_reg_->RegisterDevice(RegistrationData{test_data::kClaimTicketId}, - base::Bind([this, &done](ErrorPtr error) { + base::Bind([](decltype(this) test, bool* done, + ErrorPtr error) { EXPECT_TRUE(error->HasError("already_registered")); - done = true; - task_runner_.Break(); - EXPECT_EQ(GcdState::kConnecting, GetGcdState()); + *done = true; + test->task_runner_.Break(); + EXPECT_EQ(GcdState::kConnecting, + test->GetGcdState()); // Validate the device info saved to storage... EXPECT_EQ(test_data::kCloudId, - dev_reg_->GetSettings().cloud_id); - EXPECT_EQ(test_data::kRefreshToken, - dev_reg_->GetSettings().refresh_token); - EXPECT_EQ(test_data::kRobotAccountEmail, - dev_reg_->GetSettings().robot_account); - })); + test->dev_reg_->GetSettings().cloud_id); + EXPECT_EQ( + test_data::kRefreshToken, + test->dev_reg_->GetSettings().refresh_token); + EXPECT_EQ( + test_data::kRobotAccountEmail, + test->dev_reg_->GetSettings().robot_account); + }, base::Unretained(this), base::Unretained(&done))); task_runner_.Run(); EXPECT_TRUE(done); } @@ -573,29 +578,32 @@ void DeviceRegistrationInfoTest::RegisterDevice( bool done = false; dev_reg_->RegisterDevice( registration_data, - base::Bind([this, &done, &expected_data](ErrorPtr error) { - done = true; - task_runner_.Break(); + base::Bind([](decltype(this) test, bool* done, + const RegistrationData& expected_data, ErrorPtr error) { + *done = true; + test->task_runner_.Break(); EXPECT_FALSE(error); - EXPECT_EQ(GcdState::kConnecting, GetGcdState()); + EXPECT_EQ(GcdState::kConnecting, test->GetGcdState()); // Validate the device info saved to storage... - EXPECT_EQ(test_data::kCloudId, dev_reg_->GetSettings().cloud_id); + EXPECT_EQ(test_data::kCloudId, test->dev_reg_->GetSettings().cloud_id); EXPECT_EQ(test_data::kRefreshToken, - dev_reg_->GetSettings().refresh_token); + test->dev_reg_->GetSettings().refresh_token); EXPECT_EQ(test_data::kRobotAccountEmail, - dev_reg_->GetSettings().robot_account); - EXPECT_EQ(expected_data.oauth_url, dev_reg_->GetSettings().oauth_url); - EXPECT_EQ(expected_data.client_id, dev_reg_->GetSettings().client_id); + test->dev_reg_->GetSettings().robot_account); + EXPECT_EQ(expected_data.oauth_url, + test->dev_reg_->GetSettings().oauth_url); + EXPECT_EQ(expected_data.client_id, + test->dev_reg_->GetSettings().client_id); EXPECT_EQ(expected_data.client_secret, - dev_reg_->GetSettings().client_secret); - EXPECT_EQ(expected_data.api_key, dev_reg_->GetSettings().api_key); + test->dev_reg_->GetSettings().client_secret); + EXPECT_EQ(expected_data.api_key, test->dev_reg_->GetSettings().api_key); EXPECT_EQ(expected_data.service_url, - dev_reg_->GetSettings().service_url); + test->dev_reg_->GetSettings().service_url); EXPECT_EQ(expected_data.xmpp_endpoint, - dev_reg_->GetSettings().xmpp_endpoint); - })); + test->dev_reg_->GetSettings().xmpp_endpoint); + }, base::Unretained(this), base::Unretained(&done), expected_data)); task_runner_.Run(); EXPECT_TRUE(done); } @@ -640,12 +648,15 @@ TEST_F(DeviceRegistrationInfoTest, RegisterDeviceEndpointsOverrideNotAllowed) { registration_data.service_url = "https://test.service/"; bool done = false; - dev_reg_->RegisterDevice(registration_data, - base::Bind([this, &done](ErrorPtr error) { - done = true; - task_runner_.Break(); - EXPECT_TRUE(error->HasError("invalidParams")); - })); + dev_reg_->RegisterDevice( + registration_data, + base::Bind( + [](decltype(this) test, bool* done, ErrorPtr error) { + *done = true; + test->task_runner_.Break(); + EXPECT_TRUE(error->HasError("invalidParams")); + }, + base::Unretained(this), base::Unretained(&done))); task_runner_.Run(); EXPECT_TRUE(done); } diff --git a/src/notification/xmpp_iq_stanza_handler_unittest.cc b/src/notification/xmpp_iq_stanza_handler_unittest.cc index 052b7c5..b159171 100644 --- a/src/notification/xmpp_iq_stanza_handler_unittest.cc +++ b/src/notification/xmpp_iq_stanza_handler_unittest.cc @@ -159,12 +159,13 @@ TEST_F(IqStanzaHandlerTest, OutOfOrderResponses) { TEST_F(IqStanzaHandlerTest, RequestTimeout) { bool called = false; - auto on_timeout = [&called]() { called = true; }; + auto on_timeout = [](bool* called) { *called = true; }; EXPECT_CALL(mock_xmpp_channel_, SendMessage(_)).Times(1); EXPECT_FALSE(called); - iq_stanza_handler_.SendRequest("set", "", "", "<body/>", {}, - base::Bind(on_timeout)); + iq_stanza_handler_.SendRequest( + "set", "", "", "<body/>", {}, + base::Bind(on_timeout, base::Unretained(&called))); task_runner_.Run(); EXPECT_TRUE(called); } diff --git a/src/privet/privet_handler.cc b/src/privet/privet_handler.cc index ada9f44..2452fc5 100644 --- a/src/privet/privet_handler.cc +++ b/src/privet/privet_handler.cc @@ -897,7 +897,7 @@ void PrivetHandler::HandleComponents(const base::DictionaryValue& input, input.GetString(kPathKey, &path); const base::ListValue* filter_items = nullptr; if (input.GetList(kFilterKey, &filter_items)) { - for (const base::Value* value : *filter_items) { + for (const auto& value : *filter_items) { std::string filter_item; if (value->GetAsString(&filter_item)) filter.insert(filter_item); diff --git a/src/streams_unittest.cc b/src/streams_unittest.cc index 2eae050..4022cbe 100644 --- a/src/streams_unittest.cc +++ b/src/streams_unittest.cc @@ -25,11 +25,14 @@ TEST(Stream, CopyStreams) { bool done = false; auto callback = base::Bind( - [&test_data, &done, &destination](size_t size, ErrorPtr error) { + [](std::vector<uint8_t>* test_data, bool* done, MemoryStream* destination, + size_t size, ErrorPtr error) { EXPECT_FALSE(error); - done = true; - EXPECT_EQ(test_data, destination.GetData()); - }); + *done = true; + EXPECT_EQ(*test_data, destination->GetData()); + }, + base::Unretained(&test_data), base::Unretained(&done), + base::Unretained(&destination)); StreamCopier copier{&source, &destination}; copier.Copy(callback); diff --git a/src/weave_unittest.cc b/src/weave_unittest.cc index eb65149..c609aa7 100644 --- a/src/weave_unittest.cc +++ b/src/weave_unittest.cc @@ -328,13 +328,15 @@ class WeaveTest : public ::testing::Test { void NotifyNetworkChanged(provider::Network::State state, base::TimeDelta delay) { - auto task = [this, state] { - EXPECT_CALL(network_, GetConnectionState()).WillRepeatedly(Return(state)); - for (const auto& cb : network_callbacks_) + auto task = [](decltype(this) test, provider::Network::State state) { + EXPECT_CALL(test->network_, GetConnectionState()) + .WillRepeatedly(Return(state)); + for (const auto& cb : test->network_callbacks_) cb.Run(); }; - task_runner_.PostDelayedTask(FROM_HERE, base::Bind(task), delay); + task_runner_.PostDelayedTask( + FROM_HERE, base::Bind(task, base::Unretained(this), state), delay); } std::map<std::string, provider::HttpServer::RequestHandlerCallback> @@ -428,23 +430,27 @@ TEST_F(WeaveBasicTest, Register) { bool done = false; device_->Register(RegistrationData{"TICKET_ID"}, - base::Bind([this, &done](ErrorPtr error) { - EXPECT_FALSE(error); - done = true; - task_runner_.Break(); - EXPECT_EQ("CLOUD_ID", device_->GetSettings().cloud_id); - })); + base::Bind( + [](decltype(this) test, bool* done, ErrorPtr error) { + EXPECT_FALSE(error); + *done = true; + test->task_runner_.Break(); + EXPECT_EQ("CLOUD_ID", + test->device_->GetSettings().cloud_id); + }, + base::Unretained(this), base::Unretained(&done))); task_runner_.Run(); EXPECT_TRUE(done); done = false; - device_->Register(RegistrationData{"TICKET_ID2"}, - base::Bind([this, &done](ErrorPtr error) { - EXPECT_TRUE(error->HasError("already_registered")); - done = true; - task_runner_.Break(); - EXPECT_EQ("CLOUD_ID", device_->GetSettings().cloud_id); - })); + device_->Register( + RegistrationData{"TICKET_ID2"}, + base::Bind([](decltype(this) test, bool* done, ErrorPtr error) { + EXPECT_TRUE(error->HasError("already_registered")); + *done = true; + test->task_runner_.Break(); + EXPECT_EQ("CLOUD_ID", test->device_->GetSettings().cloud_id); + }, base::Unretained(this), base::Unretained(&done))); task_runner_.Run(); EXPECT_TRUE(done); } diff --git a/third_party/chromium/base/bind.h b/third_party/chromium/base/bind.h index 46dbb91..9cf65b6 100644 --- a/third_party/chromium/base/bind.h +++ b/third_party/chromium/base/bind.h @@ -21,90 +21,21 @@ // If you're reading the implementation, before proceeding further, you should // read the top comment of base/bind_internal.h for a definition of common // terms and concepts. -// -// RETURN TYPES -// -// Though Bind()'s result is meant to be stored in a Callback<> type, it -// cannot actually return the exact type without requiring a large amount -// of extra template specializations. The problem is that in order to -// discern the correct specialization of Callback<>, Bind would need to -// unwrap the function signature to determine the signature's arity, and -// whether or not it is a method. -// -// Each unique combination of (arity, function_type, num_prebound) where -// function_type is one of {function, method, const_method} would require -// one specialization. We eventually have to do a similar number of -// specializations anyways in the implementation (see the Invoker<>, -// classes). However, it is avoidable in Bind if we return the result -// via an indirection like we do below. -// -// TODO(ajwong): We might be able to avoid this now, but need to test. -// -// It is possible to move most of the static_assert into BindState<>, but it -// feels a little nicer to have the asserts here so people do not need to crack -// open bind_internal.h. On the other hand, it makes Bind() harder to read. namespace base { -namespace internal { - -// Don't use Alias Template directly here to avoid a compile error on MSVC2013. -template <typename Functor, typename... Args> -struct MakeUnboundRunTypeImpl { - using Type = - typename BindState< - typename FunctorTraits<Functor>::RunnableType, - typename FunctorTraits<Functor>::RunType, - Args...>::UnboundRunType; -}; - -} // namespace internal - template <typename Functor, typename... Args> -using MakeUnboundRunType = - typename internal::MakeUnboundRunTypeImpl<Functor, Args...>::Type; - -template <typename Functor, typename... Args> -base::Callback<MakeUnboundRunType<Functor, Args...>> -Bind(Functor functor, Args&&... args) { - // Type aliases for how to store and run the functor. - using RunnableType = typename internal::FunctorTraits<Functor>::RunnableType; - using RunType = typename internal::FunctorTraits<Functor>::RunType; - - // Use RunnableType::RunType instead of RunType above because our - // checks below for bound references need to know what the actual - // functor is going to interpret the argument as. - using BoundRunType = typename RunnableType::RunType; - - using BoundArgs = - internal::TakeTypeListItem<sizeof...(Args), - internal::ExtractArgs<BoundRunType>>; - - // Do not allow binding a non-const reference parameter. Non-const reference - // parameters are disallowed by the Google style guide. Also, binding a - // non-const reference parameter can make for subtle bugs because the - // invoked function will receive a reference to the stored copy of the - // argument and not the original. - static_assert(!internal::HasNonConstReferenceItem<BoundArgs>::value, - "do not bind functions with nonconst ref"); - - const bool is_method = internal::HasIsMethodTag<RunnableType>::value; - - // For methods, we need to be careful for parameter 1. We do not require - // a scoped_refptr because BindState<> itself takes care of AddRef() for - // methods. We also disallow binding of an array as the method's target - // object. - static_assert(!internal::BindsArrayToFirstArg<is_method, Args...>::value, - "first bound argument to method cannot be array"); - static_assert( - !internal::HasRefCountedParamAsRawPtr<is_method, Args...>::value, - "a parameter is a refcounted type and needs scoped_refptr"); - - using BindState = internal::BindState<RunnableType, RunType, Args...>; - - return Callback<typename BindState::UnboundRunType>( - new BindState(internal::MakeRunnable(functor), - std::forward<Args>(args)...)); +inline base::Callback<MakeUnboundRunType<Functor, Args...>> Bind( + Functor&& functor, + Args&&... args) { + using BindState = internal::MakeBindStateType<Functor, Args...>; + using UnboundRunType = MakeUnboundRunType<Functor, Args...>; + using Invoker = internal::Invoker<BindState, UnboundRunType>; + + using CallbackType = Callback<UnboundRunType>; + return CallbackType(new BindState(std::forward<Functor>(functor), + std::forward<Args>(args)...), + &Invoker::Run); } } // namespace base diff --git a/third_party/chromium/base/bind_helpers.h b/third_party/chromium/base/bind_helpers.h index 5a4524a..93d02e3 100644 --- a/third_party/chromium/base/bind_helpers.h +++ b/third_party/chromium/base/bind_helpers.h @@ -28,6 +28,9 @@ // argument will CHECK() because the first invocation would have already // transferred ownership to the target function. // +// RetainedRef() accepts a ref counted object and retains a reference to it. +// When the callback is called, the object is passed as a raw pointer. +// // ConstRef() allows binding a constant reference to an argument rather // than a copy. // @@ -71,6 +74,19 @@ // Without Owned(), someone would have to know to delete |pn| when the last // reference to the Callback is deleted. // +// EXAMPLE OF RetainedRef(): +// +// void foo(RefCountedBytes* bytes) {} +// +// scoped_refptr<RefCountedBytes> bytes = ...; +// Closure callback = Bind(&foo, base::RetainedRef(bytes)); +// callback.Run(); +// +// Without RetainedRef, the scoped_refptr would try to implicitly convert to +// a raw pointer and fail compilation: +// +// Closure callback = Bind(&foo, bytes); // ERROR! +// // // EXAMPLE OF ConstRef(): // @@ -105,10 +121,11 @@ // // EXAMPLE OF Passed(): // -// void TakesOwnership(scoped_ptr<Foo> arg) { } -// scoped_ptr<Foo> CreateFoo() { return scoped_ptr<Foo>(new Foo()); } +// void TakesOwnership(std::unique_ptr<Foo> arg) { } +// std::unique_ptr<Foo> CreateFoo() { return std::unique_ptr<Foo>(new Foo()); +// } // -// scoped_ptr<Foo> f(new Foo()); +// std::unique_ptr<Foo> f(new Foo()); // // // |cb| is given ownership of Foo(). |f| is now NULL. // // You can use std::move(f) in place of &f, but it's more verbose. @@ -145,156 +162,19 @@ #include <stddef.h> -#include <map> -#include <memory> #include <type_traits> #include <utility> -#include <vector> #include "base/callback.h" #include "base/memory/weak_ptr.h" #include "build/build_config.h" namespace base { -namespace internal { - -// Use the Substitution Failure Is Not An Error (SFINAE) trick to inspect T -// for the existence of AddRef() and Release() functions of the correct -// signature. -// -// http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error -// http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence -// http://stackoverflow.com/questions/4358584/sfinae-approach-comparison -// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions -// -// The last link in particular show the method used below. -// -// For SFINAE to work with inherited methods, we need to pull some extra tricks -// with multiple inheritance. In the more standard formulation, the overloads -// of Check would be: -// -// template <typename C> -// Yes NotTheCheckWeWant(Helper<&C::TargetFunc>*); -// -// template <typename C> -// No NotTheCheckWeWant(...); -// -// static const bool value = sizeof(NotTheCheckWeWant<T>(0)) == sizeof(Yes); -// -// The problem here is that template resolution will not match -// C::TargetFunc if TargetFunc does not exist directly in C. That is, if -// TargetFunc in inherited from an ancestor, &C::TargetFunc will not match, -// |value| will be false. This formulation only checks for whether or -// not TargetFunc exist directly in the class being introspected. -// -// To get around this, we play a dirty trick with multiple inheritance. -// First, We create a class BaseMixin that declares each function that we -// want to probe for. Then we create a class Base that inherits from both T -// (the class we wish to probe) and BaseMixin. Note that the function -// signature in BaseMixin does not need to match the signature of the function -// we are probing for; thus it's easiest to just use void(). -// -// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an -// ambiguous resolution between BaseMixin and T. This lets us write the -// following: -// -// template <typename C> -// No GoodCheck(Helper<&C::TargetFunc>*); -// -// template <typename C> -// Yes GoodCheck(...); -// -// static const bool value = sizeof(GoodCheck<Base>(0)) == sizeof(Yes); -// -// Notice here that the variadic version of GoodCheck() returns Yes here -// instead of No like the previous one. Also notice that we calculate |value| -// by specializing GoodCheck() on Base instead of T. -// -// We've reversed the roles of the variadic, and Helper overloads. -// GoodCheck(Helper<&C::TargetFunc>*), when C = Base, fails to be a valid -// substitution if T::TargetFunc exists. Thus GoodCheck<Base>(0) will resolve -// to the variadic version if T has TargetFunc. If T::TargetFunc does not -// exist, then &C::TargetFunc is not ambiguous, and the overload resolution -// will prefer GoodCheck(Helper<&C::TargetFunc>*). -// -// This method of SFINAE will correctly probe for inherited names, but it cannot -// typecheck those names. It's still a good enough sanity check though. -// -// Works on gcc-4.2, gcc-4.4, and Visual Studio 2008. -// -// TODO(ajwong): Move to ref_counted.h or template_util.h when we've vetted -// this works well. -// -// TODO(ajwong): Make this check for Release() as well. -// See http://crbug.com/82038. -template <typename T> -class SupportsAddRefAndRelease { - using Yes = char[1]; - using No = char[2]; - - struct BaseMixin { - void AddRef(); - }; - -// MSVC warns when you try to use Base if T has a private destructor, the -// common pattern for refcounted types. It does this even though no attempt to -// instantiate Base is made. We disable the warning for this definition. -#if defined(OS_WIN) -#pragma warning(push) -#pragma warning(disable:4624) -#endif - struct Base : public T, public BaseMixin { - }; -#if defined(OS_WIN) -#pragma warning(pop) -#endif - - template <void(BaseMixin::*)()> struct Helper {}; - - template <typename C> - static No& Check(Helper<&C::AddRef>*); - - template <typename > - static Yes& Check(...); - - public: - enum { value = sizeof(Check<Base>(0)) == sizeof(Yes) }; -}; - -// Helpers to assert that arguments of a recounted type are bound with a -// scoped_refptr. -template <bool IsClasstype, typename T> -struct UnsafeBindtoRefCountedArgHelper : std::false_type { -}; - -template <typename T> -struct UnsafeBindtoRefCountedArgHelper<true, T> - : std::integral_constant<bool, SupportsAddRefAndRelease<T>::value> { -}; - -template <typename T> -struct UnsafeBindtoRefCountedArg : std::false_type { -}; - -template <typename T> -struct UnsafeBindtoRefCountedArg<T*> - : UnsafeBindtoRefCountedArgHelper<std::is_class<T>::value, T> { -}; template <typename T> -class HasIsMethodTag { - using Yes = char[1]; - using No = char[2]; - - template <typename U> - static Yes& Check(typename U::IsMethod*); +struct IsWeakReceiver; - template <typename U> - static No& Check(...); - - public: - enum { value = sizeof(Check<T>(0)) == sizeof(Yes) }; -}; +namespace internal { template <typename T> class UnretainedWrapper { @@ -315,22 +195,26 @@ class ConstRefWrapper { }; template <typename T> -struct IgnoreResultHelper { - explicit IgnoreResultHelper(T functor) : functor_(functor) {} - - T functor_; +class RetainedRefWrapper { + public: + explicit RetainedRefWrapper(T* o) : ptr_(o) {} + explicit RetainedRefWrapper(scoped_refptr<T> o) : ptr_(std::move(o)) {} + T* get() const { return ptr_.get(); } + private: + scoped_refptr<T> ptr_; }; template <typename T> -struct IgnoreResultHelper<Callback<T> > { - explicit IgnoreResultHelper(const Callback<T>& functor) : functor_(functor) {} +struct IgnoreResultHelper { + explicit IgnoreResultHelper(T functor) : functor_(std::move(functor)) {} + explicit operator bool() const { return !!functor_; } - const Callback<T>& functor_; + T functor_; }; // An alternate implementation is to avoid the destructive copy, and instead // specialize ParamTraits<> for OwnedWrapper<> to change the StorageType to -// a class that is essentially a scoped_ptr<>. +// a class that is essentially a std::unique_ptr<>. // // The current implementation has the benefit though of leaving ParamTraits<> // fully in callback_internal.h as well as avoiding type conversions during @@ -341,7 +225,7 @@ class OwnedWrapper { explicit OwnedWrapper(T* o) : ptr_(o) {} ~OwnedWrapper() { delete ptr_; } T* get() const { return ptr_; } - OwnedWrapper(const OwnedWrapper& other) { + OwnedWrapper(OwnedWrapper&& other) { ptr_ = other.ptr_; other.ptr_ = NULL; } @@ -378,7 +262,7 @@ class PassedWrapper { public: explicit PassedWrapper(T&& scoper) : is_valid_(true), scoper_(std::move(scoper)) {} - PassedWrapper(const PassedWrapper& other) + PassedWrapper(PassedWrapper&& other) : is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {} T Take() const { CHECK(is_valid_); @@ -393,37 +277,32 @@ class PassedWrapper { // Unwrap the stored parameters for the wrappers above. template <typename T> -const T& Unwrap(const T& o) { - return o; +T&& Unwrap(T&& o) { + return std::forward<T>(o); } template <typename T> -T* Unwrap(UnretainedWrapper<T> unretained) { +T* Unwrap(const UnretainedWrapper<T>& unretained) { return unretained.get(); } template <typename T> -const T& Unwrap(ConstRefWrapper<T> const_ref) { +const T& Unwrap(const ConstRefWrapper<T>& const_ref) { return const_ref.get(); } template <typename T> -T* Unwrap(const scoped_refptr<T>& o) { +T* Unwrap(const RetainedRefWrapper<T>& o) { return o.get(); } template <typename T> -const WeakPtr<T>& Unwrap(const WeakPtr<T>& o) { - return o; -} - -template <typename T> T* Unwrap(const OwnedWrapper<T>& o) { return o.get(); } template <typename T> -T Unwrap(PassedWrapper<T>& o) { +T Unwrap(const PassedWrapper<T>& o) { return o.Take(); } @@ -434,16 +313,11 @@ T Unwrap(PassedWrapper<T>& o) { // // The first argument should be the type of the object that will be received by // the method. -template <bool IsMethod, typename... Args> -struct IsWeakMethod : public std::false_type {}; +template <bool is_method, typename... Args> +struct IsWeakMethod : std::false_type {}; template <typename T, typename... Args> -struct IsWeakMethod<true, WeakPtr<T>, Args...> : public std::true_type {}; - -template <typename T, typename... Args> -struct IsWeakMethod<true, ConstRefWrapper<WeakPtr<T>>, Args...> - : public std::true_type {}; - +struct IsWeakMethod<true, T, Args...> : IsWeakReceiver<T> {}; // Packs a list of types to hold them in a single type. template <typename... Types> @@ -526,19 +400,25 @@ struct MakeFunctionTypeImpl<R, TypeList<Args...>> { template <typename R, typename ArgList> using MakeFunctionType = typename MakeFunctionTypeImpl<R, ArgList>::Type; -// Used for ExtractArgs. +// Used for ExtractArgs and ExtractReturnType. template <typename Signature> struct ExtractArgsImpl; template <typename R, typename... Args> struct ExtractArgsImpl<R(Args...)> { - using Type = TypeList<Args...>; + using ReturnType = R; + using ArgsList = TypeList<Args...>; }; // A type-level function that extracts function arguments into a TypeList. // E.g. ExtractArgs<R(A, B, C)> is evaluated to TypeList<A, B, C>. template <typename Signature> -using ExtractArgs = typename ExtractArgsImpl<Signature>::Type; +using ExtractArgs = typename ExtractArgsImpl<Signature>::ArgsList; + +// A type-level function that extracts the return type of a function. +// E.g. ExtractReturnType<R(A, B, C)> is evaluated to R. +template <typename Signature> +using ExtractReturnType = typename ExtractArgsImpl<Signature>::ReturnType; } // namespace internal @@ -548,6 +428,16 @@ static inline internal::UnretainedWrapper<T> Unretained(T* o) { } template <typename T> +static inline internal::RetainedRefWrapper<T> RetainedRef(T* o) { + return internal::RetainedRefWrapper<T>(o); +} + +template <typename T> +static inline internal::RetainedRefWrapper<T> RetainedRef(scoped_refptr<T> o) { + return internal::RetainedRefWrapper<T>(std::move(o)); +} + +template <typename T> static inline internal::ConstRefWrapper<T> ConstRef(const T& o) { return internal::ConstRefWrapper<T>(o); } @@ -577,22 +467,36 @@ static inline internal::PassedWrapper<T> Passed(T* scoper) { template <typename T> static inline internal::IgnoreResultHelper<T> IgnoreResult(T data) { - return internal::IgnoreResultHelper<T>(data); + return internal::IgnoreResultHelper<T>(std::move(data)); } -template <typename T> -static inline internal::IgnoreResultHelper<Callback<T> > -IgnoreResult(const Callback<T>& data) { - return internal::IgnoreResultHelper<Callback<T> >(data); -} - -void DoNothing(); +BASE_EXPORT void DoNothing(); template<typename T> void DeletePointer(T* obj) { delete obj; } +// An injection point to control |this| pointer behavior on a method invocation. +// If IsWeakReceiver<> is true_type for |T| and |T| is used for a receiver of a +// method, base::Bind cancels the method invocation if the receiver is tested as +// false. +// E.g. Foo::bar() is not called: +// struct Foo : base::SupportsWeakPtr<Foo> { +// void bar() {} +// }; +// +// WeakPtr<Foo> oo = nullptr; +// base::Bind(&Foo::bar, oo).Run(); +template <typename T> +struct IsWeakReceiver : std::false_type {}; + +template <typename T> +struct IsWeakReceiver<internal::ConstRefWrapper<T>> : IsWeakReceiver<T> {}; + +template <typename T> +struct IsWeakReceiver<WeakPtr<T>> : std::true_type {}; + } // namespace base #endif // BASE_BIND_HELPERS_H_ diff --git a/third_party/chromium/base/bind_internal.h b/third_party/chromium/base/bind_internal.h index 199467c..3d6ca09 100644 --- a/third_party/chromium/base/bind_internal.h +++ b/third_party/chromium/base/bind_internal.h @@ -7,6 +7,7 @@ #include <stddef.h> +#include <tuple> #include <type_traits> #include "base/bind_helpers.h" @@ -17,10 +18,6 @@ #include "base/tuple.h" #include "build/build_config.h" -#if defined(OS_WIN) -#include "base/bind_internal_win.h" -#endif - namespace base { namespace internal { @@ -28,56 +25,80 @@ namespace internal { // // // CONCEPTS: -// Runnable -- A type (really a type class) that has a single Run() method -// and a RunType typedef that corresponds to the type of Run(). -// A Runnable can declare that it should treated like a method -// call by including a typedef named IsMethod. The value of -// this typedef is NOT inspected, only the existence. When a -// Runnable declares itself a method, Bind() will enforce special -// refcounting + WeakPtr handling semantics for the first -// parameter which is expected to be an object. -// Functor -- A copyable type representing something that should be called. -// All function pointers, Callback<>, and Runnables are functors -// even if the invocation syntax differs. +// Functor -- A movable type representing something that should be called. +// All function pointers and Callback<> are functors even if the +// invocation syntax differs. // RunType -- A function type (as opposed to function _pointer_ type) for -// a Run() function. Usually just a convenience typedef. +// a Callback<>::Run(). Usually just a convenience typedef. // (Bound)Args -- A set of types that stores the arguments. // // Types: -// RunnableAdapter<> -- Wraps the various "function" pointer types into an -// object that adheres to the Runnable interface. // ForceVoidReturn<> -- Helper class for translating function signatures to // equivalent forms with a "void" return type. -// FunctorTraits<> -- Type traits used determine the correct RunType and -// RunnableType for a Functor. This is where function +// FunctorTraits<> -- Type traits used to determine the correct RunType and +// invocation manner for a Functor. This is where function // signature adapters are applied. -// MakeRunnable<> -- Takes a Functor and returns an object in the Runnable -// type class that represents the underlying Functor. -// InvokeHelper<> -- Take a Runnable + arguments and actully invokes it. +// InvokeHelper<> -- Take a Functor + arguments and actully invokes it. // Handle the differing syntaxes needed for WeakPtr<> -// support, and for ignoring return values. This is separate -// from Invoker to avoid creating multiple version of -// Invoker<>. -// Invoker<> -- Unwraps the curried parameters and executes the Runnable. +// support. This is separate from Invoker to avoid creating +// multiple version of Invoker<>. +// Invoker<> -- Unwraps the curried parameters and executes the Functor. // BindState<> -- Stores the curried parameters, and is the main entry point -// into the Bind() system, doing most of the type resolution. -// There are ARITY BindState types. +// into the Bind() system. -// HasNonConstReferenceParam selects true_type when any of the parameters in -// |Sig| is a non-const reference. -// Implementation note: This non-specialized case handles zero-arity case only. -// Non-zero-arity cases should be handled by the specialization below. -template <typename List> -struct HasNonConstReferenceItem : std::false_type {}; +template <typename...> +struct make_void { + using type = void; +}; -// Implementation note: Select true_type if the first parameter is a non-const -// reference. Otherwise, skip the first parameter and check rest of parameters -// recursively. -template <typename T, typename... Args> -struct HasNonConstReferenceItem<TypeList<T, Args...>> - : std::conditional<is_non_const_reference<T>::value, - std::true_type, - HasNonConstReferenceItem<TypeList<Args...>>>::type {}; +// A clone of C++17 std::void_t. +// Unlike the original version, we need |make_void| as a helper struct to avoid +// a C++14 defect. +// ref: http://en.cppreference.com/w/cpp/types/void_t +// ref: http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558 +template <typename... Ts> +using void_t = typename make_void<Ts...>::type; + +template <typename Callable, + typename Signature = decltype(&Callable::operator())> +struct ExtractCallableRunTypeImpl; + +template <typename Callable, typename R, typename... Args> +struct ExtractCallableRunTypeImpl<Callable, R(Callable::*)(Args...) const> { + using Type = R(Args...); +}; + +// Evaluated to RunType of the given callable type. +// Example: +// auto f = [](int, char*) { return 0.1; }; +// ExtractCallableRunType<decltype(f)> +// is evaluated to +// double(int, char*); +template <typename Callable> +using ExtractCallableRunType = + typename ExtractCallableRunTypeImpl<Callable>::Type; + +// IsConvertibleToRunType<Functor> is std::true_type if |Functor| has operator() +// and convertible to the corresponding function pointer. Otherwise, it's +// std::false_type. +// Example: +// IsConvertibleToRunType<void(*)()>::value is false. +// +// struct Foo {}; +// IsConvertibleToRunType<void(Foo::*)()>::value is false. +// +// auto f = []() {}; +// IsConvertibleToRunType<decltype(f)>::value is true. +// +// int i = 0; +// auto g = [i]() {}; +// IsConvertibleToRunType<decltype(g)>::value is false. +template <typename Functor, typename SFINAE = void> +struct IsConvertibleToRunType : std::false_type {}; + +template <typename Callable> +struct IsConvertibleToRunType<Callable, void_t<decltype(&Callable::operator())>> + : std::is_convertible<Callable, ExtractCallableRunType<Callable>*> {}; // HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw // pointer to a RefCounted type. @@ -95,344 +116,338 @@ struct HasRefCountedTypeAsRawPtr<T, Args...> std::true_type, HasRefCountedTypeAsRawPtr<Args...>>::type {}; -// BindsArrayToFirstArg selects true_type when |is_method| is true and the first -// item of |Args| is an array type. -// Implementation note: This non-specialized case handles !is_method case and -// zero-arity case only. Other cases should be handled by the specialization -// below. -template <bool is_method, typename... Args> -struct BindsArrayToFirstArg : std::false_type {}; - -template <typename T, typename... Args> -struct BindsArrayToFirstArg<true, T, Args...> - : std::is_array<typename std::remove_reference<T>::type> {}; - -// HasRefCountedParamAsRawPtr is the same to HasRefCountedTypeAsRawPtr except -// when |is_method| is true HasRefCountedParamAsRawPtr skips the first argument. -// Implementation note: This non-specialized case handles !is_method case and -// zero-arity case only. Other cases should be handled by the specialization -// below. -template <bool is_method, typename... Args> -struct HasRefCountedParamAsRawPtr : HasRefCountedTypeAsRawPtr<Args...> {}; +// ForceVoidReturn<> +// +// Set of templates that support forcing the function return type to void. +template <typename Sig> +struct ForceVoidReturn; -template <typename T, typename... Args> -struct HasRefCountedParamAsRawPtr<true, T, Args...> - : HasRefCountedTypeAsRawPtr<Args...> {}; +template <typename R, typename... Args> +struct ForceVoidReturn<R(Args...)> { + using RunType = void(Args...); +}; -// RunnableAdapter<> -// -// The RunnableAdapter<> templates provide a uniform interface for invoking -// a function pointer, method pointer, or const method pointer. The adapter -// exposes a Run() method with an appropriate signature. Using this wrapper -// allows for writing code that supports all three pointer types without -// undue repetition. Without it, a lot of code would need to be repeated 3 -// times. -// -// For method pointers and const method pointers the first argument to Run() -// is considered to be the received of the method. This is similar to STL's -// mem_fun(). -// -// This class also exposes a RunType typedef that is the function type of the -// Run() function. +// FunctorTraits<> // -// If and only if the wrapper contains a method or const method pointer, an -// IsMethod typedef is exposed. The existence of this typedef (NOT the value) -// marks that the wrapper should be considered a method wrapper. +// See description at top of file. +template <typename Functor, typename SFINAE = void> +struct FunctorTraits; +// For a callable type that is convertible to the corresponding function type. +// This specialization is intended to allow binding captureless lambdas by +// base::Bind(), based on the fact that captureless lambdas can be convertible +// to the function type while capturing lambdas can't. template <typename Functor> -class RunnableAdapter; - -// Function. -template <typename R, typename... Args> -class RunnableAdapter<R(*)(Args...)> { - public: - // MSVC 2013 doesn't support Type Alias of function types. - // Revisit this after we update it to newer version. - typedef R RunType(Args...); - - explicit RunnableAdapter(R(*function)(Args...)) - : function_(function) { - } +struct FunctorTraits< + Functor, + typename std::enable_if<IsConvertibleToRunType<Functor>::value>::type> { + using RunType = ExtractCallableRunType<Functor>; + static constexpr bool is_method = false; + static constexpr bool is_nullable = false; template <typename... RunArgs> - R Run(RunArgs&&... args) { - return function_(std::forward<RunArgs>(args)...); + static ExtractReturnType<RunType> + Invoke(const Functor& functor, RunArgs&&... args) { + return functor(std::forward<RunArgs>(args)...); } - - private: - R (*function_)(Args...); }; -// Method. -template <typename R, typename T, typename... Args> -class RunnableAdapter<R(T::*)(Args...)> { - public: - // MSVC 2013 doesn't support Type Alias of function types. - // Revisit this after we update it to newer version. - typedef R RunType(T*, Args...); - using IsMethod = std::true_type; - - explicit RunnableAdapter(R(T::*method)(Args...)) - : method_(method) { - } +// For functions. +template <typename R, typename... Args> +struct FunctorTraits<R (*)(Args...)> { + using RunType = R(Args...); + static constexpr bool is_method = false; + static constexpr bool is_nullable = true; template <typename... RunArgs> - R Run(T* object, RunArgs&&... args) { - return (object->*method_)(std::forward<RunArgs>(args)...); + static R Invoke(R (*function)(Args...), RunArgs&&... args) { + return function(std::forward<RunArgs>(args)...); } - - private: - R (T::*method_)(Args...); }; -// Const Method. -template <typename R, typename T, typename... Args> -class RunnableAdapter<R(T::*)(Args...) const> { - public: - using RunType = R(const T*, Args...); - using IsMethod = std::true_type; +#if defined(OS_WIN) && !defined(ARCH_CPU_X86_64) - explicit RunnableAdapter(R(T::*method)(Args...) const) - : method_(method) { - } +// For functions. +template <typename R, typename... Args> +struct FunctorTraits<R(__stdcall*)(Args...)> { + using RunType = R(Args...); + static constexpr bool is_method = false; + static constexpr bool is_nullable = true; template <typename... RunArgs> - R Run(const T* object, RunArgs&&... args) { - return (object->*method_)(std::forward<RunArgs>(args)...); + static R Invoke(R(__stdcall* function)(Args...), RunArgs&&... args) { + return function(std::forward<RunArgs>(args)...); } - - private: - R (T::*method_)(Args...) const; }; - -// ForceVoidReturn<> -// -// Set of templates that support forcing the function return type to void. -template <typename Sig> -struct ForceVoidReturn; - +// For functions. template <typename R, typename... Args> -struct ForceVoidReturn<R(Args...)> { - // MSVC 2013 doesn't support Type Alias of function types. - // Revisit this after we update it to newer version. - typedef void RunType(Args...); -}; +struct FunctorTraits<R(__fastcall*)(Args...)> { + using RunType = R(Args...); + static constexpr bool is_method = false; + static constexpr bool is_nullable = true; - -// FunctorTraits<> -// -// See description at top of file. -template <typename T> -struct FunctorTraits { - using RunnableType = RunnableAdapter<T>; - using RunType = typename RunnableType::RunType; + template <typename... RunArgs> + static R Invoke(R(__fastcall* function)(Args...), RunArgs&&... args) { + return function(std::forward<RunArgs>(args)...); + } }; -template <typename T> -struct FunctorTraits<IgnoreResultHelper<T>> { - using RunnableType = typename FunctorTraits<T>::RunnableType; - using RunType = - typename ForceVoidReturn<typename RunnableType::RunType>::RunType; +#endif // defined(OS_WIN) && !defined(ARCH_CPU_X86_64) + +// For methods. +template <typename R, typename Receiver, typename... Args> +struct FunctorTraits<R (Receiver::*)(Args...)> { + using RunType = R(Receiver*, Args...); + static constexpr bool is_method = true; + static constexpr bool is_nullable = true; + + template <typename ReceiverPtr, typename... RunArgs> + static R Invoke(R (Receiver::*method)(Args...), + ReceiverPtr&& receiver_ptr, + RunArgs&&... args) { + // Clang skips CV qualifier check on a method pointer invocation when the + // receiver is a subclass. Store the receiver into a const reference to + // T to ensure the CV check works. + // https://llvm.org/bugs/show_bug.cgi?id=27037 + Receiver& receiver = *receiver_ptr; + return (receiver.*method)(std::forward<RunArgs>(args)...); + } }; -template <typename T> -struct FunctorTraits<Callback<T>> { - using RunnableType = Callback<T> ; - using RunType = typename Callback<T>::RunType; +// For const methods. +template <typename R, typename Receiver, typename... Args> +struct FunctorTraits<R (Receiver::*)(Args...) const> { + using RunType = R(const Receiver*, Args...); + static constexpr bool is_method = true; + static constexpr bool is_nullable = true; + + template <typename ReceiverPtr, typename... RunArgs> + static R Invoke(R (Receiver::*method)(Args...) const, + ReceiverPtr&& receiver_ptr, + RunArgs&&... args) { + // Clang skips CV qualifier check on a method pointer invocation when the + // receiver is a subclass. Store the receiver into a const reference to + // T to ensure the CV check works. + // https://llvm.org/bugs/show_bug.cgi?id=27037 + const Receiver& receiver = *receiver_ptr; + return (receiver.*method)(std::forward<RunArgs>(args)...); + } }; - -// MakeRunnable<> -// -// Converts a passed in functor to a RunnableType using type inference. - +// For IgnoreResults. template <typename T> -typename FunctorTraits<T>::RunnableType MakeRunnable(const T& t) { - return RunnableAdapter<T>(t); -} - -template <typename T> -typename FunctorTraits<T>::RunnableType -MakeRunnable(const IgnoreResultHelper<T>& t) { - return MakeRunnable(t.functor_); -} +struct FunctorTraits<IgnoreResultHelper<T>> : FunctorTraits<T> { + using RunType = + typename ForceVoidReturn<typename FunctorTraits<T>::RunType>::RunType; -template <typename T> -const typename FunctorTraits<Callback<T>>::RunnableType& -MakeRunnable(const Callback<T>& t) { - DCHECK(!t.is_null()); - return t; -} + template <typename IgnoreResultType, typename... RunArgs> + static void Invoke(IgnoreResultType&& ignore_result_helper, + RunArgs&&... args) { + FunctorTraits<T>::Invoke(ignore_result_helper.functor_, + std::forward<RunArgs>(args)...); + } +}; +// For Callbacks. +template <typename R, typename... Args, CopyMode copy_mode> +struct FunctorTraits<Callback<R(Args...), copy_mode>> { + using RunType = R(Args...); + static constexpr bool is_method = false; + static constexpr bool is_nullable = true; + + template <typename CallbackType, typename... RunArgs> + static R Invoke(CallbackType&& callback, RunArgs&&... args) { + DCHECK(!callback.is_null()); + return std::forward<CallbackType>(callback).Run( + std::forward<RunArgs>(args)...); + } +}; // InvokeHelper<> // -// There are 3 logical InvokeHelper<> specializations: normal, void-return, -// WeakCalls. +// There are 2 logical InvokeHelper<> specializations: normal, WeakCalls. // // The normal type just calls the underlying runnable. // -// We need a InvokeHelper to handle void return types in order to support -// IgnoreResult(). Normally, if the Runnable's RunType had a void return, -// the template system would just accept "return functor.Run()" ignoring -// the fact that a void function is being used with return. This piece of -// sugar breaks though when the Runnable's RunType is not void. Thus, we -// need a partial specialization to change the syntax to drop the "return" -// from the invocation call. -// -// WeakCalls similarly need special syntax that is applied to the first -// argument to check if they should no-op themselves. -template <bool IsWeakCall, typename ReturnType, typename Runnable> +// WeakCalls need special syntax that is applied to the first argument to check +// if they should no-op themselves. +template <bool is_weak_call, typename ReturnType> struct InvokeHelper; -template <typename ReturnType, typename Runnable> -struct InvokeHelper<false, ReturnType, Runnable> { - template <typename... RunArgs> - static ReturnType MakeItSo(Runnable runnable, RunArgs&&... args) { - return runnable.Run(std::forward<RunArgs>(args)...); - } -}; - -template <typename Runnable> -struct InvokeHelper<false, void, Runnable> { - template <typename... RunArgs> - static void MakeItSo(Runnable runnable, RunArgs&&... args) { - runnable.Run(std::forward<RunArgs>(args)...); - } -}; - -template <typename Runnable> -struct InvokeHelper<true, void, Runnable> { - template <typename BoundWeakPtr, typename... RunArgs> - static void MakeItSo(Runnable runnable, - BoundWeakPtr weak_ptr, - RunArgs&&... args) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get(), std::forward<RunArgs>(args)...); +template <typename ReturnType> +struct InvokeHelper<false, ReturnType> { + template <typename Functor, typename... RunArgs> + static inline ReturnType MakeItSo(Functor&& functor, RunArgs&&... args) { + using Traits = FunctorTraits<typename std::decay<Functor>::type>; + return Traits::Invoke(std::forward<Functor>(functor), + std::forward<RunArgs>(args)...); } }; -#if !defined(_MSC_VER) - -template <typename ReturnType, typename Runnable> -struct InvokeHelper<true, ReturnType, Runnable> { +template <typename ReturnType> +struct InvokeHelper<true, ReturnType> { // WeakCalls are only supported for functions with a void return type. // Otherwise, the function result would be undefined if the the WeakPtr<> // is invalidated. static_assert(std::is_void<ReturnType>::value, "weak_ptrs can only bind to methods without return values"); -}; -#endif + template <typename Functor, typename BoundWeakPtr, typename... RunArgs> + static inline void MakeItSo(Functor&& functor, + BoundWeakPtr&& weak_ptr, + RunArgs&&... args) { + if (!weak_ptr) + return; + using Traits = FunctorTraits<typename std::decay<Functor>::type>; + Traits::Invoke(std::forward<Functor>(functor), + std::forward<BoundWeakPtr>(weak_ptr), + std::forward<RunArgs>(args)...); + } +}; // Invoker<> // // See description at the top of the file. -template <typename BoundIndices, typename StorageType, - typename InvokeHelperType, typename UnboundForwardRunType> +template <typename StorageType, typename UnboundRunType> struct Invoker; -template <size_t... bound_indices, - typename StorageType, - typename InvokeHelperType, - typename R, - typename... UnboundArgs> -struct Invoker<IndexSequence<bound_indices...>, - StorageType, - InvokeHelperType, - R(UnboundArgs...)> { +template <typename StorageType, typename R, typename... UnboundArgs> +struct Invoker<StorageType, R(UnboundArgs...)> { static R Run(BindStateBase* base, UnboundArgs&&... unbound_args) { - StorageType* storage = static_cast<StorageType*>(base); // Local references to make debugger stepping easier. If in a debugger, // you really want to warp ahead and step through the // InvokeHelper<>::MakeItSo() call below. - return InvokeHelperType::MakeItSo( - storage->runnable_, Unwrap(get<bound_indices>(storage->bound_args_))..., - std::forward<UnboundArgs>(unbound_args)...); + const StorageType* storage = static_cast<StorageType*>(base); + static constexpr size_t num_bound_args = + std::tuple_size<decltype(storage->bound_args_)>::value; + return RunImpl(storage->functor_, + storage->bound_args_, + MakeIndexSequence<num_bound_args>(), + std::forward<UnboundArgs>(unbound_args)...); } -}; -// Used to implement MakeArgsStorage. -template <bool is_method, typename... BoundArgs> -struct MakeArgsStorageImpl { - using Type = std::tuple<BoundArgs...>; + private: + template <typename Functor, typename BoundArgsTuple, size_t... indices> + static inline R RunImpl(Functor&& functor, + BoundArgsTuple&& bound, + IndexSequence<indices...>, + UnboundArgs&&... unbound_args) { + static constexpr bool is_method = + FunctorTraits<typename std::decay<Functor>::type>::is_method; + + using DecayedArgsTuple = typename std::decay<BoundArgsTuple>::type; + static constexpr bool is_weak_call = + IsWeakMethod<is_method, + typename std::tuple_element< + indices, + DecayedArgsTuple>::type...>::value; + + return InvokeHelper<is_weak_call, R>::MakeItSo( + std::forward<Functor>(functor), + Unwrap(base::get<indices>(std::forward<BoundArgsTuple>(bound)))..., + std::forward<UnboundArgs>(unbound_args)...); + } }; -template <typename Obj, typename... BoundArgs> -struct MakeArgsStorageImpl<true, Obj*, BoundArgs...> { - using Type = std::tuple<scoped_refptr<Obj>, BoundArgs...>; +// Used to implement MakeUnboundRunType. +template <typename Functor, typename... BoundArgs> +struct MakeUnboundRunTypeImpl { + using RunType = + typename FunctorTraits<typename std::decay<Functor>::type>::RunType; + using ReturnType = ExtractReturnType<RunType>; + using Args = ExtractArgs<RunType>; + using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), Args>; + using Type = MakeFunctionType<ReturnType, UnboundArgs>; }; +template <typename Functor> +typename std::enable_if<FunctorTraits<Functor>::is_nullable, bool>::type +IsNull(const Functor& functor) { + return !functor; +} -// Constructs a tuple type to store BoundArgs into BindState. -// This wraps the first argument into a scoped_refptr if |is_method| is true and -// the first argument is a raw pointer. -// Other arguments are adjusted for store and packed into a tuple. -template <bool is_method, typename... BoundArgs> -using MakeArgsStorage = typename MakeArgsStorageImpl< - is_method, typename std::decay<BoundArgs>::type...>::Type; +template <typename Functor> +typename std::enable_if<!FunctorTraits<Functor>::is_nullable, bool>::type +IsNull(const Functor&) { + return false; +} // BindState<> // -// This stores all the state passed into Bind() and is also where most -// of the template resolution magic occurs. -// -// Runnable is the functor we are binding arguments to. -// RunType is type of the Run() function that the Invoker<> should use. -// Normally, this is the same as the RunType of the Runnable, but it can -// be different if an adapter like IgnoreResult() has been used. -// -// BoundArgs contains the storage type for all the bound arguments. -template <typename Runnable, typename RunType, typename... BoundArgs> -struct BindState; - -template <typename Runnable, - typename R, - typename... Args, - typename... BoundArgs> -struct BindState<Runnable, R(Args...), BoundArgs...> final - : public BindStateBase { - private: - using StorageType = BindState<Runnable, R(Args...), BoundArgs...>; - using RunnableType = Runnable; +// This stores all the state passed into Bind(). +template <typename Functor, typename... BoundArgs> +struct BindState final : BindStateBase { + template <typename ForwardFunctor, typename... ForwardBoundArgs> + explicit BindState(ForwardFunctor&& functor, ForwardBoundArgs&&... bound_args) + : BindStateBase(&Destroy), + functor_(std::forward<ForwardFunctor>(functor)), + bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) { + DCHECK(!IsNull(functor_)); + } - enum { is_method = HasIsMethodTag<Runnable>::value }; + Functor functor_; + std::tuple<BoundArgs...> bound_args_; - // true_type if Runnable is a method invocation and the first bound argument - // is a WeakPtr. - using IsWeakCall = - IsWeakMethod<is_method, typename std::decay<BoundArgs>::type...>; + private: + ~BindState() {} - using BoundIndices = MakeIndexSequence<sizeof...(BoundArgs)>; - using InvokeHelperType = InvokeHelper<IsWeakCall::value, R, Runnable>; + static void Destroy(BindStateBase* self) { + delete static_cast<BindState*>(self); + } +}; - using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), TypeList<Args...>>; +// Used to implement MakeBindStateType. +template <bool is_method, typename Functor, typename... BoundArgs> +struct MakeBindStateTypeImpl; - public: - using UnboundRunType = MakeFunctionType<R, UnboundArgs>; - using InvokerType = - Invoker<BoundIndices, StorageType, InvokeHelperType, UnboundRunType>; +template <typename Functor, typename... BoundArgs> +struct MakeBindStateTypeImpl<false, Functor, BoundArgs...> { + static_assert(!HasRefCountedTypeAsRawPtr<BoundArgs...>::value, + "A parameter is a refcounted type and needs scoped_refptr."); + using Type = BindState<typename std::decay<Functor>::type, + typename std::decay<BoundArgs>::type...>; +}; - template <typename... ForwardArgs> - BindState(const Runnable& runnable, ForwardArgs&&... bound_args) - : BindStateBase(&Destroy), - runnable_(runnable), - bound_args_(std::forward<ForwardArgs>(bound_args)...) {} +template <typename Functor> +struct MakeBindStateTypeImpl<true, Functor> { + using Type = BindState<typename std::decay<Functor>::type>; +}; - RunnableType runnable_; - MakeArgsStorage<is_method, BoundArgs...> bound_args_; +template <typename Functor, typename Receiver, typename... BoundArgs> +struct MakeBindStateTypeImpl<true, Functor, Receiver, BoundArgs...> { + static_assert( + !std::is_array<typename std::remove_reference<Receiver>::type>::value, + "First bound argument to a method cannot be an array."); + static_assert(!HasRefCountedTypeAsRawPtr<BoundArgs...>::value, + "A parameter is a refcounted type and needs scoped_refptr."); private: - ~BindState() {} + using DecayedReceiver = typename std::decay<Receiver>::type; - static void Destroy(BindStateBase* self) { - delete static_cast<BindState*>(self); - } + public: + using Type = BindState< + typename std::decay<Functor>::type, + typename std::conditional< + std::is_pointer<DecayedReceiver>::value, + scoped_refptr<typename std::remove_pointer<DecayedReceiver>::type>, + DecayedReceiver>::type, + typename std::decay<BoundArgs>::type...>; }; +template <typename Functor, typename... BoundArgs> +using MakeBindStateType = typename MakeBindStateTypeImpl< + FunctorTraits<typename std::decay<Functor>::type>::is_method, + Functor, + BoundArgs...>::Type; + } // namespace internal + +// Returns a RunType of bound functor. +// E.g. MakeUnboundRunType<R(A, B, C), A, B> is evaluated to R(C). +template <typename Functor, typename... BoundArgs> +using MakeUnboundRunType = + typename internal::MakeUnboundRunTypeImpl<Functor, BoundArgs...>::Type; + } // namespace base #endif // BASE_BIND_INTERNAL_H_ diff --git a/third_party/chromium/base/bind_unittest.cc b/third_party/chromium/base/bind_unittest.cc index 4c4f3e6..8188d2c 100644 --- a/third_party/chromium/base/bind_unittest.cc +++ b/third_party/chromium/base/bind_unittest.cc @@ -656,28 +656,6 @@ TEST_F(BindTest, ArrayArgumentBinding) { EXPECT_EQ(3, const_array_cb.Run()); } -// Verify SupportsAddRefAndRelease correctly introspects the class type for -// AddRef() and Release(). -// - Class with AddRef() and Release() -// - Class without AddRef() and Release() -// - Derived Class with AddRef() and Release() -// - Derived Class without AddRef() and Release() -// - Derived Class with AddRef() and Release() and a private destructor. -TEST_F(BindTest, SupportsAddRefAndRelease) { - EXPECT_TRUE(internal::SupportsAddRefAndRelease<HasRef>::value); - EXPECT_FALSE(internal::SupportsAddRefAndRelease<NoRef>::value); - - // StrictMock<T> is a derived class of T. So, we use StrictMock<HasRef> and - // StrictMock<NoRef> to test that SupportsAddRefAndRelease works over - // inheritance. - EXPECT_TRUE(internal::SupportsAddRefAndRelease<StrictMock<HasRef> >::value); - EXPECT_FALSE(internal::SupportsAddRefAndRelease<StrictMock<NoRef> >::value); - - // This matters because the implementation creates a dummy class that - // inherits from the template type. - EXPECT_TRUE(internal::SupportsAddRefAndRelease<HasRefPrivateDtor>::value); -} - // Unretained() wrapper support. // - Method bound to Unretained() non-const object. // - Const method bound to Unretained() non-const object. @@ -769,15 +747,10 @@ TEST_F(BindTest, ConstRef) { } TEST_F(BindTest, ScopedRefptr) { - // BUG: The scoped_refptr should cause the only AddRef()/Release() pair. But - // due to a bug in base::Bind(), there's an extra call when invoking the - // callback. - // https://code.google.com/p/chromium/issues/detail?id=251937 - EXPECT_CALL(has_ref_, AddRef()).Times(2); - EXPECT_CALL(has_ref_, Release()).Times(2); - - const scoped_refptr<StrictMock<HasRef> > refptr(&has_ref_); + EXPECT_CALL(has_ref_, AddRef()).Times(1); + EXPECT_CALL(has_ref_, Release()).Times(1); + const scoped_refptr<HasRef> refptr(&has_ref_); Callback<int()> scoped_refptr_const_ref_cb = Bind(&FunctionWithScopedRefptrFirstParam, base::ConstRef(refptr), 1); EXPECT_EQ(1, scoped_refptr_const_ref_cb.Run()); @@ -808,6 +781,12 @@ TEST_F(BindTest, Owned) { EXPECT_EQ(1, deletes); } +TEST_F(BindTest, UniquePtrReceiver) { + std::unique_ptr<StrictMock<NoRef>> no_ref(new StrictMock<NoRef>); + EXPECT_CALL(*no_ref, VoidMethod0()).Times(1); + Bind(&NoRef::VoidMethod0, std::move(no_ref)).Run(); +} + // Tests for Passed() wrapper support: // - Passed() can be constructed from a pointer to scoper. // - Passed() can be constructed from a scoper rvalue. @@ -896,7 +875,7 @@ TEST_F(BindTest, BindMoveOnlyVector) { using MoveOnlyVector = std::vector<std::unique_ptr<int>>; MoveOnlyVector v; - v.push_back(base::MakeUnique<int>(12345)); + v.push_back(WrapUnique(new int(12345))); // Early binding should work: base::Callback<MoveOnlyVector()> bound_cb = @@ -1065,6 +1044,36 @@ TEST_F(BindTest, ArgumentCopiesAndMoves) { EXPECT_EQ(0, move_assigns); } +TEST_F(BindTest, CapturelessLambda) { + EXPECT_FALSE(internal::IsConvertibleToRunType<void>::value); + EXPECT_FALSE(internal::IsConvertibleToRunType<int>::value); + EXPECT_FALSE(internal::IsConvertibleToRunType<void(*)()>::value); + EXPECT_FALSE(internal::IsConvertibleToRunType<void(NoRef::*)()>::value); + + auto f = []() {}; + EXPECT_TRUE(internal::IsConvertibleToRunType<decltype(f)>::value); + + int i = 0; + auto g = [i]() {}; + EXPECT_FALSE(internal::IsConvertibleToRunType<decltype(g)>::value); + + auto h = [](int, double) { return 'k'; }; + EXPECT_TRUE((std::is_same< + char(int, double), + internal::ExtractCallableRunType<decltype(h)>>::value)); + + EXPECT_EQ(42, Bind([] { return 42; }).Run()); + EXPECT_EQ(42, Bind([](int i) { return i * 7; }, 6).Run()); + + int x = 1; + base::Callback<void(int)> cb = + Bind([](int* x, int i) { *x *= i; }, Unretained(&x)); + cb.Run(6); + EXPECT_EQ(6, x); + cb.Run(7); + EXPECT_EQ(42, x); +} + // Callback construction and assignment tests. // - Construction from an InvokerStorageHolder should not cause ref/deref. // - Assignment from other callback should only cause one ref diff --git a/third_party/chromium/base/callback.h b/third_party/chromium/base/callback.h index c04e90d..e087c73 100644 --- a/third_party/chromium/base/callback.h +++ b/third_party/chromium/base/callback.h @@ -187,8 +187,8 @@ // // PASSING PARAMETERS AS A scoped_ptr // -// void TakesOwnership(scoped_ptr<Foo> arg) {} -// scoped_ptr<Foo> f(new Foo); +// void TakesOwnership(std::unique_ptr<Foo> arg) {} +// std::unique_ptr<Foo> f(new Foo); // // f becomes null during the following call. // base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f)); // @@ -345,14 +345,13 @@ // please include "base/callback_forward.h" instead. namespace base { -namespace internal { -template <typename Runnable, typename RunType, typename... BoundArgsType> -struct BindState; -} // namespace internal template <typename R, typename... Args, internal::CopyMode copy_mode> class Callback<R(Args...), copy_mode> : public internal::CallbackBase<copy_mode> { + private: + using PolymorphicInvoke = R (*)(internal::BindStateBase*, Args&&...); + public: // MSVC 2013 doesn't support Type Alias of function types. // Revisit this after we update it to newer version. @@ -360,16 +359,9 @@ class Callback<R(Args...), copy_mode> Callback() : internal::CallbackBase<copy_mode>(nullptr) {} - template <typename Runnable, typename BindRunType, typename... BoundArgs> - explicit Callback( - internal::BindState<Runnable, BindRunType, BoundArgs...>* bind_state) + Callback(internal::BindStateBase* bind_state, + PolymorphicInvoke invoke_func) : internal::CallbackBase<copy_mode>(bind_state) { - // Force the assignment to a local variable of PolymorphicInvoke - // so the compiler will typecheck that the passed in Run() method has - // the correct type. - PolymorphicInvoke invoke_func = - &internal::BindState<Runnable, BindRunType, BoundArgs...> - ::InvokerType::Run; using InvokeFuncStorage = typename internal::CallbackBase<copy_mode>::InvokeFuncStorage; this->polymorphic_invoke_ = @@ -396,9 +388,6 @@ class Callback<R(Args...), copy_mode> reinterpret_cast<PolymorphicInvoke>(this->polymorphic_invoke_); return f(this->bind_state_.get(), std::forward<Args>(args)...); } - - private: - using PolymorphicInvoke = R (*)(internal::BindStateBase*, Args&&...); }; } // namespace base diff --git a/third_party/chromium/base/callback_helpers.h b/third_party/chromium/base/callback_helpers.h new file mode 100644 index 0000000..782371f --- /dev/null +++ b/third_party/chromium/base/callback_helpers.h @@ -0,0 +1,61 @@ +// Copyright (c) 2012 The Chromium 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 defines helpful methods for dealing with Callbacks. Because Callbacks +// are implemented using templates, with a class per callback signature, adding +// methods to Callback<> itself is unattractive (lots of extra code gets +// generated). Instead, consider adding methods here. +// +// ResetAndReturn(&cb) is like cb.Reset() but allows executing a callback (via a +// copy) after the original callback is Reset(). This can be handy if Run() +// reads/writes the variable holding the Callback. + +#ifndef BASE_CALLBACK_HELPERS_H_ +#define BASE_CALLBACK_HELPERS_H_ + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/macros.h" + +namespace base { + +template <typename Sig> +base::Callback<Sig> ResetAndReturn(base::Callback<Sig>* cb) { + base::Callback<Sig> ret(*cb); + cb->Reset(); + return ret; +} + +// ScopedClosureRunner is akin to std::unique_ptr<> for Closures. It ensures +// that the Closure is executed no matter how the current scope exits. +class BASE_EXPORT ScopedClosureRunner { + public: + ScopedClosureRunner(); + explicit ScopedClosureRunner(const Closure& closure); + ~ScopedClosureRunner(); + + ScopedClosureRunner(ScopedClosureRunner&& other); + + // Releases the current closure if it's set and replaces it with the closure + // from |other|. + ScopedClosureRunner& operator=(ScopedClosureRunner&& other); + + // Calls the current closure and resets it, so it wont be called again. + void RunAndReset(); + + // Replaces closure with the new one releasing the old one without calling it. + void ReplaceClosure(const Closure& closure); + + // Releases the Closure without calling. + Closure Release() WARN_UNUSED_RESULT; + + private: + Closure closure_; + + DISALLOW_COPY_AND_ASSIGN(ScopedClosureRunner); +}; + +} // namespace base + +#endif // BASE_CALLBACK_HELPERS_H_ diff --git a/third_party/chromium/base/callback_internal.h b/third_party/chromium/base/callback_internal.h index d700794..7cec0bc 100644 --- a/third_party/chromium/base/callback_internal.h +++ b/third_party/chromium/base/callback_internal.h @@ -65,6 +65,7 @@ class BASE_EXPORT CallbackBase<CopyMode::MoveOnly> { // Returns true if Callback is null (doesn't refer to anything). bool is_null() const { return bind_state_.get() == NULL; } + explicit operator bool() const { return !is_null(); } // Returns the Callback into an uninitialized state. void Reset(); diff --git a/third_party/chromium/base/callback_unittest.cc b/third_party/chromium/base/callback_unittest.cc index 0d35a9d..aab05e7 100644 --- a/third_party/chromium/base/callback_unittest.cc +++ b/third_party/chromium/base/callback_unittest.cc @@ -8,68 +8,44 @@ #include <memory> #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/callback_internal.h" #include "base/memory/ref_counted.h" namespace base { -namespace { - -struct FakeInvoker { - // MSVC 2013 doesn't support Type Alias of function types. - // Revisit this after we update it to newer version. - typedef void RunType(internal::BindStateBase*); - static void Run(internal::BindStateBase*) { - } -}; - -} // namespace - -namespace internal { +void NopInvokeFunc(internal::BindStateBase*) {} // White-box testpoints to inject into a Callback<> object for checking // comparators and emptiness APIs. Use a BindState that is specialized // based on a type we declared in the anonymous namespace above to remove any // chance of colliding with another instantiation and breaking the // one-definition-rule. -template <> -struct BindState<void(), void(), FakeInvoker> - : public BindStateBase { - public: - BindState() : BindStateBase(&Destroy) {} - using InvokerType = FakeInvoker; +struct FakeBindState1 : internal::BindStateBase { + FakeBindState1() : BindStateBase(&Destroy) {} private: - ~BindState() {} - static void Destroy(BindStateBase* self) { - delete static_cast<BindState*>(self); + ~FakeBindState1() {} + static void Destroy(internal::BindStateBase* self) { + delete static_cast<FakeBindState1*>(self); } }; -template <> -struct BindState<void(), void(), FakeInvoker, FakeInvoker> - : public BindStateBase { - public: - BindState() : BindStateBase(&Destroy) {} - using InvokerType = FakeInvoker; +struct FakeBindState2 : internal::BindStateBase { + FakeBindState2() : BindStateBase(&Destroy) {} private: - ~BindState() {} - static void Destroy(BindStateBase* self) { - delete static_cast<BindState*>(self); + ~FakeBindState2() {} + static void Destroy(internal::BindStateBase* self) { + delete static_cast<FakeBindState2*>(self); } }; -} // namespace internal namespace { -using FakeBindState1 = internal::BindState<void(), void(), FakeInvoker>; -using FakeBindState2 = - internal::BindState<void(), void(), FakeInvoker, FakeInvoker>; - class CallbackTest : public ::testing::Test { public: CallbackTest() - : callback_a_(new FakeBindState1()), - callback_b_(new FakeBindState2()) { + : callback_a_(new FakeBindState1(), &NopInvokeFunc), + callback_b_(new FakeBindState2(), &NopInvokeFunc) { } ~CallbackTest() override {} @@ -112,7 +88,7 @@ TEST_F(CallbackTest, Equals) { EXPECT_FALSE(callback_b_.Equals(callback_a_)); // We should compare based on instance, not type. - Callback<void()> callback_c(new FakeBindState1()); + Callback<void()> callback_c(new FakeBindState1(), &NopInvokeFunc); Callback<void()> callback_a2 = callback_a_; EXPECT_TRUE(callback_a_.Equals(callback_a2)); EXPECT_FALSE(callback_a_.Equals(callback_c)); @@ -146,6 +122,15 @@ struct TestForReentrancy { Closure cb; }; +TEST_F(CallbackTest, ResetAndReturn) { + TestForReentrancy tfr; + ASSERT_FALSE(tfr.cb.is_null()); + ASSERT_FALSE(tfr.cb_already_run); + ResetAndReturn(&tfr.cb).Run(); + ASSERT_TRUE(tfr.cb.is_null()); + ASSERT_TRUE(tfr.cb_already_run); +} + class CallbackOwner : public base::RefCounted<CallbackOwner> { public: explicit CallbackOwner(bool* deleted) { diff --git a/third_party/chromium/base/guid_posix.cc b/third_party/chromium/base/guid.cc index ec1ca51..bb41e8c 100644 --- a/third_party/chromium/base/guid_posix.cc +++ b/third_party/chromium/base/guid.cc @@ -4,13 +4,42 @@ #include "base/guid.h" +#include <stddef.h> #include <stdint.h> #include "base/rand_util.h" +#include "base/strings/string_util.h" #include "base/strings/stringprintf.h" namespace base { +namespace { + +bool IsLowerHexDigit(char c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); +} + +bool IsValidGUIDInternal(const base::StringPiece& guid, bool strict) { + const size_t kGUIDLength = 36U; + if (guid.length() != kGUIDLength) + return false; + + for (size_t i = 0; i < guid.length(); ++i) { + char current = guid[i]; + if (i == 8 || i == 13 || i == 18 || i == 23) { + if (current != '-') + return false; + } else { + if ((strict && !IsLowerHexDigit(current)) || !IsHexDigit(current)) + return false; + } + } + + return true; +} + +} // namespace + std::string GenerateGUID() { uint64_t sixteen_bytes[2] = {base::RandUint64(), base::RandUint64()}; @@ -30,8 +59,14 @@ std::string GenerateGUID() { return RandomDataToGUIDString(sixteen_bytes); } -// TODO(cmasone): Once we're comfortable this works, migrate Windows code to -// use this as well. +bool IsValidGUID(const base::StringPiece& guid) { + return IsValidGUIDInternal(guid, false /* strict */); +} + +bool IsValidGUIDOutputString(const base::StringPiece& guid) { + return IsValidGUIDInternal(guid, true /* strict */); +} + std::string RandomDataToGUIDString(const uint64_t bytes[2]) { return StringPrintf("%08X-%04X-%04X-%04X-%012llX", static_cast<unsigned int>(bytes[0] >> 32), diff --git a/third_party/chromium/base/guid.h b/third_party/chromium/base/guid.h index 1bb9ab2..e6f4508 100644 --- a/third_party/chromium/base/guid.h +++ b/third_party/chromium/base/guid.h @@ -10,20 +10,33 @@ #include <string> #include "base/base_export.h" +#include "base/strings/string_piece.h" #include "build/build_config.h" namespace base { -// Generate a 128-bit random GUID of the form: "%08X-%04X-%04X-%04X-%012llX". +// Generate a 128-bit (pseudo) random GUID in the form of version 4 as described +// in RFC 4122, section 4.4. +// The format of GUID version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, +// where y is one of [8, 9, A, B]. +// The hexadecimal values "a" through "f" are output as lower case characters. // If GUID generation fails an empty string is returned. -// The POSIX implementation uses pseudo random number generation to create -// the GUID. The Windows implementation uses system services. std::string GenerateGUID(); -#if defined(OS_POSIX) +// Returns true if the input string conforms to the version 4 GUID format. +// Note that this does NOT check if the hexadecimal values "a" through "f" +// are in lower case characters, as Version 4 RFC says onput they're +// case insensitive. (Use IsValidGUIDOutputString for checking if the +// given string is valid output string) +bool IsValidGUID(const base::StringPiece& guid); + +// Returns true if the input string is valid version 4 GUID output string. +// This also checks if the hexadecimal values "a" through "f" are in lower +// case characters. +bool IsValidGUIDOutputString(const base::StringPiece& guid); + // For unit testing purposes only. Do not use outside of tests. std::string RandomDataToGUIDString(const uint64_t bytes[2]); -#endif } // namespace base diff --git a/third_party/chromium/base/guid_unittest.cc b/third_party/chromium/base/guid_unittest.cc index acbd1a2..e53fda8 100644 --- a/third_party/chromium/base/guid_unittest.cc +++ b/third_party/chromium/base/guid_unittest.cc @@ -15,36 +15,8 @@ namespace base { -#if defined(OS_POSIX) - namespace { -template <typename Char> -inline bool IsHexDigit(Char c) { - return (c >= '0' && c <= '9') || - (c >= 'A' && c <= 'F') || - (c >= 'a' && c <= 'f'); -} - -bool IsValidGUID(const std::string& guid) { - const size_t kGUIDLength = 36U; - if (guid.length() != kGUIDLength) - return false; - - for (size_t i = 0; i < guid.length(); ++i) { - char current = guid[i]; - if (i == 8 || i == 13 || i == 18 || i == 23) { - if (current != '-') - return false; - } else { - if (!IsHexDigit(current)) - return false; - } - } - - return true; -} - bool IsGUIDv4(const std::string& guid) { // The format of GUID version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, // where y is one of [8, 9, A, B]. @@ -66,7 +38,6 @@ TEST(GUIDTest, GUIDGeneratesCorrectly) { std::string clientid = RandomDataToGUIDString(bytes); EXPECT_EQ("01234567-89AB-CDEF-FEDC-BA9876543210", clientid); } -#endif TEST(GUIDTest, GUIDCorrectlyFormatted) { const int kIterations = 10; @@ -84,10 +55,8 @@ TEST(GUIDTest, GUIDBasicUniqueness) { EXPECT_EQ(36U, guid1.length()); EXPECT_EQ(36U, guid2.length()); EXPECT_NE(guid1, guid2); -#if defined(OS_POSIX) EXPECT_TRUE(IsGUIDv4(guid1)); EXPECT_TRUE(IsGUIDv4(guid2)); -#endif } } diff --git a/third_party/chromium/base/json/json_parser.cc b/third_party/chromium/base/json/json_parser.cc index 708965a..011272f 100644 --- a/third_party/chromium/base/json/json_parser.cc +++ b/third_party/chromium/base/json/json_parser.cc @@ -187,9 +187,9 @@ class StackMarker { JSONParser::JSONParser(int options) : options_(options), - start_pos_(NULL), - pos_(NULL), - end_pos_(NULL), + start_pos_(nullptr), + pos_(nullptr), + end_pos_(nullptr), index_(0), stack_depth_(0), line_number_(0), @@ -208,7 +208,7 @@ std::unique_ptr<Value> JSONParser::Parse(StringPiece input) { // be used, so do not bother copying the input because StringPiece will not // be used anywhere. if (!(options_ & JSON_DETACHABLE_CHILDREN)) { - input_copy = WrapUnique(new std::string(input.as_string())); + input_copy = MakeUnique<std::string>(input.as_string()); start_pos_ = input_copy->data(); } else { start_pos_ = input.data(); @@ -250,12 +250,14 @@ std::unique_ptr<Value> JSONParser::Parse(StringPiece input) { // hidden root. if (!(options_ & JSON_DETACHABLE_CHILDREN)) { if (root->IsType(Value::TYPE_DICTIONARY)) { - return WrapUnique(new DictionaryHiddenRootValue(std::move(input_copy), - std::move(root))); - } else if (root->IsType(Value::TYPE_LIST)) { - return WrapUnique( - new ListHiddenRootValue(std::move(input_copy), std::move(root))); - } else if (root->IsType(Value::TYPE_STRING)) { + return MakeUnique<DictionaryHiddenRootValue>(std::move(input_copy), + std::move(root)); + } + if (root->IsType(Value::TYPE_LIST)) { + return MakeUnique<ListHiddenRootValue>(std::move(input_copy), + std::move(root)); + } + if (root->IsType(Value::TYPE_STRING)) { // A string type could be a JSONStringValue, but because there's no // corresponding HiddenRootValue, the memory will be lost. Deep copy to // preserve it. @@ -286,16 +288,12 @@ int JSONParser::error_column() const { // StringBuilder /////////////////////////////////////////////////////////////// -JSONParser::StringBuilder::StringBuilder() - : pos_(NULL), - length_(0), - string_(NULL) { -} +JSONParser::StringBuilder::StringBuilder() : StringBuilder(nullptr) {} JSONParser::StringBuilder::StringBuilder(const char* pos) : pos_(pos), length_(0), - string_(NULL) { + string_(nullptr) { } void JSONParser::StringBuilder::Swap(StringBuilder* other) { @@ -484,20 +482,20 @@ Value* JSONParser::ParseToken(Token token) { return ConsumeLiteral(); default: ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); - return NULL; + return nullptr; } } Value* JSONParser::ConsumeDictionary() { if (*pos_ != '{') { ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); - return NULL; + return nullptr; } StackMarker depth_check(&stack_depth_); if (depth_check.IsTooDeep()) { ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 1); - return NULL; + return nullptr; } std::unique_ptr<DictionaryValue> dict(new DictionaryValue); @@ -507,13 +505,13 @@ Value* JSONParser::ConsumeDictionary() { while (token != T_OBJECT_END) { if (token != T_STRING) { ReportError(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, 1); - return NULL; + return nullptr; } // First consume the key. StringBuilder key; if (!ConsumeStringRaw(&key)) { - return NULL; + return nullptr; } // Read the separator. @@ -521,7 +519,7 @@ Value* JSONParser::ConsumeDictionary() { token = GetNextToken(); if (token != T_OBJECT_PAIR_SEPARATOR) { ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; + return nullptr; } // The next token is the value. Ownership transfers to |dict|. @@ -529,7 +527,7 @@ Value* JSONParser::ConsumeDictionary() { Value* value = ParseNextToken(); if (!value) { // ReportError from deeper level. - return NULL; + return nullptr; } dict->SetWithoutPathExpansion(key.AsString(), value); @@ -541,11 +539,11 @@ Value* JSONParser::ConsumeDictionary() { token = GetNextToken(); if (token == T_OBJECT_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) { ReportError(JSONReader::JSON_TRAILING_COMMA, 1); - return NULL; + return nullptr; } } else if (token != T_OBJECT_END) { ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); - return NULL; + return nullptr; } } @@ -555,13 +553,13 @@ Value* JSONParser::ConsumeDictionary() { Value* JSONParser::ConsumeList() { if (*pos_ != '[') { ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); - return NULL; + return nullptr; } StackMarker depth_check(&stack_depth_); if (depth_check.IsTooDeep()) { ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 1); - return NULL; + return nullptr; } std::unique_ptr<ListValue> list(new ListValue); @@ -572,7 +570,7 @@ Value* JSONParser::ConsumeList() { Value* item = ParseToken(token); if (!item) { // ReportError from deeper level. - return NULL; + return nullptr; } list->Append(item); @@ -584,11 +582,11 @@ Value* JSONParser::ConsumeList() { token = GetNextToken(); if (token == T_ARRAY_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) { ReportError(JSONReader::JSON_TRAILING_COMMA, 1); - return NULL; + return nullptr; } } else if (token != T_ARRAY_END) { ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; + return nullptr; } } @@ -598,17 +596,16 @@ Value* JSONParser::ConsumeList() { Value* JSONParser::ConsumeString() { StringBuilder string; if (!ConsumeStringRaw(&string)) - return NULL; + return nullptr; // Create the Value representation, using a hidden root, if configured // to do so, and if the string can be represented by StringPiece. - if (string.CanBeStringPiece() && !(options_ & JSON_DETACHABLE_CHILDREN)) { + if (string.CanBeStringPiece() && !(options_ & JSON_DETACHABLE_CHILDREN)) return new JSONStringValue(string.AsStringPiece()); - } else { - if (string.CanBeStringPiece()) - string.Convert(); - return new StringValue(string.AsString()); - } + + if (string.CanBeStringPiece()) + string.Convert(); + return new StringValue(string.AsString()); } bool JSONParser::ConsumeStringRaw(StringBuilder* out) { @@ -633,11 +630,23 @@ bool JSONParser::ConsumeStringRaw(StringBuilder* out) { return false; } - // If this character is an escape sequence... - if (next_char == '\\') { - // The input string will be adjusted (either by combining the two - // characters of an encoded escape sequence, or with a UTF conversion), - // so using StringPiece isn't possible -- force a conversion. + if (next_char == '"') { + --index_; // Rewind by one because of CBU8_NEXT. + out->Swap(&string); + return true; + } + + // If this character is not an escape sequence... + if (next_char != '\\') { + if (next_char < kExtendedASCIIStart) + string.Append(static_cast<char>(next_char)); + else + DecodeUTF8(next_char, &string); + } else { + // And if it is an escape sequence, the input string will be adjusted + // (either by combining the two characters of an encoded escape sequence, + // or with a UTF conversion), so using StringPiece isn't possible -- force + // a conversion. string.Convert(); if (!CanConsume(1)) { @@ -719,15 +728,6 @@ bool JSONParser::ConsumeStringRaw(StringBuilder* out) { ReportError(JSONReader::JSON_INVALID_ESCAPE, 0); return false; } - } else if (next_char == '"') { - --index_; // Rewind by one because of CBU8_NEXT. - out->Swap(&string); - return true; - } else { - if (next_char < kExtendedASCIIStart) - string.Append(static_cast<char>(next_char)); - else - DecodeUTF8(next_char, &string); } } @@ -832,7 +832,7 @@ Value* JSONParser::ConsumeNumber() { if (!ReadInt(false)) { ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; + return nullptr; } end_index = index_; @@ -840,12 +840,12 @@ Value* JSONParser::ConsumeNumber() { if (*pos_ == '.') { if (!CanConsume(1)) { ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; + return nullptr; } NextChar(); if (!ReadInt(true)) { ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; + return nullptr; } end_index = index_; } @@ -857,7 +857,7 @@ Value* JSONParser::ConsumeNumber() { NextChar(); if (!ReadInt(true)) { ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; + return nullptr; } end_index = index_; } @@ -877,7 +877,7 @@ Value* JSONParser::ConsumeNumber() { break; default: ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; + return nullptr; } pos_ = exit_pos; @@ -895,7 +895,7 @@ Value* JSONParser::ConsumeNumber() { return new FundamentalValue(num_double); } - return NULL; + return nullptr; } bool JSONParser::ReadInt(bool allow_leading_zeros) { @@ -925,7 +925,7 @@ Value* JSONParser::ConsumeLiteral() { if (!CanConsume(kTrueLen - 1) || !StringsAreEqual(pos_, kTrueLiteral, kTrueLen)) { ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; + return nullptr; } NextNChars(kTrueLen - 1); return new FundamentalValue(true); @@ -936,7 +936,7 @@ Value* JSONParser::ConsumeLiteral() { if (!CanConsume(kFalseLen - 1) || !StringsAreEqual(pos_, kFalseLiteral, kFalseLen)) { ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; + return nullptr; } NextNChars(kFalseLen - 1); return new FundamentalValue(false); @@ -947,14 +947,14 @@ Value* JSONParser::ConsumeLiteral() { if (!CanConsume(kNullLen - 1) || !StringsAreEqual(pos_, kNullLiteral, kNullLen)) { ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); - return NULL; + return nullptr; } NextNChars(kNullLen - 1); return Value::CreateNullValue().release(); } default: ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); - return NULL; + return nullptr; } } diff --git a/third_party/chromium/base/json/json_reader_unittest.cc b/third_party/chromium/base/json/json_reader_unittest.cc index b1ad46e..1daf26c 100644 --- a/third_party/chromium/base/json/json_reader_unittest.cc +++ b/third_party/chromium/base/json/json_reader_unittest.cc @@ -19,525 +19,549 @@ namespace base { TEST(JSONReaderTest, Reading) { - // some whitespace checking - std::unique_ptr<Value> root = JSONReader().ReadToValue(" null "); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_NULL)); - - // Invalid JSON string - root = JSONReader().ReadToValue("nu"); - EXPECT_FALSE(root.get()); - - // Simple bool - root = JSONReader().ReadToValue("true "); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN)); - - // Embedded comment - root = JSONReader().ReadToValue("/* comment */null"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_NULL)); - root = JSONReader().ReadToValue("40 /* comment */"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); - root = JSONReader().ReadToValue("true // comment"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN)); - root = JSONReader().ReadToValue("/* comment */\"sample string\""); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - std::string value; - EXPECT_TRUE(root->GetAsString(&value)); - EXPECT_EQ("sample string", value); - root = JSONReader().ReadToValue("[1, /* comment, 2 ] */ \n 3]"); - ASSERT_TRUE(root.get()); - ListValue* list = static_cast<ListValue*>(root.get()); - EXPECT_EQ(2u, list->GetSize()); - int int_val = 0; - EXPECT_TRUE(list->GetInteger(0, &int_val)); - EXPECT_EQ(1, int_val); - EXPECT_TRUE(list->GetInteger(1, &int_val)); - EXPECT_EQ(3, int_val); - root = JSONReader().ReadToValue("[1, /*a*/2, 3]"); - ASSERT_TRUE(root.get()); - list = static_cast<ListValue*>(root.get()); - EXPECT_EQ(3u, list->GetSize()); - root = JSONReader().ReadToValue("/* comment **/42"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); - EXPECT_TRUE(root->GetAsInteger(&int_val)); - EXPECT_EQ(42, int_val); - root = JSONReader().ReadToValue( - "/* comment **/\n" - "// */ 43\n" - "44"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); - EXPECT_TRUE(root->GetAsInteger(&int_val)); - EXPECT_EQ(44, int_val); - - // Test number formats - root = JSONReader().ReadToValue("43"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); - EXPECT_TRUE(root->GetAsInteger(&int_val)); - EXPECT_EQ(43, int_val); - - // According to RFC4627, oct, hex, and leading zeros are invalid JSON. - root = JSONReader().ReadToValue("043"); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("0x43"); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("00"); - EXPECT_FALSE(root.get()); - - // Test 0 (which needs to be special cased because of the leading zero - // clause). - root = JSONReader().ReadToValue("0"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); - int_val = 1; - EXPECT_TRUE(root->GetAsInteger(&int_val)); - EXPECT_EQ(0, int_val); - - // Numbers that overflow ints should succeed, being internally promoted to - // storage as doubles - root = JSONReader().ReadToValue("2147483648"); - ASSERT_TRUE(root.get()); - double double_val; - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(2147483648.0, double_val); - root = JSONReader().ReadToValue("-2147483649"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(-2147483649.0, double_val); - - // Parse a double - root = JSONReader().ReadToValue("43.1"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(43.1, double_val); - - root = JSONReader().ReadToValue("4.3e-1"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(.43, double_val); - - root = JSONReader().ReadToValue("2.1e0"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(2.1, double_val); - - root = JSONReader().ReadToValue("2.1e+0001"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(21.0, double_val); - - root = JSONReader().ReadToValue("0.01"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(0.01, double_val); - - root = JSONReader().ReadToValue("1.00"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); - double_val = 0.0; - EXPECT_TRUE(root->GetAsDouble(&double_val)); - EXPECT_DOUBLE_EQ(1.0, double_val); - - // Fractional parts must have a digit before and after the decimal point. - root = JSONReader().ReadToValue("1."); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue(".1"); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("1.e10"); - EXPECT_FALSE(root.get()); - - // Exponent must have a digit following the 'e'. - root = JSONReader().ReadToValue("1e"); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("1E"); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("1e1."); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("1e1.0"); - EXPECT_FALSE(root.get()); - - // INF/-INF/NaN are not valid - root = JSONReader().ReadToValue("1e1000"); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("-1e1000"); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("NaN"); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("nan"); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("inf"); - EXPECT_FALSE(root.get()); - - // Invalid number formats - root = JSONReader().ReadToValue("4.3.1"); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("4e3.1"); - EXPECT_FALSE(root.get()); - - // Test string parser - root = JSONReader().ReadToValue("\"hello world\""); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - std::string str_val; - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("hello world", str_val); - - // Empty string - root = JSONReader().ReadToValue("\"\""); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - str_val.clear(); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("", str_val); - - // Test basic string escapes - root = JSONReader().ReadToValue("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\\v\""); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - str_val.clear(); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ(" \"\\/\b\f\n\r\t\v", str_val); - - // Test hex and unicode escapes including the null character. - root = JSONReader().ReadToValue("\"\\x41\\x00\\u1234\""); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - str_val.clear(); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ((std::string{'A', '\0', '\xE1', '\x88', '\xB4'}), str_val); - - // Test invalid strings - root = JSONReader().ReadToValue("\"no closing quote"); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("\"\\z invalid escape char\""); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("\"\\xAQ invalid hex code\""); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("not enough hex chars\\x1\""); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("\"not enough escape chars\\u123\""); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("\"extra backslash at end of input\\\""); - EXPECT_FALSE(root.get()); - - // Basic array - root = JSONReader::Read("[true, false, null]"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); - list = static_cast<ListValue*>(root.get()); - EXPECT_EQ(3U, list->GetSize()); - - // Test with trailing comma. Should be parsed the same as above. - std::unique_ptr<Value> root2 = - JSONReader::Read("[true, false, null, ]", JSON_ALLOW_TRAILING_COMMAS); - EXPECT_TRUE(root->Equals(root2.get())); - - // Empty array - root = JSONReader::Read("[]"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); - list = static_cast<ListValue*>(root.get()); - EXPECT_EQ(0U, list->GetSize()); - - // Nested arrays - root = JSONReader::Read("[[true], [], [false, [], [null]], null]"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); - list = static_cast<ListValue*>(root.get()); - EXPECT_EQ(4U, list->GetSize()); - - // Lots of trailing commas. - root2 = JSONReader::Read("[[true], [], [false, [], [null, ] , ], null,]", - JSON_ALLOW_TRAILING_COMMAS); - EXPECT_TRUE(root->Equals(root2.get())); - - // Invalid, missing close brace. - root = JSONReader::Read("[[true], [], [false, [], [null]], null"); - EXPECT_FALSE(root.get()); - - // Invalid, too many commas - root = JSONReader::Read("[true,, null]"); - EXPECT_FALSE(root.get()); - root = JSONReader::Read("[true,, null]", JSON_ALLOW_TRAILING_COMMAS); - EXPECT_FALSE(root.get()); - - // Invalid, no commas - root = JSONReader::Read("[true null]"); - EXPECT_FALSE(root.get()); - - // Invalid, trailing comma - root = JSONReader::Read("[true,]"); - EXPECT_FALSE(root.get()); - - // Valid if we set |allow_trailing_comma| to true. - root = JSONReader::Read("[true,]", JSON_ALLOW_TRAILING_COMMAS); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); - list = static_cast<ListValue*>(root.get()); - EXPECT_EQ(1U, list->GetSize()); - Value* tmp_value = NULL; - ASSERT_TRUE(list->Get(0, &tmp_value)); - EXPECT_TRUE(tmp_value->IsType(Value::TYPE_BOOLEAN)); - bool bool_value = false; - EXPECT_TRUE(tmp_value->GetAsBoolean(&bool_value)); - EXPECT_TRUE(bool_value); - - // Don't allow empty elements, even if |allow_trailing_comma| is - // true. - root = JSONReader::Read("[,]", JSON_ALLOW_TRAILING_COMMAS); - EXPECT_FALSE(root.get()); - root = JSONReader::Read("[true,,]", JSON_ALLOW_TRAILING_COMMAS); - EXPECT_FALSE(root.get()); - root = JSONReader::Read("[,true,]", JSON_ALLOW_TRAILING_COMMAS); - EXPECT_FALSE(root.get()); - root = JSONReader::Read("[true,,false]", JSON_ALLOW_TRAILING_COMMAS); - EXPECT_FALSE(root.get()); - - // Test objects - root = JSONReader::Read("{}"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); - - root = JSONReader::Read( - "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); - DictionaryValue* dict_val = static_cast<DictionaryValue*>(root.get()); - double_val = 0.0; - EXPECT_TRUE(dict_val->GetDouble("number", &double_val)); - EXPECT_DOUBLE_EQ(9.87654321, double_val); - Value* null_val = NULL; - ASSERT_TRUE(dict_val->Get("null", &null_val)); - EXPECT_TRUE(null_val->IsType(Value::TYPE_NULL)); - str_val.clear(); - EXPECT_TRUE(dict_val->GetString("S", &str_val)); - EXPECT_EQ("str", str_val); - - root2 = JSONReader::Read( - "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }", - JSON_ALLOW_TRAILING_COMMAS); - ASSERT_TRUE(root2.get()); - EXPECT_TRUE(root->Equals(root2.get())); - - // Test newline equivalence. - root2 = JSONReader::Read( - "{\n" - " \"number\":9.87654321,\n" - " \"null\":null,\n" - " \"\\x53\":\"str\",\n" - "}\n", - JSON_ALLOW_TRAILING_COMMAS); - ASSERT_TRUE(root2.get()); - EXPECT_TRUE(root->Equals(root2.get())); - - root2 = JSONReader::Read( - "{\r\n" - " \"number\":9.87654321,\r\n" - " \"null\":null,\r\n" - " \"\\x53\":\"str\",\r\n" - "}\r\n", - JSON_ALLOW_TRAILING_COMMAS); - ASSERT_TRUE(root2.get()); - EXPECT_TRUE(root->Equals(root2.get())); - - // Test nesting - root = JSONReader::Read( - "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); - dict_val = static_cast<DictionaryValue*>(root.get()); - DictionaryValue* inner_dict = NULL; - ASSERT_TRUE(dict_val->GetDictionary("inner", &inner_dict)); - ListValue* inner_array = NULL; - ASSERT_TRUE(inner_dict->GetList("array", &inner_array)); - EXPECT_EQ(1U, inner_array->GetSize()); - bool_value = true; - EXPECT_TRUE(dict_val->GetBoolean("false", &bool_value)); - EXPECT_FALSE(bool_value); - inner_dict = NULL; - EXPECT_TRUE(dict_val->GetDictionary("d", &inner_dict)); - - root2 = JSONReader::Read( - "{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}", - JSON_ALLOW_TRAILING_COMMAS); - EXPECT_TRUE(root->Equals(root2.get())); - - // Test keys with periods - root = JSONReader::Read("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); - dict_val = static_cast<DictionaryValue*>(root.get()); - int integer_value = 0; - EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value)); - EXPECT_EQ(3, integer_value); - EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("c", &integer_value)); - EXPECT_EQ(2, integer_value); - inner_dict = NULL; - ASSERT_TRUE(dict_val->GetDictionaryWithoutPathExpansion("d.e.f", - &inner_dict)); - EXPECT_EQ(1U, inner_dict->size()); - EXPECT_TRUE(inner_dict->GetIntegerWithoutPathExpansion("g.h.i.j", - &integer_value)); - EXPECT_EQ(1, integer_value); - - root = JSONReader::Read("{\"a\":{\"b\":2},\"a.b\":1}"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); - dict_val = static_cast<DictionaryValue*>(root.get()); - EXPECT_TRUE(dict_val->GetInteger("a.b", &integer_value)); - EXPECT_EQ(2, integer_value); - EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value)); - EXPECT_EQ(1, integer_value); - - // Invalid, no closing brace - root = JSONReader::Read("{\"a\": true"); - EXPECT_FALSE(root.get()); - - // Invalid, keys must be quoted - root = JSONReader::Read("{foo:true}"); - EXPECT_FALSE(root.get()); - - // Invalid, trailing comma - root = JSONReader::Read("{\"a\":true,}"); - EXPECT_FALSE(root.get()); - - // Invalid, too many commas - root = JSONReader::Read("{\"a\":true,,\"b\":false}"); - EXPECT_FALSE(root.get()); - root = - JSONReader::Read("{\"a\":true,,\"b\":false}", JSON_ALLOW_TRAILING_COMMAS); - EXPECT_FALSE(root.get()); - - // Invalid, no separator - root = JSONReader::Read("{\"a\" \"b\"}"); - EXPECT_FALSE(root.get()); - - // Invalid, lone comma. - root = JSONReader::Read("{,}"); - EXPECT_FALSE(root.get()); - root = JSONReader::Read("{,}", JSON_ALLOW_TRAILING_COMMAS); - EXPECT_FALSE(root.get()); - root = JSONReader::Read("{\"a\":true,,}", JSON_ALLOW_TRAILING_COMMAS); - EXPECT_FALSE(root.get()); - root = JSONReader::Read("{,\"a\":true}", JSON_ALLOW_TRAILING_COMMAS); - EXPECT_FALSE(root.get()); - root = - JSONReader::Read("{\"a\":true,,\"b\":false}", JSON_ALLOW_TRAILING_COMMAS); - EXPECT_FALSE(root.get()); - - // Test stack overflow - std::string evil(1000000, '['); - evil.append(std::string(1000000, ']')); - root = JSONReader::Read(evil); - EXPECT_FALSE(root.get()); - - // A few thousand adjacent lists is fine. - std::string not_evil("["); - not_evil.reserve(15010); - for (int i = 0; i < 5000; ++i) { - not_evil.append("[],"); - } - not_evil.append("[]]"); - root = JSONReader::Read(not_evil); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); - list = static_cast<ListValue*>(root.get()); - EXPECT_EQ(5001U, list->GetSize()); - - // Test utf8 encoded input - root = JSONReader().ReadToValue("\"\xe7\xbd\x91\xe9\xa1\xb5\""); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - str_val.clear(); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("\xE7\xBD\x91\xE9\xA1\xB5", str_val); - - root = JSONReader().ReadToValue( - "{\"path\": \"/tmp/\xc3\xa0\xc3\xa8\xc3\xb2.png\"}"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); - EXPECT_TRUE(root->GetAsDictionary(&dict_val)); - EXPECT_TRUE(dict_val->GetString("path", &str_val)); - EXPECT_EQ("/tmp/\xC3\xA0\xC3\xA8\xC3\xB2.png", str_val); - - // Test invalid utf8 encoded input - root = JSONReader().ReadToValue("\"345\xb0\xa1\xb0\xa2\""); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("\"123\xc0\x81\""); - EXPECT_FALSE(root.get()); - root = JSONReader().ReadToValue("\"abc\xc0\xae\""); - EXPECT_FALSE(root.get()); - - // Test utf16 encoded strings. - root = JSONReader().ReadToValue("\"\\u20ac3,14\""); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - str_val.clear(); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("\xe2\x82\xac""3,14", str_val); - - root = JSONReader().ReadToValue("\"\\ud83d\\udca9\\ud83d\\udc6c\""); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); - str_val.clear(); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("\xf0\x9f\x92\xa9\xf0\x9f\x91\xac", str_val); - - // Test invalid utf16 strings. - const char* const cases[] = { - "\"\\u123\"", // Invalid scalar. - "\"\\ud83d\"", // Invalid scalar. - "\"\\u$%@!\"", // Invalid scalar. - "\"\\uzz89\"", // Invalid scalar. - "\"\\ud83d\\udca\"", // Invalid lower surrogate. - "\"\\ud83d\\ud83d\"", // Invalid lower surrogate. - "\"\\ud83foo\"", // No lower surrogate. - "\"\\ud83\\foo\"" // No lower surrogate. - }; - for (size_t i = 0; i < arraysize(cases); ++i) { - root = JSONReader().ReadToValue(cases[i]); - EXPECT_FALSE(root.get()) << cases[i]; + { + // some whitespace checking + std::unique_ptr<Value> root = JSONReader().ReadToValue(" null "); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_NULL)); + } + + { + // Invalid JSON string + EXPECT_FALSE(JSONReader().ReadToValue("nu")); + } + + { + // Simple bool + std::unique_ptr<Value> root = JSONReader().ReadToValue("true "); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN)); + } + + { + // Embedded comment + std::unique_ptr<Value> root = JSONReader().ReadToValue("/* comment */null"); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_NULL)); + root = JSONReader().ReadToValue("40 /* comment */"); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); + root = JSONReader().ReadToValue("true // comment"); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN)); + root = JSONReader().ReadToValue("/* comment */\"sample string\""); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + std::string value; + EXPECT_TRUE(root->GetAsString(&value)); + EXPECT_EQ("sample string", value); + std::unique_ptr<ListValue> list = ListValue::From( + JSONReader().ReadToValue("[1, /* comment, 2 ] */ \n 3]")); + ASSERT_TRUE(list); + EXPECT_EQ(2u, list->GetSize()); + int int_val = 0; + EXPECT_TRUE(list->GetInteger(0, &int_val)); + EXPECT_EQ(1, int_val); + EXPECT_TRUE(list->GetInteger(1, &int_val)); + EXPECT_EQ(3, int_val); + list = ListValue::From(JSONReader().ReadToValue("[1, /*a*/2, 3]")); + ASSERT_TRUE(list); + EXPECT_EQ(3u, list->GetSize()); + root = JSONReader().ReadToValue("/* comment **/42"); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); + EXPECT_TRUE(root->GetAsInteger(&int_val)); + EXPECT_EQ(42, int_val); + root = JSONReader().ReadToValue( + "/* comment **/\n" + "// */ 43\n" + "44"); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); + EXPECT_TRUE(root->GetAsInteger(&int_val)); + EXPECT_EQ(44, int_val); + } + + { + // Test number formats + std::unique_ptr<Value> root = JSONReader().ReadToValue("43"); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); + int int_val = 0; + EXPECT_TRUE(root->GetAsInteger(&int_val)); + EXPECT_EQ(43, int_val); + } + + { + // According to RFC4627, oct, hex, and leading zeros are invalid JSON. + EXPECT_FALSE(JSONReader().ReadToValue("043")); + EXPECT_FALSE(JSONReader().ReadToValue("0x43")); + EXPECT_FALSE(JSONReader().ReadToValue("00")); + } + + { + // Test 0 (which needs to be special cased because of the leading zero + // clause). + std::unique_ptr<Value> root = JSONReader().ReadToValue("0"); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); + int int_val = 1; + EXPECT_TRUE(root->GetAsInteger(&int_val)); + EXPECT_EQ(0, int_val); + } + + { + // Numbers that overflow ints should succeed, being internally promoted to + // storage as doubles + std::unique_ptr<Value> root = JSONReader().ReadToValue("2147483648"); + ASSERT_TRUE(root); + double double_val; + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(2147483648.0, double_val); + root = JSONReader().ReadToValue("-2147483649"); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(-2147483649.0, double_val); + } + + { + // Parse a double + std::unique_ptr<Value> root = JSONReader().ReadToValue("43.1"); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(43.1, double_val); + + root = JSONReader().ReadToValue("4.3e-1"); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(.43, double_val); + + root = JSONReader().ReadToValue("2.1e0"); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(2.1, double_val); + + root = JSONReader().ReadToValue("2.1e+0001"); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(21.0, double_val); + + root = JSONReader().ReadToValue("0.01"); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(0.01, double_val); + + root = JSONReader().ReadToValue("1.00"); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(1.0, double_val); } - // Test literal root objects. - root = JSONReader::Read("null"); - EXPECT_TRUE(root->IsType(Value::TYPE_NULL)); + { + // Fractional parts must have a digit before and after the decimal point. + EXPECT_FALSE(JSONReader().ReadToValue("1.")); + EXPECT_FALSE(JSONReader().ReadToValue(".1")); + EXPECT_FALSE(JSONReader().ReadToValue("1.e10")); + } + + { + // Exponent must have a digit following the 'e'. + EXPECT_FALSE(JSONReader().ReadToValue("1e")); + EXPECT_FALSE(JSONReader().ReadToValue("1E")); + EXPECT_FALSE(JSONReader().ReadToValue("1e1.")); + EXPECT_FALSE(JSONReader().ReadToValue("1e1.0")); + } + + { + // INF/-INF/NaN are not valid + EXPECT_FALSE(JSONReader().ReadToValue("1e1000")); + EXPECT_FALSE(JSONReader().ReadToValue("-1e1000")); + EXPECT_FALSE(JSONReader().ReadToValue("NaN")); + EXPECT_FALSE(JSONReader().ReadToValue("nan")); + EXPECT_FALSE(JSONReader().ReadToValue("inf")); + } + + { + // Invalid number formats + EXPECT_FALSE(JSONReader().ReadToValue("4.3.1")); + EXPECT_FALSE(JSONReader().ReadToValue("4e3.1")); + } + + { + // Test string parser + std::unique_ptr<Value> root = JSONReader().ReadToValue("\"hello world\""); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + std::string str_val; + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ("hello world", str_val); + } - root = JSONReader::Read("true"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->GetAsBoolean(&bool_value)); - EXPECT_TRUE(bool_value); + { + // Empty string + std::unique_ptr<Value> root = JSONReader().ReadToValue("\"\""); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + std::string str_val; + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ("", str_val); + } - root = JSONReader::Read("10"); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->GetAsInteger(&integer_value)); - EXPECT_EQ(10, integer_value); + { + // Test basic string escapes + std::unique_ptr<Value> root = + JSONReader().ReadToValue("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\\v\""); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + std::string str_val; + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ(" \"\\/\b\f\n\r\t\v", str_val); + } - root = JSONReader::Read("\"root\""); - ASSERT_TRUE(root.get()); - EXPECT_TRUE(root->GetAsString(&str_val)); - EXPECT_EQ("root", str_val); + { + // Test hex and unicode escapes including the null character. + std::unique_ptr<Value> root = + JSONReader().ReadToValue("\"\\x41\\x00\\u1234\""); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + std::string str_val; + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ((std::string{'A', '\0', '\xE1', '\x88', '\xB4'}), str_val); + } + + { + // Test invalid strings + EXPECT_FALSE(JSONReader().ReadToValue("\"no closing quote")); + EXPECT_FALSE(JSONReader().ReadToValue("\"\\z invalid escape char\"")); + EXPECT_FALSE(JSONReader().ReadToValue("\"\\xAQ invalid hex code\"")); + EXPECT_FALSE(JSONReader().ReadToValue("not enough hex chars\\x1\"")); + EXPECT_FALSE(JSONReader().ReadToValue("\"not enough escape chars\\u123\"")); + EXPECT_FALSE( + JSONReader().ReadToValue("\"extra backslash at end of input\\\"")); + } + + { + // Basic array + std::unique_ptr<ListValue> list = + ListValue::From(JSONReader::Read("[true, false, null]")); + ASSERT_TRUE(list); + EXPECT_EQ(3U, list->GetSize()); + + // Test with trailing comma. Should be parsed the same as above. + std::unique_ptr<Value> root2 = + JSONReader::Read("[true, false, null, ]", JSON_ALLOW_TRAILING_COMMAS); + EXPECT_TRUE(list->Equals(root2.get())); + } + + { + // Empty array + std::unique_ptr<ListValue> list = ListValue::From(JSONReader::Read("[]")); + ASSERT_TRUE(list); + EXPECT_EQ(0U, list->GetSize()); + } + + { + // Nested arrays + std::unique_ptr<ListValue> list = ListValue::From( + JSONReader::Read("[[true], [], [false, [], [null]], null]")); + ASSERT_TRUE(list); + EXPECT_EQ(4U, list->GetSize()); + + // Lots of trailing commas. + std::unique_ptr<Value> root2 = + JSONReader::Read("[[true], [], [false, [], [null, ] , ], null,]", + JSON_ALLOW_TRAILING_COMMAS); + EXPECT_TRUE(list->Equals(root2.get())); + } + + { + // Invalid, missing close brace. + EXPECT_FALSE(JSONReader::Read("[[true], [], [false, [], [null]], null")); + + // Invalid, too many commas + EXPECT_FALSE(JSONReader::Read("[true,, null]")); + EXPECT_FALSE(JSONReader::Read("[true,, null]", JSON_ALLOW_TRAILING_COMMAS)); + + // Invalid, no commas + EXPECT_FALSE(JSONReader::Read("[true null]")); + + // Invalid, trailing comma + EXPECT_FALSE(JSONReader::Read("[true,]")); + } + + { + // Valid if we set |allow_trailing_comma| to true. + std::unique_ptr<ListValue> list = ListValue::From( + JSONReader::Read("[true,]", JSON_ALLOW_TRAILING_COMMAS)); + ASSERT_TRUE(list); + EXPECT_EQ(1U, list->GetSize()); + Value* tmp_value = nullptr; + ASSERT_TRUE(list->Get(0, &tmp_value)); + EXPECT_TRUE(tmp_value->IsType(Value::TYPE_BOOLEAN)); + bool bool_value = false; + EXPECT_TRUE(tmp_value->GetAsBoolean(&bool_value)); + EXPECT_TRUE(bool_value); + } + + { + // Don't allow empty elements, even if |allow_trailing_comma| is + // true. + EXPECT_FALSE(JSONReader::Read("[,]", JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(JSONReader::Read("[true,,]", JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(JSONReader::Read("[,true,]", JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(JSONReader::Read("[true,,false]", JSON_ALLOW_TRAILING_COMMAS)); + } + + { + // Test objects + std::unique_ptr<DictionaryValue> dict_val = + DictionaryValue::From(JSONReader::Read("{}")); + ASSERT_TRUE(dict_val); + + dict_val = DictionaryValue::From(JSONReader::Read( + "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }")); + ASSERT_TRUE(dict_val); + double double_val = 0.0; + EXPECT_TRUE(dict_val->GetDouble("number", &double_val)); + EXPECT_DOUBLE_EQ(9.87654321, double_val); + Value* null_val = nullptr; + ASSERT_TRUE(dict_val->Get("null", &null_val)); + EXPECT_TRUE(null_val->IsType(Value::TYPE_NULL)); + std::string str_val; + EXPECT_TRUE(dict_val->GetString("S", &str_val)); + EXPECT_EQ("str", str_val); + + std::unique_ptr<Value> root2 = JSONReader::Read( + "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }", + JSON_ALLOW_TRAILING_COMMAS); + ASSERT_TRUE(root2); + EXPECT_TRUE(dict_val->Equals(root2.get())); + + // Test newline equivalence. + root2 = JSONReader::Read( + "{\n" + " \"number\":9.87654321,\n" + " \"null\":null,\n" + " \"\\x53\":\"str\",\n" + "}\n", + JSON_ALLOW_TRAILING_COMMAS); + ASSERT_TRUE(root2); + EXPECT_TRUE(dict_val->Equals(root2.get())); + + root2 = JSONReader::Read( + "{\r\n" + " \"number\":9.87654321,\r\n" + " \"null\":null,\r\n" + " \"\\x53\":\"str\",\r\n" + "}\r\n", + JSON_ALLOW_TRAILING_COMMAS); + ASSERT_TRUE(root2); + EXPECT_TRUE(dict_val->Equals(root2.get())); + } + + { + // Test nesting + std::unique_ptr<DictionaryValue> dict_val = + DictionaryValue::From(JSONReader::Read( + "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}")); + ASSERT_TRUE(dict_val); + DictionaryValue* inner_dict = nullptr; + ASSERT_TRUE(dict_val->GetDictionary("inner", &inner_dict)); + ListValue* inner_array = nullptr; + ASSERT_TRUE(inner_dict->GetList("array", &inner_array)); + EXPECT_EQ(1U, inner_array->GetSize()); + bool bool_value = true; + EXPECT_TRUE(dict_val->GetBoolean("false", &bool_value)); + EXPECT_FALSE(bool_value); + inner_dict = nullptr; + EXPECT_TRUE(dict_val->GetDictionary("d", &inner_dict)); + + std::unique_ptr<Value> root2 = JSONReader::Read( + "{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}", + JSON_ALLOW_TRAILING_COMMAS); + EXPECT_TRUE(dict_val->Equals(root2.get())); + } + + { + // Test keys with periods + std::unique_ptr<DictionaryValue> dict_val = DictionaryValue::From( + JSONReader::Read("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}")); + ASSERT_TRUE(dict_val); + int integer_value = 0; + EXPECT_TRUE( + dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value)); + EXPECT_EQ(3, integer_value); + EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("c", &integer_value)); + EXPECT_EQ(2, integer_value); + DictionaryValue* inner_dict = nullptr; + ASSERT_TRUE( + dict_val->GetDictionaryWithoutPathExpansion("d.e.f", &inner_dict)); + EXPECT_EQ(1U, inner_dict->size()); + EXPECT_TRUE( + inner_dict->GetIntegerWithoutPathExpansion("g.h.i.j", &integer_value)); + EXPECT_EQ(1, integer_value); + + dict_val = + DictionaryValue::From(JSONReader::Read("{\"a\":{\"b\":2},\"a.b\":1}")); + ASSERT_TRUE(dict_val); + EXPECT_TRUE(dict_val->GetInteger("a.b", &integer_value)); + EXPECT_EQ(2, integer_value); + EXPECT_TRUE( + dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value)); + EXPECT_EQ(1, integer_value); + } + + { + // Invalid, no closing brace + EXPECT_FALSE(JSONReader::Read("{\"a\": true")); + + // Invalid, keys must be quoted + EXPECT_FALSE(JSONReader::Read("{foo:true}")); + + // Invalid, trailing comma + EXPECT_FALSE(JSONReader::Read("{\"a\":true,}")); + + // Invalid, too many commas + EXPECT_FALSE(JSONReader::Read("{\"a\":true,,\"b\":false}")); + EXPECT_FALSE(JSONReader::Read("{\"a\":true,,\"b\":false}", + JSON_ALLOW_TRAILING_COMMAS)); + + // Invalid, no separator + EXPECT_FALSE(JSONReader::Read("{\"a\" \"b\"}")); + + // Invalid, lone comma. + EXPECT_FALSE(JSONReader::Read("{,}")); + EXPECT_FALSE(JSONReader::Read("{,}", JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE( + JSONReader::Read("{\"a\":true,,}", JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(JSONReader::Read("{,\"a\":true}", JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(JSONReader::Read("{\"a\":true,,\"b\":false}", + JSON_ALLOW_TRAILING_COMMAS)); + } + + { + // Test stack overflow + std::string evil(1000000, '['); + evil.append(std::string(1000000, ']')); + EXPECT_FALSE(JSONReader::Read(evil)); + } + + { + // A few thousand adjacent lists is fine. + std::string not_evil("["); + not_evil.reserve(15010); + for (int i = 0; i < 5000; ++i) + not_evil.append("[],"); + not_evil.append("[]]"); + std::unique_ptr<ListValue> list = + ListValue::From(JSONReader::Read(not_evil)); + ASSERT_TRUE(list); + EXPECT_EQ(5001U, list->GetSize()); + } + + { + // Test utf8 encoded input + std::unique_ptr<Value> root = + JSONReader().ReadToValue("\"\xe7\xbd\x91\xe9\xa1\xb5\""); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + std::string str_val; + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ("\xE7\xBD\x91\xE9\xA1\xB5", str_val); + + std::unique_ptr<DictionaryValue> dict_val = + DictionaryValue::From(JSONReader().ReadToValue( + "{\"path\": \"/tmp/\xc3\xa0\xc3\xa8\xc3\xb2.png\"}")); + ASSERT_TRUE(dict_val); + EXPECT_TRUE(dict_val->GetString("path", &str_val)); + EXPECT_EQ("/tmp/\xC3\xA0\xC3\xA8\xC3\xB2.png", str_val); + } + + { + // Test invalid utf8 encoded input + EXPECT_FALSE(JSONReader().ReadToValue("\"345\xb0\xa1\xb0\xa2\"")); + EXPECT_FALSE(JSONReader().ReadToValue("\"123\xc0\x81\"")); + EXPECT_FALSE(JSONReader().ReadToValue("\"abc\xc0\xae\"")); + } + + { + // Test utf16 encoded strings. + std::unique_ptr<Value> root = JSONReader().ReadToValue("\"\\u20ac3,14\""); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + std::string str_val; + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ( + "\xe2\x82\xac" + "3,14", + str_val); + + root = JSONReader().ReadToValue("\"\\ud83d\\udca9\\ud83d\\udc6c\""); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + str_val.clear(); + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ("\xf0\x9f\x92\xa9\xf0\x9f\x91\xac", str_val); + } + + { + // Test invalid utf16 strings. + const char* const cases[] = { + "\"\\u123\"", // Invalid scalar. + "\"\\ud83d\"", // Invalid scalar. + "\"\\u$%@!\"", // Invalid scalar. + "\"\\uzz89\"", // Invalid scalar. + "\"\\ud83d\\udca\"", // Invalid lower surrogate. + "\"\\ud83d\\ud83d\"", // Invalid lower surrogate. + "\"\\ud83foo\"", // No lower surrogate. + "\"\\ud83\\foo\"" // No lower surrogate. + }; + std::unique_ptr<Value> root; + for (size_t i = 0; i < arraysize(cases); ++i) { + root = JSONReader().ReadToValue(cases[i]); + EXPECT_FALSE(root) << cases[i]; + } + } + + { + // Test literal root objects. + std::unique_ptr<Value> root = JSONReader::Read("null"); + EXPECT_TRUE(root->IsType(Value::TYPE_NULL)); + + root = JSONReader::Read("true"); + ASSERT_TRUE(root); + bool bool_value; + EXPECT_TRUE(root->GetAsBoolean(&bool_value)); + EXPECT_TRUE(bool_value); + + root = JSONReader::Read("10"); + ASSERT_TRUE(root); + int integer_value; + EXPECT_TRUE(root->GetAsInteger(&integer_value)); + EXPECT_EQ(10, integer_value); + + root = JSONReader::Read("\"root\""); + ASSERT_TRUE(root); + std::string str_val; + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ("root", str_val); + } } // Tests that the root of a JSON object can be deleted safely while its @@ -565,25 +589,25 @@ TEST(JSONReaderTest, StringOptimizations) { " ]" "}", JSON_DETACHABLE_CHILDREN); - ASSERT_TRUE(root.get()); + ASSERT_TRUE(root); - DictionaryValue* root_dict = NULL; + DictionaryValue* root_dict = nullptr; ASSERT_TRUE(root->GetAsDictionary(&root_dict)); - DictionaryValue* dict = NULL; - ListValue* list = NULL; + DictionaryValue* dict = nullptr; + ListValue* list = nullptr; ASSERT_TRUE(root_dict->GetDictionary("test", &dict)); ASSERT_TRUE(root_dict->GetList("list", &list)); - EXPECT_TRUE(dict->Remove("foo", &dict_literal_0)); - EXPECT_TRUE(dict->Remove("bar", &dict_literal_1)); - EXPECT_TRUE(dict->Remove("baz", &dict_string_0)); - EXPECT_TRUE(dict->Remove("moo", &dict_string_1)); + ASSERT_TRUE(dict->Remove("foo", &dict_literal_0)); + ASSERT_TRUE(dict->Remove("bar", &dict_literal_1)); + ASSERT_TRUE(dict->Remove("baz", &dict_string_0)); + ASSERT_TRUE(dict->Remove("moo", &dict_string_1)); ASSERT_EQ(2u, list->GetSize()); - EXPECT_TRUE(list->Remove(0, &list_value_0)); - EXPECT_TRUE(list->Remove(0, &list_value_1)); + ASSERT_TRUE(list->Remove(0, &list_value_0)); + ASSERT_TRUE(list->Remove(0, &list_value_1)); } bool b = false; @@ -612,19 +636,14 @@ TEST(JSONReaderTest, StringOptimizations) { // parser implementation against buffer overflow. Best run with DCHECKs so // that the one in NextChar fires. TEST(JSONReaderTest, InvalidSanity) { - const char* const invalid_json[] = { - "/* test *", - "{\"foo\"", - "{\"foo\":", - " [", - "\"\\u123g\"", - "{\n\"eh:\n}", + const char* const kInvalidJson[] = { + "/* test *", "{\"foo\"", "{\"foo\":", " [", "\"\\u123g\"", "{\n\"eh:\n}", }; - for (size_t i = 0; i < arraysize(invalid_json); ++i) { + for (size_t i = 0; i < arraysize(kInvalidJson); ++i) { JSONReader reader; - LOG(INFO) << "Sanity test " << i << ": <" << invalid_json[i] << ">"; - EXPECT_FALSE(reader.ReadToValue(invalid_json[i])); + LOG(INFO) << "Sanity test " << i << ": <" << kInvalidJson[i] << ">"; + EXPECT_FALSE(reader.ReadToValue(kInvalidJson[i])); EXPECT_NE(JSONReader::JSON_NO_ERROR, reader.error_code()); EXPECT_NE("", reader.GetErrorMessage()); } diff --git a/third_party/chromium/base/json/json_writer.cc b/third_party/chromium/base/json/json_writer.cc index be19c93..060bce9 100644 --- a/third_party/chromium/base/json/json_writer.cc +++ b/third_party/chromium/base/json/json_writer.cc @@ -127,9 +127,7 @@ bool JSONWriter::BuildJSONString(const Value& node, size_t depth) { bool first_value_has_been_output = false; bool result = node.GetAsList(&list); DCHECK(result); - for (ListValue::const_iterator it = list->begin(); it != list->end(); - ++it) { - const Value* value = *it; + for (const auto& value : *list) { if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) continue; diff --git a/third_party/chromium/base/json/json_writer_unittest.cc b/third_party/chromium/base/json/json_writer_unittest.cc index 7aaa78b..0e6875f 100644 --- a/third_party/chromium/base/json/json_writer_unittest.cc +++ b/third_party/chromium/base/json/json_writer_unittest.cc @@ -130,14 +130,11 @@ TEST(JSONWriterTest, BinaryValues) { EXPECT_EQ("[5,2]", output_js); DictionaryValue binary_dict; - binary_dict.Set( - "a", WrapUnique(BinaryValue::CreateWithCopiedBuffer("asdf", 4))); + binary_dict.Set("a", BinaryValue::CreateWithCopiedBuffer("asdf", 4)); binary_dict.SetInteger("b", 5); - binary_dict.Set( - "c", WrapUnique(BinaryValue::CreateWithCopiedBuffer("asdf", 4))); + binary_dict.Set("c", BinaryValue::CreateWithCopiedBuffer("asdf", 4)); binary_dict.SetInteger("d", 2); - binary_dict.Set( - "e", WrapUnique(BinaryValue::CreateWithCopiedBuffer("asdf", 4))); + binary_dict.Set("e", BinaryValue::CreateWithCopiedBuffer("asdf", 4)); EXPECT_FALSE(JSONWriter::Write(binary_dict, &output_js)); EXPECT_TRUE(JSONWriter::WriteWithOptions( binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js)); diff --git a/third_party/chromium/base/logging.cc b/third_party/chromium/base/logging.cc index ab97073..100d726 100644 --- a/third_party/chromium/base/logging.cc +++ b/third_party/chromium/base/logging.cc @@ -128,6 +128,10 @@ template std::string* MakeCheckOpString<unsigned int, unsigned long>( template std::string* MakeCheckOpString<std::string, std::string>( const std::string&, const std::string&, const char* name); +void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p) { + (*os) << "nullptr"; +} + LogMessage::LogMessage(const char* file, int line, LogSeverity severity) : severity_(severity), file_(file), line_(line) { Init(file, line); diff --git a/third_party/chromium/base/logging.h b/third_party/chromium/base/logging.h index 1290bfe..3b89853 100644 --- a/third_party/chromium/base/logging.h +++ b/third_party/chromium/base/logging.h @@ -12,9 +12,12 @@ #include <sstream> #include <string> #include <typeinfo> +#include <type_traits> +#include <utility> #include "base/base_export.h" #include "base/macros.h" +#include "base/template_util.h" #include "build/build_config.h" // @@ -421,6 +424,30 @@ class CheckOpResult { #endif +// This formats a value for a failing CHECK_XX statement. Ordinarily, +// it uses the definition for operator<<, with a few special cases below. +template <typename T> +inline typename std::enable_if< + base::internal::SupportsOstreamOperator<const T&>::value, + void>::type +MakeCheckOpValueString(std::ostream* os, const T& v) { + (*os) << v; +} + +// We need overloads for enums that don't support operator<<. +// (i.e. scoped enums where no operator<< overload was declared). +template <typename T> +inline typename std::enable_if< + !base::internal::SupportsOstreamOperator<const T&>::value && + std::is_enum<T>::value, + void>::type +MakeCheckOpValueString(std::ostream* os, const T& v) { + (*os) << static_cast<typename base::underlying_type<T>::type>(v); +} + +// We need an explicit overload for std::nullptr_t. +BASE_EXPORT void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p); + // Build the error message string. This is separate from the "Impl" // function template because it is not performance critical and so can // be out of line, while the "Impl" code should be inline. Caller @@ -428,7 +455,11 @@ class CheckOpResult { template<class t1, class t2> std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) { std::ostringstream ss; - ss << names << " (" << v1 << " vs. " << v2 << ")"; + ss << names << " ("; + MakeCheckOpValueString(&ss, v1); + ss << " vs. "; + MakeCheckOpValueString(&ss, v2); + ss << ")"; std::string* msg = new std::string(ss.str()); return msg; } diff --git a/third_party/chromium/base/logging_unittest.cc b/third_party/chromium/base/logging_unittest.cc index d2c1177..281b311 100644 --- a/third_party/chromium/base/logging_unittest.cc +++ b/third_party/chromium/base/logging_unittest.cc @@ -221,6 +221,23 @@ TEST_F(LoggingTest, Dcheck) { EXPECT_EQ(DCHECK_IS_ON() ? 1 : 0, log_sink_call_count); DCHECK_EQ(0, 1); EXPECT_EQ(DCHECK_IS_ON() ? 2 : 0, log_sink_call_count); + + // Test DCHECK on std::nullptr_t + log_sink_call_count = 0; + const void* p_null = nullptr; + const void* p_not_null = &p_null; + DCHECK_EQ(p_null, nullptr); + DCHECK_EQ(nullptr, p_null); + DCHECK_NE(p_not_null, nullptr); + DCHECK_NE(nullptr, p_not_null); + EXPECT_EQ(0, log_sink_call_count); + + // Test DCHECK on a scoped enum. + enum class Animal { DOG, CAT }; + DCHECK_EQ(Animal::DOG, Animal::DOG); + EXPECT_EQ(0, log_sink_call_count); + DCHECK_EQ(Animal::DOG, Animal::CAT); + EXPECT_EQ(DCHECK_IS_ON() ? 1 : 0, log_sink_call_count); } TEST_F(LoggingTest, DcheckReleaseBehavior) { diff --git a/third_party/chromium/base/macros.h b/third_party/chromium/base/macros.h index 46ee1da..2bbf7e1 100644 --- a/third_party/chromium/base/macros.h +++ b/third_party/chromium/base/macros.h @@ -20,11 +20,11 @@ #define DISALLOW_ASSIGN(TypeName) \ void operator=(const TypeName&) = delete -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for a class +// A macro to disallow the copy constructor and operator= functions. +// This should be used in the private: declarations for a class. #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) + TypeName(const TypeName&) = delete; \ + void operator=(const TypeName&) = delete // A macro to disallow all the implicit constructors, namely the // default constructor, copy constructor and operator= functions. diff --git a/third_party/chromium/base/memory/ref_counted.h b/third_party/chromium/base/memory/ref_counted.h index a480eb0..eed3062 100644 --- a/third_party/chromium/base/memory/ref_counted.h +++ b/third_party/chromium/base/memory/ref_counted.h @@ -95,7 +95,7 @@ class BASE_EXPORT RefCountedThreadSafeBase { // // A base class for reference counted classes. Otherwise, known as a cheap -// knock-off of WebKit's RefCounted<T> class. To use this guy just extend your +// knock-off of WebKit's RefCounted<T> class. To use this, just extend your // class from it like so: // // class MyFoo : public base::RefCounted<MyFoo> { diff --git a/third_party/chromium/base/memory/weak_ptr.cc b/third_party/chromium/base/memory/weak_ptr.cc index 7c9ced0..cd43a01 100644 --- a/third_party/chromium/base/memory/weak_ptr.cc +++ b/third_party/chromium/base/memory/weak_ptr.cc @@ -24,14 +24,16 @@ WeakReference::Flag::~Flag() { WeakReference::WeakReference() { } -WeakReference::WeakReference(const WeakReference& other) = default; - WeakReference::WeakReference(const Flag* flag) : flag_(flag) { } WeakReference::~WeakReference() { } +WeakReference::WeakReference(WeakReference&& other) = default; + +WeakReference::WeakReference(const WeakReference& other) = default; + bool WeakReference::is_valid() const { return flag_.get() && flag_->IsValid(); } WeakReferenceOwner::WeakReferenceOwner() { diff --git a/third_party/chromium/base/memory/weak_ptr.h b/third_party/chromium/base/memory/weak_ptr.h index 2efb024..509b380 100644 --- a/third_party/chromium/base/memory/weak_ptr.h +++ b/third_party/chromium/base/memory/weak_ptr.h @@ -107,10 +107,14 @@ class BASE_EXPORT WeakReference { }; WeakReference(); - WeakReference(const WeakReference& other); explicit WeakReference(const Flag* flag); ~WeakReference(); + WeakReference(WeakReference&& other); + WeakReference(const WeakReference& other); + WeakReference& operator=(WeakReference&& other) = default; + WeakReference& operator=(const WeakReference& other) = default; + bool is_valid() const; private: @@ -143,6 +147,11 @@ class BASE_EXPORT WeakPtrBase { WeakPtrBase(); ~WeakPtrBase(); + WeakPtrBase(const WeakPtrBase& other) = default; + WeakPtrBase(WeakPtrBase&& other) = default; + WeakPtrBase& operator=(const WeakPtrBase& other) = default; + WeakPtrBase& operator=(WeakPtrBase&& other) = default; + protected: explicit WeakPtrBase(const WeakReference& ref); @@ -203,10 +212,13 @@ class WeakPtr : public internal::WeakPtrBase { WeakPtr(std::nullptr_t) : ptr_(nullptr) {} // Allow conversion from U to T provided U "is a" T. Note that this - // is separate from the (implicit) copy constructor. + // is separate from the (implicit) copy and move constructors. template <typename U> WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other), ptr_(other.ptr_) { } + template <typename U> + WeakPtr(WeakPtr<U>&& other) + : WeakPtrBase(std::move(other)), ptr_(other.ptr_) {} T* get() const { return ref_.is_valid() ? ptr_ : nullptr; } @@ -224,36 +236,10 @@ class WeakPtr : public internal::WeakPtrBase { ptr_ = nullptr; } - // Implement "Safe Bool Idiom" - // https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool - // - // Allow WeakPtr<element_type> to be used in boolean expressions such as - // if (weak_ptr_instance) - // But do not become convertible to a real bool (which is dangerous). - // Implementation requires: - // typedef Testable - // operator Testable() const - // operator== - // operator!= - // - // == and != operators must be declared explicitly or dissallowed, as - // otherwise "ptr1 == ptr2" will compile but do the wrong thing (i.e., convert - // to Testable and then do the comparison). - // - // C++11 provides for "explicit operator bool()", however it is currently - // banned due to MSVS2013. https://chromium-cpp.appspot.com/#core-blacklist - private: - typedef T* WeakPtr::*Testable; - - public: - operator Testable() const { return get() ? &WeakPtr::ptr_ : nullptr; } + // Allow conditionals to test validity, e.g. if (weak_ptr) {...}; + explicit operator bool() const { return get() != nullptr; } private: - // Explicitly declare comparison operators as required by the "Safe Bool - // Idiom", but keep them private. - template <class U> bool operator==(WeakPtr<U> const&) const; - template <class U> bool operator!=(WeakPtr<U> const&) const; - friend class internal::SupportsWeakPtrBase; template <typename U> friend class WeakPtr; friend class SupportsWeakPtr<T>; @@ -269,6 +255,24 @@ class WeakPtr : public internal::WeakPtrBase { T* ptr_; }; +// Allow callers to compare WeakPtrs against nullptr to test validity. +template <class T> +bool operator!=(const WeakPtr<T>& weak_ptr, std::nullptr_t) { + return !(weak_ptr == nullptr); +} +template <class T> +bool operator!=(std::nullptr_t, const WeakPtr<T>& weak_ptr) { + return weak_ptr != nullptr; +} +template <class T> +bool operator==(const WeakPtr<T>& weak_ptr, std::nullptr_t) { + return weak_ptr.get() == nullptr; +} +template <class T> +bool operator==(std::nullptr_t, const WeakPtr<T>& weak_ptr) { + return weak_ptr == nullptr; +} + // A class may be composed of a WeakPtrFactory and thereby // control how it exposes weak pointers to itself. This is helpful if you only // need weak pointers within the implementation of a class. This class is also diff --git a/third_party/chromium/base/memory/weak_ptr_unittest.cc b/third_party/chromium/base/memory/weak_ptr_unittest.cc index 982becd..9c5c29b 100644 --- a/third_party/chromium/base/memory/weak_ptr_unittest.cc +++ b/third_party/chromium/base/memory/weak_ptr_unittest.cc @@ -54,6 +54,16 @@ TEST(WeakPtrFactoryTest, Comparison) { EXPECT_EQ(ptr.get(), ptr2.get()); } +TEST(WeakPtrFactoryTest, Move) { + int data; + WeakPtrFactory<int> factory(&data); + WeakPtr<int> ptr = factory.GetWeakPtr(); + WeakPtr<int> ptr2 = factory.GetWeakPtr(); + WeakPtr<int> ptr3 = std::move(ptr2); + EXPECT_NE(ptr.get(), ptr2.get()); + EXPECT_EQ(ptr.get(), ptr3.get()); +} + TEST(WeakPtrFactoryTest, OutOfScope) { WeakPtr<int> ptr; EXPECT_EQ(nullptr, ptr.get()); @@ -159,6 +169,19 @@ TEST(WeakPtrFactoryTest, BooleanTesting) { } } +TEST(WeakPtrFactoryTest, ComparisonToNull) { + int data; + WeakPtrFactory<int> factory(&data); + + WeakPtr<int> ptr_to_an_instance = factory.GetWeakPtr(); + EXPECT_NE(nullptr, ptr_to_an_instance); + EXPECT_NE(ptr_to_an_instance, nullptr); + + WeakPtr<int> null_ptr; + EXPECT_EQ(null_ptr, nullptr); + EXPECT_EQ(nullptr, null_ptr); +} + TEST(WeakPtrTest, InvalidateWeakPtrs) { int data; WeakPtrFactory<int> factory(&data); diff --git a/third_party/chromium/base/observer_list.h b/third_party/chromium/base/observer_list.h index bb76091..0f74367 100644 --- a/third_party/chromium/base/observer_list.h +++ b/third_party/chromium/base/observer_list.h @@ -231,8 +231,8 @@ class ObserverList : public ObserverListBase<ObserverType> { #define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \ do { \ if ((observer_list).might_have_observers()) { \ - base::ObserverListBase<ObserverType>::Iterator it_inside_observer_macro( \ - &observer_list); \ + typename base::ObserverListBase<ObserverType>::Iterator \ + it_inside_observer_macro(&observer_list); \ ObserverType* obs; \ while ((obs = it_inside_observer_macro.GetNext()) != nullptr) \ obs->func; \ diff --git a/third_party/chromium/base/strings/string_number_conversions.h b/third_party/chromium/base/strings/string_number_conversions.h index af0faa6..49bb08b 100644 --- a/third_party/chromium/base/strings/string_number_conversions.h +++ b/third_party/chromium/base/strings/string_number_conversions.h @@ -24,6 +24,14 @@ // Please do not add "convenience" functions for converting strings to integers // that return the value and ignore success/failure. That encourages people to // write code that doesn't properly handle the error conditions. +// +// DO NOT use these functions in any UI unless it's NOT localized on purpose. +// Instead, use base::MessageFormatter for a complex message with numbers +// (integer, float, double) embedded or base::Format{Number,Double,Percent} to +// just format a single number/percent. Note that some languages use native +// digits instead of ASCII digits while others use a group separator or decimal +// point different from ',' and '.'. Using these functions in the UI would lead +// numbers to be formatted in a non-native way. // ---------------------------------------------------------------------------- namespace base { diff --git a/third_party/chromium/base/strings/string_util.h b/third_party/chromium/base/strings/string_util.h index f505bb6..6b87324 100644 --- a/third_party/chromium/base/strings/string_util.h +++ b/third_party/chromium/base/strings/string_util.h @@ -173,6 +173,13 @@ TrimPositions TrimWhitespaceASCII(const std::string& input, bool IsStringUTF8(const StringPiece& str); bool IsStringASCII(const StringPiece& str); +template <typename Char> +inline bool IsHexDigit(Char c) { + return (c >= '0' && c <= '9') || + (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f'); +} + // Reserves enough memory in |str| to accommodate |length_with_null| characters, // sets the size of |str| to |length_with_null - 1| characters, and returns a // pointer to the underlying contiguous array of characters. This is typically diff --git a/third_party/chromium/base/template_util.h b/third_party/chromium/base/template_util.h index 0c3cac2..158daf1 100644 --- a/third_party/chromium/base/template_util.h +++ b/third_party/chromium/base/template_util.h @@ -5,16 +5,66 @@ #ifndef BASE_TEMPLATE_UTIL_H_ #define BASE_TEMPLATE_UTIL_H_ +#include <iosfwd> #include <type_traits> +#include <utility> #include "build/build_config.h" +// This hacks around libstdc++ 4.6 missing stuff in type_traits, while we need +// to support it. +#define CR_GLIBCXX_4_7_0 20120322 +#define CR_GLIBCXX_4_5_4 20120702 +#define CR_GLIBCXX_4_6_4 20121127 +#if defined(__GLIBCXX__) && \ + (__GLIBCXX__ < CR_GLIBCXX_4_7_0 || __GLIBCXX__ == CR_GLIBCXX_4_5_4 || \ + __GLIBCXX__ == CR_GLIBCXX_4_6_4) +#define CR_USE_FALLBACKS_FOR_OLD_GLIBCXX +#endif + namespace base { template <class T> struct is_non_const_reference : std::false_type {}; template <class T> struct is_non_const_reference<T&> : std::true_type {}; template <class T> struct is_non_const_reference<const T&> : std::false_type {}; +namespace internal { +// Uses expression SFINAE to detect whether using operator<< would work. +template <typename T, typename = void> +struct SupportsOstreamOperator : std::false_type {}; +template <typename T> +struct SupportsOstreamOperator<T, + decltype(void(std::declval<std::ostream&>() + << std::declval<T>()))> + : std::true_type {}; + +} // namespace internal + +// underlying_type produces the integer type backing an enum type. +// TODO(crbug.com/554293): Remove this when all platforms have this in the std +// namespace. +#if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX) +template <typename T> +struct underlying_type { + using type = __underlying_type(T); +}; +#else +template <typename T> +using underlying_type = std::underlying_type<T>; +#endif + +// TODO(crbug.com/554293): Remove this when all platforms have this in the std +// namespace. +#if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX) +template <class T> +using is_trivially_destructible = std::has_trivial_destructor<T>; +#else +template <class T> +using is_trivially_destructible = std::is_trivially_destructible<T>; +#endif + } // namespace base +#undef CR_USE_FALLBACKS_FOR_OLD_GLIBCXX + #endif // BASE_TEMPLATE_UTIL_H_ diff --git a/third_party/chromium/base/template_util_unittest.cc b/third_party/chromium/base/template_util_unittest.cc index 25f4ba3..70ba069 100644 --- a/third_party/chromium/base/template_util_unittest.cc +++ b/third_party/chromium/base/template_util_unittest.cc @@ -6,15 +6,91 @@ #include <gtest/gtest.h> +#include <string> namespace base { namespace { +enum SimpleEnum { SIMPLE_ENUM }; +enum EnumWithExplicitType : uint64_t { ENUM_WITH_EXPLICIT_TYPE }; +enum class ScopedEnum { SCOPED_ENUM }; +enum class ScopedEnumWithOperator { SCOPED_ENUM_WITH_OPERATOR }; +std::ostream& operator<<(std::ostream& os, ScopedEnumWithOperator v) { + return os; +} +struct SimpleStruct {}; +struct StructWithOperator {}; +std::ostream& operator<<(std::ostream& os, const StructWithOperator& v) { + return os; +} + // is_non_const_reference<Type> static_assert(!is_non_const_reference<int>::value, "IsNonConstReference"); static_assert(!is_non_const_reference<const int&>::value, "IsNonConstReference"); static_assert(is_non_const_reference<int&>::value, "IsNonConstReference"); +// A few standard types that definitely support printing. +static_assert(internal::SupportsOstreamOperator<int>::value, + "ints should be printable"); +static_assert(internal::SupportsOstreamOperator<const char*>::value, + "C strings should be printable"); +static_assert(internal::SupportsOstreamOperator<std::string>::value, + "std::string should be printable"); + +// Various kinds of enums operator<< support. +static_assert(internal::SupportsOstreamOperator<SimpleEnum>::value, + "simple enum should be printable by value"); +static_assert(internal::SupportsOstreamOperator<const SimpleEnum&>::value, + "simple enum should be printable by const ref"); +static_assert(internal::SupportsOstreamOperator<EnumWithExplicitType>::value, + "enum with explicit type should be printable by value"); +static_assert( + internal::SupportsOstreamOperator<const EnumWithExplicitType&>::value, + "enum with explicit type should be printable by const ref"); +static_assert(!internal::SupportsOstreamOperator<ScopedEnum>::value, + "scoped enum should not be printable by value"); +static_assert(!internal::SupportsOstreamOperator<const ScopedEnum&>::value, + "simple enum should not be printable by const ref"); +static_assert(internal::SupportsOstreamOperator<ScopedEnumWithOperator>::value, + "scoped enum with operator<< should be printable by value"); +static_assert( + internal::SupportsOstreamOperator<const ScopedEnumWithOperator&>::value, + "scoped enum with operator<< should be printable by const ref"); + +// operator<< support on structs. +static_assert(!internal::SupportsOstreamOperator<SimpleStruct>::value, + "simple struct should not be printable by value"); +static_assert(!internal::SupportsOstreamOperator<const SimpleStruct&>::value, + "simple struct should not be printable by const ref"); +static_assert(internal::SupportsOstreamOperator<StructWithOperator>::value, + "struct with operator<< should be printable by value"); +static_assert( + internal::SupportsOstreamOperator<const StructWithOperator&>::value, + "struct with operator<< should be printable by const ref"); + +// underlying type of enums +static_assert(std::is_integral<underlying_type<SimpleEnum>::type>::value, + "simple enum must have some integral type"); +static_assert( + std::is_same<underlying_type<EnumWithExplicitType>::type, uint64_t>::value, + "explicit type must be detected"); +static_assert(std::is_same<underlying_type<ScopedEnum>::type, int>::value, + "scoped enum defaults to int"); + +struct TriviallyDestructible { + int field; +}; + +class NonTriviallyDestructible { + ~NonTriviallyDestructible() {} +}; + +static_assert(is_trivially_destructible<int>::value, "IsTriviallyDestructible"); +static_assert(is_trivially_destructible<TriviallyDestructible>::value, + "IsTriviallyDestructible"); +static_assert(!is_trivially_destructible<NonTriviallyDestructible>::value, + "IsTriviallyDestructible"); + } // namespace } // namespace base diff --git a/third_party/chromium/base/time/time.cc b/third_party/chromium/base/time/time.cc index 0dc892a..dd65628 100644 --- a/third_party/chromium/base/time/time.cc +++ b/third_party/chromium/base/time/time.cc @@ -133,11 +133,6 @@ std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) { // Time ----------------------------------------------------------------------- // static -Time Time::Max() { - return Time(std::numeric_limits<int64_t>::max()); -} - -// static Time Time::FromTimeT(time_t tt) { if (tt == 0) return Time(); // Preserve 0 so we can tell it doesn't exist. @@ -239,6 +234,14 @@ Time Time::LocalMidnight() const { return FromLocalExploded(exploded); } +// static +bool Time::ExplodedMostlyEquals(const Exploded& lhs, const Exploded& rhs) { + return lhs.year == rhs.year && lhs.month == rhs.month && + lhs.day_of_month == rhs.day_of_month && lhs.hour == rhs.hour && + lhs.minute == rhs.minute && lhs.second == rhs.second && + lhs.millisecond == rhs.millisecond; +} + std::ostream& operator<<(std::ostream& os, Time time) { Time::Exploded exploded; time.UTCExplode(&exploded); diff --git a/third_party/chromium/base/time/time.h b/third_party/chromium/base/time/time.h index 9456cc7..974207a 100644 --- a/third_party/chromium/base/time/time.h +++ b/third_party/chromium/base/time/time.h @@ -56,6 +56,7 @@ #include <limits> #include "base/base_export.h" +#include "base/compiler_specific.h" #include "base/numerics/safe_math.h" #include "build/build_config.h" @@ -307,6 +308,12 @@ class TimeBase { // Returns true if this object represents the maximum time. bool is_max() const { return us_ == std::numeric_limits<int64_t>::max(); } + // Returns the maximum time, which should be greater than any reasonable time + // with which we might compare it. + static TimeClass Max() { + return TimeClass(std::numeric_limits<int64_t>::max()); + } + // For serializing only. Use FromInternalValue() to reconstitute. Please don't // use this and do arithmetic on it, as it is more error prone than using the // provided operators. @@ -434,10 +441,6 @@ class BASE_EXPORT Time : public time_internal::TimeBase<Time> { // times are increasing, or that two calls to Now() won't be the same. static Time Now(); - // Returns the maximum time, which should be greater than any reasonable time - // with which we might compare it. - static Time Max(); - // Returns the current time. Same as Now() except that this function always // uses system time so that there are no discrepancies between the returned // time and system time even on virtual environments including our test bot. @@ -515,11 +518,29 @@ class BASE_EXPORT Time : public time_internal::TimeBase<Time> { // Converts an exploded structure representing either the local time or UTC // into a Time class. + // TODO(maksims): Get rid of these in favor of the methods below when + // all the callers stop using these ones. static Time FromUTCExploded(const Exploded& exploded) { - return FromExploded(false, exploded); + base::Time time; + ignore_result(FromUTCExploded(exploded, &time)); + return time; } static Time FromLocalExploded(const Exploded& exploded) { - return FromExploded(true, exploded); + base::Time time; + ignore_result(FromLocalExploded(exploded, &time)); + return time; + } + + // Converts an exploded structure representing either the local time or UTC + // into a Time class. Returns false on a failure when, for example, a day of + // month is set to 31 on a 28-30 day month. + static bool FromUTCExploded(const Exploded& exploded, + Time* time) WARN_UNUSED_RESULT { + return FromExploded(false, exploded, time); + } + static bool FromLocalExploded(const Exploded& exploded, + Time* time) WARN_UNUSED_RESULT { + return FromExploded(true, exploded, time); } // Fills the given exploded structure with either the local time or UTC from @@ -545,8 +566,15 @@ class BASE_EXPORT Time : public time_internal::TimeBase<Time> { void Explode(bool is_local, Exploded* exploded) const; // Unexplodes a given time assuming the source is either local time - // |is_local = true| or UTC |is_local = false|. - static Time FromExploded(bool is_local, const Exploded& exploded); + // |is_local = true| or UTC |is_local = false|. Function returns false on + // failure and sets |time| to Time(0). Otherwise returns true and sets |time| + // to non-exploded time. + static bool FromExploded(bool is_local, + const Exploded& exploded, + Time* time) WARN_UNUSED_RESULT; + + // Comparison does not consider |day_of_week| when doing the operation. + static bool ExplodedMostlyEquals(const Exploded& lhs, const Exploded& rhs); }; // Inline the TimeDelta factory methods, for fast TimeDelta construction. diff --git a/third_party/chromium/base/time/time_posix.cc b/third_party/chromium/base/time/time_posix.cc index 4b37b4a..ba805e0 100644 --- a/third_party/chromium/base/time/time_posix.cc +++ b/third_party/chromium/base/time/time_posix.cc @@ -191,7 +191,7 @@ void Time::Explode(bool is_local, Exploded* exploded) const { } // static -Time Time::FromExploded(bool is_local, const Exploded& exploded) { +bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) { struct tm timestruct; timestruct.tm_sec = exploded.second; timestruct.tm_min = exploded.minute; @@ -281,8 +281,26 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) { } // Adjust from Unix (1970) to Windows (1601) epoch. - return Time((milliseconds * kMicrosecondsPerMillisecond) + - kWindowsEpochDeltaMicroseconds); + base::Time converted_time = + Time((milliseconds * kMicrosecondsPerMillisecond) + + kWindowsEpochDeltaMicroseconds); + + // If |exploded.day_of_month| is set to 31 on a 28-30 day month, it will + // return the first day of the next month. Thus round-trip the time and + // compare the initial |exploded| with |utc_to_exploded| time. + base::Time::Exploded to_exploded; + if (!is_local) + converted_time.UTCExplode(&to_exploded); + else + converted_time.LocalExplode(&to_exploded); + + if (ExplodedMostlyEquals(to_exploded, exploded)) { + *time = converted_time; + return true; + } + + *time = Time(0); + return false; } // TimeTicks ------------------------------------------------------------------ diff --git a/third_party/chromium/base/time/time_unittest.cc b/third_party/chromium/base/time/time_unittest.cc index c471a76..c4c61df 100644 --- a/third_party/chromium/base/time/time_unittest.cc +++ b/third_party/chromium/base/time/time_unittest.cc @@ -21,6 +21,52 @@ namespace base { namespace { +TEST(TimeTestOutOfBounds, FromExplodedOutOfBoundsTime) { + // FromUTCExploded must set time to Time(0) and failure, if the day is set to + // 31 on a 28-30 day month. Test |exploded| returns Time(0) on 31st of + // February and 31st of April. New implementation handles this. + + const struct DateTestData { + Time::Exploded explode; + bool is_valid; + } kDateTestData[] = { + // 31st of February + {{2016, 2, 0, 31, 12, 30, 0, 0}, true}, + // 31st of April + {{2016, 4, 0, 31, 8, 43, 0, 0}, true}, + // Negative month + {{2016, -5, 0, 2, 4, 10, 0, 0}, false}, + // Negative date of month + {{2016, 6, 0, -15, 2, 50, 0, 0}, false}, + // Negative hours + {{2016, 7, 0, 10, -11, 29, 0, 0}, false}, + // Negative minutes + {{2016, 3, 0, 14, 10, -29, 0, 0}, false}, + // Negative seconds + {{2016, 10, 0, 25, 7, 47, -30, 0}, false}, + // Negative milliseconds + {{2016, 10, 0, 25, 7, 47, 20, -500}, false}, + // Hours are too large + {{2016, 7, 0, 10, 26, 29, 0, 0}, false}, + // Minutes are too large + {{2016, 3, 0, 14, 10, 78, 0, 0}, false}, + // Seconds are too large + {{2016, 10, 0, 25, 7, 47, 234, 0}, false}, + // Milliseconds are too large + {{2016, 10, 0, 25, 6, 31, 23, 1643}, false}, + }; + + for (const auto& test : kDateTestData) { + EXPECT_EQ(test.explode.HasValidValues(), test.is_valid); + + base::Time result; + EXPECT_FALSE(base::Time::FromUTCExploded(test.explode, &result)); + EXPECT_TRUE(result.is_null()); + EXPECT_FALSE(base::Time::FromLocalExploded(test.explode, &result)); + EXPECT_TRUE(result.is_null()); + } +} + // Specialized test fixture allowing time strings without timezones to be // tested by comparing them to a known time in the local zone. // See also pr_time_unittests.cc @@ -80,7 +126,8 @@ TEST_F(TimeTest, TimeT) { EXPECT_EQ(tms.tm_sec, exploded.second); // Convert exploded back to the time struct. - Time our_time_2 = Time::FromLocalExploded(exploded); + Time our_time_2; + EXPECT_TRUE(Time::FromLocalExploded(exploded, &our_time_2)); EXPECT_TRUE(our_time_1 == our_time_2); time_t now_t_2 = our_time_2.ToTimeT(); @@ -119,7 +166,8 @@ TEST_F(TimeTest, FromExplodedWithMilliseconds) { Time::Exploded exploded1 = {0}; now.UTCExplode(&exploded1); exploded1.millisecond = 500; - Time time = Time::FromUTCExploded(exploded1); + Time time; + EXPECT_TRUE(Time::FromUTCExploded(exploded1, &time)); Time::Exploded exploded2 = {0}; time.UTCExplode(&exploded2); EXPECT_EQ(exploded1.millisecond, exploded2.millisecond); @@ -137,7 +185,8 @@ TEST_F(TimeTest, LocalExplode) { Time::Exploded exploded; a.LocalExplode(&exploded); - Time b = Time::FromLocalExploded(exploded); + Time b; + EXPECT_TRUE(Time::FromLocalExploded(exploded, &b)); // The exploded structure doesn't have microseconds, and on Mac & Linux, the // internal OS conversion uses seconds, which will cause truncation. So we @@ -150,7 +199,8 @@ TEST_F(TimeTest, UTCExplode) { Time::Exploded exploded; a.UTCExplode(&exploded); - Time b = Time::FromUTCExploded(exploded); + Time b; + EXPECT_TRUE(Time::FromUTCExploded(exploded, &b)); EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1)); } @@ -370,7 +420,8 @@ TEST_F(TimeTest, FromLocalExplodedCrashOnAndroid) { static char buffer[] = "TZ=America/Santiago"; putenv(buffer); tzset(); - Time t = Time::FromLocalExploded(midnight); + Time t; + EXPECT_TRUE(Time::FromLocalExploded(midnight, &t)); EXPECT_EQ(1381633200, t.ToTimeT()); } #endif // OS_ANDROID @@ -532,7 +583,8 @@ TEST(TimeDelta, WindowsEpoch) { exploded.minute = 0; exploded.second = 0; exploded.millisecond = 0; - Time t = Time::FromUTCExploded(exploded); + Time t; + EXPECT_TRUE(Time::FromUTCExploded(exploded, &t)); // Unix 1970 epoch. EXPECT_EQ(11644473600000000ll, t.ToInternalValue()); diff --git a/third_party/chromium/base/tuple.h b/third_party/chromium/base/tuple.h index 78dfd75..3a8b88a 100644 --- a/third_party/chromium/base/tuple.h +++ b/third_party/chromium/base/tuple.h @@ -2,27 +2,24 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// A Tuple is a generic templatized container, similar in concept to std::pair -// and std::tuple. The convenient MakeTuple() function takes any number of -// arguments and will construct and return the appropriate Tuple object. The -// functions DispatchToMethod and DispatchToFunction take a function pointer or -// instance and method pointer, and unpack a tuple into arguments to the call. -// -// Tuple elements are copied by value, and stored in the tuple. See the unit -// tests for more details of how/when the values are copied. +// Use std::tuple as tuple type. This file contains helper functions for +// working with std::tuples. +// The functions DispatchToMethod and DispatchToFunction take a function pointer +// or instance and method pointer, and unpack a tuple into arguments to the +// call. // // Example usage: // // These two methods of creating a Tuple are identical. -// Tuple<int, const char*> tuple_a(1, "wee"); -// Tuple<int, const char*> tuple_b = MakeTuple(1, "wee"); +// std::tuple<int, const char*> tuple_a(1, "wee"); +// std::tuple<int, const char*> tuple_b = std::make_tuple(1, "wee"); // // void SomeFunc(int a, const char* b) { } // DispatchToFunction(&SomeFunc, tuple_a); // SomeFunc(1, "wee") // DispatchToFunction( -// &SomeFunc, MakeTuple(10, "foo")); // SomeFunc(10, "foo") +// &SomeFunc, std::make_tuple(10, "foo")); // SomeFunc(10, "foo") // // struct { void SomeMeth(int a, int b, int c) { } } foo; -// DispatchToMethod(&foo, &Foo::SomeMeth, MakeTuple(1, 2, 3)); +// DispatchToMethod(&foo, &Foo::SomeMeth, std::make_tuple(1, 2, 3)); // // foo->SomeMeth(1, 2, 3); #ifndef BASE_TUPLE_H_ @@ -107,46 +104,23 @@ struct MakeIndexSequenceImpl<N, Ns...> #endif // defined(WIN) && defined(_PREFAST_) -template <size_t N> -using MakeIndexSequence = typename MakeIndexSequenceImpl<N>::Type; - -// Tuple ----------------------------------------------------------------------- -// -// This set of classes is useful for bundling 0 or more heterogeneous data types -// into a single variable. The advantage of this is that it greatly simplifies -// function objects that need to take an arbitrary number of parameters; see -// RunnableMethod and IPC::MessageWithTuple. -// -// Tuple<> is supplied to act as a 'void' type. It can be used, for example, -// when dispatching to a function that accepts no arguments (see the -// Dispatchers below). -// Tuple<A> is rarely useful. One such use is when A is non-const ref that you -// want filled by the dispatchee, and the tuple is merely a container for that -// output (a "tier"). See MakeRefTuple and its usages. - -template <typename... Ts> -using Tuple = std::tuple<Ts...>; - -using std::get; - -// Tuple creators ------------------------------------------------------------- -// -// Helper functions for constructing tuples while inferring the template -// argument types. - -template <typename... Ts> -inline Tuple<Ts...> MakeTuple(const Ts&... arg) { - return Tuple<Ts...>(arg...); +// std::get() in <=libstdc++-4.6 returns an lvalue-reference for +// rvalue-reference of a tuple, where an rvalue-reference is expected. +template <size_t I, typename... Ts> +typename std::tuple_element<I, std::tuple<Ts...>>::type&& get( + std::tuple<Ts...>&& t) { + using ElemType = typename std::tuple_element<I, std::tuple<Ts...>>::type; + return std::forward<ElemType>(std::get<I>(t)); } -// The following set of helpers make what Boost refers to as "Tiers" - a tuple -// of references. - -template <typename... Ts> -inline Tuple<Ts&...> MakeRefTuple(Ts&... arg) { - return Tuple<Ts&...>(arg...); +template <size_t I, typename T> +auto get(T& t) -> decltype(std::get<I>(t)) { + return std::get<I>(t); } +template <size_t N> +using MakeIndexSequence = typename MakeIndexSequenceImpl<N>::Type; + // Dispatchers ---------------------------------------------------------------- // // Helper functions that call the given method on an object, with the unpacked @@ -161,15 +135,15 @@ inline Tuple<Ts&...> MakeRefTuple(Ts&... arg) { template <typename ObjT, typename Method, typename... Ts, size_t... Ns> inline void DispatchToMethodImpl(const ObjT& obj, Method method, - const Tuple<Ts...>& arg, + const std::tuple<Ts...>& arg, IndexSequence<Ns...>) { - (obj->*method)(internal::Unwrap(get<Ns>(arg))...); + (obj->*method)(internal::Unwrap(std::get<Ns>(arg))...); } template <typename ObjT, typename Method, typename... Ts> inline void DispatchToMethod(const ObjT& obj, Method method, - const Tuple<Ts...>& arg) { + const std::tuple<Ts...>& arg) { DispatchToMethodImpl(obj, method, arg, MakeIndexSequence<sizeof...(Ts)>()); } @@ -177,13 +151,14 @@ inline void DispatchToMethod(const ObjT& obj, template <typename Function, typename... Ts, size_t... Ns> inline void DispatchToFunctionImpl(Function function, - const Tuple<Ts...>& arg, + const std::tuple<Ts...>& arg, IndexSequence<Ns...>) { - (*function)(internal::Unwrap(get<Ns>(arg))...); + (*function)(internal::Unwrap(std::get<Ns>(arg))...); } template <typename Function, typename... Ts> -inline void DispatchToFunction(Function function, const Tuple<Ts...>& arg) { +inline void DispatchToFunction(Function function, + const std::tuple<Ts...>& arg) { DispatchToFunctionImpl(function, arg, MakeIndexSequence<sizeof...(Ts)>()); } @@ -197,18 +172,19 @@ template <typename ObjT, size_t... OutNs> inline void DispatchToMethodImpl(const ObjT& obj, Method method, - const Tuple<InTs...>& in, - Tuple<OutTs...>* out, + const std::tuple<InTs...>& in, + std::tuple<OutTs...>* out, IndexSequence<InNs...>, IndexSequence<OutNs...>) { - (obj->*method)(internal::Unwrap(get<InNs>(in))..., &get<OutNs>(*out)...); + (obj->*method)(internal::Unwrap(std::get<InNs>(in))..., + &std::get<OutNs>(*out)...); } template <typename ObjT, typename Method, typename... InTs, typename... OutTs> inline void DispatchToMethod(const ObjT& obj, Method method, - const Tuple<InTs...>& in, - Tuple<OutTs...>* out) { + const std::tuple<InTs...>& in, + std::tuple<OutTs...>* out) { DispatchToMethodImpl(obj, method, in, out, MakeIndexSequence<sizeof...(InTs)>(), MakeIndexSequence<sizeof...(OutTs)>()); diff --git a/third_party/chromium/base/tuple_unittest.cc b/third_party/chromium/base/tuple_unittest.cc index 668c115..65e3396 100644 --- a/third_party/chromium/base/tuple_unittest.cc +++ b/third_party/chromium/base/tuple_unittest.cc @@ -33,51 +33,34 @@ struct Addz { } // namespace TEST(TupleTest, Basic) { - base::Tuple<> t0 = base::MakeTuple(); + std::tuple<> t0 = std::make_tuple(); ALLOW_UNUSED_LOCAL(t0); - base::Tuple<int> t1(1); - base::Tuple<int, const char*> t2 = - base::MakeTuple(1, static_cast<const char*>("wee")); - base::Tuple<int, int, int> t3(1, 2, 3); - base::Tuple<int, int, int, int*> t4(1, 2, 3, &get<0>(t1)); - base::Tuple<int, int, int, int, int*> t5(1, 2, 3, 4, &get<0>(t4)); - base::Tuple<int, int, int, int, int, int*> t6(1, 2, 3, 4, 5, &get<0>(t4)); - - EXPECT_EQ(1, get<0>(t1)); - EXPECT_EQ(1, get<0>(t2)); - EXPECT_EQ(1, get<0>(t3)); - EXPECT_EQ(2, get<1>(t3)); - EXPECT_EQ(3, get<2>(t3)); - EXPECT_EQ(1, get<0>(t4)); - EXPECT_EQ(2, get<1>(t4)); - EXPECT_EQ(3, get<2>(t4)); - EXPECT_EQ(1, get<0>(t5)); - EXPECT_EQ(2, get<1>(t5)); - EXPECT_EQ(3, get<2>(t5)); - EXPECT_EQ(4, get<3>(t5)); - EXPECT_EQ(1, get<0>(t6)); - EXPECT_EQ(2, get<1>(t6)); - EXPECT_EQ(3, get<2>(t6)); - EXPECT_EQ(4, get<3>(t6)); - EXPECT_EQ(5, get<4>(t6)); - - EXPECT_EQ(1, get<0>(t1)); + std::tuple<int> t1(1); + std::tuple<int, const char*> t2 = + std::make_tuple(1, static_cast<const char*>("wee")); + ALLOW_UNUSED_LOCAL(t2); + std::tuple<int, int, int> t3(1, 2, 3); + std::tuple<int, int, int, int*> t4(1, 2, 3, &std::get<0>(t1)); + std::tuple<int, int, int, int, int*> t5(1, 2, 3, 4, &std::get<0>(t4)); + std::tuple<int, int, int, int, int, int*> t6(1, 2, 3, 4, 5, &std::get<0>(t4)); + + EXPECT_EQ(1, std::get<0>(t1)); DispatchToFunction(&DoAdd, t4); - EXPECT_EQ(6, get<0>(t1)); + EXPECT_EQ(6, std::get<0>(t1)); int res = 0; - DispatchToFunction(&DoAdd, base::MakeTuple(9, 8, 7, &res)); + DispatchToFunction(&DoAdd, std::make_tuple(9, 8, 7, &res)); EXPECT_EQ(24, res); Addy addy; - EXPECT_EQ(1, get<0>(t4)); + EXPECT_EQ(1, std::get<0>(t4)); DispatchToMethod(&addy, &Addy::DoAdd, t5); - EXPECT_EQ(10, get<0>(t4)); + EXPECT_EQ(10, std::get<0>(t4)); Addz addz; - EXPECT_EQ(10, get<0>(t4)); + EXPECT_EQ(10, std::get<0>(t4)); DispatchToMethod(&addz, &Addz::DoAdd, t6); - EXPECT_EQ(15, get<0>(t4)); + EXPECT_EQ(15, std::get<0>(t4)); } namespace { @@ -112,8 +95,8 @@ TEST(TupleTest, Copying) { bool res = false; // Creating the tuple should copy the class to store internally in the tuple. - base::Tuple<CopyLogger, CopyLogger*, bool*> tuple(logger, &logger, &res); - get<1>(tuple) = &get<0>(tuple); + std::tuple<CopyLogger, CopyLogger*, bool*> tuple(logger, &logger, &res); + std::get<1>(tuple) = &std::get<0>(tuple); EXPECT_EQ(2, CopyLogger::TimesConstructed); EXPECT_EQ(1, CopyLogger::TimesCopied); @@ -132,4 +115,30 @@ TEST(TupleTest, Copying) { EXPECT_EQ(2, CopyLogger::TimesCopied); } +TEST(TupleTest, Get) { + int i = 1; + int j = 2; + std::tuple<int, int&, int&&> t(3, i, std::move(j)); + EXPECT_TRUE((std::is_same<int&, decltype(base::get<0>(t))>::value)); + EXPECT_EQ(3, base::get<0>(t)); + + EXPECT_TRUE((std::is_same<int&, decltype(base::get<1>(t))>::value)); + EXPECT_EQ(1, base::get<1>(t)); + + EXPECT_TRUE((std::is_same<int&, decltype(base::get<2>(t))>::value)); + EXPECT_EQ(2, base::get<2>(t)); + + EXPECT_TRUE((std::is_same<int&&, + decltype(base::get<0>(std::move(t)))>::value)); + EXPECT_EQ(3, base::get<0>(std::move(t))); + + EXPECT_TRUE((std::is_same<int&, + decltype(base::get<1>(std::move(t)))>::value)); + EXPECT_EQ(1, base::get<1>(std::move(t))); + + EXPECT_TRUE((std::is_same<int&&, + decltype(base::get<2>(std::move(t)))>::value)); + EXPECT_EQ(2, base::get<2>(std::move(t))); +} + } // namespace base diff --git a/third_party/chromium/base/values.cc b/third_party/chromium/base/values.cc index 4af9919..89c4e33 100644 --- a/third_party/chromium/base/values.cc +++ b/third_party/chromium/base/values.cc @@ -14,7 +14,6 @@ #include "base/json/json_writer.h" #include "base/logging.h" #include "base/memory/ptr_util.h" -#include "base/move.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversion_utils.h" @@ -29,8 +28,8 @@ std::unique_ptr<Value> CopyWithoutEmptyChildren(const Value& node); // expects |node| to always be non-NULL. std::unique_ptr<ListValue> CopyListWithoutEmptyChildren(const ListValue& list) { std::unique_ptr<ListValue> copy; - for (ListValue::const_iterator it = list.begin(); it != list.end(); ++it) { - std::unique_ptr<Value> child_copy = CopyWithoutEmptyChildren(**it); + for (const auto& entry : list) { + std::unique_ptr<Value> child_copy = CopyWithoutEmptyChildren(*entry); if (child_copy) { if (!copy) copy.reset(new ListValue); @@ -68,22 +67,6 @@ std::unique_ptr<Value> CopyWithoutEmptyChildren(const Value& node) { } } -// A small functor for comparing Values for std::find_if and similar. -class ValueEquals { - public: - // Pass the value against which all consecutive calls of the () operator will - // compare their argument to. This Value object must not be destroyed while - // the ValueEquals is in use. - explicit ValueEquals(const Value* first) : first_(first) { } - - bool operator ()(const Value* second) const { - return first_->Equals(second); - } - - private: - const Value* first_; -}; - } // namespace Value::~Value() { @@ -306,12 +289,12 @@ BinaryValue::~BinaryValue() { } // static -BinaryValue* BinaryValue::CreateWithCopiedBuffer(const char* buffer, - size_t size) { - char* buffer_copy = new char[size]; - memcpy(buffer_copy, buffer, size); - std::unique_ptr<char[]> scoped_buffer_copy(buffer_copy); - return new BinaryValue(std::move(scoped_buffer_copy), size); +std::unique_ptr<BinaryValue> BinaryValue::CreateWithCopiedBuffer( + const char* buffer, + size_t size) { + std::unique_ptr<char[]> buffer_copy(new char[size]); + memcpy(buffer_copy.get(), buffer, size); + return base::MakeUnique<BinaryValue>(std::move(buffer_copy), size); } bool BinaryValue::GetAsBinary(const BinaryValue** out_value) const { @@ -321,7 +304,7 @@ bool BinaryValue::GetAsBinary(const BinaryValue** out_value) const { } BinaryValue* BinaryValue::DeepCopy() const { - return CreateWithCopiedBuffer(buffer_.get(), size_); + return CreateWithCopiedBuffer(buffer_.get(), size_).release(); } bool BinaryValue::Equals(const Value* other) const { @@ -368,18 +351,12 @@ bool DictionaryValue::GetAsDictionary(const DictionaryValue** out_value) const { bool DictionaryValue::HasKey(const std::string& key) const { DCHECK(IsStringUTF8(key)); - ValueMap::const_iterator current_entry = dictionary_.find(key); + auto current_entry = dictionary_.find(key); DCHECK((current_entry == dictionary_.end()) || current_entry->second); return current_entry != dictionary_.end(); } void DictionaryValue::Clear() { - ValueMap::iterator dict_iterator = dictionary_.begin(); - while (dict_iterator != dictionary_.end()) { - delete dict_iterator->second; - ++dict_iterator; - } - dictionary_.clear(); } @@ -432,16 +409,7 @@ void DictionaryValue::SetString(const std::string& path, void DictionaryValue::SetWithoutPathExpansion(const std::string& key, std::unique_ptr<Value> in_value) { - Value* bare_ptr = in_value.release(); - // If there's an existing value here, we need to delete it, because - // we own all our children. - std::pair<ValueMap::iterator, bool> ins_res = - dictionary_.insert(std::make_pair(key, bare_ptr)); - if (!ins_res.second) { - DCHECK_NE(ins_res.first->second, bare_ptr); // This would be bogus - delete ins_res.first->second; - ins_res.first->second = bare_ptr; - } + dictionary_[key] = std::move(in_value); } void DictionaryValue::SetWithoutPathExpansion(const std::string& key, @@ -611,13 +579,12 @@ bool DictionaryValue::GetList(const std::string& path, ListValue** out_value) { bool DictionaryValue::GetWithoutPathExpansion(const std::string& key, const Value** out_value) const { DCHECK(IsStringUTF8(key)); - ValueMap::const_iterator entry_iterator = dictionary_.find(key); + auto entry_iterator = dictionary_.find(key); if (entry_iterator == dictionary_.end()) return false; - const Value* entry = entry_iterator->second; if (out_value) - *out_value = entry; + *out_value = entry_iterator->second.get(); return true; } @@ -732,15 +699,12 @@ bool DictionaryValue::RemoveWithoutPathExpansion( const std::string& key, std::unique_ptr<Value>* out_value) { DCHECK(IsStringUTF8(key)); - ValueMap::iterator entry_iterator = dictionary_.find(key); + auto entry_iterator = dictionary_.find(key); if (entry_iterator == dictionary_.end()) return false; - Value* entry = entry_iterator->second; if (out_value) - out_value->reset(entry); - else - delete entry; + *out_value = std::move(entry_iterator->second); dictionary_.erase(entry_iterator); return true; } @@ -806,10 +770,9 @@ DictionaryValue::Iterator::~Iterator() {} DictionaryValue* DictionaryValue::DeepCopy() const { DictionaryValue* result = new DictionaryValue; - for (ValueMap::const_iterator current_entry(dictionary_.begin()); - current_entry != dictionary_.end(); ++current_entry) { - result->SetWithoutPathExpansion(current_entry->first, - current_entry->second->DeepCopy()); + for (const auto& current_entry : dictionary_) { + result->SetWithoutPathExpansion(current_entry.first, + current_entry.second->CreateDeepCopy()); } return result; @@ -861,12 +824,14 @@ ListValue::~ListValue() { } void ListValue::Clear() { - for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i) - delete *i; list_.clear(); } bool ListValue::Set(size_t index, Value* in_value) { + return Set(index, WrapUnique(in_value)); +} + +bool ListValue::Set(size_t index, std::unique_ptr<Value> in_value) { if (!in_value) return false; @@ -874,25 +839,21 @@ bool ListValue::Set(size_t index, Value* in_value) { // Pad out any intermediate indexes with null settings while (index > list_.size()) Append(CreateNullValue()); - Append(in_value); + Append(std::move(in_value)); } else { + // TODO(dcheng): remove this DCHECK once the raw pointer version is removed? DCHECK(list_[index] != in_value); - delete list_[index]; - list_[index] = in_value; + list_[index] = std::move(in_value); } return true; } -bool ListValue::Set(size_t index, std::unique_ptr<Value> in_value) { - return Set(index, in_value.release()); -} - bool ListValue::Get(size_t index, const Value** out_value) const { if (index >= list_.size()) return false; if (out_value) - *out_value = list_[index]; + *out_value = list_[index].get(); return true; } @@ -995,20 +956,17 @@ bool ListValue::Remove(size_t index, std::unique_ptr<Value>* out_value) { return false; if (out_value) - out_value->reset(list_[index]); - else - delete list_[index]; + *out_value = std::move(list_[index]); list_.erase(list_.begin() + index); return true; } bool ListValue::Remove(const Value& value, size_t* index) { - for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i) { - if ((*i)->Equals(&value)) { - size_t previous_index = i - list_.begin(); - delete *i; - list_.erase(i); + for (auto it = list_.begin(); it != list_.end(); ++it) { + if ((*it)->Equals(&value)) { + size_t previous_index = it - list_.begin(); + list_.erase(it); if (index) *index = previous_index; @@ -1021,20 +979,18 @@ bool ListValue::Remove(const Value& value, size_t* index) { ListValue::iterator ListValue::Erase(iterator iter, std::unique_ptr<Value>* out_value) { if (out_value) - out_value->reset(*iter); - else - delete *iter; + *out_value = std::move(*Storage::iterator(iter)); return list_.erase(iter); } void ListValue::Append(std::unique_ptr<Value> in_value) { - Append(in_value.release()); + list_.push_back(std::move(in_value)); } void ListValue::Append(Value* in_value) { DCHECK(in_value); - list_.push_back(in_value); + Append(WrapUnique(in_value)); } void ListValue::AppendBoolean(bool in_value) { @@ -1062,13 +1018,13 @@ void ListValue::AppendStrings(const std::vector<std::string>& in_values) { bool ListValue::AppendIfNotPresent(Value* in_value) { DCHECK(in_value); - for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i) { - if ((*i)->Equals(in_value)) { + for (const auto& entry : list_) { + if (entry->Equals(in_value)) { delete in_value; return false; } } - list_.push_back(in_value); + list_.emplace_back(in_value); return true; } @@ -1077,12 +1033,15 @@ bool ListValue::Insert(size_t index, Value* in_value) { if (index > list_.size()) return false; - list_.insert(list_.begin() + index, in_value); + list_.insert(list_.begin() + index, WrapUnique(in_value)); return true; } ListValue::const_iterator ListValue::Find(const Value& value) const { - return std::find_if(list_.begin(), list_.end(), ValueEquals(&value)); + return std::find_if(list_.begin(), list_.end(), + [&value](const std::unique_ptr<Value>& entry) { + return entry->Equals(&value); + }); } void ListValue::Swap(ListValue* other) { @@ -1104,8 +1063,8 @@ bool ListValue::GetAsList(const ListValue** out_value) const { ListValue* ListValue::DeepCopy() const { ListValue* result = new ListValue; - for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i) - result->Append((*i)->DeepCopy()); + for (const auto& entry : list_) + result->Append(entry->CreateDeepCopy()); return result; } @@ -1120,11 +1079,11 @@ bool ListValue::Equals(const Value* other) const { const ListValue* other_list = static_cast<const ListValue*>(other); - const_iterator lhs_it, rhs_it; + Storage::const_iterator lhs_it, rhs_it; for (lhs_it = begin(), rhs_it = other_list->begin(); lhs_it != end() && rhs_it != other_list->end(); ++lhs_it, ++rhs_it) { - if (!(*lhs_it)->Equals(*rhs_it)) + if (!(*lhs_it)->Equals(rhs_it->get())) return false; } if (lhs_it != end() || rhs_it != other_list->end()) diff --git a/third_party/chromium/base/values.h b/third_party/chromium/base/values.h index fca5239..d5c43ef 100644 --- a/third_party/chromium/base/values.h +++ b/third_party/chromium/base/values.h @@ -41,9 +41,6 @@ class ListValue; class StringValue; class Value; -typedef std::vector<Value*> ValueVector; -typedef std::map<std::string, Value*> ValueMap; - // The Value class is the base class for Values. A Value can be instantiated // via the Create*Value() factory methods, or by directly creating instances of // the subclasses. @@ -179,7 +176,8 @@ class BASE_EXPORT BinaryValue : public Value { // For situations where you want to keep ownership of your buffer, this // factory method creates a new BinaryValue by copying the contents of the // buffer that's passed in. - static BinaryValue* CreateWithCopiedBuffer(const char* buffer, size_t size); + static std::unique_ptr<BinaryValue> CreateWithCopiedBuffer(const char* buffer, + size_t size); size_t GetSize() const { return size_; } @@ -204,6 +202,7 @@ class BASE_EXPORT BinaryValue : public Value { // are |std::string|s and should be UTF-8 encoded. class BASE_EXPORT DictionaryValue : public Value { public: + using Storage = std::map<std::string, std::unique_ptr<Value>>; // Returns |value| if it is a dictionary, nullptr otherwise. static std::unique_ptr<DictionaryValue> From(std::unique_ptr<Value> value); @@ -360,7 +359,7 @@ class BASE_EXPORT DictionaryValue : public Value { private: const DictionaryValue& target_; - ValueMap::const_iterator it_; + Storage::const_iterator it_; }; // Overridden from Value: @@ -370,7 +369,7 @@ class BASE_EXPORT DictionaryValue : public Value { bool Equals(const Value* other) const override; private: - ValueMap dictionary_; + Storage dictionary_; DISALLOW_COPY_AND_ASSIGN(DictionaryValue); }; @@ -378,8 +377,9 @@ class BASE_EXPORT DictionaryValue : public Value { // This type of Value represents a list of other Value values. class BASE_EXPORT ListValue : public Value { public: - typedef ValueVector::iterator iterator; - typedef ValueVector::const_iterator const_iterator; + using Storage = std::vector<std::unique_ptr<Value>>; + using const_iterator = Storage::const_iterator; + using iterator = Storage::iterator; // Returns |value| if it is a list, nullptr otherwise. static std::unique_ptr<ListValue> From(std::unique_ptr<Value> value); @@ -493,7 +493,7 @@ class BASE_EXPORT ListValue : public Value { std::unique_ptr<ListValue> CreateDeepCopy() const; private: - ValueVector list_; + Storage list_; DISALLOW_COPY_AND_ASSIGN(ListValue); }; diff --git a/third_party/chromium/base/values_unittest.cc b/third_party/chromium/base/values_unittest.cc index 5e49446..bc5424e 100644 --- a/third_party/chromium/base/values_unittest.cc +++ b/third_party/chromium/base/values_unittest.cc @@ -127,7 +127,7 @@ TEST(ValuesTest, BinaryValue) { char stack_buffer[42]; memset(stack_buffer, '!', 42); - binary.reset(BinaryValue::CreateWithCopiedBuffer(stack_buffer, 42)); + binary = BinaryValue::CreateWithCopiedBuffer(stack_buffer, 42); ASSERT_TRUE(binary.get()); ASSERT_TRUE(binary->GetBuffer()); ASSERT_NE(stack_buffer, binary->GetBuffer()); |