読者です 読者をやめる 読者になる 読者になる

コンテナslistの実装:プログラミング原論(ステパノフ)の補助資料

プログラミング原論(ステパノフ)のサンプルコードはここにあるのですが、1万行を超えていることもあり、少し読むのに時間もかかります。ということで、単方向リンクリスト(slist)に関係するところだけ引っ張り出して、テストを書いてみました。他のコンテナ(list, slist, array..)も同じような関数でできているので、他の部分を読むのにも役立つと思います。

#include<cstddef>// NULL, ptrdiff_t
#include<new>// placement operator new
#include<cassert>// assert
#include<cstdlib>// malloc, free
template<typename T>
bool operator!=(const T& x, const T& y) {
  return !(x == y);
}
#define pointer(T) T*
template<typename T>
T& sink(pointer(T) x) {
  return *x;
}
template<typename T>
T& source(pointer(T) x) {
  return *x;
}
template<typename T>
T& deref(pointer(T) x) {
  return *x;
}
template<typename T>
pointer(T) successor(pointer(T) x) {
  return x + ptrdiff_t(1);
}
template<typename S>
struct iterator_type;
#define IteratorType(S) typename iterator_type<S>::type
template<typename T>
struct value_type;
#define ValueType(T) typename value_type<T>::type
template<typename T>
struct underlying_type {
  typedef T type;
};
#define UnderlyingType(T) typename underlying_type<T>::type
template<typename T>
UnderlyingType(T)& underlying_ref(T& x) {
  return reinterpret_cast<UnderlyingType(T)&>(x);
}
template<typename W>
bool empty(const W& x) {
  return begin(x) == end(x);
}
template<typename T>
struct slist_node {
  T value;
  pointer(slist_node) forward_link;
  slist_node(const T& v, pointer(slist_node) f): value(v), forward_link(f) {} 
};
template<typename T>
struct slist_iterator {
  pointer(slist_node<T>) p;
  slist_iterator(): p(NULL) {}
  slist_iterator(pointer(slist_node<T>) p): p(p) {}
};
template<typename T>
bool operator==(const slist_iterator<T>& x, const slist_iterator<T>& y) {
  return x.p == y.p;
}
template<typename T>
const T& source(slist_iterator<T> x) {
  return source(x.p).value;
}
template<typename T>
T& sink(slist_iterator<T> x) {
  return sink(x.p).value;
}
template<typename T>
void set_link_forward(slist_iterator<T> i, slist_iterator<T> j) {
  sink(i.p).forward_link = j.p;
}
template<typename T>
slist_iterator<T>  successor(const slist_iterator<T>& x) {
  return slist_iterator<T>(sink(x.p).forward_link);
}
template<typename T>
struct slist {
  slist_iterator<T> first;
  slist(): first(NULL) {}
  template<typename W>
  slist(const W& w) {
    dynamic_sequence_construction(sink(this), w);
  }
  ~slist() {
    erase_all(sink(this));
  }
};
template<typename T>
struct underlying_type< slist<T> > {
  typedef slist_iterator<T> type;
};
template<typename T>
struct value_type< slist<T> > {
  typedef T type;
};
template<typename T>
struct iterator_type< slist<T> > {
  typedef slist_iterator<T> type;
};
template<typename T>
IteratorType(slist<T>) begin(const slist<T>& x) {
  return x.first;
}
template<typename T>
IteratorType(slist<T>) end(const slist<T>&) {
  return slist_iterator<T>();
}
template<typename S>
struct after {
  typedef IteratorType(S) I;
  pointer(S) s;
  I i;
  after(S& s, I i): s(&s), i(i) {}
};
template<typename S>
struct value_type< after<S> >{
  typedef ValueType(S) type;
};
template<typename S>
S& base(after<S>& p) {
  return deref(p.s);
}
template<typename S>
IteratorType(S) current(after<S>& x) {
  return x.i;
}
template<typename S>
IteratorType(S) begin(after<S>& x) {
  return begin(base(x));
}
template<typename S>
IteratorType(S) end(after<S>& x) {
  return end(base(x));
}
template<typename T>
void construct(T& p) {
  new (&p) T();
}
template<typename T, typename U>
void construct(T& p, const U& initializer) {
  new (&p) T(initializer);
}
template<typename T>
void destroy(T& p) {
  sink(&p).~T();
}
template<typename T, typename U>
void insert_0(after< slist<T> >& p, const U& u) {
  assert(current(p) == end(p));
  slist_iterator<T> i((slist_node<T>*)malloc(sizeof(slist_node<T>)));
  construct(sink(i), u);
  set_link_forward(i, begin(p));
  base(p).first = i;
}
void test_insert_after_0(void) {
  typedef int Z;
  slist<Z> s;
  after< slist<Z> >  w(s, end(s));
  insert_0(w, Z(2));
  assert(Z(2) == source(s.first));
}
template<typename T, typename U>
after< slist<T> > insert(after< slist<T> >& p, const U& u) {
  slist_iterator<T> i((slist_node<T>*)malloc(sizeof(slist_node<T>)));
  construct(sink(i), u); 
  if(current(p) == end(p)) {
    set_link_forward(i, begin(p));
    base(p).first = i;
  } else {
    set_link_forward(i, successor(current(p)));
    set_link_forward(current(p), i);
  }
  return after< slist<T> >(base(p), i);
}
void test_insert_after(void) {
  typedef int Z;
  slist<Z> s;
  after< slist<Z> >  w(s, end(s));
  int i;
  for(i = 0; i < 6; i++)
    w = insert(w, Z(i));
  slist_iterator<Z> p = s.first;
  for(i = 0; i < 6; i ++) {
    assert(Z(i) == source(p));
    p = successor(p);
  }
}
template<typename T>
struct distance_type;
#define DistanceType(T) typename distance_type<T>::type
template<typename T>
struct distance_type<pointer(T)> {
  typedef T type;
};
template<typename I>
struct counted_range{
  typedef DistanceType(I) N;
  N n;
  I f;
  counted_range(I f, N n): f(f), n(n) {}
};
template<typename I>
struct iterator_type< counted_range<I> > {
  typedef I type;
};
template<typename I>
I begin(const counted_range<I>& x) {
  return x.f;
}
template<typename I>
I end(const counted_range<I>& x) {
  return x.f + x.n;
}
template<typename I, typename O>
void copy_step(I& f_i, O& f_o) {
  sink(f_o) = source(f_i);
  f_i = successor(f_i);
  f_o = successor(f_o);
}
template<typename I, typename O>
void copy(I f_i, I f_l, O f_o) {
  while(f_i != f_l) copy_step(f_i, f_o);
}
void test_copy(void) {
  typedef int Z;
  slist<Z> s;
  after< slist<Z> >  w(s, end(s));
  int i;
  for(i = 0; i < 6; i++)
    w = insert(w, Z(i));
  Z a[6];
  counted_range<Z*> s2(a, sizeof(a)/sizeof(a[0]));  
  copy(begin(s), end(s), begin(s2));
  for(i = 0; i < 6; i++)
    assert(a[i] == i);
}
template<typename P>
struct insert_iterator {
  P p;
  insert_iterator(const P& p): p(p) {}
  void operator=(const ValueType(P)& x) { p = insert(p, x);}
};
template<typename P>
insert_iterator<P> successor(const insert_iterator<P>& x) {
  return x;
}
template<typename P>
insert_iterator<P>& sink(insert_iterator<P>& i) {
  return i;
}
template<typename P, typename W>
void insert_range(P p, const W& w) {
 copy(begin(w), end(w), insert_iterator<P>(p));
}
void test_insert_range(void) {
  typedef int Z;
  Z a[] = {0,1,2,3,4,5};
  slist<Z> s;
  after< slist<Z> > p(s, end(s));
  insert_range(p, counted_range<Z*>(a, sizeof(a)/sizeof(a[0])));
  int i = 0;
  slist_iterator<Z> f = begin(s);
  slist_iterator<Z> l = end(s);
  while(f != l) {
    assert(source(f) == i++);
    f = successor(f);
  }
}
template<typename T>
void swap(T& x, T& y) {
  UnderlyingType(T) tmp = underlying_ref(x);
  underlying_ref(x) = underlying_ref(y);
  underlying_ref(y) = tmp;
}
template<typename S, typename W>
void dynamic_sequence_construction(S& s, const W& w) {
  construct(s);
  S tmp;
  insert_range(after<S>(tmp, end(tmp)), w);
  swap(s, tmp);
}
void test_dynamic_sequence_construction(void) {
  typedef int Z;
  Z a[] = {0,1,2,3,4,5};
  slist<Z> s(counted_range<Z*>(a, sizeof(a)/sizeof(a[0])));
  slist_iterator<Z> f = begin(s);
  slist_iterator<Z> l = end(s);
  int i = 0;
  while(f != l) {
    assert(source(f) == i++);
    f = successor(f);
  }
  assert(6 == i);
}
template<typename T>
slist_iterator<T> erase_first(slist_iterator<T> i) {
  slist_iterator<T> j = successor(i);
  destroy(sink(i));
  free(i.p);
  return j;
}
template<typename T>
void erase_first(slist<T>& x) {
  x.first = erase_first(begin(x));
}
void test_erase_first(void) {
  typedef int Z;
  Z a[] = {0,1,2,3,4,5};
  slist<Z> s(counted_range<Z*>(a, sizeof(a)/sizeof(a[0])));
  erase_first(s);
  slist_iterator<Z> f = begin(s);
  slist_iterator<Z> l = end(s);
  int i = 1;
  while(f != l) {
    assert(source(f) == i++);
    f = successor(f);
  }
  assert(6 == i);
}
template<typename T>
void erase_all(slist<T>& x) {
  while(!empty(x)) erase_first(x);
}
void test_erase_all(void) {
  typedef int Z;
  Z a[] = {0,1,2,3,4,5};
  slist<Z> s(counted_range<Z*>(a, sizeof(a)/sizeof(a[0])));
  erase_all(s);
  assert(empty(s));
}
int main(void) {
  test_insert_after_0();
  test_insert_after();
  test_copy();
  test_insert_range();
  test_dynamic_sequence_construction();
  test_erase_first();
  test_erase_all();
  return 0;
}