<commit_before>/* Copyright (c) 2008, Avian Contributors

   Permission to use, copy, modify, and/or distribute this software
   for any purpose with or without fee is hereby granted, provided
   that the above copyright notice and this permission notice appear
   in all copies.

   There is NO WARRANTY for this software.  See license.txt for
   details. */

#include "machine.h"

using namespace vm;

namespace {

const uintptr_t PointerShift = log(BytesPerWord);

class Set {
 public:
  class Entry {
   public:
    object value;
    uint32_t number;
    int next;
  };

  static unsigned footprint(unsigned capacity) {
    return sizeof(Set)
      + pad(sizeof(int) * capacity)
      + pad(sizeof(Set::Entry) * capacity);
  }

  Set(unsigned capacity):
    size(0),
    capacity(capacity),
    index(reinterpret_cast<int*>
          (reinterpret_cast<uint8_t*>(this)
           + sizeof(Set))),
    entries(reinterpret_cast<Entry*>
            (reinterpret_cast<uint8_t*>(index)
             + pad(sizeof(int) * capacity)))
  { }

  unsigned size;
  unsigned capacity;
  int* index;
  Entry* entries;
};

class Stack {
 public:
  class Entry {
   public:
    object value;
    int offset;
  };

  static const unsigned Capacity = 4096;

  Stack(Stack* next): next(next), entryCount(0) { }

  Stack* next;
  unsigned entryCount;
  Entry entries[Capacity];
};

class Context {
 public:
  Context(Thread* thread, FILE* out):
    thread(thread), out(out), objects(0), stack(0), nextNumber(1)
  { }

  ~Context() {
    if (objects) {
      thread->m->heap->free(objects, Set::footprint(objects->capacity));
    }
    while (stack) {
      Stack* dead = stack;
      stack = dead->next;
      thread->m->heap->free(stack, sizeof(Stack));
    }
  }

  Thread* thread;
  FILE* out;
  Set* objects;
  Stack* stack;
  uint32_t nextNumber;
};

void
push(Context* c, object p, int offset)
{
  if (c->stack == 0 or c->stack->entryCount == Stack::Capacity) {
    c->stack = new (c->thread->m->heap->allocate(sizeof(Stack)))
      Stack(c->stack);
  }
  Stack::Entry* e = c->stack->entries + (c->stack->entryCount++);
  e->value = p;
  e->offset = offset;
}

bool
pop(Context* c, object* p, int* offset)
{
  if (c->stack) {
    if (c->stack->entryCount == 0) {
      if (c->stack->next) {
        Stack* dead = c->stack;
        c->stack = dead->next;
        c->thread->m->heap->free(dead, sizeof(Stack));
      } else {
        return false;
      }
    }
    Stack::Entry* e = c->stack->entries + (--c->stack->entryCount);
    *p = e->value;
    *offset = e->offset;
    return true;
  } else {
    return false;
  }
}

unsigned
hash(object p, unsigned capacity)
{
  return (reinterpret_cast<uintptr_t>(p) >> PointerShift)
    & (capacity - 1);
}

Set::Entry*
find(Context* c, object p)
{
  if (c->objects == 0) return 0;

  for (int i = c->objects->index[hash(p, c->objects->capacity)]; i >= 0;) {
    Set::Entry* e = c->objects->entries + i;
    if (e->value == p) {
      return e;
    }
    i = e->next;
  }

  return 0;
}

Set::Entry*
add(Context* c UNUSED, Set* set, object p, uint32_t number)
{
  assert(c->thread, set->size < set->capacity);

  unsigned index = hash(p, set->capacity);

  int offset = set->size++;
  Set::Entry* e = set->entries + offset;
  e->value = p;
  e->number = number;
  e->next = set->index[index];
  set->index[index] = offset;
  return e;
}

Set::Entry*
add(Context* c, object p)
{
  if (c->objects == 0 or c->objects->size == c->objects->capacity) {
    unsigned capacity;
    if (c->objects) {
      capacity = c->objects->capacity * 2;
    } else {
      capacity = 4096; // must be power of two
    }

    Set* set = new (c->thread->m->heap->allocate(Set::footprint(capacity)))
      Set(capacity);

    memset(set->index, 0xFF, sizeof(int) * capacity);

    if (c->objects) {
      for (unsigned i = 0; i < c->objects->capacity; ++i) {
        for (int j = c->objects->index[i]; j >= 0;) {
          Set::Entry* e = c->objects->entries + j;
          add(c, set, e->value, e->number);
          j = e->next;
        }
      }

      c->thread->m->heap->free
        (c->objects, Set::footprint(c->objects->capacity));
    }

    c->objects = set;
  }

  return add(c, c->objects, p, 0);
}

enum {
  Root,
  Size,
  ClassName,
  Push,
  Pop
};

inline object
get(object o, unsigned offsetInWords)
{
  return static_cast<object>
    (mask(cast<void*>(o, offsetInWords * BytesPerWord)));
}

void
write1(Context* c, uint8_t v)
{
  fwrite(&v, 1, 1, c->out);
}

void
write4(Context* c, uint32_t v)
{
  uint8_t b[] = { v >> 24, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF };
  fwrite(b, 4, 1, c->out);
}

void
writeString(Context* c, int8_t* p, unsigned size)
{
  write4(c, size);
  fwrite(p, size, 1, c->out);
}

unsigned
objectSize(Thread* t, object o)
{
  unsigned n = baseSize(t, o, objectClass(t, o));
  if (objectExtended(t, o)) {
    ++ n;
  }
  return n;
}

void
visit(Context* c, object p)
{
  Thread* t = c->thread;
  int nextChildOffset;

  write1(c, Root);

 visit: {
    Set::Entry* e = find(c, p);
    if (e) {
      write4(c, e->number);
    } else {
      e = add(c, p);
      e->number = c->nextNumber++;

      write4(c, e->number);

      write1(c, Size);
      write4(c, objectSize(t, p));

      if (objectClass(t, p) == arrayBody(t, t->m->types, Machine::ClassType)) {
        object name = className(t, p);
        if (name) {
          write1(c, ClassName);
          writeString(c, &byteArrayBody(t, name, 0),
                      byteArrayLength(t, name) - 1);
        }
      }

      nextChildOffset = walkNext(t, p, -1);
      if (nextChildOffset != -1) {
        goto children;
      }
    }
  }

  goto pop;

 children: {
    write1(c, Push);
    push(c, p, nextChildOffset);
    p = get(p, nextChildOffset);
    goto visit;
  }

 pop: {
    if (pop(c, &p, &nextChildOffset)) {
      write1(c, Pop);
      nextChildOffset = walkNext(t, p, nextChildOffset);
      if (nextChildOffset >= 0) {
        goto children;
      } else {
        goto pop;
      }
    }
  }
}

} // namespace

namespace vm {

void
dumpHeap(Thread* t, FILE* out)
{
  Context context(t, out);

  class Visitor : public Heap::Visitor {
   public:
    Visitor(Context* c): c(c) { }

    virtual void visit(void* p) {
      ::visit(c, static_cast<object>(mask(*static_cast<void**>(p))));
    }

    Context* c;
  } v(&context);

  add(&context, 0)->number = 0;

  visitRoots(t->m, &v);
}

} // namespace vm
<commit_msg>Check return value of fwrite() calls.<commit_after>/* Copyright (c) 2008, Avian Contributors

   Permission to use, copy, modify, and/or distribute this software
   for any purpose with or without fee is hereby granted, provided
   that the above copyright notice and this permission notice appear
   in all copies.

   There is NO WARRANTY for this software.  See license.txt for
   details. */

#include "machine.h"

using namespace vm;

namespace {

const uintptr_t PointerShift = log(BytesPerWord);

class Set {
 public:
  class Entry {
   public:
    object value;
    uint32_t number;
    int next;
  };

  static unsigned footprint(unsigned capacity) {
    return sizeof(Set)
      + pad(sizeof(int) * capacity)
      + pad(sizeof(Set::Entry) * capacity);
  }

  Set(unsigned capacity):
    size(0),
    capacity(capacity),
    index(reinterpret_cast<int*>
          (reinterpret_cast<uint8_t*>(this)
           + sizeof(Set))),
    entries(reinterpret_cast<Entry*>
            (reinterpret_cast<uint8_t*>(index)
             + pad(sizeof(int) * capacity)))
  { }

  unsigned size;
  unsigned capacity;
  int* index;
  Entry* entries;
};

class Stack {
 public:
  class Entry {
   public:
    object value;
    int offset;
  };

  static const unsigned Capacity = 4096;

  Stack(Stack* next): next(next), entryCount(0) { }

  Stack* next;
  unsigned entryCount;
  Entry entries[Capacity];
};

class Context {
 public:
  Context(Thread* thread, FILE* out):
    thread(thread), out(out), objects(0), stack(0), nextNumber(1)
  { }

  ~Context() {
    if (objects) {
      thread->m->heap->free(objects, Set::footprint(objects->capacity));
    }
    while (stack) {
      Stack* dead = stack;
      stack = dead->next;
      thread->m->heap->free(stack, sizeof(Stack));
    }
  }

  Thread* thread;
  FILE* out;
  Set* objects;
  Stack* stack;
  uint32_t nextNumber;
};

void
push(Context* c, object p, int offset)
{
  if (c->stack == 0 or c->stack->entryCount == Stack::Capacity) {
    c->stack = new (c->thread->m->heap->allocate(sizeof(Stack)))
      Stack(c->stack);
  }
  Stack::Entry* e = c->stack->entries + (c->stack->entryCount++);
  e->value = p;
  e->offset = offset;
}

bool
pop(Context* c, object* p, int* offset)
{
  if (c->stack) {
    if (c->stack->entryCount == 0) {
      if (c->stack->next) {
        Stack* dead = c->stack;
        c->stack = dead->next;
        c->thread->m->heap->free(dead, sizeof(Stack));
      } else {
        return false;
      }
    }
    Stack::Entry* e = c->stack->entries + (--c->stack->entryCount);
    *p = e->value;
    *offset = e->offset;
    return true;
  } else {
    return false;
  }
}

unsigned
hash(object p, unsigned capacity)
{
  return (reinterpret_cast<uintptr_t>(p) >> PointerShift)
    & (capacity - 1);
}

Set::Entry*
find(Context* c, object p)
{
  if (c->objects == 0) return 0;

  for (int i = c->objects->index[hash(p, c->objects->capacity)]; i >= 0;) {
    Set::Entry* e = c->objects->entries + i;
    if (e->value == p) {
      return e;
    }
    i = e->next;
  }

  return 0;
}

Set::Entry*
add(Context* c UNUSED, Set* set, object p, uint32_t number)
{
  assert(c->thread, set->size < set->capacity);

  unsigned index = hash(p, set->capacity);

  int offset = set->size++;
  Set::Entry* e = set->entries + offset;
  e->value = p;
  e->number = number;
  e->next = set->index[index];
  set->index[index] = offset;
  return e;
}

Set::Entry*
add(Context* c, object p)
{
  if (c->objects == 0 or c->objects->size == c->objects->capacity) {
    unsigned capacity;
    if (c->objects) {
      capacity = c->objects->capacity * 2;
    } else {
      capacity = 4096; // must be power of two
    }

    Set* set = new (c->thread->m->heap->allocate(Set::footprint(capacity)))
      Set(capacity);

    memset(set->index, 0xFF, sizeof(int) * capacity);

    if (c->objects) {
      for (unsigned i = 0; i < c->objects->capacity; ++i) {
        for (int j = c->objects->index[i]; j >= 0;) {
          Set::Entry* e = c->objects->entries + j;
          add(c, set, e->value, e->number);
          j = e->next;
        }
      }

      c->thread->m->heap->free
        (c->objects, Set::footprint(c->objects->capacity));
    }

    c->objects = set;
  }

  return add(c, c->objects, p, 0);
}

enum {
  Root,
  Size,
  ClassName,
  Push,
  Pop
};

inline object
get(object o, unsigned offsetInWords)
{
  return static_cast<object>
    (mask(cast<void*>(o, offsetInWords * BytesPerWord)));
}

void
write1(Context* c, uint8_t v)
{
  size_t n UNUSED = fwrite(&v, 1, 1, c->out);
}

void
write4(Context* c, uint32_t v)
{
  uint8_t b[] = { v >> 24, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF };
  size_t n UNUSED = fwrite(b, 4, 1, c->out);
}

void
writeString(Context* c, int8_t* p, unsigned size)
{
  write4(c, size);
  size_t n UNUSED = fwrite(p, size, 1, c->out);
}

unsigned
objectSize(Thread* t, object o)
{
  unsigned n = baseSize(t, o, objectClass(t, o));
  if (objectExtended(t, o)) {
    ++ n;
  }
  return n;
}

void
visit(Context* c, object p)
{
  Thread* t = c->thread;
  int nextChildOffset;

  write1(c, Root);

 visit: {
    Set::Entry* e = find(c, p);
    if (e) {
      write4(c, e->number);
    } else {
      e = add(c, p);
      e->number = c->nextNumber++;

      write4(c, e->number);

      write1(c, Size);
      write4(c, objectSize(t, p));

      if (objectClass(t, p) == arrayBody(t, t->m->types, Machine::ClassType)) {
        object name = className(t, p);
        if (name) {
          write1(c, ClassName);
          writeString(c, &byteArrayBody(t, name, 0),
                      byteArrayLength(t, name) - 1);
        }
      }

      nextChildOffset = walkNext(t, p, -1);
      if (nextChildOffset != -1) {
        goto children;
      }
    }
  }

  goto pop;

 children: {
    write1(c, Push);
    push(c, p, nextChildOffset);
    p = get(p, nextChildOffset);
    goto visit;
  }

 pop: {
    if (pop(c, &p, &nextChildOffset)) {
      write1(c, Pop);
      nextChildOffset = walkNext(t, p, nextChildOffset);
      if (nextChildOffset >= 0) {
        goto children;
      } else {
        goto pop;
      }
    }
  }
}

} // namespace

namespace vm {

void
dumpHeap(Thread* t, FILE* out)
{
  Context context(t, out);

  class Visitor : public Heap::Visitor {
   public:
    Visitor(Context* c): c(c) { }

    virtual void visit(void* p) {
      ::visit(c, static_cast<object>(mask(*static_cast<void**>(p))));
    }

    Context* c;
  } v(&context);

  add(&context, 0)->number = 0;

  visitRoots(t->m, &v);
}

} // namespace vm
<|endoftext|>


<commit_before>
#include	<cmath>
#include    <cfloat>

#include    "string.h"
#include    "turing_calculator.h"

turing_calculator::turing_calculator():machine_(0), instructions_(0), instructions_sum_(0), yield_execution_(false) {
}

turing_calculator::~turing_calculator() {
    delete[]    instructions_;
}

size_t   turing_calculator::set_str_variable(const std::string& key, const std::string& value) {
    variable    str_index;
    if(fetch_variable(key, str_index)) {
        str_variables_[size_t(str_index)]   = value;
        return  size_t(str_index);
    }

    size_t  index   = str_variables_.size();
    str_variables_.push_back(value);
    this->set_variable(key, variable(index));
    return  index;
}

const char* turing_calculator::get_str_variable(const std::string& key) {
    variable    index;
    if(!fetch_variable(key, index)) {
        return  0;
    }
    size_t  str_index   = size_t(index);
    return  get_str_variable(str_index);
}

const char* turing_calculator::get_str_variable(size_t str_var_index) {
    if(str_var_index >= str_variables_.size()) {
        return  0;
    }
    return  str_variables_[str_var_index].c_str();
}

int turing_calculator::set_label_variable(const std::string& key, int value) {
    int var;
    if(fetch_label_variable(key, var)) {
        return  var;
    }

    set_variable(key, variable(value));
    return  value;
}

bool turing_calculator::fetch_label_variable(const std::string& key, int& value) {
    variable    var;
    if(!fetch_variable(key, var)) {
        return  false;
    }
    value   = int(var);
    return  true;
}

bool    turing_calculator::execute_instruction(turing_machine* machine, int instruction_address) {
    if(instruction_address < 0 || instruction_address >= int(instructions_sum_)) {
        this->set_error_message("invalid instruction address");
        return  false;
    }

    this->set_error_message("");
    const char* pstr    = instructions_[instruction_address];
    switch(*pstr) {
    case 0:
    case '#':
    case ':':
    case '@': {
        return  true;
    }
    }

    machine_            = machine;
    yield_execution_    = false;

    variable    result;
    bool        succeed  = execute(pstr, result);

    machine_    = 0;
    return  succeed && !yield_execution_;
}

void    turing_calculator::do_reset() {
    delete[]    instructions_;
    instructions_       = 0;
    instructions_sum_   = 0;
    str_variables_.clear();

    calculator::do_reset();
}

#define FX(FUNK,LEN,BIN,DO) if(!strncmp(buf,FUNK,LEN)) { move = LEN + fetch_func_params(buf+LEN,BIN,x,y); { DO; } }
calculator::variable	turing_calculator::do_find_function(const char* buf, int& move) {
    calculator::variable x,y;
    switch (*buf) {
    case 'A':
        FX("AND(",      4,2, return ((std::abs(x) <= DBL_EPSILON) && (std::abs(y) <= DBL_EPSILON))?1.0:0.0;);
        break;
    case 'E':
        FX("EQ(",       3,2, return (std::abs(x-y) <= DBL_EPSILON)?1.0:0.0;);
        break;
    case 'G':
        FX("GOTO("  ,   5,1, if(machine_)machine_->set_instruction_address(int(x)); return variable(1););
        FX("GOTO_IF(",  8,2, if(machine_ && y > 0.0)machine_->set_instruction_address(int(x)); return variable(y>0?1:0););
        FX("GT(",       3,2, return x>y?1.0:0.0;);
        break;
    case 'L':
        FX("LT(",       3,2, return x<y?1.0:0.0;);
        break;
    case 'N':
        FX("NOT(",      4,1, return x<=0.0?1.0:0.0;);
        break;
    case 'O':
        FX("OR(",       3,2, return ((std::abs(x) <= DBL_EPSILON) || (std::abs(y) <= DBL_EPSILON))?1.0:0.0;);
        break;
    case 'S':
        FX("STOP(",     5,0, if(machine_)machine_->stop(); return variable(1););
        break;
    case 'Y':
        FX("YIELD(",    6,0, this->yield_execution_ = true; return variable(1););
        break;
    }
    return	calculator::do_find_function(buf, move);
}
#undef	FX

bool    turing_calculator::do_preprocess_instructions() {
    for(size_t i = 0; i < instructions_sum_; ++i) {
        const char* pstr    = instructions_[i];
        if(NULL != pstr) {
            while(*pstr && isspace(*pstr)) {
                pstr++;
            }

            instructions_[i]    = pstr;// ignore white spaces
            switch(*pstr) {
            case '@': {//str variable define
                std::string name;
                name.reserve(32);
                do {
                    name.push_back(*pstr);
                    pstr++;
                } while(isalnum(*pstr) || *pstr == '_');
                const char* pValue = strchr(pstr,'=');
                if(NULL == pValue) {
                    this->set_str_variable(name, "");
                } else {
                    this->set_str_variable(name, ++pValue);
                }
            }
            break;
            case ':': {//label define
                std::string name;
                name.reserve(32);
                do {
                    name.push_back(*pstr);
                    pstr++;
                } while(isalnum(*pstr) || *pstr == '_');
                this->set_label_variable(name, int(i));
            }
            break;
            }
        }
    }
    return  true;
}
<commit_msg>turing_calculator would stop the machine if instruction address is invalid<commit_after>
#include	<cmath>
#include    <cfloat>

#include    "string.h"
#include    "turing_calculator.h"

turing_calculator::turing_calculator():machine_(0), instructions_(0), instructions_sum_(0), yield_execution_(false) {
}

turing_calculator::~turing_calculator() {
    delete[]    instructions_;
}

size_t   turing_calculator::set_str_variable(const std::string& key, const std::string& value) {
    variable    str_index;
    if(fetch_variable(key, str_index)) {
        str_variables_[size_t(str_index)]   = value;
        return  size_t(str_index);
    }

    size_t  index   = str_variables_.size();
    str_variables_.push_back(value);
    this->set_variable(key, variable(index));
    return  index;
}

const char* turing_calculator::get_str_variable(const std::string& key) {
    variable    index;
    if(!fetch_variable(key, index)) {
        return  0;
    }
    size_t  str_index   = size_t(index);
    return  get_str_variable(str_index);
}

const char* turing_calculator::get_str_variable(size_t str_var_index) {
    if(str_var_index >= str_variables_.size()) {
        return  0;
    }
    return  str_variables_[str_var_index].c_str();
}

int turing_calculator::set_label_variable(const std::string& key, int value) {
    int var;
    if(fetch_label_variable(key, var)) {
        return  var;
    }

    set_variable(key, variable(value));
    return  value;
}

bool turing_calculator::fetch_label_variable(const std::string& key, int& value) {
    variable    var;
    if(!fetch_variable(key, var)) {
        return  false;
    }
    value   = int(var);
    return  true;
}

bool    turing_calculator::execute_instruction(turing_machine* machine, int instruction_address) {
    if(instruction_address < 0 || instruction_address >= int(instructions_sum_)) {
        this->set_error_message("invalid instruction address");
        machine->stop();
        return  false;
    }

    this->set_error_message("");
    const char* pstr    = instructions_[instruction_address];
    switch(*pstr) {
    case 0:
    case '#':
    case ':':
    case '@': {
        return  true;
    }
    }

    machine_            = machine;
    yield_execution_    = false;

    variable    result;
    bool        succeed  = execute(pstr, result);

    machine_    = 0;
    return  succeed && !yield_execution_;
}

void    turing_calculator::do_reset() {
    delete[]    instructions_;
    instructions_       = 0;
    instructions_sum_   = 0;
    str_variables_.clear();

    calculator::do_reset();
}

#define FX(FUNK,LEN,BIN,DO) if(!strncmp(buf,FUNK,LEN)) { move = LEN + fetch_func_params(buf+LEN,BIN,x,y); { DO; } }
calculator::variable	turing_calculator::do_find_function(const char* buf, int& move) {
    calculator::variable x,y;
    switch (*buf) {
    case 'A':
        FX("AND(",      4,2, return ((std::abs(x) <= DBL_EPSILON) && (std::abs(y) <= DBL_EPSILON))?1.0:0.0;);
        break;
    case 'E':
        FX("EQ(",       3,2, return (std::abs(x-y) <= DBL_EPSILON)?1.0:0.0;);
        break;
    case 'G':
        FX("GOTO("  ,   5,1, if(machine_)machine_->set_instruction_address(int(x)); return variable(1););
        FX("GOTO_IF(",  8,2, if(machine_ && y > 0.0)machine_->set_instruction_address(int(x)); return variable(y>0?1:0););
        FX("GT(",       3,2, return x>y?1.0:0.0;);
        break;
    case 'L':
        FX("LT(",       3,2, return x<y?1.0:0.0;);
        break;
    case 'N':
        FX("NOT(",      4,1, return x<=0.0?1.0:0.0;);
        break;
    case 'O':
        FX("OR(",       3,2, return ((std::abs(x) <= DBL_EPSILON) || (std::abs(y) <= DBL_EPSILON))?1.0:0.0;);
        break;
    case 'S':
        FX("STOP(",     5,0, if(machine_)machine_->stop(); return variable(1););
        break;
    case 'Y':
        FX("YIELD(",    6,0, this->yield_execution_ = true; return variable(1););
        break;
    }
    return	calculator::do_find_function(buf, move);
}
#undef	FX

bool    turing_calculator::do_preprocess_instructions() {
    for(size_t i = 0; i < instructions_sum_; ++i) {
        const char* pstr    = instructions_[i];
        if(NULL != pstr) {
            while(*pstr && isspace(*pstr)) {
                pstr++;
            }

            instructions_[i]    = pstr;// ignore white spaces
            switch(*pstr) {
            case '@': {//str variable define
                std::string name;
                name.reserve(32);
                do {
                    name.push_back(*pstr);
                    pstr++;
                } while(isalnum(*pstr) || *pstr == '_');
                const char* pValue = strchr(pstr,'=');
                if(NULL == pValue) {
                    this->set_str_variable(name, "");
                } else {
                    this->set_str_variable(name, ++pValue);
                }
            }
            break;
            case ':': {//label define
                std::string name;
                name.reserve(32);
                do {
                    name.push_back(*pstr);
                    pstr++;
                } while(isalnum(*pstr) || *pstr == '_');
                this->set_label_variable(name, int(i));
            }
            break;
            }
        }
    }
    return  true;
}
<|endoftext|>


<commit_before><commit_msg>Disable two ui_tests on linux after a WebKit merge.<commit_after><|endoftext|>


<commit_before>/**
 * @file  shared_ptr.hpp
 * @brief shared_ptr is a minimal implementation of smart pointer, a subset of the C++11 std::shared_ptr or boost::shared_ptr.
 *
 *  This file includes "boost/shared_ptr.hpp" if LOGGER_USE_BOOST_SHARED_PTR is defined,
 * or <memory> (or <tr1/memory>) when C++11 (or experimental C++0x) is available,
 * and imports the symbol "shared_ptr" inside the current namespace (ie. Log::shared_ptr).
 *  If no std::shared_ptr is available, it defines a minimal shared_ptr implementation.
 *
 * Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */
#pragma once

/// Compatibility with non-clang compilers.
#ifndef __has_feature
  #define __has_feature(x) 0
#endif

//
// Try to detect the better shared_ptr to use, and then imports the symbol in the current namespace
// => if you include this "shared_ptr.hpp" file inside your own namespace you will
//    get a kind of universal easy to use "shared_ptr" type
//
#ifdef LOGGER_USE_BOOST_SHARED_PTR
    // Use Boost only if explicitly told
    #include <boost/shared_ptr.hpp>
    namespace Log {
    using boost::shared_ptr;
    } // namespace Log
// Detect whether the compiler supports C++11 shared_ptr or its TR1 pre-version.
#elif (defined(__GNUC__) && \
       (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && \
       defined(__GXX_EXPERIMENTAL_CXX0X__))
    // GCC 4.3 and following have std::shared_ptr support when called with -std=c++0x (or -std=c++11 starting with GCC 4.7)
    #include <memory>
    namespace Log {
    using std::shared_ptr;
    } // namespace Log
#elif (defined(__GNUC__) && (__GNUC__ == 4) && defined(__GXX_EXPERIMENTAL_CXX0X__))
    // GCC 4.0/4.1/4.2 have std::shared_ptr support when when called with -std=c++0x
    #include <tr1/memory>
    namespace Log {
    using std::tr1::shared_ptr;
    } // namespace Log
#elif defined(__clang__) && __has_feature(cxx_nullptr)
    // Clang 2.9 and above ?
    #include <memory>
    namespace Log {
    using std::shared_ptr;
    } // namespace Log
#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
    // Visual Studio 2010 compile by default in C++11 mode
    #include <memory>
    namespace Log {
    using std::shared_ptr;
    } // namespace Log
#elif defined(_MSC_VER) && (_MSC_VER >= 1500)
    // Visual Studio 2008 : beware, TR1 is provided with the Service Pack 1 only !
    #include <memory>
    namespace Log {
    using std::tr1:shared_ptr;
    } // namespace Log
#else

#include <cstddef>      // NULL
#include <algorithm>    // std::swap
#include <cassert>

// can be replaced by other error mechanism
#define SHARED_ASSERT(x)    assert(x)

namespace Log {

/**
 * @brief minimal implementation of smart pointer, a subset of the C++11 std::shared_ptr or boost::shared_ptr.
 *
 * shared_ptr is a smart pointer retaining ownership of an object through a provided pointer,
 * and sharing this ownership with a reference counter.
 * It destroys the object when the last shared pointer pointing to it is destroyed or reset.
 */
template<class T>
class shared_ptr
{
public:
    /// The type of the managed object, aliased as member type
    typedef T element_type;

    /// @brief Default constructor
    shared_ptr(void) throw() : // never throws
        px(NULL),
        pn(NULL)
    {
    }
    /// @brief Constructor with the provided pointer to manage
    explicit shared_ptr(T* p) : // may throw std::bad_alloc
      //px(p), would be unsafe as acquire() may throw, which would call release() in destructor
        pn(NULL)
    {
        acquire(p);   // may throw std::bad_alloc
    }
    /// @brief Constructor to share ownership. Warning : to be used for pointer_cast only ! (does not manage two separate <T> and <U> pointers)
    template <class U>
    shared_ptr(const shared_ptr<U>& ptr, T* p) :
     //px(p), would be unsafe as acquire() may throw, which would call release() in destructor
       pn(ptr.pn)
    {
       acquire(p);   // may throw std::bad_alloc
    }
    /// @brief Copy constructor to convert from another pointer type
    template <class U>
    shared_ptr(const shared_ptr<U>& ptr) throw() : // never throws (see comment below)
      //px(ptr.px),
        pn(ptr.pn)
    {
        SHARED_ASSERT((NULL == ptr.px) || (NULL != ptr.pn)); // must be cohérent : no allocation allowed in this path
        acquire(static_cast<typename shared_ptr<T>::element_type*>(ptr.px));   // will never throw std::bad_alloc
    }
    /// @brief Copy constructor (used by the copy-and-swap idiom)
    shared_ptr(const shared_ptr& ptr) throw() : // never throws (see comment below)
       //px(ptr.px),
        pn(ptr.pn)
    {
        SHARED_ASSERT((NULL == ptr.px) || (NULL != ptr.pn)); // must be cohérent : no allocation allowed in this path
        acquire(ptr.px);   // will never throw std::bad_alloc
    }
    /// @brief Assignment operator using the copy-and-swap idiom (copy constructor and swap method)
    shared_ptr& operator=(shared_ptr ptr) throw() // never throws
    {
        swap(ptr);
        return *this;
    }
    /// @brief the destructor releases its ownership
    inline ~shared_ptr(void) throw() // never throws
    {
        release();
    }
    /// @brief this reset releases its ownership
    inline void reset(void) throw() // never throws
    {
        release();
    }
    /// @brief this reset release its ownership and re-acquire another one
    void reset(T* p) throw() // may throw std::bad_alloc
    {
        SHARED_ASSERT((NULL == p) || (px != p)); // auto-reset not allowed
        release();
        acquire(p); // may throw std::bad_alloc
    }

    /// @brief Swap method for the copy-and-swap idiom (copy constructor and swap method)
    void swap(shared_ptr& lhs) throw() // never throws
    {
        // Would be nice to enable use of ustl::swap by define
        std::swap(px, lhs.px);
        std::swap(pn, lhs.pn);
    }

    // reference counter operations :
    inline operator bool() const throw() // never throws
    {
        return (0 < use_count());
    }
    inline bool unique(void)  const throw() // never throws
    {
        return (1 == use_count());
    }
    long use_count(void)  const throw() // never throws
    {
        long count = 0;
        if (NULL != pn)
        {
            count = *pn;
        }
        return count;
    }

    // underlying pointer operations :
    inline T& operator*()  const throw() // never throws
    {
        SHARED_ASSERT(NULL != px);
        return *px;
    }
    inline T* operator->() const throw() // never throws
    {
        SHARED_ASSERT(NULL != px);
        return px;
    }
    inline T* get(void)  const throw() // never throws
    {
        // no assert, car return NULL
        return px;
    }

private:
    /// @brief acquire/share the ownership of the px pointer, initializing the reference counter
    void acquire(T* p) // may throw std::bad_alloc
    {
        if (NULL != p)
        {
            if (NULL == pn)
            {
                try
                {
                    pn = new long(1); // may throw std::bad_alloc
                }
                catch (std::bad_alloc&)
                {
                    delete p;
                    throw; // rethrow the std::bad_alloc
                }
            }
            else
            {
                ++(*pn);
            }
        }
        // here it is safe to acquire the ownership of the provided raw pointer, where exception cannot be thrown any more
        px = p;
    }

    /// @brief release the ownership of the px pointer, destroying the object when appropriate
    void release(void) throw() // never throws
    {
        if (NULL != pn)
        {
            --(*pn);
            if (0 == *pn)
            {
                delete px;
                delete pn;
            }
            px = NULL;
            pn = NULL;
        }
    }

private:
    // This allow pointer_cast functions to share the reference counter between different shared_ptr types
    template<class U>
    friend class shared_ptr;

private:
    T*      px; //!< Native pointer
    long*   pn; //!< Reference counter
};

// comparaison operators
template<class T, class U> inline bool operator==(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() == r.get());
}
template<class T, class U> inline bool operator!=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() != r.get());
}
template<class T, class U> inline bool operator<=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() <= r.get());
}
template<class T, class U> inline bool operator<(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() < r.get());
}
template<class T, class U> inline bool operator>=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() >= r.get());
}
template<class T, class U> inline bool operator>(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() > r.get());
}

// static cast of shared_ptr
template<class T, class U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& ptr) // never throws
{
    return shared_ptr<T>(ptr, static_cast<typename shared_ptr<T>::element_type*>(ptr.get()));
}

// dynamic cast of shared_ptr
template<class T, class U>
shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& ptr) // never throws
{
    T* p = dynamic_cast<typename shared_ptr<T>::element_type*>(ptr.get());
    if (NULL != p)
    {
        return shared_ptr<T>(ptr, p);
    }
    else
    {
        return shared_ptr<T>();
    }
}

} // namespace Log

#endif
<commit_msg>Fix a syntax issue for VS2008<commit_after>/**
 * @file  shared_ptr.hpp
 * @brief shared_ptr is a minimal implementation of smart pointer, a subset of the C++11 std::shared_ptr or boost::shared_ptr.
 *
 *  This file includes "boost/shared_ptr.hpp" if LOGGER_USE_BOOST_SHARED_PTR is defined,
 * or <memory> (or <tr1/memory>) when C++11 (or experimental C++0x) is available,
 * and imports the symbol "shared_ptr" inside the current namespace (ie. Log::shared_ptr).
 *  If no std::shared_ptr is available, it defines a minimal shared_ptr implementation.
 *
 * Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */
#pragma once

/// Compatibility with non-clang compilers.
#ifndef __has_feature
  #define __has_feature(x) 0
#endif

//
// Try to detect the better shared_ptr to use, and then imports the symbol in the current namespace
// => if you include this "shared_ptr.hpp" file inside your own namespace you will
//    get a kind of universal easy to use "shared_ptr" type
//
#ifdef LOGGER_USE_BOOST_SHARED_PTR
    // Use Boost only if explicitly told
    #include <boost/shared_ptr.hpp>
    namespace Log {
    using boost::shared_ptr;
    } // namespace Log
// Detect whether the compiler supports C++11 shared_ptr or its TR1 pre-version.
#elif (defined(__GNUC__) && \
       (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && \
       defined(__GXX_EXPERIMENTAL_CXX0X__))
    // GCC 4.3 and following have std::shared_ptr support when called with -std=c++0x (or -std=c++11 starting with GCC 4.7)
    #include <memory>
    namespace Log {
    using std::shared_ptr;
    } // namespace Log
#elif (defined(__GNUC__) && (__GNUC__ == 4) && defined(__GXX_EXPERIMENTAL_CXX0X__))
    // GCC 4.0/4.1/4.2 have std::shared_ptr support when when called with -std=c++0x
    #include <tr1/memory>
    namespace Log {
    using std::tr1::shared_ptr;
    } // namespace Log
#elif defined(__clang__) && __has_feature(cxx_nullptr)
    // Clang 2.9 and above ?
    #include <memory>
    namespace Log {
    using std::shared_ptr;
    } // namespace Log
#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
    // Visual Studio 2010 compile by default in C++11 mode
    #include <memory>
    namespace Log {
    using std::shared_ptr;
    } // namespace Log
#elif defined(_MSC_VER) && (_MSC_VER >= 1500)
    // Visual Studio 2008 : beware, TR1 is provided with the Service Pack 1 only !
    #include <memory>
    namespace Log {
    using std::tr1::shared_ptr;
    } // namespace Log
#else

#include <cstddef>      // NULL
#include <algorithm>    // std::swap
#include <cassert>

// can be replaced by other error mechanism
#define SHARED_ASSERT(x)    assert(x)

namespace Log {

/**
 * @brief minimal implementation of smart pointer, a subset of the C++11 std::shared_ptr or boost::shared_ptr.
 *
 * shared_ptr is a smart pointer retaining ownership of an object through a provided pointer,
 * and sharing this ownership with a reference counter.
 * It destroys the object when the last shared pointer pointing to it is destroyed or reset.
 */
template<class T>
class shared_ptr
{
public:
    /// The type of the managed object, aliased as member type
    typedef T element_type;

    /// @brief Default constructor
    shared_ptr(void) throw() : // never throws
        px(NULL),
        pn(NULL)
    {
    }
    /// @brief Constructor with the provided pointer to manage
    explicit shared_ptr(T* p) : // may throw std::bad_alloc
      //px(p), would be unsafe as acquire() may throw, which would call release() in destructor
        pn(NULL)
    {
        acquire(p);   // may throw std::bad_alloc
    }
    /// @brief Constructor to share ownership. Warning : to be used for pointer_cast only ! (does not manage two separate <T> and <U> pointers)
    template <class U>
    shared_ptr(const shared_ptr<U>& ptr, T* p) :
     //px(p), would be unsafe as acquire() may throw, which would call release() in destructor
       pn(ptr.pn)
    {
       acquire(p);   // may throw std::bad_alloc
    }
    /// @brief Copy constructor to convert from another pointer type
    template <class U>
    shared_ptr(const shared_ptr<U>& ptr) throw() : // never throws (see comment below)
      //px(ptr.px),
        pn(ptr.pn)
    {
        SHARED_ASSERT((NULL == ptr.px) || (NULL != ptr.pn)); // must be cohérent : no allocation allowed in this path
        acquire(static_cast<typename shared_ptr<T>::element_type*>(ptr.px));   // will never throw std::bad_alloc
    }
    /// @brief Copy constructor (used by the copy-and-swap idiom)
    shared_ptr(const shared_ptr& ptr) throw() : // never throws (see comment below)
       //px(ptr.px),
        pn(ptr.pn)
    {
        SHARED_ASSERT((NULL == ptr.px) || (NULL != ptr.pn)); // must be cohérent : no allocation allowed in this path
        acquire(ptr.px);   // will never throw std::bad_alloc
    }
    /// @brief Assignment operator using the copy-and-swap idiom (copy constructor and swap method)
    shared_ptr& operator=(shared_ptr ptr) throw() // never throws
    {
        swap(ptr);
        return *this;
    }
    /// @brief the destructor releases its ownership
    inline ~shared_ptr(void) throw() // never throws
    {
        release();
    }
    /// @brief this reset releases its ownership
    inline void reset(void) throw() // never throws
    {
        release();
    }
    /// @brief this reset release its ownership and re-acquire another one
    void reset(T* p) throw() // may throw std::bad_alloc
    {
        SHARED_ASSERT((NULL == p) || (px != p)); // auto-reset not allowed
        release();
        acquire(p); // may throw std::bad_alloc
    }

    /// @brief Swap method for the copy-and-swap idiom (copy constructor and swap method)
    void swap(shared_ptr& lhs) throw() // never throws
    {
        // Would be nice to enable use of ustl::swap by define
        std::swap(px, lhs.px);
        std::swap(pn, lhs.pn);
    }

    // reference counter operations :
    inline operator bool() const throw() // never throws
    {
        return (0 < use_count());
    }
    inline bool unique(void)  const throw() // never throws
    {
        return (1 == use_count());
    }
    long use_count(void)  const throw() // never throws
    {
        long count = 0;
        if (NULL != pn)
        {
            count = *pn;
        }
        return count;
    }

    // underlying pointer operations :
    inline T& operator*()  const throw() // never throws
    {
        SHARED_ASSERT(NULL != px);
        return *px;
    }
    inline T* operator->() const throw() // never throws
    {
        SHARED_ASSERT(NULL != px);
        return px;
    }
    inline T* get(void)  const throw() // never throws
    {
        // no assert, car return NULL
        return px;
    }

private:
    /// @brief acquire/share the ownership of the px pointer, initializing the reference counter
    void acquire(T* p) // may throw std::bad_alloc
    {
        if (NULL != p)
        {
            if (NULL == pn)
            {
                try
                {
                    pn = new long(1); // may throw std::bad_alloc
                }
                catch (std::bad_alloc&)
                {
                    delete p;
                    throw; // rethrow the std::bad_alloc
                }
            }
            else
            {
                ++(*pn);
            }
        }
        // here it is safe to acquire the ownership of the provided raw pointer, where exception cannot be thrown any more
        px = p;
    }

    /// @brief release the ownership of the px pointer, destroying the object when appropriate
    void release(void) throw() // never throws
    {
        if (NULL != pn)
        {
            --(*pn);
            if (0 == *pn)
            {
                delete px;
                delete pn;
            }
            px = NULL;
            pn = NULL;
        }
    }

private:
    // This allow pointer_cast functions to share the reference counter between different shared_ptr types
    template<class U>
    friend class shared_ptr;

private:
    T*      px; //!< Native pointer
    long*   pn; //!< Reference counter
};

// comparaison operators
template<class T, class U> inline bool operator==(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() == r.get());
}
template<class T, class U> inline bool operator!=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() != r.get());
}
template<class T, class U> inline bool operator<=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() <= r.get());
}
template<class T, class U> inline bool operator<(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() < r.get());
}
template<class T, class U> inline bool operator>=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() >= r.get());
}
template<class T, class U> inline bool operator>(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
{
    return (l.get() > r.get());
}

// static cast of shared_ptr
template<class T, class U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& ptr) // never throws
{
    return shared_ptr<T>(ptr, static_cast<typename shared_ptr<T>::element_type*>(ptr.get()));
}

// dynamic cast of shared_ptr
template<class T, class U>
shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& ptr) // never throws
{
    T* p = dynamic_cast<typename shared_ptr<T>::element_type*>(ptr.get());
    if (NULL != p)
    {
        return shared_ptr<T>(ptr, p);
    }
    else
    {
        return shared_ptr<T>();
    }
}

} // namespace Log

#endif
<|endoftext|>


<commit_before>/**
 * @file
 *  Zenderer/Math/Vector.hpp - A vector class representing a position
 *  in 3D (or 2D) space, fully supporting the mathematical operations
 *  typical of such a structure.
 *
 * @author      George Kudrayvtsev (halcyon)
 * @version     1.1.3
 * @copyright   Apache License v2.0
 *  Licensed under the Apache License, Version 2.0 (the "License").         \n
 *  You may not use this file except in compliance with the License.        \n
 *  You may obtain a copy of the License at:
 *  http://www.apache.org/licenses/LICENSE-2.0                              \n
 *  Unless required by applicable law or agreed to in writing, software     \n
 *  distributed under the License is distributed on an "AS IS" BASIS,       \n
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n
 *  See the License for the specific language governing permissions and     \n
 *  limitations under the License.
 *
 * @addtogroup Math
 * @{
 **/

#ifndef IRON_CLAD__MATH__VECTOR_2_HPP
#define IRON_CLAD__MATH__VECTOR_2_HPP

#include <cmath>
#include <ostream>

#include "Zenderer/Core/Types.hpp"
#include "MathCore.hpp"

namespace zen
{
namespace math
{
    /**
     * Forward declaration of a 4x4 matrix for use in
     * 2D vector translation.
     **/
    class ZEN_API matrix4x4_t;

    /**
     * Represents a point in 3D rectangular-coordinate space.
     *  Supports all vector operations such as cross products,
     *  dot products, movement, scaling, and rotation.
     *
     *  The class is templated to store any sort of POD values that
     *  you'd like, such as `float`, `int`, `uint32_t`, etc.
     *  Beware that any operations between mixed vector types will
     *  return the type of the vector on the left-hand side of the
     *  operation. e.g.:
     *
     *  @code
     *  Vector<int> A(1, 2, 3);
     *  Vector<float> B(1.1, 2.2, 3.3);
     *
     *  Vector<float> C = A + B;    // INVALID!
     *  Vector<int> C = A + B;      // VALID
     *  @endcode
     *
     *  Thus if you need a higher level of precision, keep that vector
     *  instance on the right-hand side.
     *
     *  There is a built-in shortcut to `vector_t` that is a floating-point
     *  vector representation that is used throughout the engine.
     *
     * @todo    Add support for translation via matrices.
     * @note    There is support for creating translation matrices via
     *          vectors but not vice-versa.
     *
     * @see     USE_DOUBLE_PRECISION
     **/
    template<typename T>
    struct ZEN_API Vector
    {
        /// The publicly-accessible vector components.
        T x, y, z;

        /// Default constructor that moves the vector to the origin.
        Vector() : x(0), y(0), z(0) {}

        /// Constructor for any coordinate space (defaults to 2D).
        Vector(real_t x, real_t y, real_t z = 0) : x(x), y(y), z(z) {}

        /// Copies vector components from one to another.
        template<typename U>
        Vector(const Vector<U>& C) : x(C.x), y(C.y), z(C.z) {}

        /// Assigns one vector to another.
        template<typename U> inline
        Vector<T>& operator=(const Vector<U>& Copy);

        /// Compares two vectors for equivalence.
        template<typename U> inline
        bool operator==(const Vector<U>& Other) const;

        /// Opposite of Vector::operator==()
        template<typename U> inline
        bool operator!=(const Vector<U>& Other) const;

        // Begin mathematical vector operations.

        /**
         * Calculates the cross product of two vectors.
         *  The cross product of two vectors is a vector that is
         *  perpendicular to both operators. e.g. i = j ^ k.
         *
         * @param   Other   The vector to cross with
         *
         * @return  A 3D vector normal to both vectors.
         **/
        template<typename U> inline
        Vector<T> operator^(const Vector<U>& Other) const;

        /**
         * Calculates the dot product of two vectors.
         *  The dot product is useful in finding the angle between two
         *  vectors. The formula for that is as follows:
         *
         *      cos(T) = (A . B) / (|| A || * || B ||)
         *
         *  The actual operation is defined as such:
         *
         *      A = (x1, y1, z1)
         *      B = (x2, y2, z2)
         *      A . B = x1*x2 + y1*y2 + z1*z2
         *
         * @param   Other   The vector to dot with.
         *
         * @return  The dot product as a scalar.
         **/
        template<typename U> inline
        real_t operator*(const Vector<U>& Other) const;

        /**
         * Multiplies each component by a scalar factor.
         * @param   scalar  The component scaling factor
         * @return  A 2D resultant vector.
         **/
        inline Vector<T> operator*(const real_t scalar) const;

        /**
         * Divides each component by a scalar factor.
         * @param   scalar  The component scaling factor
         * @return  A 2D resultant vector.
         **/
        inline Vector<T> operator/(const real_t scalar) const;

        /**
         * Adds a given vector to the current vector, returning the result.
         * @param   Other   The vector to add (component-wise)
         * @return  A 2D resultant vector.
         **/
        template<typename U> inline
        Vector<T> operator+(const Vector<U>& Other) const;

        /**
         * Adds a value to both components of the current vector.
         * @param   value   The value to add
         * @return  A 2D resultant vector.
         **/
        inline Vector<T> operator+(const real_t value) const;

        /**
         * Subtracts a given vector from the current vector, returning the result.
         * @param   Other   The vector to subtract from the current vector
         * @return  A 2D resultant vector.
         **/
        template<typename U> inline
        Vector<T> operator-(const Vector<U>& Other) const;

        /**
         * Normalizes the current vector.
         *  This *DOES* modify the current vector, and makes it into
         *  a unit vector version of itself.
         **/
        inline void Normalize();

        /// Returns the current vectors magnitude, or 'norm'.
        inline real_t Magnitude() const;

        /**
         * Rotates the current vector using the rotation matrix.
         *  The rotation matrix (in right-hand Cartesian plane)
         *  is defined as being
         *  | x | | cos(d), -sin(d) |
         *  | y | | sin(d),  cos(d) |
         *
         *  But in the OpenGL coordinate system, the origin is in
         *  the top-left, as opposed to bottom-left, as shown above.
         *  So rotations are actually inverted and the matrix is
         *  | x | | cos(d),  sin(d) |
         *  | y | | -sin(d), cos(d) |
         *
         *  So the final rotation in OpenGL would be:
         *      x =  x * cos(d) + y * sin(d)
         *      y = -x * sin(d) + y * cos(d)
         *
         * @param   radians The rotation angle in radians.
         *
         * @info    The coordinate system adjustment was removed.
         **/
        inline void Rotate(const real_t radians);

        /**
         * Translates the current vector by a matrix.
         * @param   TransMat    Translation matrix
         **/
        void Translate(const matrix4x4_t& TransMat);

        /**
         * Returns a scalar cross product value between two 2D vectors.
         *  Given a vector v = <x1, y1> and a vector w = <x2, y2>, their
         *  cross-product is determined as <0, 0, x1*y2 - y1*x2>.
         *  So, this method returns the third component.
         *
         *  This value can be used to determine which side of a vector
         *  another vector is on. If the return value is negative, the
         *  "Other" vector is on the left (going ccw). If positive,
         *  it's on the right (going c/w). This can also be done by
         *  examining the dot product.
         *
         * @param   Other   Vector to test cross product on
         *
         * @return  2D cross product (z-component of 3D cross).
         *
         * @see     operator*(const Vector&)
         **/
        template<typename U> inline
        real_t Cross2D(const Vector<U>& Other) const;

        /**
         * Returns a normalized version of the current vector.
         * @see Vector::Normalize()
         **/
        inline Vector<T> GetNormalized() const;

        /// Outputs the vector in the form `<x, y, z>`
        template<typename U> friend
        std::ostream& operator<<(std::ostream& out,
                                 const Vector<U>& Other);
    };

    #include "Vector.inl"

    /// A shortcut for the default vector implementation in the engine.
    typedef Vector<real_t> vector_t;

}   // namespace math
}   // namespace ic

#endif // IRON_CLAD__MATH__VECTOR_2_HPP

/** @} **/
<commit_msg>Vector constructor uses template<commit_after>/**
 * @file
 *  Zenderer/Math/Vector.hpp - A vector class representing a position
 *  in 3D (or 2D) space, fully supporting the mathematical operations
 *  typical of such a structure.
 *
 * @author      George Kudrayvtsev (halcyon)
 * @version     1.1.3
 * @copyright   Apache License v2.0
 *  Licensed under the Apache License, Version 2.0 (the "License").         \n
 *  You may not use this file except in compliance with the License.        \n
 *  You may obtain a copy of the License at:
 *  http://www.apache.org/licenses/LICENSE-2.0                              \n
 *  Unless required by applicable law or agreed to in writing, software     \n
 *  distributed under the License is distributed on an "AS IS" BASIS,       \n
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n
 *  See the License for the specific language governing permissions and     \n
 *  limitations under the License.
 *
 * @addtogroup Math
 * @{
 **/

#ifndef IRON_CLAD__MATH__VECTOR_2_HPP
#define IRON_CLAD__MATH__VECTOR_2_HPP

#include <cmath>
#include <ostream>

#include "Zenderer/Core/Types.hpp"
#include "MathCore.hpp"

namespace zen
{
namespace math
{
    /**
     * Forward declaration of a 4x4 matrix for use in
     * 2D vector translation.
     **/
    class ZEN_API matrix4x4_t;

    /**
     * Represents a point in 3D rectangular-coordinate space.
     *  Supports all vector operations such as cross products,
     *  dot products, movement, scaling, and rotation.
     *
     *  The class is templated to store any sort of POD values that
     *  you'd like, such as `float`, `int`, `uint32_t`, etc.
     *  Beware that any operations between mixed vector types will
     *  return the type of the vector on the left-hand side of the
     *  operation. e.g.:
     *
     *  @code
     *  Vector<int> A(1, 2, 3);
     *  Vector<float> B(1.1, 2.2, 3.3);
     *
     *  Vector<float> C = A + B;    // INVALID!
     *  Vector<int> C = A + B;      // VALID
     *  @endcode
     *
     *  Thus if you need a higher level of precision, keep that vector
     *  instance on the right-hand side.
     *
     *  There is a built-in shortcut to `vector_t` that is a floating-point
     *  vector representation that is used throughout the engine.
     *
     * @todo    Add support for translation via matrices.
     * @note    There is support for creating translation matrices via
     *          vectors but not vice-versa.
     *
     * @see     USE_DOUBLE_PRECISION
     **/
    template<typename T>
    struct ZEN_API Vector
    {
        /// The publicly-accessible vector components.
        T x, y, z;

        /// Default constructor that moves the vector to the origin.
        Vector() : x(0), y(0), z(0) {}

        /// Constructor for any coordinate space (defaults to 2D).
        Vector(T x, T y, T z = 0) : x(x), y(y), z(z) {}

        /// Copies vector components from one to another.
        template<typename U>
        Vector(const Vector<U>& C) : x(C.x), y(C.y), z(C.z) {}

        /// Assigns one vector to another.
        template<typename U> inline
        Vector<T>& operator=(const Vector<U>& Copy);

        /// Compares two vectors for equivalence.
        template<typename U> inline
        bool operator==(const Vector<U>& Other) const;

        /// Opposite of Vector::operator==()
        template<typename U> inline
        bool operator!=(const Vector<U>& Other) const;

        // Begin mathematical vector operations.

        /**
         * Calculates the cross product of two vectors.
         *  The cross product of two vectors is a vector that is
         *  perpendicular to both operators. e.g. i = j ^ k.
         *
         * @param   Other   The vector to cross with
         *
         * @return  A 3D vector normal to both vectors.
         **/
        template<typename U> inline
        Vector<T> operator^(const Vector<U>& Other) const;

        /**
         * Calculates the dot product of two vectors.
         *  The dot product is useful in finding the angle between two
         *  vectors. The formula for that is as follows:
         *
         *      cos(T) = (A . B) / (|| A || * || B ||)
         *
         *  The actual operation is defined as such:
         *
         *      A = (x1, y1, z1)
         *      B = (x2, y2, z2)
         *      A . B = x1*x2 + y1*y2 + z1*z2
         *
         * @param   Other   The vector to dot with.
         *
         * @return  The dot product as a scalar.
         **/
        template<typename U> inline
        real_t operator*(const Vector<U>& Other) const;

        /**
         * Multiplies each component by a scalar factor.
         * @param   scalar  The component scaling factor
         * @return  A 2D resultant vector.
         **/
        inline Vector<T> operator*(const real_t scalar) const;

        /**
         * Divides each component by a scalar factor.
         * @param   scalar  The component scaling factor
         * @return  A 2D resultant vector.
         **/
        inline Vector<T> operator/(const real_t scalar) const;

        /**
         * Adds a given vector to the current vector, returning the result.
         * @param   Other   The vector to add (component-wise)
         * @return  A 2D resultant vector.
         **/
        template<typename U> inline
        Vector<T> operator+(const Vector<U>& Other) const;

        /**
         * Adds a value to both components of the current vector.
         * @param   value   The value to add
         * @return  A 2D resultant vector.
         **/
        inline Vector<T> operator+(const real_t value) const;

        /**
         * Subtracts a given vector from the current vector, returning the result.
         * @param   Other   The vector to subtract from the current vector
         * @return  A 2D resultant vector.
         **/
        template<typename U> inline
        Vector<T> operator-(const Vector<U>& Other) const;

        /**
         * Normalizes the current vector.
         *  This *DOES* modify the current vector, and makes it into
         *  a unit vector version of itself.
         **/
        inline void Normalize();

        /// Returns the current vectors magnitude, or 'norm'.
        inline real_t Magnitude() const;

        /**
         * Rotates the current vector using the rotation matrix.
         *  The rotation matrix (in right-hand Cartesian plane)
         *  is defined as being
         *  | x | | cos(d), -sin(d) |
         *  | y | | sin(d),  cos(d) |
         *
         *  But in the OpenGL coordinate system, the origin is in
         *  the top-left, as opposed to bottom-left, as shown above.
         *  So rotations are actually inverted and the matrix is
         *  | x | | cos(d),  sin(d) |
         *  | y | | -sin(d), cos(d) |
         *
         *  So the final rotation in OpenGL would be:
         *      x =  x * cos(d) + y * sin(d)
         *      y = -x * sin(d) + y * cos(d)
         *
         * @param   radians The rotation angle in radians.
         *
         * @info    The coordinate system adjustment was removed.
         **/
        inline void Rotate(const real_t radians);

        /**
         * Translates the current vector by a matrix.
         * @param   TransMat    Translation matrix
         **/
        void Translate(const matrix4x4_t& TransMat);

        /**
         * Returns a scalar cross product value between two 2D vectors.
         *  Given a vector v = <x1, y1> and a vector w = <x2, y2>, their
         *  cross-product is determined as <0, 0, x1*y2 - y1*x2>.
         *  So, this method returns the third component.
         *
         *  This value can be used to determine which side of a vector
         *  another vector is on. If the return value is negative, the
         *  "Other" vector is on the left (going ccw). If positive,
         *  it's on the right (going c/w). This can also be done by
         *  examining the dot product.
         *
         * @param   Other   Vector to test cross product on
         *
         * @return  2D cross product (z-component of 3D cross).
         *
         * @see     operator*(const Vector&)
         **/
        template<typename U> inline
        real_t Cross2D(const Vector<U>& Other) const;

        /**
         * Returns a normalized version of the current vector.
         * @see Vector::Normalize()
         **/
        inline Vector<T> GetNormalized() const;

        /// Outputs the vector in the form `<x, y, z>`
        template<typename U> friend
        std::ostream& operator<<(std::ostream& out,
                                 const Vector<U>& Other);
    };

    #include "Vector.inl"

    /// A shortcut for the default vector implementation in the engine.
    typedef Vector<real_t> vector_t;

}   // namespace math
}   // namespace ic

#endif // IRON_CLAD__MATH__VECTOR_2_HPP

/** @} **/
<|endoftext|>


<commit_before>//
//
// Copyright (c) 2017, 2019 Ivan Baidakou (basiliscos) (the dot dmol at gmail
// dot com)
//
// Distributed under the MIT Software License
//
#pragma once

#include "../Protocol.hpp"
#include "../Result.hpp"
#include <memory>
#include <utility>

#include <boost/asio.hpp>
#include <boost/variant.hpp>

namespace bredis {

template <typename Iterator, typename Policy> struct result_handler_t;

template <typename Iterator>
struct result_handler_t<Iterator, parsing_policy::drop_result> {
    using policy_t = parsing_policy::drop_result;
    using positive_result_t = parse_result_mapper_t<Iterator, policy_t>;

    std::size_t replies_count;
    size_t cumulative_consumption;
    size_t count;
    positive_result_t result;

    result_handler_t(std::size_t replies_count_)
        : replies_count{replies_count_},
          cumulative_consumption{0}, count{0}, result{0} {}

    void init() {
        // NO-OP;
    }

    bool on_result(positive_result_t &&parse_result) {
        ++count;
        cumulative_consumption += parse_result.consumed;
        return count < replies_count;
    }

    void complete_result() {
        result = positive_result_t{cumulative_consumption};
    }
};

template <typename Iterator>
struct result_handler_t<Iterator, parsing_policy::keep_result> {
    using policy_t = parsing_policy::keep_result;
    using positive_result_t = parse_result_mapper_t<Iterator, policy_t>;

    std::size_t replies_count;
    size_t cumulative_consumption;
    size_t count;
    positive_result_t result;
    markers::array_holder_t<Iterator> tmp_results;

    result_handler_t(std::size_t replies_count_)
        : replies_count{replies_count_}, cumulative_consumption{0}, count{0} {}

    void init() { tmp_results.elements.reserve(replies_count); }

    bool on_result(positive_result_t &&parse_result) {
        tmp_results.elements.emplace_back(std::move(parse_result.result));
        ++count;
        cumulative_consumption += parse_result.consumed;
        return count < replies_count;
    }

    void complete_result() {
        if (replies_count == 1) {
            result = positive_result_t{std::move(tmp_results.elements[0]),
                                       cumulative_consumption};
        } else {
            result = positive_result_t{std::move(tmp_results),
                                       cumulative_consumption};
        }
    }
};

template <typename DynamicBuffer, typename Policy> struct async_read_op_impl {
    DynamicBuffer &rx_buff_;
    std::size_t replies_count_;

    async_read_op_impl(DynamicBuffer &rx_buff, std::size_t replies_count)
        : rx_buff_{rx_buff}, replies_count_{replies_count} {}
    using Iterator = typename to_iterator<DynamicBuffer>::iterator_t;
    using ResultHandler = result_handler_t<Iterator, Policy>;
    using positive_result_t = parse_result_mapper_t<Iterator, Policy>;

    positive_result_t op(boost::system::error_code &error_code,
                         std::size_t /*bytes_transferred*/) {

        ResultHandler result_handler(replies_count_);

        if (!error_code) {
            auto const_buff = rx_buff_.data();
            auto begin = Iterator::begin(const_buff);
            auto end = Iterator::end(const_buff);

            result_handler.init();

            bool continue_parsing;
            do {
                using boost::get;
                auto parse_result =
                    Protocol::parse<Iterator, Policy>(begin, end);
                auto *parse_error = boost::get<protocol_error_t>(&parse_result);
                if (parse_error) {
                    error_code = parse_error->code;
                    continue_parsing = false;
                } else {
                    auto &positive_result =
                        get<positive_result_t>(parse_result);
                    begin += positive_result.consumed;
                    continue_parsing =
                        result_handler.on_result(std::move(positive_result));
                }
            } while (continue_parsing);

            /* check again, as protocol error might be met */
            if (!error_code) {
                result_handler.complete_result();
            }
        }
        return result_handler.result;
    }
};

template <typename NextLayer, typename DynamicBuffer, typename ReadCallback,
          typename Policy>
class async_read_op {
    NextLayer &stream_;
    DynamicBuffer &rx_buff_;
    std::size_t replies_count_;
    ReadCallback callback_;

  public:
    async_read_op(async_read_op &&) = default;
    async_read_op(const async_read_op &) = default;

    template <class DeducedHandler>
    async_read_op(DeducedHandler &&deduced_handler, NextLayer &stream,
                  DynamicBuffer &rx_buff, std::size_t replies_count)
        : stream_(stream), rx_buff_(rx_buff), replies_count_(replies_count),
          callback_(std::forward<ReadCallback>(deduced_handler)) {}

    void operator()(boost::system::error_code, std::size_t bytes_transferred);

    friend bool asio_handler_is_continuation(async_read_op *op) {
        using boost::asio::asio_handler_is_continuation;
        return asio_handler_is_continuation(std::addressof(op->callback_));
    }

    friend void *asio_handler_allocate(std::size_t size, async_read_op *op) {
        using boost::asio::asio_handler_allocate;
        return asio_handler_allocate(size, std::addressof(op->callback_));
    }

    friend void asio_handler_deallocate(void *p, std::size_t size,
                                        async_read_op *op) {
        using boost::asio::asio_handler_deallocate;
        return asio_handler_deallocate(p, size, std::addressof(op->callback_));
    }

    template <class Function>
    friend void asio_handler_invoke(Function &&f, async_read_op *op) {
        using boost::asio::asio_handler_invoke;
        return asio_handler_invoke(f, std::addressof(op->callback_));
    }
};

template <typename NextLayer, typename DynamicBuffer, typename ReadCallback,
          typename Policy>
void async_read_op<NextLayer, DynamicBuffer, ReadCallback, Policy>::
operator()(boost::system::error_code error_code,
           std::size_t bytes_transferred) {
    using op_impl = async_read_op_impl<DynamicBuffer, Policy>;
    callback_(
        error_code,
        op_impl(rx_buff_, replies_count_).op(error_code, bytes_transferred));
}

} // namespace bredis
<commit_msg>It should be better<commit_after>//
//
// Copyright (c) 2017, 2019 Ivan Baidakou (basiliscos) (the dot dmol at gmail
// dot com)
//
// Distributed under the MIT Software License
//
#pragma once

#include "../Protocol.hpp"
#include "../Result.hpp"
#include <memory>
#include <utility>

#include <boost/asio.hpp>
#include <boost/variant.hpp>

namespace bredis {

struct base_result_visitor_t : public boost::static_visitor<std::size_t> {
    boost::system::error_code &error_code_;

    base_result_visitor_t(boost::system::error_code &error_code)
        : error_code_{error_code} {}

    std::size_t operator()(const not_enough_data_t &) const { std::abort(); }

    std::size_t operator()(const protocol_error_t &value) const {
        error_code_ = value.code;
        return 0;
    }
};

template <typename Iterator, typename Policy> struct result_visitor_t;

template <typename Iterator>
struct result_visitor_t<Iterator, parsing_policy::drop_result>
    : public base_result_visitor_t {
    using base_t = base_result_visitor_t;
    using policy_t = parsing_policy::drop_result;
    using positive_result_t = parse_result_mapper_t<Iterator, policy_t>;

    std::size_t replies_count;
    positive_result_t &result;
    size_t cumulative_consumption;
    size_t count;

    static positive_result_t construct() { return positive_result_t{0}; }

    result_visitor_t(boost::system::error_code &error_code,
                     std::size_t replies_count_, positive_result_t &result_)
        : base_t{error_code}, replies_count{replies_count_}, result{result_},
          cumulative_consumption{0}, count{0} {}

    void init() {
        // NO-OP;
    }

    using base_t::operator();

    size_t operator()(const positive_result_t &parse_result) {
        ++count;
        cumulative_consumption += parse_result.consumed;
        // return parse_result.consumed;
        return count < replies_count ? parse_result.consumed : 0;
    }

    void complete_result() {
        result = positive_result_t{cumulative_consumption};
    }
};

template <typename Iterator>
struct result_visitor_t<Iterator, parsing_policy::keep_result>
    : public base_result_visitor_t {
    using base_t = base_result_visitor_t;
    using policy_t = parsing_policy::keep_result;
    using positive_result_t = parse_result_mapper_t<Iterator, policy_t>;

    std::size_t replies_count;
    positive_result_t &result;
    size_t cumulative_consumption;
    size_t count;
    markers::array_holder_t<Iterator> tmp_results;

    static positive_result_t construct() { return positive_result_t{}; }

    result_visitor_t(boost::system::error_code &error_code,
                     std::size_t replies_count_, positive_result_t &result_)
        : base_t{error_code}, replies_count{replies_count_}, result{result_},
          cumulative_consumption{0}, count{0} {}

    void init() { tmp_results.elements.reserve(replies_count); }

    using base_t::operator();

    size_t operator()(const positive_result_t &parse_result) {
        tmp_results.elements.emplace_back(std::move(parse_result.result));
        ++count;
        cumulative_consumption += parse_result.consumed;
        return count < replies_count ? parse_result.consumed : 0;
    }

    void complete_result() {
        if (replies_count == 1) {
            result = positive_result_t{std::move(tmp_results.elements[0]),
                                       cumulative_consumption};
        } else {
            result = positive_result_t{std::move(tmp_results),
                                       cumulative_consumption};
        }
    }
};

template <typename DynamicBuffer, typename Policy> struct async_read_op_impl {
    DynamicBuffer &rx_buff_;
    std::size_t replies_count_;

    async_read_op_impl(DynamicBuffer &rx_buff, std::size_t replies_count)
        : rx_buff_{rx_buff}, replies_count_{replies_count} {}
    using Iterator = typename to_iterator<DynamicBuffer>::iterator_t;
    using ResultVisitor = result_visitor_t<Iterator, Policy>;
    using positive_result_t = parse_result_mapper_t<Iterator, Policy>;

    positive_result_t op(boost::system::error_code &error_code,
                         std::size_t /*bytes_transferred*/) {

        auto result = ResultVisitor::construct();

        if (!error_code) {
            auto const_buff = rx_buff_.data();
            auto begin = Iterator::begin(const_buff);
            auto end = Iterator::end(const_buff);

            ResultVisitor visitor(error_code, replies_count_, result);
            visitor.init();

            std::size_t consumed{0};
            do {
                begin += consumed;
                auto parse_result =
                    Protocol::parse<Iterator, Policy>(begin, end);
                consumed = boost::apply_visitor(visitor, parse_result);
            } while (consumed);

            /* check again, as protocol error might be met */
            if (!error_code) {
                visitor.complete_result();
            }
        }
        return result;
    }
};

template <typename NextLayer, typename DynamicBuffer, typename ReadCallback,
          typename Policy>
class async_read_op {
    NextLayer &stream_;
    DynamicBuffer &rx_buff_;
    std::size_t replies_count_;
    ReadCallback callback_;

  public:
    async_read_op(async_read_op &&) = default;
    async_read_op(const async_read_op &) = default;

    template <class DeducedHandler>
    async_read_op(DeducedHandler &&deduced_handler, NextLayer &stream,
                  DynamicBuffer &rx_buff, std::size_t replies_count)
        : stream_(stream), rx_buff_(rx_buff), replies_count_(replies_count),
          callback_(std::forward<ReadCallback>(deduced_handler)) {}

    void operator()(boost::system::error_code, std::size_t bytes_transferred);

    friend bool asio_handler_is_continuation(async_read_op *op) {
        using boost::asio::asio_handler_is_continuation;
        return asio_handler_is_continuation(std::addressof(op->callback_));
    }

    friend void *asio_handler_allocate(std::size_t size, async_read_op *op) {
        using boost::asio::asio_handler_allocate;
        return asio_handler_allocate(size, std::addressof(op->callback_));
    }

    friend void asio_handler_deallocate(void *p, std::size_t size,
                                        async_read_op *op) {
        using boost::asio::asio_handler_deallocate;
        return asio_handler_deallocate(p, size, std::addressof(op->callback_));
    }

    template <class Function>
    friend void asio_handler_invoke(Function &&f, async_read_op *op) {
        using boost::asio::asio_handler_invoke;
        return asio_handler_invoke(f, std::addressof(op->callback_));
    }
};

template <typename NextLayer, typename DynamicBuffer, typename ReadCallback,
          typename Policy>
void async_read_op<NextLayer, DynamicBuffer, ReadCallback, Policy>::
operator()(boost::system::error_code error_code,
           std::size_t bytes_transferred) {
    using op_impl = async_read_op_impl<DynamicBuffer, Policy>;
    callback_(
        error_code,
        op_impl(rx_buff_, replies_count_).op(error_code, bytes_transferred));
}

} // namespace bredis
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Julian Ganz
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#ifndef CMOH_ACCESSOR_BUNDLE_HPP__
#define CMOH_ACCESSOR_BUNDLE_HPP__

// std includes
#include <type_traits>
#include <utility>

// local includes
#include <cmoh/selectable_items.hpp>
#include <cmoh/utils.hpp>

namespace cmoh {

/**
 * Check whether a type can construct an object from some attributes
 *
 * This checks whether the `SupposedConstructor` features a template with the
 * name `is_initializable_from`. If it does, it evaluates that template with
 * the `PassedAttributes` and presents that result via the static member
 * `value`. Otherwise, `value` is `false`.
 */
template <
    typename SupposedConstructor, ///< type which _may_ be a constructor type
    typename ...PassedAttributes ///< attributes available for construction
>
struct is_initializable_from {
private:
    /**
     * Check whether a type can be used to initialize anything
     *
     * This metafunction effectively checks whether a type features a template with
     * the name `is_initializable_from` for which an instantiation with zero
     * parameters exist.
     */
    template <
        typename T, ///< type which may feature the template
        typename = void
    >
    struct has_is_initializable_from : std::false_type {};

    // specialization for types featuring the name
    template <
        typename T
    >
    struct has_is_initializable_from<
        T,
        util::void_t<typename T::template is_initializable_from<>>
    > : std::true_type {};

    /**
     * Internal helper for selective evaluation of is_initializable_from
     *
     * Evaluates `T::is_initializable_from<Attributes...>` only if `flag` is
     * `true`.
     */
    template <
        typename T, ///< type featuring `is_initializable_from`
        bool flag, ///< flag controlling the evaluation
        typename ...Attributes ///< attributes to pass as template parameters
    >
    struct helper : std::false_type {};

    // specialization for evaluating the template
    template <
        typename T,
        typename ...Attributes
    >
    struct helper<T, true, Attributes...> :
        T::template is_initializable_from<Attributes...> {};

public:
    static constexpr bool value = helper<
        SupposedConstructor,
        has_is_initializable_from<SupposedConstructor>::value,
        PassedAttributes...
    >::value;
};

/**
 * Check whether an accessor accesses a specific attribute
 *
 * This checks whether the accessor provided features a type `attribute`
 * identical to the attribute provided.
 */
template <
    typename Accessor, ///< accessor to test for the attribute
    typename Attribute, ///< attribute to be accessed
    typename = void
>
struct accesses_attribute : std::false_type {};

// Specialization for accessors featuring a type `attr`
template <
    typename Accessor,
    typename Attribute
>
struct accesses_attribute<
    Accessor,
    Attribute,
    util::void_t<typename Accessor::attribute>
> : std::is_same<Attribute, typename Accessor::attribute> {};

/**
 * Accessor bundle
 *
 * Instantiations of this template bundle accessors and make them conveniently
 * accessible as a group, posing as an abstraction layer.
 *
 * TODO: further explanation
 *
 * Users are discouraged from constructing accessor bundles directly. Use
 * `bundle()` instread as a factory.
 */
template <
    typename ...Accessors
>
struct accessor_bundle {
    typedef
        typename util::common_type<typename Accessors::object_type...>::type
        object_type;

    accessor_bundle(Accessors... accessors) :
            _accessors(std::forward<Accessors>(accessors)...) {}
    accessor_bundle(accessor_bundle const&) = default;
    accessor_bundle(accessor_bundle&&) = default;
    accessor_bundle() = delete;

    /**
     * Set the value of a specific attribute on an object
     */
    template <
        typename ...Attributes ///< attributes from which to construct an object
    >
    object_type
    create(
        typename Attributes::type&&... values ///< value to set
    ) const {
        auto factory = _accessors.
            template get<is_initializable_from<Accessors, Attributes...>...>();

        // construct the object itself
        auto retval{factory.template create<Attributes...>(
            std::forward<typename Attributes::type>(values)...
        )};

        initialize_if_unused<decltype(factory), Attributes...>(
            retval,
            std::forward<typename Attributes::type>(values)...
        );

        return retval;
    }

    /**
     * Get the value of a specific attribute from an object
     *
     * \returns the value of the attribute
     */
    template <
        typename Attribute ///< attribute to get
    >
    typename Attribute::type
    get(
        object_type const& obj ///< object from which to get the value
    ) const {
        return _accessors.
            template get<accesses_attribute<Accessors, Attribute>...>().
            get(obj);
    }

    /**
     * Set the value of a specific attribute on an object
     */
    template <
        typename Attribute ///< attribute to set
    >
    void
    set(
        object_type& obj, ///< object on which to set the attribute
        typename Attribute::type&& value ///< value to set
    ) const {
        _accessors.
            template get<accesses_attribute<Accessors, Attribute>...>().
            set(obj, std::forward<typename Attribute::type>(value));
    }

private:
    /**
     * Initialize attributes which are not used by a specific constructor
     */
    template <
        typename Constructor, ///< constructor to consider
        typename Attribute0, ///< first of the attributes
        typename ...Attributes ///< rest of the attributes
    >
    void
    initialize_if_unused(
        object_type& obj, ///< object on which to set the attributes' values
        typename Attribute0::type&& value0, ///< first of the values
        typename Attributes::type&&... values ///< rest of the values
    ) const {
        initialize_single_if_unused<Constructor, Attribute0>(
            obj,
            std::forward<typename Attribute0::type>(value0)
        );

        // recurse
        initialize_if_unused<Constructor, Attributes...>(
            obj,
            std::forward<typename Attributes::type>(values)...
        );
    }

    // overload for an empty list of attributes
    template <
        typename Constructor
    >
    void
    initialize_if_unused(
        object_type& obj
    ) const {}

    /**
     * Initialize a single attribute if it is not used by a specific constructor
     */
    template <
        typename Constructor, ///< constructor to consider
        typename Attribute ///< attribute to set
    >
    typename std::enable_if<!Constructor::template uses<Attribute>::value>::type
    initialize_single_if_unused(
        object_type& obj, ///< object on which to set the attribute's value
        typename Attribute::type&& value ///< value to set
    ) const {
        // TODO: static assertion for unsettable attributes
        set<Attribute>(obj, std::forward<typename Attribute::type>(value));
    }

    // overload for attributes which are used by the constructor specified
    template <
        typename Constructor,
        typename Attribute
    >
    typename std::enable_if<Constructor::template uses<Attribute>::value>::type
    initialize_single_if_unused(
        object_type& obj,
        typename Attribute::type&& value
    ) const {}

    selectable_items<Accessors...> _accessors;
};

/**
 * Construct an accessor bundle from a bunch of accessors
 *
 * \returns an accessor bundle holding all the accessors supplied
 */
template <
    typename ...Accessors
>
constexpr
const
accessor_bundle<Accessors...>
bundle(
    Accessors&&... accessors ///< accessors to bundle
) {
    return accessor_bundle<Accessors...>(std::forward<Accessors>(accessors)...);
}

}

#endif
<commit_msg>Seperate declaration of _accessors from the diefinition of its type<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Julian Ganz
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#ifndef CMOH_ACCESSOR_BUNDLE_HPP__
#define CMOH_ACCESSOR_BUNDLE_HPP__

// std includes
#include <type_traits>
#include <utility>

// local includes
#include <cmoh/selectable_items.hpp>
#include <cmoh/utils.hpp>

namespace cmoh {

/**
 * Check whether a type can construct an object from some attributes
 *
 * This checks whether the `SupposedConstructor` features a template with the
 * name `is_initializable_from`. If it does, it evaluates that template with
 * the `PassedAttributes` and presents that result via the static member
 * `value`. Otherwise, `value` is `false`.
 */
template <
    typename SupposedConstructor, ///< type which _may_ be a constructor type
    typename ...PassedAttributes ///< attributes available for construction
>
struct is_initializable_from {
private:
    /**
     * Check whether a type can be used to initialize anything
     *
     * This metafunction effectively checks whether a type features a template with
     * the name `is_initializable_from` for which an instantiation with zero
     * parameters exist.
     */
    template <
        typename T, ///< type which may feature the template
        typename = void
    >
    struct has_is_initializable_from : std::false_type {};

    // specialization for types featuring the name
    template <
        typename T
    >
    struct has_is_initializable_from<
        T,
        util::void_t<typename T::template is_initializable_from<>>
    > : std::true_type {};

    /**
     * Internal helper for selective evaluation of is_initializable_from
     *
     * Evaluates `T::is_initializable_from<Attributes...>` only if `flag` is
     * `true`.
     */
    template <
        typename T, ///< type featuring `is_initializable_from`
        bool flag, ///< flag controlling the evaluation
        typename ...Attributes ///< attributes to pass as template parameters
    >
    struct helper : std::false_type {};

    // specialization for evaluating the template
    template <
        typename T,
        typename ...Attributes
    >
    struct helper<T, true, Attributes...> :
        T::template is_initializable_from<Attributes...> {};

public:
    static constexpr bool value = helper<
        SupposedConstructor,
        has_is_initializable_from<SupposedConstructor>::value,
        PassedAttributes...
    >::value;
};

/**
 * Check whether an accessor accesses a specific attribute
 *
 * This checks whether the accessor provided features a type `attribute`
 * identical to the attribute provided.
 */
template <
    typename Accessor, ///< accessor to test for the attribute
    typename Attribute, ///< attribute to be accessed
    typename = void
>
struct accesses_attribute : std::false_type {};

// Specialization for accessors featuring a type `attr`
template <
    typename Accessor,
    typename Attribute
>
struct accesses_attribute<
    Accessor,
    Attribute,
    util::void_t<typename Accessor::attribute>
> : std::is_same<Attribute, typename Accessor::attribute> {};

/**
 * Accessor bundle
 *
 * Instantiations of this template bundle accessors and make them conveniently
 * accessible as a group, posing as an abstraction layer.
 *
 * TODO: further explanation
 *
 * Users are discouraged from constructing accessor bundles directly. Use
 * `bundle()` instread as a factory.
 */
template <
    typename ...Accessors
>
struct accessor_bundle {
private:
    typedef selectable_items<Accessors...> accessors;

public:
    typedef
        typename util::common_type<typename Accessors::object_type...>::type
        object_type;

    accessor_bundle(Accessors... accessors) :
            _accessors(std::forward<Accessors>(accessors)...) {}
    accessor_bundle(accessor_bundle const&) = default;
    accessor_bundle(accessor_bundle&&) = default;
    accessor_bundle() = delete;

    /**
     * Set the value of a specific attribute on an object
     */
    template <
        typename ...Attributes ///< attributes from which to construct an object
    >
    object_type
    create(
        typename Attributes::type&&... values ///< value to set
    ) const {
        auto factory = _accessors.
            template get<is_initializable_from<Accessors, Attributes...>...>();

        // construct the object itself
        auto retval{factory.template create<Attributes...>(
            std::forward<typename Attributes::type>(values)...
        )};

        initialize_if_unused<decltype(factory), Attributes...>(
            retval,
            std::forward<typename Attributes::type>(values)...
        );

        return retval;
    }

    /**
     * Get the value of a specific attribute from an object
     *
     * \returns the value of the attribute
     */
    template <
        typename Attribute ///< attribute to get
    >
    typename Attribute::type
    get(
        object_type const& obj ///< object from which to get the value
    ) const {
        return _accessors.
            template get<accesses_attribute<Accessors, Attribute>...>().
            get(obj);
    }

    /**
     * Set the value of a specific attribute on an object
     */
    template <
        typename Attribute ///< attribute to set
    >
    void
    set(
        object_type& obj, ///< object on which to set the attribute
        typename Attribute::type&& value ///< value to set
    ) const {
        _accessors.
            template get<accesses_attribute<Accessors, Attribute>...>().
            set(obj, std::forward<typename Attribute::type>(value));
    }

private:
    /**
     * Initialize attributes which are not used by a specific constructor
     */
    template <
        typename Constructor, ///< constructor to consider
        typename Attribute0, ///< first of the attributes
        typename ...Attributes ///< rest of the attributes
    >
    void
    initialize_if_unused(
        object_type& obj, ///< object on which to set the attributes' values
        typename Attribute0::type&& value0, ///< first of the values
        typename Attributes::type&&... values ///< rest of the values
    ) const {
        initialize_single_if_unused<Constructor, Attribute0>(
            obj,
            std::forward<typename Attribute0::type>(value0)
        );

        // recurse
        initialize_if_unused<Constructor, Attributes...>(
            obj,
            std::forward<typename Attributes::type>(values)...
        );
    }

    // overload for an empty list of attributes
    template <
        typename Constructor
    >
    void
    initialize_if_unused(
        object_type& obj
    ) const {}

    /**
     * Initialize a single attribute if it is not used by a specific constructor
     */
    template <
        typename Constructor, ///< constructor to consider
        typename Attribute ///< attribute to set
    >
    typename std::enable_if<!Constructor::template uses<Attribute>::value>::type
    initialize_single_if_unused(
        object_type& obj, ///< object on which to set the attribute's value
        typename Attribute::type&& value ///< value to set
    ) const {
        // TODO: static assertion for unsettable attributes
        set<Attribute>(obj, std::forward<typename Attribute::type>(value));
    }

    // overload for attributes which are used by the constructor specified
    template <
        typename Constructor,
        typename Attribute
    >
    typename std::enable_if<Constructor::template uses<Attribute>::value>::type
    initialize_single_if_unused(
        object_type& obj,
        typename Attribute::type&& value
    ) const {}

    accessors _accessors;
};

/**
 * Construct an accessor bundle from a bunch of accessors
 *
 * \returns an accessor bundle holding all the accessors supplied
 */
template <
    typename ...Accessors
>
constexpr
const
accessor_bundle<Accessors...>
bundle(
    Accessors&&... accessors ///< accessors to bundle
) {
    return accessor_bundle<Accessors...>(std::forward<Accessors>(accessors)...);
}

}

#endif
<|endoftext|>