From 31c2eedcb21182e2b1a3e23cb1bac90f0f026a97 Mon Sep 17 00:00:00 2001 From: pezy Date: Wed, 4 Feb 2015 20:56:30 +0800 Subject: [PATCH] finished 13.5 --- ch13/README.md | 41 +++- ch13/ex13.39.40/main.cpp | 70 ------ ch13/ex13.39.40/strvec.cpp | 219 ------------------ ch13/ex13.39.40/strvec.h | 77 ------- ch13/ex13.41.42/main.cpp | 59 ----- ch13/ex13.41.42/queryresult.cpp | 28 --- ch13/ex13.41.42/queryresult.h | 45 ---- ch13/ex13.41.42/strvec.cpp | 219 ------------------ ch13/ex13.41.42/strvec.h | 72 ------ ch13/ex13.41.42/textquery.cpp | 81 ------- ch13/ex13.41.42/textquery.h | 44 ---- ch13/ex13.43/main.cpp | 28 --- ch13/ex13.43/strvec.cpp | 241 -------------------- ch13/ex13.43/strvec.h | 72 ------ ch13/ex13_40.cpp | 107 +++++++++ ch13/ex13_40.h | 53 +++++ ch13/ex13_42.cpp | 19 ++ ch13/ex13_42_StrVec.cpp | 97 ++++++++ ch13/ex13_42_StrVec.h | 46 ++++ ch13/ex13_42_TextQuery.cpp | 39 ++++ ch13/ex13_42_TextQuery.h | 36 +++ ch13/{ex13.44/string.cpp => ex13_44.cpp} | 0 ch13/{ex13.44/string.h => ex13_44.h} | 0 ch13/{ex13.44/main.cpp => ex13_44_TEST.cpp} | 0 24 files changed, 437 insertions(+), 1256 deletions(-) delete mode 100644 ch13/ex13.39.40/main.cpp delete mode 100644 ch13/ex13.39.40/strvec.cpp delete mode 100644 ch13/ex13.39.40/strvec.h delete mode 100644 ch13/ex13.41.42/main.cpp delete mode 100644 ch13/ex13.41.42/queryresult.cpp delete mode 100644 ch13/ex13.41.42/queryresult.h delete mode 100644 ch13/ex13.41.42/strvec.cpp delete mode 100644 ch13/ex13.41.42/strvec.h delete mode 100644 ch13/ex13.41.42/textquery.cpp delete mode 100644 ch13/ex13.41.42/textquery.h delete mode 100644 ch13/ex13.43/main.cpp delete mode 100644 ch13/ex13.43/strvec.cpp delete mode 100644 ch13/ex13.43/strvec.h create mode 100644 ch13/ex13_40.cpp create mode 100644 ch13/ex13_40.h create mode 100644 ch13/ex13_42.cpp create mode 100644 ch13/ex13_42_StrVec.cpp create mode 100644 ch13/ex13_42_StrVec.h create mode 100644 ch13/ex13_42_TextQuery.cpp create mode 100644 ch13/ex13_42_TextQuery.h rename ch13/{ex13.44/string.cpp => ex13_44.cpp} (100%) rename ch13/{ex13.44/string.h => ex13_44.h} (100%) rename ch13/{ex13.44/main.cpp => ex13_44_TEST.cpp} (100%) diff --git a/ch13/README.md b/ch13/README.md index 035686b1..6ea66393 100644 --- a/ch13/README.md +++ b/ch13/README.md @@ -225,4 +225,43 @@ The copy and swap is an elegant way when working with dynamicly allocated memory @pezy In this case, `swap` function is special. It will be clear two `Message`'s folders , then swap members, and added themselves to each folders. But, `Message` assignment operator just clear itself, and copy the members, and added itself to each folders. The `rhs` don't need to clear and add to folders. So, if using copy and swap to define, it will be very inefficiency. -## Exercise 13.39 [hpp](ex13_39.h) | [cpp](ex13_39.cpp) \ No newline at end of file +## Exercise 13.39 [hpp](ex13_39.h) | [cpp](ex13_39.cpp) +## Exercise 13.40 [hpp](ex13_40.h) | [cpp](ex13_40.cpp) + +## Exercise 13.41: Why did we use postfix increment in the call to construct inside push_back? What would happen if it used the prefix increment? + +```cpp +|a|b|c|d|f|..............| +^ ^ ^ +elements first_free cap + +// if use alloc.construct(first_free++, "g"); +|a|b|c|d|f|g|.............| +^ ^ ^ +elements first_free cap + +// if use alloc.construct(++first_free, "g"); +|a|b|c|d|f|.|g|............| +^ ^ ^ ^ +elements | first_free cap + | + "unconstructed" +``` + +## Exercise 13.42: Test your StrVec class by using it in place of the vector in your TextQuery and QueryResult classes (12.3, p. 484). + +- StrVec : [hpp](ex13_42_StrVec.h) | [cpp](ex13_42_StrVec.cpp) +- TextQuery and QueryResult : [hpp](ex13_42_TextQuery.h) | [cpp](ex13_42_TextQuery.cpp) +- Text : [ex13_42.cpp](ex13_42.cpp) + +## Exercise 13.43: Rewrite the free member to use `for_each` and a lambda (10.3.2, p. 388) in place of the for loop to destroy the elements. Which implementation do you prefer, and why? + +**Rewrite** +```cpp +for_each(elements, first_free, [this](std::string &rhs){ alloc.destroy(&rhs); }); +``` + +@Mooophy: +The new version is better. Compared to the old one, it doesn't need to worry about the order and decrement.So more straightforward and handy. The only thing to do for using this approach is to add "&" to build the pointers to string pointers. + +## Exercise 13.44 [hpp](ex13_44.h) | [cpp](ex13_44.cpp) | [Test](ex13_44_TEST.cpp) \ No newline at end of file diff --git a/ch13/ex13.39.40/main.cpp b/ch13/ex13.39.40/main.cpp deleted file mode 100644 index f93a70fa..00000000 --- a/ch13/ex13.39.40/main.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 05 JAN 2014 - * @remark - ***************************************************************************/ -//! -//! Exercise 13.39: -//! Write your own version of StrVec, including versions of reserve, capacity -//! (§ 9.4, p. 356), and resize (§ 9.3.5, p. 352). -// When implementing the member resize, two overloaded functions was being considered. -// They were resize(size_t n) and resize(size_t n, valueType v), respectively. -// The former calls the default construct and the latter copy constuctor, when -// executing alloc.construct(). -// -//! design of resize(): -//! -//! [0][1][2][3][unconstructed elements] -//! ^ ^ ^ -//! element first_free cap -//! -//! if within [0, first_free - element), the current size is trunctated -//! -//! if equal to first_free - elemnt, the function will return wiouth any operation performed -//! -//! if within (first_free - element, +infinity) push_back will be called to append new elements, -//! using default constructor or copy constructor depending -//! on overloaded function matching. -//! -// discussion on SO: -// http://stackoverflow.com/questions/20930063/is-it-nessary-to-destroy-a-string-before-constructing-it-again -// and -// http://stackoverflow.com/questions/20931581/is-it-a-good-practice-to-use-temporary-objects-as-arguments-when-overloading-fun -//! -//! Exercise 13.40: -//! Add a constructor that takes an initializer_list to your StrVec class. -//! - - -#include -#include -#include -#include - -#include "strvec.h" - - - -int main() -{ - StrVec v{"1\n","2\n","3\n","4\n","5\n"} , v2; - - v =v2; - - v.push_back("alan\n"); - - - std::cout << v.size() << "\n"; - std::cout << v.capacity() << "\n"; - std::cout << "=============\n"; - - for(const auto &s : v ) - std::cout << s; - - return 0; -} - - - - diff --git a/ch13/ex13.39.40/strvec.cpp b/ch13/ex13.39.40/strvec.cpp deleted file mode 100644 index be619986..00000000 --- a/ch13/ex13.39.40/strvec.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/*************************************************************************** - * @file strvec.cpp - * @author Alan.W - * @date 05 JAN 2014 - * @remark - ***************************************************************************/ - -#include "strvec.h" -#include - - -//! copy constructor -StrVec::StrVec(const StrVec &s) -{ - /** - * @brief newData is a pair of pointers pointing to newly allocated and copied - * range : [b, e) - */ - std::pair - newData = alloc_n_copy(s.begin(), s.end()); - - element = newData.first; - first_free = cap = newData.second; -} - -/** - * @brief constructor taking initializer_list - * for ex 13.40 - * @param l - */ -StrVec::StrVec(std::initializer_list l) -{ - //! allocate memory as large as l.size() - std::string * const - newData = alloc.allocate(l.size()); - - //! copy elements from l to the address allocated - auto p = newData; - for(const auto &s : l) - alloc.construct(p++, s); - - //! build the data structure - element = newData; - first_free = cap = element + l.size(); -} - - -//! operator = -StrVec& -StrVec::operator =(const StrVec& rhs) -{ - //! allocate and copy first to protect against self-assignment - std::pair - newData = alloc_n_copy(rhs.begin(), rhs.end()); - - //! destroy and deallocate - free(); - - element = newData.first; - first_free = cap = newData.second; - - return *this; -} - -//! destructor -StrVec::~StrVec() -{ - free(); -} - -/** - * @brief allocate new room if nessary and push back the new string - * @param s new string - */ -void StrVec::push_back(const std::string& s) -{ - chk_n_alloc(); - alloc.construct(first_free++, s); -} - -/** - * @brief preallocate enough memory for specified number of elements - * @param n number of elements required - * @note this function is implemented refering to StrVec::reallocate(). - */ -void StrVec::reserve(std::size_t n) -{ - //! if the n is too small, just ignore it. - if(n <= capacity()) return; - - //! allocate and move old ones into the new address. - wy_alloc_n_move(n); -} - - -/** - * @brief Resizes to the specified number of elements. - * @param n Number of elements the %vector should contain. - * - * This function will resize it to the specified - * number of elements. If the number is smaller than the - * current size it is truncated, otherwise - * default constructed elements are appended. - */ - -void StrVec::resize(std::size_t n) -{ - resize(n,std::string()); -} - -/** - * @brief Resizes it to the specified number of elements. - * @param __new_size Number of elements it should contain. - * @param __x Data with which new elements should be populated. - * - * This function will resize it to the specified - * number of elements. If the number is smaller than the - * current size the it is truncated, otherwise - * the it is extended and new elements are populated with - * given data. - */ -void StrVec::resize(std::size_t n, const std::string &s) -{ - if(n < size()) - { - //! destroy the range : [element+n, first_free) using destructor - for(auto p = element + n; p != first_free; /* empty */) - alloc.destroy(p++); - - //! move frist_free point to the new address element + n - first_free = element + n; - } - else if( n > size() ) - { - for(auto i = size(); i != n; ++i) - push_back(std::string(s)); - } -} - -/** - * @brief Double the capacity and using std::move move the original strings to the newly - * allocated memory - */ -void StrVec::reallocate() -{ - //! calculate the new capacity required. - std::size_t newCapacity = size() ? 2 * size() : 1; - - //! allocate and move old ones into the new address. - wy_alloc_n_move(newCapacity); -} - -/** - * @brief allocate new space for the given range and copy them into it - * @param b - * @param e - * @return a pair of pointers pointing to [first element , one past the last) in the new space - */ -std::pair -StrVec::alloc_n_copy(std::string *b, std::string *e) -{ - //! calculate the size needed and allocate space accordingly - std::string* data = alloc.allocate(e - b); - - return { data, std::uninitialized_copy(b, e, data) }; - //! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - //! which copies the range [first,last) into the space of which - //! the starting address p_data is pointing to. - //! This function returns a pointer pointing to one past the last element. -} - -/** - * @brief destroy the elements and deallocate the space previously allocated. - */ -void StrVec::free() -{ - - if(element) // if not nullptr - { - //! destory it in reverse order. - for(auto p = first_free; p != element; /* empty */) - alloc.destroy(--p); - - alloc.deallocate(element, capacity()); - } -} - -/** - * @brief allocate memory for spicified number of elements - * @param n - * @note it's user's responsibility to ensure that @param n is greater than - * the current capacity. - */ -void StrVec::wy_alloc_n_move(std::size_t n) -{ - std::size_t newCapacity = n; - - std::string* - newData = alloc.allocate(newCapacity); - - std::string* - dest = newData; - std::string* - elem = element; - - //! move the old to newly allocated space. - for(std::size_t i = 0; i != size(); ++i) - alloc.construct(dest++, std::move(*elem++)); - - free(); - - //! update data structure - element = newData; - first_free = dest; - cap = element + newCapacity; -} - - - diff --git a/ch13/ex13.39.40/strvec.h b/ch13/ex13.39.40/strvec.h deleted file mode 100644 index 90d83f9a..00000000 --- a/ch13/ex13.39.40/strvec.h +++ /dev/null @@ -1,77 +0,0 @@ -/*************************************************************************** - * @file strvec.h - * @author Alan.W - * @date 05 JAN 2014 - * @remark - ***************************************************************************/ - - -#ifndef STRVEC_H -#define STRVEC_H - -#include - - -class StrVec -{ -public: - //! Big 3/5. - StrVec(): - element(nullptr), first_free(nullptr), cap(nullptr) - {} - - StrVec(std::initializer_list l); - - - StrVec(const StrVec& s); - - StrVec& - operator =(const StrVec& rhs); - - ~StrVec(); - - - //! public members - void push_back(const std::string &s); - - std::size_t size() const { return first_free - element; } - std::size_t capacity() const { return cap - element; } - - std::string* begin() const { return element; } - std::string* end() const { return first_free; } - - //! preallocate enough memory for specified number of elements - void reserve(std::size_t n); - - //! resize as required. - void resize(std::size_t n); - void resize(std::size_t n, const std::string& s); - - - - - -private: - - //! data members - std::string* element; // pointer to the first element - std::string* first_free; // pointer to the first free element - std::string* cap; // pointer to one past the end - - std::allocator alloc; - - //! utilities for Big 3/5 - void reallocate(); - void chk_n_alloc() { if (size() == capacity()) reallocate(); } - void free(); - - //! utilities added - //! used in reallocate() reserve() and resize(). - void wy_alloc_n_move(std::size_t n); - - std::pair - alloc_n_copy (std::string* b, std::string* e); - -}; - -#endif // STRVEC_H diff --git a/ch13/ex13.41.42/main.cpp b/ch13/ex13.41.42/main.cpp deleted file mode 100644 index 5e4dc615..00000000 --- a/ch13/ex13.41.42/main.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 06 JAN 2014 - * @remark - ***************************************************************************/ -//! -//! Exercise 13.41: -//! Why did we use postfix increment in the call to construct inside push_back? -//! What would happen if it used the prefix increment? -// The prefix operator++ does a single operation -- increment the value. -// The postfix operator++ does three operations -- save the current value, -// increment the value, return the old value. -// -// The prefix version is conceptually simpler, and is always (up to bizarre -// operator overloads) at least as efficient as the postfix version. -// --From SO -// -// alloc.construct(first_free++, s); -// -// Hence, if prefix increment is used instead, alloc.construct will jump over -// one place leaving it unconstructed. Any operation ,like dereference or destruction, -// on this address would be a disaster. -// -//! -//! Exercise 13.42: -//! Test your StrVec class by using it in place of the vector in your -//! TextQuery and QueryResult classes (§ 12.3, p. 484). -//! - -#include -#include -#include - -#include "queryresult.h" -#include "textquery.h" - - -void runQueries(std::ifstream &infile); -int main() -{ - std::ifstream fin("test.txt"); - runQueries(fin); - return 0; -} - -void runQueries(std::ifstream &infile) -{ - - TextQuery tq(infile); - while (true) { - std::cout << "enter word to look for, or q to quit: "; - std::string s; - - if (!(std::cin >> s) || s == "q") break; - - print(std::cout, tq.query(s)) << std::endl; - } -} diff --git a/ch13/ex13.41.42/queryresult.cpp b/ch13/ex13.41.42/queryresult.cpp deleted file mode 100644 index f220ee1f..00000000 --- a/ch13/ex13.41.42/queryresult.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/*************************************************************************** - * @file queryresult.cpp - * @author Alan.W - * @date 06 JAN 2014 - * @remark using StrVec rather than std::vector - ***************************************************************************/ - - -#include "queryresult.h" - - -/** - * @brief print the result to the output stream specified. - * @note class QueryResult's friend - */ -std::ostream -&print(std::ostream &os, const QueryResult &qr) -{ - os << qr.sought << " occurs " << qr.sp_lines->size() << " " - << "times" << "\n"; - - //! print each line in which the word appears - for (const auto &index: *qr.sp_lines) - os << "\t(line " << index + 1 << ") " - << *(qr.sp_file->begin() + index) << "\n"; - return os; - -} diff --git a/ch13/ex13.41.42/queryresult.h b/ch13/ex13.41.42/queryresult.h deleted file mode 100644 index 76f198e4..00000000 --- a/ch13/ex13.41.42/queryresult.h +++ /dev/null @@ -1,45 +0,0 @@ -/*************************************************************************** - * @file queryresult.h - * @author Alan.W - * @date 06 JAN 2014 - * @remark using StrVec rather than std::vector - ***************************************************************************/ -#ifndef QUERYRESULT_H -#define QUERYRESULT_H - -#include -#include -#include -#include -#include -#include "textquery.h" - - -class QueryResult -{ - friend std::ostream& print(std::ostream&, const QueryResult&); - -public: - //! constructor - QueryResult(std::string s, - std::shared_ptr> sp_l, - // std::shared_ptr> sp_f) ://!@@ - std::shared_ptr sp_f) ://! - sought(s), sp_lines(sp_l), sp_file(sp_f) { } - - -private: - //! three data members - std::string sought; - std::shared_ptr> sp_lines; - //std::shared_ptr> sp_file;//!@@ - std::shared_ptr sp_file;//! - -}; - -/** - * @brief print the result to the output stream specified. - */ -std::ostream& -print(std::ostream&, const QueryResult&); -#endif // QUERYRESULT_H diff --git a/ch13/ex13.41.42/strvec.cpp b/ch13/ex13.41.42/strvec.cpp deleted file mode 100644 index be619986..00000000 --- a/ch13/ex13.41.42/strvec.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/*************************************************************************** - * @file strvec.cpp - * @author Alan.W - * @date 05 JAN 2014 - * @remark - ***************************************************************************/ - -#include "strvec.h" -#include - - -//! copy constructor -StrVec::StrVec(const StrVec &s) -{ - /** - * @brief newData is a pair of pointers pointing to newly allocated and copied - * range : [b, e) - */ - std::pair - newData = alloc_n_copy(s.begin(), s.end()); - - element = newData.first; - first_free = cap = newData.second; -} - -/** - * @brief constructor taking initializer_list - * for ex 13.40 - * @param l - */ -StrVec::StrVec(std::initializer_list l) -{ - //! allocate memory as large as l.size() - std::string * const - newData = alloc.allocate(l.size()); - - //! copy elements from l to the address allocated - auto p = newData; - for(const auto &s : l) - alloc.construct(p++, s); - - //! build the data structure - element = newData; - first_free = cap = element + l.size(); -} - - -//! operator = -StrVec& -StrVec::operator =(const StrVec& rhs) -{ - //! allocate and copy first to protect against self-assignment - std::pair - newData = alloc_n_copy(rhs.begin(), rhs.end()); - - //! destroy and deallocate - free(); - - element = newData.first; - first_free = cap = newData.second; - - return *this; -} - -//! destructor -StrVec::~StrVec() -{ - free(); -} - -/** - * @brief allocate new room if nessary and push back the new string - * @param s new string - */ -void StrVec::push_back(const std::string& s) -{ - chk_n_alloc(); - alloc.construct(first_free++, s); -} - -/** - * @brief preallocate enough memory for specified number of elements - * @param n number of elements required - * @note this function is implemented refering to StrVec::reallocate(). - */ -void StrVec::reserve(std::size_t n) -{ - //! if the n is too small, just ignore it. - if(n <= capacity()) return; - - //! allocate and move old ones into the new address. - wy_alloc_n_move(n); -} - - -/** - * @brief Resizes to the specified number of elements. - * @param n Number of elements the %vector should contain. - * - * This function will resize it to the specified - * number of elements. If the number is smaller than the - * current size it is truncated, otherwise - * default constructed elements are appended. - */ - -void StrVec::resize(std::size_t n) -{ - resize(n,std::string()); -} - -/** - * @brief Resizes it to the specified number of elements. - * @param __new_size Number of elements it should contain. - * @param __x Data with which new elements should be populated. - * - * This function will resize it to the specified - * number of elements. If the number is smaller than the - * current size the it is truncated, otherwise - * the it is extended and new elements are populated with - * given data. - */ -void StrVec::resize(std::size_t n, const std::string &s) -{ - if(n < size()) - { - //! destroy the range : [element+n, first_free) using destructor - for(auto p = element + n; p != first_free; /* empty */) - alloc.destroy(p++); - - //! move frist_free point to the new address element + n - first_free = element + n; - } - else if( n > size() ) - { - for(auto i = size(); i != n; ++i) - push_back(std::string(s)); - } -} - -/** - * @brief Double the capacity and using std::move move the original strings to the newly - * allocated memory - */ -void StrVec::reallocate() -{ - //! calculate the new capacity required. - std::size_t newCapacity = size() ? 2 * size() : 1; - - //! allocate and move old ones into the new address. - wy_alloc_n_move(newCapacity); -} - -/** - * @brief allocate new space for the given range and copy them into it - * @param b - * @param e - * @return a pair of pointers pointing to [first element , one past the last) in the new space - */ -std::pair -StrVec::alloc_n_copy(std::string *b, std::string *e) -{ - //! calculate the size needed and allocate space accordingly - std::string* data = alloc.allocate(e - b); - - return { data, std::uninitialized_copy(b, e, data) }; - //! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - //! which copies the range [first,last) into the space of which - //! the starting address p_data is pointing to. - //! This function returns a pointer pointing to one past the last element. -} - -/** - * @brief destroy the elements and deallocate the space previously allocated. - */ -void StrVec::free() -{ - - if(element) // if not nullptr - { - //! destory it in reverse order. - for(auto p = first_free; p != element; /* empty */) - alloc.destroy(--p); - - alloc.deallocate(element, capacity()); - } -} - -/** - * @brief allocate memory for spicified number of elements - * @param n - * @note it's user's responsibility to ensure that @param n is greater than - * the current capacity. - */ -void StrVec::wy_alloc_n_move(std::size_t n) -{ - std::size_t newCapacity = n; - - std::string* - newData = alloc.allocate(newCapacity); - - std::string* - dest = newData; - std::string* - elem = element; - - //! move the old to newly allocated space. - for(std::size_t i = 0; i != size(); ++i) - alloc.construct(dest++, std::move(*elem++)); - - free(); - - //! update data structure - element = newData; - first_free = dest; - cap = element + newCapacity; -} - - - diff --git a/ch13/ex13.41.42/strvec.h b/ch13/ex13.41.42/strvec.h deleted file mode 100644 index 17ccdc02..00000000 --- a/ch13/ex13.41.42/strvec.h +++ /dev/null @@ -1,72 +0,0 @@ -/*************************************************************************** - * @file strvec.h - * @author Alan.W - * @date 05 JAN 2014 - * @remark - ***************************************************************************/ - - -#ifndef STRVEC_H -#define STRVEC_H - -#include - - -class StrVec -{ -public: - //! Big 3/5. - StrVec(): - element(nullptr), first_free(nullptr), cap(nullptr) - {} - - StrVec(std::initializer_list l); - - - StrVec(const StrVec& s); - - StrVec& - operator =(const StrVec& rhs); - - ~StrVec(); - - //! public members - void push_back(const std::string &s); - - std::size_t size() const { return first_free - element; } - std::size_t capacity() const { return cap - element; } - - std::string* begin() const { return element; } - std::string* end() const { return first_free; } - - //! preallocate enough memory for specified number of elements - void reserve(std::size_t n); - - //! resize as required. - void resize(std::size_t n); - void resize(std::size_t n, const std::string& s); - -private: - - //! data members - std::string* element; // pointer to the first element - std::string* first_free; // pointer to the first free element - std::string* cap; // pointer to one past the end - - std::allocator alloc; - - //! utilities for Big 3/5 - void reallocate(); - void chk_n_alloc() { if (size() == capacity()) reallocate(); } - void free(); - - //! utilities added - //! used in reallocate() reserve() and resize(). - void wy_alloc_n_move(std::size_t n); - - std::pair - alloc_n_copy (std::string* b, std::string* e); - -}; - -#endif // STRVEC_H diff --git a/ch13/ex13.41.42/textquery.cpp b/ch13/ex13.41.42/textquery.cpp deleted file mode 100644 index d7aa0a08..00000000 --- a/ch13/ex13.41.42/textquery.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/*************************************************************************** - * @file textquery.h - * @author Alan.W - * @date 06 JAN 2014 - * @remark using StrVec rather than std::vector - ***************************************************************************/ - -#include "textquery.h" -#include "queryresult.h" -#include -#include -#include - -//! Constructor -//TextQuery::TextQuery(std::ifstream & is) : file(new std::vector)//!@@ - TextQuery::TextQuery(std::ifstream & is) : file(new StrVec() )//! -{ - //! each line - std::string line; - while(std::getline(is,line)) - { - file->push_back(line); - //! current line index - int index = file->size() - 1; - - //! for each word - std::stringstream lineSteam(line); - std::string word; - while(lineSteam >> word) - { - //! fetch the smart pointer which is null when the word first time seen - std::shared_ptr< - std::set>& sp_lineIndex = wm[word]; - - //! if null, allcate a new set to contain line indices - if(!sp_lineIndex) - sp_lineIndex.reset(new std::set); - - //! insert - sp_lineIndex->insert(index); - } - } - - //! =debugging= - std::cout << "@alan : the size of wm is " << wm.size() <<"\n"; - - for(const auto &line : *file) - std::cout<<"@alan : \t" << line << "\n"; - - /* - for(const auto &e : wm) - { - std::cout << e.first << " :\n"; - for (const auto &index : *(e.second)) - { - std::cout << index << " "; - } - std::cout << "\n"; - } - */ - //! =end= -} - -/** - * @brief do a query opertion and return QueryResult object. - */ -QueryResult -TextQuery::query(const std::string &sought) const -{ - //! dynamicaly allocated set used for the word does not appear. - static std::shared_ptr> noData(new std::set); - - //! fetch the iterator to the matching element in the map. - //std::map>>::const_iterator - auto iter = wm.find(sought); - if(iter == wm.end()) - return QueryResult(sought, noData, file); - else - return QueryResult(sought, iter->second, file); -} - diff --git a/ch13/ex13.41.42/textquery.h b/ch13/ex13.41.42/textquery.h deleted file mode 100644 index 36c4461f..00000000 --- a/ch13/ex13.41.42/textquery.h +++ /dev/null @@ -1,44 +0,0 @@ -/*************************************************************************** - * @file textquery.h - * @author Alan.W - * @date 06 JAN 2014 - * @remark using StrVec rather than std::vector - ***************************************************************************/ - - -#ifndef TEXTQUERY_H -#define TEXTQUERY_H - -#include -#include -#include -#include -#include -#include -#include "strvec.h" - -class QueryResult; - -class TextQuery -{ - -public: - //typedef std::vector::size_type index_Tp; //!@@ - typedef std::size_t index_Tp; //!06 JAN 2014 - - - //! constructor - TextQuery(std::ifstream&); - - //! member function for query operation - QueryResult - query(const std::string&) const; - -private: - //std::shared_ptr> file;//!@@ - std::shared_ptr file; //!06 JAN 2014 - std::map>> wm; -}; - -#endif // TEXTQUERY_H diff --git a/ch13/ex13.43/main.cpp b/ch13/ex13.43/main.cpp deleted file mode 100644 index c576a66c..00000000 --- a/ch13/ex13.43/main.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/*************************************************************************** - * @file main.cpp - * @author Alan.W - * @date 06 JAN 2014 - * @remark - ***************************************************************************/ -//! -//! Exercise 13.43: -//! Rewrite the free member to use for_each and a lambda (§ 10.3.2, p. 388) -//! in place of the for loop to destroy the elements. Which implementation do -//! you prefer, and why? -//! - -#include -#include "strvec.h" - - - -int main() -{ - StrVec v{"alan1","alan2","alan3"}; - - for(const auto &s: v) - std::cout << s; - - std::cout << "\nexit normally\n"; - return 0; -} diff --git a/ch13/ex13.43/strvec.cpp b/ch13/ex13.43/strvec.cpp deleted file mode 100644 index 76bfae8f..00000000 --- a/ch13/ex13.43/strvec.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/*************************************************************************** - * @file strvec.cpp - * @author Alan.W - * @date 06 JAN 2014 - * @remark Using for_each and a lambda in place of for loop in the member - * of free(). - ***************************************************************************/ - -//! -//! Exercise 13.43: -//! Rewrite the free member to use for_each and a lambda (§ 10.3.2, p. 388) -//! in place of the for loop to destroy the elements. Which implementation do -//! you prefer, and why? -// The new version is better. Compared to the old one, it doesn't need to -// worry about the order and decrement.So more straightforward and handy. -// The only thing to do for using this approach is to add "&" to build the pointers -// to string pointers. -//! - -#include "strvec.h" -#include -#include -#include - -std::allocator StrVec::alloc; - -//! copy constructor -StrVec::StrVec(const StrVec &s) -{ - /** - * @brief newData is a pair of pointers pointing to newly allocated and copied - * range : [b, e) - */ - std::pair - newData = alloc_n_copy(s.begin(), s.end()); - - element = newData.first; - first_free = cap = newData.second; -} - -/** - * @brief constructor taking initializer_list - * for ex 13.40 - * @param l - */ -StrVec::StrVec(std::initializer_list l) -{ - //! allocate memory as large as l.size() - std::string * const - newData = alloc.allocate(l.size()); - - //! copy elements from l to the address allocated - auto p = newData; - for(const auto &s : l) - alloc.construct(p++, s); - - //! build the data structure - element = newData; - first_free = cap = element + l.size(); -} - - -//! operator = -StrVec& -StrVec::operator =(const StrVec& rhs) -{ - //! allocate and copy first to protect against self-assignment - std::pair - newData = alloc_n_copy(rhs.begin(), rhs.end()); - - //! destroy and deallocate - free(); - - element = newData.first; - first_free = cap = newData.second; - - return *this; -} - -//! destructor -StrVec::~StrVec() -{ - free(); -} - -/** - * @brief allocate new room if nessary and push back the new string - * @param s new string - */ -void StrVec::push_back(const std::string& s) -{ - chk_n_alloc(); - alloc.construct(first_free++, s); -} - -/** - * @brief preallocate enough memory for specified number of elements - * @param n number of elements required - * @note this function is implemented refering to StrVec::reallocate(). - */ -void StrVec::reserve(std::size_t n) -{ - //! if the n is too small, just ignore it. - if(n <= capacity()) return; - - //! allocate and move old ones into the new address. - wy_alloc_n_move(n); -} - - -/** - * @brief Resizes to the specified number of elements. - * @param n Number of elements the %vector should contain. - * - * This function will resize it to the specified - * number of elements. If the number is smaller than the - * current size it is truncated, otherwise - * default constructed elements are appended. - */ - -void StrVec::resize(std::size_t n) -{ - resize(n,std::string()); -} - -/** - * @brief Resizes it to the specified number of elements. - * @param __new_size Number of elements it should contain. - * @param __x Data with which new elements should be populated. - * - * This function will resize it to the specified - * number of elements. If the number is smaller than the - * current size the it is truncated, otherwise - * the it is extended and new elements are populated with - * given data. - */ -void StrVec::resize(std::size_t n, const std::string &s) -{ - if(n < size()) - { - //! destroy the range : [element+n, first_free) using destructor - for(auto p = element + n; p != first_free; /* empty */) - alloc.destroy(p++); - - //! move frist_free point to the new address element + n - first_free = element + n; - } - else if( n > size() ) - { - for(auto i = size(); i != n; ++i) - push_back(std::string(s)); - } -} - -/** - * @brief Double the capacity and using std::move move the original strings to the newly - * allocated memory - */ -void StrVec::reallocate() -{ - //! calculate the new capacity required. - std::size_t newCapacity = size() ? 2 * size() : 1; - - //! allocate and move old ones into the new address. - wy_alloc_n_move(newCapacity); -} - -/** - * @brief allocate new space for the given range and copy them into it - * @param b - * @param e - * @return a pair of pointers pointing to [first element , one past the last) in the new space - */ -std::pair -StrVec::alloc_n_copy(std::string *b, std::string *e) -{ - //! calculate the size needed and allocate space accordingly - std::string* data = alloc.allocate(e - b); - - return { data, std::uninitialized_copy(b, e, data) }; - //! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - //! which copies the range [first,last) into the space of which - //! the starting address p_data is pointing to. - //! This function returns a pointer pointing to one past the last element. -} - -/** - * @brief destroy the elements and deallocate the space previously allocated. - */ -void StrVec::free() -{ - if(element) // if not nullptr - { - /** @oldcode - * using for loop, destory it in reverse order. - * 05 JAN 2014 - */ -// for(auto p = first_free; p != element; ) -// alloc.destroy(--p); - - /** @newcode - * using std::for_each and a lambda - * 06 JAN 2014 - */ - std::for_each(element,first_free,[this](std::string& p){ - alloc.destroy(&p); - }); - - alloc.deallocate(element, capacity()); - } -} - -/** - * @brief allocate memory for spicified number of elements - * @param n - * @note it's user's responsibility to ensure that @param n is greater than - * the current capacity. - */ -void StrVec::wy_alloc_n_move(std::size_t n) -{ - std::size_t newCapacity = n; - - std::string* - newData = alloc.allocate(newCapacity); - - std::string* - dest = newData; - std::string* - elem = element; - - //! move the old to newly allocated space. - for(std::size_t i = 0; i != size(); ++i) - alloc.construct(dest++, std::move(*elem++)); - - free(); - - //! update data structure - element = newData; - first_free = dest; - cap = element + newCapacity; -} diff --git a/ch13/ex13.43/strvec.h b/ch13/ex13.43/strvec.h deleted file mode 100644 index 66db89e4..00000000 --- a/ch13/ex13.43/strvec.h +++ /dev/null @@ -1,72 +0,0 @@ -/*************************************************************************** - * @file strvec.h - * @author Alan.W - * @date 05 JAN 2014 - * @remark - ***************************************************************************/ - - -#ifndef STRVEC_H -#define STRVEC_H - -#include - - -class StrVec -{ -public: - //! Big 3/5. - StrVec(): - element(nullptr), first_free(nullptr), cap(nullptr) - {} - - StrVec(std::initializer_list l); - - - StrVec(const StrVec& s); - - StrVec& - operator =(const StrVec& rhs); - - ~StrVec(); - - //! public members - void push_back(const std::string &s); - - std::size_t size() const { return first_free - element; } - std::size_t capacity() const { return cap - element; } - - std::string* begin() const { return element; } - std::string* end() const { return first_free; } - - //! preallocate enough memory for specified number of elements - void reserve(std::size_t n); - - //! resize as required. - void resize(std::size_t n); - void resize(std::size_t n, const std::string& s); - -private: - - //! data members - std::string* element; // pointer to the first element - std::string* first_free; // pointer to the first free element - std::string* cap; // pointer to one past the end - - static std::allocator alloc; - - //! utilities for Big 3/5 - void reallocate(); - void chk_n_alloc() { if (size() == capacity()) reallocate(); } - void free(); - - //! utilities added - //! used in reallocate() reserve() and resize(). - void wy_alloc_n_move(std::size_t n); - - std::pair - alloc_n_copy (std::string* b, std::string* e); - -}; - -#endif // STRVEC_H diff --git a/ch13/ex13_40.cpp b/ch13/ex13_40.cpp new file mode 100644 index 00000000..107cdd0c --- /dev/null +++ b/ch13/ex13_40.cpp @@ -0,0 +1,107 @@ +// +// ex13_40.cpp +// Exercise 13.40 +// +// Created by pezy on 2/3/15. +// Copyright (c) 2015 pezy. All rights reserved. +// +// Add a constructor that takes an initializer_list to your StrVec class. +// + +#include "StrVec.h" + +void StrVec::push_back(const std::string &s) +{ + chk_n_alloc(); + alloc.construct(first_free++, s); +} + +std::pair +StrVec::alloc_n_copy(const std::string *b, const std::string *e) +{ + auto data = alloc.allocate(e-b); + return { data, std::uninitialized_copy(b, e, data) }; +} + +void StrVec::free() +{ + if (elements) { + for (auto p = first_free; p != elements;) + alloc.destroy(--p); + alloc.deallocate(elements, cap - elements); + } +} + +void StrVec::range_initialize(const std::string *first, const std::string *last) +{ + auto newdata = alloc_n_copy(first, last); + elements = newdata.first; + first_free = cap = newdata.second; +} + +StrVec::StrVec(const StrVec &rhs) +{ + range_initialize(rhs.begin(), rhs.end()); +} + +StrVec::StrVec(std::initializer_list il) +{ + range_initialize(il.begin(), il.end()); +} + +StrVec::~StrVec() +{ + free(); +} + +StrVec& StrVec::operator = (const StrVec &rhs) +{ + auto data = alloc_n_copy(rhs.begin(), rhs.end()); + free(); + elements = data.first; + first_free = cap = data.second; + return *this; +} + +void StrVec::alloc_n_move(size_t new_cap) +{ + auto newdata = alloc.allocate(new_cap); + auto dest = newdata; + auto elem = elements; + for (size_t i = 0; i != size(); ++i) + alloc.construct(dest++, std::move(*elem++)); + free(); + elements = newdata; + first_free = dest; + cap = elements + new_cap; +} + +void StrVec::reallocate() +{ + auto newcapacity = size() ? 2 * size() : 1; + alloc_n_move(newcapacity); +} + +void StrVec::reserve(size_t new_cap) +{ + if (new_cap <= capacity()) return; + alloc_n_move(new_cap); +} + +void StrVec::resize(size_t count) +{ + resize(count, std::string()); +} + +void StrVec::resize(size_t count, const std::string &s) +{ + if (count > size()) { + if (count > capacity()) reserve(count * 2); + for (size_t i = size(); i != count; ++i) + alloc.construct(first_free++, s); + } + else if (count < size()) { + while (first_free != elements + count) + alloc.destroy(--first_free); + } +} diff --git a/ch13/ex13_40.h b/ch13/ex13_40.h new file mode 100644 index 00000000..3a79b3c2 --- /dev/null +++ b/ch13/ex13_40.h @@ -0,0 +1,53 @@ +// +// ex13_40.h +// Exercise 13.40 +// +// Created by pezy on 2/3/15. +// Copyright (c) 2015 pezy. All rights reserved. +// +// Add a constructor that takes an initializer_list to your StrVec class. +// + +#ifndef CP5_EX_13_40_H_ +#define CP5_EX_13_40_H_ + +#include +#include +#include + +class StrVec +{ +public: + StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {} + StrVec(const StrVec&); + StrVec(std::initializer_list); + StrVec& operator=(const StrVec&); + ~StrVec(); + + void push_back(const std::string&); + size_t size() const { return first_free - elements; } + size_t capacity() const { return cap - elements; } + std::string *begin() const { return elements; } + std::string *end() const { return first_free; } + + void reserve(size_t new_cap); + void resize(size_t count); + void resize(size_t count, const std::string&); + +private: + std::pair alloc_n_copy(const std::string*, const std::string*); + void free(); + void chk_n_alloc() { if (size() == capacity()) reallocate(); } + void reallocate(); + void alloc_n_move(size_t new_cap); + void range_initialize(const std::string*, const std::string*); + +private: + std::string *elements; + std::string *first_free; + std::string *cap; + std::allocator alloc; +}; + +#endif + diff --git a/ch13/ex13_42.cpp b/ch13/ex13_42.cpp new file mode 100644 index 00000000..e7053ca9 --- /dev/null +++ b/ch13/ex13_42.cpp @@ -0,0 +1,19 @@ +#include "ex13_42_TextQuery.h" +#include + +void runQueries(std::ifstream &infile) +{ + TextQuery tq(infile); + while (true) { + std::cout << "enter word to look for, or q to quit: "; + std::string s; + if (!(std::cin >> s) || s == "q") break; + print(std::cout, tq.query(s)) << std::endl; + } +} + +int main() +{ + std::ifstream file("../data/storyDataFile.txt"); + runQueries(file); +} diff --git a/ch13/ex13_42_StrVec.cpp b/ch13/ex13_42_StrVec.cpp new file mode 100644 index 00000000..467b5404 --- /dev/null +++ b/ch13/ex13_42_StrVec.cpp @@ -0,0 +1,97 @@ +#include "ex13_42_StrVec.h" + +void StrVec::push_back(const std::string &s) +{ + chk_n_alloc(); + alloc.construct(first_free++, s); +} + +std::pair +StrVec::alloc_n_copy(const std::string *b, const std::string *e) +{ + auto data = alloc.allocate(e-b); + return { data, std::uninitialized_copy(b, e, data) }; +} + +void StrVec::free() +{ + if (elements) { + for (auto p = first_free; p != elements;) + alloc.destroy(--p); + alloc.deallocate(elements, cap - elements); + } +} + +void StrVec::range_initialize(const std::string *first, const std::string *last) +{ + auto newdata = alloc_n_copy(first, last); + elements = newdata.first; + first_free = cap = newdata.second; +} + +StrVec::StrVec(const StrVec &rhs) +{ + range_initialize(rhs.begin(), rhs.end()); +} + +StrVec::StrVec(std::initializer_list il) +{ + range_initialize(il.begin(), il.end()); +} + +StrVec::~StrVec() +{ + free(); +} + +StrVec& StrVec::operator = (const StrVec &rhs) +{ + auto data = alloc_n_copy(rhs.begin(), rhs.end()); + free(); + elements = data.first; + first_free = cap = data.second; + return *this; +} + +void StrVec::alloc_n_move(size_t new_cap) +{ + auto newdata = alloc.allocate(new_cap); + auto dest = newdata; + auto elem = elements; + for (size_t i = 0; i != size(); ++i) + alloc.construct(dest++, std::move(*elem++)); + free(); + elements = newdata; + first_free = dest; + cap = elements + new_cap; +} + +void StrVec::reallocate() +{ + auto newcapacity = size() ? 2 * size() : 1; + alloc_n_move(newcapacity); +} + +void StrVec::reserve(size_t new_cap) +{ + if (new_cap <= capacity()) return; + alloc_n_move(new_cap); +} + +void StrVec::resize(size_t count) +{ + resize(count, std::string()); +} + +void StrVec::resize(size_t count, const std::string &s) +{ + if (count > size()) { + if (count > capacity()) reserve(count * 2); + for (size_t i = size(); i != count; ++i) + alloc.construct(first_free++, s); + } + else if (count < size()) { + while (first_free != elements + count) + alloc.destroy(--first_free); + } +} diff --git a/ch13/ex13_42_StrVec.h b/ch13/ex13_42_StrVec.h new file mode 100644 index 00000000..bd6e89ee --- /dev/null +++ b/ch13/ex13_42_StrVec.h @@ -0,0 +1,46 @@ +#ifndef CP5_STRVEC_H_ +#define CP5_STRVEC_H_ + +#include +#include +#include + +class StrVec +{ +public: + StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {} + StrVec(const StrVec&); + StrVec(std::initializer_list); + StrVec& operator=(const StrVec&); + ~StrVec(); + + void push_back(const std::string&); + size_t size() const { return first_free - elements; } + size_t capacity() const { return cap - elements; } + std::string *begin() const { return elements; } + std::string *end() const { return first_free; } + + std::string& at(size_t pos) { return *(elements + pos); } + const std::string& at(size_t pos) const { return *(elements + pos); } + + void reserve(size_t new_cap); + void resize(size_t count); + void resize(size_t count, const std::string&); + +private: + std::pair alloc_n_copy(const std::string*, const std::string*); + void free(); + void chk_n_alloc() { if (size() == capacity()) reallocate(); } + void reallocate(); + void alloc_n_move(size_t new_cap); + void range_initialize(const std::string*, const std::string*); + +private: + std::string *elements; + std::string *first_free; + std::string *cap; + std::allocator alloc; +}; + +#endif + diff --git a/ch13/ex13_42_TextQuery.cpp b/ch13/ex13_42_TextQuery.cpp new file mode 100644 index 00000000..55246ac6 --- /dev/null +++ b/ch13/ex13_42_TextQuery.cpp @@ -0,0 +1,39 @@ +#include "ex13_42_TextQuery.h" +#include +#include + +using std::string; + +TextQuery::TextQuery(std::ifstream &ifs) : input(new StrVec) +{ + size_t lineNo = 0; + for (string line; std::getline(ifs, line); ++lineNo) { + input->push_back(line); + std::istringstream line_stream(line); + for (string text, word; line_stream >> text; word.clear()) { + // avoid read a word followed by punctuation(such as: word, ) + std::remove_copy_if(text.begin(), text.end(), std::back_inserter(word), ispunct); + // use reference avoid count of shared_ptr add. + auto &nos = result[word]; + if (!nos) nos.reset(new std::set); + nos->insert(lineNo); + } + } +} + +QueryResult TextQuery::query(const string& str) const +{ + // use static just allocate once. + static std::shared_ptr> nodate(new std::set); + auto found = result.find(str); + if (found == result.end()) return QueryResult(str, nodate, input); + else return QueryResult(str, found->second, input); +} + +std::ostream& print(std::ostream &out, const QueryResult& qr) +{ + out << qr.word << " occurs " << qr.nos->size() << (qr.nos->size() > 1 ? " times" : " time") << std::endl; + for (auto i : *qr.nos) + out << "\t(line " << i+1 << ") " << qr.input->at(i) << std::endl; + return out; +} diff --git a/ch13/ex13_42_TextQuery.h b/ch13/ex13_42_TextQuery.h new file mode 100644 index 00000000..55ddffe6 --- /dev/null +++ b/ch13/ex13_42_TextQuery.h @@ -0,0 +1,36 @@ +#ifndef CP5_TEXTQUERY_H_ +#define CP5_TEXTQUERY_H_ + +#include +#include +#include +#include +#include +#include + +#include "ex13_42_StrVec.h" + +class QueryResult; +class TextQuery { +public: + TextQuery(std::ifstream &); + QueryResult query(const std::string&) const; +private: + std::shared_ptr input; + std::map>> result; +}; + +class QueryResult { +public: + friend std::ostream& print(std::ostream &, const QueryResult&); +public: + QueryResult(const std::string &s, std::shared_ptr> set, std::shared_ptr v) : word(s), nos(set), input(v) {} +private: + std::string word; + std::shared_ptr> nos; + std::shared_ptr input; +}; + +std::ostream& print(std::ostream &, const QueryResult&); + +#endif diff --git a/ch13/ex13.44/string.cpp b/ch13/ex13_44.cpp similarity index 100% rename from ch13/ex13.44/string.cpp rename to ch13/ex13_44.cpp diff --git a/ch13/ex13.44/string.h b/ch13/ex13_44.h similarity index 100% rename from ch13/ex13.44/string.h rename to ch13/ex13_44.h diff --git a/ch13/ex13.44/main.cpp b/ch13/ex13_44_TEST.cpp similarity index 100% rename from ch13/ex13.44/main.cpp rename to ch13/ex13_44_TEST.cpp