<commit_before>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	result.cxx
 *
 *   DESCRIPTION
 *      implementation of the pqxx::result class and support classes.
 *   pqxx::result represents the set of result tuples from a database query
 *
 * Copyright (c) 2001-2006, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler-internal.hxx"

#include <stdexcept>

#include "libpq-fe.h"

#include "pqxx/except"
#include "pqxx/result"

using namespace PGSTD;

const string pqxx::result::s_empty_string;

pqxx::internal::result_data::result_data() : data(0), protocol(0), query() {}

pqxx::internal::result_data::result_data(pqxx::internal::pq::PGresult *d,
	int p,
	const string &q) :
  data(d),
  protocol(p),
  query(q)
	{}

pqxx::internal::result_data::~result_data() { PQclear(data); }

void pqxx::internal::freemem_result_data(result_data *d) throw () { delete d; }

pqxx::result::result(pqxx::internal::pq::PGresult *rhs,
	int protocol,
	const string &Query) :
  super(new internal::result_data(rhs, protocol, Query)),
  m_data(rhs)
	{}

bool pqxx::result::operator==(const result &rhs) const throw ()
{
  if (&rhs == this) return true;
  const size_type s(size());
  if (rhs.size() != s) return false;
  for (size_type i=0; i<s; ++i)
    if ((*this)[i] != rhs[i]) return false;
  return true;
}

bool pqxx::result::tuple::operator==(const tuple &rhs) const throw ()
{
  if (&rhs == this) return true;
  const size_type s(size());
  if (rhs.size() != s) return false;
  // TODO: Depends on how null is handled!
  for (size_type i=0; i<s; ++i) if ((*this)[i] != rhs[i]) return false;
  return true;
}

void pqxx::result::tuple::swap(tuple &rhs) throw ()
{
  const result *const h(m_Home);
  const result::size_type i(m_Index);
  m_Home = rhs.m_Home;
  m_Index = rhs.m_Index;
  rhs.m_Home = h;
  rhs.m_Index = i;
}

bool pqxx::result::field::operator==(const field &rhs) const
{
  if (is_null() != rhs.is_null()) return false;
  // TODO: Verify null handling decision
  const size_type s = size();
  if (s != rhs.size()) return false;
  const char *const l(c_str()), *const r(rhs.c_str());
  for (size_type i = 0; i < s; ++i) if (l[i] != r[i]) return false;
  return true;
}

pqxx::result::size_type pqxx::result::size() const throw ()
{
  return m_data ? PQntuples(m_data) : 0;
}

bool pqxx::result::empty() const throw ()
{
  return !m_data || !PQntuples(m_data);
}

void pqxx::result::swap(result &rhs) throw ()
{
  super::swap(rhs);
  m_data = (c_ptr() ? c_ptr()->data : 0);
  rhs.m_data = (rhs.c_ptr() ? rhs.c_ptr()->data : 0);
}

const pqxx::result::tuple pqxx::result::at(pqxx::result::size_type i) const
  throw (out_of_range)
{
  if (i >= size())
    throw out_of_range("Tuple number out of range");

  return operator[](i);
}

void pqxx::result::ThrowSQLError(const PGSTD::string &Err,
	const PGSTD::string &Query) const
{
#if defined(PQXX_HAVE_PQRESULTERRORFIELD)
  // Try to establish more precise error type, and throw corresponding exception
  const char *const code = PQresultErrorField(m_data, PG_DIAG_SQLSTATE);
  if (code) switch (code[0])
  {
  case '0':
    switch (code[1])
    {
    case '8':
      throw broken_connection(Err);
    case 'A':
      throw feature_not_supported(Err, Query);
    }
    break;
  case '2':
    switch (code[1])
    {
    case '2':
      throw data_exception(Err, Query);
    case '3':
      throw integrity_constraint_violation(Err, Query);
    case '4':
      throw invalid_cursor_state(Err, Query);
    case '6':
      throw invalid_sql_statement_name(Err, Query);
    }
    break;
  case '3':
    switch (code[1])
    {
    case '4':
      throw invalid_cursor_name(Err, Query);
    }
    break;
  case '4':
    switch (code[1])
    {
    case '2':
      if (strcmp(code,"42501")==0) throw insufficient_privilege(Err, Query);
      if (strcmp(code,"42601")==0) throw syntax_error(Err, Query);
      if (strcmp(code,"42703")==0) throw undefined_column(Err, Query);
      if (strcmp(code,"42883")==0) throw undefined_function(Err, Query);
      if (strcmp(code,"42P01")==0) throw undefined_table(Err, Query);
    }
    break;
  case '5':
    switch (code[1])
    {
    case '3':
      if (strcmp(code,"53100")==0) throw disk_full(Err, Query);
      if (strcmp(code,"53200")==0) throw out_of_memory(Err, Query);
      if (strcmp(code,"53300")==0) throw too_many_connections(Err);
      throw insufficient_resources(Err, Query);
    }
    break;
  }
#endif
  throw sql_error(Err, Query);
}

void pqxx::result::CheckStatus() const
{
  const string Err = StatusError();
  if (!Err.empty()) ThrowSQLError(Err, query());
}

string pqxx::result::StatusError() const
{
  if (!m_data)
    throw runtime_error("No result set given");

  string Err;

  switch (PQresultStatus(m_data))
  {
  case PGRES_EMPTY_QUERY: // The string sent to the backend was empty.
  case PGRES_COMMAND_OK: // Successful completion of a command returning no data
  case PGRES_TUPLES_OK: // The query successfully executed
    break;

  case PGRES_COPY_OUT: // Copy Out (from server) data transfer started
  case PGRES_COPY_IN: // Copy In (to server) data transfer started
    break;

  case PGRES_BAD_RESPONSE: // The server's response was not understood
  case PGRES_NONFATAL_ERROR:
  case PGRES_FATAL_ERROR:
    Err = PQresultErrorMessage(m_data);
    break;

  default:
    throw internal_error("pqxx::result: Unrecognized response code " +
		      to_string(int(PQresultStatus(m_data))));
  }
  return Err;
}

const char *pqxx::result::CmdStatus() const throw ()
{
  return PQcmdStatus(m_data);
}

const string &pqxx::result::query() const throw ()
{
  return c_ptr() ? c_ptr()->query : s_empty_string;
}

pqxx::oid pqxx::result::inserted_oid() const
{
  if (!m_data)
    throw logic_error("Attempt to read oid of inserted row without an INSERT "
	"result");
  return PQoidValue(m_data);
}

pqxx::result::size_type pqxx::result::affected_rows() const
{
  const char *const RowsStr = PQcmdTuples(m_data);
  return RowsStr[0] ? atoi(RowsStr) : 0;
}

const char *pqxx::result::GetValue(pqxx::result::size_type Row,
		                 pqxx::result::tuple::size_type Col) const
{
  return PQgetvalue(m_data, Row, Col);
}

bool pqxx::result::GetIsNull(pqxx::result::size_type Row,
		           pqxx::result::tuple::size_type Col) const
{
  return PQgetisnull(m_data, Row, Col) != 0;
}

pqxx::result::field::size_type
pqxx::result::GetLength(pqxx::result::size_type Row,
                        pqxx::result::tuple::size_type Col) const
{
  return PQgetlength(m_data, Row, Col);
}

pqxx::oid pqxx::result::column_type(tuple::size_type ColNum) const
{
  const oid T = PQftype(m_data, ColNum);
  if (T == oid_none)
    throw PGSTD::invalid_argument(
	"Attempt to retrieve type of nonexistant column " +
	to_string(ColNum) + " of query result");
  return T;
}

#ifdef PQXX_HAVE_PQFTABLE
pqxx::oid pqxx::result::column_table(tuple::size_type ColNum) const
{
  const oid T = PQftable(m_data, ColNum);

  /* If we get oid_none, it may be because the column is computed, or because we
   * got an invalid row number.
   */
  if (T == oid_none && ColNum >= columns())
    throw PGSTD::invalid_argument("Attempt to retrieve table ID for column " +
	to_string(ColNum) + " out of " + to_string(columns()));

  return T;
}
#endif

#ifdef PQXX_HAVE_PQFTABLECOL
pqxx::result::tuple::size_type
pqxx::result::table_column(tuple::size_type ColNum) const
{
  const tuple::size_type n = PQftablecol(m_data, ColNum);
  if (n) return n-1;

  // Failed.  Now find out why, so we can throw a sensible exception.
  // Possible reasons:
  // 1. Column out of range
  // 2. Not using protocol 3.0 or better
  // 3. Column not taken directly from a table
  if (ColNum > columns())
    throw out_of_range("Invalid column index in table_column(): " +
      to_string(ColNum));

  if (!c_ptr() || c_ptr()->protocol < 3)
    throw feature_not_supported("Backend version does not support querying of "
      "column's original number",
      "[TABLE_COLUMN]");

  throw logic_error("Can't query origin of column " + to_string(ColNum) + ": "
	"not derived from table column");
}
#endif

int pqxx::result::errorposition() const throw ()
{
  int pos = -1;
#if defined(PQXX_HAVE_PQRESULTERRORFIELD)
  if (m_data)
  {
    const char *p = PQresultErrorField(m_data, PG_DIAG_STATEMENT_POSITION);
    if (p) from_string(p, pos);
  }
#endif // PQXX_HAVE_PQRESULTERRORFIELD
  return pos;
}

// tuple

pqxx::result::field pqxx::result::tuple::operator[](const char f[]) const
{
  return field(*this, m_Home->column_number(f));
}

pqxx::result::field pqxx::result::tuple::at(const char f[]) const
{
  const int fnum = m_Home->column_number(f);
  // TODO: Should this be an out_of_range?
  if (fnum == -1)
    throw invalid_argument(string("Unknown field '") + f + "'");

  return field(*this, fnum);
}

pqxx::result::field
pqxx::result::tuple::at(pqxx::result::tuple::size_type i) const throw (out_of_range)
{
  if (i >= size())
    throw out_of_range("Invalid field number");

  return operator[](i);
}

const char *
pqxx::result::column_name(pqxx::result::tuple::size_type Number) const
{
  const char *const N = PQfname(m_data, Number);
  if (!N)
    throw out_of_range("Invalid column number: " + to_string(Number));

  return N;
}

pqxx::result::tuple::size_type pqxx::result::columns() const throw ()
{
  return m_data ? PQnfields(m_data) : 0;
}

pqxx::result::tuple::size_type
pqxx::result::column_number(const char ColName[]) const
{
  const int N = PQfnumber(m_data, ColName);
  // TODO: Should this be an out_of_range?
  if (N == -1)
    throw invalid_argument("Unknown column name: '" + string(ColName) + "'");

  return tuple::size_type(N);
}

// const_iterator

pqxx::result::const_iterator
pqxx::result::const_iterator::operator++(int)
{
  const_iterator old(*this);
  m_Index++;
  return old;
}

pqxx::result::const_iterator
pqxx::result::const_iterator::operator--(int)
{
  const_iterator old(*this);
  m_Index--;
  return old;
}

// const_fielditerator

pqxx::result::const_fielditerator
pqxx::result::const_fielditerator::operator++(int)
{
  const_fielditerator old(*this);
  m_col++;
  return old;
}

pqxx::result::const_fielditerator
pqxx::result::const_fielditerator::operator--(int)
{
  const_fielditerator old(*this);
  m_col--;
  return old;
}

pqxx::result::const_iterator
pqxx::result::const_reverse_iterator::base() const throw ()
{
  iterator_type tmp(*this);
  return ++tmp;
}

pqxx::result::const_reverse_iterator
pqxx::result::const_reverse_iterator::operator++(int)
{
  const_reverse_iterator tmp(*this);
  iterator_type::operator--();
  return tmp;
}

pqxx::result::const_reverse_iterator
pqxx::result::const_reverse_iterator::operator--(int)
{
  const_reverse_iterator tmp(*this);
  iterator_type::operator++();
  return tmp;
}

pqxx::result::const_fielditerator
pqxx::result::const_reverse_fielditerator::base() const throw ()
{
  iterator_type tmp(*this);
  return ++tmp;
}

pqxx::result::const_reverse_fielditerator
pqxx::result::const_reverse_fielditerator::operator++(int)
{
  const_reverse_fielditerator tmp(*this);
  operator++();
  return tmp;
}

pqxx::result::const_reverse_fielditerator
pqxx::result::const_reverse_fielditerator::operator--(int)
{
  const_reverse_fielditerator tmp(*this);
  operator--();
  return tmp;
}

<commit_msg>Copyright update<commit_after>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	result.cxx
 *
 *   DESCRIPTION
 *      implementation of the pqxx::result class and support classes.
 *   pqxx::result represents the set of result tuples from a database query
 *
 * Copyright (c) 2001-2007, Jeroen T. Vermeulen <jtv@xs4all.nl>
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 *
 *-------------------------------------------------------------------------
 */
#include "pqxx/compiler-internal.hxx"

#include <stdexcept>

#include "libpq-fe.h"

#include "pqxx/except"
#include "pqxx/result"

using namespace PGSTD;

const string pqxx::result::s_empty_string;

pqxx::internal::result_data::result_data() : data(0), protocol(0), query() {}

pqxx::internal::result_data::result_data(pqxx::internal::pq::PGresult *d,
	int p,
	const string &q) :
  data(d),
  protocol(p),
  query(q)
	{}

pqxx::internal::result_data::~result_data() { PQclear(data); }

void pqxx::internal::freemem_result_data(result_data *d) throw () { delete d; }

pqxx::result::result(pqxx::internal::pq::PGresult *rhs,
	int protocol,
	const string &Query) :
  super(new internal::result_data(rhs, protocol, Query)),
  m_data(rhs)
	{}

bool pqxx::result::operator==(const result &rhs) const throw ()
{
  if (&rhs == this) return true;
  const size_type s(size());
  if (rhs.size() != s) return false;
  for (size_type i=0; i<s; ++i)
    if ((*this)[i] != rhs[i]) return false;
  return true;
}

bool pqxx::result::tuple::operator==(const tuple &rhs) const throw ()
{
  if (&rhs == this) return true;
  const size_type s(size());
  if (rhs.size() != s) return false;
  // TODO: Depends on how null is handled!
  for (size_type i=0; i<s; ++i) if ((*this)[i] != rhs[i]) return false;
  return true;
}

void pqxx::result::tuple::swap(tuple &rhs) throw ()
{
  const result *const h(m_Home);
  const result::size_type i(m_Index);
  m_Home = rhs.m_Home;
  m_Index = rhs.m_Index;
  rhs.m_Home = h;
  rhs.m_Index = i;
}

bool pqxx::result::field::operator==(const field &rhs) const
{
  if (is_null() != rhs.is_null()) return false;
  // TODO: Verify null handling decision
  const size_type s = size();
  if (s != rhs.size()) return false;
  const char *const l(c_str()), *const r(rhs.c_str());
  for (size_type i = 0; i < s; ++i) if (l[i] != r[i]) return false;
  return true;
}

pqxx::result::size_type pqxx::result::size() const throw ()
{
  return m_data ? PQntuples(m_data) : 0;
}

bool pqxx::result::empty() const throw ()
{
  return !m_data || !PQntuples(m_data);
}

void pqxx::result::swap(result &rhs) throw ()
{
  super::swap(rhs);
  m_data = (c_ptr() ? c_ptr()->data : 0);
  rhs.m_data = (rhs.c_ptr() ? rhs.c_ptr()->data : 0);
}

const pqxx::result::tuple pqxx::result::at(pqxx::result::size_type i) const
  throw (out_of_range)
{
  if (i >= size())
    throw out_of_range("Tuple number out of range");

  return operator[](i);
}

void pqxx::result::ThrowSQLError(const PGSTD::string &Err,
	const PGSTD::string &Query) const
{
#if defined(PQXX_HAVE_PQRESULTERRORFIELD)
  // Try to establish more precise error type, and throw corresponding exception
  const char *const code = PQresultErrorField(m_data, PG_DIAG_SQLSTATE);
  if (code) switch (code[0])
  {
  case '0':
    switch (code[1])
    {
    case '8':
      throw broken_connection(Err);
    case 'A':
      throw feature_not_supported(Err, Query);
    }
    break;
  case '2':
    switch (code[1])
    {
    case '2':
      throw data_exception(Err, Query);
    case '3':
      throw integrity_constraint_violation(Err, Query);
    case '4':
      throw invalid_cursor_state(Err, Query);
    case '6':
      throw invalid_sql_statement_name(Err, Query);
    }
    break;
  case '3':
    switch (code[1])
    {
    case '4':
      throw invalid_cursor_name(Err, Query);
    }
    break;
  case '4':
    switch (code[1])
    {
    case '2':
      if (strcmp(code,"42501")==0) throw insufficient_privilege(Err, Query);
      if (strcmp(code,"42601")==0) throw syntax_error(Err, Query);
      if (strcmp(code,"42703")==0) throw undefined_column(Err, Query);
      if (strcmp(code,"42883")==0) throw undefined_function(Err, Query);
      if (strcmp(code,"42P01")==0) throw undefined_table(Err, Query);
    }
    break;
  case '5':
    switch (code[1])
    {
    case '3':
      if (strcmp(code,"53100")==0) throw disk_full(Err, Query);
      if (strcmp(code,"53200")==0) throw out_of_memory(Err, Query);
      if (strcmp(code,"53300")==0) throw too_many_connections(Err);
      throw insufficient_resources(Err, Query);
    }
    break;
  }
#endif
  throw sql_error(Err, Query);
}

void pqxx::result::CheckStatus() const
{
  const string Err = StatusError();
  if (!Err.empty()) ThrowSQLError(Err, query());
}

string pqxx::result::StatusError() const
{
  if (!m_data)
    throw runtime_error("No result set given");

  string Err;

  switch (PQresultStatus(m_data))
  {
  case PGRES_EMPTY_QUERY: // The string sent to the backend was empty.
  case PGRES_COMMAND_OK: // Successful completion of a command returning no data
  case PGRES_TUPLES_OK: // The query successfully executed
    break;

  case PGRES_COPY_OUT: // Copy Out (from server) data transfer started
  case PGRES_COPY_IN: // Copy In (to server) data transfer started
    break;

  case PGRES_BAD_RESPONSE: // The server's response was not understood
  case PGRES_NONFATAL_ERROR:
  case PGRES_FATAL_ERROR:
    Err = PQresultErrorMessage(m_data);
    break;

  default:
    throw internal_error("pqxx::result: Unrecognized response code " +
		      to_string(int(PQresultStatus(m_data))));
  }
  return Err;
}

const char *pqxx::result::CmdStatus() const throw ()
{
  return PQcmdStatus(m_data);
}

const string &pqxx::result::query() const throw ()
{
  return c_ptr() ? c_ptr()->query : s_empty_string;
}

pqxx::oid pqxx::result::inserted_oid() const
{
  if (!m_data)
    throw logic_error("Attempt to read oid of inserted row without an INSERT "
	"result");
  return PQoidValue(m_data);
}

pqxx::result::size_type pqxx::result::affected_rows() const
{
  const char *const RowsStr = PQcmdTuples(m_data);
  return RowsStr[0] ? atoi(RowsStr) : 0;
}

const char *pqxx::result::GetValue(pqxx::result::size_type Row,
		                 pqxx::result::tuple::size_type Col) const
{
  return PQgetvalue(m_data, Row, Col);
}

bool pqxx::result::GetIsNull(pqxx::result::size_type Row,
		           pqxx::result::tuple::size_type Col) const
{
  return PQgetisnull(m_data, Row, Col) != 0;
}

pqxx::result::field::size_type
pqxx::result::GetLength(pqxx::result::size_type Row,
                        pqxx::result::tuple::size_type Col) const
{
  return PQgetlength(m_data, Row, Col);
}

pqxx::oid pqxx::result::column_type(tuple::size_type ColNum) const
{
  const oid T = PQftype(m_data, ColNum);
  if (T == oid_none)
    throw PGSTD::invalid_argument(
	"Attempt to retrieve type of nonexistant column " +
	to_string(ColNum) + " of query result");
  return T;
}

#ifdef PQXX_HAVE_PQFTABLE
pqxx::oid pqxx::result::column_table(tuple::size_type ColNum) const
{
  const oid T = PQftable(m_data, ColNum);

  /* If we get oid_none, it may be because the column is computed, or because we
   * got an invalid row number.
   */
  if (T == oid_none && ColNum >= columns())
    throw PGSTD::invalid_argument("Attempt to retrieve table ID for column " +
	to_string(ColNum) + " out of " + to_string(columns()));

  return T;
}
#endif

#ifdef PQXX_HAVE_PQFTABLECOL
pqxx::result::tuple::size_type
pqxx::result::table_column(tuple::size_type ColNum) const
{
  const tuple::size_type n = PQftablecol(m_data, ColNum);
  if (n) return n-1;

  // Failed.  Now find out why, so we can throw a sensible exception.
  // Possible reasons:
  // 1. Column out of range
  // 2. Not using protocol 3.0 or better
  // 3. Column not taken directly from a table
  if (ColNum > columns())
    throw out_of_range("Invalid column index in table_column(): " +
      to_string(ColNum));

  if (!c_ptr() || c_ptr()->protocol < 3)
    throw feature_not_supported("Backend version does not support querying of "
      "column's original number",
      "[TABLE_COLUMN]");

  throw logic_error("Can't query origin of column " + to_string(ColNum) + ": "
	"not derived from table column");
}
#endif

int pqxx::result::errorposition() const throw ()
{
  int pos = -1;
#if defined(PQXX_HAVE_PQRESULTERRORFIELD)
  if (m_data)
  {
    const char *p = PQresultErrorField(m_data, PG_DIAG_STATEMENT_POSITION);
    if (p) from_string(p, pos);
  }
#endif // PQXX_HAVE_PQRESULTERRORFIELD
  return pos;
}

// tuple

pqxx::result::field pqxx::result::tuple::operator[](const char f[]) const
{
  return field(*this, m_Home->column_number(f));
}

pqxx::result::field pqxx::result::tuple::at(const char f[]) const
{
  const int fnum = m_Home->column_number(f);
  // TODO: Should this be an out_of_range?
  if (fnum == -1)
    throw invalid_argument(string("Unknown field '") + f + "'");

  return field(*this, fnum);
}

pqxx::result::field
pqxx::result::tuple::at(pqxx::result::tuple::size_type i) const throw (out_of_range)
{
  if (i >= size())
    throw out_of_range("Invalid field number");

  return operator[](i);
}

const char *
pqxx::result::column_name(pqxx::result::tuple::size_type Number) const
{
  const char *const N = PQfname(m_data, Number);
  if (!N)
    throw out_of_range("Invalid column number: " + to_string(Number));

  return N;
}

pqxx::result::tuple::size_type pqxx::result::columns() const throw ()
{
  return m_data ? PQnfields(m_data) : 0;
}

pqxx::result::tuple::size_type
pqxx::result::column_number(const char ColName[]) const
{
  const int N = PQfnumber(m_data, ColName);
  // TODO: Should this be an out_of_range?
  if (N == -1)
    throw invalid_argument("Unknown column name: '" + string(ColName) + "'");

  return tuple::size_type(N);
}

// const_iterator

pqxx::result::const_iterator
pqxx::result::const_iterator::operator++(int)
{
  const_iterator old(*this);
  m_Index++;
  return old;
}

pqxx::result::const_iterator
pqxx::result::const_iterator::operator--(int)
{
  const_iterator old(*this);
  m_Index--;
  return old;
}

// const_fielditerator

pqxx::result::const_fielditerator
pqxx::result::const_fielditerator::operator++(int)
{
  const_fielditerator old(*this);
  m_col++;
  return old;
}

pqxx::result::const_fielditerator
pqxx::result::const_fielditerator::operator--(int)
{
  const_fielditerator old(*this);
  m_col--;
  return old;
}

pqxx::result::const_iterator
pqxx::result::const_reverse_iterator::base() const throw ()
{
  iterator_type tmp(*this);
  return ++tmp;
}

pqxx::result::const_reverse_iterator
pqxx::result::const_reverse_iterator::operator++(int)
{
  const_reverse_iterator tmp(*this);
  iterator_type::operator--();
  return tmp;
}

pqxx::result::const_reverse_iterator
pqxx::result::const_reverse_iterator::operator--(int)
{
  const_reverse_iterator tmp(*this);
  iterator_type::operator++();
  return tmp;
}

pqxx::result::const_fielditerator
pqxx::result::const_reverse_fielditerator::base() const throw ()
{
  iterator_type tmp(*this);
  return ++tmp;
}

pqxx::result::const_reverse_fielditerator
pqxx::result::const_reverse_fielditerator::operator++(int)
{
  const_reverse_fielditerator tmp(*this);
  operator++();
  return tmp;
}

pqxx::result::const_reverse_fielditerator
pqxx::result::const_reverse_fielditerator::operator--(int)
{
  const_reverse_fielditerator tmp(*this);
  operator--();
  return tmp;
}

<|endoftext|>


<commit_before>#include <boost/tokenizer.hpp>
#include <iostream>
#include <unistd.h>
#include <string.h>
#include <cstdlib>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string>
#include <sstream>
#include <vector>

//using namespace boost;
using namespace std;

int main()
{
	using namespace boost;
	string args;
	while(1 != 2)
	{
		cout << "$ ";
		getline(cin, args);

		char *argv[9];
		int i = 0;
		vector<string> arg_s;
		typedef tokenizer< char_separator<char> > tokenizer;
		char_separator<char> sep(" ", "-;||&&", drop_empty_tokens);
		tokenizer tokens(args, sep);

		for(tokenizer::iterator tok_iter=tokens.begin(); tok_iter != tokens.end();++tok_iter) {
			if(*tok_iter == "&&" || *tok_iter == "||" || *tok_iter == ";") {

	//			argv[i] = NULL;
	//			int pidb = fork();
	//			if(pidb == -1) {
	//				perror("fork");
	//			}
	//			if(pidb == 0) {
	//				int t = execvp(argv[0], argv);
	//				if(t == -1) {
	//					perror("execvp");
	//				}
	//			}
	//			else {
	//				if(-1 == waitpid(pidb, &pidb, 0)) {
	//					perror("waitpid");
	//				}
	//			}
			}
			else {

				arg_s.push_back(*tok_iter);
				argv[i] = new char[12];
				strcpy(argv[i], const_cast<char*>(arg_s[i].c_str()));
				if(*tok_iter == "exit")
					exit(1);
				++i;
			}
		}
		argv[i] = NULL;
		int pid = fork();
		if(pid == -1) {
			perror("fork");
			exit(1);
		}
		if(pid == 0) {
			int r = execvp(argv[0], argv);
			if(r == -1) {
				perror("execvp");
				exit(1);
			}
		}
		else {
			if(-1 == waitpid(pid, &pid, 0)) {
				perror("waitpid");
			}
		}

//	int pid = fork();
//	if(pid == -1) {
//		perror("fork");
//		exit(1);
//	}
//	if(pid == 0)
//	{
		//char *argv2[4];
		//argv2[0] = new char[6];
		//strcpy(argv[0], "ls");
		//argv2[1] = new char[6];
		//strcpy(argv[1], "-a");
		//argv2[2] = new char [6];
		//strcpy(argv[2], "-l");

	//	int pid2 = fork();
	//	if(pid2 == -1) {
	//		perror("fork");
	//		exit(1);
	//	}
	//	if(pid2 == 0) {
	///		if(execvp(argv[0], argv) == -1) {
	//			perror("execvp");
	//			exit(1);
	//		}
	//	}
	//	else {
	//		if(-1 == waitpid(pid2,&pid2,0 ))
	//			perror("waitpid");
	//	}
	//
	  //      if(execvp(argv[1], argv) == -1) {
	//		perror("execvp");
	//		exit(1);
	//	}
//
//		cout << "after" << endl;
//	}
//	else {
//		if(-1 == waitpid(pid, &pid, 0))
//			perror("waitpid");
//	}

	}

	return 0;
}
<commit_msg>rshell.cpp making progress<commit_after>#include <boost/tokenizer.hpp>
#include <iostream>
#include <unistd.h>
#include <string.h>
#include <cstdlib>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string>
#include <sstream>
#include <vector>

//using namespace boost;
using namespace std;

int main()
{
	using namespace boost;
	string args;
	while(1 != 2)
	{
		cout << "$ ";
		getline(cin, args);

		char *argv[9];
		int i = 0;
		vector<string> arg_s;
		typedef tokenizer< char_separator<char> > tokenizer;
		char_separator<char> sep(" ", "-;||&&", drop_empty_tokens);
		tokenizer tokens(args, sep);

		for(tokenizer::iterator tok_iter=tokens.begin(); tok_iter != tokens.end();++tok_iter) {
			if(*tok_iter == "&&" || *tok_iter == "||" || *tok_iter == ";") {

			}
			else {

				arg_s.push_back(*tok_iter);
				argv[i] = new char[12];
				strcpy(argv[i], const_cast<char*>(arg_s[i].c_str()));
				if(*tok_iter == "exit")
					exit(1);
				++i;
			}
		}
		argv[i] = NULL;
		int pid = fork();
		if(pid == -1) {
			perror("fork");
			exit(1);
		}
		if(pid == 0) {
			int r = execvp(argv[0], argv);
			if(r == -1) {
				perror("execvp");
				exit(1);
			}
		}
		else {
			if(-1 == waitpid(pid, &pid, 0)) {
				perror("waitpid");
			}
		}

//	int pid = fork();
//	if(pid == -1) {
//		perror("fork");
//		exit(1);
//	}
//	if(pid == 0)
//	{
		//char *argv2[4];
		//argv2[0] = new char[6];
		//strcpy(argv[0], "ls");
		//argv2[1] = new char[6];
		//strcpy(argv[1], "-a");
		//argv2[2] = new char [6];
		//strcpy(argv[2], "-l");

	//	int pid2 = fork();
	//	if(pid2 == -1) {
	//		perror("fork");
	//		exit(1);
	//	}
	//	if(pid2 == 0) {
	///		if(execvp(argv[0], argv) == -1) {
	//			perror("execvp");
	//			exit(1);
	//		}
	//	}
	//	else {
	//		if(-1 == waitpid(pid2,&pid2,0 ))
	//			perror("waitpid");
	//	}
	//
	  //      if(execvp(argv[1], argv) == -1) {
	//		perror("execvp");
	//		exit(1);
	//	}
//
//		cout << "after" << endl;
//	}
//	else {
//		if(-1 == waitpid(pid, &pid, 0))
//			perror("waitpid");
//	}

	}

	return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string.h>
#include <boost/tokenizer.hpp>
#include <vector>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <algorithm>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>

using namespace std;
using namespace boost;

class Connector
{
    public:
        Connector();
        ~Connector();
        bool run;
        int type;
        bool runNext();
        bool precedence;

};

Connector::Connector()
{
    // the semicolon connector allows the next command to be execute always
    run = true;
    type = 0; // semicolon connector set to 0
    precedence = false;
}

Connector::~Connector()
{
}
bool Connector::runNext()
{
    if (type == 1) // && connector
    {
        if (!run) // if the first command doesn't succeed  it wont run the next command
        {
            return false;
        }
    }
    else if (type == 2) // || connector
    {
        if (run) // if the first command succeed it wont run the next command
        {
            return false;
        }
    }
    return true;
}
void parseinator(vector<string> input, string& command, string& argument, int& position, Connector& connect, string& flag);
void commandifier(string command, string argument, Connector& connect, string flag);
void test_function(string command, string flag, string argument, Connector& connect);
int main()
{
    string flag;
    string str;
    string command;
    string argument;
    Connector connect;
    char hostname[100];
    int position = 0;
    while (true)
    {
        printf("%s",getlogin()); // returns string containing name of user logged in
        gethostname(hostname, sizeof hostname); // returns the standard host name for the current machine
        cout << "@" << hostname << "$ ";
        getline(cin, str);
        if (str == "exit") // special command of exit
        {
            break;
        }
        vector<string> instruction; // vector of strings
        typedef tokenizer<boost::char_separator<char> > Tok;
        char_separator<char> sep; // default constructed
        Tok tok(str, sep);;
        for (Tok::iterator tok_iter = tok.begin(); tok_iter != tok.end(); ++tok_iter) // parses the input into a command and argument
        {
	    instruction.push_back(*tok_iter);

	}
	if (instruction[0] != "#") // checks for user input except for comments (#)
        {
            parseinator(instruction, command, argument, position, connect, flag); // parses the input into a command and argument
            commandifier(command, argument, connect, flag); // runs a command with a given argument
            command = "";
            argument = "";
            int vector_size = instruction.size();
            for (; position < vector_size;) // run until the end of the instruction
            {
                parseinator(instruction, command, argument, position, connect, flag);
                if (connect.runNext()) // checks connector to see if the next command should be ran
	        {
                    commandifier(command, argument, connect, flag);
                }
	        else
	        {
	            while(connect.precedence && position < vector_size)
		        {
		            if(instruction[position] == ")")
		            {
		                connect.precedence = false;
		            }
		            position++;
		        }
	            connect.run = true;
	            command = "";
	        }
	        command = "";
                argument = "";
            }
            position = 0;
        }
    }
    return 0;
}
void parseinator(vector<string> input, string& command, string& argument, int& position, Connector& connect, string& flag)
{
    if (input[position] == "&") // check if string is equal to & connector
    {
        connect.type = 1; // set & connector to 1
        position += 2; // +=2 in order to take && connect
    }
    if (input[position] == "|")
    {
        connect.type = 2; // set | connector to 2
        position += 2; // +=2 in order to take || connector
    }
    if (input[position] == ";")
    {
        connect.type = 0; // set ; connector to 0
        position ++;
    }
    if (input[position] == "(")
    {
        connect.precedence = true;
        position++;
    }
    if (input[position] != "#")
    {
        command = input[position];
        position++;
    }
    if (command == "test")
    {
        if(input[position] == "-")
        {
            position++;
	    if (input[position] == "f")
            {
		flag = "-e";
		position++;
	    }
	    else if (input[position] == "d")
	    {
		flag = "-d";
		position++;
	    }
	    else // DEFAULT E
	    {
		flag = "-e";
		position++;
            }
        }
    }

    int input_size = input.size();
    for (; position < input_size; position++)
    {
        if (input[position] == ")")
        {
            connect.precedence = false;
            position++;
            break;
        }
        if(command == "echo" && input[position] == "\"")
        {
            position++;
            while(input[position] != "\"" && position <= input_size)
            {

                argument += input[position];
                if(!isalnum(input[position].at(0)) && !isalnum(input[position+1].at(0)))
                {

                }
                else
		{
                    argument += " ";
                }
		position++;
            }
            position++;
            break;
        }
        if (input[position] == "#")
        {
            position = input.size();
            break;
        }
        if (input[position] == "&" || input[position] == "|" || input[position] == ";")
	    {
            break;
    	}

        argument += input[position];
        int input_size1 = input.size();
        if (position+1 != input_size1 && command == "echo")
	{
	    //adds spaces when echoing
            argument += " ";
	}
    }
}
void commandifier(string command, string argument, Connector& connect, string flag)
{
    const char * const_command = command.c_str();
    char * char_command = new char[command.size()];
    const char * const_argument = argument.c_str();
    char * char_argument = new char[argument.size()];
    strcpy (char_command, const_command);
    strcpy (char_argument, const_argument);
    char * args[2]; // char pointer array that holds command, and NULL
    char * args1[3]; // char pointer array that holds command, argument, and NULL
    bool no_arg = true;
    bool failed = false;

    if(command == "test" || command == "[")
    {
	test_function(command,flag,argument,connect);
	return;
    }
    // exit command
    if(command == "exit" || argument == "exit")
    {
	exit(1);
    }

    if (argument.size() == 0) // no arguments
    {
        args[0] = char_command; // args will contain the command
        args[1] = NULL;
    }
    else
    {
	no_arg = false; // sets bool no_arg to false
	args1[0] = char_command; // args1 contains command and argument
        args1[1] = char_argument;
        args1[2] = NULL;
    }
    pid_t c_pid, pid; // data type to reporesent process ID's
    int status;
    c_pid = fork(); // create our fork

    if (c_pid < 0) // indicates the fork has fail if its less than 0
    {
        perror("fork failed");
        exit(1);
    }
    else if (c_pid == 0) // in child process
    {
 	if (no_arg) // no argument
	{
        	execvp( args[0], args); // execvp the char pointer array that holds the command only
        	if (execvp(args[0], args) == -1) // if it returns -1 it failed
                {
                    perror("execvp failed");
                    connect.run = false;
                    failed = true;
                }
		exit(3);
	}
	else // with command and argument
	{
		execvp(args1[0], args1); // execvp the char pointer array that holds the command, and argument
		if (execvp(args1[0], args1) == -1) // if it returns -1 it failed
                {
                    perror("execvp failed");
                    connect.run = false;
                    failed = true;
                }
		exit(3);
	}
    }
    else if (c_pid > 0) // parent process
    {
        if((pid = wait(&status)) < 0 )
        {
            perror("wait");
	    exit(3);
        }
        if (WIFEXITED(status))  //Evaluates to a non-zero value if status was returned for a child process that terminated normally.

        {
            if (WEXITSTATUS(status) != 0)
            {
                connect.run = false;
            }
	    else
	    {
		connect.run = true;
            }
        }
       else
        {
            connect.run = true;
        }
     }
}
void test_function(string command, string flag, string argument, Connector &connect)
{
   const char * arg = argument.c_str();
   struct stat sb;
   if(flag == "-f")
   {
 	switch (sb.st_mode & S_IFMT){
	case S_IFREG:   connect.run = true;
	}
   }
   if(flag == "-d")
   {
	switch(sb.st_mode & S_IFMT){
	case S_IFDIR: connect.run = true;
	}

   }
   if(stat(arg,&sb)==0)
   {
        connect.run = true;
   }
   else
   {
   	connect.run = false;
   }
}

<commit_msg>Fixed empty command<commit_after>#include <iostream>
#include <string.h>
#include <boost/tokenizer.hpp>
#include <vector>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <algorithm>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>

using namespace std;
using namespace boost;

class Connector
{
    public:
        Connector();
        ~Connector();
        bool run;
        int type;
        bool runNext();
        bool precedence;

};

Connector::Connector()
{
    // the semicolon connector allows the next command to be execute always
    run = true;
    type = 0; // semicolon connector set to 0
    precedence = false;
}

Connector::~Connector()
{
}
bool Connector::runNext()
{
    if (type == 1) // && connector
    {
        if (!run) // if the first command doesn't succeed  it wont run the next command
        {
            return false;
        }
    }
    else if (type == 2) // || connector
    {
        if (run) // if the first command succeed it wont run the next command
        {
            return false;
        }
    }
    return true;
}
void parseinator(vector<string> input, string& command, string& argument, int& position, Connector& connect, string& flag);
void commandifier(string command, string argument, Connector& connect, string flag);
void test_function(string command, string flag, string argument, Connector& connect);
int main()
{
    string flag;
    string str;
    string command;
    string argument;
    Connector connect;
    char hostname[100];
    int position = 0;
    while (true)
    {
        printf("%s",getlogin()); // returns string containing name of user logged in
        gethostname(hostname, sizeof hostname); // returns the standard host name for the current machine
        cout << "@" << hostname << "$ ";
        getline(cin, str);
        if (str == "exit") // special command of exit
        {
            break;
        }
        vector<string> instruction; // vector of strings
        typedef tokenizer<boost::char_separator<char> > Tok;
        char_separator<char> sep; // default constructed
        Tok tok(str, sep);;
        for (Tok::iterator tok_iter = tok.begin(); tok_iter != tok.end(); ++tok_iter) // parses the input into a command and argument
        {
	    instruction.push_back(*tok_iter);

	}
	if (instruction[0] != "#") // checks for user input except for comments (#)
        {
            parseinator(instruction, command, argument, position, connect, flag); // parses the input into a command and argument
            commandifier(command, argument, connect, flag); // runs a command with a given argument
            command = "";
            argument = "";
            int vector_size = instruction.size();
            for (; position < vector_size;) // run until the end of the instruction
            {
                parseinator(instruction, command, argument, position, connect, flag);
                if (connect.runNext() && command != "") // checks connector to see if the next command should be ran
	        {
                    commandifier(command, argument, connect, flag);
                }
	        else
	        {
	            while(connect.precedence && position < vector_size)
		        {
		            if(instruction[position] == ")")
		            {
		                connect.precedence = false;
		            }
		            position++;
		        }
	            connect.run = true;
	            command = "";
	        }
	        command = "";
                argument = "";
            }
            position = 0;
        }
    }
    return 0;
}
void parseinator(vector<string> input, string& command, string& argument, int& position, Connector& connect, string& flag)
{
    if (input[position] == "&") // check if string is equal to & connector
    {
        connect.type = 1; // set & connector to 1
        position += 2; // +=2 in order to take && connect
    }
    if (input[position] == "|")
    {
        connect.type = 2; // set | connector to 2
        position += 2; // +=2 in order to take || connector
    }
    if (input[position] == ";")
    {
        connect.type = 0; // set ; connector to 0
        position ++;
    }
    if (input[position] == "(")
    {
        connect.precedence = true;
        position++;
    }
    if (input[position] != "#")
    {
        command = input[position];
        position++;
    }
    if (command == "test")
    {
        if(input[position] == "-")
        {
            position++;
	    if (input[position] == "f")
            {
		flag = "-e";
		position++;
	    }
	    else if (input[position] == "d")
	    {
		flag = "-d";
		position++;
	    }
	    else // DEFAULT E
	    {
		flag = "-e";
		position++;
            }
        }
    }

    int input_size = input.size();
    for (; position < input_size; position++)
    {
        if (input[position] == ")")
        {
            connect.precedence = false;
            position++;
            break;
        }
        if(command == "echo" && input[position] == "\"")
        {
            position++;
            while(input[position] != "\"" && position <= input_size)
            {

                argument += input[position];
                if(!isalnum(input[position].at(0)) && !isalnum(input[position+1].at(0)))
                {

                }
                else
		{
                    argument += " ";
                }
		position++;
            }
            position++;
            break;
        }
        if (input[position] == "#")
        {
            position = input.size();
            break;
        }
        if (input[position] == "&" || input[position] == "|" || input[position] == ";")
	    {
            break;
    	}

        argument += input[position];
        int input_size1 = input.size();
        if (position+1 != input_size1 && command == "echo")
	{
	    //adds spaces when echoing
            argument += " ";
	}
    }
}
void commandifier(string command, string argument, Connector& connect, string flag)
{
    const char * const_command = command.c_str();
    char * char_command = new char[command.size()];
    const char * const_argument = argument.c_str();
    char * char_argument = new char[argument.size()];
    strcpy (char_command, const_command);
    strcpy (char_argument, const_argument);
    char * args[2]; // char pointer array that holds command, and NULL
    char * args1[3]; // char pointer array that holds command, argument, and NULL
    bool no_arg = true;
    bool failed = false;

    if(command == "test" || command == "[")
    {
	test_function(command,flag,argument,connect);
	return;
    }
    // exit command
    if(command == "exit" || argument == "exit")
    {
	exit(1);
    }

    if (argument.size() == 0) // no arguments
    {
        args[0] = char_command; // args will contain the command
        args[1] = NULL;
    }
    else
    {
	no_arg = false; // sets bool no_arg to false
	args1[0] = char_command; // args1 contains command and argument
        args1[1] = char_argument;
        args1[2] = NULL;
    }
    pid_t c_pid, pid; // data type to reporesent process ID's
    int status;
    c_pid = fork(); // create our fork

    if (c_pid < 0) // indicates the fork has fail if its less than 0
    {
        perror("fork failed");
        exit(1);
    }
    else if (c_pid == 0) // in child process
    {
 	if (no_arg) // no argument
	{
        	execvp( args[0], args); // execvp the char pointer array that holds the command only
        	if (execvp(args[0], args) == -1) // if it returns -1 it failed
                {
                    perror("execvp failed");
                    connect.run = false;
                    failed = true;
                }
		exit(3);
	}
	else // with command and argument
	{
		execvp(args1[0], args1); // execvp the char pointer array that holds the command, and argument
		if (execvp(args1[0], args1) == -1) // if it returns -1 it failed
                {
                    perror("execvp failed");
                    connect.run = false;
                    failed = true;
                }
		exit(3);
	}
    }
    else if (c_pid > 0) // parent process
    {
        if((pid = wait(&status)) < 0 )
        {
            perror("wait");
	    exit(3);
        }
        if (WIFEXITED(status))  //Evaluates to a non-zero value if status was returned for a child process that terminated normally.

        {
            if (WEXITSTATUS(status) != 0)
            {
                connect.run = false;
            }
	    else
	    {
		connect.run = true;
            }
        }
       else
        {
            connect.run = true;
        }
     }
}
void test_function(string command, string flag, string argument, Connector &connect)
{
   const char * arg = argument.c_str();
   struct stat sb;
   if(flag == "-f")
   {
 	switch (sb.st_mode & S_IFMT){
	case S_IFREG:   connect.run = true;
	}
   }
   if(flag == "-d")
   {
	switch(sb.st_mode & S_IFMT){
	case S_IFDIR: connect.run = true;
	}

   }
   if(stat(arg,&sb)==0)
   {
        connect.run = true;
   }
   else
   {
   	connect.run = false;
   }
}

<|endoftext|>


<commit_before>// Copyright (c) 2012-2013, the scalloc Project Authors.  All rights reserved.
// Please see the AUTHORS file for details.  Use of this source code is governed
// by a BSD license that can be found in the LICENSE file.

#include "scalloc.h"

#include <errno.h>
#include <string.h>

#include "allocators/block_pool.h"
#include "allocators/large_allocator.h"
#include "allocators/small_allocator.h"
#include "allocators/span_pool.h"
#include "assert.h"
#include "common.h"
#include "distributed_queue.h"
#include "override.h"
#include "scalloc_arenas.h"
#include "scalloc_guard.h"
#include "size_classes_raw.h"
#include "size_classes.h"
#include "thread_cache.h"
#include "utils.h"

#ifdef PROFILER_ON
#include "profiler.h"
#endif  // PROFILER_ON

namespace scalloc {

cache_aligned Arena InternalArena;

cache_aligned Arena SmallArena;

cache_aligned const uint64_t ClassToObjects[] = {
#define SIZE_CLASS(a, b, c, d) (d),
SIZE_CLASSES
#undef SIZE_CLASS
};

cache_aligned const uint64_t ClassToSize[] = {
#define SIZE_CLASS(a, b, c, d) (b),
SIZE_CLASSES
#undef SIZE_CLASS
};

cache_aligned const uint64_t ClassToSpanSize[] = {
#define SIZE_CLASS(a, b, c, d) (c),
SIZE_CLASSES
#undef SIZE_CLASS
};

}  // namespace scalloc

static int scallocguard_refcount = 0;
ScallocGuard::ScallocGuard() {
  if (scallocguard_refcount++ == 0) {
    ReplaceSystemAlloc();

    scalloc::InternalArena.Init(kInternalSpace);
    scalloc::SmallArena.Init(kSmallSpace);
    DistributedQueue::InitModule();
    scalloc::SpanPool::InitModule();
    scalloc::BlockPool::InitModule();
    scalloc::SmallAllocator::InitModule();
    scalloc::ThreadCache::InitModule();

    free(malloc(1));

#ifdef PROFILER_ON
    scalloc::GlobalProfiler::Instance().Init();
    scalloc::Profiler::Enable();
#endif  // PROFILER_ON
  }
}

ScallocGuard::~ScallocGuard() {
  if (--scallocguard_refcount == 0) {
  }
}

static ScallocGuard StartupExitHook;

namespace scalloc {

void* malloc(const size_t size) {
  void* p;
  if (LIKELY(size <= kMaxMediumSize && SmallAllocator::Enabled())) {
    p = ThreadCache::GetCache().Allocate(size);
  } else {
    p = LargeAllocator::Alloc(size);
  }
  if (UNLIKELY(p == NULL)) {
    errno = ENOMEM;
  }
  return p;
}

void free(void* p) {
  if (UNLIKELY(p == NULL)) {
    return;
  }
  if (SmallArena.Contains(p)) {
    ThreadCache::GetCache().Free(p, reinterpret_cast<SpanHeader*>(
        SpanHeader::GetFromObject(p)));
  } else {
    LargeAllocator::Free(reinterpret_cast<LargeObjectHeader*>(
        LargeObjectHeader::GetFromObject(p)));
  }
  return;
}

void* calloc(size_t nmemb, size_t size) {
  const size_t malloc_size = nmemb * size;
  if (size != 0 && (malloc_size / size) != nmemb) {
    return NULL;
  }
  void* result = malloc(malloc_size);  // also sets errno
  if (result != NULL) {
    memset(result, 0, malloc_size);
  }
  return result;
}

void* realloc(void* ptr, size_t size) {
  if (ptr == NULL) {
    return malloc(size);
  }
  void* new_ptr;
  size_t old_size;
  if (scalloc::SmallArena.Contains(ptr)) {
    old_size = ClassToSize[reinterpret_cast<SpanHeader*>(
        SpanHeader::GetFromObject(ptr))->size_class];
  } else {
    old_size =
        reinterpret_cast<LargeObjectHeader*>(
            LargeObjectHeader::GetFromObject(ptr))->size
        - sizeof(LargeObjectHeader);
  }
  if (size <= old_size) {
    return ptr;
  } else {
    new_ptr = malloc(size);
    if (LIKELY(new_ptr != NULL)) {
      memcpy(new_ptr, ptr, old_size);
      free(ptr);
    }
  }
  return new_ptr;
}

int posix_memalign(void** ptr, size_t align, size_t size) {
  if (UNLIKELY(size == 0)) {                    // Return free-able pointer if
    *ptr = NULL;                                // size == 0.
    return 0;
  }

  const size_t size_needed = align + size;

  if (UNLIKELY(!utils::IsPowerOfTwo(align)) ||  // Power of 2 requirement.
      size_needed < size) {                     // Overflow check.
    return EINVAL;
  }

  uintptr_t start = reinterpret_cast<uintptr_t>(malloc(size_needed));
  if (UNLIKELY(start == 0)) {
    return ENOMEM;
  }

  if (SmallArena.Contains(reinterpret_cast<void*>(start))) {
    start += (start % align);
    ScallocAssert((start % align) == 0);
  } else {
    LargeObjectHeader* original_header = LargeObjectHeader::GetFromObject(
        reinterpret_cast<void*>(start));
    start += (start % align);
    if ((start % kPageSize) == 0) {
      uintptr_t new_hdr_adr = start - kPageSize;
      if (new_hdr_adr != reinterpret_cast<uintptr_t>(original_header)) {
        reinterpret_cast<LargeObjectHeader*>(new_hdr_adr)->Reset(0);
        reinterpret_cast<LargeObjectHeader*>(new_hdr_adr)->fwd =
        original_header;
      }
    }
  }
  *ptr = reinterpret_cast<void*>(start);
  return 0;
}

void* memalign(size_t __alignment, size_t __size) {
  void* mem;
  if (posix_memalign(&mem, __alignment, __size)) {
    return NULL;
  }
  return mem;
}

void* valloc(size_t __size) {
  return memalign(kPageSize, __size);
}

void* pvalloc(size_t __size) {
  return memalign(kPageSize, utils::PadSize(__size, kPageSize));
}

void malloc_stats(void) {}

int mallopt(int cmd, int value) {
  return 0;
}

bool Ours(const void* p) {
  return SmallArena.Contains(const_cast<void*>(p)) || LargeAllocator::Owns(p);
}

}  // namespace scalloc

#ifndef __THROW
#define __THROW
#endif

extern "C" {
void* scalloc_malloc(size_t size) __THROW {
  return scalloc::malloc(size);
}

void scalloc_free(void* p) __THROW {
  scalloc::free(p);
}

void* scalloc_calloc(size_t nmemb, size_t size) __THROW {
  return scalloc::calloc(nmemb, size);
}

void* scalloc_realloc(void* ptr, size_t size) __THROW {
  return scalloc::realloc(ptr, size);
}

void* scalloc_memalign(size_t __alignment, size_t __size) __THROW {
  return scalloc::memalign(__alignment, __size);
}

int scalloc_posix_memalign(void** ptr, size_t align, size_t size) __THROW {
  return scalloc::posix_memalign(ptr, align, size);
}

void* scalloc_valloc(size_t __size) __THROW {
  return scalloc::valloc(__size);
}

void* scalloc_pvalloc(size_t __size) __THROW {
  return scalloc::pvalloc(__size);
}

void scalloc_malloc_stats() __THROW {
  scalloc::malloc_stats();
}

int scalloc_mallopt(int cmd, int value) __THROW {
  return scalloc::mallopt(cmd, value);
}
}
<commit_msg>Fix alignment in posix_memalign.<commit_after>// Copyright (c) 2012-2013, the scalloc Project Authors.  All rights reserved.
// Please see the AUTHORS file for details.  Use of this source code is governed
// by a BSD license that can be found in the LICENSE file.

#include "scalloc.h"

#include <errno.h>
#include <string.h>

#include "allocators/block_pool.h"
#include "allocators/large_allocator.h"
#include "allocators/small_allocator.h"
#include "allocators/span_pool.h"
#include "assert.h"
#include "common.h"
#include "distributed_queue.h"
#include "override.h"
#include "scalloc_arenas.h"
#include "scalloc_guard.h"
#include "size_classes_raw.h"
#include "size_classes.h"
#include "thread_cache.h"
#include "utils.h"

#ifdef PROFILER_ON
#include "profiler.h"
#endif  // PROFILER_ON

namespace scalloc {

cache_aligned Arena InternalArena;

cache_aligned Arena SmallArena;

cache_aligned const uint64_t ClassToObjects[] = {
#define SIZE_CLASS(a, b, c, d) (d),
SIZE_CLASSES
#undef SIZE_CLASS
};

cache_aligned const uint64_t ClassToSize[] = {
#define SIZE_CLASS(a, b, c, d) (b),
SIZE_CLASSES
#undef SIZE_CLASS
};

cache_aligned const uint64_t ClassToSpanSize[] = {
#define SIZE_CLASS(a, b, c, d) (c),
SIZE_CLASSES
#undef SIZE_CLASS
};

}  // namespace scalloc

static int scallocguard_refcount = 0;
ScallocGuard::ScallocGuard() {
  if (scallocguard_refcount++ == 0) {
    ReplaceSystemAlloc();

    scalloc::InternalArena.Init(kInternalSpace);
    scalloc::SmallArena.Init(kSmallSpace);
    DistributedQueue::InitModule();
    scalloc::SpanPool::InitModule();
    scalloc::BlockPool::InitModule();
    scalloc::SmallAllocator::InitModule();
    scalloc::ThreadCache::InitModule();

    free(malloc(1));

#ifdef PROFILER_ON
    scalloc::GlobalProfiler::Instance().Init();
    scalloc::Profiler::Enable();
#endif  // PROFILER_ON
  }
}

ScallocGuard::~ScallocGuard() {
  if (--scallocguard_refcount == 0) {
  }
}

static ScallocGuard StartupExitHook;

namespace scalloc {

void* malloc(const size_t size) {
  void* p;
  if (LIKELY(size <= kMaxMediumSize && SmallAllocator::Enabled())) {
    p = ThreadCache::GetCache().Allocate(size);
  } else {
    p = LargeAllocator::Alloc(size);
  }
  if (UNLIKELY(p == NULL)) {
    errno = ENOMEM;
  }
  return p;
}

void free(void* p) {
  if (UNLIKELY(p == NULL)) {
    return;
  }
  if (SmallArena.Contains(p)) {
    ThreadCache::GetCache().Free(p, reinterpret_cast<SpanHeader*>(
        SpanHeader::GetFromObject(p)));
  } else {
    LargeAllocator::Free(reinterpret_cast<LargeObjectHeader*>(
        LargeObjectHeader::GetFromObject(p)));
  }
  return;
}

void* calloc(size_t nmemb, size_t size) {
  const size_t malloc_size = nmemb * size;
  if (size != 0 && (malloc_size / size) != nmemb) {
    return NULL;
  }
  void* result = malloc(malloc_size);  // also sets errno
  if (result != NULL) {
    memset(result, 0, malloc_size);
  }
  return result;
}

void* realloc(void* ptr, size_t size) {
  if (ptr == NULL) {
    return malloc(size);
  }
  void* new_ptr;
  size_t old_size;
  if (scalloc::SmallArena.Contains(ptr)) {
    old_size = ClassToSize[reinterpret_cast<SpanHeader*>(
        SpanHeader::GetFromObject(ptr))->size_class];
  } else {
    old_size =
        reinterpret_cast<LargeObjectHeader*>(
            LargeObjectHeader::GetFromObject(ptr))->size
        - sizeof(LargeObjectHeader);
  }
  if (size <= old_size) {
    return ptr;
  } else {
    new_ptr = malloc(size);
    if (LIKELY(new_ptr != NULL)) {
      memcpy(new_ptr, ptr, old_size);
      free(ptr);
    }
  }
  return new_ptr;
}

int posix_memalign(void** ptr, size_t align, size_t size) {
  if (UNLIKELY(size == 0)) {                    // Return free-able pointer if
    *ptr = NULL;                                // size == 0.
    return 0;
  }

  const size_t size_needed = align + size;

  if (UNLIKELY(!utils::IsPowerOfTwo(align)) ||  // Power of 2 requirement.
      size_needed < size) {                     // Overflow check.
    return EINVAL;
  }

  uintptr_t start = reinterpret_cast<uintptr_t>(malloc(size_needed));
  if (UNLIKELY(start == 0)) {
    return ENOMEM;
  }

  if (SmallArena.Contains(reinterpret_cast<void*>(start))) {
    start += align - (start % align);
    ScallocAssert((start % align) == 0);
  } else {
    LargeObjectHeader* original_header = LargeObjectHeader::GetFromObject(
        reinterpret_cast<void*>(start));
    start += align - (start % align);
    if ((start % kPageSize) == 0) {
      uintptr_t new_hdr_adr = start - kPageSize;
      if (new_hdr_adr != reinterpret_cast<uintptr_t>(original_header)) {
        reinterpret_cast<LargeObjectHeader*>(new_hdr_adr)->Reset(0);
        reinterpret_cast<LargeObjectHeader*>(new_hdr_adr)->fwd =
        original_header;
      }
    }
  }
  *ptr = reinterpret_cast<void*>(start);
  return 0;
}

void* memalign(size_t __alignment, size_t __size) {
  void* mem;
  if (posix_memalign(&mem, __alignment, __size)) {
    return NULL;
  }
  return mem;
}

void* valloc(size_t __size) {
  return memalign(kPageSize, __size);
}

void* pvalloc(size_t __size) {
  return memalign(kPageSize, utils::PadSize(__size, kPageSize));
}

void malloc_stats(void) {}

int mallopt(int cmd, int value) {
  return 0;
}

bool Ours(const void* p) {
  return SmallArena.Contains(const_cast<void*>(p)) || LargeAllocator::Owns(p);
}

}  // namespace scalloc

#ifndef __THROW
#define __THROW
#endif

extern "C" {
void* scalloc_malloc(size_t size) __THROW {
  return scalloc::malloc(size);
}

void scalloc_free(void* p) __THROW {
  scalloc::free(p);
}

void* scalloc_calloc(size_t nmemb, size_t size) __THROW {
  return scalloc::calloc(nmemb, size);
}

void* scalloc_realloc(void* ptr, size_t size) __THROW {
  return scalloc::realloc(ptr, size);
}

void* scalloc_memalign(size_t __alignment, size_t __size) __THROW {
  return scalloc::memalign(__alignment, __size);
}

int scalloc_posix_memalign(void** ptr, size_t align, size_t size) __THROW {
  return scalloc::posix_memalign(ptr, align, size);
}

void* scalloc_valloc(size_t __size) __THROW {
  return scalloc::valloc(__size);
}

void* scalloc_pvalloc(size_t __size) __THROW {
  return scalloc::pvalloc(__size);
}

void scalloc_malloc_stats() __THROW {
  scalloc::malloc_stats();
}

int scalloc_mallopt(int cmd, int value) __THROW {
  return scalloc::mallopt(cmd, value);
}
}
<|endoftext|>


<commit_before>#include "debug.h"
#include "scanner.h"

namespace flora {

// Public Methods

Scanner::Scanner() {
  state_ = Scanner::State::Uninitialized;
  stream_ = nullptr;
  peek = 0;
}

Scanner::~Scanner() {

}

void Scanner::Initialize(CharacterStream *stream) {
  stream_ = stream;
  state_ = Scanner::State::Running;
  peek = stream->Advance();
}

Token Scanner::Advance() {
  switch (state_) {
  case Scanner::State::Uninitialized:
    ReportScannerError("the scanner is uninitialized");
    return Token::Illegal;

  case Scanner::State::Running:
    return Scan();

  case Scanner::State::Recording: {
    Token token = Scan();
    records_.push(std::make_pair(token, literal_));
    return token;
  }

  case Scanner::State::Restoring: {
    // Sequeeze the first recorded token
    std::pair<Token, std::string> &token = records_.front();
    records_.pop();
    // Check if no more recorded tokens
    if (records_.empty())
      state_ = Scanner::State::Running;
    SetTokenLiteral(token.second);
    return token.first;
  }

  case Scanner::State::End:
    return Token::EndOfSource;

  case Scanner::State::Error:
    return Token::Illegal;
  }
  UNREACHABLE();
}

void Scanner::SaveBookmark() {
  // Clean the recording queue
  while (!records_.empty())
    records_.pop();
  // Set state to recording
  state_ = Scanner::State::Recording;
}

void Scanner::LoadBookmark() {
  // Set state to restoring
  state_ = Scanner::State::Restoring;
}

void Scanner::ClearBookmark() {
  // Clean the recording queue
  while (!records_.empty())
    records_.pop();
  // Set state to running
  state_ = Scanner::State::Running;
}

const std::string& Scanner::GetTokenLiteral() {
  return literal_;
}

// Private methods

char32_t Scanner::Next() {
  char32_t save = peek;
  peek = stream_->Advance();
  return save;
}

bool Scanner::Match(char32_t expected) {
  if (expected == peek) {
    peek = stream_->Advance();
    return true;
  }
  return false;
}

void Scanner::SetTokenLiteral(const char *literal) {
  literal_.assign(literal);
}

void Scanner::SetTokenLiteral(std::string &literal) {
  literal_ = std::move(literal);
}

void Scanner::SetTokenLiteral(char literal) {
  literal_.clear();
  literal_.push_back(literal);
}

void Scanner::ClearTokenLiteral() {
  literal_.clear();
}

void Scanner::ReportScannerError(const char *message) {
  state_ = Scanner::State::Error;
  SetTokenLiteral(message);
}

void Scanner::MarkEndOfSource() {
  state_ = Scanner::State::End;
}

Token Scanner::Scan() {
  DEBUG_LOG("Scanning...");
  ClearTokenLiteral();
  char32_t ch;
  while (true) {
    switch (ch = Next()) {
    case character::EOS:
      MarkEndOfSource();
      return Token::EndOfSource;
    case '\n':
    case ' ':
    case '\t':
      continue;
    case '(': return Token::LeftParenthesis;
    case ')': return Token::RightParenthesis;
    case '[': return Token::LeftBracket;
    case ']': return Token::RightBracket;
    case '{': return Token::LeftBrace;
    case '}': return Token::RightBrace;
    case ':': return Token::Colon;
    case ';': return Token::Semicolon;
    case '~': return Token::BitwiseNot;
    case '?': return Token::Conditional;
    case ',': return Token::Comma;
    case '.': // . ...
      if (Match('.')) {
        if (Match('.')) {
          return Token::Ellipsis;
        } else {
          ReportScannerError("illegal token");
          return Token::Illegal;
        }
      }
      return Token::Period;
    case '&': // & && &=
      if (Match('&')) {
        return Token::LogicalAnd;
      } else if (Match('=')) {
        return Token::AssignmentBitwiseAnd;
      } else {
        return Token::BitwiseAnd;
      }
    case '|': // | || |=
      if (Match('|')) {
        return Token::LogicalOr;
      } else if (Match('=')) {
        return Token::AssignmentBitwiseOr;
      } else {
        return Token::BitwiseOr;
      }
    case '^': // ^ ^=
      return Match('=') ? Token::AssignmentBitwiseXor : Token::BitwiseXor;
    case '<': // < << <= <<=
      if (Match('<')) {
        return Match('=') ? Token::AssignmentShiftLeft : Token::ShiftLeft;
      } else if (Match('=')) {
        return Token::LessThanOrEqual;
      } else {
        return Token::LessThan;
      }
    case '>': // > >> >= >>=
      if (Match('>')) {
        return Match('=') ? Token::AssignmentShiftRight : Token::ShiftRight;
      } else if (Match('=')) {
        return Token::GreaterThanOrEqual;
      } else {
        return Token::GreaterThan;
      }
    case '!': // ! !=
      return Match('=') ? Token::NotEqual : Token::LogicalNot;
    case '=': // = == =>
      if (Match('>')) {
        return Token::Arrow;
      } else if (Match('=')) {
        return Token::Equal;
      } else {
        return Token::Assignment;
      }
    case '+': // + ++ +=
      if (Match('+')) {
        return Token::Increment;
      } else if (Match('=')) {
        return Token::AssignmentAddition;
      } else {
        return Token::Addition;
      }
    case '-': // - -- -=
      if (Match('-')) {
        return Token::Decrement;
      } else if (Match('=')) {
        return Token::AssignmentSubtraction;
      } else {
        return Token::Subtraction;
      }
    case '*': // * *=
      return Match('=') ? Token::AssignmentMultiplication:Token::Multiplication;
    case '/': // / /= /* multiple line comment */ // single line comment
      if (Match('=')) {
        return Token::AssignmentDivision;
      } else if (Match('*')) {
        SkipMultipleLineComment();
      } else if (Match('/')) {
        SkipSingleLineComment();
      } else {
        return Token::Division;
      }
      continue;
    case '%': // % %=
      return Match('=') ? Token::AssignmentModulus : Token::Modulus;
    case '"': // string literal
      return ScanStringLiteral();
    case '\'': // character literal
      return ScanCharacterLiteral();
    default:
      if (character::IsIdentifierStart(ch)) {
        return ScanIdentifierOrKeyword(ch);
      } else if (character::IsDecimalDigit(ch)) {
        return ScanIntegerOrRealNumber(ch);
      } else {
        ReportScannerError("unknown token");
        return Token::Illegal;
      }
    }
  }
}

bool Scanner::SkipMultipleLineComment() {
  int cascade = 1;
  char ch;
  while (true) {
    ch = Next();
    if (ch == '/') {
      if (peek == '*') {
        Next();
        cascade++;
      }
    } else if (ch == '*') {
      if (peek == '/') {
        Next();
        cascade--;
        if (cascade == 0) break;
      }
    } else if (ch == character::EOS) {
      ReportScannerError("unexpected end of source in multiple line comment");
      return false;
    }
  }
  return true;
}

void Scanner::SkipSingleLineComment() {
  while (!character::IsLineFeed(peek) && peek != character::EOS)
    Next();
}

Token Scanner::ScanStringLiteral() {
  std::string literal;
  char32_t ch;
  while (true) {
    ch = Next();
    if (ch == character::EOS) {
      ReportScannerError("unexpected EOF in string literal");
      return Token::Illegal;
    } else if (ch == '\\') {
      ch = ScanCharacterEscape();
      if (ch == character::EOS)
        return Token::Illegal;
      literal.push_back(ch);
    } else if (ch == '"') {
      break;
    } else {
      literal.push_back(ch);
    }
  }
  SetTokenLiteral(literal);
  return Token::String;
}

Token Scanner::ScanCharacterLiteral() {
  char32_t literal = Next();
  if (literal == character::EOS) {
    ReportScannerError("unexpected EOF in character literal");
    return Token::Illegal;
  } else if (literal == '\\') {
    literal = ScanCharacterEscape();
    if (literal == character::EOS)
      return Token::Illegal;
  }
  // to ensure that there is only one character in literal
  if (Next() != '\'') {
    ReportScannerError("too more character in literal");
    return Token::Illegal;
  }
  SetTokenLiteral(literal);
  return Token::Character;
}

char32_t Scanner::ScanCharacterEscape() {
  char32_t codepoint = 0;
  switch (peek) {
  case 'n': return '\n';
  case 'r': return '\r';
  case 't': return '\t';
  case '\\': return '\\';
  case '\'': return '\'';
  case '\"': return '\"';
  case 'u':
    Next();
    while (character::IsDecimalDigit(peek)) {
      codepoint *= 10;
      codepoint += peek - '0';
      Next();
    }
    return codepoint;
  case 'x':
    Next();
    while (character::IsHexDigit(peek)) {
      codepoint *= 16;
      if (character::IsDecimalDigit(peek)) {
        codepoint += peek - '0';
      } else {
        codepoint += 10 + character::AsciiToLowerCase(peek) - 'a';
      }
      Next();
    }
    return codepoint;
  default:
    ReportScannerError("illegal character escape");
    return character::EOS;
  }
}

Token Scanner::ScanIdentifierOrKeyword(char32_t firstChar) {
  std::string identifier;
  identifier.push_back(firstChar);

  while (character::IsIdentifierBody(peek)) {
    identifier.push_back(Next());
  }
  Token token = Tokens::LookupKeyword(identifier);
  if (token == Token::Identifier)
    SetTokenLiteral(identifier);
  return token;
}

Token Scanner::ScanIntegerOrRealNumber(char32_t firstChar) {
  // There are 4 kinds of integer:
  // (1) Hexidecimal integer
  // (2) Decimal integer
  // (3) Octal integer
  // (4) Binary integer
  // (1), (3) and (4) has a prefix, so we can easily dintinguish them
  std::string num;
  if (firstChar == '0') {
    if (peek == 'x') {
      Next();
      return ScanHexInteger();
    } else if (peek == 'o') {
      Next();
      return ScanOctalInteger();
    } else if (peek == 'b') {
      Next();
      return ScanBinaryInteger();
    }
  }
  num.push_back(firstChar);
  // Scan the integral part
  while (character::IsDecimalDigit(peek)) {
    num.push_back(firstChar);
  }
  // Real number
  if (peek == '.' || character::AsciiToLowerCase(peek) == 'e') {
    return ScanRealNumber(&num);
  }
  // Integer
  SetTokenLiteral(num);
  return Token::Integer;
}

Token Scanner::ScanRealNumber(const std::string *integral_part,
                              bool scanned_period) {
  std::string num;
  if (integral_part) {
    num = *integral_part;
  } else {
    num.push_back('0');
  }
  // Fraction part
  if (Match('.')) {
    while (character::IsDecimalDigit(peek)) {
      num.push_back(Next());
    }
  }
  // Exponent part
  if (peek == 'E' || peek == 'e') {
    num.push_back(Next());
    if (peek == '+' || peek == '-')
      num.push_back(Next());
    // An error circumstance: 1.234E
    if (!character::IsDecimalDigit(peek)) {
      ReportScannerError("unexpected end of source in real number literal");
      return Token::Illegal;
    }
    while (character::IsDecimalDigit(peek)) {
      num.push_back(Next());
    }
  }
  SetTokenLiteral(num);
  return Token::RealNumber;
}

#define SCAN_INTEGER(base, ch, checker)\
  Token Scanner::Scan##base##Integer() {\
    std::string num;\
    num.push_back(ch);\
    if (!checker(peek)) {\
      ReportScannerError("unexpected end of source in integer literal");\
      return Token::Illegal;\
    }\
    while (checker(peek))\
      num.push_back(Next());\
    SetTokenLiteral(num);\
    return Token::Integer;\
  }

SCAN_INTEGER(Hex, 'x', character::IsHexDigit)
SCAN_INTEGER(Octal, 'o', character::IsOctalDigit)
SCAN_INTEGER(Binary, 'b', character::IsBinaryDigit)

}<commit_msg>Remove debug print...<commit_after>#include "debug.h"
#include "scanner.h"

namespace flora {

// Public Methods

Scanner::Scanner() {
  state_ = Scanner::State::Uninitialized;
  stream_ = nullptr;
  peek = 0;
}

Scanner::~Scanner() {

}

void Scanner::Initialize(CharacterStream *stream) {
  stream_ = stream;
  state_ = Scanner::State::Running;
  peek = stream->Advance();
}

Token Scanner::Advance() {
  switch (state_) {
  case Scanner::State::Uninitialized:
    ReportScannerError("the scanner is uninitialized");
    return Token::Illegal;

  case Scanner::State::Running:
    return Scan();

  case Scanner::State::Recording: {
    Token token = Scan();
    records_.push(std::make_pair(token, literal_));
    return token;
  }

  case Scanner::State::Restoring: {
    // Sequeeze the first recorded token
    std::pair<Token, std::string> &token = records_.front();
    records_.pop();
    // Check if no more recorded tokens
    if (records_.empty())
      state_ = Scanner::State::Running;
    SetTokenLiteral(token.second);
    return token.first;
  }

  case Scanner::State::End:
    return Token::EndOfSource;

  case Scanner::State::Error:
    return Token::Illegal;
  }
  UNREACHABLE();
}

void Scanner::SaveBookmark() {
  // Clean the recording queue
  while (!records_.empty())
    records_.pop();
  // Set state to recording
  state_ = Scanner::State::Recording;
}

void Scanner::LoadBookmark() {
  // Set state to restoring
  state_ = Scanner::State::Restoring;
}

void Scanner::ClearBookmark() {
  // Clean the recording queue
  while (!records_.empty())
    records_.pop();
  // Set state to running
  state_ = Scanner::State::Running;
}

const std::string& Scanner::GetTokenLiteral() {
  return literal_;
}

// Private methods

char32_t Scanner::Next() {
  char32_t save = peek;
  peek = stream_->Advance();
  return save;
}

bool Scanner::Match(char32_t expected) {
  if (expected == peek) {
    peek = stream_->Advance();
    return true;
  }
  return false;
}

void Scanner::SetTokenLiteral(const char *literal) {
  literal_.assign(literal);
}

void Scanner::SetTokenLiteral(std::string &literal) {
  literal_ = std::move(literal);
}

void Scanner::SetTokenLiteral(char literal) {
  literal_.clear();
  literal_.push_back(literal);
}

void Scanner::ClearTokenLiteral() {
  literal_.clear();
}

void Scanner::ReportScannerError(const char *message) {
  state_ = Scanner::State::Error;
  SetTokenLiteral(message);
}

void Scanner::MarkEndOfSource() {
  state_ = Scanner::State::End;
}

Token Scanner::Scan() {
  ClearTokenLiteral();
  char32_t ch;
  while (true) {
    switch (ch = Next()) {
    case character::EOS:
      MarkEndOfSource();
      return Token::EndOfSource;
    case '\n':
    case ' ':
    case '\t':
      continue;
    case '(': return Token::LeftParenthesis;
    case ')': return Token::RightParenthesis;
    case '[': return Token::LeftBracket;
    case ']': return Token::RightBracket;
    case '{': return Token::LeftBrace;
    case '}': return Token::RightBrace;
    case ':': return Token::Colon;
    case ';': return Token::Semicolon;
    case '~': return Token::BitwiseNot;
    case '?': return Token::Conditional;
    case ',': return Token::Comma;
    case '.': // . ...
      if (Match('.')) {
        if (Match('.')) {
          return Token::Ellipsis;
        } else {
          ReportScannerError("illegal token");
          return Token::Illegal;
        }
      }
      return Token::Period;
    case '&': // & && &=
      if (Match('&')) {
        return Token::LogicalAnd;
      } else if (Match('=')) {
        return Token::AssignmentBitwiseAnd;
      } else {
        return Token::BitwiseAnd;
      }
    case '|': // | || |=
      if (Match('|')) {
        return Token::LogicalOr;
      } else if (Match('=')) {
        return Token::AssignmentBitwiseOr;
      } else {
        return Token::BitwiseOr;
      }
    case '^': // ^ ^=
      return Match('=') ? Token::AssignmentBitwiseXor : Token::BitwiseXor;
    case '<': // < << <= <<=
      if (Match('<')) {
        return Match('=') ? Token::AssignmentShiftLeft : Token::ShiftLeft;
      } else if (Match('=')) {
        return Token::LessThanOrEqual;
      } else {
        return Token::LessThan;
      }
    case '>': // > >> >= >>=
      if (Match('>')) {
        return Match('=') ? Token::AssignmentShiftRight : Token::ShiftRight;
      } else if (Match('=')) {
        return Token::GreaterThanOrEqual;
      } else {
        return Token::GreaterThan;
      }
    case '!': // ! !=
      return Match('=') ? Token::NotEqual : Token::LogicalNot;
    case '=': // = == =>
      if (Match('>')) {
        return Token::Arrow;
      } else if (Match('=')) {
        return Token::Equal;
      } else {
        return Token::Assignment;
      }
    case '+': // + ++ +=
      if (Match('+')) {
        return Token::Increment;
      } else if (Match('=')) {
        return Token::AssignmentAddition;
      } else {
        return Token::Addition;
      }
    case '-': // - -- -=
      if (Match('-')) {
        return Token::Decrement;
      } else if (Match('=')) {
        return Token::AssignmentSubtraction;
      } else {
        return Token::Subtraction;
      }
    case '*': // * *=
      return Match('=') ? Token::AssignmentMultiplication:Token::Multiplication;
    case '/': // / /= /* multiple line comment */ // single line comment
      if (Match('=')) {
        return Token::AssignmentDivision;
      } else if (Match('*')) {
        SkipMultipleLineComment();
      } else if (Match('/')) {
        SkipSingleLineComment();
      } else {
        return Token::Division;
      }
      continue;
    case '%': // % %=
      return Match('=') ? Token::AssignmentModulus : Token::Modulus;
    case '"': // string literal
      return ScanStringLiteral();
    case '\'': // character literal
      return ScanCharacterLiteral();
    default:
      if (character::IsIdentifierStart(ch)) {
        return ScanIdentifierOrKeyword(ch);
      } else if (character::IsDecimalDigit(ch)) {
        return ScanIntegerOrRealNumber(ch);
      } else {
        ReportScannerError("unknown token");
        return Token::Illegal;
      }
    }
  }
}

bool Scanner::SkipMultipleLineComment() {
  int cascade = 1;
  char ch;
  while (true) {
    ch = Next();
    if (ch == '/') {
      if (peek == '*') {
        Next();
        cascade++;
      }
    } else if (ch == '*') {
      if (peek == '/') {
        Next();
        cascade--;
        if (cascade == 0) break;
      }
    } else if (ch == character::EOS) {
      ReportScannerError("unexpected end of source in multiple line comment");
      return false;
    }
  }
  return true;
}

void Scanner::SkipSingleLineComment() {
  while (!character::IsLineFeed(peek) && peek != character::EOS)
    Next();
}

Token Scanner::ScanStringLiteral() {
  std::string literal;
  char32_t ch;
  while (true) {
    ch = Next();
    if (ch == character::EOS) {
      ReportScannerError("unexpected EOF in string literal");
      return Token::Illegal;
    } else if (ch == '\\') {
      ch = ScanCharacterEscape();
      if (ch == character::EOS)
        return Token::Illegal;
      literal.push_back(ch);
    } else if (ch == '"') {
      break;
    } else {
      literal.push_back(ch);
    }
  }
  SetTokenLiteral(literal);
  return Token::String;
}

Token Scanner::ScanCharacterLiteral() {
  char32_t literal = Next();
  if (literal == character::EOS) {
    ReportScannerError("unexpected EOF in character literal");
    return Token::Illegal;
  } else if (literal == '\\') {
    literal = ScanCharacterEscape();
    if (literal == character::EOS)
      return Token::Illegal;
  }
  // to ensure that there is only one character in literal
  if (Next() != '\'') {
    ReportScannerError("too more character in literal");
    return Token::Illegal;
  }
  SetTokenLiteral(literal);
  return Token::Character;
}

char32_t Scanner::ScanCharacterEscape() {
  char32_t codepoint = 0;
  switch (peek) {
  case 'n': return '\n';
  case 'r': return '\r';
  case 't': return '\t';
  case '\\': return '\\';
  case '\'': return '\'';
  case '\"': return '\"';
  case 'u':
    Next();
    while (character::IsDecimalDigit(peek)) {
      codepoint *= 10;
      codepoint += peek - '0';
      Next();
    }
    return codepoint;
  case 'x':
    Next();
    while (character::IsHexDigit(peek)) {
      codepoint *= 16;
      if (character::IsDecimalDigit(peek)) {
        codepoint += peek - '0';
      } else {
        codepoint += 10 + character::AsciiToLowerCase(peek) - 'a';
      }
      Next();
    }
    return codepoint;
  default:
    ReportScannerError("illegal character escape");
    return character::EOS;
  }
}

Token Scanner::ScanIdentifierOrKeyword(char32_t firstChar) {
  std::string identifier;
  identifier.push_back(firstChar);

  while (character::IsIdentifierBody(peek)) {
    identifier.push_back(Next());
  }
  Token token = Tokens::LookupKeyword(identifier);
  if (token == Token::Identifier)
    SetTokenLiteral(identifier);
  return token;
}

Token Scanner::ScanIntegerOrRealNumber(char32_t firstChar) {
  // There are 4 kinds of integer:
  // (1) Hexidecimal integer
  // (2) Decimal integer
  // (3) Octal integer
  // (4) Binary integer
  // (1), (3) and (4) has a prefix, so we can easily dintinguish them
  std::string num;
  if (firstChar == '0') {
    if (peek == 'x') {
      Next();
      return ScanHexInteger();
    } else if (peek == 'o') {
      Next();
      return ScanOctalInteger();
    } else if (peek == 'b') {
      Next();
      return ScanBinaryInteger();
    }
  }
  num.push_back(firstChar);
  // Scan the integral part
  while (character::IsDecimalDigit(peek)) {
    num.push_back(firstChar);
  }
  // Real number
  if (peek == '.' || character::AsciiToLowerCase(peek) == 'e') {
    return ScanRealNumber(&num);
  }
  // Integer
  SetTokenLiteral(num);
  return Token::Integer;
}

Token Scanner::ScanRealNumber(const std::string *integral_part,
                              bool scanned_period) {
  std::string num;
  if (integral_part) {
    num = *integral_part;
  } else {
    num.push_back('0');
  }
  // Fraction part
  if (Match('.')) {
    while (character::IsDecimalDigit(peek)) {
      num.push_back(Next());
    }
  }
  // Exponent part
  if (peek == 'E' || peek == 'e') {
    num.push_back(Next());
    if (peek == '+' || peek == '-')
      num.push_back(Next());
    // An error circumstance: 1.234E
    if (!character::IsDecimalDigit(peek)) {
      ReportScannerError("unexpected end of source in real number literal");
      return Token::Illegal;
    }
    while (character::IsDecimalDigit(peek)) {
      num.push_back(Next());
    }
  }
  SetTokenLiteral(num);
  return Token::RealNumber;
}

#define SCAN_INTEGER(base, ch, checker)\
  Token Scanner::Scan##base##Integer() {\
    std::string num;\
    num.push_back(ch);\
    if (!checker(peek)) {\
      ReportScannerError("unexpected end of source in integer literal");\
      return Token::Illegal;\
    }\
    while (checker(peek))\
      num.push_back(Next());\
    SetTokenLiteral(num);\
    return Token::Integer;\
  }

SCAN_INTEGER(Hex, 'x', character::IsHexDigit)
SCAN_INTEGER(Octal, 'o', character::IsOctalDigit)
SCAN_INTEGER(Binary, 'b', character::IsBinaryDigit)

}<|endoftext|>