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