From 17f710e0eccdb78996c6e3ee65b03d43c18e1d8b Mon Sep 17 00:00:00 2001 From: Luis Hector Chavez Date: Mon, 18 Jul 2016 16:08:56 -0700 Subject: libweave: Update libchrome APIs to r405848 The new libchrome has been ported from Chromium and some APIs have changed. Make necessary changes at call sites. Notable changes are: - base::Bind() now explicitly disallows captures in lambdas (which was never allowed in the style guide). - base::ListValue::iterator now exposes std::unique_ptr instead of raw base::Value*. BUG=29104761 TEST=All tests in libweave_test pass on dragonboard-eng build TEST=make testall Change-Id: Ifb2d4f83f9f92b8ded5f12ac1c622e8ab5549b7d Reviewed-on: https://weave-review.googlesource.com/4185 Reviewed-by: Robert Ginda --- file_lists.mk | 2 +- src/access_revocation_manager_impl_unittest.cc | 9 +- src/commands/command_queue_unittest.cc | 11 +- src/component_manager_impl.cc | 6 +- src/component_manager_unittest.cc | 68 +- src/device_registration_info.cc | 4 +- src/device_registration_info_unittest.cc | 85 +- .../xmpp_iq_stanza_handler_unittest.cc | 7 +- src/privet/privet_handler.cc | 2 +- src/streams_unittest.cc | 11 +- src/weave_unittest.cc | 40 +- third_party/chromium/base/bind.h | 91 +- third_party/chromium/base/bind_helpers.h | 268 ++--- third_party/chromium/base/bind_internal.h | 615 +++++------ third_party/chromium/base/bind_unittest.cc | 71 +- third_party/chromium/base/callback.h | 25 +- third_party/chromium/base/callback_helpers.h | 61 ++ third_party/chromium/base/callback_internal.h | 1 + third_party/chromium/base/callback_unittest.cc | 63 +- third_party/chromium/base/guid.cc | 79 ++ third_party/chromium/base/guid.h | 23 +- third_party/chromium/base/guid_posix.cc | 44 - third_party/chromium/base/guid_unittest.cc | 31 - third_party/chromium/base/json/json_parser.cc | 122 +-- .../chromium/base/json/json_reader_unittest.cc | 1087 ++++++++++---------- third_party/chromium/base/json/json_writer.cc | 4 +- .../chromium/base/json/json_writer_unittest.cc | 9 +- third_party/chromium/base/logging.cc | 4 + third_party/chromium/base/logging.h | 33 +- third_party/chromium/base/logging_unittest.cc | 17 + third_party/chromium/base/macros.h | 8 +- third_party/chromium/base/memory/ref_counted.h | 2 +- third_party/chromium/base/memory/weak_ptr.cc | 6 +- third_party/chromium/base/memory/weak_ptr.h | 64 +- .../chromium/base/memory/weak_ptr_unittest.cc | 23 + third_party/chromium/base/observer_list.h | 4 +- .../base/strings/string_number_conversions.h | 8 + third_party/chromium/base/strings/string_util.h | 7 + third_party/chromium/base/template_util.h | 50 + .../chromium/base/template_util_unittest.cc | 76 ++ third_party/chromium/base/time/time.cc | 13 +- third_party/chromium/base/time/time.h | 44 +- third_party/chromium/base/time/time_posix.cc | 24 +- third_party/chromium/base/time/time_unittest.cc | 64 +- third_party/chromium/base/tuple.h | 94 +- third_party/chromium/base/tuple_unittest.cc | 81 +- third_party/chromium/base/values.cc | 133 +-- third_party/chromium/base/values.h | 18 +- third_party/chromium/base/values_unittest.cc | 2 +- 49 files changed, 1922 insertions(+), 1692 deletions(-) create mode 100644 third_party/chromium/base/callback_helpers.h create mode 100644 third_party/chromium/base/guid.cc delete mode 100644 third_party/chromium/base/guid_posix.cc 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 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) { - 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) { + 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) { - count++; - }; + auto handler = [](int* count, int tag, + const std::weak_ptr& 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 updates1; - auto callback1 = [&updates1](ComponentManager::UpdateID id) { - updates1.push_back(id); + auto callback = [](std::vector* 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 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", "", "", "", {}, - base::Bind(on_timeout)); + iq_stanza_handler_.SendRequest( + "set", "", "", "", {}, + 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* 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 @@ -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 -struct MakeUnboundRunTypeImpl { - using Type = - typename BindState< - typename FunctorTraits::RunnableType, - typename FunctorTraits::RunType, - Args...>::UnboundRunType; -}; - -} // namespace internal - template -using MakeUnboundRunType = - typename internal::MakeUnboundRunTypeImpl::Type; - -template -base::Callback> -Bind(Functor functor, Args&&... args) { - // Type aliases for how to store and run the functor. - using RunnableType = typename internal::FunctorTraits::RunnableType; - using RunType = typename internal::FunctorTraits::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>; - - // 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::value, - "do not bind functions with nonconst ref"); - - const bool is_method = internal::HasIsMethodTag::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::value, - "first bound argument to method cannot be array"); - static_assert( - !internal::HasRefCountedParamAsRawPtr::value, - "a parameter is a refcounted type and needs scoped_refptr"); - - using BindState = internal::BindState; - - return Callback( - new BindState(internal::MakeRunnable(functor), - std::forward(args)...)); +inline base::Callback> Bind( + Functor&& functor, + Args&&... args) { + using BindState = internal::MakeBindStateType; + using UnboundRunType = MakeUnboundRunType; + using Invoker = internal::Invoker; + + using CallbackType = Callback; + return CallbackType(new BindState(std::forward(functor), + std::forward(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 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 arg) { } -// scoped_ptr CreateFoo() { return scoped_ptr(new Foo()); } +// void TakesOwnership(std::unique_ptr arg) { } +// std::unique_ptr CreateFoo() { return std::unique_ptr(new Foo()); +// } // -// scoped_ptr f(new Foo()); +// std::unique_ptr 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 -#include -#include #include #include -#include #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 -// Yes NotTheCheckWeWant(Helper<&C::TargetFunc>*); -// -// template -// No NotTheCheckWeWant(...); -// -// static const bool value = sizeof(NotTheCheckWeWant(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 -// No GoodCheck(Helper<&C::TargetFunc>*); -// -// template -// Yes GoodCheck(...); -// -// static const bool value = sizeof(GoodCheck(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(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 -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 struct Helper {}; - - template - static No& Check(Helper<&C::AddRef>*); - - template - static Yes& Check(...); - - public: - enum { value = sizeof(Check(0)) == sizeof(Yes) }; -}; - -// Helpers to assert that arguments of a recounted type are bound with a -// scoped_refptr. -template -struct UnsafeBindtoRefCountedArgHelper : std::false_type { -}; - -template -struct UnsafeBindtoRefCountedArgHelper - : std::integral_constant::value> { -}; - -template -struct UnsafeBindtoRefCountedArg : std::false_type { -}; - -template -struct UnsafeBindtoRefCountedArg - : UnsafeBindtoRefCountedArgHelper::value, T> { -}; template -class HasIsMethodTag { - using Yes = char[1]; - using No = char[2]; - - template - static Yes& Check(typename U::IsMethod*); +struct IsWeakReceiver; - template - static No& Check(...); - - public: - enum { value = sizeof(Check(0)) == sizeof(Yes) }; -}; +namespace internal { template class UnretainedWrapper { @@ -315,22 +195,26 @@ class ConstRefWrapper { }; template -struct IgnoreResultHelper { - explicit IgnoreResultHelper(T functor) : functor_(functor) {} - - T functor_; +class RetainedRefWrapper { + public: + explicit RetainedRefWrapper(T* o) : ptr_(o) {} + explicit RetainedRefWrapper(scoped_refptr o) : ptr_(std::move(o)) {} + T* get() const { return ptr_.get(); } + private: + scoped_refptr ptr_; }; template -struct IgnoreResultHelper > { - explicit IgnoreResultHelper(const Callback& functor) : functor_(functor) {} +struct IgnoreResultHelper { + explicit IgnoreResultHelper(T functor) : functor_(std::move(functor)) {} + explicit operator bool() const { return !!functor_; } - const Callback& 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 -const T& Unwrap(const T& o) { - return o; +T&& Unwrap(T&& o) { + return std::forward(o); } template -T* Unwrap(UnretainedWrapper unretained) { +T* Unwrap(const UnretainedWrapper& unretained) { return unretained.get(); } template -const T& Unwrap(ConstRefWrapper const_ref) { +const T& Unwrap(const ConstRefWrapper& const_ref) { return const_ref.get(); } template -T* Unwrap(const scoped_refptr& o) { +T* Unwrap(const RetainedRefWrapper& o) { return o.get(); } -template -const WeakPtr& Unwrap(const WeakPtr& o) { - return o; -} - template T* Unwrap(const OwnedWrapper& o) { return o.get(); } template -T Unwrap(PassedWrapper& o) { +T Unwrap(const PassedWrapper& o) { return o.Take(); } @@ -434,16 +313,11 @@ T Unwrap(PassedWrapper& o) { // // The first argument should be the type of the object that will be received by // the method. -template -struct IsWeakMethod : public std::false_type {}; +template +struct IsWeakMethod : std::false_type {}; template -struct IsWeakMethod, Args...> : public std::true_type {}; - -template -struct IsWeakMethod>, Args...> - : public std::true_type {}; - +struct IsWeakMethod : IsWeakReceiver {}; // Packs a list of types to hold them in a single type. template @@ -526,19 +400,25 @@ struct MakeFunctionTypeImpl> { template using MakeFunctionType = typename MakeFunctionTypeImpl::Type; -// Used for ExtractArgs. +// Used for ExtractArgs and ExtractReturnType. template struct ExtractArgsImpl; template struct ExtractArgsImpl { - using Type = TypeList; + using ReturnType = R; + using ArgsList = TypeList; }; // A type-level function that extracts function arguments into a TypeList. // E.g. ExtractArgs is evaluated to TypeList. template -using ExtractArgs = typename ExtractArgsImpl::Type; +using ExtractArgs = typename ExtractArgsImpl::ArgsList; + +// A type-level function that extracts the return type of a function. +// E.g. ExtractReturnType is evaluated to R. +template +using ExtractReturnType = typename ExtractArgsImpl::ReturnType; } // namespace internal @@ -547,6 +427,16 @@ static inline internal::UnretainedWrapper Unretained(T* o) { return internal::UnretainedWrapper(o); } +template +static inline internal::RetainedRefWrapper RetainedRef(T* o) { + return internal::RetainedRefWrapper(o); +} + +template +static inline internal::RetainedRefWrapper RetainedRef(scoped_refptr o) { + return internal::RetainedRefWrapper(std::move(o)); +} + template static inline internal::ConstRefWrapper ConstRef(const T& o) { return internal::ConstRefWrapper(o); @@ -577,22 +467,36 @@ static inline internal::PassedWrapper Passed(T* scoper) { template static inline internal::IgnoreResultHelper IgnoreResult(T data) { - return internal::IgnoreResultHelper(data); + return internal::IgnoreResultHelper(std::move(data)); } -template -static inline internal::IgnoreResultHelper > -IgnoreResult(const Callback& data) { - return internal::IgnoreResultHelper >(data); -} - -void DoNothing(); +BASE_EXPORT void DoNothing(); template 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 { +// void bar() {} +// }; +// +// WeakPtr oo = nullptr; +// base::Bind(&Foo::bar, oo).Run(); +template +struct IsWeakReceiver : std::false_type {}; + +template +struct IsWeakReceiver> : IsWeakReceiver {}; + +template +struct IsWeakReceiver> : 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 +#include #include #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 -struct HasNonConstReferenceItem : std::false_type {}; +template +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 -struct HasNonConstReferenceItem> - : std::conditional::value, - std::true_type, - HasNonConstReferenceItem>>::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 +using void_t = typename make_void::type; + +template +struct ExtractCallableRunTypeImpl; + +template +struct ExtractCallableRunTypeImpl { + using Type = R(Args...); +}; + +// Evaluated to RunType of the given callable type. +// Example: +// auto f = [](int, char*) { return 0.1; }; +// ExtractCallableRunType +// is evaluated to +// double(int, char*); +template +using ExtractCallableRunType = + typename ExtractCallableRunTypeImpl::Type; + +// IsConvertibleToRunType is std::true_type if |Functor| has operator() +// and convertible to the corresponding function pointer. Otherwise, it's +// std::false_type. +// Example: +// IsConvertibleToRunType::value is false. +// +// struct Foo {}; +// IsConvertibleToRunType::value is false. +// +// auto f = []() {}; +// IsConvertibleToRunType::value is true. +// +// int i = 0; +// auto g = [i]() {}; +// IsConvertibleToRunType::value is false. +template +struct IsConvertibleToRunType : std::false_type {}; + +template +struct IsConvertibleToRunType> + : std::is_convertible*> {}; // HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw // pointer to a RefCounted type. @@ -95,344 +116,338 @@ struct HasRefCountedTypeAsRawPtr std::true_type, HasRefCountedTypeAsRawPtr>::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 -struct BindsArrayToFirstArg : std::false_type {}; - -template -struct BindsArrayToFirstArg - : std::is_array::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 -struct HasRefCountedParamAsRawPtr : HasRefCountedTypeAsRawPtr {}; +// ForceVoidReturn<> +// +// Set of templates that support forcing the function return type to void. +template +struct ForceVoidReturn; -template -struct HasRefCountedParamAsRawPtr - : HasRefCountedTypeAsRawPtr {}; +template +struct ForceVoidReturn { + 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 +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 -class RunnableAdapter; - -// Function. -template -class RunnableAdapter { - 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::value>::type> { + using RunType = ExtractCallableRunType; + static constexpr bool is_method = false; + static constexpr bool is_nullable = false; template - R Run(RunArgs&&... args) { - return function_(std::forward(args)...); + static ExtractReturnType + Invoke(const Functor& functor, RunArgs&&... args) { + return functor(std::forward(args)...); } - - private: - R (*function_)(Args...); }; -// Method. -template -class RunnableAdapter { - 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 +struct FunctorTraits { + using RunType = R(Args...); + static constexpr bool is_method = false; + static constexpr bool is_nullable = true; template - R Run(T* object, RunArgs&&... args) { - return (object->*method_)(std::forward(args)...); + static R Invoke(R (*function)(Args...), RunArgs&&... args) { + return function(std::forward(args)...); } - - private: - R (T::*method_)(Args...); }; -// Const Method. -template -class RunnableAdapter { - 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 +struct FunctorTraits { + using RunType = R(Args...); + static constexpr bool is_method = false; + static constexpr bool is_nullable = true; template - R Run(const T* object, RunArgs&&... args) { - return (object->*method_)(std::forward(args)...); + static R Invoke(R(__stdcall* function)(Args...), RunArgs&&... args) { + return function(std::forward(args)...); } - - private: - R (T::*method_)(Args...) const; }; - -// ForceVoidReturn<> -// -// Set of templates that support forcing the function return type to void. -template -struct ForceVoidReturn; - +// For functions. template -struct ForceVoidReturn { - // 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 { + using RunType = R(Args...); + static constexpr bool is_method = false; + static constexpr bool is_nullable = true; - -// FunctorTraits<> -// -// See description at top of file. -template -struct FunctorTraits { - using RunnableType = RunnableAdapter; - using RunType = typename RunnableType::RunType; + template + static R Invoke(R(__fastcall* function)(Args...), RunArgs&&... args) { + return function(std::forward(args)...); + } }; -template -struct FunctorTraits> { - using RunnableType = typename FunctorTraits::RunnableType; - using RunType = - typename ForceVoidReturn::RunType; +#endif // defined(OS_WIN) && !defined(ARCH_CPU_X86_64) + +// For methods. +template +struct FunctorTraits { + using RunType = R(Receiver*, Args...); + static constexpr bool is_method = true; + static constexpr bool is_nullable = true; + + template + 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(args)...); + } }; -template -struct FunctorTraits> { - using RunnableType = Callback ; - using RunType = typename Callback::RunType; +// For const methods. +template +struct FunctorTraits { + using RunType = R(const Receiver*, Args...); + static constexpr bool is_method = true; + static constexpr bool is_nullable = true; + + template + 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(args)...); + } }; - -// MakeRunnable<> -// -// Converts a passed in functor to a RunnableType using type inference. - +// For IgnoreResults. template -typename FunctorTraits::RunnableType MakeRunnable(const T& t) { - return RunnableAdapter(t); -} - -template -typename FunctorTraits::RunnableType -MakeRunnable(const IgnoreResultHelper& t) { - return MakeRunnable(t.functor_); -} +struct FunctorTraits> : FunctorTraits { + using RunType = + typename ForceVoidReturn::RunType>::RunType; -template -const typename FunctorTraits>::RunnableType& -MakeRunnable(const Callback& t) { - DCHECK(!t.is_null()); - return t; -} + template + static void Invoke(IgnoreResultType&& ignore_result_helper, + RunArgs&&... args) { + FunctorTraits::Invoke(ignore_result_helper.functor_, + std::forward(args)...); + } +}; +// For Callbacks. +template +struct FunctorTraits> { + using RunType = R(Args...); + static constexpr bool is_method = false; + static constexpr bool is_nullable = true; + + template + static R Invoke(CallbackType&& callback, RunArgs&&... args) { + DCHECK(!callback.is_null()); + return std::forward(callback).Run( + std::forward(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 +// WeakCalls need special syntax that is applied to the first argument to check +// if they should no-op themselves. +template struct InvokeHelper; -template -struct InvokeHelper { - template - static ReturnType MakeItSo(Runnable runnable, RunArgs&&... args) { - return runnable.Run(std::forward(args)...); - } -}; - -template -struct InvokeHelper { - template - static void MakeItSo(Runnable runnable, RunArgs&&... args) { - runnable.Run(std::forward(args)...); - } -}; - -template -struct InvokeHelper { - template - static void MakeItSo(Runnable runnable, - BoundWeakPtr weak_ptr, - RunArgs&&... args) { - if (!weak_ptr.get()) { - return; - } - runnable.Run(weak_ptr.get(), std::forward(args)...); +template +struct InvokeHelper { + template + static inline ReturnType MakeItSo(Functor&& functor, RunArgs&&... args) { + using Traits = FunctorTraits::type>; + return Traits::Invoke(std::forward(functor), + std::forward(args)...); } }; -#if !defined(_MSC_VER) - -template -struct InvokeHelper { +template +struct InvokeHelper { // 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::value, "weak_ptrs can only bind to methods without return values"); -}; -#endif + template + static inline void MakeItSo(Functor&& functor, + BoundWeakPtr&& weak_ptr, + RunArgs&&... args) { + if (!weak_ptr) + return; + using Traits = FunctorTraits::type>; + Traits::Invoke(std::forward(functor), + std::forward(weak_ptr), + std::forward(args)...); + } +}; // Invoker<> // // See description at the top of the file. -template +template struct Invoker; -template -struct Invoker, - StorageType, - InvokeHelperType, - R(UnboundArgs...)> { +template +struct Invoker { static R Run(BindStateBase* base, UnboundArgs&&... unbound_args) { - StorageType* storage = static_cast(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(storage->bound_args_))..., - std::forward(unbound_args)...); + const StorageType* storage = static_cast(base); + static constexpr size_t num_bound_args = + std::tuple_sizebound_args_)>::value; + return RunImpl(storage->functor_, + storage->bound_args_, + MakeIndexSequence(), + std::forward(unbound_args)...); } -}; -// Used to implement MakeArgsStorage. -template -struct MakeArgsStorageImpl { - using Type = std::tuple; + private: + template + static inline R RunImpl(Functor&& functor, + BoundArgsTuple&& bound, + IndexSequence, + UnboundArgs&&... unbound_args) { + static constexpr bool is_method = + FunctorTraits::type>::is_method; + + using DecayedArgsTuple = typename std::decay::type; + static constexpr bool is_weak_call = + IsWeakMethod::type...>::value; + + return InvokeHelper::MakeItSo( + std::forward(functor), + Unwrap(base::get(std::forward(bound)))..., + std::forward(unbound_args)...); + } }; -template -struct MakeArgsStorageImpl { - using Type = std::tuple, BoundArgs...>; +// Used to implement MakeUnboundRunType. +template +struct MakeUnboundRunTypeImpl { + using RunType = + typename FunctorTraits::type>::RunType; + using ReturnType = ExtractReturnType; + using Args = ExtractArgs; + using UnboundArgs = DropTypeListItem; + using Type = MakeFunctionType; }; +template +typename std::enable_if::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 -using MakeArgsStorage = typename MakeArgsStorageImpl< - is_method, typename std::decay::type...>::Type; +template +typename std::enable_if::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 -struct BindState; - -template -struct BindState final - : public BindStateBase { - private: - using StorageType = BindState; - using RunnableType = Runnable; +// This stores all the state passed into Bind(). +template +struct BindState final : BindStateBase { + template + explicit BindState(ForwardFunctor&& functor, ForwardBoundArgs&&... bound_args) + : BindStateBase(&Destroy), + functor_(std::forward(functor)), + bound_args_(std::forward(bound_args)...) { + DCHECK(!IsNull(functor_)); + } - enum { is_method = HasIsMethodTag::value }; + Functor functor_; + std::tuple bound_args_; - // true_type if Runnable is a method invocation and the first bound argument - // is a WeakPtr. - using IsWeakCall = - IsWeakMethod::type...>; + private: + ~BindState() {} - using BoundIndices = MakeIndexSequence; - using InvokeHelperType = InvokeHelper; + static void Destroy(BindStateBase* self) { + delete static_cast(self); + } +}; - using UnboundArgs = DropTypeListItem>; +// Used to implement MakeBindStateType. +template +struct MakeBindStateTypeImpl; - public: - using UnboundRunType = MakeFunctionType; - using InvokerType = - Invoker; +template +struct MakeBindStateTypeImpl { + static_assert(!HasRefCountedTypeAsRawPtr::value, + "A parameter is a refcounted type and needs scoped_refptr."); + using Type = BindState::type, + typename std::decay::type...>; +}; - template - BindState(const Runnable& runnable, ForwardArgs&&... bound_args) - : BindStateBase(&Destroy), - runnable_(runnable), - bound_args_(std::forward(bound_args)...) {} +template +struct MakeBindStateTypeImpl { + using Type = BindState::type>; +}; - RunnableType runnable_; - MakeArgsStorage bound_args_; +template +struct MakeBindStateTypeImpl { + static_assert( + !std::is_array::type>::value, + "First bound argument to a method cannot be an array."); + static_assert(!HasRefCountedTypeAsRawPtr::value, + "A parameter is a refcounted type and needs scoped_refptr."); private: - ~BindState() {} + using DecayedReceiver = typename std::decay::type; - static void Destroy(BindStateBase* self) { - delete static_cast(self); - } + public: + using Type = BindState< + typename std::decay::type, + typename std::conditional< + std::is_pointer::value, + scoped_refptr::type>, + DecayedReceiver>::type, + typename std::decay::type...>; }; +template +using MakeBindStateType = typename MakeBindStateTypeImpl< + FunctorTraits::type>::is_method, + Functor, + BoundArgs...>::Type; + } // namespace internal + +// Returns a RunType of bound functor. +// E.g. MakeUnboundRunType is evaluated to R(C). +template +using MakeUnboundRunType = + typename internal::MakeUnboundRunTypeImpl::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::value); - EXPECT_FALSE(internal::SupportsAddRefAndRelease::value); - - // StrictMock is a derived class of T. So, we use StrictMock and - // StrictMock to test that SupportsAddRefAndRelease works over - // inheritance. - EXPECT_TRUE(internal::SupportsAddRefAndRelease >::value); - EXPECT_FALSE(internal::SupportsAddRefAndRelease >::value); - - // This matters because the implementation creates a dummy class that - // inherits from the template type. - EXPECT_TRUE(internal::SupportsAddRefAndRelease::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 > refptr(&has_ref_); + EXPECT_CALL(has_ref_, AddRef()).Times(1); + EXPECT_CALL(has_ref_, Release()).Times(1); + const scoped_refptr refptr(&has_ref_); Callback 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> no_ref(new StrictMock); + 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>; MoveOnlyVector v; - v.push_back(base::MakeUnique(12345)); + v.push_back(WrapUnique(new int(12345))); // Early binding should work: base::Callback bound_cb = @@ -1065,6 +1044,36 @@ TEST_F(BindTest, ArgumentCopiesAndMoves) { EXPECT_EQ(0, move_assigns); } +TEST_F(BindTest, CapturelessLambda) { + EXPECT_FALSE(internal::IsConvertibleToRunType::value); + EXPECT_FALSE(internal::IsConvertibleToRunType::value); + EXPECT_FALSE(internal::IsConvertibleToRunType::value); + EXPECT_FALSE(internal::IsConvertibleToRunType::value); + + auto f = []() {}; + EXPECT_TRUE(internal::IsConvertibleToRunType::value); + + int i = 0; + auto g = [i]() {}; + EXPECT_FALSE(internal::IsConvertibleToRunType::value); + + auto h = [](int, double) { return 'k'; }; + EXPECT_TRUE((std::is_same< + char(int, double), + internal::ExtractCallableRunType>::value)); + + EXPECT_EQ(42, Bind([] { return 42; }).Run()); + EXPECT_EQ(42, Bind([](int i) { return i * 7; }, 6).Run()); + + int x = 1; + base::Callback 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 arg) {} -// scoped_ptr f(new Foo); +// void TakesOwnership(std::unique_ptr arg) {} +// std::unique_ptr 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 -struct BindState; -} // namespace internal template class Callback : public internal::CallbackBase { + 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 Callback() : internal::CallbackBase(nullptr) {} - template - explicit Callback( - internal::BindState* bind_state) + Callback(internal::BindStateBase* bind_state, + PolymorphicInvoke invoke_func) : internal::CallbackBase(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 - ::InvokerType::Run; using InvokeFuncStorage = typename internal::CallbackBase::InvokeFuncStorage; this->polymorphic_invoke_ = @@ -396,9 +388,6 @@ class Callback reinterpret_cast(this->polymorphic_invoke_); return f(this->bind_state_.get(), std::forward(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 +base::Callback ResetAndReturn(base::Callback* cb) { + base::Callback 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 { // 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 #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 - : 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(self); + ~FakeBindState1() {} + static void Destroy(internal::BindStateBase* self) { + delete static_cast(self); } }; -template <> -struct BindState - : 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(self); + ~FakeBindState2() {} + static void Destroy(internal::BindStateBase* self) { + delete static_cast(self); } }; -} // namespace internal namespace { -using FakeBindState1 = internal::BindState; -using FakeBindState2 = - internal::BindState; - 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 callback_c(new FakeBindState1()); + Callback callback_c(new FakeBindState1(), &NopInvokeFunc); Callback 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 { public: explicit CallbackOwner(bool* deleted) { diff --git a/third_party/chromium/base/guid.cc b/third_party/chromium/base/guid.cc new file mode 100644 index 0000000..bb41e8c --- /dev/null +++ b/third_party/chromium/base/guid.cc @@ -0,0 +1,79 @@ +// 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. + +#include "base/guid.h" + +#include +#include + +#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()}; + + // Set the GUID to 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]. + + // Clear the version bits and set the version to 4: + sixteen_bytes[0] &= 0xffffffffffff0fffULL; + sixteen_bytes[0] |= 0x0000000000004000ULL; + + // Set the two most significant bits (bits 6 and 7) of the + // clock_seq_hi_and_reserved to zero and one, respectively: + sixteen_bytes[1] &= 0x3fffffffffffffffULL; + sixteen_bytes[1] |= 0x8000000000000000ULL; + + return RandomDataToGUIDString(sixteen_bytes); +} + +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(bytes[0] >> 32), + static_cast((bytes[0] >> 16) & 0x0000ffff), + static_cast(bytes[0] & 0x0000ffff), + static_cast(bytes[1] >> 48), + bytes[1] & 0x0000ffffffffffffULL); +} + +} // namespace base 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 #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_posix.cc b/third_party/chromium/base/guid_posix.cc deleted file mode 100644 index ec1ca51..0000000 --- a/third_party/chromium/base/guid_posix.cc +++ /dev/null @@ -1,44 +0,0 @@ -// 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. - -#include "base/guid.h" - -#include - -#include "base/rand_util.h" -#include "base/strings/stringprintf.h" - -namespace base { - -std::string GenerateGUID() { - uint64_t sixteen_bytes[2] = {base::RandUint64(), base::RandUint64()}; - - // Set the GUID to 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]. - - // Clear the version bits and set the version to 4: - sixteen_bytes[0] &= 0xffffffffffff0fffULL; - sixteen_bytes[0] |= 0x0000000000004000ULL; - - // Set the two most significant bits (bits 6 and 7) of the - // clock_seq_hi_and_reserved to zero and one, respectively: - sixteen_bytes[1] &= 0x3fffffffffffffffULL; - sixteen_bytes[1] |= 0x8000000000000000ULL; - - return RandomDataToGUIDString(sixteen_bytes); -} - -// TODO(cmasone): Once we're comfortable this works, migrate Windows code to -// use this as well. -std::string RandomDataToGUIDString(const uint64_t bytes[2]) { - return StringPrintf("%08X-%04X-%04X-%04X-%012llX", - static_cast(bytes[0] >> 32), - static_cast((bytes[0] >> 16) & 0x0000ffff), - static_cast(bytes[0] & 0x0000ffff), - static_cast(bytes[1] >> 48), - bytes[1] & 0x0000ffffffffffffULL); -} - -} // 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 -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 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(input.as_string()); start_pos_ = input_copy->data(); } else { start_pos_ = input.data(); @@ -250,12 +250,14 @@ std::unique_ptr 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(std::move(input_copy), + std::move(root)); + } + if (root->IsType(Value::TYPE_LIST)) { + return MakeUnique(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 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 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(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(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 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(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(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(root.get()); - EXPECT_EQ(3U, list->GetSize()); - - // Test with trailing comma. Should be parsed the same as above. - std::unique_ptr 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(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(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(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(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(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(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(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(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 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 root = JSONReader().ReadToValue("true "); + ASSERT_TRUE(root); + EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN)); + } + + { + // Embedded comment + std::unique_ptr 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 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 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 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 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 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 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 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 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 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 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 root2 = + JSONReader::Read("[true, false, null, ]", JSON_ALLOW_TRAILING_COMMAS); + EXPECT_TRUE(list->Equals(root2.get())); + } + + { + // Empty array + std::unique_ptr list = ListValue::From(JSONReader::Read("[]")); + ASSERT_TRUE(list); + EXPECT_EQ(0U, list->GetSize()); + } + + { + // Nested arrays + std::unique_ptr list = ListValue::From( + JSONReader::Read("[[true], [], [false, [], [null]], null]")); + ASSERT_TRUE(list); + EXPECT_EQ(4U, list->GetSize()); + + // Lots of trailing commas. + std::unique_ptr 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 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 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 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 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 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 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 list = + ListValue::From(JSONReader::Read(not_evil)); + ASSERT_TRUE(list); + EXPECT_EQ(5001U, list->GetSize()); + } + + { + // Test utf8 encoded input + std::unique_ptr 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 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 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 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 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( template std::string* MakeCheckOpString( 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 #include #include +#include +#include #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 +inline typename std::enable_if< + base::internal::SupportsOstreamOperator::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 +inline typename std::enable_if< + !base::internal::SupportsOstreamOperator::value && + std::is_enum::value, + void>::type +MakeCheckOpValueString(std::ostream* os, const T& v) { + (*os) << static_cast::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 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 class. To use this guy just extend your +// knock-off of WebKit's RefCounted class. To use this, just extend your // class from it like so: // // class MyFoo : public base::RefCounted { 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 WeakPtr(const WeakPtr& other) : WeakPtrBase(other), ptr_(other.ptr_) { } + template + WeakPtr(WeakPtr&& 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 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 bool operator==(WeakPtr const&) const; - template bool operator!=(WeakPtr const&) const; - friend class internal::SupportsWeakPtrBase; template friend class WeakPtr; friend class SupportsWeakPtr; @@ -269,6 +255,24 @@ class WeakPtr : public internal::WeakPtrBase { T* ptr_; }; +// Allow callers to compare WeakPtrs against nullptr to test validity. +template +bool operator!=(const WeakPtr& weak_ptr, std::nullptr_t) { + return !(weak_ptr == nullptr); +} +template +bool operator!=(std::nullptr_t, const WeakPtr& weak_ptr) { + return weak_ptr != nullptr; +} +template +bool operator==(const WeakPtr& weak_ptr, std::nullptr_t) { + return weak_ptr.get() == nullptr; +} +template +bool operator==(std::nullptr_t, const WeakPtr& 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 factory(&data); + WeakPtr ptr = factory.GetWeakPtr(); + WeakPtr ptr2 = factory.GetWeakPtr(); + WeakPtr ptr3 = std::move(ptr2); + EXPECT_NE(ptr.get(), ptr2.get()); + EXPECT_EQ(ptr.get(), ptr3.get()); +} + TEST(WeakPtrFactoryTest, OutOfScope) { WeakPtr ptr; EXPECT_EQ(nullptr, ptr.get()); @@ -159,6 +169,19 @@ TEST(WeakPtrFactoryTest, BooleanTesting) { } } +TEST(WeakPtrFactoryTest, ComparisonToNull) { + int data; + WeakPtrFactory factory(&data); + + WeakPtr ptr_to_an_instance = factory.GetWeakPtr(); + EXPECT_NE(nullptr, ptr_to_an_instance); + EXPECT_NE(ptr_to_an_instance, nullptr); + + WeakPtr null_ptr; + EXPECT_EQ(null_ptr, nullptr); + EXPECT_EQ(nullptr, null_ptr); +} + TEST(WeakPtrTest, InvalidateWeakPtrs) { int data; WeakPtrFactory 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 { #define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \ do { \ if ((observer_list).might_have_observers()) { \ - base::ObserverListBase::Iterator it_inside_observer_macro( \ - &observer_list); \ + typename base::ObserverListBase::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 +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 #include +#include #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 struct is_non_const_reference : std::false_type {}; template struct is_non_const_reference : std::true_type {}; template struct is_non_const_reference : std::false_type {}; +namespace internal { +// Uses expression SFINAE to detect whether using operator<< would work. +template +struct SupportsOstreamOperator : std::false_type {}; +template +struct SupportsOstreamOperator() + << std::declval()))> + : 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 +struct underlying_type { + using type = __underlying_type(T); +}; +#else +template +using underlying_type = std::underlying_type; +#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 +using is_trivially_destructible = std::has_trivial_destructor; +#else +template +using is_trivially_destructible = std::is_trivially_destructible; +#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 +#include 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 static_assert(!is_non_const_reference::value, "IsNonConstReference"); static_assert(!is_non_const_reference::value, "IsNonConstReference"); static_assert(is_non_const_reference::value, "IsNonConstReference"); +// A few standard types that definitely support printing. +static_assert(internal::SupportsOstreamOperator::value, + "ints should be printable"); +static_assert(internal::SupportsOstreamOperator::value, + "C strings should be printable"); +static_assert(internal::SupportsOstreamOperator::value, + "std::string should be printable"); + +// Various kinds of enums operator<< support. +static_assert(internal::SupportsOstreamOperator::value, + "simple enum should be printable by value"); +static_assert(internal::SupportsOstreamOperator::value, + "simple enum should be printable by const ref"); +static_assert(internal::SupportsOstreamOperator::value, + "enum with explicit type should be printable by value"); +static_assert( + internal::SupportsOstreamOperator::value, + "enum with explicit type should be printable by const ref"); +static_assert(!internal::SupportsOstreamOperator::value, + "scoped enum should not be printable by value"); +static_assert(!internal::SupportsOstreamOperator::value, + "simple enum should not be printable by const ref"); +static_assert(internal::SupportsOstreamOperator::value, + "scoped enum with operator<< should be printable by value"); +static_assert( + internal::SupportsOstreamOperator::value, + "scoped enum with operator<< should be printable by const ref"); + +// operator<< support on structs. +static_assert(!internal::SupportsOstreamOperator::value, + "simple struct should not be printable by value"); +static_assert(!internal::SupportsOstreamOperator::value, + "simple struct should not be printable by const ref"); +static_assert(internal::SupportsOstreamOperator::value, + "struct with operator<< should be printable by value"); +static_assert( + internal::SupportsOstreamOperator::value, + "struct with operator<< should be printable by const ref"); + +// underlying type of enums +static_assert(std::is_integral::type>::value, + "simple enum must have some integral type"); +static_assert( + std::is_same::type, uint64_t>::value, + "explicit type must be detected"); +static_assert(std::is_same::type, int>::value, + "scoped enum defaults to int"); + +struct TriviallyDestructible { + int field; +}; + +class NonTriviallyDestructible { + ~NonTriviallyDestructible() {} +}; + +static_assert(is_trivially_destructible::value, "IsTriviallyDestructible"); +static_assert(is_trivially_destructible::value, + "IsTriviallyDestructible"); +static_assert(!is_trivially_destructible::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 @@ -132,11 +132,6 @@ std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) { // Time ----------------------------------------------------------------------- -// static -Time Time::Max() { - return Time(std::numeric_limits::max()); -} - // static Time Time::FromTimeT(time_t tt) { if (tt == 0) @@ -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 #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::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::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