路傍のプログラマ

只のプログラマが綴る愚痴と備忘録

オブジェクト指向alloca (alloca_array)

2005-09-27 14:13:19 | プログラミング
Boostのarray.hppをまねて、スタックからメモリを調達する配列を作ってみる。その名もalloca_array。 

機能: 
・スタック上に、動的にサイズが決定される配列を作る 
(いったん作られた後は大きさを変更できない)。 
・STLコンテナである。begin()やらend()やらが提供される。 

--------------- alloca_array.hppここから --------------- 
#if ! defined ALLOCA_ARRAY_H

#include <cassert>
#include <cstddef>

#if defined _MSC_VER

#include <malloc.h>
#define alloca _alloca

#elif defined _GCC

#include <alloca.h>

#else

#error "unsupported compiler"

#endif

#define DECL_ALLOCA_ARRAY(variable, ElemType, count) alloca_array<ElemType> variable(alloca(count * sizeof(ElemType)), (count))

template<typename ElemType>
class alloca_array {
public:
    typedef ElemType value_type;
    typedef ElemType *iterator;
    typedef const ElemType *const_iterator;
    typedef ElemType &reference;
    typedef const ElemType &const_reference;
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
private:
  ElemType *buf;
  size_type buf_size;
public:
  alloca_array(void *alloca_buffer, size_t count)
    : buf(NULL), buf_size(0)
  {
    buf = reinterpret_cast<ElemType *>(alloca_buffer);
    for (size_t i = 0; i < count; ++i) {
      new(&buf[i]) ElemType();
    }
    buf_size = count;
  }
  ~alloca_array()
  {
    for (size_t i = buf_size; i-- > 0; ) {
      buf[i].~ElemType();
    }
  }
  reference operator[](size_t index)
  {
    return buf[index];
  }
  const reference operator[](size_t index) const
  {
    return buf[index];
  }
  iterator begin()
  {
    return &buf[0];
  }
  iterator end()
  {
    return &buf[count];
  }
  const_iterator begin() const
  {
    return &buf[0];
  }
  const_iterator end() const
  {
    return &buf[count];
  }
  
  // swap (note: linear complexity)
  void swap (alloca_array<ElemType> &y) {
    std::swap_ranges(begin(), end(), y.begin());
  }

  const ElemType* data() const 
  { 
    return buf; 
  }
  ElemType *c_array() 
  { 
    return buf; 
  }
  template <typename T2>
  alloca_array<ElemType> &operator= (const alloca_array<T2> &rhs) {
    std::copy(rhs.begin(), rhs.end(), begin());
    return *this;
  }
  size_type size() const
  {
    return buf_size;
  }
  bool empty() const
  {
    return buf_size > 0;
  }
  reference at(size_type i) 
  { 
    rangecheck(i); 
    return buf[i]; 
  }
  const_reference at(size_type i) const 
  { 
    rangecheck(i); 
    return elems[i]; 
  }
  void rangecheck (size_type i) const
  {
    if (i >= buf_size) { 
      throw std::range_error("alloca_array<>: index out of range");
    }
  }

};


#endif // ALLOCA_ARRAY_H
--------------- alloca_array.hppここまで --------------- 

テスト用コードを以下に。うまく動いてるみたいです。 

--------------- aatest.cppここから --------------- 
// allocatest

#include "alloca_array.hpp"

#include <string>
#include <cassert>

int main(int argc, char *argv[])

  const int size = 100;

  DECL_ALLOCA_ARRAY(astr, std::string, size);
  astr[0] = "";
  for (size_t i = 1; i < astr.size(); ++i) {
    astr[i] = astr[i - 1] + std:: string("a");
  }
  for (size_t i = 0; i < astr.size(); ++i) {
    assert(astr[i].length() == i);
  }

  DECL_ALLOCA_ARRAY(aint, int, size);
  for (size_t i = 0; i < aint.size(); ++i) {
    aint[i] = i;
  }
  for (size_t i = 0; i < astr.size(); ++i) {
    assert(aint[i] == i);
  }

  return 0;

--------------- aatest.cppここまで --------------- 

反省点と弱点 

・プリプロセッサマクロを使っている。∵関数にするとスタックフレームが新たに作られてしまってallocaが役に立たないから。 
・C99ではallocaなんか使わなくてもスタック上に配列を確保できるから、その機能を利用するようにarray.hppを修正したら、alloca_arrayは不要なのでは(お 

(2005/09/28) 文字化けしていたので、いくつかの半角文字を全角文字で置換。orz

最新の画像もっと見る