Hello again,
Please find attached the last iteration of the ParagraphList rewrite.
It's updated to take into account Angus and Lars recent comment. I have
tested it as usual and I cannot see anything wrong with it.
I am a bit fad up with it so take it please.
Abdel.
Index: D:/msys/home/yns/src/lyx-svn/trunk/src/paragraph.C
===================================================================
--- D:/msys/home/yns/src/lyx-svn/trunk/src/paragraph.C (revision 13339)
+++ D:/msys/home/yns/src/lyx-svn/trunk/src/paragraph.C (working copy)
@@ -66,10 +66,6 @@
using std::ostringstream;
-ParagraphList::ParagraphList()
-{}
-
-
Paragraph::Paragraph()
: begin_of_body_(0), pimpl_(new Paragraph::Pimpl(this))
{
Index: D:/msys/home/yns/src/lyx-svn/trunk/src/ParagraphList_fwd.h
===================================================================
--- D:/msys/home/yns/src/lyx-svn/trunk/src/ParagraphList_fwd.h (revision 13339)
+++ D:/msys/home/yns/src/lyx-svn/trunk/src/ParagraphList_fwd.h (working copy)
@@ -7,27 +7,37 @@
* \author Angus Leeming
*
* Full author contact details are available in file CREDITS.
+ *
+ * \todo Rename this file to ParagraphList.h
*/
#ifndef PARAGRAPH_LIST_FWD_H
#define PARAGRAPH_LIST_FWD_H
#include "paragraph.h"
+#include "RandomAccessList.h"
-#include <vector>
+/// Container for all kind of Paragraphs used in Lyx.
+/**
+The line below could have been enougth
+ typedef RandomAccessList<Paragraph> ParagraphList;
-class ParagraphList : public std::vector<Paragraph>
+but in order to let other files that forward declare ParagraphList, we
+have to derive it from RandomAccessList.
+And then there might be some useful specialisation depending on the
+type of Paragraph we want to store... food for thought.
+*/
+
+class ParagraphList: public RandomAccessList<Paragraph>
{
public:
- ///
- typedef std::vector<Paragraph> BaseType;
- ///
- ParagraphList();
- ///
- template <class Iter>
- ParagraphList(Iter beg, Iter end)
- : BaseType(beg, end)
- {}
+ ParagraphList()
+ : RandomAccessList<Paragraph> () {}
+ ParagraphList(ParagraphList const & ext_list, size_t pos, size_t length)
+ : RandomAccessList<Paragraph> (ext_list, pos, length) {}
+ template<class It>
+ ParagraphList(It it_start, It it_end)
+ : RandomAccessList<Paragraph> (it_start, it_end) {}
};
#endif
// -*- C++ -*-
/**
* \file RandomAccessList.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Abdelrazak Younes
*
* Full author contact details are available in file CREDITS.
*
*/
#ifndef RANDOM_ACESS_LIST_H
#define RANDOM_ACESS_LIST_H
#include "debug.h"
#include <boost/utility.hpp>
#include <vector>
#include <list>
#include <algorithm>
using std::endl;
/// Random Access List.
/**
This templatized class provide a std::vector like interface to a
standard std::list underneath. An important property is that it
keeps the std::list::iterator interface. A typical use would be:
typedef RandomAccessList<some_class> MyContainer;
Then you can use MyContainer as if it was a standard
std::vector<some_class> for operator[] access and as if it was a
standard std::list for iterator access. The main difference with
std::vector is that insertion of elements is much less costly. Compared
to a standard list alone, there is of course a small overhead because
the class always keeps its internal vector of iterator (it_vector_) up
to date.
*/
template <class T>
class RandomAccessList
{
protected:
typedef std::list<T> Container;
typedef typename Container::const_iterator BaseConstIt;
typedef typename Container::iterator BaseIt;
public:
typedef T value_type;
typedef typename Container::difference_type difference_type;
typedef size_t size_type;
///
class iterator: public Container::iterator
{
public:
iterator() {
}
iterator(BaseIt const & it) {
Container::iterator::operator=(it);
}
iterator & operator+=(difference_type pos) {
std::advance(*this, pos);
return *this;
}
iterator operator+(difference_type pos) const {
return boost::next(*this,pos);
}
difference_type operator-(iterator it2) const {
return std::distance(it2, *this);
}
};
///
class const_iterator: public Container::const_iterator
{
public:
const_iterator() {
}
const_iterator(BaseConstIt const & it) {
Container::const_iterator::operator=(it);
}
const_iterator(iterator const & it) {
Container::const_iterator::operator=(static_cast<BaseIt>(it));
}
const_iterator & operator+=(difference_type pos) {
std::advance(*this, pos);
return *this;
}
const_iterator operator+(difference_type pos) const {
return boost::next(*this, pos);
}
difference_type operator-(const_iterator it2) const {
return std::distance(it2, *this);
}
};
private:
/// Our container.
Container container_;
/// Our vector of container iterator.
std::vector<iterator> it_vector_;
public:
///
RandomAccessList() {
}
/// Copy constructor.
RandomAccessList(RandomAccessList const & ext_list) {
it_vector_.reserve(ext_list.size());
size_t end = ext_list.size();
for (size_t i = 0; i != end; ++i)
push_back(ext_list[i]);
}
/// Partial copy constructor.
/**
Copy "length" elements from ext_list beginning at pos.
*/
RandomAccessList(RandomAccessList const & ext_list, size_t pos, size_t
length) {
it_vector_.reserve(length);
size_t end = pos + length;
BOOST_ASSERT(end <= ext_list.size());
for (size_t i = pos; i != end; ++i)
push_back(ext_list[i]);
}
/// Construct a new RandomAccessList by copying elements pointed from
it_start to it_end.
template<class It>
RandomAccessList(It it_start, It it_end) {
for (It it = it_start; it != it_end; ++it)
push_back(*it);
}
///
value_type & operator[](size_t pos) {
return at(pos);
}
///
value_type const & operator[](size_t pos) const {
return at(pos);
}
///
iterator operator()(size_t pos) {
return it_vector_[pos];
}
///
const_iterator operator()(size_t pos) const {
return it_vector_[pos];
}
///
RandomAccessList & operator=(RandomAccessList const & ext_list) {
assign(ext_list);
return *this;
}
/// Copy ext_list.
void assign(RandomAccessList const & ext_list) {
assign(ext_list, 0, ext_list.size());
}
/// Copy ext_list from it_start to it_end.
template<class It>
void assign(It it_start, It it_end) {
clear();
for (It it = it_start; it != it_end; ++it)
push_back(*it);
}
/// Copy "length" elements from ext_list beginning at pos.
void assign(RandomAccessList const & ext_list, size_t pos, size_t
length) {
clear();
size_t end = pos + length;
for (size_t i = pos; i != end; ++i)
push_back(ext_list[i]);
}
value_type & at(size_t pos) {
// Make sure it_vector_ and container_ are always in sync.
BOOST_ASSERT(it_vector_[pos]==boost::next(container_.begin(),pos));
return *it_vector_[pos];
}
/// \todo remove first test (pos >= it_vector_.size()) when output_*.C
has been verified.
value_type const & at(size_t pos) const {
// Make sure it_vector_ and container_ are always in sync.
BOOST_ASSERT(it_vector_[pos]==boost::next(container_.begin(),pos));
return *it_vector_[pos];
}
size_t size() const {
return it_vector_.size();
}
const_iterator begin() const {
return container_.begin();
}
iterator begin() {
return container_.begin();
}
const_iterator end() const {
return container_.end();
}
iterator end() {
return container_.end();
}
value_type & back() {
return container_.back();
}
value_type const & back() const {
return container_.back();
}
value_type & front() {
return container_.front();
}
value_type const & front() const {
return container_.front();
}
bool empty() const {
return container_.empty();
}
void clear() {
container_.clear();
it_vector_.clear();
}
/// Erases 'length' elements starting from pos.
/**
\todo This could be optimized a bit by rebuilding ItVector instead of
multiple deletion.
Comments from Angus: use std::remove_if and vector<>::erase, passing the
same predicate to remove_if as is used by erase(size_t);
Refactor the other erase() member funtions to use this predicate
also?
std::remove_if doesn't actually remove anything from the vector. It
simply rearranges the
contents so that the stuff to be removed is all at the end, making it
trivial
(and cheap) to then used "itVector_.erase(it, itVector_.end());" to
resize the
vector. (it here is the iterator returned by std::remove_if). You just
need to
write the predicate that would actually flag up elements for removal.
*/
bool erase(size_t pos, size_t length) {
bool result = true;
size_t end = pos + length;
for (size_t i = pos; i != end; ++i)
result = result && erase(i);
return result;
}
/// Erases last element.
void pop_back() {
lyxerr[Debug::ACTION] << "pop_back from Container"<< endl;
container_.pop_back();
it_vector_.pop_back();
lyxerr[Debug::ACTION] << "pop_back done"<< endl;
}
/// Erases the element at position pos.
bool erase(size_t pos) {
if (pos >= it_vector_.size()) {
lyxerr[Debug::ACTION] << "trying to erase element at "
<< pos << " while size is "<< size() << endl;
// What happened here?
return false;
}
if (pos == it_vector_.size() - 1) {
pop_back();
return true;
}
lyxerr[Debug::ACTION] << "erasing element from Container at "
<< pos << endl;
container_.erase(it_vector_[pos]);
it_vector_.erase(it_vector_.begin() + pos);
lyxerr[Debug::ACTION] << "erasing done"<< endl;
return true;
}
bool erase(iterator it) {
size_t pos = std::distance(container_.begin(),
static_cast<BaseIt>(it));
return erase(pos);
}
bool erase(iterator start, iterator end) {
size_t const startpos = std::distance(container_.begin(),
static_cast<BaseIt>(start));
size_t const endpos = std::distance(container_.begin(),
static_cast<BaseIt>(end));
return erase(startpos, endpos - startpos);
}
void push_back(value_type const & new_element)
{
lyxerr[Debug::ACTION] << "push_back new_element in Container"<<
endl;
iterator it = container_.insert(container_.end(), new_element);
it_vector_.push_back(it);
lyxerr[Debug::ACTION] << "push_back done"<< endl;
}
/// Inserts the contents of an external container at position pos.
/**
The subsequent elements are shifted toward the end.
\todo This could be optimized a bit by rebuilding ItVector instead of
multiple insertion.
*/
template<class SomeContainer>
bool insert(size_t pos, SomeContainer const & some_container) {
bool result = true;
size_t i = pos;
typedef typename SomeContainer::const_iterator It;
It it_end = some_container.end();
for (It it = some_container.begin(); it != it_end; ++it) {
result = result && insert(i, *it);
++i;
}
return result;
}
/// Inserts an external RandomAccessList at position pos.
/**
The subsequent elements are shifted toward the end.
\todo This could be optimized a bit by rebuilding ItVector instead of
multiple insertion
and maybe using list::splice.
*/
bool insert(size_t pos, RandomAccessList const & ext_list, size_t
ext_pos, size_t length) {
bool result = true;
size_t i = pos;
size_t ext_end = ext_pos + length;
for (size_t j = ext_pos; j != ext_end; ++j) {
result = result && insert(i, ext_list[j]);
++i;
}
return result;
}
/// Inserts external elements pointed by iterator it_start and it_end
at position pos.
/**
The subsequent elements are shifted toward the end.
\return the position after the last inserted element.
\todo This could be optimized a bit by rebuilding ItVector instead of
multiple insertion
and maybe using list::splice.
*/
template<class It>
size_t insert(size_t pos, It it_start, It it_end) {
bool result = true;
size_t i = pos;
for (It it = it_start; it != it_end; ++it) {
result = result && insert(i, *it);
++i;
}
if (result)
return i;
return size();
}
/// Inserts external elements pointed by iterator it_start and it_end
before element pointed by it.
/**
The subsequent elements are shifted toward the end.
\return the iterator after the last inserted element.
\todo This could be optimized a bit by rebuilding ItVector instead of
multiple insertion
and maybe using list::splice.
*/
template<class It>
iterator insert(iterator it, It it_start, It it_end) {
size_t pos = std::distance(container_.begin(),
static_cast<BaseIt>(it));
pos = insert(pos, it_start, it_end);
if (pos < size())
return it_vector_[pos];
return container_.end();
}
/// Inserts new_element at position pos.
/// The subsequent value_types are shifted toward the end.
bool insert(size_t pos, value_type const & new_element) {
if (pos > it_vector_.size()) {
lyxerr[Debug::ACTION] << "trying to insert element at "
<< pos << " while size is "<< size() << endl;
// What happened here?
return false;
}
if (pos == it_vector_.size()) {
push_back(new_element);
return true;
}
lyxerr[Debug::ACTION] << "inserting new_element in Container at
"<< pos << endl;
iterator it = container_.insert(it_vector_[pos], new_element);
it_vector_.insert(it_vector_.begin() + pos, it);
lyxerr[Debug::ACTION] << "insertion done"<< endl;
return true;
}
/// Inserts new_element before element pointed by iterator it.
/**
\return The iterator pointing to the newly inserted element
or container_.end() if the insertion did not succeed.
*/
iterator insert(iterator it, value_type const & new_element) {
size_t pos = std::distance(container_.begin(),
static_cast<BaseIt>(it));
if (insert(pos, new_element))
return it_vector_[pos];
return container_.end();
}
}; // RandomAccessList
#endif