<commit_before>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	pqxx/cursor.hxx
 *
 *   DESCRIPTION
 *      definition of the iterator/container-style cursor classes
 *   C++-style wrappers for SQL cursors
 *   DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/pipeline instead.
 *
 * Copyright (c) 2004, 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/libcompiler.h"

#include <limits>
#include <string>

#include "pqxx/result"

namespace pqxx
{
class transaction_base;

/// Common definitions for cursor types
/** @warning This code is experimental.  It is not fully covered by libpqxx'
 * regression tests, and may see considerable change before becoming part of a
 * stable release.  Do not use except to test it.
 */
class PQXX_LIBEXPORT cursor_base
{
public:
  typedef result::size_type size_type;

  operator void *() const { return m_done ? 0 : &s_dummy; }		//[t81]
  bool operator!() const { return m_done; }				//[t81]

  static size_type all() throw ();					//[t81]
  static size_type next() throw () { return 1; }			//[t81]
  static size_type prior() throw () { return -1; }			//[]
  static size_type backward_all() throw ();				//[]

  const PGSTD::string &name() const throw () { return m_name; }		//[t81]

protected:
  cursor_base(transaction_base *context, const PGSTD::string &cname) :
  	m_context(context), m_done(false), m_name(cname)
  {
    m_name += "_";
    m_name += to_string(get_unique_cursor_num());
  }

  transaction_base *m_context;
  bool m_done;

private:
  int get_unique_cursor_num();

  PGSTD::string m_name;

  /// Purely to give us a non-null pointer to return
  static unsigned char s_dummy;

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

inline cursor_base::size_type cursor_base::all() throw ()
{
#ifdef _MSC_VER
  // Microsoft's compiler defines max() and min() macros!  Others may as well
  return INT_MAX;
#else
  return PGSTD::numeric_limits<size_type>::max();
#endif
}

inline cursor_base::size_type cursor_base::backward_all() throw ()
{
#ifdef _MSC_VER
  // Microsoft's compiler defines max() and min() macros!  Others may as well
  return INT_MIN + 1;
#else
  return PGSTD::numeric_limits<size_type>::min() + 1;
#endif
}

/// Simple read-only cursor represented as a stream of results
/** Data is fetched from the cursor as a sequence of result objects.  Each of
 * these will contain the number of rows defined as the stream's stride, except
 * of course the last block of data which may contain fewer rows.
 *
 * @warning This code is experimental.  It is not fully covered by libpqxx'
 * regression tests, and may see considerable change before becoming part of a
 * stable release.  Do not use except to test it.
 */
class PQXX_LIBEXPORT icursorstream : public cursor_base
{
public:
  /// Set up a read-only, forward-only cursor
  /** Roughly equivalent to a C++ Standard Library istream, this cursor type
   * supports only two operations: reading a block of rows while moving forward,
   * and moving forward without reading any data.
   *
   * @param context transaction context that this cursor will be active in
   * @param query SQL query whose results this cursor shall iterate
   * @param basename suggested name for the SQL cursor; a unique code will be
   * appended by the library to ensure its uniqueness
   * @param stride the number of rows to fetch per read operation; must be a
   * positive number
   */
  icursorstream(transaction_base &context,
      const PGSTD::string &query,
      const PGSTD::string &basename,
      size_type stride=1);						//[t81]

  /// Read new value into given result object; same as operator >>
  /** The result set may continue any number of rows from zero to the chosen
   * stride, inclusive.  An empty result will only be returned if there are no
   * more rows to retrieve.
   */
  icursorstream &get(result &res) { res = fetch(); return *this; }	//[]
  /// Read new value into given result object; same as get(result &)
  /** The result set may continue any number of rows from zero to the chosen
   * stride, inclusive.  An empty result will only be returned if there are no
   * more rows to retrieve.
   */
  icursorstream &operator>>(result &res) { return get(res); }		//[t81]
  /// Move given number of rows forward (ignoring stride) without reading data
  icursorstream &ignore(PGSTD::streamsize n=1);				//[]

  /// Change stride, i.e. the number of rows to fetch per read operation
  /**
   * @param stride must be a positive number
   */
  void set_stride(size_type stride);					//[t81]

private:
  void declare(const PGSTD::string &query);
  result fetch();

  size_type m_stride;
};

/// Approximate istream_iterator for icursorstream
/** A rough equivalent of the C++ Standard Library's istream_iterator or
 * input_iterator, this class supports only two basic operations: reading the
 * current element, and moving forward.  In addition to the minimal guarantees
 * for istream_iterators, this class supports multiple successive reads of the
 * same position (the current result set is cached in the iterator) even after
 * copying and even after new data have been read from the stream.
 *
 * The iterator has no concept of its own position, however.  Moving an iterator
 * forward moves the underlying stream forward and reads the data from the new
 * position, regardless of "where the iterator was" in the stream.  Comparison
 * of iterators is only supported for detecting the end of a stream.
 *
 * @warning This code is experimental.  It is not fully covered by libpqxx'
 * regression tests, and may see considerable change before becoming part of a
 * stable release.  Do not use except to test it.
 */
class PQXX_LIBEXPORT icursor_iterator :
  public PGSTD::iterator<PGSTD::input_iterator_tag,
  	result,
	cursor_base::size_type,
	const result *,
	const result &>
{
public:
  typedef icursorstream istream_type;
  typedef istream_type::size_type size_type;

  icursor_iterator() : m_stream(0), m_here(), m_fresh(true) {}		//[]
  icursor_iterator(istream_type &s) :					//[]
    m_stream(&s), m_here(), m_fresh(false) {}
  icursor_iterator(const icursor_iterator &rhs) : 			//[]
    m_stream(rhs.m_stream), m_here(rhs.m_here), m_fresh(rhs.m_fresh) {}

  const result &operator*() const { refresh(); return m_here; }		//[]
  const result *operator->() const { refresh(); return &m_here; }	//[]

  icursor_iterator &operator++() { read(); return *this; }		//[]

  icursor_iterator operator++(int)					//[]
  	{ icursor_iterator old(*this); read(); return old; }

  icursor_iterator &operator+=(size_type n)				//[]
  {
    m_stream->ignore(n);
    m_fresh = false;
    return *this;
  }

  icursor_iterator &operator=(const icursor_iterator &rhs)		//[]
  {
    m_here = rhs.m_here;	// (Already protected against self-assignment)
    m_stream = rhs.m_stream;	// (Does not throw, so we're exception-safe)
    m_fresh = rhs.m_fresh;
    return *this;
  }

  bool operator==(const icursor_iterator &rhs) const throw ()		//[]
  	{ return m_here.empty() && rhs.m_here.empty(); }
  bool operator!=(const icursor_iterator &rhs) const throw ()		//[]
  	{ return !operator==(rhs); }

private:
  void read() const
  {
    m_stream->get(m_here);
    m_fresh = true;
  }
  void refresh() const { if (!m_fresh) read(); }
  icursorstream *m_stream;
  mutable result m_here;
  mutable bool m_fresh;
};

} // namespace pqxx

<commit_msg>Corrected iterator comparison<commit_after>/*-------------------------------------------------------------------------
 *
 *   FILE
 *	pqxx/cursor.hxx
 *
 *   DESCRIPTION
 *      definition of the iterator/container-style cursor classes
 *   C++-style wrappers for SQL cursors
 *   DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/pipeline instead.
 *
 * Copyright (c) 2004, 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/libcompiler.h"

#include <limits>
#include <string>

#include "pqxx/result"

namespace pqxx
{
class transaction_base;

/// Common definitions for cursor types
/** @warning This code is experimental.  It is not fully covered by libpqxx'
 * regression tests, and may see considerable change before becoming part of a
 * stable release.  Do not use except to test it.
 */
class PQXX_LIBEXPORT cursor_base
{
public:
  typedef result::size_type size_type;

  operator void *() const { return m_done ? 0 : &s_dummy; }		//[t81]
  bool operator!() const { return m_done; }				//[t81]

  static size_type all() throw ();					//[t81]
  static size_type next() throw () { return 1; }			//[t81]
  static size_type prior() throw () { return -1; }			//[]
  static size_type backward_all() throw ();				//[]

  const PGSTD::string &name() const throw () { return m_name; }		//[t81]

protected:
  cursor_base(transaction_base *context, const PGSTD::string &cname) :
  	m_context(context), m_done(false), m_name(cname)
  {
    m_name += "_";
    m_name += to_string(get_unique_cursor_num());
  }

  transaction_base *m_context;
  bool m_done;

private:
  int get_unique_cursor_num();

  PGSTD::string m_name;

  /// Purely to give us a non-null pointer to return
  static unsigned char s_dummy;

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

inline cursor_base::size_type cursor_base::all() throw ()
{
#ifdef _MSC_VER
  // Microsoft's compiler defines max() and min() macros!  Others may as well
  return INT_MAX;
#else
  return PGSTD::numeric_limits<size_type>::max();
#endif
}

inline cursor_base::size_type cursor_base::backward_all() throw ()
{
#ifdef _MSC_VER
  // Microsoft's compiler defines max() and min() macros!  Others may as well
  return INT_MIN + 1;
#else
  return PGSTD::numeric_limits<size_type>::min() + 1;
#endif
}

/// Simple read-only cursor represented as a stream of results
/** Data is fetched from the cursor as a sequence of result objects.  Each of
 * these will contain the number of rows defined as the stream's stride, except
 * of course the last block of data which may contain fewer rows.
 *
 * @warning This code is experimental.  It is not fully covered by libpqxx'
 * regression tests, and may see considerable change before becoming part of a
 * stable release.  Do not use except to test it.
 */
class PQXX_LIBEXPORT icursorstream : public cursor_base
{
public:
  /// Set up a read-only, forward-only cursor
  /** Roughly equivalent to a C++ Standard Library istream, this cursor type
   * supports only two operations: reading a block of rows while moving forward,
   * and moving forward without reading any data.
   *
   * @param context transaction context that this cursor will be active in
   * @param query SQL query whose results this cursor shall iterate
   * @param basename suggested name for the SQL cursor; a unique code will be
   * appended by the library to ensure its uniqueness
   * @param stride the number of rows to fetch per read operation; must be a
   * positive number
   */
  icursorstream(transaction_base &context,
      const PGSTD::string &query,
      const PGSTD::string &basename,
      size_type stride=1);						//[t81]

  /// Read new value into given result object; same as operator >>
  /** The result set may continue any number of rows from zero to the chosen
   * stride, inclusive.  An empty result will only be returned if there are no
   * more rows to retrieve.
   */
  icursorstream &get(result &res) { res = fetch(); return *this; }	//[]
  /// Read new value into given result object; same as get(result &)
  /** The result set may continue any number of rows from zero to the chosen
   * stride, inclusive.  An empty result will only be returned if there are no
   * more rows to retrieve.
   */
  icursorstream &operator>>(result &res) { return get(res); }		//[t81]
  /// Move given number of rows forward (ignoring stride) without reading data
  icursorstream &ignore(PGSTD::streamsize n=1);				//[]

  /// Change stride, i.e. the number of rows to fetch per read operation
  /**
   * @param stride must be a positive number
   */
  void set_stride(size_type stride);					//[t81]

private:
  void declare(const PGSTD::string &query);
  result fetch();

  size_type m_stride;
};

/// Approximate istream_iterator for icursorstream
/** Intended as an implementation of an input_iterator (as defined by the C++
 * Standard Library), this class supports only two basic operations: reading the
 * current element, and moving forward.  In addition to the minimal guarantees
 * for istream_iterators, this class supports multiple successive reads of the
 * same position (the current result set is cached in the iterator) even after
 * copying and even after new data have been read from the stream.  This appears
 * to be a requirement for input_iterators.
 *
 * The iterator has no concept of its own position, however.  Moving an iterator
 * forward moves the underlying stream forward and reads the data from the new
 * position, regardless of "where the iterator was" in the stream.  Comparison
 * of iterators is only supported for detecting the end of a stream.
 *
 * @warning This code is experimental.  It is not fully covered by libpqxx'
 * regression tests, and may see considerable change before becoming part of a
 * stable release.  Do not use except to test it.
 */
class PQXX_LIBEXPORT icursor_iterator :
  public PGSTD::iterator<PGSTD::input_iterator_tag,
  	result,
	cursor_base::size_type,
	const result *,
	const result &>
{
public:
  typedef icursorstream istream_type;
  typedef istream_type::size_type size_type;

  icursor_iterator() : m_stream(0), m_here(), m_fresh(true), m_pos(0){}	//[]
  icursor_iterator(istream_type &s) :					//[]
    m_stream(&s), m_here(), m_fresh(false), m_pos(0) {}
  icursor_iterator(const icursor_iterator &rhs) : 			//[]
    m_stream(rhs.m_stream),
    m_here(rhs.m_here),
    m_fresh(rhs.m_fresh),
    m_pos(rhs.m_pos)
  {}

  const result &operator*() const { refresh(); return m_here; }		//[]
  const result *operator->() const { refresh(); return &m_here; }	//[]

  icursor_iterator &operator++() { read(); return *this; }		//[]

  icursor_iterator operator++(int)					//[]
  	{ icursor_iterator old(*this); read(); return old; }

  icursor_iterator &operator+=(size_type n)				//[]
  {
    m_stream->ignore(n);
    m_fresh = false;
    m_pos += n;
    return *this;
  }

  icursor_iterator &operator=(const icursor_iterator &rhs)		//[]
  {
    m_here = rhs.m_here;	// (Already protected against self-assignment)
    m_stream = rhs.m_stream;	// (Does not throw, so we're exception-safe)
    m_fresh = rhs.m_fresh;
    m_pos = rhs.m_pos;
    return *this;
  }

  bool operator==(const icursor_iterator &rhs) const throw ()		//[]
  {
    return (m_stream==rhs.m_stream && m_pos==rhs.m_pos) ||
      (m_here.empty() && rhs.m_here.empty());
  }
  bool operator!=(const icursor_iterator &rhs) const throw ()		//[]
  	{ return !operator==(rhs); }

private:
  void read() const
  {
    m_stream->get(m_here);
    m_fresh = true;
    ++m_pos;
  }
  void refresh() const { if (!m_fresh) read(); }
  icursorstream *m_stream;
  mutable result m_here;
  mutable bool m_fresh;
  mutable result::size_type m_pos;
};

} // namespace pqxx

<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2015                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#ifndef CAF_DESERIALIZER_HPP
#define CAF_DESERIALIZER_HPP

#include <string>
#include <cstddef>

#include "caf/primitive_variant.hpp"
#include "caf/uniform_type_info.hpp"

namespace caf {

class actor_namespace;
class uniform_type_info;

/// @ingroup TypeSystem
/// Technology-independent deserialization interface.
class deserializer {
public:
  explicit deserializer(actor_namespace* ns = nullptr);

  deserializer(const deserializer&) = delete;
  deserializer& operator=(const deserializer&) = delete;

  virtual ~deserializer();

  /// Begins deserialization of a new object.
  virtual const uniform_type_info* begin_object() = 0;

  /// Ends deserialization of an object.
  virtual void end_object() = 0;

  /// Begins deserialization of a sequence.
  /// @returns The size of the sequence.
  virtual size_t begin_sequence() = 0;

  /// Ends deserialization of a sequence.
  virtual void end_sequence() = 0;

  /// Reads a primitive value from the data source.
  virtual void read_value(primitive_variant& storage) = 0;

  /// Reads a value of type `T` from the data source.
  /// @note `T` must be a primitive type.
  template <class T>
  inline T read() {
    primitive_variant val{T()};
    read_value(val);
    return std::move(get<T>(val));
  }

  template <class T>
  inline T read(const uniform_type_info* uti) {
    T result;
    uti->deserialize(&result, this);
    return result;
  }

  template <class T>
  inline deserializer& read(T& storage) {
    primitive_variant val{T()};
    read_value(val);
    storage = std::move(get<T>(val));
    return *this;
  }

  template <class T>
  inline deserializer& read(T& storage, const uniform_type_info* uti) {
    uti->deserialize(&storage, this);
    return *this;
  }

  /// Reads a raw memory block.
  virtual void read_raw(size_t num_bytes, void* storage) = 0;

  inline actor_namespace* get_namespace() {
    return namespace_;
  }

  template <class Buffer>
  void read_raw(size_t num_bytes, Buffer& storage) {
    storage.resize(num_bytes);
    read_raw(num_bytes, storage.data());
  }

protected:
  actor_namespace* namespace_;
};

/// Serializes a value to `s`.
/// @relates serializer
template <class T>
typename std::enable_if<
  detail::is_primitive<T>::value,
  deserializer&
>::type
operator>>(deserializer& source, T& value) {
  return source.read(value);
}

/// Serializes a value to `s`.
/// @relates serializer
template <class T>
typename std::enable_if<
  ! detail::is_primitive<T>::value,
  deserializer&
>::type
operator>>(deserializer& source, T& value) {
  return source.read(value, uniform_typeid<T>());
}

template <class T>
void operator&(deserializer& source, T& value) {
  source >> value;
}

} // namespace caf

#endif // CAF_DESERIALIZER_HPP
<commit_msg>Work around weird static_assert in boost::variant<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2015                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#ifndef CAF_DESERIALIZER_HPP
#define CAF_DESERIALIZER_HPP

#include <string>
#include <cstddef>

#include "caf/primitive_variant.hpp"
#include "caf/uniform_type_info.hpp"

namespace caf {

class actor_namespace;
class uniform_type_info;

/// @ingroup TypeSystem
/// Technology-independent deserialization interface.
class deserializer {
public:
  explicit deserializer(actor_namespace* ns = nullptr);

  deserializer(const deserializer&) = delete;
  deserializer& operator=(const deserializer&) = delete;

  virtual ~deserializer();

  /// Begins deserialization of a new object.
  virtual const uniform_type_info* begin_object() = 0;

  /// Ends deserialization of an object.
  virtual void end_object() = 0;

  /// Begins deserialization of a sequence.
  /// @returns The size of the sequence.
  virtual size_t begin_sequence() = 0;

  /// Ends deserialization of a sequence.
  virtual void end_sequence() = 0;

  /// Reads a primitive value from the data source.
  virtual void read_value(primitive_variant& storage) = 0;

  /// Reads a value of type `T` from the data source.
  /// @note `T` must be a primitive type.
  template <class T>
  inline T read() {
    primitive_variant val{T()};
    read_value(val);
    // works around the all-to-strict boost::strict_get of boost::variant
    using result =
      typename std::conditional<
        std::is_same<T, char>::value,
        uint8_t,
        T
      >::type;
    return std::move(get<result>(val));
  }

  template <class T>
  inline T read(const uniform_type_info* uti) {
    T result;
    uti->deserialize(&result, this);
    return result;
  }

  template <class T>
  inline deserializer& read(T& storage) {
    primitive_variant val{T()};
    read_value(val);
    storage = std::move(get<T>(val));
    return *this;
  }

  template <class T>
  inline deserializer& read(T& storage, const uniform_type_info* uti) {
    uti->deserialize(&storage, this);
    return *this;
  }

  /// Reads a raw memory block.
  virtual void read_raw(size_t num_bytes, void* storage) = 0;

  inline actor_namespace* get_namespace() {
    return namespace_;
  }

  template <class Buffer>
  void read_raw(size_t num_bytes, Buffer& storage) {
    storage.resize(num_bytes);
    read_raw(num_bytes, storage.data());
  }

protected:
  actor_namespace* namespace_;
};

/// Serializes a value to `s`.
/// @relates serializer
template <class T>
typename std::enable_if<
  detail::is_primitive<T>::value,
  deserializer&
>::type
operator>>(deserializer& source, T& value) {
  return source.read(value);
}

/// Serializes a value to `s`.
/// @relates serializer
template <class T>
typename std::enable_if<
  ! detail::is_primitive<T>::value,
  deserializer&
>::type
operator>>(deserializer& source, T& value) {
  return source.read(value, uniform_typeid<T>());
}

template <class T>
void operator&(deserializer& source, T& value) {
  source >> value;
}

} // namespace caf

#endif // CAF_DESERIALIZER_HPP
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Unit tests for the solidity compiler.
 */

#include <string>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <libdevcore/Log.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/AST.h>

using namespace std;
using namespace dev::eth;

namespace dev
{
namespace solidity
{
namespace test
{

namespace
{

bytes compileContract(const string& _sourceCode)
{
	Parser parser;
	ASTPointer<SourceUnit> sourceUnit;
	BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode))));
	NameAndTypeResolver resolver({});
	resolver.registerDeclarations(*sourceUnit);
	for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
		if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
		{
			BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));
		}
	for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
		if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
		{
			BOOST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract));
		}
	for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
		if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
		{
			Compiler compiler;
			compiler.compileContract(*contract, map<ContractDefinition const*, bytes const*>{});

			// debug
			//compiler.streamAssembly(cout);
			return compiler.getAssembledBytecode();
		}
	BOOST_FAIL("No contract found in source.");
	return bytes();
}

/// Checks that @a _compiledCode is present starting from offset @a _offset in @a _expectation.
/// This is necessary since the compiler will add boilerplate add the beginning that is not
/// tested here.
void checkCodePresentAt(bytes const& _compiledCode, bytes const& _expectation, unsigned _offset)
{
	BOOST_REQUIRE(_compiledCode.size() >= _offset + _expectation.size());
	auto checkStart = _compiledCode.begin() + _offset;
	BOOST_CHECK_EQUAL_COLLECTIONS(checkStart, checkStart + _expectation.size(),
								  _expectation.begin(), _expectation.end());
}

} // end anonymous namespace

BOOST_AUTO_TEST_SUITE(SolidityCompiler)

BOOST_AUTO_TEST_CASE(smoke_test)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { var x = 2; }\n"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned boilerplateSize = 73;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0, // initialize local variable x
					   byte(Instruction::PUSH1), 0x2,
					   byte(Instruction::SWAP1),
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP)});
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(ifStatement)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { bool x; if (x) 77; else if (!x) 78; else 79; }"
							 "}\n";
	bytes code = compileContract(sourceCode);
	unsigned shift = 60;
	unsigned boilerplateSize = 73;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0,
					   byte(Instruction::DUP1),
					   byte(Instruction::PUSH1), byte(0x1b + shift), // "true" target
					   byte(Instruction::JUMPI),
					   // new check "else if" condition
					   byte(Instruction::DUP1),
					   byte(Instruction::ISZERO),
					   byte(Instruction::PUSH1), byte(0x13 + shift),
					   byte(Instruction::JUMPI),
					   // "else" body
					   byte(Instruction::PUSH1), 0x4f,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x17 + shift), // exit path of second part
					   byte(Instruction::JUMP),
					   // "else if" body
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x4e,
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), byte(0x1f + shift),
					   byte(Instruction::JUMP),
					   // "if" body
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x4d,
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP)});
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(loops)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { while(true){1;break;2;continue;3;return;4;} }"
							 "}\n";
	bytes code = compileContract(sourceCode);
	unsigned shift = 60;
	unsigned boilerplateSize = 73;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x1,
					   byte(Instruction::ISZERO),
					   byte(Instruction::PUSH1), byte(0x21 + shift),
					   byte(Instruction::JUMPI),
					   byte(Instruction::PUSH1), 0x1,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x21 + shift),
					   byte(Instruction::JUMP), // break
					   byte(Instruction::PUSH1), 0x2,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x2 + shift),
					   byte(Instruction::JUMP), // continue
					   byte(Instruction::PUSH1), 0x3,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x22 + shift),
					   byte(Instruction::JUMP), // return
					   byte(Instruction::PUSH1), 0x4,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x2 + shift),
					   byte(Instruction::JUMP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMP)});

	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_SUITE_END()

}
}
} // end namespaces
<commit_msg>Reverse if and else body.<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Unit tests for the solidity compiler.
 */

#include <string>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <libdevcore/Log.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/AST.h>

using namespace std;
using namespace dev::eth;

namespace dev
{
namespace solidity
{
namespace test
{

namespace
{

bytes compileContract(const string& _sourceCode)
{
	Parser parser;
	ASTPointer<SourceUnit> sourceUnit;
	BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode))));
	NameAndTypeResolver resolver({});
	resolver.registerDeclarations(*sourceUnit);
	for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
		if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
		{
			BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));
		}
	for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
		if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
		{
			BOOST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract));
		}
	for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
		if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
		{
			Compiler compiler;
			compiler.compileContract(*contract, map<ContractDefinition const*, bytes const*>{});

			// debug
			//compiler.streamAssembly(cout);
			return compiler.getAssembledBytecode();
		}
	BOOST_FAIL("No contract found in source.");
	return bytes();
}

/// Checks that @a _compiledCode is present starting from offset @a _offset in @a _expectation.
/// This is necessary since the compiler will add boilerplate add the beginning that is not
/// tested here.
void checkCodePresentAt(bytes const& _compiledCode, bytes const& _expectation, unsigned _offset)
{
	BOOST_REQUIRE(_compiledCode.size() >= _offset + _expectation.size());
	auto checkStart = _compiledCode.begin() + _offset;
	BOOST_CHECK_EQUAL_COLLECTIONS(checkStart, checkStart + _expectation.size(),
								  _expectation.begin(), _expectation.end());
}

} // end anonymous namespace

BOOST_AUTO_TEST_SUITE(SolidityCompiler)

BOOST_AUTO_TEST_CASE(smoke_test)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { var x = 2; }\n"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned boilerplateSize = 73;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0, // initialize local variable x
					   byte(Instruction::PUSH1), 0x2,
					   byte(Instruction::SWAP1),
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP)});
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(ifStatement)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { bool x; if (x) 77; else if (!x) 78; else 79; }"
							 "}\n";
	bytes code = compileContract(sourceCode);
	unsigned shift = 60;
	unsigned boilerplateSize = 73;
	bytes expectation({
		byte(Instruction::JUMPDEST),
		byte(Instruction::PUSH1), 0x0,
		byte(Instruction::DUP1),
		byte(Instruction::ISZERO),
		byte(Instruction::PUSH1), byte(0x0f + shift), // "false" target
		byte(Instruction::JUMPI),
		// "if" body
		byte(Instruction::PUSH1), 0x4d,
		byte(Instruction::POP),
		byte(Instruction::PUSH1), byte(0x21 + shift),
		byte(Instruction::JUMP),
		// new check "else if" condition
		byte(Instruction::JUMPDEST),
		byte(Instruction::DUP1),
		byte(Instruction::ISZERO),
		byte(Instruction::ISZERO),
		byte(Instruction::PUSH1), byte(0x1c + shift),
		byte(Instruction::JUMPI),
		// "else if" body
		byte(Instruction::PUSH1), 0x4e,
		byte(Instruction::POP),
		byte(Instruction::PUSH1), byte(0x20 + shift),
		byte(Instruction::JUMP),
		// "else" body
		byte(Instruction::JUMPDEST),
		byte(Instruction::PUSH1), 0x4f,
		byte(Instruction::POP),
	});
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(loops)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { while(true){1;break;2;continue;3;return;4;} }"
							 "}\n";
	bytes code = compileContract(sourceCode);
	unsigned shift = 60;
	unsigned boilerplateSize = 73;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x1,
					   byte(Instruction::ISZERO),
					   byte(Instruction::PUSH1), byte(0x21 + shift),
					   byte(Instruction::JUMPI),
					   byte(Instruction::PUSH1), 0x1,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x21 + shift),
					   byte(Instruction::JUMP), // break
					   byte(Instruction::PUSH1), 0x2,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x2 + shift),
					   byte(Instruction::JUMP), // continue
					   byte(Instruction::PUSH1), 0x3,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x22 + shift),
					   byte(Instruction::JUMP), // return
					   byte(Instruction::PUSH1), 0x4,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), byte(0x2 + shift),
					   byte(Instruction::JUMP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMP)});

	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_SUITE_END()

}
}
} // end namespaces
<|endoftext|>


<commit_before>#ifndef FILE_SOLDATA
#define FILE_SOLDATA

namespace netgen
{

  using namespace std;

  class SolutionData
  {
  protected:

    string name;
    int components;
    bool iscomplex;

    int multidimcomponent;

  public:
    SolutionData (const string & aname,
                  int acomponents = 1, bool aiscomplex = 0)
      : name(aname), components(acomponents), iscomplex(aiscomplex)
    { ; }

    virtual ~SolutionData ()
    { ; }

    int GetComponents() { return components; }
    bool IsComplex() { return iscomplex; }

    virtual bool GetValue (int /* elnr */,
                           double /* lam1 */, double /* lam2 */, double /* lam3 */,
                           double * /* values */)
    { return false; }

    virtual bool GetValue (int selnr,
                           const double xref[], const double x[], const double dxdxref[],
                           double * values)
    { return GetValue (selnr, xref[0], xref[1], xref[2], values); }

    virtual bool GetSurfValue (int /* selnr */,
                               double /* lam1 */, double /* lam2 */,
                               double * /* values */)
    { return false; }

    virtual bool GetSurfValue (int selnr,
                               const double xref[], const double x[], const double dxdxref[],
                               double * values)
    { return GetSurfValue (selnr, xref[0], xref[1], values); }

    virtual bool GetMultiSurfValue (int selnr, int npts,
                                    const double * xref, int sxref,
                                    const double * x, int sx,
                                    const double * dxdxref, int sdxdxref,
                                    double * values, int svalues);

    void SetMultiDimComponent (int mc)
    { multidimcomponent = mc; }
  };
}

#endif

<commit_msg>dll-export<commit_after>#ifndef FILE_SOLDATA
#define FILE_SOLDATA

namespace netgen
{

  using namespace std;

  class DLL_HEADER SolutionData
  {
  protected:

    string name;
    int components;
    bool iscomplex;

    int multidimcomponent;

  public:
    SolutionData (const string & aname,
                  int acomponents = 1, bool aiscomplex = 0)
      : name(aname), components(acomponents), iscomplex(aiscomplex)
    { ; }

    virtual ~SolutionData ()
    { ; }

    int GetComponents() { return components; }
    bool IsComplex() { return iscomplex; }

    virtual bool GetValue (int /* elnr */,
                           double /* lam1 */, double /* lam2 */, double /* lam3 */,
                           double * /* values */)
    { return false; }

    virtual bool GetValue (int selnr,
                           const double xref[], const double x[], const double dxdxref[],
                           double * values)
    { return GetValue (selnr, xref[0], xref[1], xref[2], values); }

    virtual bool GetSurfValue (int /* selnr */,
                               double /* lam1 */, double /* lam2 */,
                               double * /* values */)
    { return false; }

    virtual bool GetSurfValue (int selnr,
                               const double xref[], const double x[], const double dxdxref[],
                               double * values)
    { return GetSurfValue (selnr, xref[0], xref[1], values); }

    virtual bool GetMultiSurfValue (int selnr, int npts,
                                    const double * xref, int sxref,
                                    const double * x, int sx,
                                    const double * dxdxref, int sdxdxref,
                                    double * values, int svalues);

    void SetMultiDimComponent (int mc)
    { multidimcomponent = mc; }
  };
}

#endif

<|endoftext|>


<commit_before>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#include "vast/concept/parseable/to.hpp"
#include "vast/concept/parseable/vast/expression.hpp"

#include "vast/query_options.hpp"
#include "vast/table_slice_handle.hpp"

#include "vast/system/archive.hpp"
#include "vast/system/exporter.hpp"
#include "vast/system/importer.hpp"
#include "vast/system/index.hpp"
#include "vast/system/replicated_store.hpp"

#include "vast/detail/spawn_container_source.hpp"

#define SUITE exporter
#include "test.hpp"
#include "fixtures/actor_system_and_events.hpp"

using namespace caf;
using namespace vast;

using std::string;
using std::chrono_literals::operator""ms;

namespace {

using fixture_base = fixtures::deterministic_actor_system_and_events;

struct fixture : fixture_base {
  fixture() {
    expr = unbox(to<expression>("service == \"http\" "
                                "&& :addr == 212.227.96.110"));
  }

  ~fixture() {
    for (auto& hdl : {index, importer, exporter, consensus})
      self->send_exit(hdl, exit_reason::user_shutdown);
    self->send_exit(archive, exit_reason::user_shutdown);
    self->send_exit(meta_store, exit_reason::user_shutdown);
    run();
  }

  void spawn_index() {
    index = self->spawn(system::index, directory / "index", 10000, 5, 5, 1);
  }

  void spawn_archive() {
    archive = self->spawn(system::archive, directory / "archive", 1, 1024);
  }

  void spawn_importer() {
    importer = self->spawn(system::importer, directory / "importer",
                           slice_size);
  }

  void spawn_consensus() {
    consensus = self->spawn(system::raft::consensus, directory / "consensus");
  }

  void spawn_meta_store() {
    if (!consensus)
      spawn_consensus();
    meta_store = self->spawn(system::replicated_store<string, data>, consensus);
  }

  void spawn_exporter(query_options opts) {
    exporter = self->spawn(system::exporter, expr, opts);
  }

  void importer_setup() {
    if (!index)
      spawn_index();
    if (!archive)
      spawn_archive();
    if (!importer)
      spawn_importer();
    if (!meta_store)
      spawn_meta_store();
    send(consensus, system::run_atom::value);
    run();
    send(importer, archive);
    send(importer, system::index_atom::value, index);
    send(importer, meta_store);
    run();
  }

  void exporter_setup(query_options opts) {
    spawn_exporter(opts);
    send(exporter, archive);
    send(exporter, system::index_atom::value, index);
    send(exporter, system::sink_atom::value, self);
    send(exporter, system::run_atom::value);
    send(exporter, system::extract_atom::value);
    run();
  }

  template <class Hdl, class... Ts>
  void send(Hdl hdl, Ts&&... xs) {
    self->send(hdl, std::forward<Ts>(xs)...);
  }

  auto fetch_results() {
    std::vector<event> result;
    bool done = false;
    self->do_receive(
      [&](std::vector<event>& xs) {
        MESSAGE("... got " << xs.size() << " events");
        std::move(xs.begin(), xs.end(), std::back_inserter(result));
      },
      error_handler(),
      after(0ms) >> [&] {
        done = true;
      }
    ).until(done);
    MESSAGE("got " << result.size() << " events in total");
    return result;
  }

  actor index;
  system::archive_type archive;
  actor importer;
  actor exporter;
  actor consensus;
  system::meta_store_type meta_store;
  expression expr;
};

} // namespace <anonymous>

FIXTURE_SCOPE(exporter_tests, fixture)

TEST(historical query without importer) {
  MESSAGE("spawn index and archive");
  spawn_index();
  spawn_archive();
  run();
  MESSAGE("ingest conn.log into archive and index");
  vast::detail::spawn_container_source(sys, const_bro_conn_log_slices, index,
                                       archive);
  run();
  MESSAGE("spawn exporter for historical query");
  exporter_setup(historical);
  MESSAGE("fetch results");
  auto results = fetch_results();
  REQUIRE_EQUAL(results.size(), 28u);
  std::sort(results.begin(), results.end());
  CHECK_EQUAL(results.front().id(), 105u);
  CHECK_EQUAL(results.front().type().name(), "bro::conn");
  CHECK_EQUAL(results.back().id(), 8354u);
}

TEST(historical query with importer) {
  MESSAGE("prepare importer");
  importer_setup();
  MESSAGE("ingest conn.log via importer");
  // We need to copy bro_conn_log_slices here, because the importer will assign
  // IDs to the slices it received and we mustn't mess our static test data.
  vast::detail::spawn_container_source(sys, copy(bro_conn_log_slices),
                                       importer);
  run();
  MESSAGE("spawn exporter for historical query");
  exporter_setup(historical);
  MESSAGE("fetch results");
  auto results = fetch_results();
  REQUIRE_EQUAL(results.size(), 28u);
  std::sort(results.begin(), results.end());
  CHECK_EQUAL(results.front().id(), 105u);
  CHECK_EQUAL(results.front().type().name(), "bro::conn");
  CHECK_EQUAL(results.back().id(), 8354u);
}

TEST(continuous query with exporter only) {
  MESSAGE("prepare exporter for continuous query");
  spawn_exporter(continuous);
  send(exporter, system::sink_atom::value, self);
  send(exporter, system::extract_atom::value);
  run();
  MESSAGE("send conn.log directly to exporter");
  vast::detail::spawn_container_source(sys, const_bro_conn_log_slices,
                                       exporter);
  run();
  MESSAGE("fetch results");
  auto results = fetch_results();
  REQUIRE_EQUAL(results.size(), 28u);
  std::sort(results.begin(), results.end());
  CHECK_EQUAL(results.front().id(), 105u);
  CHECK_EQUAL(results.front().type().name(), "bro::conn");
  CHECK_EQUAL(results.back().id(), 8354u);
}

TEST(continuous query with importer) {
  MESSAGE("prepare importer");
  importer_setup();
  MESSAGE("prepare exporter for continous query");
  exporter_setup(continuous);
  send(importer, system::exporter_atom::value, exporter);
  MESSAGE("ingest conn.log via importer");
  // Again: copy because we musn't mutate static test data.
  vast::detail::spawn_container_source(sys, copy(bro_conn_log_slices),
                                       importer);
  run();
  MESSAGE("fetch results");
  auto results = fetch_results();
  REQUIRE_EQUAL(results.size(), 28u);
  std::sort(results.begin(), results.end());
  CHECK_EQUAL(results.front().id(), 105u);
  CHECK_EQUAL(results.front().type().name(), "bro::conn");
  CHECK_EQUAL(results.back().id(), 8354u);
}

FIXTURE_SCOPE_END()
<commit_msg>Temporarily disable exporter unit tests<commit_after>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#include "vast/concept/parseable/to.hpp"
#include "vast/concept/parseable/vast/expression.hpp"

#include "vast/query_options.hpp"
#include "vast/table_slice_handle.hpp"

#include "vast/system/archive.hpp"
#include "vast/system/exporter.hpp"
#include "vast/system/importer.hpp"
#include "vast/system/index.hpp"
#include "vast/system/replicated_store.hpp"

#include "vast/detail/spawn_container_source.hpp"

#define SUITE exporter
#include "test.hpp"
#include "fixtures/actor_system_and_events.hpp"

using namespace caf;
using namespace vast;

using std::string;
using std::chrono_literals::operator""ms;

namespace {

using fixture_base = fixtures::deterministic_actor_system_and_events;

struct fixture : fixture_base {
  fixture() {
    expr = unbox(to<expression>("service == \"http\" "
                                "&& :addr == 212.227.96.110"));
  }

  ~fixture() {
    for (auto& hdl : {index, importer, exporter, consensus})
      self->send_exit(hdl, exit_reason::user_shutdown);
    self->send_exit(archive, exit_reason::user_shutdown);
    self->send_exit(meta_store, exit_reason::user_shutdown);
    run();
  }

  void spawn_index() {
    index = self->spawn(system::index, directory / "index", 10000, 5, 5, 1);
  }

  void spawn_archive() {
    archive = self->spawn(system::archive, directory / "archive", 1, 1024);
  }

  void spawn_importer() {
    importer = self->spawn(system::importer, directory / "importer",
                           slice_size);
  }

  void spawn_consensus() {
    consensus = self->spawn(system::raft::consensus, directory / "consensus");
  }

  void spawn_meta_store() {
    if (!consensus)
      spawn_consensus();
    meta_store = self->spawn(system::replicated_store<string, data>, consensus);
  }

  void spawn_exporter(query_options opts) {
    exporter = self->spawn(system::exporter, expr, opts);
  }

  void importer_setup() {
    if (!index)
      spawn_index();
    if (!archive)
      spawn_archive();
    if (!importer)
      spawn_importer();
    if (!meta_store)
      spawn_meta_store();
    send(consensus, system::run_atom::value);
    run();
    send(importer, archive);
    send(importer, system::index_atom::value, index);
    send(importer, meta_store);
    run();
  }

  void exporter_setup(query_options opts) {
    spawn_exporter(opts);
    send(exporter, archive);
    send(exporter, system::index_atom::value, index);
    send(exporter, system::sink_atom::value, self);
    send(exporter, system::run_atom::value);
    send(exporter, system::extract_atom::value);
    run();
  }

  template <class Hdl, class... Ts>
  void send(Hdl hdl, Ts&&... xs) {
    self->send(hdl, std::forward<Ts>(xs)...);
  }

  auto fetch_results() {
    std::vector<event> result;
    bool done = false;
    self->do_receive(
      [&](std::vector<event>& xs) {
        MESSAGE("... got " << xs.size() << " events");
        std::move(xs.begin(), xs.end(), std::back_inserter(result));
      },
      error_handler(),
      after(0ms) >> [&] {
        done = true;
      }
    ).until(done);
    MESSAGE("got " << result.size() << " events in total");
    return result;
  }

  actor index;
  system::archive_type archive;
  actor importer;
  actor exporter;
  actor consensus;
  system::meta_store_type meta_store;
  expression expr;
};

} // namespace <anonymous>

FIXTURE_SCOPE(exporter_tests, fixture)

TEST_DISABLED(historical query without importer) {
  MESSAGE("spawn index and archive");
  spawn_index();
  spawn_archive();
  run();
  MESSAGE("ingest conn.log into archive and index");
  vast::detail::spawn_container_source(sys, const_bro_conn_log_slices, index,
                                       archive);
  run();
  MESSAGE("spawn exporter for historical query");
  exporter_setup(historical);
  MESSAGE("fetch results");
  auto results = fetch_results();
  REQUIRE_EQUAL(results.size(), 28u);
  std::sort(results.begin(), results.end());
  CHECK_EQUAL(results.front().id(), 105u);
  CHECK_EQUAL(results.front().type().name(), "bro::conn");
  CHECK_EQUAL(results.back().id(), 8354u);
}

TEST_DISABLED(historical query with importer) {
  MESSAGE("prepare importer");
  importer_setup();
  MESSAGE("ingest conn.log via importer");
  // We need to copy bro_conn_log_slices here, because the importer will assign
  // IDs to the slices it received and we mustn't mess our static test data.
  vast::detail::spawn_container_source(sys, copy(bro_conn_log_slices),
                                       importer);
  run();
  MESSAGE("spawn exporter for historical query");
  exporter_setup(historical);
  MESSAGE("fetch results");
  auto results = fetch_results();
  REQUIRE_EQUAL(results.size(), 28u);
  std::sort(results.begin(), results.end());
  CHECK_EQUAL(results.front().id(), 105u);
  CHECK_EQUAL(results.front().type().name(), "bro::conn");
  CHECK_EQUAL(results.back().id(), 8354u);
}

TEST_DISABLED(continuous query with exporter only) {
  MESSAGE("prepare exporter for continuous query");
  spawn_exporter(continuous);
  send(exporter, system::sink_atom::value, self);
  send(exporter, system::extract_atom::value);
  run();
  MESSAGE("send conn.log directly to exporter");
  vast::detail::spawn_container_source(sys, const_bro_conn_log_slices,
                                       exporter);
  run();
  MESSAGE("fetch results");
  auto results = fetch_results();
  REQUIRE_EQUAL(results.size(), 28u);
  std::sort(results.begin(), results.end());
  CHECK_EQUAL(results.front().id(), 105u);
  CHECK_EQUAL(results.front().type().name(), "bro::conn");
  CHECK_EQUAL(results.back().id(), 8354u);
}

TEST_DISABLED(continuous query with importer) {
  MESSAGE("prepare importer");
  importer_setup();
  MESSAGE("prepare exporter for continous query");
  exporter_setup(continuous);
  send(importer, system::exporter_atom::value, exporter);
  MESSAGE("ingest conn.log via importer");
  // Again: copy because we musn't mutate static test data.
  vast::detail::spawn_container_source(sys, copy(bro_conn_log_slices),
                                       importer);
  run();
  MESSAGE("fetch results");
  auto results = fetch_results();
  REQUIRE_EQUAL(results.size(), 28u);
  std::sort(results.begin(), results.end());
  CHECK_EQUAL(results.front().id(), 105u);
  CHECK_EQUAL(results.front().type().name(), "bro::conn");
  CHECK_EQUAL(results.back().id(), 8354u);
}

FIXTURE_SCOPE_END()
<|endoftext|>


<commit_before>#include <lms/internal/framework.h>
#include <lms/internal/executionmanager.h>
#include <pugixml.hpp>
#include <fstream>
#include <csignal>
#include <map>
#include <thread>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <unistd.h>
#include <sys/stat.h>
#include "lms/internal/backtrace_formatter.h"
#include "lms/logger.h"
#include "lms/time.h"
#include "lms/config.h"
#include "lms/extra/string.h"
#include "lms/internal/xml_parser.h"
#include "lms/extra/colors.h"
#include "lms/definitions.h"
#include "lms/internal/runtime.h"
#include "lms/extra/os.h"
#include "lms/logging/debug_server_sink.h"

namespace lms {
namespace internal {

std::string Framework::externalDirectory = LMS_EXTERNAL;
std::string Framework::configsDirectory = LMS_CONFIGS;

Framework::Framework(const ArgumentHandler &arguments) :
    logger("lms.Framework"), argumentHandler(arguments),
    m_running(false) {

    logging::Context &ctx = logging::Context::getDefault();

    if(! arguments.argQuiet) {
        ctx.appendSink(new logging::ConsoleSink(std::cout));
    }

    if(! arguments.argLogFile.empty()) {
        ctx.appendSink(new logging::FileSink(arguments.argLogFile));
    }

    SignalHandler::getInstance()
            .addListener(SIGINT, this)
            .addListener(SIGSEGV, this)
            .addListener(SIGUSR1, this);

    if(arguments.argEnableDebugServer) {
        if(arguments.argDebugServerBind.find('/') == std::string::npos) {
            m_debugServer.useDualstack(atoi(arguments.argDebugServerBind.c_str()));
        } else {
            m_debugServer.useUnix(arguments.argDebugServerBind);
        }
        m_debugServer.startThread();

        ctx.appendSink(new logging::DebugServerSink(&m_debugServer));

        m_profiler.appendListener(new DebugServerProfiler(&m_debugServer));
    }

    if(! argumentHandler.argProfilingFile.empty()) {
        logger.info() << "Enable profiling";
        m_profiler.appendListener(new FileProfiler(arguments.argProfilingFile));
    } else {
        logger.info() << "Disable profiling";
    }

    logger.info() << "RunLevel " <<  arguments.argRunLevel;

    std::unique_ptr<logging::ThresholdFilter> filter;

#ifndef LMS_STANDALONE
    m_serviceLoader.addModulePath(LMS_SERVICES, 0);
#endif
    char *lms_service_path = std::getenv("LMS_SERVICE_PATH");
    if(lms_service_path != nullptr && lms_service_path[0] != '\0') {
        m_serviceLoader.addModulePath(lms_service_path, 0);
    }

    //parse framework config
    if(arguments.argRunLevel >= RunLevel::CONFIG) {

        Runtime* rt = new Runtime("default", *this);
        registerRuntime(rt);

        XmlParser parser(*this, rt, arguments);
        parser.parseConfig(XmlParser::LoadConfigFlag::LOAD_EVERYTHING, arguments.argLoadConfiguration);

        for(const auto& rt : runtimes) {
            logger.info("registerRuntime") << rt.first << " " <<
                lms::executionTypeName(rt.second->executionType());
        }

        filter = parser.filter();

        for(auto error : parser.errors()) {
            logger.error() << error;
        }

        for(auto file : parser.files()) {
            configMonitor.watch(file);
        }
    }

    if(arguments.argRunLevel >= RunLevel::ENABLE) {
        if(arguments.argEnableLoad) {
            if(arguments.argEnableLoadPath.find('/') == std::string::npos) {
                // no slashes
                m_loadLogPath = lms::extra::homepath() + "/.lmslog/" + arguments.argEnableLoadPath;
            } else {
                m_loadLogPath = arguments.argEnableLoadPath;
            }

            if(extra::fileType(m_loadLogPath) != extra::FileType::DIRECTORY) {
                logger.error() << "Given load path is not a directory: " << m_loadLogPath;
                return;
            }

            logger.info() << "Enable load: " << m_loadLogPath;
        }
        if(arguments.argEnableSave) {
            m_saveLogPath = lms::extra::homepath() + "/.lmslog";
            mkdir(m_saveLogPath.c_str(), MODE);

            m_saveLogPath += "/" + currentTimeString();
            if(! arguments.argEnableSaveTag.empty()) {
                m_saveLogPath += "-" + arguments.argEnableSaveTag;
            }
            mkdir(m_saveLogPath.c_str(), MODE);

            logger.info() << "Enable save: " << m_saveLogPath;
        }

        for(auto& service : services) {
            if(m_serviceLoader.load(service.second.get())) {
                service.second->instance()->initBase(service.second.get(), service.second->defaultLogLevel());

                try {
                    if(! service.second->instance()->init()) {
                        logger.error() << "Library " << service.first << " failed to init()";
                        return;
                    }
                } catch(std::exception const& ex) {
                    logger.error() << service.first << " throws " << extra::typeName(ex) << " : " << ex.what();
                    return;
                }
            } else {
                return;
            }
        }

#ifndef LMS_STANDALONE
        m_moduleLoader.addModulePath(LMS_MODULES, 0);
#endif
        char *lms_module_path = std::getenv("LMS_MODULE_PATH");
        if(lms_module_path != nullptr && lms_module_path[0] != '\0') {
            m_moduleLoader.addModulePath(lms_module_path, 0);
        }

        // enable modules after they were made available
        logger.info() << "Start enabling modules";

        for(auto& runtime : runtimes) {
            if(! runtime.second->enableModules()) {
                return;
            }
        }
    }

    if(arguments.argRunLevel >= RunLevel::CYCLE) {
        logger.info() << "Start running modules";

        if(! filter) { // check if filter == nullptr
            filter.reset(new logging::ThresholdFilter(arguments.argLoggingThreshold));
        }
        if(arguments.argDefinedLoggingThreshold) {
            filter->defaultThreshold(arguments.argLoggingThreshold);
        }
        ctx.filter(filter.release());

        // start threaded runtimes
        for(auto& runtime : runtimes) {
            if(runtime.second->executionType() == ExecutionType::NEVER_MAIN_THREAD) {
                runtime.second->startAsync();
            }
        }

        // run main thread runtimes
        m_running = true;

        while(m_running) {
            bool anyCycle = false;

            for(auto& runtime : runtimes) {
                if(runtime.second->executionType() == ExecutionType::ONLY_MAIN_THREAD) {
                    if(runtime.second->cycle()) {
                        anyCycle = true;
                    }
                }
            }

            // wait some time if there are no main thread runtimes
            // TODO this should wait for SIGINT instead
            if(! anyCycle) {
                Time::fromMillis(100).sleep();
            }

            // config monitor stuff
            if(lms::extra::FILE_MONITOR_SUPPORTED && configMonitor.hasChangedFiles()) {
                logger.info() << "Reload configs";
                configMonitor.unwatchAll();
                XmlParser parser(*this, getRuntimeByName("default"), arguments);
                parser.parseConfig(XmlParser::LoadConfigFlag::ONLY_MODULE_CONFIG,
                                   arguments.argLoadConfiguration);

                for(auto error : parser.errors()) {
                    logger.error() << error;
                }

                for(auto file : parser.files()) {
                    configMonitor.watch(file);
                }
            }
        }

        // wait for threaded runtimes to stop
        for(auto& rt : runtimes) {
            if(rt.second->executionType() == ExecutionType::NEVER_MAIN_THREAD) {
                rt.second->join();
            }
        }

        ctx.filter(nullptr);
        logger.info() << "Stopped";
    }

    exportGraphs();
}

Framework::~Framework() {
    for(auto& service : services) {
        if(service.second && service.second->instance() != nullptr) {
            try {
                service.second->instance()->destroy();
            } catch(std::exception const& ex) {
                logger.error() << service.first << " throws " << extra::typeName(ex) << " : " << ex.what();
            }
        }
    }

    SignalHandler::getInstance()
            .removeListener(SIGINT, this)
            .removeListener(SIGSEGV, this);
}

void Framework::signal(int s) {
    switch (s) {
    case SIGINT:
        for(auto& runtime : runtimes) {
            runtime.second->stopAsync();
        }
        m_running = false;

        SignalHandler::getInstance().removeListener(SIGINT, this);

        break;
    case SIGSEGV:
        //Segmentation Fault - try to identify what went wrong;
        std::cerr << std::endl << lms::extra::COLOR_RED
                << "######################################################" << std::endl
                << "                   Segfault Found                     " << std::endl
                << "######################################################" << std::endl
                << lms::extra::COLOR_WHITE;

        //In Case of Segfault while recovering - shutdown.
        SignalHandler::getInstance().removeListener(SIGSEGV, this);

        printStacktrace();

        exit(EXIT_FAILURE);

        break;
    case SIGUSR1:
        printStacktrace();
        break;
    }
}

bool Framework::exportGraphsHelper(bool isExecOrData) {
    std::string gvPath("/tmp/lms.");
    std::string outPath("/tmp/lms.");
    if(isExecOrData) {
        gvPath += "exec";
        outPath += "exec";
    } else {
        gvPath += "data";
        outPath += "data";
    }
    gvPath += ".gv";
    outPath += ".png";

    std::ofstream file(gvPath);

    if(! file) {
        logger.error() << "Failed to open file: " << gvPath;
        return false;
    }

    DotExporter dot(file);
    dot.startDigraph("dag");
    for(auto& rt : runtimes) {
        dot.startSubgraph(rt.first);
        if(isExecOrData) {
            rt.second->executionManager().writeDAG(dot, rt.first);
        } else {
            rt.second->dataManager().writeDAG(dot, rt.first);
        }
        dot.endSubgraph();
    }
    dot.endDigraph();
    file.close();

    if(dot.lastError() != DotExporter::Error::OK) {
        logger.error() << "Dot export failed: " << dot.lastError();
        return false;
    }

#ifdef __linux__
    std::string dotCall = "dot -Tpng " + gvPath + " -o " + outPath;
    std::string xdgOpenCall = "xdg-open " + outPath;

    if(0 != system(dotCall.c_str())) {
        logger.error() << "Failed to execute " << dotCall;
        logger.error() << "Check for file permissions and graphviz package";
        return false;
    }

    if(0 != system(xdgOpenCall.c_str())) {
        logger.error() << "Failed to execute " << xdgOpenCall;
        logger.error() << "Are you using gnome?";
        return false;
    }
#else
    logger.info() << "dot -Tpng " << gvPath << " > " << outPath;
    logger.info() << "xdg-open " << outPath;
#endif
    return true;
}

void Framework::exportGraphs() {
    if(argumentHandler.argDAG) {
        logger.info() << "Write dot files...";

        exportGraphsHelper(true);
        exportGraphsHelper(false);
    }
}

void Framework::registerRuntime(Runtime *runtime) {
    runtimes.insert(std::make_pair(runtime->name(), std::unique_ptr<Runtime>(runtime)));
}

Runtime* Framework::getRuntimeByName(std::string const& name) {
    return runtimes[name].get();
}

bool Framework::hasRuntime(std::string const& name) {
    return runtimes.find(name) != runtimes.end();
}

ArgumentHandler const& Framework::getArgumentHandler() {
    return argumentHandler;
}

Profiler& Framework::profiler() {
    return m_profiler;
}

Loader<Module>& Framework::moduleLoader() {
    return m_moduleLoader;
}

std::shared_ptr<ServiceWrapper> Framework::getServiceWrapper(std::string const& name) {
    return services[name];
}

void Framework::installService(std::shared_ptr<ServiceWrapper> service) {
    auto it = services.find(service->name());

    if(it != services.end()) {
        logger.error("installService") << "Tried to install service "
            << service->name() << " but was already installed";
    } else {
        services[service->name()] = service;
    }
}

void Framework::reloadService(std::shared_ptr<ServiceWrapper> service) {
    std::shared_ptr<ServiceWrapper> originalService = services[service->name()];

    std::unique_lock<std::mutex> lock(originalService->mutex());
    originalService->update(std::move(*service.get()));
    originalService->instance()->configsChanged();
}

bool Framework::isDebug() const {
    return argumentHandler.argDebug;
}

std::string Framework::loadLogObject(std::string const& name, bool isDir) {
    if(!isEnableLoad()) {
        throw std::runtime_error("Command line option --enable-load was not specified");
    }

    std::string logobj = m_loadLogPath + "/" + name;

    return isDir ? logobj + "/" : logobj;
}

std::string Framework::saveLogObject(std::string const& name, bool isDir) {
    if(!isEnableSave()) {
        throw std::runtime_error("Command line option --enable-save was not specified");
    }

    std::string logobj = m_saveLogPath + "/" + name;

    if(isDir) {
        mkdir(logobj.c_str(), MODE);
    }

    return isDir ? logobj + "/" : logobj;
}

bool Framework::isEnableLoad() const {
    return argumentHandler.argEnableLoad;
}

bool Framework::isEnableSave() const {
    return argumentHandler.argEnableSave;
}

}  // namespace internal
}  // namespace lms
<commit_msg>enable dag rendering on OS X<commit_after>#include <lms/internal/framework.h>
#include <lms/internal/executionmanager.h>
#include <pugixml.hpp>
#include <fstream>
#include <csignal>
#include <map>
#include <thread>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <unistd.h>
#include <sys/stat.h>
#include "lms/internal/backtrace_formatter.h"
#include "lms/logger.h"
#include "lms/time.h"
#include "lms/config.h"
#include "lms/extra/string.h"
#include "lms/internal/xml_parser.h"
#include "lms/extra/colors.h"
#include "lms/definitions.h"
#include "lms/internal/runtime.h"
#include "lms/extra/os.h"
#include "lms/logging/debug_server_sink.h"

namespace lms {
namespace internal {

std::string Framework::externalDirectory = LMS_EXTERNAL;
std::string Framework::configsDirectory = LMS_CONFIGS;

Framework::Framework(const ArgumentHandler &arguments) :
    logger("lms.Framework"), argumentHandler(arguments),
    m_running(false) {

    logging::Context &ctx = logging::Context::getDefault();

    if(! arguments.argQuiet) {
        ctx.appendSink(new logging::ConsoleSink(std::cout));
    }

    if(! arguments.argLogFile.empty()) {
        ctx.appendSink(new logging::FileSink(arguments.argLogFile));
    }

    SignalHandler::getInstance()
            .addListener(SIGINT, this)
            .addListener(SIGSEGV, this)
            .addListener(SIGUSR1, this);

    if(arguments.argEnableDebugServer) {
        if(arguments.argDebugServerBind.find('/') == std::string::npos) {
            m_debugServer.useDualstack(atoi(arguments.argDebugServerBind.c_str()));
        } else {
            m_debugServer.useUnix(arguments.argDebugServerBind);
        }
        m_debugServer.startThread();

        ctx.appendSink(new logging::DebugServerSink(&m_debugServer));

        m_profiler.appendListener(new DebugServerProfiler(&m_debugServer));
    }

    if(! argumentHandler.argProfilingFile.empty()) {
        logger.info() << "Enable profiling";
        m_profiler.appendListener(new FileProfiler(arguments.argProfilingFile));
    } else {
        logger.info() << "Disable profiling";
    }

    logger.info() << "RunLevel " <<  arguments.argRunLevel;

    std::unique_ptr<logging::ThresholdFilter> filter;

#ifndef LMS_STANDALONE
    m_serviceLoader.addModulePath(LMS_SERVICES, 0);
#endif
    char *lms_service_path = std::getenv("LMS_SERVICE_PATH");
    if(lms_service_path != nullptr && lms_service_path[0] != '\0') {
        m_serviceLoader.addModulePath(lms_service_path, 0);
    }

    //parse framework config
    if(arguments.argRunLevel >= RunLevel::CONFIG) {

        Runtime* rt = new Runtime("default", *this);
        registerRuntime(rt);

        XmlParser parser(*this, rt, arguments);
        parser.parseConfig(XmlParser::LoadConfigFlag::LOAD_EVERYTHING, arguments.argLoadConfiguration);

        for(const auto& rt : runtimes) {
            logger.info("registerRuntime") << rt.first << " " <<
                lms::executionTypeName(rt.second->executionType());
        }

        filter = parser.filter();

        for(auto error : parser.errors()) {
            logger.error() << error;
        }

        for(auto file : parser.files()) {
            configMonitor.watch(file);
        }
    }

    if(arguments.argRunLevel >= RunLevel::ENABLE) {
        if(arguments.argEnableLoad) {
            if(arguments.argEnableLoadPath.find('/') == std::string::npos) {
                // no slashes
                m_loadLogPath = lms::extra::homepath() + "/.lmslog/" + arguments.argEnableLoadPath;
            } else {
                m_loadLogPath = arguments.argEnableLoadPath;
            }

            if(extra::fileType(m_loadLogPath) != extra::FileType::DIRECTORY) {
                logger.error() << "Given load path is not a directory: " << m_loadLogPath;
                return;
            }

            logger.info() << "Enable load: " << m_loadLogPath;
        }
        if(arguments.argEnableSave) {
            m_saveLogPath = lms::extra::homepath() + "/.lmslog";
            mkdir(m_saveLogPath.c_str(), MODE);

            m_saveLogPath += "/" + currentTimeString();
            if(! arguments.argEnableSaveTag.empty()) {
                m_saveLogPath += "-" + arguments.argEnableSaveTag;
            }
            mkdir(m_saveLogPath.c_str(), MODE);

            logger.info() << "Enable save: " << m_saveLogPath;
        }

        for(auto& service : services) {
            if(m_serviceLoader.load(service.second.get())) {
                service.second->instance()->initBase(service.second.get(), service.second->defaultLogLevel());

                try {
                    if(! service.second->instance()->init()) {
                        logger.error() << "Library " << service.first << " failed to init()";
                        return;
                    }
                } catch(std::exception const& ex) {
                    logger.error() << service.first << " throws " << extra::typeName(ex) << " : " << ex.what();
                    return;
                }
            } else {
                return;
            }
        }

#ifndef LMS_STANDALONE
        m_moduleLoader.addModulePath(LMS_MODULES, 0);
#endif
        char *lms_module_path = std::getenv("LMS_MODULE_PATH");
        if(lms_module_path != nullptr && lms_module_path[0] != '\0') {
            m_moduleLoader.addModulePath(lms_module_path, 0);
        }

        // enable modules after they were made available
        logger.info() << "Start enabling modules";

        for(auto& runtime : runtimes) {
            if(! runtime.second->enableModules()) {
                return;
            }
        }
    }

    if(arguments.argRunLevel >= RunLevel::CYCLE) {
        logger.info() << "Start running modules";

        if(! filter) { // check if filter == nullptr
            filter.reset(new logging::ThresholdFilter(arguments.argLoggingThreshold));
        }
        if(arguments.argDefinedLoggingThreshold) {
            filter->defaultThreshold(arguments.argLoggingThreshold);
        }
        ctx.filter(filter.release());

        // start threaded runtimes
        for(auto& runtime : runtimes) {
            if(runtime.second->executionType() == ExecutionType::NEVER_MAIN_THREAD) {
                runtime.second->startAsync();
            }
        }

        // run main thread runtimes
        m_running = true;

        while(m_running) {
            bool anyCycle = false;

            for(auto& runtime : runtimes) {
                if(runtime.second->executionType() == ExecutionType::ONLY_MAIN_THREAD) {
                    if(runtime.second->cycle()) {
                        anyCycle = true;
                    }
                }
            }

            // wait some time if there are no main thread runtimes
            // TODO this should wait for SIGINT instead
            if(! anyCycle) {
                Time::fromMillis(100).sleep();
            }

            // config monitor stuff
            if(lms::extra::FILE_MONITOR_SUPPORTED && configMonitor.hasChangedFiles()) {
                logger.info() << "Reload configs";
                configMonitor.unwatchAll();
                XmlParser parser(*this, getRuntimeByName("default"), arguments);
                parser.parseConfig(XmlParser::LoadConfigFlag::ONLY_MODULE_CONFIG,
                                   arguments.argLoadConfiguration);

                for(auto error : parser.errors()) {
                    logger.error() << error;
                }

                for(auto file : parser.files()) {
                    configMonitor.watch(file);
                }
            }
        }

        // wait for threaded runtimes to stop
        for(auto& rt : runtimes) {
            if(rt.second->executionType() == ExecutionType::NEVER_MAIN_THREAD) {
                rt.second->join();
            }
        }

        ctx.filter(nullptr);
        logger.info() << "Stopped";
    }

    exportGraphs();
}

Framework::~Framework() {
    for(auto& service : services) {
        if(service.second && service.second->instance() != nullptr) {
            try {
                service.second->instance()->destroy();
            } catch(std::exception const& ex) {
                logger.error() << service.first << " throws " << extra::typeName(ex) << " : " << ex.what();
            }
        }
    }

    SignalHandler::getInstance()
            .removeListener(SIGINT, this)
            .removeListener(SIGSEGV, this);
}

void Framework::signal(int s) {
    switch (s) {
    case SIGINT:
        for(auto& runtime : runtimes) {
            runtime.second->stopAsync();
        }
        m_running = false;

        SignalHandler::getInstance().removeListener(SIGINT, this);

        break;
    case SIGSEGV:
        //Segmentation Fault - try to identify what went wrong;
        std::cerr << std::endl << lms::extra::COLOR_RED
                << "######################################################" << std::endl
                << "                   Segfault Found                     " << std::endl
                << "######################################################" << std::endl
                << lms::extra::COLOR_WHITE;

        //In Case of Segfault while recovering - shutdown.
        SignalHandler::getInstance().removeListener(SIGSEGV, this);

        printStacktrace();

        exit(EXIT_FAILURE);

        break;
    case SIGUSR1:
        printStacktrace();
        break;
    }
}

bool Framework::exportGraphsHelper(bool isExecOrData) {
    std::string gvPath("/tmp/lms.");
    std::string outPath("/tmp/lms.");
    if(isExecOrData) {
        gvPath += "exec";
        outPath += "exec";
    } else {
        gvPath += "data";
        outPath += "data";
    }
    gvPath += ".gv";
    outPath += ".png";

    std::ofstream file(gvPath);

    if(! file) {
        logger.error() << "Failed to open file: " << gvPath;
        return false;
    }

    DotExporter dot(file);
    dot.startDigraph("dag");
    for(auto& rt : runtimes) {
        dot.startSubgraph(rt.first);
        if(isExecOrData) {
            rt.second->executionManager().writeDAG(dot, rt.first);
        } else {
            rt.second->dataManager().writeDAG(dot, rt.first);
        }
        dot.endSubgraph();
    }
    dot.endDigraph();
    file.close();

    if(dot.lastError() != DotExporter::Error::OK) {
        logger.error() << "Dot export failed: " << dot.lastError();
        return false;
    }

#ifdef __linux__
    std::string dotCall = "dot -Tpng " + gvPath + " -o " + outPath;
    std::string xdgOpenCall = "xdg-open " + outPath;

    if(0 != system(dotCall.c_str())) {
        logger.error() << "Failed to execute " << dotCall;
        logger.error() << "Check for file permissions and graphviz package";
        return false;
    }

    if(0 != system(xdgOpenCall.c_str())) {
        logger.error() << "Failed to execute " << xdgOpenCall;
        logger.error() << "Are you using gnome?";
        return false;
    }
#elif __APPLE__
    std::string dotCall = "dot -Tpng " + gvPath + " -o " + outPath;
    std::string openCall = "open " + outPath;

    if(0 != system(dotCall.c_str())) {
        logger.error() << "Failed to execute " << dotCall;
        logger.error() << "Check for file permissions and graphviz package";
        return false;
    }

    if(0 != system(openCall.c_str())) {
        logger.error() << "Failed to execute " << openCall;
        logger.error() << "Are you using gnome?";
        return false;
    }
#else
    logger.info() << "dot -Tpng " << gvPath << " > " << outPath;
    logger.info() << "xdg-open " << outPath;
#endif
    return true;
}

void Framework::exportGraphs() {
    if(argumentHandler.argDAG) {
        logger.info() << "Write dot files...";

        exportGraphsHelper(true);
        exportGraphsHelper(false);
    }
}

void Framework::registerRuntime(Runtime *runtime) {
    runtimes.insert(std::make_pair(runtime->name(), std::unique_ptr<Runtime>(runtime)));
}

Runtime* Framework::getRuntimeByName(std::string const& name) {
    return runtimes[name].get();
}

bool Framework::hasRuntime(std::string const& name) {
    return runtimes.find(name) != runtimes.end();
}

ArgumentHandler const& Framework::getArgumentHandler() {
    return argumentHandler;
}

Profiler& Framework::profiler() {
    return m_profiler;
}

Loader<Module>& Framework::moduleLoader() {
    return m_moduleLoader;
}

std::shared_ptr<ServiceWrapper> Framework::getServiceWrapper(std::string const& name) {
    return services[name];
}

void Framework::installService(std::shared_ptr<ServiceWrapper> service) {
    auto it = services.find(service->name());

    if(it != services.end()) {
        logger.error("installService") << "Tried to install service "
            << service->name() << " but was already installed";
    } else {
        services[service->name()] = service;
    }
}

void Framework::reloadService(std::shared_ptr<ServiceWrapper> service) {
    std::shared_ptr<ServiceWrapper> originalService = services[service->name()];

    std::unique_lock<std::mutex> lock(originalService->mutex());
    originalService->update(std::move(*service.get()));
    originalService->instance()->configsChanged();
}

bool Framework::isDebug() const {
    return argumentHandler.argDebug;
}

std::string Framework::loadLogObject(std::string const& name, bool isDir) {
    if(!isEnableLoad()) {
        throw std::runtime_error("Command line option --enable-load was not specified");
    }

    std::string logobj = m_loadLogPath + "/" + name;

    return isDir ? logobj + "/" : logobj;
}

std::string Framework::saveLogObject(std::string const& name, bool isDir) {
    if(!isEnableSave()) {
        throw std::runtime_error("Command line option --enable-save was not specified");
    }

    std::string logobj = m_saveLogPath + "/" + name;

    if(isDir) {
        mkdir(logobj.c_str(), MODE);
    }

    return isDir ? logobj + "/" : logobj;
}

bool Framework::isEnableLoad() const {
    return argumentHandler.argEnableLoad;
}

bool Framework::isEnableSave() const {
    return argumentHandler.argEnableSave;
}

}  // namespace internal
}  // namespace lms
<|endoftext|>