aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiko Catania <niko@google.com>2010-01-28 13:20:02 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2010-01-28 13:20:02 -0800
commit21d15b6379f94dc2d1e7b161cda269d8168488e8 (patch)
treee2a7c474d14016eec77a33aca55e150ea13b3af5
parentf31fdb2e57186a552855e27f55036369ec1c279a (diff)
parent9bf9b2a29e7da59f45b86a800665ad72dafe3f72 (diff)
downloadastl-21d15b6379f94dc2d1e7b161cda269d8168488e8.tar.gz
Merge "Added iterator based vector constructor."
-rw-r--r--include/vector89
-rw-r--r--tests/test_vector.cpp39
2 files changed, 128 insertions, 0 deletions
diff --git a/include/vector b/include/vector
index a068bc3..d9e4642 100644
--- a/include/vector
+++ b/include/vector
@@ -81,6 +81,22 @@ class vector
// @param init_value The element to copy.
explicit vector(const size_type num, const value_type& init_value = value_type());
+ // Create a vector by copying the elements from [first, last).
+ //
+ // If the iterators are random-access, the constructor will be
+ // able to reserve the memory in a single call before copying the
+ // elements. If the elements are POD, the constructor uses memmove.
+ template<typename _Iterator>
+ vector(_Iterator first, _Iterator last) {
+ // Because of template matching, vector<int>(int n, int val)
+ // will now match this constructor (int != size_type) instead
+ // of the repeat one above. In this case, the _Iterator
+ // template parameter is an integral type and not an iterator,
+ // we use that to call the correct initialize impl.
+ typedef typename is_integral<_Iterator>::type integral;
+ initialize(first, last, integral());
+ }
+
~vector() { clear(); }
// @return true if the vector is empty, false otherwise.
@@ -137,6 +153,39 @@ class vector
void swap(vector& other);
private:
+ // See the 2 'initialize' methods first. They desambiguate between
+ // repeat and range initialize. For range initialize, there is
+ // another desambiguation based on the nature of the iterators.
+
+ // Repeat constructor implementation.
+ void repeat_initialize(const size_type num,
+ const value_type& init_value);
+
+ // Initialize from a random access iterator.
+ template<typename _Iterator>
+ void range_initialize(_Iterator first, _Iterator last,
+ random_access_iterator_tag);
+
+ // Initialize from an input iterator.
+ template<typename _InputIterator>
+ void range_initialize(_InputIterator first, _InputIterator last,
+ input_iterator_tag);
+
+ // Repeat constructor that matched the templatized constructor for iterator.
+ // The last parameter true_type is used by the caller to target this method.
+ template<typename _Integral>
+ void initialize(_Integral num, _Integral init_value, true_type) {
+ repeat_initialize((size_type)num, init_value);
+ }
+
+ // Not a repeat constructor (last param type is false_type). first
+ // and last are really iterators. Dispatch the call depending on
+ // the iterators' category.
+ template<typename _InputIterator>
+ void initialize(_InputIterator first, _InputIterator last, false_type) {
+ range_initialize(first, last, android::iterator_category(first));
+ }
+
// @return New internal buffer size when it is adjusted automatically.
size_type grow() const;
@@ -171,6 +220,13 @@ vector<_T>::vector()
template<typename _T>
vector<_T>::vector(const size_type num, const value_type& init_value)
{
+ repeat_initialize(num, init_value);
+}
+
+template<typename _T>
+void vector<_T>::repeat_initialize(const size_type num,
+ const value_type& init_value)
+{
if (num < max_size())
{
mBegin = static_cast<pointer>(malloc(num * sizeof(value_type)));
@@ -289,6 +345,39 @@ void vector<_T>::swap(vector& other)
std::swap(mLength, other.mLength);
}
+template<typename _T>
+template<typename _InputIterator>
+void vector<_T>::range_initialize(_InputIterator first, _InputIterator last,
+ input_iterator_tag) {
+ // There is no way to know how many elements we are going to
+ // insert, call push_back which will alloc/realloc as needed.
+ mBegin = NULL;
+ mLength = mCapacity = 0;
+ for (; first != last; ++first) {
+ push_back(*first);
+ }
+}
+
+template<typename _T>
+template<typename _Iterator>
+void vector<_T>::range_initialize(_Iterator first, _Iterator last,
+ random_access_iterator_tag) {
+ typedef typename iterator_traits<_Iterator>::difference_type difference_type;
+ const difference_type num = std::distance(first, last);
+
+ if (0 <= num && static_cast<size_type>(num) < max_size()) {
+ mBegin = static_cast<pointer>(malloc(num * sizeof(value_type)));
+ if (mBegin) {
+ mLength = mCapacity = num;
+ std::uninitialized_copy(first, last, iterator(mBegin));
+ return;
+ }
+ }
+ mBegin = NULL;
+ mLength = mCapacity = 0;
+}
+
+
// Grow the capacity. Use exponential until kExponentialLimit then
// linear until it reaches max_size().
template<typename _T>
diff --git a/tests/test_vector.cpp b/tests/test_vector.cpp
index 122557b..304b114 100644
--- a/tests/test_vector.cpp
+++ b/tests/test_vector.cpp
@@ -122,6 +122,44 @@ bool testConstructorRepeat()
return true;
}
+bool testConstructorIterator()
+{
+ {
+ vector<string> src;
+ EXPECT_TRUE(src.empty());
+ vector<string> dst(src.begin(), src.end());
+ EXPECT_TRUE(dst.empty());
+ }
+ {
+ vector<int> src;
+ EXPECT_TRUE(src.empty());
+ vector<int> dst(src.begin(), src.end());
+ EXPECT_TRUE(dst.empty());
+ }
+ {
+ vector<int> src;
+ src.push_back(10);
+ src.push_back(20);
+ src.push_back(30);
+ vector<int> dst(src.begin(), src.end());
+ EXPECT_TRUE(dst.size() == 3);
+ EXPECT_TRUE(dst[0] == 10);
+ EXPECT_TRUE(dst[1] == 20);
+ EXPECT_TRUE(dst[2] == 30);
+ }
+ {
+ vector<string> src;
+ src.push_back("str1");
+ src.push_back("str2");
+ src.push_back("str3");
+ vector<string> dst(src.begin(), src.end());
+ EXPECT_TRUE(dst.size() == 3);
+ EXPECT_TRUE(dst[0] == "str1");
+ EXPECT_TRUE(dst[1] == "str2");
+ EXPECT_TRUE(dst[2] == "str3");
+ }
+ return true;
+}
bool testReserve()
{
@@ -390,6 +428,7 @@ int main(int argc, char **argv)
FAIL_UNLESS(testConstructorInt);
FAIL_UNLESS(testConstructorString);
FAIL_UNLESS(testConstructorRepeat);
+ FAIL_UNLESS(testConstructorIterator);
FAIL_UNLESS(testReserve);
FAIL_UNLESS(testPushBack);
FAIL_UNLESS(testPopBack);