<commit_before>#include <ruby.h>

#include "leveldb/db.h"
#include "leveldb/slice.h"

static VALUE m_leveldb;
static VALUE c_db;
static VALUE c_error;

// support 1.9 and 1.8
#ifndef RSTRING_PTR
#define RSTRING_PTR(v) RSTRING(v)->ptr
#endif

// convert status errors into exceptions
#define RAISE_ON_ERROR(status) do { \
  if(!status.ok()) { \
    VALUE exc = rb_exc_new2(c_error, status.ToString().c_str()); \
    rb_exc_raise(exc); \
  }  \
} while(0)

typedef struct bound_db {
  leveldb::DB* db;
} bound_db;

static void db_free(bound_db* db) {
  if(db->db != NULL) {
    delete db->db;
    db->db = NULL;
  }
  delete db;
}

static VALUE db_make(VALUE klass, VALUE v_pathname, VALUE v_create_if_necessary, VALUE v_break_if_exists) {
  Check_Type(v_pathname, T_STRING);

  bound_db* db = new bound_db;
  std::string pathname = std::string((char*)RSTRING_PTR(v_pathname));

  leveldb::Options options;
  if(RTEST(v_create_if_necessary)) options.create_if_missing = true;
  if(RTEST(v_break_if_exists)) options.error_if_exists = true;
  leveldb::Status status = leveldb::DB::Open(options, pathname, &db->db);
  RAISE_ON_ERROR(status);

  VALUE o_db = Data_Wrap_Struct(klass, NULL, db_free, db);
  VALUE argv[1] = { v_pathname };
  rb_obj_call_init(o_db, 1, argv);

  return o_db;
}

static VALUE db_close(VALUE self) {
  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  if(db->db != NULL) {
    delete db->db;
    db->db = NULL;
  }
  return Qtrue;
}

static leveldb::ReadOptions db_readOptions(VALUE options) {
  leveldb::ReadOptions readOptions;

  if(!NIL_P(options)) {
    Check_Type(options, T_HASH);
    VALUE k_fill = ID2SYM(rb_intern("fill_cache"));
    if(rb_hash_aref(options, k_fill) == Qfalse)
      readOptions.fill_cache = false;
    VALUE k_verify = ID2SYM(rb_intern("verify_checksums"));
    if(rb_hash_aref(options, k_verify) == Qtrue)
      readOptions.verify_checksums = true;
  }

  return readOptions;
}

static leveldb::WriteOptions db_writeOptions(VALUE options) {
  leveldb::WriteOptions writeOptions;

  if(!NIL_P(options)) {
    Check_Type(options, T_HASH);
    VALUE k_sync = ID2SYM(rb_intern("sync"));
    if(rb_hash_aref(options, k_sync) == Qtrue)
      writeOptions.sync = true;
  }

  return writeOptions;
}

#define RUBY_STRING_TO_SLICE(x) leveldb::Slice(RSTRING_PTR(x), RSTRING_LEN(x))
#define SLICE_TO_RUBY_STRING(x) rb_str_new(x.data(), x.size())
#define STRING_TO_RUBY_STRING(x) rb_str_new(x.data(), x.size())
static VALUE db_get(int argc, VALUE* argv, VALUE self) {
  VALUE v_key, v_options;
  rb_scan_args(argc, argv, "11", &v_key, &v_options);
  Check_Type(v_key, T_STRING);
  leveldb::ReadOptions readOptions = db_readOptions(v_options);

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  leveldb::Slice key = RUBY_STRING_TO_SLICE(v_key);
  std::string value;
  leveldb::Status status = db->db->Get(readOptions, key, &value);
  if(status.IsNotFound()) return Qnil;

  RAISE_ON_ERROR(status);
  return STRING_TO_RUBY_STRING(value);
}

static VALUE db_delete(int argc, VALUE* argv, VALUE self) {
  VALUE v_key, v_options;
  rb_scan_args(argc, argv, "11", &v_key, &v_options);
  Check_Type(v_key, T_STRING);
  leveldb::WriteOptions writeOptions = db_writeOptions(v_options);
  leveldb::ReadOptions readOptions;
  readOptions.fill_cache = false;

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  leveldb::Slice key = RUBY_STRING_TO_SLICE(v_key);
  std::string value;
  leveldb::Status status = db->db->Get(readOptions, key, &value);

  if(status.IsNotFound()) return Qnil;

  status = db->db->Delete(writeOptions, key);
  RAISE_ON_ERROR(status);

  return STRING_TO_RUBY_STRING(value);
}

static VALUE db_exists(VALUE self, VALUE v_key) {
  Check_Type(v_key, T_STRING);

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  leveldb::Slice key = RUBY_STRING_TO_SLICE(v_key);
  std::string value;
  leveldb::Status status = db->db->Get(leveldb::ReadOptions(), key, &value);

  if(status.IsNotFound()) return Qfalse;
  return Qtrue;
}

static VALUE db_put(int argc, VALUE* argv, VALUE self) {
  VALUE v_key, v_value, v_options;

  rb_scan_args(argc, argv, "21", &v_key, &v_value, &v_options);
  Check_Type(v_key, T_STRING);
  Check_Type(v_value, T_STRING);
  leveldb::WriteOptions writeOptions = db_writeOptions(v_options);

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  leveldb::Slice key = RUBY_STRING_TO_SLICE(v_key);
  leveldb::Slice value = RUBY_STRING_TO_SLICE(v_value);
  leveldb::Status status = db->db->Put(writeOptions, key, value);

  RAISE_ON_ERROR(status);

  return v_value;
}

static VALUE db_size(VALUE self) {
  long count = 0;

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);
  leveldb::ReadOptions readOptions;
  readOptions.fill_cache = false;
  leveldb::Iterator* it = db->db->NewIterator(readOptions);

  // apparently this is how we have to do it. slow and painful!
  for (it->SeekToFirst(); it->Valid(); it->Next()) count++;
  RAISE_ON_ERROR(it->status());
  delete it;
  return INT2NUM(count);
}

static VALUE db_iterate(VALUE self, VALUE key_from, VALUE key_to, bool reversed) {
  bound_db* db;
  Data_Get_Struct(self, bound_db, db);
  leveldb::ReadOptions readOptions;
  readOptions.fill_cache = false;
  leveldb::Iterator* it = db->db->NewIterator(readOptions);
  ID to_s = rb_intern("to_s");

  if(RTEST(key_from)) {
    it->Seek(RUBY_STRING_TO_SLICE(rb_funcall(key_from, to_s, 0)));
  } else {
    if(reversed) {
      it->SeekToLast();
    } else {
      it->SeekToFirst();
    }
  }

  bool passed_limit = false;
  bool check_limit = RTEST(key_to);
  std::string key_to_str;

  if(check_limit)
    key_to_str = RUBY_STRING_TO_SLICE(rb_funcall(key_to, to_s, 0)).ToString();

  while(!passed_limit && it->Valid()) {
    leveldb::Slice key_sl = it->key();

    if(check_limit &&
        (reversed ?
          (key_sl.ToString() < key_to_str) :
          (key_sl.ToString() > key_to_str))) {
      passed_limit = true;
    } else {
      VALUE key = SLICE_TO_RUBY_STRING(key_sl);
      VALUE value = SLICE_TO_RUBY_STRING(it->value());
      VALUE ary = rb_ary_new2(2);
      rb_ary_push(ary, key);
      rb_ary_push(ary, value);
      rb_yield(ary);
      reversed ? it->Prev() : it->Next();
    }
  }

  RAISE_ON_ERROR(it->status());
  delete it;

  return self;
}

static VALUE db_each(int argc, VALUE* argv, VALUE self) {
  VALUE key_from, key_to;
  rb_scan_args(argc, argv, "02", &key_from, &key_to);

  return db_iterate(self, key_from, key_to, false);
}

static VALUE db_reverse_each(int argc, VALUE* argv, VALUE self) {
  VALUE key_from, key_to;
  rb_scan_args(argc, argv, "02", &key_from, &key_to);

  return db_iterate(self, key_from, key_to, true);
}

static VALUE db_init(VALUE self, VALUE v_pathname) {
  rb_iv_set(self, "@pathname", v_pathname);
  return self;
}

extern "C" {
void Init_leveldb() {
  m_leveldb = rb_define_module("LevelDB");

  c_db = rb_define_class_under(m_leveldb, "DB", rb_cObject);
  rb_define_singleton_method(c_db, "make", (VALUE (*)(...))db_make, 3);
  rb_define_method(c_db, "initialize", (VALUE (*)(...))db_init, 1);
  rb_define_method(c_db, "get", (VALUE (*)(...))db_get, -1);
  rb_define_method(c_db, "delete", (VALUE (*)(...))db_delete, -1);
  rb_define_method(c_db, "put", (VALUE (*)(...))db_put, -1);
  rb_define_method(c_db, "exists?", (VALUE (*)(...))db_exists, 1);
  rb_define_method(c_db, "close", (VALUE (*)(...))db_close, 0);
  rb_define_method(c_db, "size", (VALUE (*)(...))db_size, 0);
  rb_define_method(c_db, "each", (VALUE (*)(...))db_each, -1);
  rb_define_method(c_db, "reverse_each", (VALUE (*)(...))db_reverse_each, -1);

  c_error = rb_define_class_under(m_leveldb, "Error", rb_eStandardError);
}
}
<commit_msg>preliminary WriteBatch support.  crashes on exit, doh!<commit_after>#include <ruby.h>

#include "leveldb/db.h"
#include "leveldb/slice.h"
#include "leveldb/write_batch.h"

static VALUE m_leveldb;
static VALUE c_db;
static VALUE c_batch;
static VALUE c_error;

// support 1.9 and 1.8
#ifndef RSTRING_PTR
#define RSTRING_PTR(v) RSTRING(v)->ptr
#endif

// convert status errors into exceptions
#define RAISE_ON_ERROR(status) do { \
  if(!status.ok()) { \
    VALUE exc = rb_exc_new2(c_error, status.ToString().c_str()); \
    rb_exc_raise(exc); \
  }  \
} while(0)

typedef struct bound_db {
  leveldb::DB* db;
} bound_db;

static void db_free(bound_db* db) {
  if(db->db != NULL) {
    delete db->db;
    db->db = NULL;
  }
  delete db;
}

static VALUE db_make(VALUE klass, VALUE v_pathname, VALUE v_create_if_necessary, VALUE v_break_if_exists) {
  Check_Type(v_pathname, T_STRING);

  bound_db* db = new bound_db;
  std::string pathname = std::string((char*)RSTRING_PTR(v_pathname));

  leveldb::Options options;
  if(RTEST(v_create_if_necessary)) options.create_if_missing = true;
  if(RTEST(v_break_if_exists)) options.error_if_exists = true;
  leveldb::Status status = leveldb::DB::Open(options, pathname, &db->db);
  RAISE_ON_ERROR(status);

  VALUE o_db = Data_Wrap_Struct(klass, NULL, db_free, db);
  VALUE argv[1] = { v_pathname };
  rb_obj_call_init(o_db, 1, argv);

  return o_db;
}

static VALUE db_close(VALUE self) {
  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  if(db->db != NULL) {
    delete db->db;
    db->db = NULL;
  }
  return Qtrue;
}

static leveldb::ReadOptions db_readOptions(VALUE options) {
  leveldb::ReadOptions readOptions;

  if(!NIL_P(options)) {
    Check_Type(options, T_HASH);
    VALUE k_fill = ID2SYM(rb_intern("fill_cache"));
    if(rb_hash_aref(options, k_fill) == Qfalse)
      readOptions.fill_cache = false;
    VALUE k_verify = ID2SYM(rb_intern("verify_checksums"));
    if(rb_hash_aref(options, k_verify) == Qtrue)
      readOptions.verify_checksums = true;
  }

  return readOptions;
}

static leveldb::WriteOptions db_writeOptions(VALUE options) {
  leveldb::WriteOptions writeOptions;

  if(!NIL_P(options)) {
    Check_Type(options, T_HASH);
    VALUE k_sync = ID2SYM(rb_intern("sync"));
    if(rb_hash_aref(options, k_sync) == Qtrue)
      writeOptions.sync = true;
  }

  return writeOptions;
}

#define RUBY_STRING_TO_SLICE(x) leveldb::Slice(RSTRING_PTR(x), RSTRING_LEN(x))
#define SLICE_TO_RUBY_STRING(x) rb_str_new(x.data(), x.size())
#define STRING_TO_RUBY_STRING(x) rb_str_new(x.data(), x.size())
static VALUE db_get(int argc, VALUE* argv, VALUE self) {
  VALUE v_key, v_options;
  rb_scan_args(argc, argv, "11", &v_key, &v_options);
  Check_Type(v_key, T_STRING);
  leveldb::ReadOptions readOptions = db_readOptions(v_options);

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  leveldb::Slice key = RUBY_STRING_TO_SLICE(v_key);
  std::string value;
  leveldb::Status status = db->db->Get(readOptions, key, &value);
  if(status.IsNotFound()) return Qnil;

  RAISE_ON_ERROR(status);
  return STRING_TO_RUBY_STRING(value);
}

static VALUE db_delete(int argc, VALUE* argv, VALUE self) {
  VALUE v_key, v_options;
  rb_scan_args(argc, argv, "11", &v_key, &v_options);
  Check_Type(v_key, T_STRING);
  leveldb::WriteOptions writeOptions = db_writeOptions(v_options);
  leveldb::ReadOptions readOptions;
  readOptions.fill_cache = false;

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  leveldb::Slice key = RUBY_STRING_TO_SLICE(v_key);
  std::string value;
  leveldb::Status status = db->db->Get(readOptions, key, &value);

  if(status.IsNotFound()) return Qnil;

  status = db->db->Delete(writeOptions, key);
  RAISE_ON_ERROR(status);

  return STRING_TO_RUBY_STRING(value);
}

static VALUE db_exists(VALUE self, VALUE v_key) {
  Check_Type(v_key, T_STRING);

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  leveldb::Slice key = RUBY_STRING_TO_SLICE(v_key);
  std::string value;
  leveldb::Status status = db->db->Get(leveldb::ReadOptions(), key, &value);

  if(status.IsNotFound()) return Qfalse;
  return Qtrue;
}

static VALUE db_put(int argc, VALUE* argv, VALUE self) {
  VALUE v_key, v_value, v_options;

  rb_scan_args(argc, argv, "21", &v_key, &v_value, &v_options);
  Check_Type(v_key, T_STRING);
  Check_Type(v_value, T_STRING);
  leveldb::WriteOptions writeOptions = db_writeOptions(v_options);

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);

  leveldb::Slice key = RUBY_STRING_TO_SLICE(v_key);
  leveldb::Slice value = RUBY_STRING_TO_SLICE(v_value);
  leveldb::Status status = db->db->Put(writeOptions, key, value);

  RAISE_ON_ERROR(status);

  return v_value;
}

static VALUE db_size(VALUE self) {
  long count = 0;

  bound_db* db;
  Data_Get_Struct(self, bound_db, db);
  leveldb::ReadOptions readOptions;
  readOptions.fill_cache = false;
  leveldb::Iterator* it = db->db->NewIterator(readOptions);

  // apparently this is how we have to do it. slow and painful!
  for (it->SeekToFirst(); it->Valid(); it->Next()) count++;
  RAISE_ON_ERROR(it->status());
  delete it;
  return INT2NUM(count);
}

static VALUE db_iterate(VALUE self, VALUE key_from, VALUE key_to, bool reversed) {
  bound_db* db;
  Data_Get_Struct(self, bound_db, db);
  leveldb::ReadOptions readOptions;
  readOptions.fill_cache = false;
  leveldb::Iterator* it = db->db->NewIterator(readOptions);
  ID to_s = rb_intern("to_s");

  if(RTEST(key_from)) {
    it->Seek(RUBY_STRING_TO_SLICE(rb_funcall(key_from, to_s, 0)));
  } else {
    if(reversed) {
      it->SeekToLast();
    } else {
      it->SeekToFirst();
    }
  }

  bool passed_limit = false;
  bool check_limit = RTEST(key_to);
  std::string key_to_str;

  if(check_limit)
    key_to_str = RUBY_STRING_TO_SLICE(rb_funcall(key_to, to_s, 0)).ToString();

  while(!passed_limit && it->Valid()) {
    leveldb::Slice key_sl = it->key();

    if(check_limit &&
        (reversed ?
          (key_sl.ToString() < key_to_str) :
          (key_sl.ToString() > key_to_str))) {
      passed_limit = true;
    } else {
      VALUE key = SLICE_TO_RUBY_STRING(key_sl);
      VALUE value = SLICE_TO_RUBY_STRING(it->value());
      VALUE ary = rb_ary_new2(2);
      rb_ary_push(ary, key);
      rb_ary_push(ary, value);
      rb_yield(ary);
      reversed ? it->Prev() : it->Next();
    }
  }

  RAISE_ON_ERROR(it->status());
  delete it;

  return self;
}

static VALUE db_each(int argc, VALUE* argv, VALUE self) {
  VALUE key_from, key_to;
  rb_scan_args(argc, argv, "02", &key_from, &key_to);

  return db_iterate(self, key_from, key_to, false);
}

static VALUE db_reverse_each(int argc, VALUE* argv, VALUE self) {
  VALUE key_from, key_to;
  rb_scan_args(argc, argv, "02", &key_from, &key_to);

  return db_iterate(self, key_from, key_to, true);
}

static VALUE db_init(VALUE self, VALUE v_pathname) {
  rb_iv_set(self, "@pathname", v_pathname);
  return self;
}

typedef struct bound_batch {
  leveldb::WriteBatch batch;
} bound_batch;

static void batch_free(bound_batch* batch) {
  delete batch;
}

static VALUE batch_make(VALUE klass) {
  bound_batch* batch = new bound_batch;
  batch->batch = leveldb::WriteBatch();

  VALUE o_batch = Data_Wrap_Struct(klass, NULL, batch_free, batch);
  VALUE argv[0];
  rb_obj_call_init(o_batch, 0, argv);

  return o_batch;
}

static VALUE batch_put(VALUE self, VALUE v_key, VALUE v_value) {
  Check_Type(v_key, T_STRING);
  Check_Type(v_value, T_STRING);

  bound_batch* batch;
  Data_Get_Struct(self, bound_batch, batch);
  batch->batch.Put(RUBY_STRING_TO_SLICE(v_key), RUBY_STRING_TO_SLICE(v_value));

  return v_value;
}

static VALUE batch_delete(VALUE self, VALUE v_key) {
  Check_Type(v_key, T_STRING);
  bound_batch* batch;
  Data_Get_Struct(self, bound_batch, batch);
  batch->batch.Delete(RUBY_STRING_TO_SLICE(v_key));
  return Qtrue;
}

static VALUE db_batch(VALUE self) {
  VALUE m_leveldb, c_batch, o_batch;
  m_leveldb = rb_const_get(rb_cObject, rb_intern("LevelDB"));
  c_batch = rb_const_get(m_leveldb, rb_intern("WriteBatch"));
  o_batch = batch_make(c_batch);
  rb_yield(o_batch);

  bound_batch* batch;
  bound_db* db;
  Data_Get_Struct(o_batch, bound_batch, batch);
  Data_Get_Struct(self, bound_db, db);

  leveldb::Status status = db->db->Write(leveldb::WriteOptions(), &batch->batch);
  batch_free(batch);
  if(status.ok()) {
    return Qtrue;
  } else {
    RAISE_ON_ERROR(status);
    return Qfalse;
  }
}

extern "C" {
void Init_leveldb() {
  m_leveldb = rb_define_module("LevelDB");

  c_db = rb_define_class_under(m_leveldb, "DB", rb_cObject);
  rb_define_singleton_method(c_db, "make", (VALUE (*)(...))db_make, 3);
  rb_define_method(c_db, "initialize", (VALUE (*)(...))db_init, 1);
  rb_define_method(c_db, "get", (VALUE (*)(...))db_get, -1);
  rb_define_method(c_db, "delete", (VALUE (*)(...))db_delete, -1);
  rb_define_method(c_db, "put", (VALUE (*)(...))db_put, -1);
  rb_define_method(c_db, "exists?", (VALUE (*)(...))db_exists, 1);
  rb_define_method(c_db, "close", (VALUE (*)(...))db_close, 0);
  rb_define_method(c_db, "size", (VALUE (*)(...))db_size, 0);
  rb_define_method(c_db, "each", (VALUE (*)(...))db_each, -1);
  rb_define_method(c_db, "reverse_each", (VALUE (*)(...))db_reverse_each, -1);
  rb_define_method(c_db, "batch", (VALUE (*)(...))db_batch, 0);

  c_batch = rb_define_class_under(m_leveldb, "WriteBatch", rb_cObject);
  rb_define_singleton_method(c_batch, "make", (VALUE (*)(...))batch_make, 0);
  rb_define_method(c_batch, "put", (VALUE (*)(...))batch_put, 2);
  rb_define_method(c_batch, "delete", (VALUE (*)(...))batch_delete, 1);

  c_error = rb_define_class_under(m_leveldb, "Error", rb_eStandardError);
}
}
<|endoftext|>


<commit_before>/*
  User Server code for CMPT 276 Group Assignment, Spring 2016.

  This server manages a user’s social networking session.

  This server supports sign on/off, add friend, unfriend, update status,
  get user's friend list.

  This server handles disallowed method malformed request.
*/

#include <exception>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <string>

#include <cpprest/base_uri.h>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>

#include <pplx/pplxtasks.h>

#include <was/common.h>
#include <was/storage_account.h>
#include <was/table.h>

#include "../include/TableCache.h"

#include "../include/make_unique.h"

#include "../include/azure_keys.h"

#include "../include/ServerUtils.h"

using azure::storage::cloud_storage_account;
using azure::storage::storage_credentials;
using azure::storage::storage_exception;
using azure::storage::cloud_table;
using azure::storage::cloud_table_client;
using azure::storage::edm_type;
using azure::storage::entity_property;
using azure::storage::table_entity;
using azure::storage::table_operation;
using azure::storage::table_query;
using azure::storage::table_query_iterator;
using azure::storage::table_result;

using pplx::extensibility::critical_section_t;
using pplx::extensibility::scoped_critical_section_t;

using std::cin;
using std::cout;
using std::endl;
using std::getline;
using std::make_pair;
using std::pair;
using std::string;
using std::unordered_map;
using std::vector;

using web::http::http_headers;
using web::http::http_request;
using web::http::methods;
using web::http::status_codes;
using web::http::uri;

using web::json::value;

using web::http::experimental::listener::http_listener;

using prop_vals_t = vector<pair<string,value>>;

constexpr const char* def_url = "http://localhost:34572";

const string sign_on {"SignOn"}; //POST
const string sign_off {"SignOff"}; //POST

const string add_friend {"AddFriend"}; // PUT
const string unfriend {"UnFriend"}; //PUT
const string update_status {"UpdateStatus"}; //PUT

const string get_friend_list {"ReadFriendList"}; //GET

// Cache of opened tables
TableCache table_cache {};

void handle_post (http_request message){
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  if(true/*basic criteria*/){}
  else if (paths[0] == sign_on) {}
  else if (paths[0] == sign_off) {}
  else {
    // malformed request
    vector<value> vec;
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }
}

void handle_put (http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  if(true/*basic criteria*/){}
  else if (paths[0] == add_friend) {}
  else if (paths[0] == unfriend) {}
  else if (paths[0] == update_status) {}
  else {
    // malformed request
    vector<value> vec;
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }
}

void handle_get (http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  if(true/*basic criteria*/){}
  else if (paths[0] == get_friend_list) {}
  else {
    // malformed request
    vector<value> vec;
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }
}

int main (int argc, char const * argv[]) {
  cout << "Parsing connection string" << endl;
  table_cache.init (storage_connection_string);

  cout << "Opening listener" << endl;
  http_listener listener {def_url};
  listener.support(methods::GET, &handle_get); // Get user's friend list
  listener.support(methods::POST, &handle_post); // SignOn, SignOff
  listener.support(methods::PUT, &handle_put); // Add friend, Unfriend, Update Status
  /*TO DO: Disallowed method*/
  listener.open().wait(); // Wait for listener to complete starting

  cout << "Enter carriage return to stop server." << endl;
  string line;
  getline(std::cin, line);

  // Shut it down
  listener.close().wait();
  cout << "Closed" << endl;
}
<commit_msg>Add general server functions to UserServer<commit_after>/*
  User Server code for CMPT 276 Group Assignment, Spring 2016.

  This server manages a user’s social networking session.

  This server supports sign on/off, add friend, unfriend, update status,
  get user's friend list.

  This server handles disallowed method malformed request.
*/

#include <exception>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <string>

#include <cpprest/base_uri.h>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>

#include <pplx/pplxtasks.h>

#include <was/common.h>
#include <was/storage_account.h>
#include <was/table.h>

#include "../include/TableCache.h"

#include "../include/make_unique.h"

#include "../include/azure_keys.h"

#include "../include/ServerUtils.h"

using azure::storage::cloud_storage_account;
using azure::storage::storage_credentials;
using azure::storage::storage_exception;
using azure::storage::cloud_table;
using azure::storage::cloud_table_client;
using azure::storage::edm_type;
using azure::storage::entity_property;
using azure::storage::table_entity;
using azure::storage::table_operation;
using azure::storage::table_query;
using azure::storage::table_query_iterator;
using azure::storage::table_result;

using pplx::extensibility::critical_section_t;
using pplx::extensibility::scoped_critical_section_t;

using std::cin;
using std::cout;
using std::endl;
using std::getline;
using std::make_pair;
using std::pair;
using std::string;
using std::unordered_map;
using std::vector;

using web::http::http_headers;
using web::http::http_request;
using web::http::methods;
using web::http::status_codes;
using web::http::uri;

using web::json::value;

using web::http::experimental::listener::http_listener;

using prop_vals_t = vector<pair<string,value>>;

constexpr const char* def_url = "http://localhost:34572";

const string sign_on {"SignOn"}; //POST
const string sign_off {"SignOff"}; //POST

const string add_friend {"AddFriend"}; // PUT
const string unfriend {"UnFriend"}; //PUT
const string update_status {"UpdateStatus"}; //PUT

const string get_friend_list {"ReadFriendList"}; //GET

// Cache of opened tables
TableCache table_cache {};

/*
  Return true if an HTTP request has a JSON body

  This routine can be called multiple times on the same message.
 */
bool has_json_body (http_request message) {
  return message.headers()["Content-type"] == "application/json";
}

/*
  Given an HTTP message with a JSON body, return the JSON
  body as an unordered map of strings to strings.
  get_json_body and get_json_bourne are valid and identical function calls.

  If the message has no JSON body, return an empty map.

  THIS ROUTINE CAN ONLY BE CALLED ONCE FOR A GIVEN MESSAGE
  (see http://microsoft.github.io/cpprestsdk/classweb_1_1http_1_1http__request.html#ae6c3d7532fe943de75dcc0445456cbc7
  for source of this limit).

  Note that all types of JSON values are returned as strings.
  Use C++ conversion utilities to convert to numbers or dates
  as necessary.
 */
unordered_map<string,string> get_json_body(http_request message) {
  unordered_map<string,string> results {};
  const http_headers& headers {message.headers()};
  auto content_type (headers.find("Content-Type"));
  if (content_type == headers.end() ||
      content_type->second != "application/json")
    return results;

  value json{};
  message.extract_json(true)
    .then([&json](value v) -> bool
          {
            json = v;
            return true;
          })
    .wait();

  if (json.is_object()) {
    for (const auto& v : json.as_object()) {
      if (v.second.is_string()) {
        results[v.first] = v.second.as_string();
      }
      else {
        results[v.first] = v.second.serialize();
      }
    }
  }
  return results;
}

unordered_map<string,string> get_json_bourne(http_request message) {
 return get_json_body(message);
}

void handle_post (http_request message){
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  if(true/*basic criteria*/){}
  else if (paths[0] == sign_on) {}
  else if (paths[0] == sign_off) {}
  else {
    // malformed request
    vector<value> vec;
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }
}

void handle_put (http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  if(true/*basic criteria*/){}
  else if (paths[0] == add_friend) {}
  else if (paths[0] == unfriend) {}
  else if (paths[0] == update_status) {}
  else {
    // malformed request
    vector<value> vec;
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }
}

void handle_get (http_request message) {
  string path {uri::decode(message.relative_uri().path())};
  cout << endl << "**** POST " << path << endl;
  auto paths = uri::split_path(path);

  if(true/*basic criteria*/){}
  else if (paths[0] == get_friend_list) {}
  else {
    // malformed request
    vector<value> vec;
    message.reply(status_codes::BadRequest, value::array(vec));
    return;
  }
}

int main (int argc, char const * argv[]) {
  cout << "Parsing connection string" << endl;
  table_cache.init (storage_connection_string);

  cout << "Opening listener" << endl;
  http_listener listener {def_url};
  listener.support(methods::GET, &handle_get); // Get user's friend list
  listener.support(methods::POST, &handle_post); // SignOn, SignOff
  listener.support(methods::PUT, &handle_put); // Add friend, Unfriend, Update Status
  /*TO DO: Disallowed method*/
  listener.open().wait(); // Wait for listener to complete starting

  cout << "Enter carriage return to stop server." << endl;
  string line;
  getline(std::cin, line);

  // Shut it down
  listener.close().wait();
  cout << "Closed" << endl;
}
<|endoftext|>


<commit_before>#pragma ident "$Id$"

/**
 * @file VectorBase.hpp
 * Base Vector class
 */

#ifndef GPSTK_VECTOR_BASE_HPP
#define GPSTK_VECTOR_BASE_HPP

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

#include <valarray>
#include "Exception.hpp"

#include "MathBase.hpp"

namespace gpstk
{
/** @addtogroup VectorGroup */
   //@{

/// An exception thrown when there's a problem with a vector
/// @ingroup exceptiongroup
NEW_EXCEPTION_CLASS(VectorException, gpstk::Exception);

/*
 * There were two overriding philosophies to the vector and matrix classes:
 *
 * The concept of "const" and "reference" (i.e. changable) vector
 * and matrix types both exist, so that any Const* type could not be altered
 * while Ref* types can.  This allowed one to add the slice classes that
 * let you use a subset of a vector and modify (or not if it's const) the
 * original vector.  Furthermore, it allowed slice and non-slice classes
 * to interoperate through the ConstVectorBase or ConstMatrixBase classes, so, for
 * example, operator* only needs to be written in terms of ConstVectorBase to
 * work correctly with Vector, VectorSlice and ConstVectorSlice.
 *
 * Remember that a slice MUST refer to a vector or matrix; you cannot have
 * a slice independent of a base vector or matrix.
 *
 * In the future:
 *
 * - Change the math operators to template expressions.
 * - Add general slices and diagonal matrix slices.
 * - Make range checking more consistent.
 * - Make operator= and copy constructors consistent between const and
 *   non-const versions.
 * - Reevaluate the need for default slice constructors...?
 * - find a way for LUD and SVD to use the template type of the parameters
 *   rather than specified when the object is created.
 * - come up with a policy for when zeroize() will be used before results
 *   are returned.
 *
 * @warning MSVC cant deal with cmath header.
 * Changes to accomidate this may break complex!
 */

/**
 * A base class for a vector that does not allow modification of the internal
 * vector.  BaseClass is the base class that implements the vector.
 */
   template <class T, class BaseClass>
   class ConstVectorBase
   {
   public:
         /// Constructor
      explicit ConstVectorBase() {}

         /// Returns the size of the base class.
      size_t size() const
         { return static_cast<const BaseClass*>(this)->size(); }
         /// returns the element at index i
      T operator[] (size_t i) const
         { return constVectorRef(i); }
         /// returns the element at index i
      T operator() (size_t i) const
         { return constVectorRef(i); }

   protected:
         /// returns the element at index i by calling the base class's operator[]
      inline T constVectorRef(size_t i) const
         throw(VectorException)
         {
            const BaseClass& b = static_cast<const BaseClass&>(*this);
#ifdef RANGECHECK
            if (i >= b.size())
            {
               VectorException e("Invalid ConstVectorBase index");
               GPSTK_THROW(e);
            }
#endif
            return b[i];
         }
   };

      /// a class to hold the static members of RefVectorBase. Static members
      /// in template classes have to be initialized on a PER TEMPLATE
      /// basis - this gets around that problem.
   class RefVectorBaseHelper
   {
   public:
         /// used with zeroize(), any number below this value will become 0.
         /// this variable can be assigned any value.
      static double zeroTolerance;
   };

/**
 * A vector base class that allows modification of the internal representation.
 */
   template <class T, class BaseClass>
   class RefVectorBase : public ConstVectorBase<T, BaseClass>,
                      public RefVectorBaseHelper
   {
   public:
         /// constructor
      explicit RefVectorBase() {}
         /// returns a modifiable version of the element at index i.
      T& operator[] (size_t i)
         { return vecRef(i); }
         /// returns a modifiable version of the element at index i.
      T& operator() (size_t i)
         { return vecRef(i); }
         /// Any value in the vector with absolute value below
         /// zeroTolerance is set to zero.
      BaseClass& zeroize()
         {
            BaseClass& me = static_cast<BaseClass&>(*this);
            size_t i;
            for (i = 0; i < me.size(); i++)
               if (ABS(me[i]) < zeroTolerance)
                  me[i] = T(0);
            return me;
         }

#define VecBaseArrayAssignMacroDontCheckRange(func) \
   BaseClass& me = static_cast<BaseClass&>(*this); \
   size_t i; for (i=0; i < me.size(); i++) { \
      me[i] func x[i]; \
   } \
   return me;

#ifdef RANGECHECK
#define VecBaseArrayAssignMacro(func) \
   BaseClass& me = static_cast<BaseClass&>(*this); \
   if (x.size() != me.size()) \
      { \
         VectorException e("Unequal lengths for vectors"); \
         GPSTK_THROW(e); \
      } \
   size_t i; for (i=0; i < me.size(); i++) me[i] func x[i]; \
   return me;
#else
#define VecBaseArrayAssignMacro(func) \
VecBaseArrayAssignMacroDontCheckRange(func)
#endif

#define VecBaseAtomicAssignMacro(func) \
   BaseClass& me = static_cast<BaseClass&>(*this); \
   size_t i; for (i=0; i < me.size(); i++) me[i] func x; \
   return me;

#define VecBaseNewAssignOperator(funcName, op) \
            /** Performs op on (*this).size() elements of (*this) from x */ \
   template <class E> BaseClass& funcName(const ConstVectorBase<T, E>& x) \
      { VecBaseArrayAssignMacro(op) } \
            /** Performs op on (*this).size() elements of (*this) from x */ \
   BaseClass& funcName(const std::valarray<T>& x) \
      { VecBaseArrayAssignMacro(op) } \
            /** Performs op on (*this).size() elements of (*this) from x */ \
   BaseClass& funcName(const T* x) \
      { VecBaseArrayAssignMacroDontCheckRange(op) } \
            /** Performs op on (*this).size() elements of (*this) from x */ \
   BaseClass& funcName(T x) \
      { VecBaseAtomicAssignMacro(op) }

         /**
          * Remember that operator= is NOT inherited. Derived classes can
          * use assignFrom to initialize values from a copy constructor or
          * their own operator= rather than explicitly copying them.
          */
      VecBaseNewAssignOperator(assignFrom, =);
      VecBaseNewAssignOperator(operator+=, +=);
      VecBaseNewAssignOperator(operator-=, -=);
      VecBaseNewAssignOperator(operator*=, *=);
      VecBaseNewAssignOperator(operator/=, /=);

         /// unary minus: multiplies each element of this vector by -1.
      BaseClass& operator-()
         {
            const T x=T(-1);
            VecBaseAtomicAssignMacro(*=);
         }

   protected:
         /// Returns a modifiable object at index i.
      inline T& vecRef(size_t i)
         throw(VectorException)
         {
            BaseClass& b = static_cast<BaseClass&>(*this);
#ifdef RANGECHECK
            if (i >= b.size())
            {
               VectorException e("Invalid VectorBase index");
               GPSTK_THROW(e);
            }
#endif
            return b[i];
         }
   };

/**
 * A base class that represents a subset of a vector.
 */
   template <class BaseClass>
   class VectorSliceBase
   {
   public:
         /// constructor
      explicit VectorSliceBase() {}

         /// the number of elements in the slice.
      size_t size() const
         { return static_cast<const BaseClass*>(this)->size(); }
         /// the start index in the BaseClass vector for this slice.
      size_t start() const
         { return static_cast<const BaseClass*>(this)->start(); }
         /// How many elements separate the i'th element from the i+1'th element.
      size_t stride() const
         { return static_cast<const BaseClass*>(this)->stride(); }

   protected:
         /// Given the size of the source vector, checks that the slice is valid.
      inline void vecSliceCheck(size_t sourceSize) const
         throw(VectorException)
         {
#ifdef RANGECHECK
               // sanity checks...
            if ( (start() >= sourceSize) ||
                 ((start() + (size() - 1) * stride()) >= sourceSize) )
            {
               VectorException e("Invalid range for slice");
               GPSTK_THROW(e);
            }
#endif
         }
   };

/**
 * A vector slice base class that doesn't allow modification of the
 * internal elements.
 */
   template <class T, class BaseClass>
   class ConstVectorSliceBase : public VectorSliceBase<BaseClass>,
                             public ConstVectorBase<T, BaseClass>
   {
public:
   explicit ConstVectorSliceBase() {}
};

/**
 * A vector slice base class that does allow modification of the
 * internal elements.
 */
template <class T, class BaseClass>
class RefVectorSliceBase : public VectorSliceBase<BaseClass>,
                        public RefVectorBase<T, BaseClass>
{
public:
   explicit RefVectorSliceBase() {}
};

//@}

}  // namespace gpstk

#include "VectorBaseOperators.hpp"

#endif //GPSTK_VECTOR_BASE_HPP
<commit_msg>unary minus must not return an l-value<commit_after>#pragma ident "$Id$"

/**
 * @file VectorBase.hpp
 * Base Vector class
 */

#ifndef GPSTK_VECTOR_BASE_HPP
#define GPSTK_VECTOR_BASE_HPP

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

#include <valarray>
#include "Exception.hpp"

#include "MathBase.hpp"

namespace gpstk
{
/** @addtogroup VectorGroup */
   //@{

/// An exception thrown when there's a problem with a vector
/// @ingroup exceptiongroup
NEW_EXCEPTION_CLASS(VectorException, gpstk::Exception);

/*
 * There were two overriding philosophies to the vector and matrix classes:
 *
 * The concept of "const" and "reference" (i.e. changable) vector
 * and matrix types both exist, so that any Const* type could not be altered
 * while Ref* types can.  This allowed one to add the slice classes that
 * let you use a subset of a vector and modify (or not if it's const) the
 * original vector.  Furthermore, it allowed slice and non-slice classes
 * to interoperate through the ConstVectorBase or ConstMatrixBase classes, so, for
 * example, operator* only needs to be written in terms of ConstVectorBase to
 * work correctly with Vector, VectorSlice and ConstVectorSlice.
 *
 * Remember that a slice MUST refer to a vector or matrix; you cannot have
 * a slice independent of a base vector or matrix.
 *
 * In the future:
 *
 * - Change the math operators to template expressions.
 * - Add general slices and diagonal matrix slices.
 * - Make range checking more consistent.
 * - Make operator= and copy constructors consistent between const and
 *   non-const versions.
 * - Reevaluate the need for default slice constructors...?
 * - find a way for LUD and SVD to use the template type of the parameters
 *   rather than specified when the object is created.
 * - come up with a policy for when zeroize() will be used before results
 *   are returned.
 *
 * @warning MSVC cant deal with cmath header.
 * Changes to accomidate this may break complex!
 */

/**
 * A base class for a vector that does not allow modification of the internal
 * vector.  BaseClass is the base class that implements the vector.
 */
   template <class T, class BaseClass>
   class ConstVectorBase
   {
   public:
         /// Constructor
      explicit ConstVectorBase() {}

         /// Returns the size of the base class.
      size_t size() const
         { return static_cast<const BaseClass*>(this)->size(); }
         /// returns the element at index i
      T operator[] (size_t i) const
         { return constVectorRef(i); }
         /// returns the element at index i
      T operator() (size_t i) const
         { return constVectorRef(i); }

   protected:
         /// returns the element at index i by calling the base class's operator[]
      inline T constVectorRef(size_t i) const
         throw(VectorException)
         {
            const BaseClass& b = static_cast<const BaseClass&>(*this);
#ifdef RANGECHECK
            if (i >= b.size())
            {
               VectorException e("Invalid ConstVectorBase index");
               GPSTK_THROW(e);
            }
#endif
            return b[i];
         }
   };

      /// a class to hold the static members of RefVectorBase. Static members
      /// in template classes have to be initialized on a PER TEMPLATE
      /// basis - this gets around that problem.
   class RefVectorBaseHelper
   {
   public:
         /// used with zeroize(), any number below this value will become 0.
         /// this variable can be assigned any value.
      static double zeroTolerance;
   };

/**
 * A vector base class that allows modification of the internal representation.
 */
   template <class T, class BaseClass>
   class RefVectorBase : public ConstVectorBase<T, BaseClass>,
                      public RefVectorBaseHelper
   {
   public:
         /// constructor
      explicit RefVectorBase() {}
         /// returns a modifiable version of the element at index i.
      T& operator[] (size_t i)
         { return vecRef(i); }
         /// returns a modifiable version of the element at index i.
      T& operator() (size_t i)
         { return vecRef(i); }
         /// Any value in the vector with absolute value below
         /// zeroTolerance is set to zero.
      BaseClass& zeroize()
         {
            BaseClass& me = static_cast<BaseClass&>(*this);
            size_t i;
            for (i = 0; i < me.size(); i++)
               if (ABS(me[i]) < zeroTolerance)
                  me[i] = T(0);
            return me;
         }

#define VecBaseArrayAssignMacroDontCheckRange(func) \
   BaseClass& me = static_cast<BaseClass&>(*this); \
   size_t i; for (i=0; i < me.size(); i++) { \
      me[i] func x[i]; \
   } \
   return me;

#ifdef RANGECHECK
#define VecBaseArrayAssignMacro(func) \
   BaseClass& me = static_cast<BaseClass&>(*this); \
   if (x.size() != me.size()) \
      { \
         VectorException e("Unequal lengths for vectors"); \
         GPSTK_THROW(e); \
      } \
   size_t i; for (i=0; i < me.size(); i++) me[i] func x[i]; \
   return me;
#else
#define VecBaseArrayAssignMacro(func) \
VecBaseArrayAssignMacroDontCheckRange(func)
#endif

#define VecBaseAtomicAssignMacro(func) \
   BaseClass& me = static_cast<BaseClass&>(*this); \
   size_t i; for (i=0; i < me.size(); i++) me[i] func x; \
   return me;

#define VecBaseNewAssignOperator(funcName, op) \
            /** Performs op on (*this).size() elements of (*this) from x */ \
   template <class E> BaseClass& funcName(const ConstVectorBase<T, E>& x) \
      { VecBaseArrayAssignMacro(op) } \
            /** Performs op on (*this).size() elements of (*this) from x */ \
   BaseClass& funcName(const std::valarray<T>& x) \
      { VecBaseArrayAssignMacro(op) } \
            /** Performs op on (*this).size() elements of (*this) from x */ \
   BaseClass& funcName(const T* x) \
      { VecBaseArrayAssignMacroDontCheckRange(op) } \
            /** Performs op on (*this).size() elements of (*this) from x */ \
   BaseClass& funcName(T x) \
      { VecBaseAtomicAssignMacro(op) }

         /**
          * Remember that operator= is NOT inherited. Derived classes can
          * use assignFrom to initialize values from a copy constructor or
          * their own operator= rather than explicitly copying them.
          */
      VecBaseNewAssignOperator(assignFrom, =);
      VecBaseNewAssignOperator(operator+=, +=);
      VecBaseNewAssignOperator(operator-=, -=);
      VecBaseNewAssignOperator(operator*=, *=);
      VecBaseNewAssignOperator(operator/=, /=);

      //   // unary minus: multiplies each element of this vector by -1.
      //BaseClass& operator-()
      //   {
      //      const T x=T(-1);
      //      VecBaseAtomicAssignMacro(*=);
      //   }
      // unary minus must not return an l-value

         /// unary minus: multiplies each element in this matrix by -1.
      BaseClass operator-()
         {
            const T x=T(-1);
            BaseClass me = static_cast<BaseClass>(*this);
            size_t i;
            for (i=0; i < me.size(); i++) me(i) *= x;
            return me;
         }

   protected:
         /// Returns a modifiable object at index i.
      inline T& vecRef(size_t i)
         throw(VectorException)
         {
            BaseClass& b = static_cast<BaseClass&>(*this);
#ifdef RANGECHECK
            if (i >= b.size())
            {
               VectorException e("Invalid VectorBase index");
               GPSTK_THROW(e);
            }
#endif
            return b[i];
         }
   };

/**
 * A base class that represents a subset of a vector.
 */
   template <class BaseClass>
   class VectorSliceBase
   {
   public:
         /// constructor
      explicit VectorSliceBase() {}

         /// the number of elements in the slice.
      size_t size() const
         { return static_cast<const BaseClass*>(this)->size(); }
         /// the start index in the BaseClass vector for this slice.
      size_t start() const
         { return static_cast<const BaseClass*>(this)->start(); }
         /// How many elements separate the i'th element from the i+1'th element.
      size_t stride() const
         { return static_cast<const BaseClass*>(this)->stride(); }

   protected:
         /// Given the size of the source vector, checks that the slice is valid.
      inline void vecSliceCheck(size_t sourceSize) const
         throw(VectorException)
         {
#ifdef RANGECHECK
               // sanity checks...
            if ( (start() >= sourceSize) ||
                 ((start() + (size() - 1) * stride()) >= sourceSize) )
            {
               VectorException e("Invalid range for slice");
               GPSTK_THROW(e);
            }
#endif
         }
   };

/**
 * A vector slice base class that doesn't allow modification of the
 * internal elements.
 */
   template <class T, class BaseClass>
   class ConstVectorSliceBase : public VectorSliceBase<BaseClass>,
                             public ConstVectorBase<T, BaseClass>
   {
public:
   explicit ConstVectorSliceBase() {}
};

/**
 * A vector slice base class that does allow modification of the
 * internal elements.
 */
template <class T, class BaseClass>
class RefVectorSliceBase : public VectorSliceBase<BaseClass>,
                        public RefVectorBase<T, BaseClass>
{
public:
   explicit RefVectorSliceBase() {}
};

//@}

}  // namespace gpstk

#include "VectorBaseOperators.hpp"

#endif //GPSTK_VECTOR_BASE_HPP
<|endoftext|>


<commit_before>//
//  Copyright (C) 2016  Clifford Wolf <clifford@clifford.at>
//
//  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.
//
//  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
//  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
//  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
//  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
//  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
//  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
//  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <sys/time.h>

#include <map>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>

using std::map;
using std::pair;
using std::vector;
using std::string;
using std::ifstream;
using std::getline;

uint64_t x;
uint64_t xorshift64star(void) {
	x ^= x >> 12; // a
	x ^= x << 25; // b
	x ^= x >> 27; // c
	return x * UINT64_C(2685821657736338717);
}

void parse_hexfile_line(const char *filename, int linenr, vector<vector<bool>> &hexfile, string &line)
{
	vector<int> digits;

	for (char c : line) {
		if ('0' <= c && c <= '9')
			digits.push_back(c - '0');
		else if ('a' <= c && c <= 'f')
			digits.push_back(10 + c - 'a');
		else if ('A' <= c && c <= 'F')
			digits.push_back(10 + c - 'A');
		else goto error;
	}

	hexfile.push_back(vector<bool>(digits.size() * 4));

	for (int i = 0; i < digits.size() * 4; i++)
		if ((digits.at(digits.size() - i/4 -1) & (1 << (i%4))) != 0)
			hexfile.back().at(i) = true;

	return;

error:
	fprintf(stderr, "Can't parse line %d of %s: %s\n", linenr, filename, line.c_str());
	exit(1);
}

void help(const char *cmd)
{
	printf("\n");
	printf("Usage: %s [options] <from_hexfile> <to_hexfile>\n", cmd);
	printf("       %s [options] -g <width> <depth>\n", cmd);
	printf("\n");
	printf("Replace BRAM initialization data in a .asc file. This can be used\n");
	printf("for example to replace firmware images without re-running synthesis\n");
	printf("and place&route.\n");
	printf("\n");
	printf("    -g\n");
	printf("        generate a hex file with random contents.\n");
	printf("        use this to generate the hex file used during synthesis, then\n");
	printf("        use the same file as <from_hexfile> later.\n");
	printf("\n");
	printf("    -v\n");
	printf("        verbose output\n");
	printf("\n");
	exit(1);
}

int main(int argc, char **argv)
{
	bool verbose = false;
	bool generate = false;

	int opt;
	while ((opt = getopt(argc, argv, "vg")) != -1)
	{
		switch (opt)
		{
		case 'v':
			verbose = true;
			break;
		case 'g':
			generate = true;
			break;
		default:
			help(argv[0]);
		}
	}

	if (generate)
	{
		if (optind+2 != argc)
			help(argv[0]);

		int width = atoi(argv[optind]);
		int depth = atoi(argv[optind+1]);

		if (width <= 0 || width % 4 != 0) {
			fprintf(stderr, "Hexfile width (%d bits) is not divisible by 4 or nonpositive!\n", width);
			exit(1);
		}

		if (depth <= 0 || depth % 256 != 0) {
			fprintf(stderr, "Hexfile number of words (%d) is not divisible by 256 or nonpositive!\n", depth);
			exit(1);
		}

		x = uint64_t(getpid()) << 32;
		x ^= uint64_t(depth) << 16;
		x ^= uint64_t(width) << 10;

		xorshift64star();
		xorshift64star();
		xorshift64star();

		struct timeval tv;
		gettimeofday(&tv, NULL);
		x ^= uint64_t(tv.tv_sec) << 20;
		x ^= uint64_t(tv.tv_usec);

		xorshift64star();
		xorshift64star();
		xorshift64star();

		for (int i = 0; i < depth; i++) {
			for (int j = 0; j < width / 4; j++) {
				int digit = xorshift64star() & 15;
				std::cout << "0123456789abcdef"[digit];
			}
			std::cout << std::endl;
		}

		exit(1);
	}

	if (optind+2 != argc)
		help(argv[0]);

	// -------------------------------------------------------
	// Load from_hexfile and to_hexfile

	const char *from_hexfile_n = argv[optind];
	ifstream from_hexfile_f(from_hexfile_n);
	vector<vector<bool>> from_hexfile;

	const char *to_hexfile_n = argv[optind+1];
	ifstream to_hexfile_f(to_hexfile_n);
	vector<vector<bool>> to_hexfile;

	string line;

	for (int i = 1; getline(from_hexfile_f, line); i++)
		parse_hexfile_line(from_hexfile_n, i, from_hexfile, line);

	for (int i = 1; getline(to_hexfile_f, line); i++)
		parse_hexfile_line(to_hexfile_n, i, to_hexfile, line);

	if (from_hexfile.size() != to_hexfile.size()) {
		fprintf(stderr, "Hexfiles have different number of words! (%d vs. %d)\n", int(from_hexfile.size()), int(to_hexfile.size()));
		exit(1);
	}

	if (from_hexfile.size() % 256 != 0) {
		fprintf(stderr, "Hexfile number of words (%d) is not divisible by 256!\n", int(from_hexfile.size()));
		exit(1);
	}

	for (size_t i = 1; i < from_hexfile.size(); i++)
		if (from_hexfile.at(i-1).size() != from_hexfile.at(i).size()) {
			fprintf(stderr, "Inconsistent word width at line %d of %s!\n", int(i), from_hexfile_n);
			exit(1);
		}

	for (size_t i = 1; i < to_hexfile.size(); i++)
		if (to_hexfile.at(i-1).size() != to_hexfile.at(i).size()) {
			fprintf(stderr, "Inconsistent word width at line %d of %s!\n", int(i+1), to_hexfile_n);
			exit(1);
		}

	if (from_hexfile.size() == 0 || from_hexfile.at(0).size() == 0) {
		fprintf(stderr, "Empty from/to hexfiles!\n");
		exit(1);
	}

	if (verbose)
		fprintf(stderr, "Loaded pattern for %d bits wide and %d words deep memory.\n", int(from_hexfile.at(0).size()), int(from_hexfile.size()));

	// -------------------------------------------------------
	// Create bitslices from pattern data

	map<vector<bool>, pair<vector<bool>, int>> pattern;

	for (int i = 0; i < int(from_hexfile.at(0).size()); i++)
	{
		vector<bool> pattern_from, pattern_to;

		for (int j = 0; j < int(from_hexfile.size()); j++)
		{
			pattern_from.push_back(from_hexfile.at(j).at(i));
			pattern_to.push_back(to_hexfile.at(j).at(i));

			if (pattern_from.size() == 256) {
				if (pattern.count(pattern_from)) {
					fprintf(stderr, "Conflicting from pattern for bit slice from_hexfile[%d:%d][%d]!\n", j, j-255, i);
					exit(1);
				}
				pattern[pattern_from] = std::make_pair(pattern_to, 0);
				pattern_from.clear(), pattern_to.clear();
			}
		}

		assert(pattern_from.empty());
		assert(pattern_to.empty());
	}

	if (verbose)
		fprintf(stderr, "Extracted %d bit slices from from/to hexfile data.\n", int(pattern.size()));

	// -------------------------------------------------------
	// Read ascfile from stdin

	vector<string> ascfile_lines;
	map<string, vector<vector<bool>>> ascfile_hexdata;

	for (int i = 1; getline(std::cin, line); i++)
	{
	next_asc_stmt:
		ascfile_lines.push_back(line);

		if (line.substr(0, 9) == ".ram_data")
		{
			auto &hexdata = ascfile_hexdata[line];

			for (; getline(std::cin, line); i++) {
				if (line.substr(0, 1) == ".")
					goto next_asc_stmt;
				parse_hexfile_line("stdin", i, hexdata, line);
			}
		}
	}

	if (verbose)
		fprintf(stderr, "Found %d initialized bram cells in asc file.\n", int(ascfile_hexdata.size()));

	// -------------------------------------------------------
	// Replace bram data

	int max_replace_cnt = 0;

	for (auto &bram_it : ascfile_hexdata)
	{
		auto &bram_data = bram_it.second;

		for (int i = 0; i < 16; i++)
		{
			vector<bool> from_bitslice;

			for (int j = 0; j < 256; j++)
				from_bitslice.push_back(bram_data.at(j / 16).at(16 * (j % 16) + i));

			auto p = pattern.find(from_bitslice);
			if (p != pattern.end())
			{
				auto &to_bitslice = p->second.first;

				for (int j = 0; j < 256; j++)
					bram_data.at(j / 16).at(16 * (j % 16) + i) = to_bitslice.at(j);

				max_replace_cnt = std::max(++p->second.second, max_replace_cnt);
			}
		}
	}

	int min_replace_cnt = max_replace_cnt;
	for (auto &it : pattern)
		min_replace_cnt = std::min(min_replace_cnt, it.second.second);

	if (min_replace_cnt != max_replace_cnt) {
		fprintf(stderr, "Found some bitslices up to %d times, others only %d times!\n", max_replace_cnt, min_replace_cnt);
		exit(1);
	}

	if (verbose)
		fprintf(stderr, "Found and replaced %d instances of the memory.\n", max_replace_cnt);

	// -------------------------------------------------------
	// Write ascfile to stdout

	for (size_t i = 0; i < ascfile_lines.size(); i++) {
		auto &line = ascfile_lines.at(i);
		std::cout << line << std::endl;
		if (ascfile_hexdata.count(line)) {
			for (auto &word : ascfile_hexdata.at(line)) {
				for (int k = word.size()-4; k >= 0; k -= 4) {
					int digit = (word[k+3] ? 8 : 0) + (word[k+2] ? 4 : 0) + (word[k+1] ? 2 : 0) + (word[k] ? 1 : 0);
					std::cout << "0123456789abcdef"[digit];
				}
				std::cout << std::endl;
			}
		}
	}

	return 0;
}
<commit_msg>Minor icebram improvements<commit_after>//
//  Copyright (C) 2016  Clifford Wolf <clifford@clifford.at>
//
//  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.
//
//  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
//  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
//  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
//  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
//  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
//  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
//  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <sys/time.h>

#include <map>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>

using std::map;
using std::pair;
using std::vector;
using std::string;
using std::ifstream;
using std::getline;

uint64_t x;
uint64_t xorshift64star(void) {
	x ^= x >> 12; // a
	x ^= x << 25; // b
	x ^= x >> 27; // c
	return x * UINT64_C(2685821657736338717);
}

void parse_hexfile_line(const char *filename, int linenr, vector<vector<bool>> &hexfile, string &line)
{
	vector<int> digits;

	for (char c : line) {
		if ('0' <= c && c <= '9')
			digits.push_back(c - '0');
		else if ('a' <= c && c <= 'f')
			digits.push_back(10 + c - 'a');
		else if ('A' <= c && c <= 'F')
			digits.push_back(10 + c - 'A');
		else goto error;
	}

	hexfile.push_back(vector<bool>(digits.size() * 4));

	for (int i = 0; i < int(digits.size()) * 4; i++)
		if ((digits.at(digits.size() - i/4 -1) & (1 << (i%4))) != 0)
			hexfile.back().at(i) = true;

	return;

error:
	fprintf(stderr, "Can't parse line %d of %s: %s\n", linenr, filename, line.c_str());
	exit(1);
}

void help(const char *cmd)
{
	printf("\n");
	printf("Usage: %s [options] <from_hexfile> <to_hexfile>\n", cmd);
	printf("       %s [options] -g <width> <depth>\n", cmd);
	printf("\n");
	printf("Replace BRAM initialization data in a .asc file. This can be used\n");
	printf("for example to replace firmware images without re-running synthesis\n");
	printf("and place&route.\n");
	printf("\n");
	printf("    -g\n");
	printf("        generate a hex file with random contents.\n");
	printf("        use this to generate the hex file used during synthesis, then\n");
	printf("        use the same file as <from_hexfile> later.\n");
	printf("\n");
	printf("    -v\n");
	printf("        verbose output\n");
	printf("\n");
	exit(1);
}

int main(int argc, char **argv)
{
	bool verbose = false;
	bool generate = false;

	int opt;
	while ((opt = getopt(argc, argv, "vg")) != -1)
	{
		switch (opt)
		{
		case 'v':
			verbose = true;
			break;
		case 'g':
			generate = true;
			break;
		default:
			help(argv[0]);
		}
	}

	if (generate)
	{
		if (optind+2 != argc)
			help(argv[0]);

		int width = atoi(argv[optind]);
		int depth = atoi(argv[optind+1]);

		if (width <= 0 || width % 4 != 0) {
			fprintf(stderr, "Hexfile width (%d bits) is not divisible by 4 or nonpositive!\n", width);
			exit(1);
		}

		if (depth <= 0 || depth % 256 != 0) {
			fprintf(stderr, "Hexfile number of words (%d) is not divisible by 256 or nonpositive!\n", depth);
			exit(1);
		}

		x = uint64_t(getpid()) << 32;
		x ^= uint64_t(depth) << 16;
		x ^= uint64_t(width) << 10;

		xorshift64star();
		xorshift64star();
		xorshift64star();

		struct timeval tv;
		gettimeofday(&tv, NULL);
		x ^= uint64_t(tv.tv_sec) << 20;
		x ^= uint64_t(tv.tv_usec);

		xorshift64star();
		xorshift64star();
		xorshift64star();

		for (int i = 0; i < depth; i++) {
			for (int j = 0; j < width / 4; j++) {
				int digit = xorshift64star() & 15;
				std::cout << "0123456789abcdef"[digit];
			}
			std::cout << std::endl;
		}

		exit(0);
	}

	if (optind+2 != argc)
		help(argv[0]);

	// -------------------------------------------------------
	// Load from_hexfile and to_hexfile

	const char *from_hexfile_n = argv[optind];
	ifstream from_hexfile_f(from_hexfile_n);
	vector<vector<bool>> from_hexfile;

	const char *to_hexfile_n = argv[optind+1];
	ifstream to_hexfile_f(to_hexfile_n);
	vector<vector<bool>> to_hexfile;

	string line;

	for (int i = 1; getline(from_hexfile_f, line); i++)
		parse_hexfile_line(from_hexfile_n, i, from_hexfile, line);

	for (int i = 1; getline(to_hexfile_f, line); i++)
		parse_hexfile_line(to_hexfile_n, i, to_hexfile, line);

	if (from_hexfile.size() != to_hexfile.size()) {
		fprintf(stderr, "Hexfiles have different number of words! (%d vs. %d)\n", int(from_hexfile.size()), int(to_hexfile.size()));
		exit(1);
	}

	if (from_hexfile.size() % 256 != 0) {
		fprintf(stderr, "Hexfile number of words (%d) is not divisible by 256!\n", int(from_hexfile.size()));
		exit(1);
	}

	for (size_t i = 1; i < from_hexfile.size(); i++)
		if (from_hexfile.at(i-1).size() != from_hexfile.at(i).size()) {
			fprintf(stderr, "Inconsistent word width at line %d of %s!\n", int(i), from_hexfile_n);
			exit(1);
		}

	for (size_t i = 1; i < to_hexfile.size(); i++) {
		while (to_hexfile.at(i-1).size() > to_hexfile.at(i).size())
			to_hexfile.at(i).push_back(false);
		if (to_hexfile.at(i-1).size() != to_hexfile.at(i).size()) {
			fprintf(stderr, "Inconsistent word width at line %d of %s!\n", int(i+1), to_hexfile_n);
			exit(1);
		}
	}

	if (from_hexfile.size() == 0 || from_hexfile.at(0).size() == 0) {
		fprintf(stderr, "Empty from/to hexfiles!\n");
		exit(1);
	}

	if (verbose)
		fprintf(stderr, "Loaded pattern for %d bits wide and %d words deep memory.\n", int(from_hexfile.at(0).size()), int(from_hexfile.size()));

	// -------------------------------------------------------
	// Create bitslices from pattern data

	map<vector<bool>, pair<vector<bool>, int>> pattern;

	for (int i = 0; i < int(from_hexfile.at(0).size()); i++)
	{
		vector<bool> pattern_from, pattern_to;

		for (int j = 0; j < int(from_hexfile.size()); j++)
		{
			pattern_from.push_back(from_hexfile.at(j).at(i));
			pattern_to.push_back(to_hexfile.at(j).at(i));

			if (pattern_from.size() == 256) {
				if (pattern.count(pattern_from)) {
					fprintf(stderr, "Conflicting from pattern for bit slice from_hexfile[%d:%d][%d]!\n", j, j-255, i);
					exit(1);
				}
				pattern[pattern_from] = std::make_pair(pattern_to, 0);
				pattern_from.clear(), pattern_to.clear();
			}
		}

		assert(pattern_from.empty());
		assert(pattern_to.empty());
	}

	if (verbose)
		fprintf(stderr, "Extracted %d bit slices from from/to hexfile data.\n", int(pattern.size()));

	// -------------------------------------------------------
	// Read ascfile from stdin

	vector<string> ascfile_lines;
	map<string, vector<vector<bool>>> ascfile_hexdata;

	for (int i = 1; getline(std::cin, line); i++)
	{
	next_asc_stmt:
		ascfile_lines.push_back(line);

		if (line.substr(0, 9) == ".ram_data")
		{
			auto &hexdata = ascfile_hexdata[line];

			for (; getline(std::cin, line); i++) {
				if (line.substr(0, 1) == ".")
					goto next_asc_stmt;
				parse_hexfile_line("stdin", i, hexdata, line);
			}
		}
	}

	if (verbose)
		fprintf(stderr, "Found %d initialized bram cells in asc file.\n", int(ascfile_hexdata.size()));

	// -------------------------------------------------------
	// Replace bram data

	int max_replace_cnt = 0;

	for (auto &bram_it : ascfile_hexdata)
	{
		auto &bram_data = bram_it.second;

		for (int i = 0; i < 16; i++)
		{
			vector<bool> from_bitslice;

			for (int j = 0; j < 256; j++)
				from_bitslice.push_back(bram_data.at(j / 16).at(16 * (j % 16) + i));

			auto p = pattern.find(from_bitslice);
			if (p != pattern.end())
			{
				auto &to_bitslice = p->second.first;

				for (int j = 0; j < 256; j++)
					bram_data.at(j / 16).at(16 * (j % 16) + i) = to_bitslice.at(j);

				max_replace_cnt = std::max(++p->second.second, max_replace_cnt);
			}
		}
	}

	int min_replace_cnt = max_replace_cnt;
	for (auto &it : pattern)
		min_replace_cnt = std::min(min_replace_cnt, it.second.second);

	if (min_replace_cnt != max_replace_cnt) {
		fprintf(stderr, "Found some bitslices up to %d times, others only %d times!\n", max_replace_cnt, min_replace_cnt);
		exit(1);
	}

	if (verbose)
		fprintf(stderr, "Found and replaced %d instances of the memory.\n", max_replace_cnt);

	// -------------------------------------------------------
	// Write ascfile to stdout

	for (size_t i = 0; i < ascfile_lines.size(); i++) {
		auto &line = ascfile_lines.at(i);
		std::cout << line << std::endl;
		if (ascfile_hexdata.count(line)) {
			for (auto &word : ascfile_hexdata.at(line)) {
				for (int k = word.size()-4; k >= 0; k -= 4) {
					int digit = (word[k+3] ? 8 : 0) + (word[k+2] ? 4 : 0) + (word[k+1] ? 2 : 0) + (word[k] ? 1 : 0);
					std::cout << "0123456789abcdef"[digit];
				}
				std::cout << std::endl;
			}
		}
	}

	return 0;
}
<|endoftext|>


<commit_before>#include "blocktypesreader.h"

#include <QMap>
#include "flowchart/blocktype.h"
#include <QIODevice>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QString>
#include "flowchart/datatype.h"
#include "flowchart/blockoption.h"
#include "flowchart/blockoptioninteger.h"
#include "flowchart/blockoptioncombobox.h"
#include <QSharedPointer>
#include <QMap>

BlockTypesReader::BlockTypesReader() {}

QMap<QString, BlockType> BlockTypesReader::blockTypes() {
    return m_blockTypes;
}

void BlockTypesReader::read(QIODevice *device) {
    QByteArray bytes = device->readAll();
    QJsonDocument doc(QJsonDocument::fromJson(bytes));
    QJsonObject node = doc.object();
    m_blockTypes = readBlockTypes(node["BlockTypes"]);
}

QMap<QString, BlockType> BlockTypesReader::readBlockTypes(QJsonValue node) {
    QJsonArray nodeArray = node.toArray();
    QMap<QString, BlockType> blockTypes;
    for (int i = 0; i < nodeArray.size(); i++) {
        QJsonValue element = nodeArray[i];
        BlockType bt = readBlockType(element);
        blockTypes[bt.name()] = bt;
    }
    return blockTypes;
}

BlockType BlockTypesReader::readBlockType(QJsonValue node) {
    QJsonObject nodeObject = node.toObject();
    QString name = nodeObject["name"].toString();
    QString displayName = nodeObject["displayName"].toString();
    QMap<QString, DataType> inputs = readPinList(nodeObject["inputs"]);
    QMap<QString, DataType> outputs = readPinList(nodeObject["outputs"]);
    QMap<QString, QSharedPointer<const BlockOption> > options;
    QJsonObject optionsNodeObject = nodeObject["options"].toObject();
    for (QJsonObject::const_iterator i = optionsNodeObject.begin(); i != optionsNodeObject.end(); i++) {
        options[i.key()] = readBlockOption(i.value());
    }
    BlockType blockType(name, displayName, inputs, outputs, options);
    return blockType;
}

QMap<QString, DataType> BlockTypesReader::readPinList(QJsonValue node) {
    QJsonObject nodeObject = node.toObject();
    QMap<QString, DataType> pinList;
    QJsonObject::const_iterator i;
    for (i = nodeObject.begin(); i != nodeObject.end(); i++) {
        pinList[i.key()] = static_cast<DataType>(i.value().toInt());
    }
    return pinList;
}

QSharedPointer<const BlockOption> BlockTypesReader::readBlockOption(QJsonValue node) {
    QJsonObject nodeObject = node.toObject();
    QString displayName = nodeObject["displayName"].toString();
    QString defaultValue = nodeObject["defaultValue"].toString();
    QString optionType = nodeObject["optionType"].toString();
    if (optionType == "integer") {
        int minimum = 0;
        int maximum = 99;
        QJsonValue minimumMaybe = nodeObject["minimum"];
        if (!(minimumMaybe.isNull() || minimumMaybe.isUndefined())) {
            minimum = minimumMaybe.toInt();
        }
        QJsonValue maximumMaybe = nodeObject["maximum"];
        if (!(maximumMaybe.isNull() || minimumMaybe.isUndefined())) {
            maximum = maximumMaybe.toInt();
        }
        return QSharedPointer<const BlockOption>(new BlockOptionInteger(displayName, defaultValue, minimum, maximum));
    } else if (optionType == "combobox") {
        QJsonObject choicesNodeObject = nodeObject["choices"].toObject();
        QMap<QString, QString> choices;
        for (QJsonObject::const_iterator i = choicesNodeObject.begin(); i != choicesNodeObject.end(); i++) {
            choices[i.key()] = i.value().toString();
        }
        return QSharedPointer<const BlockOption>(new BlockOptionComboBox(displayName, defaultValue, choices));
    } else if (optionType == "float") {
        // TODO: throw
        throw "abc";
    } else if (optionType == "stringInput") {
        // TODO: throw
        throw "abc";
    } else {
        // TODO: throw
        throw "abc";
    }
}
<commit_msg>Fix const mismatch in BlockTypesReader<commit_after>#include "blocktypesreader.h"

#include <QMap>
#include "flowchart/blocktype.h"
#include <QIODevice>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QString>
#include "flowchart/datatype.h"
#include "flowchart/blockoption.h"
#include "flowchart/blockoptioninteger.h"
#include "flowchart/blockoptioncombobox.h"
#include <QSharedPointer>
#include <QMap>

BlockTypesReader::BlockTypesReader() {}

QMap<QString, BlockType> BlockTypesReader::blockTypes() const {
    return m_blockTypes;
}

void BlockTypesReader::read(QIODevice *device) {
    QByteArray bytes = device->readAll();
    QJsonDocument doc(QJsonDocument::fromJson(bytes));
    QJsonObject node = doc.object();
    m_blockTypes = readBlockTypes(node["BlockTypes"]);
}

QMap<QString, BlockType> BlockTypesReader::readBlockTypes(QJsonValue node) {
    QJsonArray nodeArray = node.toArray();
    QMap<QString, BlockType> blockTypes;
    for (int i = 0; i < nodeArray.size(); i++) {
        QJsonValue element = nodeArray[i];
        BlockType bt = readBlockType(element);
        blockTypes[bt.name()] = bt;
    }
    return blockTypes;
}

BlockType BlockTypesReader::readBlockType(QJsonValue node) {
    QJsonObject nodeObject = node.toObject();
    QString name = nodeObject["name"].toString();
    QString displayName = nodeObject["displayName"].toString();
    QMap<QString, DataType> inputs = readPinList(nodeObject["inputs"]);
    QMap<QString, DataType> outputs = readPinList(nodeObject["outputs"]);
    QMap<QString, QSharedPointer<const BlockOption> > options;
    QJsonObject optionsNodeObject = nodeObject["options"].toObject();
    for (QJsonObject::const_iterator i = optionsNodeObject.begin(); i != optionsNodeObject.end(); i++) {
        options[i.key()] = readBlockOption(i.value());
    }
    BlockType blockType(name, displayName, inputs, outputs, options);
    return blockType;
}

QMap<QString, DataType> BlockTypesReader::readPinList(QJsonValue node) {
    QJsonObject nodeObject = node.toObject();
    QMap<QString, DataType> pinList;
    QJsonObject::const_iterator i;
    for (i = nodeObject.begin(); i != nodeObject.end(); i++) {
        pinList[i.key()] = static_cast<DataType>(i.value().toInt());
    }
    return pinList;
}

QSharedPointer<const BlockOption> BlockTypesReader::readBlockOption(QJsonValue node) {
    QJsonObject nodeObject = node.toObject();
    QString displayName = nodeObject["displayName"].toString();
    QString defaultValue = nodeObject["defaultValue"].toString();
    QString optionType = nodeObject["optionType"].toString();
    if (optionType == "integer") {
        int minimum = 0;
        int maximum = 99;
        QJsonValue minimumMaybe = nodeObject["minimum"];
        if (!(minimumMaybe.isNull() || minimumMaybe.isUndefined())) {
            minimum = minimumMaybe.toInt();
        }
        QJsonValue maximumMaybe = nodeObject["maximum"];
        if (!(maximumMaybe.isNull() || minimumMaybe.isUndefined())) {
            maximum = maximumMaybe.toInt();
        }
        return QSharedPointer<const BlockOption>(new BlockOptionInteger(displayName, defaultValue, minimum, maximum));
    } else if (optionType == "combobox") {
        QJsonObject choicesNodeObject = nodeObject["choices"].toObject();
        QMap<QString, QString> choices;
        for (QJsonObject::const_iterator i = choicesNodeObject.begin(); i != choicesNodeObject.end(); i++) {
            choices[i.key()] = i.value().toString();
        }
        return QSharedPointer<const BlockOption>(new BlockOptionComboBox(displayName, defaultValue, choices));
    } else if (optionType == "float") {
        // TODO: throw
        throw "abc";
    } else if (optionType == "stringInput") {
        // TODO: throw
        throw "abc";
    } else {
        // TODO: throw
        throw "abc";
    }
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// aggregator.cpp
//
// Identification: src/backend/executor/aggregator.cpp
//
// Copyright (c) 2015, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "backend/executor/aggregator.h"
#include "backend/common/logger.h"

namespace peloton {
namespace executor {

/*
 * Create an instance of an aggregator for the specified aggregate
 * type, column type, and result type. The object is constructed in
 * memory from the provided memrory pool.
 */
Agg *GetAggInstance(ExpressionType agg_type) {
  Agg *aggregator;

  switch (agg_type) {
    case EXPRESSION_TYPE_AGGREGATE_COUNT:
      aggregator = new CountAgg();
      break;
    case EXPRESSION_TYPE_AGGREGATE_COUNT_STAR:
      aggregator = new CountStarAgg();
      break;
    case EXPRESSION_TYPE_AGGREGATE_SUM:
      aggregator = new SumAgg();
      break;
    case EXPRESSION_TYPE_AGGREGATE_AVG:
      aggregator = new AvgAgg(false);
      break;
    case EXPRESSION_TYPE_AGGREGATE_WEIGHTED_AVG:
      aggregator = new AvgAgg(true);
      break;
    case EXPRESSION_TYPE_AGGREGATE_MIN:
      aggregator = new MinAgg();
      break;
    case EXPRESSION_TYPE_AGGREGATE_MAX:
      aggregator = new MaxAgg();
      break;
    default: {
      std::string message = "Unknown aggregate type "
          + std::to_string(agg_type);
      throw UnknownTypeException(agg_type, message);
    }
  }

  return aggregator;
}

/*
 * Helper method responsible for inserting the results of the aggregation
 * into a new tuple in the output tile group as well as passing through any
 * additional columns from the input tile group.
 * FIXME: need to examine Value's uninlined data problem later.
 */
bool Helper(const planner::AggregateV2Node *node, Agg **aggregates,
            storage::DataTable *output_table, const AbstractTuple *prev_tuple,
            executor::ExecutorContext* econtext) {
  // Ignore null tuples
  if (prev_tuple == nullptr)
    return true;

  auto schema = output_table->GetSchema();
  std::unique_ptr<storage::Tuple> tuple(new storage::Tuple(schema, true));

  /*
   * 1) Construct a vector of aggregated values
   */
  std::vector<Value> aggregate_values;
  auto& aggregate_terms = node->GetUniqueAggTerms();
  for (oid_t column_itr = 0; column_itr < aggregate_terms.size();
      column_itr++) {
    if (aggregates[column_itr] != nullptr) {
      Value final_val = aggregates[column_itr]->Finalize();
      aggregate_values.push_back(final_val);
    }
  }

  /*
   * 2) Evaluate filter predicate;
   * if fail, just return
   */
  std::unique_ptr<expression::ContainerTuple<std::vector<Value>> > aggref_tuple(
      new expression::ContainerTuple<std::vector<Value>>(&aggregate_values));

  auto predicate = node->GetPredicate();
  if (nullptr != predicate
      && predicate->Evaluate(prev_tuple, aggref_tuple.get(), econtext).IsFalse()) {
    return true;  // Qual fails, do nothing
  }

  /*
   * 3) Construct the tuple to insert using projectInfo
   */
  node->GetProjectInfo()->Evaluate(tuple.get(), prev_tuple, aggref_tuple.get(),
                                   econtext);

  LOG_INFO("Tuple to Output :");
  std::cout << "GROUP TUPLE :: " << *(tuple.get());

  auto location = output_table->InsertTuple(econtext->GetTransaction(),
                                            tuple.get());
  if (location.block == INVALID_OID) {
    LOG_ERROR("Failed to insert tuple \n");
    return false;
  }

  return true;
}

//===--------------------------------------------------------------------===//
// Specialization of an Aggregator that uses a hash map to aggregate
// tuples from the input table, i.e. it does not expect the input
// table to be sorted on the group by key.
//===--------------------------------------------------------------------===//

template<>
Aggregator<PlanNodeType::PLAN_NODE_TYPE_HASHAGGREGATE>::Aggregator(
    const planner::AggregateV2Node *node, storage::DataTable *output_table,
    executor::ExecutorContext* econtext)
    : node(node),
      output_table(output_table),
      executor_context(econtext) {

  group_by_key_values.resize(node->GetGroupbyColIds().size(),
                             ValueFactory::GetNullValue());

}

template<>
Aggregator<PlanNodeType::PLAN_NODE_TYPE_HASHAGGREGATE>::~Aggregator() {

}

template<>
bool Aggregator<PlanNodeType::PLAN_NODE_TYPE_HASHAGGREGATE>::Advance(
    AbstractTuple *cur_tuple, AbstractTuple *prev_tuple __attribute__((unused)),
    size_t num_columns) {

  AggregateList *aggregate_list;

  // Configure a group-by-key and search for the required group.
  for (oid_t column_itr = 0; column_itr < node->GetGroupbyColIds().size();
      column_itr++) {
    Value cur_tuple_val = cur_tuple->GetValue(
        node->GetGroupbyColIds()[column_itr]);
    group_by_key_values[column_itr] = cur_tuple_val;
  }

  auto map_itr = aggregates_map.find(group_by_key_values);

// Group not found. Make a new entry in the hash for this new group.
  if (map_itr == aggregates_map.end()) {
    LOG_INFO("Group-by key not found. Start a new group.");
    // Allocate new aggregate list
    aggregate_list = new AggregateList();
    aggregate_list->aggregates = new Agg *[node->GetUniqueAggTerms().size()];
    // Make a deep copy of the first tuple we meet
    for (size_t col_id = 0; col_id < num_columns; col_id++) {
      aggregate_list->first_tuple_values.push_back(
          ValueFactory::Clone(cur_tuple->GetValue(col_id)));
    };

    for (oid_t column_itr = 0; column_itr < node->GetUniqueAggTerms().size();
        column_itr++) {
      aggregate_list->aggregates[column_itr] = GetAggInstance(
          node->GetUniqueAggTerms()[column_itr].first);
    }

    aggregates_map.insert(
        HashAggregateMapType::value_type(group_by_key_values, aggregate_list));
  }
// Otherwise, the list is the second item of the pair.
  else {
    aggregate_list = map_itr->second;
  }

// Update the aggregation calculation
  for (oid_t aggno = 0; aggno < node->GetUniqueAggTerms().size(); aggno++) {
    Value value = node->GetUniqueAggTerms()[aggno].second->Evaluate(
        cur_tuple, nullptr, this->executor_context);
    aggregate_list->aggregates[aggno]->Advance(value);
  }

  return true;
}

template<>
bool Aggregator<PlanNodeType::PLAN_NODE_TYPE_HASHAGGREGATE>::Finalize(
    AbstractTuple *prev_tuple __attribute__((unused))) {
  for (auto entry : aggregates_map) {
    // Construct a container for the first tuple
    expression::ContainerTuple<std::vector<Value>> first_tuple(&entry.second->first_tuple_values);
    if (Helper(node, entry.second->aggregates, output_table,
               &first_tuple, this->executor_context) == false) {
      return false;
    }

    // Clean up allocated storage
    delete[] entry.second->aggregates;
    for(auto &v : entry.second->first_tuple_values){
      v.FreeUninlinedData();
    }
  }

// TODO: if no record exists in input_table, we have to output a null record
// only when it doesn't have GROUP BY. See difference of these cases:
//   SELECT SUM(A) FROM BBB ,   when BBB has no tuple
//   SELECT SUM(A) FROM BBB GROUP BY C,   when BBB has no tuple

  return true;
}

//===--------------------------------------------------------------------===//
// Specialization of an aggregator that expects the input table to be
// sorted on the group by key.
//===--------------------------------------------------------------------===//
template<>
Aggregator<PlanNodeType::PLAN_NODE_TYPE_AGGREGATE>::Aggregator(
    const planner::AggregateV2Node *node, storage::DataTable *output_table,
    executor::ExecutorContext* econtext)
    : node(node),
      output_table(output_table),
      executor_context(econtext) {

  group_by_columns = node->GetGroupbyColIds();

// Create aggregators and initialize
  aggregate_terms = node->GetUniqueAggTerms();
  aggregates = new Agg *[aggregate_terms.size()];
  ::memset(aggregates, 0, sizeof(Agg *) * aggregate_terms.size());
}

template<>
Aggregator<PlanNodeType::PLAN_NODE_TYPE_AGGREGATE>::~Aggregator() {
// Clean up aggregators
  for (oid_t column_itr = 0; column_itr < aggregate_terms.size();
      column_itr++) {
    delete aggregates[column_itr];
  }
  delete[] aggregates;
}

template<>
bool Aggregator<PlanNodeType::PLAN_NODE_TYPE_AGGREGATE>::Advance(
    AbstractTuple *cur_tuple, AbstractTuple *prev_tuple,
    size_t __attribute__((unused))) {
  bool start_new_agg = false;

// Check if we are starting a new aggregate tuple
  if (prev_tuple == nullptr) {
    LOG_INFO("Prev tuple is nullptr!");
    start_new_agg = true;
  } else {
    // Compare group by columns
    for (oid_t column_itr = 0; column_itr < group_by_columns.size();
        column_itr++) {
      Value lval = cur_tuple->GetValue(group_by_columns[column_itr]);
      Value rval = prev_tuple->GetValue(group_by_columns[column_itr]);
      bool not_equal = lval.OpNotEquals(rval).IsTrue();

      if (not_equal) {
        LOG_INFO("Group-by columns changed.");
        start_new_agg = true;
        break;
      }
    }
  }

// If we have started a new aggregate tuple
  if (start_new_agg) {
    LOG_INFO("Started a new group!");

    if (Helper(node, aggregates, output_table, prev_tuple,
               this->executor_context) ==
    false) {
      return false;
    }

    // Create aggregate
    for (oid_t column_itr = 0; column_itr < aggregate_terms.size();
        column_itr++) {
      // Clean up previous aggregate
      delete aggregates[column_itr];
      aggregates[column_itr] = GetAggInstance(
          aggregate_terms[column_itr].first);
    }
  }

// Update the aggregation calculation
  for (oid_t column_itr = 0; column_itr < aggregate_terms.size();
      column_itr++) {
    Value value = aggregate_terms[column_itr].second->Evaluate(
        cur_tuple, nullptr, this->executor_context);
    aggregates[column_itr]->Advance(value);
  }

  return true;
}

template<>
bool Aggregator<PlanNodeType::PLAN_NODE_TYPE_AGGREGATE>::Finalize(
    AbstractTuple *prev_tuple) {
  if (Helper(node, aggregates, output_table, prev_tuple,
             this->executor_context) ==
             false) {
    return false;
  }

// TODO: if no record exists in input_table, we have to output a null record
// only when it doesn't have GROUP BY. See difference of these cases:
//   SELECT SUM(A) FROM BBB ,   when BBB has no tuple
//   SELECT SUM(A) FROM BBB GROUP BY C,   when BBB has no tuple

  return true;
}

}  // namespace executor
}  // namespace peloton
<commit_msg>Fix a bunch of memory leaks in aggregator.cpp<commit_after>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// aggregator.cpp
//
// Identification: src/backend/executor/aggregator.cpp
//
// Copyright (c) 2015, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "backend/executor/aggregator.h"
#include "backend/common/logger.h"

namespace peloton {
namespace executor {

/*
 * Create an instance of an aggregator for the specified aggregate
 * type, column type, and result type. The object is constructed in
 * memory from the provided memrory pool.
 */
Agg *GetAggInstance(ExpressionType agg_type) {
  Agg *aggregator;

  switch (agg_type) {
    case EXPRESSION_TYPE_AGGREGATE_COUNT:
      aggregator = new CountAgg();
      break;
    case EXPRESSION_TYPE_AGGREGATE_COUNT_STAR:
      aggregator = new CountStarAgg();
      break;
    case EXPRESSION_TYPE_AGGREGATE_SUM:
      aggregator = new SumAgg();
      break;
    case EXPRESSION_TYPE_AGGREGATE_AVG:
      aggregator = new AvgAgg(false);
      break;
    case EXPRESSION_TYPE_AGGREGATE_WEIGHTED_AVG:
      aggregator = new AvgAgg(true);
      break;
    case EXPRESSION_TYPE_AGGREGATE_MIN:
      aggregator = new MinAgg();
      break;
    case EXPRESSION_TYPE_AGGREGATE_MAX:
      aggregator = new MaxAgg();
      break;
    default: {
      std::string message = "Unknown aggregate type "
          + std::to_string(agg_type);
      throw UnknownTypeException(agg_type, message);
    }
  }

  return aggregator;
}

/*
 * Helper method responsible for inserting the results of the aggregation
 * into a new tuple in the output tile group as well as passing through any
 * additional columns from the input tile group.
 * FIXME: need to examine Value's uninlined data problem later.
 */
bool Helper(const planner::AggregateV2Node *node, Agg **aggregates,
            storage::DataTable *output_table, const AbstractTuple *prev_tuple,
            executor::ExecutorContext* econtext) {
  // Ignore null tuples
  if (prev_tuple == nullptr)
    return true;

  auto schema = output_table->GetSchema();
  std::unique_ptr<storage::Tuple> tuple(new storage::Tuple(schema, true));

  /*
   * 1) Construct a vector of aggregated values
   */
  std::vector<Value> aggregate_values;
  auto& aggregate_terms = node->GetUniqueAggTerms();
  for (oid_t column_itr = 0; column_itr < aggregate_terms.size();
      column_itr++) {
    if (aggregates[column_itr] != nullptr) {
      Value final_val = aggregates[column_itr]->Finalize();
      aggregate_values.push_back(final_val);
    }
  }

  /*
   * 2) Evaluate filter predicate;
   * if fail, just return
   */
  std::unique_ptr<expression::ContainerTuple<std::vector<Value>> > aggref_tuple(
      new expression::ContainerTuple<std::vector<Value>>(&aggregate_values));

  auto predicate = node->GetPredicate();
  if (nullptr != predicate
      && predicate->Evaluate(prev_tuple, aggref_tuple.get(), econtext).IsFalse()) {
    return true;  // Qual fails, do nothing
  }

  /*
   * 3) Construct the tuple to insert using projectInfo
   */
  node->GetProjectInfo()->Evaluate(tuple.get(), prev_tuple, aggref_tuple.get(),
                                   econtext);

  LOG_INFO("Tuple to Output :");
  std::cout << "GROUP TUPLE :: " << *(tuple.get());

  auto location = output_table->InsertTuple(econtext->GetTransaction(),
                                            tuple.get());
  if (location.block == INVALID_OID) {
    LOG_ERROR("Failed to insert tuple \n");
    return false;
  }

  return true;
}

//===--------------------------------------------------------------------===//
// Specialization of an Aggregator that uses a hash map to aggregate
// tuples from the input table, i.e. it does not expect the input
// table to be sorted on the group by key.
//===--------------------------------------------------------------------===//

template<>
Aggregator<PlanNodeType::PLAN_NODE_TYPE_HASHAGGREGATE>::Aggregator(
    const planner::AggregateV2Node *node, storage::DataTable *output_table,
    executor::ExecutorContext* econtext)
    : node(node),
      output_table(output_table),
      executor_context(econtext) {

  group_by_key_values.resize(node->GetGroupbyColIds().size(),
                             ValueFactory::GetNullValue());

}

template<>
Aggregator<PlanNodeType::PLAN_NODE_TYPE_HASHAGGREGATE>::~Aggregator() {

}

template<>
bool Aggregator<PlanNodeType::PLAN_NODE_TYPE_HASHAGGREGATE>::Advance(
    AbstractTuple *cur_tuple, AbstractTuple *prev_tuple __attribute__((unused)),
    size_t num_columns) {

  AggregateList *aggregate_list;

  // Configure a group-by-key and search for the required group.
  for (oid_t column_itr = 0; column_itr < node->GetGroupbyColIds().size();
      column_itr++) {
    Value cur_tuple_val = cur_tuple->GetValue(
        node->GetGroupbyColIds()[column_itr]);
    group_by_key_values[column_itr] = cur_tuple_val;
  }

  auto map_itr = aggregates_map.find(group_by_key_values);

// Group not found. Make a new entry in the hash for this new group.
  if (map_itr == aggregates_map.end()) {
    LOG_INFO("Group-by key not found. Start a new group.");
    // Allocate new aggregate list
    aggregate_list = new AggregateList();
    aggregate_list->aggregates = new Agg *[node->GetUniqueAggTerms().size()];
    // Make a deep copy of the first tuple we meet
    for (size_t col_id = 0; col_id < num_columns; col_id++) {
      aggregate_list->first_tuple_values.push_back(
          ValueFactory::Clone(cur_tuple->GetValue(col_id)));
    };

    for (oid_t column_itr = 0; column_itr < node->GetUniqueAggTerms().size();
        column_itr++) {
      aggregate_list->aggregates[column_itr] = GetAggInstance(
          node->GetUniqueAggTerms()[column_itr].first);
    }

    aggregates_map.insert(
        HashAggregateMapType::value_type(group_by_key_values, aggregate_list));
  }
// Otherwise, the list is the second item of the pair.
  else {
    aggregate_list = map_itr->second;
  }

// Update the aggregation calculation
  for (oid_t aggno = 0; aggno < node->GetUniqueAggTerms().size(); aggno++) {
    Value value = node->GetUniqueAggTerms()[aggno].second->Evaluate(
        cur_tuple, nullptr, this->executor_context);
    aggregate_list->aggregates[aggno]->Advance(value);
  }

  return true;
}

template<>
bool Aggregator<PlanNodeType::PLAN_NODE_TYPE_HASHAGGREGATE>::Finalize(
    AbstractTuple *prev_tuple __attribute__((unused))) {
  for (auto entry : aggregates_map) {
    // Construct a container for the first tuple
    expression::ContainerTuple<std::vector<Value>> first_tuple(&entry.second->first_tuple_values);
    if (Helper(node, entry.second->aggregates, output_table,
               &first_tuple, this->executor_context) == false) {
      return false;
    }

    // Clean up allocated storage
    for(size_t aggno = 0; aggno < node->GetUniqueAggTerms().size(); aggno++){
      delete entry.second->aggregates[aggno];
    }
    delete [] entry.second->aggregates;

    for(auto &v : entry.second->first_tuple_values){
      v.FreeUninlinedData();
    }
    delete entry.second;
  }

// TODO: if no record exists in input_table, we have to output a null record
// only when it doesn't have GROUP BY. See difference of these cases:
//   SELECT SUM(A) FROM BBB ,   when BBB has no tuple
//   SELECT SUM(A) FROM BBB GROUP BY C,   when BBB has no tuple

  return true;
}

//===--------------------------------------------------------------------===//
// Specialization of an aggregator that expects the input table to be
// sorted on the group by key.
//===--------------------------------------------------------------------===//
template<>
Aggregator<PlanNodeType::PLAN_NODE_TYPE_AGGREGATE>::Aggregator(
    const planner::AggregateV2Node *node, storage::DataTable *output_table,
    executor::ExecutorContext* econtext)
    : node(node),
      output_table(output_table),
      executor_context(econtext) {

  group_by_columns = node->GetGroupbyColIds();

// Create aggregators and initialize
  aggregate_terms = node->GetUniqueAggTerms();
  aggregates = new Agg *[aggregate_terms.size()];
  ::memset(aggregates, 0, sizeof(Agg *) * aggregate_terms.size());
}

template<>
Aggregator<PlanNodeType::PLAN_NODE_TYPE_AGGREGATE>::~Aggregator() {
// Clean up aggregators
  for (oid_t column_itr = 0; column_itr < aggregate_terms.size();
      column_itr++) {
    delete aggregates[column_itr];
  }
  delete[] aggregates;
}

template<>
bool Aggregator<PlanNodeType::PLAN_NODE_TYPE_AGGREGATE>::Advance(
    AbstractTuple *cur_tuple, AbstractTuple *prev_tuple,
    size_t __attribute__((unused))) {
  bool start_new_agg = false;

// Check if we are starting a new aggregate tuple
  if (prev_tuple == nullptr) {
    LOG_INFO("Prev tuple is nullptr!");
    start_new_agg = true;
  } else {
    // Compare group by columns
    for (oid_t column_itr = 0; column_itr < group_by_columns.size();
        column_itr++) {
      Value lval = cur_tuple->GetValue(group_by_columns[column_itr]);
      Value rval = prev_tuple->GetValue(group_by_columns[column_itr]);
      bool not_equal = lval.OpNotEquals(rval).IsTrue();

      if (not_equal) {
        LOG_INFO("Group-by columns changed.");
        start_new_agg = true;
        break;
      }
    }
  }

// If we have started a new aggregate tuple
  if (start_new_agg) {
    LOG_INFO("Started a new group!");

    if (Helper(node, aggregates, output_table, prev_tuple,
               this->executor_context) ==
    false) {
      return false;
    }

    // Create aggregate
    for (oid_t column_itr = 0; column_itr < aggregate_terms.size();
        column_itr++) {
      // Clean up previous aggregate
      delete aggregates[column_itr];
      aggregates[column_itr] = GetAggInstance(
          aggregate_terms[column_itr].first);
    }
  }

// Update the aggregation calculation
  for (oid_t column_itr = 0; column_itr < aggregate_terms.size();
      column_itr++) {
    Value value = aggregate_terms[column_itr].second->Evaluate(
        cur_tuple, nullptr, this->executor_context);
    aggregates[column_itr]->Advance(value);
  }

  return true;
}

template<>
bool Aggregator<PlanNodeType::PLAN_NODE_TYPE_AGGREGATE>::Finalize(
    AbstractTuple *prev_tuple) {
  if (Helper(node, aggregates, output_table, prev_tuple,
             this->executor_context) ==
             false) {
    return false;
  }

// TODO: if no record exists in input_table, we have to output a null record
// only when it doesn't have GROUP BY. See difference of these cases:
//   SELECT SUM(A) FROM BBB ,   when BBB has no tuple
//   SELECT SUM(A) FROM BBB GROUP BY C,   when BBB has no tuple

  return true;
}

}  // namespace executor
}  // namespace peloton
<|endoftext|>


<commit_before>#include "chunk_allocator.h"
#include "chunk.h"

#include <gflags/gflags.h>

DECLARE_int32(threads);

bool chunk_allocator::finalizer::operator()(chunk *chunk) {
    if (!chunk)
        return true;
    chunk->finalize();
    return false;
}

chunk_allocator::chunk_allocator()  :
    current_(0), finalizer_() {
    new_chunk();
    finalize_pool_ = new thread_pool<chunk*, finalizer>(FLAGS_threads, finalizer_);
}

unsigned char *chunk_allocator::alloc(size_t len) {
    assert(len < kChunkSpace);
    if ((current_->size + len) > kChunkSpace)
        new_chunk();
    unsigned char *out = current_->data + current_->size;
    current_->size += len;
    return out;
}

static chunk *alloc_chunk() {
    void *p;
    if (posix_memalign(&p, kChunkSize, kChunkSize) != 0)
        return NULL;
    return new(p) chunk;
};

void chunk_allocator::new_chunk()  {
    if (current_)
        finalize_pool_->queue(current_);
    current_ = alloc_chunk();
    chunks_.push_back(current_);
}

void chunk_allocator::finalize()  {
    finalize_pool_->queue(current_);
    for (int i = 0; i < FLAGS_threads; i++)
        finalize_pool_->queue(NULL);
    delete finalize_pool_;
    finalize_pool_ = NULL;
}

void chunk_allocator::skip_chunk() {
    current_ = 0;
    new_chunk();
}
<commit_msg>Don't leave around finalizer threads when loading the index.<commit_after>#include "chunk_allocator.h"
#include "chunk.h"

#include <gflags/gflags.h>

DECLARE_int32(threads);

bool chunk_allocator::finalizer::operator()(chunk *chunk) {
    if (!chunk)
        return true;
    chunk->finalize();
    return false;
}

chunk_allocator::chunk_allocator()  :
    current_(0), finalizer_(), finalize_pool_(0) {
    new_chunk();
}

unsigned char *chunk_allocator::alloc(size_t len) {
    assert(len < kChunkSpace);
    if ((current_->size + len) > kChunkSpace)
        new_chunk();
    unsigned char *out = current_->data + current_->size;
    current_->size += len;
    return out;
}

static chunk *alloc_chunk() {
    void *p;
    if (posix_memalign(&p, kChunkSize, kChunkSize) != 0)
        return NULL;
    return new(p) chunk;
};

void chunk_allocator::new_chunk()  {
    if (current_) {
        if (!finalize_pool_) {
            finalize_pool_ = new thread_pool<chunk*, finalizer>(FLAGS_threads, finalizer_);
        }
        finalize_pool_->queue(current_);
    }
    current_ = alloc_chunk();
    chunks_.push_back(current_);
}

void chunk_allocator::finalize()  {
    if (!finalize_pool_)
        return;
    finalize_pool_->queue(current_);
    for (int i = 0; i < FLAGS_threads; i++)
        finalize_pool_->queue(NULL);
    delete finalize_pool_;
    finalize_pool_ = NULL;
}

void chunk_allocator::skip_chunk() {
    current_ = 0;
    new_chunk();
}
<|endoftext|>