<commit_before>/* Copyright (c) 2010-2012, Revori Contributors

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

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>

#include <readline/readline.h>
#include <readline/history.h>

namespace {

enum Request {
  Execute,
  Complete
};

enum Response {
  RowSet,
  NewDatabase,
  CopySuccess,
  Success,
  Error
};

enum RowSetFlag {
  InsertedRow,
  DeletedRow,
  End,
  Item
};

class Buffer {
 public:
  Buffer(int capacity):
    array(static_cast<char*>(malloc(capacity))),
    capacity(capacity),
    position(0),
    limit(0)
  { }

  ~Buffer() {
    if (array) free(array);
  }

  char* array;
  int capacity;
  int position;
  int limit;
};

class Context {
 public:
  Context():
    buffer(8 * 1024),
    databaseName(0),
    socket(-1),
    completionCount(-1),
    trouble(false),
    exit(false),
    copying(false)
  { }

  ~Context() {
    if (databaseName) {
      free(databaseName);
    }
  }

  Buffer buffer;
  char* databaseName;
  int socket;
  int completionCount;
  bool trouble;
  bool exit;
  bool copying;
};

Context* globalContext = 0;

int
min(int a, int b)
{
  return a > b ? b : a;
}

int
connect(const char* host, int port)
{
  addrinfo hints;
  memset(&hints, 0, sizeof(addrinfo));
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;

  addrinfo* result;
  int r = getaddrinfo(host, 0, &hints, &result);
  if (r != 0) {
    fprintf(stderr, "unable to resolve host %s: %s\n", host, gai_strerror(r));
    return -1;
  }

  sockaddr_in address;
  memset(&address, 0, sizeof(sockaddr_in));
  address.sin_family = AF_INET;
  address.sin_port = htons(port);
  address.sin_addr = reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr;

  freeaddrinfo(result);

  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (socket < 0) {
    perror("unable to open socket");
    return -1;
  }

  r = connect(socket, reinterpret_cast<sockaddr*>(&address),
              sizeof(sockaddr_in));
  if (r != 0) {
    perror("unable to connect");
    return -1;
  }

  return socket;
}

bool
flush(Context* context)
{
  int r = write
    (context->socket, context->buffer.array, context->buffer.position);
  if (r != context->buffer.position) {
    perror("\nunable to write");
    context->trouble = true;
    return false;
  }
  context->buffer.position = 0;
  return true;
}

int
writeBytes(Context* context, const char* src, int count)
{
  int total = 0;
  while (total < count) {
    if (context->buffer.limit == context->buffer.position) {
      if (not flush(context)) {
        return -1;
      }
    }

    int c = min
      (count - total, context->buffer.limit - context->buffer.position);
    memcpy(context->buffer.array + context->buffer.position, src + total, c);
    context->buffer.position += c;
    total += c;
  }
  return total;
}

bool
writeByte(Context* context, int v)
{
  char src[] = { static_cast<char>(v) };
  return writeBytes(context, src, 1) == 1;
}

bool
writeInteger(Context* context, int v)
{
  char src[] = { static_cast<char>((v >> 24) & 0xFF),
                 static_cast<char>((v >> 16) & 0xFF),
                 static_cast<char>((v >>  8) & 0xFF),
                 static_cast<char>((v      ) & 0xFF) };
  return writeBytes(context, src, 4) == 4;
}

bool
writeString(Context* context, const char* s, int length)
{
  if (writeInteger(context, length)) {
    return writeBytes(context, s, length) == length;
  } else {
    return false;
  }
}

int
readBytes(Context* context, char* dst, int count)
{
  int total = 0;
  while (total < count) {
    if (context->buffer.limit == context->buffer.position) {
      context->buffer.position = 0;
      int r = read
        (context->socket, context->buffer.array, context->buffer.capacity);
      if (r == 0) {
        fprintf(stderr, "\nunexpected end of stream from server\n");
        context->trouble = true;
        context->buffer.limit = 0;
        return -1;
      } else if (r < 0) {
        perror("\nunable to read");
        context->trouble = true;
        context->buffer.limit = 0;
        return -1;
      }
      context->buffer.limit = r;
    }

    int c = min
      (count - total, context->buffer.limit - context->buffer.position);
    memcpy(dst + total, context->buffer.array + context->buffer.position, c);
    context->buffer.position += c;
    total += c;
  }
  return total;
}

int
readByte(Context* context)
{
  char dst[1];
  int r = readBytes(context, dst, 1);
  return r < 1 ? -1 : dst[0];
}

int
readInteger(Context* context)
{
  char dst[4];
  int r = readBytes(context, dst, 4);
  return r < 4 ? -1 : (((dst[0] & 0xFF) << 24) |
                       ((dst[1] & 0xFF) << 16) |
                       ((dst[2] & 0xFF) <<  8) |
                       ((dst[3] & 0xFF)      ));
}

char*
readString(Context* context)
{
  int length = readInteger(context);
  if (length < 0) {
    return 0;
  }

  char* string = static_cast<char*>(malloc(length + 1));
  if (string == 0) {
    fprintf(stderr, "\nunable to allocate memory\n");
    context->trouble = true;
    return 0;
  }

  int count = readBytes(context, string, length);
  if (count != length) {
    free(string);
    return 0;
  }

  string[length] = 0;

  return string;
}

int
startCompletion(Context* context, const char* text)
{
  context->buffer.position = 0;
  context->buffer.limit = context->buffer.capacity;

  if (not writeByte(context, Complete)) {
    return -1;
  }

  if (not writeString(context, text, strlen(text))) {
    return -1;
  }

  if (not flush(context)) {
    return -1;
  }

  context->buffer.limit = 0;

  int result = readByte(context);
  switch (result) {
  case -1:
    break;

  case Success: {
    return readInteger(context);
  } break;

  case Error: {
    char* message = readString(context);
    if (message == 0) {
      return -1;
    }

    free(message);
  } break;

  default:
    fprintf(stderr, "\nunexpected result from server: %d\n", result);
    context->trouble = true;
    break;
  }

  return -1;
}

char*
completionGenerator(const char*, int state)
{
  Context* context = globalContext;

  if (context->trouble) {
    return 0;
  }

  if (state == 0) {
    context->completionCount = startCompletion(context, rl_line_buffer);
  }

  if (context->completionCount <= 0) {
    return 0;
  } else {
    -- context->completionCount;

    return readString(context);
  }
}

char*
removeEdgeWhitespace(char* s)
{
  while (isspace(*s)) ++s;

  if (*s == 0) return s;

  char* p = s;
  char* lastNonSpace = p;
  while (*p) {
    if (not isspace(*p)) {
      lastNonSpace = p;
    }
    ++ p;
  }

  lastNonSpace[1] = 0;

  return s;
}

void
execute(Context* context, const char* command)
{
  if (strcmp(command, "exit") == 0
      || strcmp(command, "quit") == 0)
  {
    context->exit = true;
    return;
  }

  if (context->trouble) {
    return;
  }

  if (not context->copying) {
    context->buffer.position = 0;
    context->buffer.limit = context->buffer.capacity;
  }

  if (not writeByte(context, Execute)) {
    return;
  }

  if (not writeString(context, command, strlen(command))) {
    return;
  }

  if (context->copying && strcmp(command, "\\.") == 0) {
    if (not flush(context)) {
      return;
    }
    context->copying = false;
  }

  if (context->copying) {
    return;
  }

  if (not flush(context)) {
    return;
  }

  context->buffer.limit = 0;

  int result = readByte(context);
  switch (result) {
  case -1:
    break;

  case NewDatabase: {
    if (context->databaseName) {
      free(context->databaseName);
    }

    context->databaseName = readString(context);
    if (context->databaseName == 0) {
      return;
    }

    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stdout, "%s\n", message);

    free(message);
  } break;

  case CopySuccess: {
    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stdout, "%s\n", message);

    free(message);

    context->buffer.position = 0;
    context->buffer.limit = context->buffer.capacity;

    context->copying = true;
  } break;

  case Success: {
    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stdout, "%s\n", message);

    free(message);
  } break;

  case RowSet: {
    bool done = false;
    bool sawRow = false;
    while (not done) {
      int flag = readByte(context);
      switch (flag) {
      case -1:
        return;

      case InsertedRow:
        sawRow = true;
        fprintf(stdout, "\n inserted:");
        break;

      case DeletedRow:
        sawRow = true;
        fprintf(stdout, "\n  deleted:");
        break;

      case Item: {
        char* item = readString(context);
        if (item == 0) {
          return;
        }

        fprintf(stdout, " %s", item);

        free(item);
      } break;

      case End:
        if (not sawRow) {
          fprintf(stdout, "\n no matching rows found");
        }
        done = true;
        fprintf(stdout, "\n");
        break;

      default:
        fprintf(stderr, "\nunexpected flag from server: %d\n", flag);
        context->trouble = true;
        return;
      }
    }
  } break;

  case Error: {
    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stderr, "error: %s\n", message);

    free(message);
  } break;

  default:
    fprintf(stderr, "\nunexpected result from server: %d\n", result);
    context->trouble = true;
    break;
  }
}

void
usage(const char* name)
{
  fprintf(stderr, "usage: %s [--batch] <hostname> <port> [<database>]\n",
          name);
}

} // namespace

int
main(int argumentCount, const char** arguments)
{
  bool interactive = true;
  const char* hostname = 0;
  int port = -1;
  const char* database = 0;
  for (int i = 1; i < argumentCount; ++i) {
    if (strcmp("--batch", arguments[i]) == 0) {
      interactive = false;
    } else if (hostname == 0) {
      hostname = arguments[i];
    } else if (port == -1) {
      port = atoi(arguments[i]);
    } else if (database == 0) {
      database = arguments[i];
    } else {
      usage(arguments[0]);
      return -1;
    }
  }

  if (hostname == 0 or port == -1) {
    usage(arguments[0]);
    return -1;
  }

  Context context;
  globalContext = &context;

  if (context.buffer.array == 0) {
    fprintf(stderr, "\nunable to allocate memory\n");
    return -1;
  }

  context.socket = connect(hostname, port);
  if (context.socket < 0) {
    return -1;
  }

  if (database) {
    const int BufferSize = 256;
    char buffer[BufferSize];
    snprintf(buffer, BufferSize, "use database %s", database);
    execute(&context, buffer);

    if (context.trouble) {
      return -1;
    }
  }

  if (interactive) {
    fprintf(stdout, "\nWelcome to the DBMS SQL client interface.  "
            "Type \"help\" to get started.\n");

    rl_readline_name = "DBMSClient";

    rl_completion_entry_function = completionGenerator;

    while (not (context.trouble or context.exit)) {
      char* line;
      if (context.databaseName) {
        int length = strlen(context.databaseName) + 4;
        char* prompt = static_cast<char*>(malloc(length));
        if (prompt == 0) {
          fprintf(stderr, "\nunable to allocate memory\n");
          return -1;
        }

        snprintf(prompt, length, "%s > ", context.databaseName);
        line = readline(prompt);
        free(prompt);
      } else {
        line = readline("> ");
      }

      if (line == 0) {
        fprintf(stdout, "\n");
        break;
      }

      if (context.copying) {
        execute(&context, line);
      } else {
        char* s = removeEdgeWhitespace(line);
        if (*s) {
          add_history(s);

          execute(&context, s);
          fprintf(stdout, "\n");
        }
      }

      free(line);
    }
  } else {
    const int BufferSize = 8096;
    char buffer[BufferSize];
    int i = 0;

    while (true) {
      int c = fgetc(stdin);
      switch (c) {
      case EOF:
        return 0;

      case '\n':
        buffer[i] = 0;
        execute(&context, buffer);
        i = 0;
        break;

      default:
        if (i < BufferSize - 1) {
          buffer[i++] = c;
        } else {
          fprintf(stderr, "buffer overflow\n");
          return -1;
        }
        break;
      }
    }
  }

  close(context.socket);

  return context.trouble ? -1 : 0;
}
<commit_msg>rename DBMS -> Revori in client<commit_after>/* Copyright (c) 2010-2012, Revori Contributors

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

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>

#include <readline/readline.h>
#include <readline/history.h>

namespace {

enum Request {
  Execute,
  Complete
};

enum Response {
  RowSet,
  NewDatabase,
  CopySuccess,
  Success,
  Error
};

enum RowSetFlag {
  InsertedRow,
  DeletedRow,
  End,
  Item
};

class Buffer {
 public:
  Buffer(int capacity):
    array(static_cast<char*>(malloc(capacity))),
    capacity(capacity),
    position(0),
    limit(0)
  { }

  ~Buffer() {
    if (array) free(array);
  }

  char* array;
  int capacity;
  int position;
  int limit;
};

class Context {
 public:
  Context():
    buffer(8 * 1024),
    databaseName(0),
    socket(-1),
    completionCount(-1),
    trouble(false),
    exit(false),
    copying(false)
  { }

  ~Context() {
    if (databaseName) {
      free(databaseName);
    }
  }

  Buffer buffer;
  char* databaseName;
  int socket;
  int completionCount;
  bool trouble;
  bool exit;
  bool copying;
};

Context* globalContext = 0;

int
min(int a, int b)
{
  return a > b ? b : a;
}

int
connect(const char* host, int port)
{
  addrinfo hints;
  memset(&hints, 0, sizeof(addrinfo));
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;

  addrinfo* result;
  int r = getaddrinfo(host, 0, &hints, &result);
  if (r != 0) {
    fprintf(stderr, "unable to resolve host %s: %s\n", host, gai_strerror(r));
    return -1;
  }

  sockaddr_in address;
  memset(&address, 0, sizeof(sockaddr_in));
  address.sin_family = AF_INET;
  address.sin_port = htons(port);
  address.sin_addr = reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr;

  freeaddrinfo(result);

  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (socket < 0) {
    perror("unable to open socket");
    return -1;
  }

  r = connect(socket, reinterpret_cast<sockaddr*>(&address),
              sizeof(sockaddr_in));
  if (r != 0) {
    perror("unable to connect");
    return -1;
  }

  return socket;
}

bool
flush(Context* context)
{
  int r = write
    (context->socket, context->buffer.array, context->buffer.position);
  if (r != context->buffer.position) {
    perror("\nunable to write");
    context->trouble = true;
    return false;
  }
  context->buffer.position = 0;
  return true;
}

int
writeBytes(Context* context, const char* src, int count)
{
  int total = 0;
  while (total < count) {
    if (context->buffer.limit == context->buffer.position) {
      if (not flush(context)) {
        return -1;
      }
    }

    int c = min
      (count - total, context->buffer.limit - context->buffer.position);
    memcpy(context->buffer.array + context->buffer.position, src + total, c);
    context->buffer.position += c;
    total += c;
  }
  return total;
}

bool
writeByte(Context* context, int v)
{
  char src[] = { static_cast<char>(v) };
  return writeBytes(context, src, 1) == 1;
}

bool
writeInteger(Context* context, int v)
{
  char src[] = { static_cast<char>((v >> 24) & 0xFF),
                 static_cast<char>((v >> 16) & 0xFF),
                 static_cast<char>((v >>  8) & 0xFF),
                 static_cast<char>((v      ) & 0xFF) };
  return writeBytes(context, src, 4) == 4;
}

bool
writeString(Context* context, const char* s, int length)
{
  if (writeInteger(context, length)) {
    return writeBytes(context, s, length) == length;
  } else {
    return false;
  }
}

int
readBytes(Context* context, char* dst, int count)
{
  int total = 0;
  while (total < count) {
    if (context->buffer.limit == context->buffer.position) {
      context->buffer.position = 0;
      int r = read
        (context->socket, context->buffer.array, context->buffer.capacity);
      if (r == 0) {
        fprintf(stderr, "\nunexpected end of stream from server\n");
        context->trouble = true;
        context->buffer.limit = 0;
        return -1;
      } else if (r < 0) {
        perror("\nunable to read");
        context->trouble = true;
        context->buffer.limit = 0;
        return -1;
      }
      context->buffer.limit = r;
    }

    int c = min
      (count - total, context->buffer.limit - context->buffer.position);
    memcpy(dst + total, context->buffer.array + context->buffer.position, c);
    context->buffer.position += c;
    total += c;
  }
  return total;
}

int
readByte(Context* context)
{
  char dst[1];
  int r = readBytes(context, dst, 1);
  return r < 1 ? -1 : dst[0];
}

int
readInteger(Context* context)
{
  char dst[4];
  int r = readBytes(context, dst, 4);
  return r < 4 ? -1 : (((dst[0] & 0xFF) << 24) |
                       ((dst[1] & 0xFF) << 16) |
                       ((dst[2] & 0xFF) <<  8) |
                       ((dst[3] & 0xFF)      ));
}

char*
readString(Context* context)
{
  int length = readInteger(context);
  if (length < 0) {
    return 0;
  }

  char* string = static_cast<char*>(malloc(length + 1));
  if (string == 0) {
    fprintf(stderr, "\nunable to allocate memory\n");
    context->trouble = true;
    return 0;
  }

  int count = readBytes(context, string, length);
  if (count != length) {
    free(string);
    return 0;
  }

  string[length] = 0;

  return string;
}

int
startCompletion(Context* context, const char* text)
{
  context->buffer.position = 0;
  context->buffer.limit = context->buffer.capacity;

  if (not writeByte(context, Complete)) {
    return -1;
  }

  if (not writeString(context, text, strlen(text))) {
    return -1;
  }

  if (not flush(context)) {
    return -1;
  }

  context->buffer.limit = 0;

  int result = readByte(context);
  switch (result) {
  case -1:
    break;

  case Success: {
    return readInteger(context);
  } break;

  case Error: {
    char* message = readString(context);
    if (message == 0) {
      return -1;
    }

    free(message);
  } break;

  default:
    fprintf(stderr, "\nunexpected result from server: %d\n", result);
    context->trouble = true;
    break;
  }

  return -1;
}

char*
completionGenerator(const char*, int state)
{
  Context* context = globalContext;

  if (context->trouble) {
    return 0;
  }

  if (state == 0) {
    context->completionCount = startCompletion(context, rl_line_buffer);
  }

  if (context->completionCount <= 0) {
    return 0;
  } else {
    -- context->completionCount;

    return readString(context);
  }
}

char*
removeEdgeWhitespace(char* s)
{
  while (isspace(*s)) ++s;

  if (*s == 0) return s;

  char* p = s;
  char* lastNonSpace = p;
  while (*p) {
    if (not isspace(*p)) {
      lastNonSpace = p;
    }
    ++ p;
  }

  lastNonSpace[1] = 0;

  return s;
}

void
execute(Context* context, const char* command)
{
  if (strcmp(command, "exit") == 0
      || strcmp(command, "quit") == 0)
  {
    context->exit = true;
    return;
  }

  if (context->trouble) {
    return;
  }

  if (not context->copying) {
    context->buffer.position = 0;
    context->buffer.limit = context->buffer.capacity;
  }

  if (not writeByte(context, Execute)) {
    return;
  }

  if (not writeString(context, command, strlen(command))) {
    return;
  }

  if (context->copying && strcmp(command, "\\.") == 0) {
    if (not flush(context)) {
      return;
    }
    context->copying = false;
  }

  if (context->copying) {
    return;
  }

  if (not flush(context)) {
    return;
  }

  context->buffer.limit = 0;

  int result = readByte(context);
  switch (result) {
  case -1:
    break;

  case NewDatabase: {
    if (context->databaseName) {
      free(context->databaseName);
    }

    context->databaseName = readString(context);
    if (context->databaseName == 0) {
      return;
    }

    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stdout, "%s\n", message);

    free(message);
  } break;

  case CopySuccess: {
    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stdout, "%s\n", message);

    free(message);

    context->buffer.position = 0;
    context->buffer.limit = context->buffer.capacity;

    context->copying = true;
  } break;

  case Success: {
    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stdout, "%s\n", message);

    free(message);
  } break;

  case RowSet: {
    bool done = false;
    bool sawRow = false;
    while (not done) {
      int flag = readByte(context);
      switch (flag) {
      case -1:
        return;

      case InsertedRow:
        sawRow = true;
        fprintf(stdout, "\n inserted:");
        break;

      case DeletedRow:
        sawRow = true;
        fprintf(stdout, "\n  deleted:");
        break;

      case Item: {
        char* item = readString(context);
        if (item == 0) {
          return;
        }

        fprintf(stdout, " %s", item);

        free(item);
      } break;

      case End:
        if (not sawRow) {
          fprintf(stdout, "\n no matching rows found");
        }
        done = true;
        fprintf(stdout, "\n");
        break;

      default:
        fprintf(stderr, "\nunexpected flag from server: %d\n", flag);
        context->trouble = true;
        return;
      }
    }
  } break;

  case Error: {
    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stderr, "error: %s\n", message);

    free(message);
  } break;

  default:
    fprintf(stderr, "\nunexpected result from server: %d\n", result);
    context->trouble = true;
    break;
  }
}

void
usage(const char* name)
{
  fprintf(stderr, "usage: %s [--batch] <hostname> <port> [<database>]\n",
          name);
}

} // namespace

int
main(int argumentCount, const char** arguments)
{
  bool interactive = true;
  const char* hostname = 0;
  int port = -1;
  const char* database = 0;
  for (int i = 1; i < argumentCount; ++i) {
    if (strcmp("--batch", arguments[i]) == 0) {
      interactive = false;
    } else if (hostname == 0) {
      hostname = arguments[i];
    } else if (port == -1) {
      port = atoi(arguments[i]);
    } else if (database == 0) {
      database = arguments[i];
    } else {
      usage(arguments[0]);
      return -1;
    }
  }

  if (hostname == 0 or port == -1) {
    usage(arguments[0]);
    return -1;
  }

  Context context;
  globalContext = &context;

  if (context.buffer.array == 0) {
    fprintf(stderr, "\nunable to allocate memory\n");
    return -1;
  }

  context.socket = connect(hostname, port);
  if (context.socket < 0) {
    return -1;
  }

  if (database) {
    const int BufferSize = 256;
    char buffer[BufferSize];
    snprintf(buffer, BufferSize, "use database %s", database);
    execute(&context, buffer);

    if (context.trouble) {
      return -1;
    }
  }

  if (interactive) {
    fprintf(stdout, "\nWelcome to the Revori SQL client interface.  "
            "Type \"help\" to get started.\n");

    rl_readline_name = "RevoriClient";

    rl_completion_entry_function = completionGenerator;

    while (not (context.trouble or context.exit)) {
      char* line;
      if (context.databaseName) {
        int length = strlen(context.databaseName) + 4;
        char* prompt = static_cast<char*>(malloc(length));
        if (prompt == 0) {
          fprintf(stderr, "\nunable to allocate memory\n");
          return -1;
        }

        snprintf(prompt, length, "%s > ", context.databaseName);
        line = readline(prompt);
        free(prompt);
      } else {
        line = readline("> ");
      }

      if (line == 0) {
        fprintf(stdout, "\n");
        break;
      }

      if (context.copying) {
        execute(&context, line);
      } else {
        char* s = removeEdgeWhitespace(line);
        if (*s) {
          add_history(s);

          execute(&context, s);
          fprintf(stdout, "\n");
        }
      }

      free(line);
    }
  } else {
    const int BufferSize = 8096;
    char buffer[BufferSize];
    int i = 0;

    while (true) {
      int c = fgetc(stdin);
      switch (c) {
      case EOF:
        return 0;

      case '\n':
        buffer[i] = 0;
        execute(&context, buffer);
        i = 0;
        break;

      default:
        if (i < BufferSize - 1) {
          buffer[i++] = c;
        } else {
          fprintf(stderr, "buffer overflow\n");
          return -1;
        }
        break;
      }
    }
  }

  close(context.socket);

  return context.trouble ? -1 : 0;
}
<|endoftext|>


<commit_before>#include <utils.h>
#include "command.h"
#include "../CommandHandler.h"
#include "../OptionParser.h"

/* full name of the command */
CMDNAME("xp");
/* description of the command */
CMDDESCR("query experience information");
/* command usage synopsis */
CMDUSAGE("$xp [-i] NUM");

#define MAX_XP 0xBEBC200

static std::string xptolvl(int x);
static std::string lvltoxp(int x);

/* xp: query experience information */
std::string CommandHandler::xp(struct cmdinfo *c)
{
	bool inv;
	int x;
	std::string lvl;

	int opt;
	OptionParser op(c->fullCmd, "i");
	static struct OptionParser::option long_opts[] = {
		{ "help", NO_ARG, 'h' },
		{ "inverse", NO_ARG, 'i' },
		{ 0, 0, 0 }
	};

	inv = false;
	while ((opt = op.getopt_long(long_opts)) != EOF) {
		switch (opt) {
		case 'h':
			return HELPMSG(CMDNAME, CMDUSAGE, CMDDESCR);
		case 'i':
			inv = true;
			break;
		case '?':
			return std::string(op.opterr());
		default:
			return "";
		}
	}

	if (op.optind() == c->fullCmd.length()
			|| (lvl = c->fullCmd.substr(op.optind())).find(' ')
			!= std::string::npos)
		return USAGEMSG(CMDNAME, CMDUSAGE);

	try {
		if ((x = std::stoi(lvl)) < 0)
			return CMDNAME + ": number cannot be negative";
	} catch (std::invalid_argument) {
			return CMDNAME + ": invalid number -- '" + lvl + "'";
	} catch (std::out_of_range) {
			return CMDNAME + ": number too large";
	}

	if (inv) {
		if (x > MAX_XP)
			return CMDNAME + ": xp cannot exceed 200m";
		return "[XP] " + utils::formatInteger(std::to_string(x))
			+ " xp: level " + xptolvl(x);
	}

	if (x < 1 || x > 126)
		return CMDNAME + ": level must be between 1-126";
	return "[XP] level " + std::to_string(x) + ": " + lvltoxp(x) + " xp";
}

/* xptolvl: calculate the level at x xp */
static std::string xptolvl(int x)
{
	int n;

	n = 1;
	x *= 4;
	x += 1;
	while (x >= 0) {
		x -= floor(n + 300 * pow(2, n / 7.0));
		++n;
	}

	return std::to_string(n - 1);
}

/* lvltoxp: return xp required for level x */
static std::string lvltoxp(int x)
{
	int n, res;

	res = 0;
	for (n = 1; n < x; ++n)
		res += floor(n + 300 * pow(2, n / 7.0));
	res = floor(0.25 * res);

	return utils::formatInteger(std::to_string(res));
}
<commit_msg>Fix indentation<commit_after>#include <utils.h>
#include "command.h"
#include "../CommandHandler.h"
#include "../OptionParser.h"

/* full name of the command */
CMDNAME("xp");
/* description of the command */
CMDDESCR("query experience information");
/* command usage synopsis */
CMDUSAGE("$xp [-i] NUM");

#define MAX_XP 0xBEBC200

static std::string xptolvl(int x);
static std::string lvltoxp(int x);

/* xp: query experience information */
std::string CommandHandler::xp(struct cmdinfo *c)
{
	bool inv;
	int x;
	std::string lvl;

	int opt;
	OptionParser op(c->fullCmd, "i");
	static struct OptionParser::option long_opts[] = {
		{ "help", NO_ARG, 'h' },
		{ "inverse", NO_ARG, 'i' },
		{ 0, 0, 0 }
	};

	inv = false;
	while ((opt = op.getopt_long(long_opts)) != EOF) {
		switch (opt) {
		case 'h':
			return HELPMSG(CMDNAME, CMDUSAGE, CMDDESCR);
		case 'i':
			inv = true;
			break;
		case '?':
			return std::string(op.opterr());
		default:
			return "";
		}
	}

	if (op.optind() == c->fullCmd.length()
			|| (lvl = c->fullCmd.substr(op.optind())).find(' ')
			!= std::string::npos)
		return USAGEMSG(CMDNAME, CMDUSAGE);

	try {
		if ((x = std::stoi(lvl)) < 0)
			return CMDNAME + ": number cannot be negative";
	} catch (std::invalid_argument) {
		return CMDNAME + ": invalid number -- '" + lvl + "'";
	} catch (std::out_of_range) {
		return CMDNAME + ": number too large";
	}

	if (inv) {
		if (x > MAX_XP)
			return CMDNAME + ": xp cannot exceed 200m";
		return "[XP] " + utils::formatInteger(std::to_string(x))
			+ " xp: level " + xptolvl(x);
	}

	if (x < 1 || x > 126)
		return CMDNAME + ": level must be between 1-126";
	return "[XP] level " + std::to_string(x) + ": " + lvltoxp(x) + " xp";
}

/* xptolvl: calculate the level at x xp */
static std::string xptolvl(int x)
{
	int n;

	n = 1;
	x *= 4;
	x += 1;
	while (x >= 0) {
		x -= floor(n + 300 * pow(2, n / 7.0));
		++n;
	}

	return std::to_string(n - 1);
}

/* lvltoxp: return xp required for level x */
static std::string lvltoxp(int x)
{
	int n, res;

	res = 0;
	for (n = 1; n < x; ++n)
		res += floor(n + 300 * pow(2, n / 7.0));
	res = floor(0.25 * res);

	return utils::formatInteger(std::to_string(res));
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- interface include --------------------------------------------------------
#include "RequestProcessor.h"

//--- standard modules used ----------------------------------------------------
#include "Socket.h"
#include "StringStream.h"
#include "Registry.h"
#include "Server.h"
#include "ServerUtils.h"
#include "SystemLog.h"
#include "Dbg.h"
// #include "System.h"

//--- c-library modules used ---------------------------------------------------

//--- RequestProcessor ----------------------------------------------------------
RegCacheImpl(RequestProcessor);	// FindRequestProcessor()
RegisterRequestProcessor(RequestProcessor);

RequestProcessor::RequestProcessor(const char *processorName)
	: RegisterableObject(processorName)
	, fServer(0), fErrors()
{
	StartTrace(RequestProcessor.RequestProcessor);
}

void RequestProcessor::Init(Server *server)
{
	StartTrace(RequestProcessor.Init);
	fServer = server;
}

void RequestProcessor::ProcessRequest(Context &ctx)
{
	StartTrace(RequestProcessor.ProcessRequest);
	ctx.SetServer(fServer);
	Socket *socket = ctx.GetSocket();
	iostream *Ios = 0;

	if ( socket != (Socket *) NULL ) {
		ROAnything timeout;
		fServer->Lookup("SocketReadTimeout", timeout);
		socket->SetTimeout(timeout.AsLong(10 * 1000L));
		TraceAny(socket->ClientInfo(), "socket client info");
		Ios = socket->GetStream();
	}

	if ( Ios && socket->IsReadyForReading() ) {
		// disable nagle algorithm
		socket->SetNoDelay();
		DoReadInput(*Ios, ctx);

		KeepConnectionAlive(ctx);

		if ( !(*Ios) ) {
			return;
		}

		if (socket->IsReadyForWriting()) {
			// process this arguments and
			// write the output to the reply
			DoProcessRequest(*Ios, ctx);
			//FIXME: BufferReply mechanism possible
		}
	} else {
		String logMsg("No valid stream from socket: ");
		logMsg << ((socket) ? socket->GetFd() : -1L);
		if ( socket ) {
			logMsg << " (" << socket->ClientInfo()["REMOTE_ADDR"].AsString() << ':' << socket->ClientInfo()["REMOTE_PORT"].AsString() << ')';
		}
		SystemLog::Warning(logMsg);
	}
}

RequestProcessor *RequestProcessor::GetCurrentRequestProcessor(Context &ctx)
{
	String requestProcessor(ctx.Lookup("RequestProcessor", "RequestProcessor"));
	return RequestProcessor::FindRequestProcessor(requestProcessor);
}

void RequestProcessor::ForceConnectionClose(Context &ctx)
{
	ctx.GetTmpStore()["Keep-Alive"] = 0L;
}

bool RequestProcessor::KeepConnectionAlive(Context &ctx)
{
	bool retVal = false;
	StatTrace(RequestProcessor.KeepConnectionAlive, "PersistentConnections:" << (ctx.Lookup("PersistentConnections").AsBool(false) ? "true" : "false"), Storage::Current());
	if ( ctx.Lookup("PersistentConnections").AsBool(false) ) {
		// first check if we already know the result
		ROAnything lookupAny;
		if (ctx.Lookup("Keep-Alive", lookupAny) && !lookupAny.IsNull() ) {
			retVal = lookupAny.AsBool();
		} else {
			// let the current RequestProcessor decide
			retVal = GetCurrentRequestProcessor(ctx)->DoKeepConnectionAlive(ctx);
			ctx.GetTmpStore()["Keep-Alive"] = retVal;
		}
	}
	StatTrace(RequestProcessor.KeepConnectionAlive, "Keep-Alive:" << (retVal ? "true" : "false"), Storage::Current());
	return retVal;
}

bool RequestProcessor::DoKeepConnectionAlive(Context &ctx)
{
	// default is to close connection after request
	return false;
}

void RequestProcessor::RenderProtocolStatus(ostream &os, Context &ctx)
{
	StartTrace(RequestProcessor.RenderProtocolStatus);
	GetCurrentRequestProcessor(ctx)->DoRenderProtocolStatus(os, ctx);
}

void RequestProcessor::Error(ostream &reply, const String &msg, Context &ctx)
{
	StartTrace(RequestProcessor.Error);
	GetCurrentRequestProcessor(ctx)->DoError(reply, msg, ctx);
}

void RequestProcessor::DoReadInput(iostream &Ios, Context &ctx)
{
	// default implementation just
	// import the anything from the
	// socket stream

	Anything args;
	args.Import(Ios);
	StatTraceAny(RequestProcessor.DoReadInput, args, "request arguments", Storage::Current());
	ctx.PushRequest(args);
}

void RequestProcessor::DoProcessRequest(ostream &reply, Context &ctx)
{
	StartTrace(RequestProcessor.DoProcessRequest);
	fServer->ProcessRequest(reply, ctx);
}

void RequestProcessor::DoWriteOutput(iostream &Ios, ostream &reply, Context &ctx)
{
	StartTrace(RequestProcessor.DoWriteOutput);
	// dump the reply object onto the
	// socket stream
	//reply.PrintOn(Ios);
	// flush it in case not everything is
	// already dumped onto the socket
	Ios.flush();
}

void RequestProcessor::DoRenderProtocolStatus(ostream &os, Context &ctx)
{
	// unknown protocol -> no status
}

void RequestProcessor::DoError(ostream &reply, const String &msg, Context &ctx)
{
	// unknown protocol -> no error msg
}
<commit_msg>improved output message in case the stream is not good anymore<commit_after>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- interface include --------------------------------------------------------
#include "RequestProcessor.h"

//--- standard modules used ----------------------------------------------------
#include "Socket.h"
#include "StringStream.h"
#include "Registry.h"
#include "Server.h"
#include "ServerUtils.h"
#include "SystemLog.h"
#include "Dbg.h"
// #include "System.h"

//--- c-library modules used ---------------------------------------------------

//--- RequestProcessor ----------------------------------------------------------
RegCacheImpl(RequestProcessor);	// FindRequestProcessor()
RegisterRequestProcessor(RequestProcessor);

RequestProcessor::RequestProcessor(const char *processorName)
	: RegisterableObject(processorName)
	, fServer(0), fErrors()
{
	StartTrace(RequestProcessor.RequestProcessor);
}

void RequestProcessor::Init(Server *server)
{
	StartTrace(RequestProcessor.Init);
	fServer = server;
}

void RequestProcessor::ProcessRequest(Context &ctx)
{
	StartTrace(RequestProcessor.ProcessRequest);
	ctx.SetServer(fServer);
	Socket *socket = ctx.GetSocket();
	iostream *Ios = 0;

	if ( socket != (Socket *) NULL ) {
		ROAnything timeout;
		fServer->Lookup("SocketReadTimeout", timeout);
		socket->SetTimeout(timeout.AsLong(10 * 1000L));
		TraceAny(socket->ClientInfo(), "socket client info");
		Ios = socket->GetStream();
	}

	if ( Ios && socket->IsReadyForReading() ) {
		// disable nagle algorithm
		socket->SetNoDelay();
		DoReadInput(*Ios, ctx);

		KeepConnectionAlive(ctx);

		if ( !(*Ios) ) {
			return;
		}

		if (socket->IsReadyForWriting()) {
			// process this arguments and
			// write the output to the reply
			DoProcessRequest(*Ios, ctx);
			//FIXME: BufferReply mechanism possible
		}
	} else {
		String logMsg("No valid stream from socket");
		SystemLog::eLogLevel level(SystemLog::eWARNING);
		if ( socket ) {
			logMsg << ", fd:" << ((socket) ? socket->GetFd() : -1L);
			logMsg << ", from " << socket->ClientInfo()["REMOTE_ADDR"].AsString() << ':' << socket->ClientInfo()["REMOTE_PORT"].AsString();
			if ( socket->HadTimeout() ) {
				logMsg << ", had timeout (" << socket->GetTimeout() << "ms)";
				level = SystemLog::eINFO;
			}
		}
		SystemLog::Log(level, logMsg);
	}
}

RequestProcessor *RequestProcessor::GetCurrentRequestProcessor(Context &ctx)
{
	String requestProcessor(ctx.Lookup("RequestProcessor", "RequestProcessor"));
	return RequestProcessor::FindRequestProcessor(requestProcessor);
}

void RequestProcessor::ForceConnectionClose(Context &ctx)
{
	ctx.GetTmpStore()["Keep-Alive"] = 0L;
}

bool RequestProcessor::KeepConnectionAlive(Context &ctx)
{
	bool retVal = false;
	StatTrace(RequestProcessor.KeepConnectionAlive, "PersistentConnections:" << (ctx.Lookup("PersistentConnections").AsBool(false) ? "true" : "false"), Storage::Current());
	if ( ctx.Lookup("PersistentConnections").AsBool(false) ) {
		// first check if we already know the result
		ROAnything lookupAny;
		if (ctx.Lookup("Keep-Alive", lookupAny) && !lookupAny.IsNull() ) {
			retVal = lookupAny.AsBool();
		} else {
			// let the current RequestProcessor decide
			retVal = GetCurrentRequestProcessor(ctx)->DoKeepConnectionAlive(ctx);
			ctx.GetTmpStore()["Keep-Alive"] = retVal;
		}
	}
	StatTrace(RequestProcessor.KeepConnectionAlive, "Keep-Alive:" << (retVal ? "true" : "false"), Storage::Current());
	return retVal;
}

bool RequestProcessor::DoKeepConnectionAlive(Context &ctx)
{
	// default is to close connection after request
	return false;
}

void RequestProcessor::RenderProtocolStatus(ostream &os, Context &ctx)
{
	StartTrace(RequestProcessor.RenderProtocolStatus);
	GetCurrentRequestProcessor(ctx)->DoRenderProtocolStatus(os, ctx);
}

void RequestProcessor::Error(ostream &reply, const String &msg, Context &ctx)
{
	StartTrace(RequestProcessor.Error);
	GetCurrentRequestProcessor(ctx)->DoError(reply, msg, ctx);
}

void RequestProcessor::DoReadInput(iostream &Ios, Context &ctx)
{
	// default implementation just
	// import the anything from the
	// socket stream

	Anything args;
	args.Import(Ios);
	StatTraceAny(RequestProcessor.DoReadInput, args, "request arguments", Storage::Current());
	ctx.PushRequest(args);
}

void RequestProcessor::DoProcessRequest(ostream &reply, Context &ctx)
{
	StartTrace(RequestProcessor.DoProcessRequest);
	fServer->ProcessRequest(reply, ctx);
}

void RequestProcessor::DoWriteOutput(iostream &Ios, ostream &reply, Context &ctx)
{
	StartTrace(RequestProcessor.DoWriteOutput);
	// dump the reply object onto the
	// socket stream
	//reply.PrintOn(Ios);
	// flush it in case not everything is
	// already dumped onto the socket
	Ios.flush();
}

void RequestProcessor::DoRenderProtocolStatus(ostream &os, Context &ctx)
{
	// unknown protocol -> no status
}

void RequestProcessor::DoError(ostream &reply, const String &msg, Context &ctx)
{
	// unknown protocol -> no error msg
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2018, NVIDIA CORPORATION.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/** ---------------------------------------------------------------------------*
 * @brief Operations on GDF columns
 *
 * @file column.cpp
 * ---------------------------------------------------------------------------**/

#include <gdf/gdf.h>
#include <gdf/utils.h>
#include <gdf/errorutils.h>
#include <cuda_runtime_api.h>

// forward decl -- see validops.cu
gdf_error gdf_mask_concat(gdf_valid_type *output_mask,
                          gdf_size_type output_column_length,
                          gdf_valid_type *masks_to_concat[],
                          gdf_size_type *column_lengths,
                          gdf_size_type num_columns);

/** ---------------------------------------------------------------------------*
 * @brief Concatenates multiple gdf_columns into a single, contiguous column,
 * including the validity bitmasks.
 *
 * Note that input columns with nullptr validity masks are treated as if all
 * elements are valid.
 *
 * @param[out] output_column A column whose buffers are already allocated that
 *             will contain the concatenation of the input columns data and
 *             validity bitmasks
 * @Param[in] columns_to_concat[] The columns to concatenate
 * @Param[in] num_columns The number of columns to concatenate
 *
 * @return gdf_error GDF_SUCCESS upon completion; GDF_DATASET_EMPTY if any data
 *         pointer is NULL, GDF_COLUMN_SIZE_MISMATCH if the output column size
 *         != the total size of the input columns; GDF_DTYPE_MISMATCH if the
 *         input columns have different datatypes.
 * ---------------------------------------------------------------------------**/
gdf_error gdf_column_concat(gdf_column *output_column, gdf_column *columns_to_concat[], int num_columns)
{

  if (nullptr == columns_to_concat){
    return GDF_DATASET_EMPTY;
  }

  if ((nullptr == columns_to_concat[0])
      || (nullptr == output_column)){
    return GDF_DATASET_EMPTY;
  }

  const gdf_dtype column_type = columns_to_concat[0]->dtype;

  if (column_type != output_column->dtype){
    return GDF_DTYPE_MISMATCH;
  }

  gdf_size_type total_size = 0;
  bool at_least_one_mask_present = false;

  // Ensure all the columns are properly allocated
  // and have matching types
  for (int i = 0; i < num_columns; ++i) {
    gdf_column* current_column = columns_to_concat[i];
    if (nullptr == current_column) {
      return GDF_DATASET_EMPTY;
    }
    if ((current_column->size > 0) && (nullptr == current_column->data))
    {
      return GDF_DATASET_EMPTY;
    }
    if (column_type != current_column->dtype) {
      return GDF_DTYPE_MISMATCH;
    }

    total_size += current_column->size;
    at_least_one_mask_present |= (nullptr != columns_to_concat[i]->valid);
  }

  // sum of the sizes of the input columns must equal output column size
  if (output_column->size != total_size) {
    return GDF_COLUMN_SIZE_MISMATCH;
  }

  // TODO optimizations if needed
  // 1. Either
  //    a) use cudaMemcpyAsync to copy the data and overlap copies with gdf_mask_concat
  //       (this will require getting rid of the allocations below because they will
  //       implicitly sync the device), or
  //    b) use a kernel to copy the data from all columns in one go. This will likely not
  //       overlap with the gdf_mask_concat
  // 2. Detect a zero total null count and skip gdf_mask_concat -- use cudaMemsetAsync

  int8_t* target = (int8_t*)(output_column->data);
  output_column->null_count = 0;
  int column_byte_width = 0;
  gdf_error result = get_column_byte_width(output_column, &column_byte_width);
  if (GDF_SUCCESS != result) return result;

  // copy data
  for (int i = 0; i < num_columns; ++i) {
    gdf_size_type bytes = column_byte_width * columns_to_concat[i]->size;
    CUDA_TRY( cudaMemcpy(target, columns_to_concat[i]->data, bytes, cudaMemcpyDeviceToDevice) );
    target += bytes;

    output_column->null_count += columns_to_concat[i]->null_count;
  }

  if (at_least_one_mask_present) {
    gdf_valid_type** masks;
    gdf_size_type* column_lengths;
    CUDA_TRY( cudaMallocManaged((void**)&masks, sizeof(gdf_valid_type*)*num_columns) );
    CUDA_TRY( cudaMallocManaged((void**)&column_lengths, sizeof(gdf_size_type)*num_columns) );

    for (int i = 0; i < num_columns; ++i) {
      masks[i] = columns_to_concat[i]->valid;
      column_lengths[i] = columns_to_concat[i]->size;
    }

    result = gdf_mask_concat(output_column->valid,
                             output_column->size,
                             masks,
                             column_lengths,
                             num_columns);

    CUDA_TRY( cudaFree(masks) );
    CUDA_TRY( cudaFree(column_lengths) );

    return result;
  }
  else if (nullptr != output_column->valid) {
    // no masks, so just fill output valid mask with all 1 bits
    // TODO: async
    CUDA_TRY( cudaMemset(output_column->valid,
                         0xff,
                         gdf_get_num_chars_bitmask(total_size) * sizeof(gdf_valid_type)) );
  }

  return GDF_SUCCESS;
}

/** ---------------------------------------------------------------------------*
 * @brief Return the size of the gdf_column data type.
 *
 * @return gdf_size_type Size of the gdf_column data type.
 *b  ---------------------------------------------------------------------------**/
gdf_size_type gdf_column_sizeof() {
	return sizeof(gdf_column);
}

/** ---------------------------------------------------------------------------*
 * @brief Create a GDF column given data and validity bitmask pointers, size, and
 *        datatype
 *
 * @param[out] column The output column.
 * @param[in] data Pointer to data.
 * @param[in] valid Pointer to validity bitmask for the data.
 * @param[in] size Number of rows in the column.
 * @param[in] dtype Data type of the column.
 * @return gdf_error Returns GDF_SUCCESS upon successful creation.
 * ---------------------------------------------------------------------------**/
gdf_error gdf_column_view(gdf_column *column,
                          void *data,
                          gdf_valid_type *valid,
		                      gdf_size_type size,
                          gdf_dtype dtype)
{
	column->data = data;
	column->valid = valid;
	column->size = size;
	column->dtype = dtype;
	column->null_count = 0;
	return GDF_SUCCESS;
}

/** ---------------------------------------------------------------------------*
 * @brief Create a GDF column given data and validity bitmask pointers, size, and
 *        datatype, and count of null (non-valid) elements
 *
 * @param[out] column The output column.
 * @param[in] data Pointer to data.
 * @param[in] valid Pointer to validity bitmask for the data.
 * @param[in] size Number of rows in the column.
 * @param[in] dtype Data type of the column.
 * @param[in] null_count The number of non-valid elements in the validity bitmask
 * @return gdf_error Returns GDF_SUCCESS upon successful creation.
 * ---------------------------------------------------------------------------**/
gdf_error gdf_column_view_augmented(gdf_column *column,
                                    void *data,
                                    gdf_valid_type *valid,
		                                gdf_size_type size,
                                    gdf_dtype dtype,
                                    gdf_size_type null_count)
{
	column->data = data;
	column->valid = valid;
	column->size = size;
	column->dtype = dtype;
	column->null_count = null_count;
	return GDF_SUCCESS;
}

/** ---------------------------------------------------------------------------*
 * @brief Free the CUDA device memory of a gdf_column
 *
 * @param[inout] column Data and validity bitmask pointers of this column will be freed
 * @return gdf_error GDF_SUCCESS or GDF_ERROR if there is an error freeing the data
 * ---------------------------------------------------------------------------**/
gdf_error gdf_column_free(gdf_column *column)
{
  CUDA_TRY( cudaFree(column->data)  );
  CUDA_TRY( cudaFree(column->valid) );
  return GDF_SUCCESS;
}

/** ---------------------------------------------------------------------------*
 * @brief Get the byte width of a column
 *
 * @param[in] col The input column
 * @param[out] width The data type size of col
 * @return gdf_error GDF_SUCCESS, or GDF_UNSUPPORTED_DTYPE if col has an invalid
 *         datatype
 * ---------------------------------------------------------------------------**/
gdf_error get_column_byte_width(gdf_column * col,
                                int * width)
{
	switch(col->dtype) {

	case GDF_INT8 :
		*width = 1;
		break;
	case GDF_INT16 :
		*width = 2;
		break;
	case GDF_INT32 :
		*width = 4;
		break;
	case GDF_INT64 :
		*width = 8;
		break;
	case GDF_FLOAT32 :
		*width = 4;
		break;
	case GDF_FLOAT64 :
		*width = 8;
		break;
	case GDF_DATE32 :
		*width = 4;
		break;
	case GDF_DATE64 :
		*width = 8;
		break;
	case GDF_TIMESTAMP :
		*width = 8;
		break;
	default :
		*width = -1;
		return GDF_UNSUPPORTED_DTYPE;
	}

	return GDF_SUCCESS;
}
<commit_msg>Removed errant `b` in a comment.<commit_after>/*
 * Copyright (c) 2018, NVIDIA CORPORATION.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/** ---------------------------------------------------------------------------*
 * @brief Operations on GDF columns
 *
 * @file column.cpp
 * ---------------------------------------------------------------------------**/

#include <gdf/gdf.h>
#include <gdf/utils.h>
#include <gdf/errorutils.h>
#include <cuda_runtime_api.h>

// forward decl -- see validops.cu
gdf_error gdf_mask_concat(gdf_valid_type *output_mask,
                          gdf_size_type output_column_length,
                          gdf_valid_type *masks_to_concat[],
                          gdf_size_type *column_lengths,
                          gdf_size_type num_columns);

/** ---------------------------------------------------------------------------*
 * @brief Concatenates multiple gdf_columns into a single, contiguous column,
 * including the validity bitmasks.
 *
 * Note that input columns with nullptr validity masks are treated as if all
 * elements are valid.
 *
 * @param[out] output_column A column whose buffers are already allocated that
 *             will contain the concatenation of the input columns data and
 *             validity bitmasks
 * @Param[in] columns_to_concat[] The columns to concatenate
 * @Param[in] num_columns The number of columns to concatenate
 *
 * @return gdf_error GDF_SUCCESS upon completion; GDF_DATASET_EMPTY if any data
 *         pointer is NULL, GDF_COLUMN_SIZE_MISMATCH if the output column size
 *         != the total size of the input columns; GDF_DTYPE_MISMATCH if the
 *         input columns have different datatypes.
 * ---------------------------------------------------------------------------**/
gdf_error gdf_column_concat(gdf_column *output_column, gdf_column *columns_to_concat[], int num_columns)
{

  if (nullptr == columns_to_concat){
    return GDF_DATASET_EMPTY;
  }

  if ((nullptr == columns_to_concat[0])
      || (nullptr == output_column)){
    return GDF_DATASET_EMPTY;
  }

  const gdf_dtype column_type = columns_to_concat[0]->dtype;

  if (column_type != output_column->dtype){
    return GDF_DTYPE_MISMATCH;
  }

  gdf_size_type total_size = 0;
  bool at_least_one_mask_present = false;

  // Ensure all the columns are properly allocated
  // and have matching types
  for (int i = 0; i < num_columns; ++i) {
    gdf_column* current_column = columns_to_concat[i];
    if (nullptr == current_column) {
      return GDF_DATASET_EMPTY;
    }
    if ((current_column->size > 0) && (nullptr == current_column->data))
    {
      return GDF_DATASET_EMPTY;
    }
    if (column_type != current_column->dtype) {
      return GDF_DTYPE_MISMATCH;
    }

    total_size += current_column->size;
    at_least_one_mask_present |= (nullptr != columns_to_concat[i]->valid);
  }

  // sum of the sizes of the input columns must equal output column size
  if (output_column->size != total_size) {
    return GDF_COLUMN_SIZE_MISMATCH;
  }

  // TODO optimizations if needed
  // 1. Either
  //    a) use cudaMemcpyAsync to copy the data and overlap copies with gdf_mask_concat
  //       (this will require getting rid of the allocations below because they will
  //       implicitly sync the device), or
  //    b) use a kernel to copy the data from all columns in one go. This will likely not
  //       overlap with the gdf_mask_concat
  // 2. Detect a zero total null count and skip gdf_mask_concat -- use cudaMemsetAsync

  int8_t* target = (int8_t*)(output_column->data);
  output_column->null_count = 0;
  int column_byte_width = 0;
  gdf_error result = get_column_byte_width(output_column, &column_byte_width);
  if (GDF_SUCCESS != result) return result;

  // copy data
  for (int i = 0; i < num_columns; ++i) {
    gdf_size_type bytes = column_byte_width * columns_to_concat[i]->size;
    CUDA_TRY( cudaMemcpy(target, columns_to_concat[i]->data, bytes, cudaMemcpyDeviceToDevice) );
    target += bytes;

    output_column->null_count += columns_to_concat[i]->null_count;
  }

  if (at_least_one_mask_present) {
    gdf_valid_type** masks;
    gdf_size_type* column_lengths;
    CUDA_TRY( cudaMallocManaged((void**)&masks, sizeof(gdf_valid_type*)*num_columns) );
    CUDA_TRY( cudaMallocManaged((void**)&column_lengths, sizeof(gdf_size_type)*num_columns) );

    for (int i = 0; i < num_columns; ++i) {
      masks[i] = columns_to_concat[i]->valid;
      column_lengths[i] = columns_to_concat[i]->size;
    }

    result = gdf_mask_concat(output_column->valid,
                             output_column->size,
                             masks,
                             column_lengths,
                             num_columns);

    CUDA_TRY( cudaFree(masks) );
    CUDA_TRY( cudaFree(column_lengths) );

    return result;
  }
  else if (nullptr != output_column->valid) {
    // no masks, so just fill output valid mask with all 1 bits
    // TODO: async
    CUDA_TRY( cudaMemset(output_column->valid,
                         0xff,
                         gdf_get_num_chars_bitmask(total_size) * sizeof(gdf_valid_type)) );
  }

  return GDF_SUCCESS;
}

/** ---------------------------------------------------------------------------*
 * @brief Return the size of the gdf_column data type.
 *
 * @return gdf_size_type Size of the gdf_column data type.
 *  ---------------------------------------------------------------------------**/
gdf_size_type gdf_column_sizeof() {
	return sizeof(gdf_column);
}

/** ---------------------------------------------------------------------------*
 * @brief Create a GDF column given data and validity bitmask pointers, size, and
 *        datatype
 *
 * @param[out] column The output column.
 * @param[in] data Pointer to data.
 * @param[in] valid Pointer to validity bitmask for the data.
 * @param[in] size Number of rows in the column.
 * @param[in] dtype Data type of the column.
 * @return gdf_error Returns GDF_SUCCESS upon successful creation.
 * ---------------------------------------------------------------------------**/
gdf_error gdf_column_view(gdf_column *column,
                          void *data,
                          gdf_valid_type *valid,
		                      gdf_size_type size,
                          gdf_dtype dtype)
{
	column->data = data;
	column->valid = valid;
	column->size = size;
	column->dtype = dtype;
	column->null_count = 0;
	return GDF_SUCCESS;
}

/** ---------------------------------------------------------------------------*
 * @brief Create a GDF column given data and validity bitmask pointers, size, and
 *        datatype, and count of null (non-valid) elements
 *
 * @param[out] column The output column.
 * @param[in] data Pointer to data.
 * @param[in] valid Pointer to validity bitmask for the data.
 * @param[in] size Number of rows in the column.
 * @param[in] dtype Data type of the column.
 * @param[in] null_count The number of non-valid elements in the validity bitmask
 * @return gdf_error Returns GDF_SUCCESS upon successful creation.
 * ---------------------------------------------------------------------------**/
gdf_error gdf_column_view_augmented(gdf_column *column,
                                    void *data,
                                    gdf_valid_type *valid,
		                                gdf_size_type size,
                                    gdf_dtype dtype,
                                    gdf_size_type null_count)
{
	column->data = data;
	column->valid = valid;
	column->size = size;
	column->dtype = dtype;
	column->null_count = null_count;
	return GDF_SUCCESS;
}

/** ---------------------------------------------------------------------------*
 * @brief Free the CUDA device memory of a gdf_column
 *
 * @param[inout] column Data and validity bitmask pointers of this column will be freed
 * @return gdf_error GDF_SUCCESS or GDF_ERROR if there is an error freeing the data
 * ---------------------------------------------------------------------------**/
gdf_error gdf_column_free(gdf_column *column)
{
  CUDA_TRY( cudaFree(column->data)  );
  CUDA_TRY( cudaFree(column->valid) );
  return GDF_SUCCESS;
}

/** ---------------------------------------------------------------------------*
 * @brief Get the byte width of a column
 *
 * @param[in] col The input column
 * @param[out] width The data type size of col
 * @return gdf_error GDF_SUCCESS, or GDF_UNSUPPORTED_DTYPE if col has an invalid
 *         datatype
 * ---------------------------------------------------------------------------**/
gdf_error get_column_byte_width(gdf_column * col,
                                int * width)
{
	switch(col->dtype) {

	case GDF_INT8 :
		*width = 1;
		break;
	case GDF_INT16 :
		*width = 2;
		break;
	case GDF_INT32 :
		*width = 4;
		break;
	case GDF_INT64 :
		*width = 8;
		break;
	case GDF_FLOAT32 :
		*width = 4;
		break;
	case GDF_FLOAT64 :
		*width = 8;
		break;
	case GDF_DATE32 :
		*width = 4;
		break;
	case GDF_DATE64 :
		*width = 8;
		break;
	case GDF_TIMESTAMP :
		*width = 8;
		break;
	default :
		*width = -1;
		return GDF_UNSUPPORTED_DTYPE;
	}

	return GDF_SUCCESS;
}
<|endoftext|>


<commit_before>#define MAXV 2000
int d[MAXV], p[MAXV], pot[MAXV];
struct cmp {
    bool operator ()(int i, int j) {
        return d[i] == d[j] ? i < j : d[i] < d[j];
    }
};
struct flow_network {
    struct edge {
        int v, cap, cost, nxt;
        edge(int _v, int _cap, int _cost, int _nxt)
            : v(_v), cap(_cap), cost(_cost), nxt(_nxt) {  }
    };
    int n, ecnt, *head;
    vector<edge> e, e_store;
    flow_network(int _n, int m = -1) : n(_n), ecnt(0) {
        e.reserve(2 * (m == -1 ? n : m));
        memset(head = new int[n], -1, n << 2);
    }
    void destroy() { delete[] head; }
    void reset() { e = e_store; }
    void add_edge(int u, int v, int cost, int uv, int vu=0) {
        e.push_back(edge(v, uv, cost, head[u])); head[u] = ecnt++;
        e.push_back(edge(u, vu, -cost, head[v])); head[v] = ecnt++;
    }
    ii min_cost_max_flow(int s, int t, bool res = true) {
        if (s == t) return ii(0, 0);
        e_store = e;
        memset(pot, 0, n << 2);
        int f = 0, c = 0, v;
        while (true) {
            memset(d, -1, n << 2);
            memset(p, -1, n << 2);
            set<int, cmp> q;
            q.insert(s); d[s] = 0;
            while (!q.empty()) {
                int u = *q.begin();
                q.erase(q.begin());
                for (int i = head[u]; i != -1; i = e[i].nxt) {
                    if (e[i].cap == 0) continue;
                    int cd = d[u] + e[i].cost + pot[u] - pot[v = e[i].v];
                    if (d[v] == -1 || cd < d[v]) {
                        if (q.find(v) != q.end()) q.erase(q.find(v));
                        d[v] = cd; p[v] = i;
                        q.insert(v);
                    }
                }
            }
            if (p[t] == -1) break;
            int x = INF, at = p[t];
            while (at != -1) x = min(x, e[at].cap), at = p[e[at^1].v];
            at = p[t], f += x;
            while (at != -1)
                e[at].cap -= x, e[at^1].cap += x, at = p[e[at^1].v];
            c += x * (d[t] + pot[t] - pot[s]);
            rep(i,0,n) if (p[i] != -1) pot[i] += d[i];
        }
        if (res) reset();
        return ii(f, c);
    }
};
<commit_msg>Simplify min-cost max flow<commit_after>#define MAXV 2000
int d[MAXV], p[MAXV], pot[MAXV];
struct cmp {
    bool operator ()(int i, int j) {
        return d[i] == d[j] ? i < j : d[i] < d[j];
    }
};
struct flow_network {
    struct edge {
        int v, cap, cost, nxt;
        edge(int _v, int _cap, int _cost, int _nxt)
            : v(_v), cap(_cap), cost(_cost), nxt(_nxt) {  }
    };
    int n, ecnt, *head;
    vector<edge> e, e_store;
    flow_network(int _n, int m = -1) : n(_n), ecnt(0) {
        e.reserve(2 * (m == -1 ? n : m));
        memset(head = new int[n], -1, n << 2);
    }
    void destroy() { delete[] head; }
    void reset() { e = e_store; }
    void add_edge(int u, int v, int cost, int uv, int vu=0) {
        e.push_back(edge(v, uv, cost, head[u])); head[u] = ecnt++;
        e.push_back(edge(u, vu, -cost, head[v])); head[v] = ecnt++;
    }
    ii min_cost_max_flow(int s, int t, bool res = true) {
        if (s == t) return ii(0, 0);
        e_store = e;
        memset(pot, 0, n << 2);
        int f = 0, c = 0, v;
        while (true) {
            memset(d, -1, n << 2);
            memset(p, -1, n << 2);
            set<int, cmp> q;
            d[s] = 0; q.insert(s);
            while (!q.empty()) {
                int u = *q.begin();
                q.erase(q.begin());
                for (int i = head[u]; i != -1; i = e[i].nxt) {
                    if (e[i].cap == 0) continue;
                    int cd = d[u] + e[i].cost + pot[u] - pot[v = e[i].v];
                    if (d[v] == -1 || cd < d[v]) {
                        q.erase(v);
                        d[v] = cd; p[v] = i;
                        q.insert(v);
                    }
                }
            }
            if (p[t] == -1) break;
            int x = INF, at = p[t];
            while (at != -1) x = min(x, e[at].cap), at = p[e[at^1].v];
            at = p[t], f += x;
            while (at != -1)
                e[at].cap -= x, e[at^1].cap += x, at = p[e[at^1].v];
            c += x * (d[t] + pot[t] - pot[s]);
            rep(i,0,n) if (p[i] != -1) pot[i] += d[i];
        }
        if (res) reset();
        return ii(f, c);
    }
};
<|endoftext|>


<commit_before>#include <application.h>
#include "math.h"

#include "color.h"

// Convert a color from RGB representation to HSV representation.
void Color::Rgb::toHsv(Color::Hsv& hsv)
{
    uint8_t r = this->r;
    uint8_t g = this->g;
    uint8_t b = this->b;

	uint8_t min = min(r, min(g, b));
    uint8_t max = max(r, max(g, b));
	uint8_t delta = max - min;

    hsv.v = max;

    if (max == 0)
    {
        hsv.h = 0;
        hsv.s = 0;
        return;
    }

    if (max == r)
        hsv.h = ((g - b) / delta) * (Color::Hsv::H_MAX / 6);
    else if (max == g)
        hsv.h = ((b - r) / delta + 2) * (Color::Hsv::H_MAX / 6);
    else
        hsv.h = ((r - g) / delta + 4) * (Color::Hsv::H_MAX / 6);

	hsv.s = delta * Color::Hsv::S_MAX / max;
}

Color::Hsv Color::Rgb::toHsv()
{
	Color::Hsv hsv;
	this->toHsv(hsv);
	return hsv;
}

// Convert a color from HSV representation to RGB representation.
void Color::Hsv::toRgb(Color::Rgb& rgb)
{
	float h = this->h / (Color::Hsv::H_MAX / 6.0);
	float s = this->s / Color::Hsv::S_MAX;
	float v = this->v;

	uint16_t i = int(h);
	float f = h - i;
	uint8_t p = (uint8_t)(v * (1 - s));
	uint8_t q = (uint8_t)(v * (1 - s * f));
	uint8_t t = (uint8_t)(v * (1 - s * (1 - f)));

	switch (i % 6)
	{
	case 0: rgb.r = v; rgb.g = t; rgb.b = p; break;
	case 1: rgb.r = q; rgb.g = v; rgb.b = p; break;
	case 2: rgb.r = p; rgb.g = v; rgb.b = t; break;
	case 3: rgb.r = p; rgb.g = q; rgb.b = v; break;
	case 4: rgb.r = t; rgb.g = p; rgb.b = v; break;
	case 5: rgb.r = v; rgb.g = p; rgb.b = q; break;
	}
}

Color::Rgb Color::Hsv::toRgb()
{
	Color::Rgb rgb;
	this->toRgb(rgb);
	return rgb;
}
<commit_msg>Fixed floating point bugs.<commit_after>#include <application.h>
#include "math.h"

#include "color.h"

// Convert a color from RGB representation to HSV representation.
void Color::Rgb::toHsv(Color::Hsv& hsv)
{
    uint8_t r = this->r;
    uint8_t g = this->g;
    uint8_t b = this->b;

	uint8_t min = min(r, min(g, b));
    uint8_t max = max(r, max(g, b));
	float delta = max - min;

    hsv.v = max;

    if (max == 0)
    {
        hsv.h = 0;
        hsv.s = 0;
        return;
    }

    if (max == r)
        hsv.h = ((g - b) / delta) * (Color::Hsv::H_MAX / 6.0);
    else if (max == g)
        hsv.h = ((b - r) / delta + 2) * (Color::Hsv::H_MAX / 6.0);
    else
        hsv.h = ((r - g) / delta + 4) * (Color::Hsv::H_MAX / 6.0);

	hsv.s = delta * Color::Hsv::S_MAX / max;
}

Color::Hsv Color::Rgb::toHsv()
{
	Color::Hsv hsv;
	this->toHsv(hsv);
	return hsv;
}

// Convert a color from HSV representation to RGB representation.
void Color::Hsv::toRgb(Color::Rgb& rgb)
{
	float h = this->h / (Color::Hsv::H_MAX / 6.0);
	float s = this->s / (float)Color::Hsv::S_MAX;
	float v = this->v;

	uint16_t i = int(h);
	float f = h - i;
	uint8_t p = (uint8_t)(v * (1 - s));
	uint8_t q = (uint8_t)(v * (1 - s * f));
	uint8_t t = (uint8_t)(v * (1 - s * (1 - f)));

	switch (i % 6)
	{
	case 0: rgb.r = v; rgb.g = t; rgb.b = p; break;
	case 1: rgb.r = q; rgb.g = v; rgb.b = p; break;
	case 2: rgb.r = p; rgb.g = v; rgb.b = t; break;
	case 3: rgb.r = p; rgb.g = q; rgb.b = v; break;
	case 4: rgb.r = t; rgb.g = p; rgb.b = v; break;
	case 5: rgb.r = v; rgb.g = p; rgb.b = q; break;
	}
}

Color::Rgb Color::Hsv::toRgb()
{
	Color::Rgb rgb;
	this->toRgb(rgb);
	return rgb;
}
<|endoftext|>


<commit_before>#ifndef __MODEL_HPP_INCLUDED
#define __MODEL_HPP_INCLUDED

#include "entity.hpp"

// Include GLEW
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h> // GLfloat, GLuint etc.
#endif

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <queue>    // std::queue
#include <stdint.h> // uint32_t etc.
#include <string>   // std::string
#include <vector>   // std::vector

namespace ontology
{
    class Material;
    class Object;

    class Model: public ontology::Entity
    {
        public:
            // constructor.
            Model();

            // destructor.
            ~Model();

            // this method sets a object pointer.
            void set_object_pointer(uint32_t childID, ontology::Object* child_pointer);

            // this method gets a object ID and removes it from the `free_objectID_queue` if it was popped from the queue.
            uint32_t get_objectID();

            std::string color_channel;               // color channel in use: `"red"`, `"green"`, `"blue"`, `"mean"` or `"all"`.
            glm::vec3 light_position;                // light position.

            uint32_t childID;                        // species ID/text3D ID/glyph ID, set by corresponding `bind_to_parent()`.
            GLuint lightID;                          // light ID, returned by `glGetUniformLocation(programID, "LightPosition_worldspace");`.

            std::vector<ontology::Object*> object_pointer_vector;
            std::queue<uint32_t> free_objectID_queue;

            std::string triangulation_type;

            GLuint vertexPosition_modelspaceID;
            GLuint vertexUVID;
            GLuint vertexNormal_modelspaceID;

            std::vector<glm::vec3> vertices;         // vertices of the object.
            std::vector<glm::vec2> UVs;              // UVs of the object.
            std::vector<glm::vec3> normals;          // normals of the object.

            std::vector<uint32_t> indices;           // the deleted vertices will be reused (though it is not required, if there's enough memory).
            std::vector<glm::vec3> indexed_vertices;
            std::vector<glm::vec2> indexed_UVs;
            std::vector<glm::vec3> indexed_normals;

            GLuint vertexbuffer;
            GLuint uvbuffer;
            GLuint normalbuffer;
            GLuint elementbuffer;
    };
}

#endif
<commit_msg>All member variables of `class Model` are now `private`.<commit_after>#ifndef __MODEL_HPP_INCLUDED
#define __MODEL_HPP_INCLUDED

#include "entity.hpp"
#include "species_or_glyph.hpp"
#include "code/ylikuutio/hierarchy/hierarchy_templates.hpp"

// Include GLEW
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h> // GLfloat, GLuint etc.
#endif

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <queue>    // std::queue
#include <stdint.h> // uint32_t etc.
#include <string>   // std::string
#include <vector>   // std::vector

namespace space_partition
{
    class Chunk;
}

namespace ontology
{
    class Shader;
    class Material;
    class Species;
    class Object;

    class Model: public ontology::Entity
    {
        public:
            // constructor.
            Model();

            // destructor.
            ~Model();

            // this method sets a object pointer.
            void set_object_pointer(uint32_t childID, ontology::Object* child_pointer);

            // this method gets a object ID and removes it from the `free_objectID_queue` if it was popped from the queue.
            uint32_t get_objectID();

            friend class Glyph;
            friend class Species;
            friend class Object;
            friend class space_partition::Chunk;
            template<class T1>
                friend void hierarchy::bind_child_to_parent(T1 child_pointer, std::vector<T1>& child_pointer_vector, std::queue<uint32_t>& free_childID_queue);
            template<class T1, class T2>
                friend void hierarchy::bind_child_to_new_parent(T1 child_pointer, T2 new_parent_pointer, std::vector<T1>& old_child_pointer_vector, std::queue<uint32_t>& old_free_childID_queue);
            template<class T1>
                friend void render_species_or_glyph(T1 species_or_glyph_pointer);
            template<class T1>
                friend void render_this_object(ontology::Object* object_pointer, ontology::Shader* shader_pointer);
            friend GLfloat get_ground_level(ontology::Species* terrain_species, glm::vec3 position);

        private:
            std::string color_channel;               // color channel in use: `"red"`, `"green"`, `"blue"`, `"mean"` or `"all"`.
            glm::vec3 light_position;                // light position.

            uint32_t childID;                        // species ID/text3D ID/glyph ID, set by corresponding `bind_to_parent()`.
            GLuint lightID;                          // light ID, returned by `glGetUniformLocation(programID, "LightPosition_worldspace");`.

            std::vector<ontology::Object*> object_pointer_vector;
            std::queue<uint32_t> free_objectID_queue;

            std::string triangulation_type;

            GLuint vertexPosition_modelspaceID;
            GLuint vertexUVID;
            GLuint vertexNormal_modelspaceID;

            std::vector<glm::vec3> vertices;         // vertices of the object.
            std::vector<glm::vec2> UVs;              // UVs of the object.
            std::vector<glm::vec3> normals;          // normals of the object.

            std::vector<uint32_t> indices;           // the deleted vertices will be reused (though it is not required, if there's enough memory).
            std::vector<glm::vec3> indexed_vertices;
            std::vector<glm::vec2> indexed_UVs;
            std::vector<glm::vec3> indexed_normals;

            GLuint vertexbuffer;
            GLuint uvbuffer;
            GLuint normalbuffer;
            GLuint elementbuffer;
    };
}

#endif
<|endoftext|>


<commit_before>
/*
    Filename:
        common.cpp
    Author:
        Vincent Heins / TheMysteriousVincent
    Description:
        This class holds static functions for common things, like converting an string to an int, e.g...
*/

#include "common.h"

/*
    Publicity: public
    Return type: void
    Name/Type: strReplace()
    Description: replaces each char in *oldChar with *New
*/
void A3URLCommon::StrReplace(std::string *s, const char *oldArr, const char *New)
{
    std::string chars(oldArr);
    for (const char &c : chars)
    {
        //TODO: create for loop for comparison -> less loops.
        size_t found = s->find(c);
        while (found != std::string::npos)
        {
            if (strcmp(New, "") == 0)
            {
                s->erase(found, 1);
            }
            else
            {
                s->replace(found, 1, New);
            }

            found = s->find(c);
        }
    }
}

/*
    Publicity: public
    Return type: int
    Name/Type: strToInt()
    Description: converts a std::string to int !safely!
*/
int A3URLCommon::StrToInt(std::string s)
{
    int i;
    try
    {
        A3URLCommon::StrReplace(&s, "\"'abcdefghijklmnopqrstuvzxyzABCDEFGHIJKLMNOPQRSTUVWXYZöäüÖÄÜ-_*~+#`´?\\ß}{[]()/&%", "");
        i = std::stoi(s);
    }
    catch (const std::invalid_argument &e)
    {
        i = 0;
    }
    catch (const std::out_of_range &e)
    {
        i = 0;
    }

    return i;
};

//A3URLCommon::StrUnquote unquotes a given string pointer
void A3URLCommon::StrUnqoute(std::string *s)
{
    if (s->size() > 0)
    {
        if (s->compare(s->size() - 1, 1, "\"") == 0)
            s->erase(s->size() - 1);

        if (s->compare(0, 1, "\"") == 0)
            s->erase(0, 1);
    }
};

//A3URLCommon::MergeStringMaps merges two given std::map<std::string, std::string> maps
std::map<std::string, std::string> A3URLCommon::MergeStringMaps(std::map<std::string, std::string> m1, std::map<std::string, std::string> m2)
{
    //m2 -> overwrites -> m1
    for (std::map<std::string, std::string>::iterator it = m2.begin(); it != m2.end(); ++it)
        m1[it->first] = it->second;

    return m1;
};

//A3URLCommon::ToArray is the init function for the json array to ArmA 3 array convertion
std::string A3URLCommon::ToArray(std::string jTxt)
{
    Json::Value root;
    std::stringstream(jTxt) >> root;
    std::stringstream res;

    if (root.empty() || root.isNull())
    {
        res << "[]";
    }
    else if (root.isArray())
    {
        res << A3URLCommon::toArray_array(root);
    }
    else if (root.isObject())
    {
        res << A3URLCommon::toArray_object(root);
    }

    return res.str();
};

//A3URLCommon::toArray_array formats only JSON arrays to an ArmA 3 array
std::string A3URLCommon::toArray_array(const Json::Value &root)
{
    std::stringstream res;

    res << "[\"array\",[";
    if (root.size() > 0)
    {
        for (Json::Value::const_iterator it = root.begin(); it != root.end(); it++)
        {
            if (it != root.begin())
                res << ",";

            if (it->isBool())
            {
                res << Json::valueToString(it->asBool());
            }
            else if (it->isInt())
            {
                res << Json::valueToString(it->asInt());
            }
            else if (it->isInt64())
            {
                res << Json::valueToString(it->asInt64());
            }
            else if (it->isUInt())
            {
                res << Json::valueToString(it->asUInt());
            }
            else if (it->isUInt64())
            {
                res << Json::valueToString(it->asUInt64());
            }
            else if (it->isDouble())
            {
                res << Json::valueToString(it->asDouble());
            }
            else if (it->isString())
            {
                res << Json::valueToQuotedString(it->asString().c_str());
            }
            else if (it->isObject())
            {
                res << A3URLCommon::toArray_object(*it);
            }
            else if (it->isArray())
            {
                res << A3URLCommon::toArray_array(*it);
            }
            else
            {
                res << "nil";
            }
        }
    }
    res << "]]";

    return res.str();
};

//A3URLCommon::toArray_object formats a JSON object to an ArmA 3 array
std::string A3URLCommon::toArray_object(const Json::Value &root)
{
    std::stringstream res;

    res << "[\"object\",[";
    if (root.size() > 0)
    {
        for (Json::Value::const_iterator it = root.begin(); it != root.end(); it++)
        {
            if (it != root.begin())
                res << ",";

            res << "[" << Json::valueToQuotedString(it.key().asString().c_str()) << ",";

            if (it->isBool())
            {
                res << Json::valueToString(it->asBool());
            }
            else if (it->isInt())
            {
                res << Json::valueToString(it->asInt());
            }
            else if (it->isInt64())
            {
                res << Json::valueToString(it->asInt64());
            }
            else if (it->isUInt())
            {
                res << Json::valueToString(it->asUInt());
            }
            else if (it->isUInt64())
            {
                res << Json::valueToString(it->asUInt64());
            }
            else if (it->isDouble())
            {
                res << Json::valueToString(it->asDouble());
            }
            else if (it->isString())
            {
                res << Json::valueToQuotedString(it->asString().c_str());
            }
            else if (it->isObject())
            {
                res << A3URLCommon::toArray_object(*it);
            }
            else if (it->isArray())
            {
                res << A3URLCommon::toArray_array(*it);
            }
            else
            {
                res << "nil";
            }

            res << "]";
        }
    }

    res << "]]";

    return res.str();
};
<commit_msg>update unquoting arguments<commit_after>
/*
    Filename:
        common.cpp
    Author:
        Vincent Heins / TheMysteriousVincent
    Description:
        This class holds static functions for common things, like converting an string to an int, e.g...
*/

#include "common.h"

/*
    Publicity: public
    Return type: void
    Name/Type: strReplace()
    Description: replaces each char in *oldChar with *New
*/
void A3URLCommon::StrReplace(std::string *s, const char *oldArr, const char *New)
{
    std::string chars(oldArr);
    for (const char &c : chars)
    {
        //TODO: create for loop for comparison -> less loops.
        size_t found = s->find(c);
        while (found != std::string::npos)
        {
            if (strcmp(New, "") == 0)
            {
                s->erase(found, 1);
            }
            else
            {
                s->replace(found, 1, New);
            }

            found = s->find(c);
        }
    }
}

/*
    Publicity: public
    Return type: int
    Name/Type: strToInt()
    Description: converts a std::string to int !safely!
*/
int A3URLCommon::StrToInt(std::string s)
{
    int i;
    try
    {
        A3URLCommon::StrReplace(&s, "\"'abcdefghijklmnopqrstuvzxyzABCDEFGHIJKLMNOPQRSTUVWXYZöäüÖÄÜ-_*~+#`´?\\ß}{[]()/&%", "");
        i = std::stoi(s);
    }
    catch (const std::invalid_argument &e)
    {
        i = 0;
    }
    catch (const std::out_of_range &e)
    {
        i = 0;
    }

    return i;
};

//A3URLCommon::StrUnquote unquotes a given string pointer
void A3URLCommon::StrUnqoute(std::string *s)
{
    if (s->size() > 0)
    {
        if (s->front() == '"')
            s->erase(0, 1);
        if (s->back() == '"')
            s->erase(s->size() - 1);

        //unquote '""' quotes to '"'
        bool lastQuoted = false;
        for (std::string::iterator it = s->begin(); it != s->end(); it++)
        {
            if (*it == '"')
            {
                if (!lastQuoted)
                {
                    lastQuoted = true;
                }
                else
                {
                    s->erase(it);
                    it--;
                    lastQuoted = false;
                }
            }
            else
            {
                lastQuoted = false;
            }
        }
    }
};

//A3URLCommon::MergeStringMaps merges two given std::map<std::string, std::string> maps
std::map<std::string, std::string> A3URLCommon::MergeStringMaps(std::map<std::string, std::string> m1, std::map<std::string, std::string> m2)
{
    //m2 -> overwrites -> m1
    for (std::map<std::string, std::string>::iterator it = m2.begin(); it != m2.end(); ++it)
        m1[it->first] = it->second;

    return m1;
};

//A3URLCommon::ToArray is the init function for the json array to ArmA 3 array convertion
std::string A3URLCommon::ToArray(std::string jTxt)
{
    Json::Value root;
    std::stringstream(jTxt) >> root;
    std::stringstream res;

    if (root.empty() || root.isNull())
    {
        res << "[]";
    }
    else if (root.isArray())
    {
        res << A3URLCommon::toArray_array(root);
    }
    else if (root.isObject())
    {
        res << A3URLCommon::toArray_object(root);
    }

    return res.str();
};

//A3URLCommon::toArray_array formats only JSON arrays to an ArmA 3 array
std::string A3URLCommon::toArray_array(const Json::Value &root)
{
    std::stringstream res;

    res << "[\"array\",[";
    if (root.size() > 0)
    {
        for (Json::Value::const_iterator it = root.begin(); it != root.end(); it++)
        {
            if (it != root.begin())
                res << ",";

            if (it->isBool())
            {
                res << Json::valueToString(it->asBool());
            }
            else if (it->isInt())
            {
                res << Json::valueToString(it->asInt());
            }
            else if (it->isInt64())
            {
                res << Json::valueToString(it->asInt64());
            }
            else if (it->isUInt())
            {
                res << Json::valueToString(it->asUInt());
            }
            else if (it->isUInt64())
            {
                res << Json::valueToString(it->asUInt64());
            }
            else if (it->isDouble())
            {
                res << Json::valueToString(it->asDouble());
            }
            else if (it->isString())
            {
                res << Json::valueToQuotedString(it->asString().c_str());
            }
            else if (it->isObject())
            {
                res << A3URLCommon::toArray_object(*it);
            }
            else if (it->isArray())
            {
                res << A3URLCommon::toArray_array(*it);
            }
            else
            {
                res << "nil";
            }
        }
    }
    res << "]]";

    return res.str();
};

//A3URLCommon::toArray_object formats a JSON object to an ArmA 3 array
std::string A3URLCommon::toArray_object(const Json::Value &root)
{
    std::stringstream res;

    res << "[\"object\",[";
    if (root.size() > 0)
    {
        for (Json::Value::const_iterator it = root.begin(); it != root.end(); it++)
        {
            if (it != root.begin())
                res << ",";

            res << "[" << Json::valueToQuotedString(it.key().asString().c_str()) << ",";

            if (it->isBool())
            {
                res << Json::valueToString(it->asBool());
            }
            else if (it->isInt())
            {
                res << Json::valueToString(it->asInt());
            }
            else if (it->isInt64())
            {
                res << Json::valueToString(it->asInt64());
            }
            else if (it->isUInt())
            {
                res << Json::valueToString(it->asUInt());
            }
            else if (it->isUInt64())
            {
                res << Json::valueToString(it->asUInt64());
            }
            else if (it->isDouble())
            {
                res << Json::valueToString(it->asDouble());
            }
            else if (it->isString())
            {
                res << Json::valueToQuotedString(it->asString().c_str());
            }
            else if (it->isObject())
            {
                res << A3URLCommon::toArray_object(*it);
            }
            else if (it->isArray())
            {
                res << A3URLCommon::toArray_array(*it);
            }
            else
            {
                res << "nil";
            }

            res << "]";
        }
    }

    res << "]]";

    return res.str();
};
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011, Peter Thorson. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the WebSocket++ Project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef WEBSOCKET_CONSTANTS_HPP
#define WEBSOCKET_CONSTANTS_HPP

#ifndef __STDC_LIMIT_MACROS
  #define __STDC_LIMIT_MACROS
#endif
#include <stdint.h>

#include <string>
#include <vector>

#include <boost/shared_ptr.hpp>

// Defaults
namespace websocketpp {
	typedef std::vector<unsigned char> binary_string;
	typedef boost::shared_ptr<binary_string> binary_string_ptr;

	typedef std::string utf8_string;
	typedef boost::shared_ptr<utf8_string> utf8_string_ptr;

	const uint64_t DEFAULT_MAX_MESSAGE_SIZE = 0xFFFFFF; // ~16MB

	const uint16_t DEFAULT_PORT = 80;
	const uint16_t DEFAULT_SECURE_PORT = 443;

	inline uint16_t default_port(bool secure) {
		return (secure ? DEFAULT_SECURE_PORT : DEFAULT_PORT);
	}

	namespace session {
		namespace state {
			enum value {
				CONNECTING = 0,
				OPEN = 1,
				CLOSING = 2,
				CLOSED = 3
			};
		}
	}

	namespace close {
	namespace status {
		enum value {
			INVALID_END = 999,
			NORMAL = 1000,
			GOING_AWAY = 1001,
			PROTOCOL_ERROR = 1002,
			UNSUPPORTED_DATA = 1003,
			RSV_ADHOC_1 = 1004,
			NO_STATUS = 1005,
			ABNORMAL_CLOSE = 1006,
			INVALID_PAYLOAD = 1007,
			POLICY_VIOLATION = 1008,
			MESSAGE_TOO_BIG = 1009,
			EXTENSION_REQUIRE = 1010,
			INTERNAL_ENDPOINT_ERROR = 1011,
			RSV_START = 1012,
			RSV_END = 2999,
			INVALID_START = 5000
		};

		inline bool reserved(value s) {
			return ((s >= RSV_START && s <= RSV_END) ||
					s == RSV_ADHOC_1);
		}

		inline bool invalid(value s) {
			return ((s <= INVALID_END || s >= INVALID_START) ||
					s == NO_STATUS ||
					s == ABNORMAL_CLOSE);
		}

		// TODO functions for application ranges?
	} // namespace status
	} // namespace close

    namespace frame {
        // Opcodes are 4 bits
        // See spec section 5.2
        namespace opcode {
            enum value {
                CONTINUATION = 0x0,
                TEXT = 0x1,
                BINARY = 0x2,
                RSV3 = 0x3,
                RSV4 = 0x4,
                RSV5 = 0x5,
                RSV6 = 0x6,
                RSV7 = 0x7,
                CLOSE = 0x8,
                PING = 0x9,
                PONG = 0xA,
                CONTROL_RSVB = 0xB,
                CONTROL_RSVC = 0xC,
                CONTROL_RSVD = 0xD,
                CONTROL_RSVE = 0xE,
                CONTROL_RSVF = 0xF,
            };

            inline bool reserved(value v) {
                return (v >= RSV3 && v <= RSV7) ||
                (v >= CONTROL_RSVB && v <= CONTROL_RSVF);
            }

            inline bool invalid(value v) {
                return (v > 0xF || v < 0);
            }

            inline bool is_control(value v) {
                return v >= 0x8;
            }
        }

        namespace limits {
            static const uint8_t PAYLOAD_SIZE_BASIC = 125;
            static const uint16_t PAYLOAD_SIZE_EXTENDED = 0xFFFF; // 2^16, 65535
            static const uint64_t PAYLOAD_SIZE_JUMBO = 0x7FFFFFFFFFFFFFFF;//2^63
        }
    } // namespace frame
}

#endif // WEBSOCKET_CONSTANTS_HPP
<commit_msg>adds a generic exception class for application errors<commit_after>/*
 * Copyright (c) 2011, Peter Thorson. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the WebSocket++ Project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef WEBSOCKET_CONSTANTS_HPP
#define WEBSOCKET_CONSTANTS_HPP

#ifndef __STDC_LIMIT_MACROS
  #define __STDC_LIMIT_MACROS
#endif
#include <stdint.h>

#include <exception>
#include <string>
#include <vector>

#include <boost/shared_ptr.hpp>

// Defaults
namespace websocketpp {
	typedef std::vector<unsigned char> binary_string;
	typedef boost::shared_ptr<binary_string> binary_string_ptr;

	typedef std::string utf8_string;
	typedef boost::shared_ptr<utf8_string> utf8_string_ptr;

	const uint64_t DEFAULT_MAX_MESSAGE_SIZE = 0xFFFFFF; // ~16MB

	const uint16_t DEFAULT_PORT = 80;
	const uint16_t DEFAULT_SECURE_PORT = 443;

	inline uint16_t default_port(bool secure) {
		return (secure ? DEFAULT_SECURE_PORT : DEFAULT_PORT);
	}

	namespace session {
		namespace state {
			enum value {
				CONNECTING = 0,
				OPEN = 1,
				CLOSING = 2,
				CLOSED = 3
			};
		}
	}

	namespace close {
	namespace status {
		enum value {
			INVALID_END = 999,
			NORMAL = 1000,
			GOING_AWAY = 1001,
			PROTOCOL_ERROR = 1002,
			UNSUPPORTED_DATA = 1003,
			RSV_ADHOC_1 = 1004,
			NO_STATUS = 1005,
			ABNORMAL_CLOSE = 1006,
			INVALID_PAYLOAD = 1007,
			POLICY_VIOLATION = 1008,
			MESSAGE_TOO_BIG = 1009,
			EXTENSION_REQUIRE = 1010,
			INTERNAL_ENDPOINT_ERROR = 1011,
			RSV_START = 1012,
			RSV_END = 2999,
			INVALID_START = 5000
		};

		inline bool reserved(value s) {
			return ((s >= RSV_START && s <= RSV_END) ||
					s == RSV_ADHOC_1);
		}

		inline bool invalid(value s) {
			return ((s <= INVALID_END || s >= INVALID_START) ||
					s == NO_STATUS ||
					s == ABNORMAL_CLOSE);
		}

		// TODO functions for application ranges?
	} // namespace status
	} // namespace close

    namespace frame {
        // Opcodes are 4 bits
        // See spec section 5.2
        namespace opcode {
            enum value {
                CONTINUATION = 0x0,
                TEXT = 0x1,
                BINARY = 0x2,
                RSV3 = 0x3,
                RSV4 = 0x4,
                RSV5 = 0x5,
                RSV6 = 0x6,
                RSV7 = 0x7,
                CLOSE = 0x8,
                PING = 0x9,
                PONG = 0xA,
                CONTROL_RSVB = 0xB,
                CONTROL_RSVC = 0xC,
                CONTROL_RSVD = 0xD,
                CONTROL_RSVE = 0xE,
                CONTROL_RSVF = 0xF,
            };

            inline bool reserved(value v) {
                return (v >= RSV3 && v <= RSV7) ||
                (v >= CONTROL_RSVB && v <= CONTROL_RSVF);
            }

            inline bool invalid(value v) {
                return (v > 0xF || v < 0);
            }

            inline bool is_control(value v) {
                return v >= 0x8;
            }
        }

        namespace limits {
            static const uint8_t PAYLOAD_SIZE_BASIC = 125;
            static const uint16_t PAYLOAD_SIZE_EXTENDED = 0xFFFF; // 2^16, 65535
            static const uint64_t PAYLOAD_SIZE_JUMBO = 0x7FFFFFFFFFFFFFFF;//2^63
        }
    } // namespace frame

    // exception class for errors that should be propogated back to the user.
    namespace error {
        enum value {
            GENERIC = 0,
            // send attempted when endpoint write queue was full
            SEND_QUEUE_FULL = 1,
            PAYLOAD_VIOLATION = 2
        };
    }

    class exception : public std::exception {
    public:
        exception(const std::string& msg,
                  error::value code = error::GENERIC)
        : m_msg(msg),m_code(code) {}
        ~exception() throw() {}

        virtual const char* what() const throw() {
            return m_msg.c_str();
        }

        error::value code() const throw() {
            return m_code;
        }

        std::string m_msg;
        error::value m_code;
    };
}

#endif // WEBSOCKET_CONSTANTS_HPP
<|endoftext|>