<commit_before>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	pqxx/transaction_base.hxx
 *
 *   DESCRIPTION
 *      common code and definitions for the transaction classes.
 *   pqxx::transaction_base defines the interface for any abstract class that
 *   represents a database transaction
 *   DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transaction_base instead.
 *
 * 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-public.hxx"
#include "pqxx/compiler-internal-pre.hxx"

/* End-user programs need not include this file, unless they define their own
 * transaction classes.  This is not something the typical program should want
 * to do.
 *
 * However, reading this file is worthwhile because it defines the public
 * interface for the available transaction classes such as transaction and
 * nontransaction.
 */

#include "pqxx/connection_base"
#include "pqxx/isolation"
#include "pqxx/result"

/* Methods tested in eg. self-test program test001 are marked with "//[t1]"
 */

namespace pqxx
{
class connection_base;
class transaction_base;

namespace internal
{
class PQXX_LIBEXPORT transactionfocus : public virtual namedclass
{
public:
  explicit transactionfocus(transaction_base &t) :
    namedclass("transactionfocus"),
    m_Trans(t),
    m_registered(false)
  {
  }

protected:
  void register_me();
  void unregister_me() throw ();
  void reg_pending_error(const PGSTD::string &) throw ();
  bool registered() const throw () { return m_registered; }

  transaction_base &m_Trans;

private:
  bool m_registered;

  /// Not allowed
  transactionfocus();
  /// Not allowed
  transactionfocus(const transactionfocus &);
  /// Not allowed
  transactionfocus &operator=(const transactionfocus &);
};

} // namespace internal

/// Interface definition (and common code) for "transaction" classes.
/**
 * @addtogroup transaction Transaction classes
 * All database access must be channeled through one of these classes for
 * safety, although not all implementations of this interface need to provide
 * full transactional integrity.
 *
 * Several implementations of this interface are shipped with libpqxx, including
 * the plain transaction class, the entirely unprotected nontransaction, and the
 * more cautions robusttransaction.
 */
class PQXX_LIBEXPORT transaction_base : public virtual internal::namedclass
{
public:
  /// If nothing else is known, our isolation level is at least read_committed
  typedef isolation_traits<read_committed> isolation_tag;

  virtual ~transaction_base() =0;					//[t1]

  /// Commit the transaction
  /** Unless this function is called explicitly, the transaction will not be
   * committed (actually the nontransaction implementation breaks this rule,
   * hence the name).
   *
   * Once this function returns, the whole transaction will typically be
   * irrevocably completed in the database.  There is also, however, a minute
   * risk that the connection to the database may be lost at just the wrong
   * moment.  In that case, libpqxx may be unable to determine whether the
   * transaction was completed or aborted and an in_doubt_error will be thrown
   * to make this fact known to the caller.  The robusttransaction
   * implementation takes some special precautions to reduce this risk.
   */
  void commit();							//[t1]

  /// Abort the transaction
  /** No special effort is required to call this function; it will be called
   * implicitly when the transaction is destructed.
   */
  void abort();								//[t10]

  /**
   * @addtogroup escaping String escaping
   */
  //@{
  /// Escape string for use as SQL string literal in this transaction
  PGSTD::string esc(const char str[]) const;				//[t90]
  /// Escape string for use as SQL string literal in this transaction
  PGSTD::string esc(const char str[], size_t maxlen) const		//[t90]
	{ return m_Conn.esc(str,maxlen); }
  /// Escape string for use as SQL string literal in this transaction
  PGSTD::string esc(const PGSTD::string &) const;			//[t90]

  /// Escape binary data for use as SQL string literal in this transaction
  /** Raw, binary data is treated differently from regular strings.  Binary
   * strings are never interpreted as text, so they may safely include byte
   * values or byte sequences that don't happen to represent valid characters in
   * the character encoding being used.
   *
   * The binary string does not stop at the first zero byte, as is the case with
   * textual strings.  Instead, they may contain zero bytes anywhere.  If it
   * happens to contain bytes that look like quote characters, or other things
   * that can disrupt their use in SQL queries, they will be replaced with
   * special escape sequences.
   */
  PGSTD::string esc_raw(const unsigned char str[], size_t len) const	//[t62]
	{ return m_Conn.esc_raw(str, len); }
  /// Escape binary data for use as SQL string literal in this transaction
  PGSTD::string esc_raw(const PGSTD::string &) const;			//[t62]
  //@}

  /// Execute query
  /** Perform a query in this transaction.
   * @param Query Query or command to execute
   * @param Desc Optional identifier for query, to help pinpoint SQL errors
   * @return A result set describing the query's or command's result
   */
  result exec(const PGSTD::string &Query,
	      const PGSTD::string &Desc=PGSTD::string());		//[t1]

  /**
   * @name Prepared statements
   */
  //@{
  /// Execute prepared statement
  /** Prepared statements are defined using the connection classes' prepare()
   * function, and continue to live on in the ongoing session regardless of
   * the context they were defined in (unless explicitly dropped using the
   * connection's unprepare() function).  Their execution however, like other
   * forms of query execution, requires a transaction object.
   *
   * Just like param_declaration is a helper class that lets you tag parameter
   * declarations onto the statement declaration, the invocation class returned
   * here lets you tag parameter values onto the call:
   *
   * @code
   * result run_mystatement(transaction_base &T)
   * {
   *   return T.prepared("mystatement")("param1")(2)()(4).exec();
   * }
   * @endcode
   *
   * Here, parameter 1 (written as "<tt>$1</tt>" in the statement's body) is a
   * string that receives the value "param1"; the second parameter is an integer
   * with the value 2; the third receives a null, making its type irrelevant;
   * and number 4 again is an integer.  The ultimate invocation of exec() is
   * essential; if you forget this, nothing happens.
   *
   * @warning Do not try to execute a prepared statement manually through direct
   * SQL statements.  This is likely not to work, and even if it does, is likely
   * to be slower than using the proper libpqxx functions.  Also, libpqxx knows
   * how to emulate prepared statements if some part of the infrastructure does
   * not support them.
   *
   * @warning Actual definition of the prepared statement on the backend may be
   * deferred until its first use, which means that any errors in the prepared
   * statement may not show up until it is executed--and perhaps abort the
   * ongoing transaction in the process.
   */
  prepare::invocation prepared(const PGSTD::string &statement);		//[t85]

  //@}

  /**
   * @name Error/warning output
   */
  //@{
  /// Have connection process warning message
  void process_notice(const char Msg[]) const				//[t14]
	{ m_Conn.process_notice(Msg); }
  /// Have connection process warning message
  void process_notice(const PGSTD::string &Msg) const			//[t14]
	{ m_Conn.process_notice(Msg); }
  //@}

  /// Connection this transaction is running in
  connection_base &conn() const { return m_Conn; }			//[t4]

  /// Set session variable in this connection
  /** The new value is typically forgotten if the transaction aborts.
   * Known exceptions to this rule are nontransaction, and PostgreSQL versions
   * prior to 7.3.  In the case of nontransaction, the set value will be kept
   * regardless; but in that case, if the connection ever needs to be recovered,
   * the set value will not be restored.
   * @param Var The variable to set
   * @param Val The new value to store in the variable
   */
  void set_variable(const PGSTD::string &Var, const PGSTD::string &Val);//[t61]

  /// Get currently applicable value of variable
  /** First consults an internal cache of variables that have been set (whether
   * in the ongoing transaction or in the connection) using the set_variable
   * functions.  If it is not found there, the database is queried.
   *
   * @warning Do not mix the set_variable with raw "SET" queries, and do not
   * try to set or get variables while a pipeline or table stream is active.
   *
   * @warning This function used to be declared as @c const but isn't anymore.
   */
  PGSTD::string get_variable(const PGSTD::string &);			//[t61]

protected:
  /// Create a transaction (to be called by implementation classes only)
  /** The optional name, if nonempty, must begin with a letter and may contain
   * letters and digits only.
   *
   * @param direct running directly in connection context (i.e. not nested)?
   */
  explicit transaction_base(connection_base &, bool direct=true);

  /// Begin transaction (to be called by implementing class)
  /** Will typically be called from implementing class' constructor.
   */
  void Begin();

  /// End transaction.  To be called by implementing class' destructor
  void End() throw ();

  /// To be implemented by derived implementation class: start transaction
  virtual void do_begin() =0;
  /// To be implemented by derived implementation class: perform query
  virtual result do_exec(const char Query[]) =0;
  /// To be implemented by derived implementation class: commit transaction
  virtual void do_commit() =0;
  /// To be implemented by derived implementation class: abort transaction
  virtual void do_abort() =0;

  // For use by implementing class:

  /// Execute query on connection directly
  /**
   * @param C Query or command to execute
   * @param Retries Number of times to retry the query if it fails.  Be
   * extremely careful with this option; if you retry in the middle of a
   * transaction, you may be setting up a new connection transparently and
   * executing the latter part of the transaction without a backend transaction
   * being active (and with the former part aborted).
   */
  result DirectExec(const char C[], int Retries=0);

  /// Forget about any reactivation-blocking resources we tried to allocate
  void reactivation_avoidance_clear() throw ()
	{m_reactivation_avoidance.clear();}

private:
  /* A transaction goes through the following stages in its lifecycle:
   * <ul>
   * <li> nascent: the transaction hasn't actually begun yet.  If our connection
   *    fails at this stage, it may recover and the transaction can attempt to
   *    establish itself again.
   * <li> active: the transaction has begun.  Since no commit command has been
   *    issued, abortion is implicit if the connection fails now.
   * <li> aborted: an abort has been issued; the transaction is terminated and
   *    its changes to the database rolled back.  It will accept no further
   *    commands.
   * <li> committed: the transaction has completed successfully, meaning that a
   *    commit has been issued.  No further commands are accepted.
   * <li> in_doubt: the connection was lost at the exact wrong time, and there
   *    is no way of telling whether the transaction was committed or aborted.
   * </ul>
   *
   * Checking and maintaining state machine logic is the responsibility of the
   * base class (ie., this one).
   */
  enum Status
  {
    st_nascent,
    st_active,
    st_aborted,
    st_committed,
    st_in_doubt
  };

  void PQXX_PRIVATE CheckPendingError();

  template<typename T> bool parm_is_null(T *p) const throw () { return !p; }
  template<typename T> bool parm_is_null(T) const throw () { return false; }

  friend class Cursor;
  friend class cursor_base;
  void MakeEmpty(result &R) const { m_Conn.MakeEmpty(R); }

  friend class internal::transactionfocus;
  void PQXX_PRIVATE RegisterFocus(internal::transactionfocus *);
  void PQXX_PRIVATE UnregisterFocus(internal::transactionfocus *) throw ();
  void PQXX_PRIVATE RegisterPendingError(const PGSTD::string &) throw ();
  friend class tablereader;
  void PQXX_PRIVATE BeginCopyRead(const PGSTD::string &, const PGSTD::string &);
  bool ReadCopyLine(PGSTD::string &L) { return m_Conn.ReadCopyLine(L); }
  friend class tablewriter;
  void PQXX_PRIVATE BeginCopyWrite(const PGSTD::string &Table,
	const PGSTD::string &Columns = PGSTD::string());
  void WriteCopyLine(const PGSTD::string &L) { m_Conn.WriteCopyLine(L); }
  void EndCopyWrite() { m_Conn.EndCopyWrite(); }

  friend class pipeline;
  void start_exec(const PGSTD::string &Q) { m_Conn.start_exec(Q); }
  internal::pq::PGresult *get_result() { return m_Conn.get_result(); }
  void consume_input() throw () { m_Conn.consume_input(); }
  bool is_busy() const throw () { return m_Conn.is_busy(); }

  friend class prepare::invocation;
  result prepared_exec(const PGSTD::string &,
	const char *const[],
	const int[],
	int);

  connection_base &m_Conn;

  internal::unique<internal::transactionfocus> m_Focus;
  Status m_Status;
  bool m_Registered;
  PGSTD::map<PGSTD::string, PGSTD::string> m_Vars;
  PGSTD::string m_PendingError;

  friend class subtransaction;
  /// Resources allocated in this transaction that make reactivation impossible
  /** This number may be negative!
   */
  internal::reactivation_avoidance_counter m_reactivation_avoidance;

  /// Not allowed
  transaction_base();
  /// Not allowed
  transaction_base(const transaction_base &);
  /// Not allowed
  transaction_base &operator=(const transaction_base &);
};

} // namespace pqxx

#include "pqxx/compiler-internal-post.hxx"
<commit_msg>Removed one function too many...<commit_after>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	pqxx/transaction_base.hxx
 *
 *   DESCRIPTION
 *      common code and definitions for the transaction classes.
 *   pqxx::transaction_base defines the interface for any abstract class that
 *   represents a database transaction
 *   DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transaction_base instead.
 *
 * 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-public.hxx"
#include "pqxx/compiler-internal-pre.hxx"

/* End-user programs need not include this file, unless they define their own
 * transaction classes.  This is not something the typical program should want
 * to do.
 *
 * However, reading this file is worthwhile because it defines the public
 * interface for the available transaction classes such as transaction and
 * nontransaction.
 */

#include "pqxx/connection_base"
#include "pqxx/isolation"
#include "pqxx/result"

/* Methods tested in eg. self-test program test001 are marked with "//[t1]"
 */

namespace pqxx
{
class connection_base;
class transaction_base;

namespace internal
{
class PQXX_LIBEXPORT transactionfocus : public virtual namedclass
{
public:
  explicit transactionfocus(transaction_base &t) :
    namedclass("transactionfocus"),
    m_Trans(t),
    m_registered(false)
  {
  }

protected:
  void register_me();
  void unregister_me() throw ();
  void reg_pending_error(const PGSTD::string &) throw ();
  bool registered() const throw () { return m_registered; }

  transaction_base &m_Trans;

private:
  bool m_registered;

  /// Not allowed
  transactionfocus();
  /// Not allowed
  transactionfocus(const transactionfocus &);
  /// Not allowed
  transactionfocus &operator=(const transactionfocus &);
};

} // namespace internal

/// Interface definition (and common code) for "transaction" classes.
/**
 * @addtogroup transaction Transaction classes
 * All database access must be channeled through one of these classes for
 * safety, although not all implementations of this interface need to provide
 * full transactional integrity.
 *
 * Several implementations of this interface are shipped with libpqxx, including
 * the plain transaction class, the entirely unprotected nontransaction, and the
 * more cautions robusttransaction.
 */
class PQXX_LIBEXPORT transaction_base : public virtual internal::namedclass
{
public:
  /// If nothing else is known, our isolation level is at least read_committed
  typedef isolation_traits<read_committed> isolation_tag;

  virtual ~transaction_base() =0;					//[t1]

  /// Commit the transaction
  /** Unless this function is called explicitly, the transaction will not be
   * committed (actually the nontransaction implementation breaks this rule,
   * hence the name).
   *
   * Once this function returns, the whole transaction will typically be
   * irrevocably completed in the database.  There is also, however, a minute
   * risk that the connection to the database may be lost at just the wrong
   * moment.  In that case, libpqxx may be unable to determine whether the
   * transaction was completed or aborted and an in_doubt_error will be thrown
   * to make this fact known to the caller.  The robusttransaction
   * implementation takes some special precautions to reduce this risk.
   */
  void commit();							//[t1]

  /// Abort the transaction
  /** No special effort is required to call this function; it will be called
   * implicitly when the transaction is destructed.
   */
  void abort();								//[t10]

  /**
   * @addtogroup escaping String escaping
   */
  //@{
  /// Escape string for use as SQL string literal in this transaction
  PGSTD::string esc(const char str[]) const;				//[t90]
  /// Escape string for use as SQL string literal in this transaction
  PGSTD::string esc(const char str[], size_t maxlen) const		//[t90]
	{ return m_Conn.esc(str,maxlen); }
  /// Escape string for use as SQL string literal in this transaction
  PGSTD::string esc(const PGSTD::string &) const;			//[t90]

  /// Escape binary data for use as SQL string literal in this transaction
  /** Raw, binary data is treated differently from regular strings.  Binary
   * strings are never interpreted as text, so they may safely include byte
   * values or byte sequences that don't happen to represent valid characters in
   * the character encoding being used.
   *
   * The binary string does not stop at the first zero byte, as is the case with
   * textual strings.  Instead, they may contain zero bytes anywhere.  If it
   * happens to contain bytes that look like quote characters, or other things
   * that can disrupt their use in SQL queries, they will be replaced with
   * special escape sequences.
   */
  PGSTD::string esc_raw(const unsigned char str[], size_t len) const	//[t62]
	{ return m_Conn.esc_raw(str, len); }
  /// Escape binary data for use as SQL string literal in this transaction
  PGSTD::string esc_raw(const PGSTD::string &) const;			//[t62]
  //@}

  /// Execute query
  /** Perform a query in this transaction.
   * @param Query Query or command to execute
   * @param Desc Optional identifier for query, to help pinpoint SQL errors
   * @return A result set describing the query's or command's result
   */
  result exec(const PGSTD::string &Query,
	      const PGSTD::string &Desc=PGSTD::string());		//[t1]

  result exec(const PGSTD::stringstream &Query,
	      const PGSTD::string &Desc=PGSTD::string())		//[t9]
	{ return exec(Query.str(), Desc); }

  /**
   * @name Prepared statements
   */
  //@{
  /// Execute prepared statement
  /** Prepared statements are defined using the connection classes' prepare()
   * function, and continue to live on in the ongoing session regardless of
   * the context they were defined in (unless explicitly dropped using the
   * connection's unprepare() function).  Their execution however, like other
   * forms of query execution, requires a transaction object.
   *
   * Just like param_declaration is a helper class that lets you tag parameter
   * declarations onto the statement declaration, the invocation class returned
   * here lets you tag parameter values onto the call:
   *
   * @code
   * result run_mystatement(transaction_base &T)
   * {
   *   return T.prepared("mystatement")("param1")(2)()(4).exec();
   * }
   * @endcode
   *
   * Here, parameter 1 (written as "<tt>$1</tt>" in the statement's body) is a
   * string that receives the value "param1"; the second parameter is an integer
   * with the value 2; the third receives a null, making its type irrelevant;
   * and number 4 again is an integer.  The ultimate invocation of exec() is
   * essential; if you forget this, nothing happens.
   *
   * @warning Do not try to execute a prepared statement manually through direct
   * SQL statements.  This is likely not to work, and even if it does, is likely
   * to be slower than using the proper libpqxx functions.  Also, libpqxx knows
   * how to emulate prepared statements if some part of the infrastructure does
   * not support them.
   *
   * @warning Actual definition of the prepared statement on the backend may be
   * deferred until its first use, which means that any errors in the prepared
   * statement may not show up until it is executed--and perhaps abort the
   * ongoing transaction in the process.
   */
  prepare::invocation prepared(const PGSTD::string &statement);		//[t85]

  //@}

  /**
   * @name Error/warning output
   */
  //@{
  /// Have connection process warning message
  void process_notice(const char Msg[]) const				//[t14]
	{ m_Conn.process_notice(Msg); }
  /// Have connection process warning message
  void process_notice(const PGSTD::string &Msg) const			//[t14]
	{ m_Conn.process_notice(Msg); }
  //@}

  /// Connection this transaction is running in
  connection_base &conn() const { return m_Conn; }			//[t4]

  /// Set session variable in this connection
  /** The new value is typically forgotten if the transaction aborts.
   * Known exceptions to this rule are nontransaction, and PostgreSQL versions
   * prior to 7.3.  In the case of nontransaction, the set value will be kept
   * regardless; but in that case, if the connection ever needs to be recovered,
   * the set value will not be restored.
   * @param Var The variable to set
   * @param Val The new value to store in the variable
   */
  void set_variable(const PGSTD::string &Var, const PGSTD::string &Val);//[t61]

  /// Get currently applicable value of variable
  /** First consults an internal cache of variables that have been set (whether
   * in the ongoing transaction or in the connection) using the set_variable
   * functions.  If it is not found there, the database is queried.
   *
   * @warning Do not mix the set_variable with raw "SET" queries, and do not
   * try to set or get variables while a pipeline or table stream is active.
   *
   * @warning This function used to be declared as @c const but isn't anymore.
   */
  PGSTD::string get_variable(const PGSTD::string &);			//[t61]

protected:
  /// Create a transaction (to be called by implementation classes only)
  /** The optional name, if nonempty, must begin with a letter and may contain
   * letters and digits only.
   *
   * @param direct running directly in connection context (i.e. not nested)?
   */
  explicit transaction_base(connection_base &, bool direct=true);

  /// Begin transaction (to be called by implementing class)
  /** Will typically be called from implementing class' constructor.
   */
  void Begin();

  /// End transaction.  To be called by implementing class' destructor
  void End() throw ();

  /// To be implemented by derived implementation class: start transaction
  virtual void do_begin() =0;
  /// To be implemented by derived implementation class: perform query
  virtual result do_exec(const char Query[]) =0;
  /// To be implemented by derived implementation class: commit transaction
  virtual void do_commit() =0;
  /// To be implemented by derived implementation class: abort transaction
  virtual void do_abort() =0;

  // For use by implementing class:

  /// Execute query on connection directly
  /**
   * @param C Query or command to execute
   * @param Retries Number of times to retry the query if it fails.  Be
   * extremely careful with this option; if you retry in the middle of a
   * transaction, you may be setting up a new connection transparently and
   * executing the latter part of the transaction without a backend transaction
   * being active (and with the former part aborted).
   */
  result DirectExec(const char C[], int Retries=0);

  /// Forget about any reactivation-blocking resources we tried to allocate
  void reactivation_avoidance_clear() throw ()
	{m_reactivation_avoidance.clear();}

private:
  /* A transaction goes through the following stages in its lifecycle:
   * <ul>
   * <li> nascent: the transaction hasn't actually begun yet.  If our connection
   *    fails at this stage, it may recover and the transaction can attempt to
   *    establish itself again.
   * <li> active: the transaction has begun.  Since no commit command has been
   *    issued, abortion is implicit if the connection fails now.
   * <li> aborted: an abort has been issued; the transaction is terminated and
   *    its changes to the database rolled back.  It will accept no further
   *    commands.
   * <li> committed: the transaction has completed successfully, meaning that a
   *    commit has been issued.  No further commands are accepted.
   * <li> in_doubt: the connection was lost at the exact wrong time, and there
   *    is no way of telling whether the transaction was committed or aborted.
   * </ul>
   *
   * Checking and maintaining state machine logic is the responsibility of the
   * base class (ie., this one).
   */
  enum Status
  {
    st_nascent,
    st_active,
    st_aborted,
    st_committed,
    st_in_doubt
  };

  void PQXX_PRIVATE CheckPendingError();

  template<typename T> bool parm_is_null(T *p) const throw () { return !p; }
  template<typename T> bool parm_is_null(T) const throw () { return false; }

  friend class Cursor;
  friend class cursor_base;
  void MakeEmpty(result &R) const { m_Conn.MakeEmpty(R); }

  friend class internal::transactionfocus;
  void PQXX_PRIVATE RegisterFocus(internal::transactionfocus *);
  void PQXX_PRIVATE UnregisterFocus(internal::transactionfocus *) throw ();
  void PQXX_PRIVATE RegisterPendingError(const PGSTD::string &) throw ();
  friend class tablereader;
  void PQXX_PRIVATE BeginCopyRead(const PGSTD::string &, const PGSTD::string &);
  bool ReadCopyLine(PGSTD::string &L) { return m_Conn.ReadCopyLine(L); }
  friend class tablewriter;
  void PQXX_PRIVATE BeginCopyWrite(const PGSTD::string &Table,
	const PGSTD::string &Columns = PGSTD::string());
  void WriteCopyLine(const PGSTD::string &L) { m_Conn.WriteCopyLine(L); }
  void EndCopyWrite() { m_Conn.EndCopyWrite(); }

  friend class pipeline;
  void start_exec(const PGSTD::string &Q) { m_Conn.start_exec(Q); }
  internal::pq::PGresult *get_result() { return m_Conn.get_result(); }
  void consume_input() throw () { m_Conn.consume_input(); }
  bool is_busy() const throw () { return m_Conn.is_busy(); }

  friend class prepare::invocation;
  result prepared_exec(const PGSTD::string &,
	const char *const[],
	const int[],
	int);

  connection_base &m_Conn;

  internal::unique<internal::transactionfocus> m_Focus;
  Status m_Status;
  bool m_Registered;
  PGSTD::map<PGSTD::string, PGSTD::string> m_Vars;
  PGSTD::string m_PendingError;

  friend class subtransaction;
  /// Resources allocated in this transaction that make reactivation impossible
  /** This number may be negative!
   */
  internal::reactivation_avoidance_counter m_reactivation_avoidance;

  /// Not allowed
  transaction_base();
  /// Not allowed
  transaction_base(const transaction_base &);
  /// Not allowed
  transaction_base &operator=(const transaction_base &);
};

} // namespace pqxx

#include "pqxx/compiler-internal-post.hxx"
<|endoftext|>


<commit_before>#pragma once

#include <cstddef>

#include "circular_iterator.hpp"

namespace helene
{
template <class T, std::size_t Size>
class sliding_window_buffer
{
public:
    typedef T value_type;
    typedef T& reference;
    typedef const T& const_reference;
    typedef circular_iterator<T*> iterator;
    typedef circular_iterator<const T*> const_iterator;
    typedef std::size_t size_type;

public:
    sliding_window_buffer()
        : buffer_{},
          origin_(std::begin(buffer_), std::end(buffer_), std::begin(buffer_))
    {
    }

    template <class Iterator>
    sliding_window_buffer(Iterator first, Iterator last)
        : sliding_window_buffer()
    {
        std::copy(first, last, origin_);
    }

    T& operator[](size_type n)
    {
        return origin_[static_cast<typename iterator::difference_type>(n)];
    }

    const T& operator[](size_type n) const
    {
        return origin_[static_cast<typename iterator::difference_type>(n)];
    }

    void
    push_back(const T& value)
    {
        origin_[Size] = value;
        ++origin_;
    }

    void
    push_front(const T& value)
    {
        --origin_;
        *origin_ = value;
    }

    reference
    back()
    {
        return origin_[Size - 1];
    }

    const_reference
    back() const
    {
        return origin_[Size - 1];
    }

    reference
    front()
    {
        return *origin_;
    }

    const_reference
    front() const
    {
        return *origin_;
    }

    constexpr size_type
    size() const
    {
        return Size;
    }

    iterator
    begin()
    {
        return origin_;
    }

    iterator
    end()
    {
        return origin_ + Size;
    }

    const_iterator
    cbegin() const
    {
        return origin_;
    }

    const_iterator
    cend() const
    {
        return origin_ + Size;
    }

private:
    T buffer_[Size];
    iterator origin_;
};
} // namespace helene
<commit_msg>Comments and formatting. 	modified:   include/sliding_window_buffer.hpp<commit_after>#pragma once

#include <cstddef>

#include "circular_iterator.hpp"

namespace helene
{
template <class T, std::size_t Size>
class sliding_window_buffer
{
public:
    typedef T value_type;
    typedef T& reference;
    typedef const T& const_reference;
    typedef circular_iterator<T*> iterator;
    typedef circular_iterator<const T*> const_iterator;
    typedef std::size_t size_type;

public:
    /**
     * \brief default constructor
     */
    sliding_window_buffer()
        : buffer_{},
          origin_(std::begin(buffer_), std::end(buffer_), std::begin(buffer_))
    {
    }

    /**
     * \brief constructor taking range, if std::distance(first, last) exceeds
     * Size, the resulting sliding_window_buffer constructed will contain the
     * Size last elements from range.
     */
    template <class Iterator>
    sliding_window_buffer(Iterator first, Iterator last)
        : sliding_window_buffer()
    {
        std::copy(first, last, origin_);
    }

public:
    T& operator[](size_type n)
    {
        return origin_[static_cast<typename iterator::difference_type>(n)];
    }

    const T& operator[](size_type n) const
    {
        return origin_[static_cast<typename iterator::difference_type>(n)];
    }

    void
    push_back(const T& value)
    {
        origin_[Size] = value;
        ++origin_;
    }

    void
    push_front(const T& value)
    {
        --origin_;
        *origin_ = value;
    }

    reference
    back()
    {
        return origin_[Size - 1];
    }

    const_reference
    back() const
    {
        return origin_[Size - 1];
    }

    reference
    front()
    {
        return *origin_;
    }

    const_reference
    front() const
    {
        return *origin_;
    }

    constexpr size_type
    size() const
    {
        return Size;
    }

    iterator
    begin()
    {
        return origin_;
    }

    iterator
    end()
    {
        return origin_ + Size;
    }

    const_iterator
    cbegin() const
    {
        return origin_;
    }

    const_iterator
    cend() const
    {
        return origin_ + Size;
    }

private:
    T buffer_[Size];
    iterator origin_;
};
} // namespace helene
<|endoftext|>


<commit_before><commit_msg>coverity#708202 Uninitialized scalar field<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 2009, 2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#ifndef OBJECT_CXX_OBJECT_HH
# define OBJECT_CXX_OBJECT_HH

# include <vector>

# include <boost/optional.hpp>

# include <urbi/object/enumeration.hh>
# include <urbi/object/object.hh>

#define URBI_CXX_OBJECT_(Name)                                          \
  public:                                                               \
    static const ::std::string& type_name();                            \
    virtual ::std::string type_name_get() const;                        \
    static ::libport::intrusive_ptr<Name> proto;                        \
    virtual bool valid_proto(const ::urbi::object::Object& o) const;    \
  private:                                                              \
    friend class ::urbi::object::CxxObject::TypeInitializer<Name>;      \
    Name(const ::urbi::object::FirstPrototypeFlag&);                    \
  public:                                                               \
    static void initialize(::urbi::object::CxxObject::Binder<Name>&)    \

#define URBI_CXX_OBJECT(Name)                   \
  URBI_CXX_OBJECT_(Name)                        \
  {}                                            \

#define URBI_CXX_OBJECT_REGISTER(Name)                          \
  const std::string& Name::type_name()                          \
  {                                                             \
    static std::string res = #Name;                             \
    return res;                                                 \
  }                                                             \
                                                                \
  ::libport::intrusive_ptr<Name> Name::proto;                   \
                                                                \
  std::string                                                   \
  Name::type_name_get() const                                   \
  {                                                             \
    return type_name();                                         \
  }                                                             \
                                                                \
  bool Name::valid_proto(const ::urbi::object::Object& o) const \
  {                                                             \
    return dynamic_cast<const Name*>(&o);                       \
  }                                                             \
                                                                \
  struct Name ## _register__                                    \
  {                                                             \
    Name ## _register__()                                       \
    {                                                           \
      ::urbi::object::CxxObject::add<Name>();                   \
    }                                                           \
  };                                                            \
                                                                \
  static Name ## _register__ Name ## _registered__;             \
                                                                \
  Name::Name(const ::urbi::object::FirstPrototypeFlag&)

namespace urbi
{
  namespace object
  {
    struct FirstPrototypeFlag {};

    /// Base class for Urbi bound C++ classes.
    class URBI_SDK_API CxxObject: public Object
    {
    public:

      /// Build a CxxObject.
      CxxObject();

      /// Bind all registered objects.
      /** This function should be called once to bind C++ objects.
       *  \param global Where to store the new classes.
       */
      static void initialize(rObject global);
      static void create();
      static void cleanup();

      /// Push initializer for class T to the back of the initialization list.
      template<typename T>
        static void push_initializer_to_back();

      /// Register a C++ class to be bound on the urbi side.
      /** \param T      The class to bind.
       *  \param name   Name of the class on the Urbi side.
       *  \param tgt    Where to store the result.
       */
      template<typename T>
        static bool add();

      virtual std::string type_name_get() const = 0;

      protected:

      class URBI_SDK_API Initializer
      {
      public:
        Initializer();
        virtual ~Initializer();
        virtual rObject make_class() = 0;
        virtual void create() = 0;
        virtual libport::Symbol name() = 0;
      };

      template <typename T>
        class TypeInitializer: public Initializer
      {
      public:
        TypeInitializer();
        virtual rObject make_class();
        virtual void create();
        virtual libport::Symbol name();
      protected:
        libport::intrusive_ptr<T>& res_;
      };

      typedef std::list<Initializer*> initializers_type;
      static initializers_type& initializers_get();

      public:
      /// Functor to bind methods on the urbi side.
      /** An instance of this class is given to the static initialize
       *  method of the bound classes. It can then be used to bind
       *  method and/or attributes on the Urbi side.
       */
      template <typename T>
        class Binder
      {
      public:
        /// Bind \a method with \a name
        template <typename M>
        void operator()(const libport::Symbol& name, M method);
        template <typename A>
        void var(const libport::Symbol& name, A (T::*attr));
        template <typename A>
        void var(const libport::Symbol& name, A* (T::*ref)());
        rObject proto() { return tgt_; }

      private:
        Binder(rObject tgt);
        // This method is allowed to construct a Binder.
        // VC++ is not a friend of friend method templates, so friend the class.
        friend class TypeInitializer<T>;
        rObject tgt_;
      };

    };

    /// Raise an exception if \a o is not a \a exp. If \a idx is given,
    /// report the type error for argument \a idx.
    URBI_SDK_API
    void
    type_check(const rObject& o, const rObject& exp,
               boost::optional<unsigned> idx = boost::optional<unsigned>());

    /// Same as above, but check first with a dynamic_cast in order to handle
    /// atoms more efficiently.
    template<typename T>
    URBI_SDK_API
    libport::intrusive_ptr<T>
    type_check(const rObject& o,
               boost::optional<unsigned> idx = boost::optional<unsigned>());

    /// Throw an exception if formal != effective.
    /// \note: \c self is included in the count.
    URBI_SDK_API
    void check_arg_count(unsigned effective, unsigned formal);

    /// Same as above, with a minimum and maximum number of
    /// formal parameters.
    URBI_SDK_API
    void check_arg_count(unsigned effective,
                         unsigned minformal, unsigned maxformal);
  }

  typedef boost::function0<void> Initialization;
  int initialization_register(const Initialization& action);
# define URBI_INITIALIZATION_REGISTER(Action)                           \
                                                                        \
  static int LIBPORT_CAT(_urbi_initialization, __LINE__)()              \
  {                                                                     \
    ::urbi::initialization_register(Action);                            \
    return 0xbadf00d;                                                   \
  }                                                                     \
                                                                        \
  inline int LIBPORT_CAT(_urbi_initialization_bouncer, __LINE__)()      \
  {                                                                     \
    static int dummy = LIBPORT_CAT(_urbi_initialization, __LINE__)();   \
    return dummy;                                                       \
  }                                                                     \
                                                                        \
  static int LIBPORT_CAT(_urbi_initialization_register_, __LINE__) =    \
    LIBPORT_CAT(_urbi_initialization_bouncer, __LINE__)()               \

}

# if ! defined OBJECT_EXECUTABLE_HH             \
      && ! defined OBJECT_FLOAT_HH              \
      && ! defined OBJECT_LIST_HH               \
      && ! defined OBJECT_STRING_HH             \
      && ! defined OBJECT_TAG_HH
#  include <urbi/object/cxx-object.hxx>
# endif

#endif // ! OBJECT_CXX_OBJECT_HH
<commit_msg>Static initialization: avoid warning.<commit_after>/*
 * Copyright (C) 2009, 2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#ifndef OBJECT_CXX_OBJECT_HH
# define OBJECT_CXX_OBJECT_HH

# include <vector>

# include <boost/optional.hpp>

# include <urbi/object/enumeration.hh>
# include <urbi/object/object.hh>

#define URBI_CXX_OBJECT_(Name)                                          \
  public:                                                               \
    static const ::std::string& type_name();                            \
    virtual ::std::string type_name_get() const;                        \
    static ::libport::intrusive_ptr<Name> proto;                        \
    virtual bool valid_proto(const ::urbi::object::Object& o) const;    \
  private:                                                              \
    friend class ::urbi::object::CxxObject::TypeInitializer<Name>;      \
    Name(const ::urbi::object::FirstPrototypeFlag&);                    \
  public:                                                               \
    static void initialize(::urbi::object::CxxObject::Binder<Name>&)    \

#define URBI_CXX_OBJECT(Name)                   \
  URBI_CXX_OBJECT_(Name)                        \
  {}                                            \

#define URBI_CXX_OBJECT_REGISTER(Name)                          \
  const std::string& Name::type_name()                          \
  {                                                             \
    static std::string res = #Name;                             \
    return res;                                                 \
  }                                                             \
                                                                \
  ::libport::intrusive_ptr<Name> Name::proto;                   \
                                                                \
  std::string                                                   \
  Name::type_name_get() const                                   \
  {                                                             \
    return type_name();                                         \
  }                                                             \
                                                                \
  bool Name::valid_proto(const ::urbi::object::Object& o) const \
  {                                                             \
    return dynamic_cast<const Name*>(&o);                       \
  }                                                             \
                                                                \
  struct Name ## _register__                                    \
  {                                                             \
    Name ## _register__()                                       \
    {                                                           \
      ::urbi::object::CxxObject::add<Name>();                   \
    }                                                           \
  };                                                            \
                                                                \
  static Name ## _register__ Name ## _registered__;             \
                                                                \
  Name::Name(const ::urbi::object::FirstPrototypeFlag&)

namespace urbi
{
  namespace object
  {
    struct FirstPrototypeFlag {};

    /// Base class for Urbi bound C++ classes.
    class URBI_SDK_API CxxObject: public Object
    {
    public:

      /// Build a CxxObject.
      CxxObject();

      /// Bind all registered objects.
      /** This function should be called once to bind C++ objects.
       *  \param global Where to store the new classes.
       */
      static void initialize(rObject global);
      static void create();
      static void cleanup();

      /// Push initializer for class T to the back of the initialization list.
      template<typename T>
        static void push_initializer_to_back();

      /// Register a C++ class to be bound on the urbi side.
      /** \param T      The class to bind.
       *  \param name   Name of the class on the Urbi side.
       *  \param tgt    Where to store the result.
       */
      template<typename T>
        static bool add();

      virtual std::string type_name_get() const = 0;

      protected:

      class URBI_SDK_API Initializer
      {
      public:
        Initializer();
        virtual ~Initializer();
        virtual rObject make_class() = 0;
        virtual void create() = 0;
        virtual libport::Symbol name() = 0;
      };

      template <typename T>
        class TypeInitializer: public Initializer
      {
      public:
        TypeInitializer();
        virtual rObject make_class();
        virtual void create();
        virtual libport::Symbol name();
      protected:
        libport::intrusive_ptr<T>& res_;
      };

      typedef std::list<Initializer*> initializers_type;
      static initializers_type& initializers_get();

      public:
      /// Functor to bind methods on the urbi side.
      /** An instance of this class is given to the static initialize
       *  method of the bound classes. It can then be used to bind
       *  method and/or attributes on the Urbi side.
       */
      template <typename T>
        class Binder
      {
      public:
        /// Bind \a method with \a name
        template <typename M>
        void operator()(const libport::Symbol& name, M method);
        template <typename A>
        void var(const libport::Symbol& name, A (T::*attr));
        template <typename A>
        void var(const libport::Symbol& name, A* (T::*ref)());
        rObject proto() { return tgt_; }

      private:
        Binder(rObject tgt);
        // This method is allowed to construct a Binder.
        // VC++ is not a friend of friend method templates, so friend the class.
        friend class TypeInitializer<T>;
        rObject tgt_;
      };

    };

    /// Raise an exception if \a o is not a \a exp. If \a idx is given,
    /// report the type error for argument \a idx.
    URBI_SDK_API
    void
    type_check(const rObject& o, const rObject& exp,
               boost::optional<unsigned> idx = boost::optional<unsigned>());

    /// Same as above, but check first with a dynamic_cast in order to handle
    /// atoms more efficiently.
    template<typename T>
    URBI_SDK_API
    libport::intrusive_ptr<T>
    type_check(const rObject& o,
               boost::optional<unsigned> idx = boost::optional<unsigned>());

    /// Throw an exception if formal != effective.
    /// \note: \c self is included in the count.
    URBI_SDK_API
    void check_arg_count(unsigned effective, unsigned formal);

    /// Same as above, with a minimum and maximum number of
    /// formal parameters.
    URBI_SDK_API
    void check_arg_count(unsigned effective,
                         unsigned minformal, unsigned maxformal);
  }

  typedef boost::function0<void> Initialization;
  int initialization_register(const Initialization& action);

# define URBI_INITIALIZATION_REGISTER(Action)                           \
                                                                        \
  static                                                                \
  int LIBPORT_CAT(_urbi_initialization, __LINE__)()                     \
  {                                                                     \
    GD_CATEGORY(Urbi.CxxObject);                                        \
    GD_INFO_TRACE("register initialization: "                           \
                  BOOST_PP_STRINGIZE(Action));                          \
    ::urbi::initialization_register(Action);                            \
    return 0xbadf00d;                                                   \
  }                                                                     \
                                                                        \
  static inline                                                         \
  int LIBPORT_CAT(_urbi_initialization_bouncer, __LINE__)();            \
                                                                        \
  static int LIBPORT_CAT(_urbi_initialization_register_, __LINE__) =    \
    LIBPORT_CAT(_urbi_initialization_bouncer, __LINE__)();              \
                                                                        \
  static inline                                                         \
  int LIBPORT_CAT(_urbi_initialization_bouncer, __LINE__)()             \
  {                                                                     \
    static int dummy = LIBPORT_CAT(_urbi_initialization, __LINE__)();   \
    /* Avoid unused warnings */                                         \
    LIBPORT_CAT(_urbi_initialization_register_, __LINE__) =             \
      LIBPORT_CAT(_urbi_initialization_register_, __LINE__);            \
    return dummy;                                                       \
  }                                                                     \

}

# if ! defined OBJECT_EXECUTABLE_HH             \
      && ! defined OBJECT_FLOAT_HH              \
      && ! defined OBJECT_LIST_HH               \
      && ! defined OBJECT_STRING_HH             \
      && ! defined OBJECT_TAG_HH
#  include <urbi/object/cxx-object.hxx>
# endif

#endif // ! OBJECT_CXX_OBJECT_HH
<|endoftext|>


<commit_before>#pragma once

#include <boost/timer/timer.hpp>

namespace usagi::log::easy_logger
{
  using namespace std;

  boost::timer::cpu_timer global_timer;

  struct log_intermediate
  {
    stringstream buffer;

    const char* prefix;
    const char* suffix;

    const char* source;
    const size_t line;
    const char* function;

    static constexpr auto prefix_i = "";
    static constexpr auto prefix_d = "\x1b[32m";
    static constexpr auto prefix_w = "\x1b[33m";
    static constexpr auto prefix_e = "\x1b[31m";

    static constexpr auto suffix_i = "";
    static constexpr auto suffix_d = "\x1b[0m";
    static constexpr auto suffix_w = "\x1b[0m";
    static constexpr auto suffix_e = "\x1b[0m";

    static constexpr auto log_time_width = 13;

    log_intermediate( log_intermediate&& a )
      : buffer( move( a.buffer ) )
      , prefix( a.prefix )
      , suffix( a.suffix )
      , source( a.source )
      , line( a.line )
      , function( a.function )
    { }

    log_intermediate( const char* p, const char* s, const char* source_, const size_t line_, const char* function_ )
      : prefix( p )
      , suffix( s )
      , source( source_ )
      , line( line_ )
      , function( function_ )
    { }

    static auto make_info ( const char* s, const size_t l, const char* f ) { return log_intermediate( prefix_i, suffix_i, s, l, f ); }
    static auto make_debug( const char* s, const size_t l, const char* f ) { return log_intermediate( prefix_d, suffix_d, s, l, f ); }
    static auto make_warn ( const char* s, const size_t l, const char* f ) { return log_intermediate( prefix_w, suffix_w, s, l, f ); }
    static auto make_error( const char* s, const size_t l, const char* f ) { return log_intermediate( prefix_e, suffix_e, s, l, f ); }

    template < typename T >
    decltype( auto ) operator<<( const T& in ) noexcept
    {
      try
      { return buffer << in; }
      catch ( const exception& e )
      { return buffer << "<<<<<exception on " << __PRETTY_FUNCTION__ << " what=" << e.what() << ">>>>>"; }
      catch ( ... )
      { return buffer << "<<<<<exception on " << __PRETTY_FUNCTION__ << " uknown>>>>>"; }
    }

    ~log_intermediate() noexcept
    {
      try
      {
        cout
          << prefix
          << "[ " << setw( log_time_width ) << global_timer.elapsed().wall << " ]"
             "\t"
          << buffer.str()
          << "\t"
          << source << '\t' << line << '\t' << function
          << suffix
          << endl
          ;
      }
      catch ( const exception& e )
      { cerr << "\n\n<<<<<\nexception on " << __PRETTY_FUNCTION__ << "\nwhat=" << e.what() << "\n>>>>>\n\n"; }
      catch ( ... )
      { cerr << "\n\n<<<<<\nexception on " << __PRETTY_FUNCTION__ << "\nunknown\n>>>>>\n\n"; }
    }
  };
}

#define LOGI log_intermediate::make_info ( __FILE__, __LINE__, __PRETTY_FUNCTION__ ) << '\t'
#define LOGD log_intermediate::make_debug( __FILE__, __LINE__, __PRETTY_FUNCTION__ ) << '\t'
#define LOGW log_intermediate::make_warn ( __FILE__, __LINE__, __PRETTY_FUNCTION__ ) << '\t'
#define LOGE log_intermediate::make_error( __FILE__, __LINE__, __PRETTY_FUNCTION__ ) << '\t'
<commit_msg>fixup<commit_after>#pragma once

#include <boost/timer/timer.hpp>

namespace usagi::log::easy_logger
{
  using namespace std;

  boost::timer::cpu_timer global_timer;

  struct log_intermediate
  {
    stringstream buffer;

    const char* prefix;
    const char* suffix;

    const char* source;
    const size_t line;
    const char* function;

    static constexpr auto prefix_i = "";
    static constexpr auto prefix_d = "\x1b[32m";
    static constexpr auto prefix_w = "\x1b[33m";
    static constexpr auto prefix_e = "\x1b[31m";

    static constexpr auto suffix_i = "";
    static constexpr auto suffix_d = "\x1b[0m";
    static constexpr auto suffix_w = "\x1b[0m";
    static constexpr auto suffix_e = "\x1b[0m";

    static constexpr auto log_time_width = 13;

    log_intermediate( log_intermediate&& a )
      : buffer( move( a.buffer ) )
      , prefix( a.prefix )
      , suffix( a.suffix )
      , source( a.source )
      , line( a.line )
      , function( a.function )
    { }

    log_intermediate( const char* p, const char* s, const char* source_, const size_t line_, const char* function_ )
      : prefix( p )
      , suffix( s )
      , source( source_ )
      , line( line_ )
      , function( function_ )
    { }

    static auto make_info ( const char* s, const size_t l, const char* f ) { return log_intermediate( prefix_i, suffix_i, s, l, f ); }
    static auto make_debug( const char* s, const size_t l, const char* f ) { return log_intermediate( prefix_d, suffix_d, s, l, f ); }
    static auto make_warn ( const char* s, const size_t l, const char* f ) { return log_intermediate( prefix_w, suffix_w, s, l, f ); }
    static auto make_error( const char* s, const size_t l, const char* f ) { return log_intermediate( prefix_e, suffix_e, s, l, f ); }

    template < typename T >
    decltype( auto ) operator<<( const T& in ) noexcept
    {
      try
      { return buffer << in; }
      catch ( const exception& e )
      { return buffer << "<<<<<exception on " << __PRETTY_FUNCTION__ << " what=" << e.what() << ">>>>>"; }
      catch ( ... )
      { return buffer << "<<<<<exception on " << __PRETTY_FUNCTION__ << " uknown>>>>>"; }
    }

    ~log_intermediate() noexcept
    {
      try
      {
        cout
          << prefix
          << "[ " << setw( log_time_width ) << global_timer.elapsed().wall << " ]"
             "\t"
          << buffer.str()
          << "\t"
          << source << '\t' << line << '\t' << function
          << suffix
          << endl
          ;
      }
      catch ( const exception& e )
      { cerr << "\n\n<<<<<\nexception on " << __PRETTY_FUNCTION__ << "\nwhat=" << e.what() << "\n>>>>>\n\n"; }
      catch ( ... )
      { cerr << "\n\n<<<<<\nexception on " << __PRETTY_FUNCTION__ << "\nunknown\n>>>>>\n\n"; }
    }
  };
}

#define LOGI ::usagi::log::easy_logger::log_intermediate::make_info ( __FILE__, __LINE__, __PRETTY_FUNCTION__ ) << '\t'
#define LOGD ::usagi::log::easy_logger::log_intermediate::make_debug( __FILE__, __LINE__, __PRETTY_FUNCTION__ ) << '\t'
#define LOGW ::usagi::log::easy_logger::log_intermediate::make_warn ( __FILE__, __LINE__, __PRETTY_FUNCTION__ ) << '\t'
#define LOGE ::usagi::log::easy_logger::log_intermediate::make_error( __FILE__, __LINE__, __PRETTY_FUNCTION__ ) << '\t'
<|endoftext|>


<commit_before>// Simple startrails composition program using OpenCV
// Copyright 2018 Jarno Paananen <jarno.paananen@gmail.com>
// Based on script by Thomas Jacquin
// SPDX-License-Identifier: MIT

#include <getopt.h>
#include <glob.h>
#include <unistd.h>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>

#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

#define KNRM "\x1B[0m"
#define KRED "\x1B[31m"
#define KGRN "\x1B[32m"
#define KYEL "\x1B[33m"
#define KBLU "\x1B[34m"
#define KMAG "\x1B[35m"
#define KCYN "\x1B[36m"
#define KWHT "\x1B[37m"

struct config_t {
  std::string img_src_dir, img_src_ext, dst_startrails;
  bool startrails_enabled;
  int img_width;
  int img_height;
  int verbose;
  double brightness_limit;
} config;

void parse_args(int, char**, struct config_t*);
void usage_and_exit(int);

//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
void parse_args(int argc, char** argv, struct config_t* cf) {
  int c;
  cf->verbose = 0;
  cf->startrails_enabled = true;
  cf->img_height = cf->img_width = 0;
  cf->brightness_limit = 0.35;  // not terrible in the city

  while (1) {  // getopt loop
    int option_index = 0;
    static struct option long_options[] = {
        {"brightness", optional_argument, 0, 'b'},
        {"directory", required_argument, 0, 'd'},
        {"extension", required_argument, 0, 'e'},
        {"output", required_argument, 0, 'o'},
        {"image-size", required_argument, 0, 's'},
        {"statistics", no_argument, 0, 'S'},
        {"verbose", no_argument, 0, 'v'},
        {"help", no_argument, 0, 'h'},
        {0, 0, 0, 0}};

    c = getopt_long(argc, argv, "hvsd:e:o:s:", long_options, &option_index);
    if (c == -1)
      break;
    switch (c) {  // option switch
      case 'h':
        usage_and_exit(0);
        // NOTREACHED
        break;
      case 'v':
        cf->verbose++;
        break;
      case 'S':
        cf->startrails_enabled = false;
        break;
      case 's':
        int height, width;
        sscanf(optarg, "%dx%d", &width, &height);
        // 122.8Mpx should be enough for anybody.
        if (height < 0 || height > 9600 || width < 0 || width > 12800)
          height = width = 0;
        cf->img_height = height;
        cf->img_width = width;
        break;
      case 'b':
        double b;
        b = atof(optarg);
        if (b >= 0 && b <= 1.0)
          cf->brightness_limit = b;
        break;
      case 'd':
        cf->img_src_dir = optarg;
        break;
      case 'e':
        cf->img_src_ext = optarg;
        break;
      case 'o':
        cf->dst_startrails = optarg;
        break;
      default:
        break;
    }  // option switch
  }    // getopt loop
}

void usage_and_exit(int x) {
  std::cout << "Usage: startrails [-v] -d <dir> -e <ext> [-b <brightness> -o "
               "<output> -s <size> | -S]"
            << std::endl;
  if (x) {
    std::cout << KRED
              << "Source directory and file extension are always required."
              << std::endl;
    std::cout << "brightness threshold and output file are required to render "
                 "startrails"
              << KNRM << std::endl;
  }

  std::cout << std::endl << "Arguments:" << std::endl;
  std::cout << "-h | --help : display this help, then exit" << std::endl;
  std::cout << "-v | --verbose : increase log verbosity" << std::endl;
  std::cout << "-S | --statistics : print image directory statistics without "
               "producing image."
            << std::endl;
  std::cout << "-d | --directory <str> : directory from which to read images"
            << std::endl;
  std::cout << "-e | --extension <str> : filter images to just this extension"
            << std::endl;
  std::cout << "-o | --output-file <str> : output image filename" << std::endl;
  std::cout << "-s | --image-size <int>x<int> : restrict processed images to "
               "this size"
            << std::endl;
  std::cout << "-b | --brightness-limit <float> : ranges from 0 (black) to 1 "
               "(white). Default 0.35"
            << std::endl;
  std::cout << "\tA moonless sky may be as low as 0.05 while full moon can be "
               "as high as 0.4"
            << std::endl;
  std::cout << std::endl
            << "ex: startrails -b 0.07 -d ../images/20180208/ -e jpg -o "
               "startrails.jpg"
            << std::endl;
  exit(x);
}

int main(int argc, char* argv[]) {
  struct config_t config;
  int i;
  char* e;

  parse_args(argc, argv, &config);

  if (config.verbose < 1)
    if ((e = getenv("ALLSKY_DEBUG_LEVEL")))
      if ((i = atoi(e)) > 0)
        config.verbose = i;

  if (config.img_src_dir.empty() || config.img_src_ext.empty())
    usage_and_exit(3);

  if (!config.startrails_enabled) {
    config.brightness_limit = 0;
    config.dst_startrails = "/dev/null";
  }

  if (!config.dst_startrails.empty() && config.brightness_limit < 0)
    usage_and_exit(3);

  // Find files
  glob_t files;
  std::string wildcard = config.img_src_dir + "/*." + config.img_src_ext;
  glob(wildcard.c_str(), 0, NULL, &files);
  if (files.gl_pathc == 0) {
    globfree(&files);
    std::cout << "No images found, exiting." << std::endl;
    return 0;
  }

  cv::Mat accumulated;

  // Create space for statistics
  cv::Mat stats;
  stats.create(1, files.gl_pathc, CV_64F);
  int nchan = 0;

  for (size_t f = 0; f < files.gl_pathc; f++) {
    cv::Mat image = cv::imread(files.gl_pathv[f], cv::IMREAD_UNCHANGED);
    if (!image.data) {
      if (config.verbose)
        fprintf(stderr, "Error reading file %s\n", basename(files.gl_pathv[f]));
      stats.col(f) = 1.0;  // mark as invalid
      continue;
    }

    if (config.img_height && config.img_width &&
        (image.cols != config.img_width || image.rows != config.img_height)) {
      if (config.verbose)
        fprintf(stderr, "skipped %s - got size %dx%d, want %dx%d\n",
                files.gl_pathv[f], image.cols, image.cols, config.img_width,
                config.img_height);
      continue;
    }

    // first valid image sets the number of channels we expect
    if (nchan == 0 && image.channels())
      nchan = image.channels();

    cv::Scalar mean_scalar = cv::mean(image);
    double mean;
    switch (image.channels()) {
      default:  // mono case
        mean = mean_scalar.val[0];
        break;
      case 3:  // for color choose maximum channel
      case 4:
        mean = cv::max(mean_scalar[0], cv::max(mean_scalar[1], mean_scalar[2]));
        break;
    }
    // Scale to 0-1 range
    switch (image.depth()) {
      case CV_8U:
        mean /= 255.0;
        break;
      case CV_16U:
        mean /= 65535.0;
        break;
    }
    if (config.verbose > 1)
      std::cout << "[" << f + 1 << "/" << files.gl_pathc << "] "
                << basename(files.gl_pathv[f]) << " " << mean << std::endl;

    stats.col(f) = mean;

    if (config.startrails_enabled && mean <= config.brightness_limit) {
      if (image.channels() != nchan) {
        if (config.verbose)
          fprintf(stderr, "repairing %s channel mismatch: got %d, want %d\n",
                  files.gl_pathv[f], image.channels(), nchan);
        if (image.channels() < nchan)
          cv::cvtColor(image, image, cv::COLOR_GRAY2BGR, nchan);
        else if (image.channels() > nchan)
          cv::cvtColor(image, image, cv::COLOR_BGR2GRAY, nchan);
      }
      if (accumulated.empty()) {
        image.copyTo(accumulated);
      } else {
        accumulated = cv::max(accumulated, image);
      }
    }
  }

  // Calculate some statistics
  double min_mean, max_mean;
  cv::Point min_loc;
  cv::minMaxLoc(stats, &min_mean, &max_mean, &min_loc);
  double mean_mean = cv::mean(stats)[0];

  // For median, do partial sort and take middle value
  std::vector<double> vec;
  stats.copyTo(vec);
  std::nth_element(vec.begin(), vec.begin() + (vec.size() / 2), vec.end());
  double median_mean = vec[vec.size() / 2];

  std::cout << "Minimum: " << min_mean << " maximum: " << max_mean
            << " mean: " << mean_mean << " median: " << median_mean
            << std::endl;

  // If we still don't have an image (no images below threshold), copy the
  // minimum mean image so we see why
  if (config.startrails_enabled) {
    if (accumulated.empty()) {
      std::cout << "No images below threshold, writing the minimum image only"
                << std::endl;
      accumulated = cv::imread(files.gl_pathv[min_loc.x], cv::IMREAD_UNCHANGED);
    }

    std::vector<int> compression_params;
    compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION);
    compression_params.push_back(9);
    compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
    compression_params.push_back(95);

    cv::imwrite(config.dst_startrails, accumulated, compression_params);
  }
  globfree(&files);
  return 0;
}
<commit_msg>Multithreaded startrail processing.<commit_after>// Simple startrails composition program using OpenCV
// Copyright 2018 Jarno Paananen <jarno.paananen@gmail.com>
// Based on script by Thomas Jacquin
// SPDX-License-Identifier: MIT

using namespace std;

#include <getopt.h>
#include <glob.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <unistd.h>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>

#define KNRM "\x1B[0m"
#define KRED "\x1B[31m"
#define KGRN "\x1B[32m"
#define KYEL "\x1B[33m"
#define KBLU "\x1B[34m"
#define KMAG "\x1B[35m"
#define KCYN "\x1B[36m"
#define KWHT "\x1B[37m"

struct config_t {
  std::string img_src_dir, img_src_ext, dst_startrails;
  bool startrails_enabled;
  int num_threads;
  int nice_level;
  int img_width;
  int img_height;
  int verbose;
  double brightness_limit;
} config;

std::mutex stdio_mutex;

void parse_args(int, char**, struct config_t*);
void usage_and_exit(int);
void startrail_worker(int,               // thread num
                      struct config_t*,  // config
                      glob_t*,           // file list
                      std::mutex*,       // mutex
                      cv::Mat*,          // statistics
                      cv::Mat*           // accumulated
);

void startrail_worker(int thread_num,
                      struct config_t* cf,
                      glob_t* files,
                      std::mutex* mtx,
                      cv::Mat* stats_ptr,
                      cv::Mat* main_accumulator) {
  int start_num, end_num, batch_size, nchan = 0;
  unsigned long nfiles = files->gl_pathc;
  cv::Mat thread_accumulator;

  batch_size = nfiles / cf->num_threads;
  start_num = thread_num * batch_size;

  // last thread has more work to do if the number of images isn't multiple of
  // the number of threads
  if ((thread_num + 1) == cf->num_threads)
    end_num = nfiles - 1;
  else
    end_num = start_num + batch_size - 1;

  if (cf->verbose > 1) {
    stdio_mutex.lock();
    fprintf(stderr, "thread %d/%d processing files %d-%d (%d/%lu)\n",
            thread_num + 1, cf->num_threads, start_num, end_num,
            end_num - start_num + 1, nfiles);
    stdio_mutex.unlock();
  }

  for (int f = start_num; f <= end_num; f++) {
    char* filename = files->gl_pathv[f];
    cv::Mat image = cv::imread(filename, cv::IMREAD_UNCHANGED);
    filename = basename(filename);
    if (!image.data) {
      stdio_mutex.lock();
      fprintf(stderr, "Error reading file %s\n", filename);
      stdio_mutex.unlock();
      continue;
    }

    if (cf->img_height && cf->img_width &&
        (image.cols != cf->img_width || image.rows != cf->img_height)) {
      if (cf->verbose) {
        stdio_mutex.lock();
        fprintf(stderr, "skip %s size %dx%d != %dx%d\n", filename, image.cols,
                image.cols, cf->img_width, cf->img_height);
        stdio_mutex.unlock();
      }
      continue;
    }

    // first valid image sets the number of channels we expect
    if (nchan == 0 && image.channels())
      nchan = image.channels();

    cv::Scalar mean_scalar = cv::mean(image);
    double image_mean;
    switch (image.channels()) {
      default:  // mono case
        image_mean = mean_scalar.val[0];
        break;
      case 3:  // for color choose maximum channel
      case 4:
        image_mean =
            cv::max(mean_scalar[0], cv::max(mean_scalar[1], mean_scalar[2]));
        break;
    }
    // Scale to 0-1 range
    switch (image.depth()) {
      case CV_8U:
        image_mean /= 255.0;
        break;
      case CV_16U:
        image_mean /= 65535.0;
        break;
    }
    if (cf->verbose > 1) {
      stdio_mutex.lock();
      fprintf(stderr, "[%d/%lu] %s %.3f\n", f + 1, nfiles, filename,
              image_mean);
      stdio_mutex.unlock();
    }

    // the matrix pointed to by stats_ptr has already been initialized to NAN
    // so we just update the entry once the image is successfully loaded
    stats_ptr->col(f) = image_mean;

    if (cf->startrails_enabled && image_mean <= cf->brightness_limit) {
      if (image.channels() != nchan) {
        if (cf->verbose) {
          stdio_mutex.lock();
          fprintf(stderr, "repairing channel mismatch: %d != %d\n",
                  image.channels(), nchan);
          stdio_mutex.unlock();
        }
        if (image.channels() < nchan)
          cv::cvtColor(image, image, cv::COLOR_GRAY2BGR, nchan);
        else if (image.channels() > nchan)
          cv::cvtColor(image, image, cv::COLOR_BGR2GRAY, nchan);
      }
      if (thread_accumulator.empty()) {
        image.copyTo(thread_accumulator);
      } else {
        thread_accumulator = cv::max(thread_accumulator, image);
      }
    }
  }

  if (cf->startrails_enabled) {
    // skip unlucky threads that might have got only bad images
    if (!thread_accumulator.empty()) {
      mtx->lock();
      if (main_accumulator->empty()) {
        thread_accumulator.copyTo(*main_accumulator);
      } else {
        *main_accumulator = cv::max(thread_accumulator, *main_accumulator);
      }
      mtx->unlock();
    }
  }
}

void parse_args(int argc, char** argv, struct config_t* cf) {
  int c, tmp;
  cf->verbose = 0;
  cf->startrails_enabled = true;
  cf->img_height = cf->img_width = 0;
  cf->brightness_limit = 0.35;  // not terrible in the city
  cf->nice_level = 10;
  cf->num_threads = std::thread::hardware_concurrency();

  while (1) {  // getopt loop
    int option_index = 0;
    static struct option long_options[] = {
        {"brightness", optional_argument, 0, 'b'},
        {"directory", required_argument, 0, 'd'},
        {"extension", required_argument, 0, 'e'},
        {"max-threads", required_argument, 0, 'm'},
        {"nice-level", required_argument, 0, 'n'},
        {"output", required_argument, 0, 'o'},
        {"image-size", required_argument, 0, 's'},
        {"statistics", no_argument, 0, 'S'},
        {"verbose", no_argument, 0, 'v'},
        {"help", no_argument, 0, 'h'},
        {0, 0, 0, 0}};

    c = getopt_long(argc, argv, "hvSb:d:e:m:n:o:s:", long_options,
                    &option_index);
    if (c == -1)
      break;
    switch (c) {  // option switch
      case 'h':
        usage_and_exit(0);
        // NOTREACHED
        break;
      case 'v':
        cf->verbose++;
        break;
      case 'S':
        cf->startrails_enabled = false;
        break;
      case 's':
        int height, width;
        sscanf(optarg, "%dx%d", &width, &height);
        // 122.8Mpx should be enough for anybody.
        if (height < 0 || height > 9600 || width < 0 || width > 12800)
          height = width = 0;
        cf->img_height = height;
        cf->img_width = width;
        break;
      case 'b':
        double b;
        b = atof(optarg);
        if (b >= 0 && b <= 1.0)
          cf->brightness_limit = b;
        break;
      case 'd':
        cf->img_src_dir = optarg;
        break;
      case 'e':
        cf->img_src_ext = optarg;
        break;
      case 'm':
        tmp = atoi(optarg);
        if ((tmp >= 1) || (tmp < cf->num_threads))
          cf->num_threads = tmp;
        break;
      case 'n':
        tmp = atoi(optarg);
        if (PRIO_MIN > tmp) {
          tmp = PRIO_MIN;
          fprintf(stderr, "clamping scheduler priority to PRIO_MIN\n");
        } else if (PRIO_MAX < tmp) {
          fprintf(stderr, "clamping scheduler priority to PRIO_MAX\n");
          tmp = PRIO_MAX;
        }
        cf->nice_level = atoi(optarg);
        break;
      case 'o':
        cf->dst_startrails = optarg;
        break;
      default:
        break;
    }  // option switch
  }    // getopt loop
}

void usage_and_exit(int x) {
  std::cout << "Usage: startrails [-v] -d <dir> -e <ext> [-b <brightness> -o "
               "<output> | -s] [-m <max-threads>] [-n <nice>]"
            << std::endl;
  if (x) {
    std::cout << KRED
              << "Source directory and file extension are always required."
              << std::endl;
    std::cout << "brightness threshold and output file are required to render "
                 "startrails"
              << KNRM << std::endl;
  }

  std::cout << std::endl << "Arguments:" << std::endl;
  std::cout << "-h | --help : display this help, then exit" << std::endl;
  std::cout << "-v | --verbose : increase log verbosity" << std::endl;
  std::cout << "-S | --statistics : print image directory statistics without "
               "producing image."
            << std::endl;
  std::cout << "-d | --directory <str> : directory from which to read images"
            << std::endl;
  std::cout << "-e | --extension <str> : filter images to just this extension"
            << std::endl;
  std::cout << "-m | --max-threads <int> : limit maximum number of processing "
               "threads. (0 = nproc)"
            << std::endl;
  std::cout << "-n | --nice <int> : nice(2) level of processing threads (10)"
            << std::endl;
  std::cout << "-o | --output-file <str> : output image filename" << std::endl;
  std::cout << "-s | --image-size <int>x<int> : restrict processed images to "
               "this size"
            << std::endl;
  std::cout << "-b | --brightness-limit <float> : ranges from 0 (black) to 1 "
               "(white). Default 0.35"
            << std::endl;
  std::cout << "\tA moonless sky may be as low as 0.05 while full moon can be "
               "as high as 0.4"
            << std::endl;
  std::cout << std::endl
            << "ex: startrails -b 0.07 -d ../images/20180208/ -e jpg -o "
               "startrails.jpg"
            << std::endl;
  exit(x);
}

int main(int argc, char* argv[]) {
  int r;
  struct config_t config;
  int i;
  char* e;

  parse_args(argc, argv, &config);

  if (config.verbose < 1)
    if ((e = getenv("ALLSKY_DEBUG_LEVEL")))
      if ((i = atoi(e)) > 0)
        config.verbose = i;

  if (config.img_src_dir.empty() || config.img_src_ext.empty())
    usage_and_exit(3);

  if (!config.startrails_enabled) {
    config.brightness_limit = 0;
    config.dst_startrails = "/dev/null";
  }

  if (!config.dst_startrails.empty() && config.brightness_limit < 0)
    usage_and_exit(3);

  r = setpriority(PRIO_PROCESS, 0, config.nice_level);
  if (r) {
    config.nice_level = getpriority(PRIO_PROCESS, 0);
    fprintf(stderr, "unable to set nice level: %s\n", strerror(errno));
  }

  // Find files
  glob_t files;
  std::string wildcard = config.img_src_dir + "/*." + config.img_src_ext;
  glob(wildcard.c_str(), 0, NULL, &files);
  if (files.gl_pathc == 0) {
    globfree(&files);
    std::cout << "No images found, exiting." << std::endl;
    return 0;
  }

  std::mutex accumulated_mutex;
  cv::Mat accumulated;
  cv::Mat stats;
  stats.create(1, files.gl_pathc, CV_64F);
  // initialize stats to NAN because some images might legitimately be 100%
  // brightness if they're massively overexposed. They should be counted in
  // the summary statistics. It is not entirely accurate to signal invalid
  // images with 1.0 brightness since no image data was read.
  stats = NAN;

  std::vector<std::thread> threadpool;
  for (int tid = 0; tid < config.num_threads; tid++)
    threadpool.push_back(std::thread(startrail_worker, tid, &config, &files,
                                     &accumulated_mutex, &stats, &accumulated));

  for (auto& t : threadpool)
    t.join();

  // Calculate some descriptive statistics
  double ds_min, ds_max, ds_mean, ds_median;
  cv::Point min_loc;

  // Each thread will have updated stats with the brightness of the images
  // that were successfully processed. Invalid images will be left as NAN.
  // In OpenCV, NAN is unequal to everything including NAN which means we can
  // filter out bogus entries by checking stats for element-wise equality
  // with itself.
  cv::Mat nan_mask = cv::Mat(stats == stats);
  cv::Mat filtered_stats;
  stats.copyTo(filtered_stats, nan_mask);
  cv::minMaxLoc(stats, &ds_min, &ds_max, &min_loc);
  ds_mean = cv::mean(filtered_stats)[0];

  // For median, do partial sort and take middle value
  std::vector<double> vec;
  filtered_stats.copyTo(vec);
  std::nth_element(vec.begin(), vec.begin() + (vec.size() / 2), vec.end());
  ds_median = vec[vec.size() / 2];

  std::cout << "Minimum: " << ds_min << " maximum: " << ds_max
            << " mean: " << ds_mean << " median: " << ds_median << std::endl;

  // If we still don't have an image (no images below threshold), copy the
  // minimum mean image so we see why
  if (config.startrails_enabled) {
    if (accumulated.empty()) {
      fprintf(
          stderr,
          "No images below threshold %.3f, writing the minimum image only\n",
          config.brightness_limit);
      accumulated = cv::imread(files.gl_pathv[min_loc.x], cv::IMREAD_UNCHANGED);
    }

    std::vector<int> compression_params;
    compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION);
    compression_params.push_back(9);
    compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
    compression_params.push_back(95);

    cv::imwrite(config.dst_startrails, accumulated, compression_params);
  }
  globfree(&files);
  return 0;
}
<|endoftext|>