Commit f6c12979 authored by jdoerrie's avatar jdoerrie Committed by Commit Bot

[base] Implement std::size(), std::empty() and std::data()

This change provides C++14 implementations of C++17's std::size(),
std::empty() and std::data().

Bug: 828324
Change-Id: If1b83826a23b26fd557f7854962bcbc771a7ffe0
Reviewed-on: https://chromium-review.googlesource.com/992236
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: default avatarkylechar <kylechar@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#550137}
parent 8503e891
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <deque> #include <deque>
#include <forward_list> #include <forward_list>
#include <functional> #include <functional>
#include <initializer_list>
#include <iterator> #include <iterator>
#include <list> #include <list>
#include <map> #include <map>
...@@ -40,6 +41,69 @@ void IterateAndEraseIf(Container& container, Predicate pred) { ...@@ -40,6 +41,69 @@ void IterateAndEraseIf(Container& container, Predicate pred) {
} // namespace internal } // namespace internal
// C++14 implementation of C++17's std::size():
// http://en.cppreference.com/w/cpp/iterator/size
template <typename Container>
constexpr auto size(const Container& c) -> decltype(c.size()) {
return c.size();
}
template <typename T, size_t N>
constexpr size_t size(const T (&array)[N]) noexcept {
return N;
}
// C++14 implementation of C++17's std::empty():
// http://en.cppreference.com/w/cpp/iterator/empty
template <typename Container>
constexpr auto empty(const Container& c) -> decltype(c.empty()) {
return c.empty();
}
template <typename T, size_t N>
constexpr bool empty(const T (&array)[N]) noexcept {
return false;
}
template <typename T>
constexpr bool empty(std::initializer_list<T> il) noexcept {
return il.size() == 0;
}
// C++14 implementation of C++17's std::data():
// http://en.cppreference.com/w/cpp/iterator/data
template <typename Container>
constexpr auto data(Container& c) -> decltype(c.data()) {
return c.data();
}
// std::basic_string::data() had no mutable overload prior to C++17 [1].
// Hence this overload is provided.
// Note: str[0] is safe even for empty strings, as they are guaranteed to be
// null-terminated [2].
//
// [1] http://en.cppreference.com/w/cpp/string/basic_string/data
// [2] http://en.cppreference.com/w/cpp/string/basic_string/operator_at
template <typename CharT, typename Traits, typename Allocator>
CharT* data(std::basic_string<CharT, Traits, Allocator>& str) {
return std::addressof(str[0]);
}
template <typename Container>
constexpr auto data(const Container& c) -> decltype(c.data()) {
return c.data();
}
template <typename T, size_t N>
constexpr T* data(T (&array)[N]) noexcept {
return array;
}
template <typename T>
constexpr const T* data(std::initializer_list<T> il) noexcept {
return il.begin();
}
// Clears internal memory of an STL object. // Clears internal memory of an STL object.
// STL clear()/reserve(0) does not always free internal memory allocated // STL clear()/reserve(0) does not always free internal memory allocated
// This function uses swap/destructor to ensure the internal memory is freed. // This function uses swap/destructor to ensure the internal memory is freed.
...@@ -72,6 +136,8 @@ STLCount(const Container& container, const T& val) { ...@@ -72,6 +136,8 @@ STLCount(const Container& container, const T& val) {
// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530) // (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
// proposes this as the method. According to Matt Austern, this should // proposes this as the method. According to Matt Austern, this should
// already work on all current implementations. // already work on all current implementations.
//
// DEPRECATED(https://crbug.com/831499), use base::data(std::string&) instead.
inline char* string_as_array(std::string* str) { inline char* string_as_array(std::string* str) {
// DO NOT USE const_cast<char*>(str->data()) // DO NOT USE const_cast<char*>(str->data())
return str->empty() ? NULL : &*str->begin(); return str->empty() ? NULL : &*str->begin();
......
...@@ -4,14 +4,17 @@ ...@@ -4,14 +4,17 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include <array>
#include <deque> #include <deque>
#include <forward_list> #include <forward_list>
#include <functional> #include <functional>
#include <initializer_list>
#include <iterator> #include <iterator>
#include <list> #include <list>
#include <map> #include <map>
#include <set> #include <set>
#include <string> #include <string>
#include <type_traits>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
...@@ -94,6 +97,140 @@ struct HashByFirst { ...@@ -94,6 +97,140 @@ struct HashByFirst {
namespace base { namespace base {
namespace { namespace {
TEST(STLUtilTest, Size) {
{
std::vector<int> vector = {1, 2, 3, 4, 5};
static_assert(
std::is_same<decltype(base::size(vector)),
decltype(vector.size())>::value,
"base::size(vector) should have the same type as vector.size()");
EXPECT_EQ(vector.size(), base::size(vector));
}
{
std::string empty_str;
static_assert(
std::is_same<decltype(base::size(empty_str)),
decltype(empty_str.size())>::value,
"base::size(empty_str) should have the same type as empty_str.size()");
EXPECT_EQ(0u, base::size(empty_str));
}
{
std::array<int, 4> array = {1, 2, 3, 4};
static_assert(
std::is_same<decltype(base::size(array)),
decltype(array.size())>::value,
"base::size(array) should have the same type as array.size()");
static_assert(base::size(array) == array.size(),
"base::size(array) should be equal to array.size()");
}
{
int array[] = {1, 2, 3};
static_assert(std::is_same<size_t, decltype(base::size(array))>::value,
"base::size(array) should be of type size_t");
static_assert(3u == base::size(array), "base::size(array) should be 3");
}
}
TEST(STLUtilTest, Empty) {
{
std::vector<int> vector;
static_assert(
std::is_same<decltype(base::empty(vector)),
decltype(vector.empty())>::value,
"base::empty(vector) should have the same type as vector.empty()");
EXPECT_EQ(vector.empty(), base::empty(vector));
}
{
std::array<int, 4> array = {1, 2, 3, 4};
static_assert(
std::is_same<decltype(base::empty(array)),
decltype(array.empty())>::value,
"base::empty(array) should have the same type as array.empty()");
static_assert(base::empty(array) == array.empty(),
"base::empty(array) should be equal to array.empty()");
}
{
int array[] = {1, 2, 3};
static_assert(std::is_same<bool, decltype(base::empty(array))>::value,
"base::empty(array) should be of type bool");
static_assert(!base::empty(array), "base::empty(array) should be false");
}
{
constexpr std::initializer_list<int> il;
static_assert(std::is_same<bool, decltype(base::empty(il))>::value,
"base::empty(il) should be of type bool");
static_assert(base::empty(il), "base::empty(il) should be true");
}
}
TEST(STLUtilTest, Data) {
{
std::vector<int> vector = {1, 2, 3, 4, 5};
static_assert(
std::is_same<decltype(base::data(vector)),
decltype(vector.data())>::value,
"base::data(vector) should have the same type as vector.data()");
EXPECT_EQ(vector.data(), base::data(vector));
}
{
const std::string cstr = "const string";
static_assert(
std::is_same<decltype(base::data(cstr)), decltype(cstr.data())>::value,
"base::data(cstr) should have the same type as cstr.data()");
EXPECT_EQ(cstr.data(), base::data(cstr));
}
{
std::string str = "mutable string";
static_assert(std::is_same<decltype(base::data(str)), char*>::value,
"base::data(str) should be of type char*");
EXPECT_EQ(str.data(), base::data(str));
}
{
std::string empty_str;
static_assert(std::is_same<decltype(base::data(empty_str)), char*>::value,
"base::data(empty_str) should be of type char*");
EXPECT_EQ(empty_str.data(), base::data(empty_str));
}
{
std::array<int, 4> array = {1, 2, 3, 4};
static_assert(
std::is_same<decltype(base::data(array)),
decltype(array.data())>::value,
"base::data(array) should have the same type as array.data()");
// std::array::data() is not constexpr prior to C++17, hence the runtime
// check.
EXPECT_EQ(array.data(), base::data(array));
}
{
constexpr int array[] = {1, 2, 3};
static_assert(std::is_same<const int*, decltype(base::data(array))>::value,
"base::data(array) should be of type const int*");
static_assert(array == base::data(array),
"base::data(array) should be array");
}
{
constexpr std::initializer_list<int> il;
static_assert(
std::is_same<decltype(il.begin()), decltype(base::data(il))>::value,
"base::data(il) should have the same type as il.begin()");
static_assert(il.begin() == base::data(il),
"base::data(il) should be equal to il.begin()");
}
}
TEST(STLUtilTest, STLIsSorted) { TEST(STLUtilTest, STLIsSorted) {
{ {
std::set<int> set; std::set<int> set;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment