<commit_before>// Copyright (c) 2008-2010 Kent State University
// Copyright (c) 2011 Texas A&M University
//
// This file is distributed under the MIT License. See the accompanying file
// LICENSE.txt or http://www.opensource.org/licenses/mit-license.php for terms
// and conditions.

#ifndef ORIGIN_CONCEPTS_HPP
#define ORIGIN_CONCEPTS_HPP

#include <functional>

#include <origin/traits.hpp>
#include <origin/tuple.hpp>

namespace origin
{
  /**
   * The concept check metafunction evaluates to true if all of the given
   * predicates are true. If not, the metafunction evaluates to false.
   *
   * The concept check cl
   */
  template<typename... Args> struct concept_check;

  template<typename Model>
  struct concept_check<Model>
    : bool_constant<Model::value>
  { };

  template<typename Model, typename... Args>
  struct concept_check<Model, Args...>
    : std::conditional<
        Model::value, typename concept_check<Args...>::type, std::false_type
      >::type
  { };

  // A specialization for tuples, just to help out.
  template<typename... Args>
  struct concept_check<std::tuple<Args...>>
    : concept_check<Args...>::type
  { };

  // Synopsis.
  template<typename T, typename U = T> struct Equal;
  template<typename T, typename U = T> struct Ordered;

  template<typename T> struct Regular;
  template<typename T> struct Boolean;

  // FIXME: Axiomatic concepts are not validated during concept checking. They
  // are trivially true unless they are explicitly required (e.g., multipass).
  // It would probably be a good idea to define several "levels" of
  // verification, that explain why something is or is not validated.

  /**
   * @ingroup concepts
   * A relation is reflexive if, for all objects x in the domain of the
   * operation, op(x, x) == true.
   */
  template<typename Op, typename T>
  struct Reflexive_Relation
    : std::true_type
  {
    Reflexive_Relation()
    { auto p = constraints; }

    static void constraints(Op op, T x)
    { reflexivity(op, x); }

    static void reflexivity(Op op, T x)
    { assert(( op(x, x) )); }
  };

  // NOTE: Symmetry can conceivably be applied to relations on objects of
  // different types.
  /**
   * @ingroup concepts
   * An relation is symmetic if, for all objects x and y in the domain
   * of the operation, op(x, y) implies op(y, x).
   */
  template<typename Op, typename T>
  struct Symmetric_Relation
    : std::true_type
  {
    Symmetric_Relation()
    { auto p = constraints; }

    static void constraints(Op op, T x, T y)
    { symmetry(op, x, y); }

    static void symmetry(Op op, T x, T y)
    { if(op(x, y)) assert(( op(y, x) )); }
  };

  /**
   * @ingroup concepts
   * A binary operation is symmetic if, for all objects x, y, and z in the
   * domaion of the operation, op(x, y) and op(y, z) implies op(x, z).
   */
  template<typename Op, typename T>
  struct Transitive_Relation
    : std::true_type
  {
    Transitive_Relation()
    { auto p = constraints; }

    static void constraints(Op op, T x, T y, T z)
    { transitivity(op, x, y, z); }

    static void transitivity(Op op, T x, T y, T z)
    { if(op(x, y) && op(y, z)) assert(( op(x, z) )); }
  };

  /**
   * @ingroup concepts
   * When instantiated over two different types, the concept determines whether
   * or not the two types can be compared using the relational equality
   * operators (== and !=). This further requires that the the equality operator
   * be a symmetric relation.
   */
  template<typename T, typename U>
  struct Equal
  {
    Equal()
    { auto p = constraints; }

    static void constraints(T x, U y)
    {
      Boolean<decltype(x == y)>{};
      Boolean<decltype(x != y)>{};
      Boolean<decltype(y == x)>{};
      Boolean<decltype(y != x)>{};

      // FIXME: Is there anything else that I'm missing here?
    }

    // FIXME: Make this an axiom class.
    static void symmetry(T x, U y)
    {
      if(x == y) assert(( y == x ));
      if(y == x) assert(( x == y ));
    }

    typedef std::tuple<
      Boolean<typename deduce_equal<T, U>::type>,
      Boolean<typename deduce_not_equal<T, U>::type>,
      Boolean<typename deduce_equal<U, T>::type>,
      Boolean<typename deduce_not_equal<U, T>::type>
    > requirements;
    typedef concept_check<requirements> type;
    static constexpr bool value = type::value;
  };

  /**
   * When instantiated over a single type (or when both types are the same),
   * the concept determines if the given type can be used with the relational
   * equality operators (== and !=) and that it defines an equivalence relation
   * over the equality operator (==).
   */
  template <typename T>
  struct Equal<T, T>
  {
    /**
     * The equal identity concept requires that an object is equivalent to
     * itself. This is defined internally since it's definition is incomplete
     * without first evaluating whether or T is Equal.
     */
    struct Equal_Identity
      : std::true_type
    {
      Equal_Identity()
      { auto p = constraints; }

      static void constraints(T x, T y)
      { identity(x, y); }

      static void identity(T x, T y)
      { if(&x == &y) assert(( x == y )); }
    };

    // Encapsulate the operator.
    typedef std::equal_to<T> Eq;
    typedef std::not_equal_to<T> Neq;

    Equal()
    { auto p = constraints; }

    static void constraints(T x, T y)
    {
      Boolean<decltype(x == y)>{};
      Boolean<decltype(x != y)>{};

      Equal_Identity{};

      // FIXME: Say something about Eq and Neq?

      Reflexive_Relation<Eq, T>{};
      Symmetric_Relation<Eq, T>{};
      Transitive_Relation<Eq, T>{};
    }

    // NOTE: We can avoid writing has_ + deduce_ since dedce_ will return a
    // type that is not convertible to bool. This one test happens to cover
    // both cases.
    typedef std::tuple<
      std::is_convertible<typename deduce_equal<T, T>::type, bool>,
      std::is_convertible<typename deduce_not_equal<T, T>::type, bool>,
      Equal_Identity,
      Reflexive_Relation<Eq, T>,
      Symmetric_Relation<Eq, T>,
      Transitive_Relation<Eq, T>
    > requirements;
    typedef concept_check<requirements> type;
    static constexpr bool value = type::value;
  };

  // FIXME:
  // Explicitly provide models for builtin types. Hopefully, this will
  // cut down compilation times.

  /**
   * The ordered concept defines two different comparisons. When instantiated
   * over one type (or the same type), it determines if that type is ordered,
   * that it can be compared using the relational ordering operators. When
   * instantiated over two types,
   */
  template<typename T, typename U>
  struct Ordered
  { };

  template<typename T>
  struct Ordered<T, T>
  {
    // Encapsulate the operator.
    typedef std::less<T> Lt;
    typedef std::greater<T> Gt;
    typedef std::less_equal<T> Leq;
    typedef std::Greater_equal<T> Geq;

    Ordered()
    { auto p = constraints; }

    static void constraints(T x, T y)
    {
      Boolean<decltype(x < y)>{};
      Boolean<decltype(x > y)>{};
      Boolean<decltype(x <= y)>{};
      Boolean<decltype(x >= y)>{};
    }
  };

  // FIXME: Provide built-in models.

  // FIXME: Implement me!
  /**
   * A regular type...
   */
  template<typename T>
  struct Regular
  {
    Regular()
    { auto p = constraints; }

    static void constraints()
    {
      Equal<T>{};
    }

    typedef std::tuple<
      Equal<T>
    > requirements;
    typedef concept_check<requirements> type;
    static constexpr bool value = type::value;
  };

  // FIXME: Should this type actually encompass the requirements of a
  // Boolean_Algebra? Probably not. This merely wants a type that can behave
  // like a bool in a bare number of cases. It would be interesting to know
  // if this sufficiently describes the syntax required by a boolean algebra.
  /**
   * A boolean type is a type that can be evaluated in boolean contexts and
   * participate in logical expresssions. Note that this does not constrain
   * the set of values defined by the boolean type, this concept is purely
   * syntactic.
   */
  template<typename T>
  struct Boolean
  {
    Boolean()
    { auto p = constraints; }

    static void constraints(T x, T y)
    {
      Regular<T>{};

      if(x) ;

      // NOTE: I can't recursively constrain these exressions as Boolean
      // types (infinite recursion!). I shouldn't constrain them as T since
      // T might not actually be Boolean-like (it could be an int*). The only
      // reasonable choice is to require these to be convertible to bool.
      //
      // FIXME: There's an ICE calling bool{..}.
      bool(!x);
      bool(x && y);
      bool(x || y);
    }

    typedef std::tuple<
      Regular<T>,
      std::is_convertible<T, bool>,
      std::is_convertible<typename deduce_logical_not<T>::type, bool>,
      std::is_convertible<typename deduce_logical_and<T, T>::type, bool>,
      std::is_convertible<typename deduce_logical_or<T, T>::type, bool>
    > requirements;
    typedef concept_check<requirements> type;
    static constexpr bool value = type::value;
  };

  // Make sure that we have some built in models of Boolean types. Note that
  // if we don't have this, we get recursive template instantiation.
  // FIXME: Are there any other known models? char, short, int?
  template<> struct Boolean<bool> : std::true_type { };

} // namespace origin

#endif
<commit_msg>Continuing work on concepts.<commit_after>// Copyright (c) 2008-2010 Kent State University
// Copyright (c) 2011 Texas A&M University
//
// This file is distributed under the MIT License. See the accompanying file
// LICENSE.txt or http://www.opensource.org/licenses/mit-license.php for terms
// and conditions.

#ifndef ORIGIN_CONCEPTS_HPP
#define ORIGIN_CONCEPTS_HPP

#include <functional>

#include <origin/traits.hpp>
#include <origin/tuple.hpp>

namespace origin
{
  /**
   * The concept check metafunction evaluates to true if all of the given
   * predicates are true. If not, the metafunction evaluates to false.
   *
   * The concept check cl
   */
  template<typename... Args> struct concept_check;

  template<typename Model>
  struct concept_check<Model>
    : bool_constant<Model::value>
  { };

  template<typename Model, typename... Args>
  struct concept_check<Model, Args...>
    : std::conditional<
        Model::value, typename concept_check<Args...>::type, std::false_type
      >::type
  { };

  // A specialization for tuples, just to help out.
  template<typename... Args>
  struct concept_check<std::tuple<Args...>>
    : concept_check<Args...>::type
  { };

  // Synopsis.
  template<typename T, typename U = T> struct Equal;
  template<typename T, typename U = T> struct Ordered;

  template<typename T> struct Regular;
  template<typename T> struct Boolean;

  // FIXME: Axiomatic concepts are not validated during concept checking. They
  // are trivially true unless they are explicitly required (e.g., multipass).
  // It would probably be a good idea to define several "levels" of
  // verification, that explain why something is or is not validated.

  /**
   * @ingroup concepts
   * A relation is reflexive if, for all objects x in the domain of the
   * operation, op(x, x) == true.
   */
  template<typename Op, typename T>
  struct Reflexive_Relation
    : std::true_type
  {
    Reflexive_Relation()
    { auto p = constraints; }

    static void constraints(Op op, T x)
    { reflexivity(op, x); }

    static void reflexivity(Op op, T x)
    { assert(( op(x, x) )); }
  };

  // NOTE: Symmetry can conceivably be applied to relations on objects of
  // different types.
  /**
   * @ingroup concepts
   * An relation is symmetic if, for all objects x and y in the domain
   * of the operation, op(x, y) implies op(y, x).
   */
  template<typename Op, typename T>
  struct Symmetric_Relation
    : std::true_type
  {
    Symmetric_Relation()
    { auto p = constraints; }

    static void constraints(Op op, T x, T y)
    { symmetry(op, x, y); }

    static void symmetry(Op op, T x, T y)
    { if(op(x, y)) assert(( op(y, x) )); }
  };

  /**
   * @ingroup concepts
   * A binary operation is symmetic if, for all objects x, y, and z in the
   * domaion of the operation, op(x, y) and op(y, z) implies op(x, z).
   */
  template<typename Op, typename T>
  struct Transitive_Relation
    : std::true_type
  {
    Transitive_Relation()
    { auto p = constraints; }

    static void constraints(Op op, T x, T y, T z)
    { transitivity(op, x, y, z); }

    static void transitivity(Op op, T x, T y, T z)
    { if(op(x, y) && op(y, z)) assert(( op(x, z) )); }
  };

  // NOTE: The following implicitly require Equal<T>

  template<typename Op, typename T>
  struct Associative_Operation
  {
    static void associativity(Op op, T x, T y, T z)
    { assert(( op(x, op(y, z)) == op(op(x, y), z) )); }
  };

  template<typename Op, typename T>
  struct Commutative_Operation
  {
    static void commutativity(Op op, T x, T y)
    { assert(( op(x, y) == op(y, x) )); }
  };

  template<typename Op1, typename Op2, typename T>
  struct Absorptive_Property
  {
    static void absorb(Op1 op1, Op2 op2, T x, T y)
    { assert(( op1(a, op2(a, b)) == a )); }
  };

  template<typename Op1, typename Op2, typename T>
  struct Distributive_Property
  {
    static void distribute(Op1, Op2, T x, T y, T z)
    { assert(( op1(x, op2(y, z)) == op2(op1(x, y), op1(y, z)) )); }
  };

  // FIXME: Probably not the right name for this.
  template<typename Bin_Op, typename Un_Op, typename T>
  struct Compliment_Lattice
  {
    static void compliment(Bin_Op bin, Un_Op un, T x, T comp)
    { assert(( bin(x, un(x)) == comp )); }
  };

  /**
   * @ingroup concepts
   * When instantiated over two different types, the concept determines whether
   * or not the two types can be compared using the relational equality
   * operators (== and !=). This further requires that the the equality operator
   * be a symmetric relation.
   */
  template<typename T, typename U>
  struct Equal
  {
    Equal()
    { auto p = constraints; }

    static void constraints(T x, U y)
    {
      Boolean<decltype(x == y)>{};
      Boolean<decltype(x != y)>{};
      Boolean<decltype(y == x)>{};
      Boolean<decltype(y != x)>{};

      // FIXME: Is there anything else that I'm missing here?
    }

    // FIXME: Make this an axiom class.
    static void symmetry(T x, U y)
    {
      if(x == y) assert(( y == x ));
      if(y == x) assert(( x == y ));
    }

    typedef std::tuple<
      Boolean<typename deduce_equal<T, U>::type>,
      Boolean<typename deduce_not_equal<T, U>::type>,
      Boolean<typename deduce_equal<U, T>::type>,
      Boolean<typename deduce_not_equal<U, T>::type>
    > requirements;
    typedef concept_check<requirements> type;
    static constexpr bool value = type::value;
  };

  /**
   * When instantiated over a single type (or when both types are the same),
   * the concept determines if the given type can be used with the relational
   * equality operators (== and !=) and that it defines an equivalence relation
   * over the equality operator (==).
   */
  template <typename T>
  struct Equal<T, T>
  {
    /**
     * The equal identity concept requires that an object is equivalent to
     * itself. This is defined internally since it's definition is incomplete
     * without first evaluating whether or T is Equal.
     */
    struct Equal_Identity
      : std::true_type
    {
      Equal_Identity()
      { auto p = constraints; }

      static void constraints(T x, T y)
      { identity(x, y); }

      static void identity(T x, T y)
      { if(&x == &y) assert(( x == y )); }
    };

    // Encapsulate the operator.
    typedef std::equal_to<T> Eq;
    typedef std::not_equal_to<T> Neq;

    Equal()
    { auto p = constraints; }

    static void constraints(T x, T y)
    {
      Boolean<decltype(x == y)>{};
      Boolean<decltype(x != y)>{};

      Equal_Identity{};

      // FIXME: Say something about Eq and Neq?

      Reflexive_Relation<Eq, T>{};
      Symmetric_Relation<Eq, T>{};
      Transitive_Relation<Eq, T>{};
    }

    // NOTE: We can avoid writing has_ + deduce_ since dedce_ will return a
    // type that is not convertible to bool. This one test happens to cover
    // both cases.
    typedef std::tuple<
      std::is_convertible<typename deduce_equal<T, T>::type, bool>,
      std::is_convertible<typename deduce_not_equal<T, T>::type, bool>,
      Equal_Identity,
      Reflexive_Relation<Eq, T>,
      Symmetric_Relation<Eq, T>,
      Transitive_Relation<Eq, T>
    > requirements;
    typedef concept_check<requirements> type;
    static constexpr bool value = type::value;
  };

  // FIXME:
  // Explicitly provide models for builtin types. Hopefully, this will
  // cut down compilation times.

  /**
   * The ordered concept defines two different comparisons. When instantiated
   * over one type (or the same type), it determines if that type is ordered,
   * that it can be compared using the relational ordering operators. When
   * instantiated over two types,
   */
  template<typename T, typename U>
  struct Ordered
  { };

  template<typename T>
  struct Ordered<T, T>
  {
    // Encapsulate the operator.
    typedef std::less<T> Lt;
    typedef std::greater<T> Gt;
    typedef std::less_equal<T> Leq;
    typedef std::Greater_equal<T> Geq;

    Ordered()
    { auto p = constraints; }

    static void constraints(T x, T y)
    {
      Boolean<decltype(x < y)>{};
      Boolean<decltype(x > y)>{};
      Boolean<decltype(x <= y)>{};
      Boolean<decltype(x >= y)>{};
    }
  };

  // FIXME: Provide built-in models.

  // FIXME: Implement me!
  /**
   * A regular type...
   */
  template<typename T>
  struct Regular
  {
    Regular()
    { auto p = constraints; }

    static void constraints()
    {
      Equal<T>{};
    }

    typedef std::tuple<
      Equal<T>
    > requirements;
    typedef concept_check<requirements> type;
    static constexpr bool value = type::value;
  };

  // FIXME: Should this type actually encompass the requirements of a
  // Boolean_Algebra? Probably not. This merely wants a type that can behave
  // like a bool in a bare number of cases. It would be interesting to know
  // if this sufficiently describes the syntax required by a boolean algebra.
  /**
   * A boolean type is a type that can be evaluated in boolean contexts and
   * participate in logical expresssions. Note that this does not constrain
   * the set of values defined by the boolean type, this concept is purely
   * syntactic.
   */
  template<typename T>
  struct Boolean
  {
    Boolean()
    { auto p = constraints; }

    static void constraints(T x, T y)
    {
      Regular<T>{};

      if(x) ;

      // NOTE: I can't recursively constrain these exressions as Boolean
      // types (infinite recursion!). I shouldn't constrain them as T since
      // T might not actually be Boolean-like (it could be an int*). The only
      // reasonable choice is to require these to be convertible to bool.
      //
      // FIXME: There's an ICE calling bool{..}.
      bool(!x);
      bool(x && y);
      bool(x || y);

      // FIXME: Could also apply convertability requirements to these functions
      // to further separate the constraints on the expression from the result
      // type.
      auto notf = [](T x) { return !x; }
      auto andf = [](T x, T y) { return x && y; }
      auto orf = [](T x, T y) { return x || y; }

      typedef decltype(notf) Not;
      typedef decltype(andf) And;
      typedef decltype(orf) Or;

      Associative_Operation<Or, T>{};
      Commutative_Operation<Or, T>{};
      Absorptive_Property<Or, And, T>{};
      Distributive_Property<Or, And, T>{};

      // FIXME: I can't write this yet.
      // Compliment_Lattice<Or, And, T>
    }

    typedef std::tuple<
      Regular<T>,
      std::is_convertible<T, bool>,
      std::is_convertible<typename deduce_logical_not<T>::type, bool>,
      std::is_convertible<typename deduce_logical_and<T, T>::type, bool>,
      std::is_convertible<typename deduce_logical_or<T, T>::type, bool>
    > requirements;
    typedef concept_check<requirements> type;
    static constexpr bool value = type::value;
  };

  // Make sure that we have some built in models of Boolean types. Note that
  // if we don't have this, we get recursive template instantiation.
  // FIXME: Are there any other known models? char, short, int?
  template<> struct Boolean<bool> : std::true_type { };

} // namespace origin

#endif
<|endoftext|>


<commit_before>#include "primops.hh"
#include "eval-inline.hh"

#include "../../toml11/toml.hpp"

namespace nix {

static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Value & val)
{
    auto toml = state.forceStringNoCtx(*args[0], pos);

    std::istringstream tomlStream(toml);

    std::function<void(Value &, toml::value)> visit;

    visit = [&](Value & v, toml::value t) {

        switch(t.type())
        {
            case toml::value_t::table:
                {
                    auto table = toml::get<toml::table>(t);

                    size_t size = 0;
                    for (auto & i : table) { (void) i; size++; }

                    state.mkAttrs(v, size);

                    for(auto & elem: table) {

                        auto & v2 = *state.allocAttr(v, state.symbols.create(elem.first));
                        visit(v2, elem.second);
                    }
                }
                break;;
            case toml::value_t::array:
                {
                    auto array = toml::get<std::vector<toml::value>>(t);

                    size_t size = array.size();
                    state.mkList(v, size);
                    for (size_t i = 0; i < size; ++i)
                        visit(*(v.listElems()[i] = state.allocValue()), array[i]);
                }
                break;;
            case toml::value_t::boolean:
                mkBool(v, toml::get<bool>(t));
                break;;
            case toml::value_t::integer:
                mkInt(v, toml::get<int64_t>(t));
                break;;
            case toml::value_t::floating:
                mkFloat(v, toml::get<NixFloat>(t));
                break;;
            case toml::value_t::string:
                mkString(v, toml::get<std::string>(t));
                break;;
            case toml::value_t::local_datetime:
            case toml::value_t::offset_datetime:
            case toml::value_t::local_date:
            case toml::value_t::local_time:
                // We fail since Nix doesn't have date and time types
                throw std::runtime_error("Dates and times are not supported");
                break;;
            case toml::value_t::empty:
                mkNull(v);
                break;;

        }
    };

    try {
        visit(val, toml::parse(tomlStream, "fromTOML" /* the "filename" */));
    } catch (std::exception & e) { // TODO: toml::syntax_error
        throw EvalError({
            .msg = hintfmt("while parsing a TOML string: %s", e.what()),
            .errPos = pos
        });
    }
}

static RegisterPrimOp primop_fromTOML("fromTOML", 1, prim_fromTOML);

}
<commit_msg>Sort attrs from tables in fromTOML<commit_after>#include "primops.hh"
#include "eval-inline.hh"

#include "../../toml11/toml.hpp"

namespace nix {

static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Value & val)
{
    auto toml = state.forceStringNoCtx(*args[0], pos);

    std::istringstream tomlStream(toml);

    std::function<void(Value &, toml::value)> visit;

    visit = [&](Value & v, toml::value t) {

        switch(t.type())
        {
            case toml::value_t::table:
                {
                    auto table = toml::get<toml::table>(t);

                    size_t size = 0;
                    for (auto & i : table) { (void) i; size++; }

                    state.mkAttrs(v, size);

                    for(auto & elem: table) {

                        auto & v2 = *state.allocAttr(v, state.symbols.create(elem.first));
                        visit(v2, elem.second);
                    }

                    v.attrs->sort();
                }
                break;;
            case toml::value_t::array:
                {
                    auto array = toml::get<std::vector<toml::value>>(t);

                    size_t size = array.size();
                    state.mkList(v, size);
                    for (size_t i = 0; i < size; ++i)
                        visit(*(v.listElems()[i] = state.allocValue()), array[i]);
                }
                break;;
            case toml::value_t::boolean:
                mkBool(v, toml::get<bool>(t));
                break;;
            case toml::value_t::integer:
                mkInt(v, toml::get<int64_t>(t));
                break;;
            case toml::value_t::floating:
                mkFloat(v, toml::get<NixFloat>(t));
                break;;
            case toml::value_t::string:
                mkString(v, toml::get<std::string>(t));
                break;;
            case toml::value_t::local_datetime:
            case toml::value_t::offset_datetime:
            case toml::value_t::local_date:
            case toml::value_t::local_time:
                // We fail since Nix doesn't have date and time types
                throw std::runtime_error("Dates and times are not supported");
                break;;
            case toml::value_t::empty:
                mkNull(v);
                break;;

        }
    };

    try {
        visit(val, toml::parse(tomlStream, "fromTOML" /* the "filename" */));
    } catch (std::exception & e) { // TODO: toml::syntax_error
        throw EvalError({
            .msg = hintfmt("while parsing a TOML string: %s", e.what()),
            .errPos = pos
        });
    }
}

static RegisterPrimOp primop_fromTOML("fromTOML", 1, prim_fromTOML);

}
<|endoftext|>


<commit_before>#include "primops.hh"
#include "eval-inline.hh"

#include "../../toml11/toml.hpp"

namespace nix {

static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Value & val)
{
    auto toml = state.forceStringNoCtx(*args[0], pos);

    std::istringstream tomlStream(toml);

    std::function<void(Value &, toml::value)> visit;

    visit = [&](Value & v, toml::value t) {

        switch(t.type())
        {
            case toml::value_t::table:
                {
                    auto table = toml::get<toml::table>(t);

                    size_t size = 0;
                    for (auto & i : table) { (void) i; size++; }

                    state.mkAttrs(v, size);

                    for(auto & elem: table) {

                        auto & v2 = *state.allocAttr(v, state.symbols.create(elem.first));
                        visit(v2, elem.second);
                    }
                }
                break;;
            case toml::value_t::array:
                {
                    auto array = toml::get<std::vector<toml::value>>(t);

                    size_t size = array.size();
                    state.mkList(v, size);
                    for (size_t i = 0; i < size; ++i)
                        visit(*(v.listElems()[i] = state.allocValue()), array[i]);
                }
                break;;
            case toml::value_t::boolean:
                mkBool(v, toml::get<bool>(t));
                break;;
            case toml::value_t::integer:
                mkInt(v, toml::get<long>(t));
                break;;
            case toml::value_t::floating:
                mkFloat(v, toml::get<double>(t));
                break;;
            case toml::value_t::string:
                mkString(v, toml::get<std::string>(t));
                break;;
            case toml::value_t::local_datetime:
            case toml::value_t::offset_datetime:
            case toml::value_t::local_date:
            case toml::value_t::local_time:
                // We fail since Nix doesn't have date and time types
                throw std::runtime_error("Dates and times are not supported");
                break;;
            case toml::value_t::empty:
                mkNull(v);
                break;;

        }
    };

    try {
        visit(val, toml::parse(tomlStream, "fromTOML" /* the "filename" */));
    } catch (std::exception & e) { // TODO: toml::syntax_error
        throw EvalError({
            .msg = hintfmt("while parsing a TOML string: %s", e.what()),
            .errPos = pos
        });
    }
}

static RegisterPrimOp primop_fromTOML("fromTOML", 1, prim_fromTOML);

}
<commit_msg>Use int64_t and NixFloat in fromTOML types<commit_after>#include "primops.hh"
#include "eval-inline.hh"

#include "../../toml11/toml.hpp"

namespace nix {

static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Value & val)
{
    auto toml = state.forceStringNoCtx(*args[0], pos);

    std::istringstream tomlStream(toml);

    std::function<void(Value &, toml::value)> visit;

    visit = [&](Value & v, toml::value t) {

        switch(t.type())
        {
            case toml::value_t::table:
                {
                    auto table = toml::get<toml::table>(t);

                    size_t size = 0;
                    for (auto & i : table) { (void) i; size++; }

                    state.mkAttrs(v, size);

                    for(auto & elem: table) {

                        auto & v2 = *state.allocAttr(v, state.symbols.create(elem.first));
                        visit(v2, elem.second);
                    }
                }
                break;;
            case toml::value_t::array:
                {
                    auto array = toml::get<std::vector<toml::value>>(t);

                    size_t size = array.size();
                    state.mkList(v, size);
                    for (size_t i = 0; i < size; ++i)
                        visit(*(v.listElems()[i] = state.allocValue()), array[i]);
                }
                break;;
            case toml::value_t::boolean:
                mkBool(v, toml::get<bool>(t));
                break;;
            case toml::value_t::integer:
                mkInt(v, toml::get<int64_t>(t));
                break;;
            case toml::value_t::floating:
                mkFloat(v, toml::get<NixFloat>(t));
                break;;
            case toml::value_t::string:
                mkString(v, toml::get<std::string>(t));
                break;;
            case toml::value_t::local_datetime:
            case toml::value_t::offset_datetime:
            case toml::value_t::local_date:
            case toml::value_t::local_time:
                // We fail since Nix doesn't have date and time types
                throw std::runtime_error("Dates and times are not supported");
                break;;
            case toml::value_t::empty:
                mkNull(v);
                break;;

        }
    };

    try {
        visit(val, toml::parse(tomlStream, "fromTOML" /* the "filename" */));
    } catch (std::exception & e) { // TODO: toml::syntax_error
        throw EvalError({
            .msg = hintfmt("while parsing a TOML string: %s", e.what()),
            .errPos = pos
        });
    }
}

static RegisterPrimOp primop_fromTOML("fromTOML", 1, prim_fromTOML);

}
<|endoftext|>


<commit_before>#include "McMaker/TpcEffMaker.h"

void TpcEffMaker::initialize(){
	InclusiveSpectra::initialize();

	string trackType = config.getString( nodePath + ".input:type" );
	if ( "mc" == trackType ){
		cut_nHitsDedx->min = 0;
	}
}

TpcEffMaker::~TpcEffMaker(){

}

void TpcEffMaker::analyzeTrack( Int_t iTrack ){

	if ( !makeSpectra )
		return;

	// use the ptMc instead of primary pT
	double pt = pico->mcPt( iTrack );
	int charge = pico->trackCharge( iTrack );

	book->cd( "inclusive" );

	if ( cBin >= 0 ){
		string cName = "pt_" + ts( cBin ) + "_" + Common::chargeString( charge );
		book->fill( cName, pt, eventWeight );
	}
	book->cd();

}

void TpcEffMaker::analyzeTofTrack( Int_t iTrack ){

	if ( !makeTofSpectra )
		return;

	double pt = pico->mcPt( iTrack );
	int charge = pico->trackCharge( iTrack );

	book->cd( "inclusiveTof" );

	if ( cBin >= 0 ){
		string cName = "pt_" + ts( cBin ) + "_" + Common::chargeString( charge );
		book->fill( cName, pt, eventWeight );
	}
	book->cd( );

}<commit_msg>Adding more cut overrides<commit_after>#include "McMaker/TpcEffMaker.h"

void TpcEffMaker::initialize(){
	InclusiveSpectra::initialize();

	string trackType = config.getString( nodePath + ".input:type" );
	if ( "mc" == trackType ){
		cut_nHitsDedx->min = 0;
		cut_nHitsFit->min = 0;
		cut_nHitsFitOverPossible->min = 0;
	}
}

TpcEffMaker::~TpcEffMaker(){

}

void TpcEffMaker::analyzeTrack( Int_t iTrack ){

	if ( !makeSpectra )
		return;

	// use the ptMc instead of primary pT
	double pt = pico->mcPt( iTrack );
	int charge = pico->trackCharge( iTrack );

	book->cd( "inclusive" );

	if ( cBin >= 0 ){
		string cName = "pt_" + ts( cBin ) + "_" + Common::chargeString( charge );
		book->fill( cName, pt, eventWeight );
	}
	book->cd();

}

void TpcEffMaker::analyzeTofTrack( Int_t iTrack ){

	if ( !makeTofSpectra )
		return;

	double pt = pico->mcPt( iTrack );
	int charge = pico->trackCharge( iTrack );

	book->cd( "inclusiveTof" );

	if ( cBin >= 0 ){
		string cName = "pt_" + ts( cBin ) + "_" + Common::chargeString( charge );
		book->fill( cName, pt, eventWeight );
	}
	book->cd( );

}<|endoftext|>


<commit_before>/*
  board_serial.h - Arduino-XC HAL API implementation of serial comm
  Copyright (c) 2016 Ravendyne Inc.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

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

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "lib/UARTSerial.h"
#include "board/board_serial.h"
#include "ringbuffer.h"
#include "board/variant.h"

#include "chip.h"

// ----------------------------------------------------------------------------
//   CONSTANT DEFINITIONS
// ----------------------------------------------------------------------------
// These "constants" are declared as variables and their value is platform specific
// This way we can declare these in code that is not platform specific (i.e. core or lib)
// and then define their values here in platform specific part where we need to access
// platform specific values (like UART_LCR_WLEN8, UART_LCR_PARITY_F_0, etc.)
extern const uint32_t SERIAL_8N1 = (UART_LCR_WLEN8 | UART_LCR_SBS_1BIT | UART_LCR_PARITY_DIS);
extern const uint32_t SERIAL_8E1 = (UART_LCR_WLEN8 | UART_LCR_SBS_1BIT | UART_LCR_PARITY_EVEN | UART_LCR_PARITY_EN);
extern const uint32_t SERIAL_8O1 = (UART_LCR_WLEN8 | UART_LCR_SBS_1BIT | UART_LCR_PARITY_ODD | UART_LCR_PARITY_EN);
extern const uint32_t SERIAL_8M1 = (UART_LCR_WLEN8 | UART_LCR_SBS_1BIT | UART_LCR_PARITY_F_1 | UART_LCR_PARITY_EN);
extern const uint32_t SERIAL_8S1 = (UART_LCR_WLEN8 | UART_LCR_SBS_1BIT | UART_LCR_PARITY_F_0 | UART_LCR_PARITY_EN);

/******************************************************************
 * UART objects
 */
/*
 * We declare buffers here so we can have multiple instances of
 * Serial object on different ports and not have to handle that
 * in UARTClass
 */
/* Transmit and receive ring buffers */
STATIC RingBuffer txring, rxring;

/* Transmit and receive ring buffer sizes */
#define UART_SRB_SIZE 128   /* Send */
#define UART_RRB_SIZE 32    /* Receive */

/* Transmit and receive buffers */
static uint8_t rxbuff[UART_RRB_SIZE], txbuff[UART_SRB_SIZE];

// This can be either declared like this...
//UARTClass Serial(LPC_USART, UART0_IRQn, 0, &rxring, &txring);
// ...or like this...
UARTSerial Serial;
// and then constructed in Serial_Init()

// ----------------------------------------------------------------------------
//   INIT/DEINIT FUNCTIONS
// ----------------------------------------------------------------------------
void Serial_Init(void)
{

    /* Before using the ring buffers, initialize them using the ring
       buffer init function */
    RingBuffer_init(&rxring, rxbuff, UART_RRB_SIZE, sizeof(uint8_t));
    RingBuffer_init(&txring, txbuff, UART_SRB_SIZE, sizeof(uint8_t));

    Serial = UARTSerial(LPC_USART, UART0_IRQn, 0, &rxring, &txring);
}

// ----------------------------------------------------------------------------
void Serial_UART_Init(void *pUart, uint32_t dwIrq, const uint32_t dwBaudRate, const uint32_t configData)
{
    LPC_USART_T* _pUart = (LPC_USART_T*)pUart;
    IRQn_Type _dwIrq = (IRQn_Type)dwIrq;

    Chip_UART_Init(_pUart);
    Chip_UART_SetBaud(_pUart, dwBaudRate);
    Chip_UART_ConfigData(_pUart, configData);
    Chip_UART_SetupFIFOS(_pUart, (UART_FCR_FIFO_EN | UART_FCR_TRG_LEV2));
    Chip_UART_TXEnable(_pUart);

    /* Enable receive data and line status interrupt, the transmit interrupt
       is handled by the driver. */
    Chip_UART_IntEnable(_pUart, (UART_IER_RBRINT | UART_IER_RLSINT));

    NVIC_SetPriority(_dwIrq, 1);
    NVIC_EnableIRQ(_dwIrq);
}

// ----------------------------------------------------------------------------
void Serial_UART_End(void *pUart, uint32_t dwIrq)
{
    LPC_USART_T* _pUart = (LPC_USART_T*)pUart;
    IRQn_Type _dwIrq = (IRQn_Type)dwIrq;

    NVIC_DisableIRQ(_dwIrq);
    Chip_UART_DeInit(_pUart);
}

// ----------------------------------------------------------------------------
void Serial_UART_Flush(void *pUart)
{
    LPC_USART_T* _pUart = (LPC_USART_T*)pUart;

    // Wait for transmission to complete
    while (!Serial_UART_TxRegisterEmpty(_pUart)) yield();
}

// ----------------------------------------------------------------------------
//   LOW-LEVEL RX/TX FUNCTIONS, ALSO USED IN IRQ HANDLER
// ----------------------------------------------------------------------------
/* UART transmit-only interrupt handler for ring buffers */
void Serial_UART_Transmit(void *pUART, RingBuffer *pRB)
{
	uint8_t ch;

    /* Fill FIFO until full or until TX ring buffer is empty */
    while (Serial_UART_TxRegisterEmpty(pUART) && RingBuffer_popOne(pRB, &ch))
    {
        Chip_UART_SendByte((LPC_USART_T*)pUART, ch);
    }
}

// ----------------------------------------------------------------------------
/* UART receive-only interrupt handler for ring buffers */
void Serial_UART_Receive(void *pUART, RingBuffer *pRB)
{
    /* New data will be ignored if data not popped in time */
    while (Serial_UART_RxRegisterHasData(pUART))
    {
        uint8_t ch = Chip_UART_ReadByte((LPC_USART_T*)pUART);
        RingBuffer_pushOne(pRB, &ch);
    }
}

// ----------------------------------------------------------------------------
/*
 * When this returns true, that means UART is ready for the next byte to be sent.
 * This usually means: the top byte of the hardware UART FIFO is available
 * to accept next byte to be sent.
 */
bool Serial_UART_TxRegisterEmpty(void *pUART)
{
	return (Chip_UART_ReadLineStatus((LPC_USART_T *)pUART) & UART_LSR_THRE) != 0;
}

// ----------------------------------------------------------------------------
/*
 * When this returns true, that means UART has received a byte and it is waiting
 * for us to read it. This usually means: location at which UART register that
 * points to the oldest received byte in hardware UART FIFO, has not been read yet,
 * there's still data to read from receive FIFO.
 */
bool Serial_UART_RxRegisterHasData(void *pUART)
{
	return (Chip_UART_ReadLineStatus((LPC_USART_T *)pUART) & UART_LSR_RDR) != 0;
}

// ----------------------------------------------------------------------------
//   INTERRUPTS
// ----------------------------------------------------------------------------
void Serial_UART_Set_Interrupt_Priority(uint32_t dwIrq, uint32_t priority)
{
    IRQn_Type _dwIrq = (IRQn_Type)dwIrq;

    NVIC_SetPriority(_dwIrq, priority & 0x0F);
}

// ----------------------------------------------------------------------------
uint32_t Serial_UART_Get_Interrupt_Priority(uint32_t dwIrq)
{
    IRQn_Type _dwIrq = (IRQn_Type)dwIrq;

    return NVIC_GetPriority(_dwIrq);
}

// ----------------------------------------------------------------------------
void Serial_UART_Disable_Interrupt(void *pUART, uint32_t dwIrq)
{
	Chip_UART_IntDisable((LPC_USART_T *)pUART, UART_IER_THREINT);
}

// ----------------------------------------------------------------------------
void Serial_UART_Enable_Interrupt(void *pUART, uint32_t dwIrq)
{
	Chip_UART_IntEnable((LPC_USART_T *)pUART, UART_IER_THREINT);
}

// ----------------------------------------------------------------------------
//   EVENTS
// ----------------------------------------------------------------------------
// This fires in main loop whenever UART receives any bytes
// and they are available to be read
void serialEvent() __attribute__((weak));
void serialEvent() { }
// This one is called by main.cpp after every loop() call
void serialEventRun(void)
{
  if (Serial.available()) serialEvent();
}

// ----------------------------------------------------------------------------
//   IRQ HANDLERS
// ----------------------------------------------------------------------------

#ifdef __cplusplus
extern "C" {
#endif

/**
 * All LPC IRQ handlers and such have to be implemented here
 * within extern "C" declaration, otherwise their names will get mangled
 * by C++ compiler and they WON'T get linked where you would expect them
 * to be because they are declared with __attribute__((weak)).
 */

/**
 * @brief   UART interrupt handler using ring buffers
 * @return  Nothing
 */
#if defined (__USE_LPCOPEN)
void UART_IRQHandler(void)
#else
USART_IRQHandler
#endif
{
    /* Want to handle any errors? Do it here. */

    /* Use default ring buffer handler. Override this with your own
       code if you need more capability. */
    /* Handle transmit interrupt if enabled */
    if (LPC_USART->IER & UART_IER_THREINT)
    {
    	Serial_UART_Transmit(LPC_USART, &txring);

        /* Disable transmit interrupt if the ring buffer is empty */
        if (RingBuffer_isEmpty(&txring))
        {
        	Serial_UART_Disable_Interrupt(LPC_USART, 0);
        }
    }

    /* Handle receive interrupt */
    Serial_UART_Receive(LPC_USART, &rxring);
}

#ifdef __cplusplus
}
#endif

<commit_msg>Using strucutre to keep and pass all the information relevant to an UART peripheral.<commit_after>/*
  board_serial.h - Arduino-XC HAL API implementation of serial comm
  Copyright (c) 2016 Ravendyne Inc.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

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

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "lib/UARTSerial.h"
#include "board/board_serial.h"
#include "ringbuffer.h"
#include "board/variant.h"

#include "chip.h"

// ----------------------------------------------------------------------------
//   CONSTANT DEFINITIONS
// ----------------------------------------------------------------------------
// These "constants" are declared as variables and their value is platform specific
// This way we can declare these in code that is not platform specific (i.e. core or lib)
// and then define their values here in platform specific part where we need to access
// platform specific values (like UART_LCR_WLEN8, UART_LCR_PARITY_F_0, etc.)
extern const uint32_t SERIAL_8N1 = (UART_LCR_WLEN8 | UART_LCR_SBS_1BIT | UART_LCR_PARITY_DIS);
extern const uint32_t SERIAL_8E1 = (UART_LCR_WLEN8 | UART_LCR_SBS_1BIT | UART_LCR_PARITY_EVEN | UART_LCR_PARITY_EN);
extern const uint32_t SERIAL_8O1 = (UART_LCR_WLEN8 | UART_LCR_SBS_1BIT | UART_LCR_PARITY_ODD | UART_LCR_PARITY_EN);
extern const uint32_t SERIAL_8M1 = (UART_LCR_WLEN8 | UART_LCR_SBS_1BIT | UART_LCR_PARITY_F_1 | UART_LCR_PARITY_EN);
extern const uint32_t SERIAL_8S1 = (UART_LCR_WLEN8 | UART_LCR_SBS_1BIT | UART_LCR_PARITY_F_0 | UART_LCR_PARITY_EN);

/******************************************************************
 * UART objects
 */
/*
 * For each USART present on the chip, we declare one context
 */
Serial_UART_Context UART0_Context;
//Serial_UART_Context UART1_Context;
//Serial_UART_Context UART2_Context;

// This can be either declared like this...
//UARTClass Serial(LPC_USART, UART0_IRQn, 0, &rxring, &txring);
// ...or like this...
UARTSerial Serial;
// and then constructed in Serial_Init()

/* Transmit and receive ring buffer sizes */
#define UART_TXRB_SIZE 128   /* Send */
#define UART_RXRB_SIZE 32    /* Receive */

// ----------------------------------------------------------------------------
//   INIT/DEINIT FUNCTIONS
// ----------------------------------------------------------------------------
void Serial_Init(void)
{
	// Add code here for each USART chip has and you want to use in Zeeduino
	UART0_Context.dwId = 0;
	UART0_Context.pUART = (void*)LPC_USART;
	UART0_Context.dwIrq = UART0_IRQn;
	UART0_Context.rx_rbr = new RingBuffer;
	UART0_Context.tx_rbr = new RingBuffer;
	UART0_Context.rx_buffer = new uint8_t[UART_RXRB_SIZE];
	UART0_Context.tx_buffer = new uint8_t[UART_TXRB_SIZE];
	RingBuffer_init(UART0_Context.rx_rbr, UART0_Context.rx_buffer, UART_RXRB_SIZE, sizeof(uint8_t));
	RingBuffer_init(UART0_Context.tx_rbr, UART0_Context.tx_buffer, UART_TXRB_SIZE, sizeof(uint8_t));
    Serial = UARTSerial(&UART0_Context);
}

// ----------------------------------------------------------------------------
void Serial_UART_Init(void *uartHandle, const uint32_t dwBaudRate, const uint32_t configData)
{
    LPC_USART_T* pUart = (LPC_USART_T*)UART_CONTEXT(uartHandle)->pUART;
    IRQn_Type _dwIrq = (IRQn_Type)UART_CONTEXT(uartHandle)->dwIrq;

    Chip_UART_Init(pUart);
    Chip_UART_SetBaud(pUart, dwBaudRate);
    Chip_UART_ConfigData(pUart, configData);
    Chip_UART_SetupFIFOS(pUart, (UART_FCR_FIFO_EN | UART_FCR_TRG_LEV2));
    Chip_UART_TXEnable(pUart);

    /* Enable receive data and line status interrupt, the transmit interrupt
       is handled by the driver. */
    Chip_UART_IntEnable(pUart, (UART_IER_RBRINT | UART_IER_RLSINT));

    NVIC_SetPriority(_dwIrq, 1);
    NVIC_EnableIRQ(_dwIrq);
}

// ----------------------------------------------------------------------------
void Serial_UART_End(void *uartHandle)
{
    LPC_USART_T* pUart = (LPC_USART_T*)UART_CONTEXT(uartHandle)->pUART;
    IRQn_Type _dwIrq = (IRQn_Type)UART_CONTEXT(uartHandle)->dwIrq;

    NVIC_DisableIRQ(_dwIrq);
    Chip_UART_DeInit(pUart);
}

// ----------------------------------------------------------------------------
void Serial_UART_Flush(void *uartHandle)
{
    // Wait for transmission to complete
    while (!Serial_UART_TxRegisterEmpty(uartHandle)) yield();
}

// ----------------------------------------------------------------------------
//   LOW-LEVEL RX/TX FUNCTIONS, ALSO USED IN IRQ HANDLER
// ----------------------------------------------------------------------------
/* UART transmit-only interrupt handler for ring buffers */
void Serial_UART_Transmit(void *uartHandle)
{
	uint8_t ch;
    LPC_USART_T* pUart = (LPC_USART_T*)UART_CONTEXT(uartHandle)->pUART;

    /* Fill FIFO until full or until TX ring buffer is empty */
    while (Serial_UART_TxRegisterEmpty(uartHandle) && RingBuffer_popOne(UART_CONTEXT(uartHandle)->tx_rbr, &ch))
    {
        Chip_UART_SendByte(pUart, ch);
    }
}

// ----------------------------------------------------------------------------
/* UART receive-only interrupt handler for ring buffers */
void Serial_UART_Receive(void *uartHandle)
{
    LPC_USART_T* pUart = (LPC_USART_T*)UART_CONTEXT(uartHandle)->pUART;

    /* New data will be ignored if data not popped in time */
    while (Serial_UART_RxRegisterHasData(uartHandle))
    {
        uint8_t ch = Chip_UART_ReadByte(pUart);
        RingBuffer_pushOne(UART_CONTEXT(uartHandle)->rx_rbr, &ch);
    }
}

// ----------------------------------------------------------------------------
/*
 * When this returns true, that means UART is ready for the next byte to be sent.
 * This usually means: the top byte of the hardware UART FIFO is available
 * to accept next byte to be sent.
 */
bool Serial_UART_TxRegisterEmpty(void *uartHandle)
{
    LPC_USART_T* pUart = (LPC_USART_T*)UART_CONTEXT(uartHandle)->pUART;
	return (Chip_UART_ReadLineStatus(pUart) & UART_LSR_THRE) != 0;
}

// ----------------------------------------------------------------------------
/*
 * When this returns true, that means UART has received a byte and it is waiting
 * for us to read it. This usually means: location at which UART register that
 * points to the oldest received byte in hardware UART FIFO, has not been read yet,
 * there's still data to read from receive FIFO.
 */
bool Serial_UART_RxRegisterHasData(void *uartHandle)
{
    LPC_USART_T* pUart = (LPC_USART_T*)UART_CONTEXT(uartHandle)->pUART;
	return (Chip_UART_ReadLineStatus(pUart) & UART_LSR_RDR) != 0;
}

// ----------------------------------------------------------------------------
//   INTERRUPTS
// ----------------------------------------------------------------------------
void Serial_UART_Set_Interrupt_Priority(void *uartHandle, uint32_t priority)
{
	IRQn_Type _dwIrq = (IRQn_Type)UART_CONTEXT(uartHandle)->dwIrq;

    NVIC_SetPriority(_dwIrq, priority & 0x0F);
}

// ----------------------------------------------------------------------------
uint32_t Serial_UART_Get_Interrupt_Priority(void *uartHandle)
{
	IRQn_Type _dwIrq = (IRQn_Type)UART_CONTEXT(uartHandle)->dwIrq;

    return NVIC_GetPriority(_dwIrq);
}

// ----------------------------------------------------------------------------
void Serial_UART_Disable_Interrupt(void *uartHandle)
{
    LPC_USART_T* pUart = (LPC_USART_T*)UART_CONTEXT(uartHandle)->pUART;
	Chip_UART_IntDisable(pUart, UART_IER_THREINT);
}

// ----------------------------------------------------------------------------
void Serial_UART_Enable_Interrupt(void *uartHandle)
{
    LPC_USART_T* pUart = (LPC_USART_T*)UART_CONTEXT(uartHandle)->pUART;
	Chip_UART_IntEnable(pUart, UART_IER_THREINT);
}

// ----------------------------------------------------------------------------
//   EVENTS
// ----------------------------------------------------------------------------
// This fires in main loop whenever UART receives any bytes
// and they are available to be read
void serialEvent() __attribute__((weak));
void serialEvent() { }
// This one is called by main.cpp after every loop() call
void serialEventRun(void)
{
  if (Serial.available()) serialEvent();
}

// ----------------------------------------------------------------------------
//   IRQ HANDLERS
// ----------------------------------------------------------------------------

#ifdef __cplusplus
extern "C" {
#endif

/**
 * All LPC IRQ handlers and such have to be implemented here
 * within extern "C" declaration, otherwise their names will get mangled
 * by C++ compiler and they WON'T get linked where you would expect them
 * to be because they are declared with __attribute__((weak)).
 */

/**
 * Each USART peripheral will have it's own IRQ handler.
 * In the IRQ code, use a corresponding UARTx_Context declared above,
 * similar to what we did here for UART0 (the only USART on LPC1347)
 */
#if defined (__USE_LPCOPEN)
void UART_IRQHandler(void)
#else
USART_IRQHandler
#endif
{
    /* Want to handle any errors? Do it here. */

    /* Use default ring buffer handler. Override this with your own
       code if you need more capability. */
    /* Handle transmit interrupt if enabled */
    if (LPC_USART->IER & UART_IER_THREINT)
    {
    	Serial_UART_Transmit(&UART0_Context);

        /* Disable transmit interrupt if the ring buffer is empty */
        if (RingBuffer_isEmpty(UART0_Context.tx_rbr))
        {
        	Serial_UART_Disable_Interrupt(&UART0_Context);
        }
    }

    /* Handle receive interrupt */
    Serial_UART_Receive(&UART0_Context);
}

#ifdef __cplusplus
}
#endif

<|endoftext|>


<commit_before>/*!
 * @file window.cpp
 *
 * @brief Window class source file
 */

#include <algorithm>

#include "window.hpp"

#include "spoa/spoa.hpp"

namespace racon {

std::unique_ptr<Window> createWindow(uint64_t id, uint32_t rank, WindowType type,
    const char* backbone, uint32_t backbone_length, const char* quality,
    uint32_t quality_length) {

    if (backbone_length == 0 || backbone_length != quality_length) {
        fprintf(stderr, "[racon::createWindow] error: "
            "empty backbone sequence/unequal quality length!\n");
        exit(1);
    }

    return std::unique_ptr<Window>(new Window(id, rank, type, backbone,
        backbone_length, quality, quality_length));
}

Window::Window(uint64_t id, uint32_t rank, WindowType type, const char* backbone,
    uint32_t backbone_length, const char* quality, uint32_t quality_length)
        : id_(id), rank_(rank), type_(type), consensus_(), sequences_(),
        qualities_(), positions_() {

    sequences_.emplace_back(backbone, backbone_length);
    qualities_.emplace_back(quality, quality_length);
    positions_.emplace_back(0, 0);
}

Window::~Window() {
}

void Window::add_layer(const char* sequence, uint32_t sequence_length,
    const char* quality, uint32_t quality_length, uint32_t begin, uint32_t end) {

    if (quality != nullptr && sequence_length != quality_length) {
        fprintf(stderr, "[racon::Window::add_layer] error: "
            "unequal quality size!\n");
        exit(1);
    }
    if (begin >= end || begin > sequences_.front().second || end > sequences_.front().second) {
        fprintf(stderr, "[racon::Window::add_layer] error: "
            "layer begin and end positions are invalid!\n");
        exit(1);
    }

    sequences_.emplace_back(sequence, sequence_length);
    qualities_.emplace_back(quality, quality_length);
    positions_.emplace_back(begin, end);
}

bool Window::generate_consensus(std::shared_ptr<spoa::AlignmentEngine> alignment_engine) {

    if (sequences_.size() < 3) {
        consensus_ = std::string(sequences_.front().first, sequences_.front().second);
        return false;
    }

    auto graph = spoa::createGraph();
    graph->add_alignment(spoa::Alignment(), sequences_.front().first,
        sequences_.front().second, qualities_.front().first,
        qualities_.front().second);

    std::vector<uint32_t> rank;
    rank.reserve(sequences_.size());
    for (uint32_t i = 0; i < sequences_.size(); ++i) {
        rank.emplace_back(i);
    }

    std::sort(rank.begin() + 1, rank.end(), [&](uint32_t lhs, uint32_t rhs) {
        return positions_[lhs].first < positions_[rhs].first; });

    uint32_t offset = 0.01 * sequences_.front().second;
    for (uint32_t j = 1; j < sequences_.size(); ++j) {
        uint32_t i = rank[j];

        spoa::Alignment alignment;
        if (positions_[i].first < offset && positions_[i].second >
            sequences_.front().second - offset) {
            alignment = alignment_engine->align_sequence_with_graph(
                sequences_[i].first, sequences_[i].second, graph);
        } else {
            std::vector<int32_t> mapping;
            auto subgraph = graph->subgraph(positions_[i].first,
                positions_[i].second, mapping);
            alignment = alignment_engine->align_sequence_with_graph(
                sequences_[i].first, sequences_[i].second, subgraph);
            subgraph->update_alignment(alignment, mapping);
        }

        if (qualities_[i].first == nullptr) {
            graph->add_alignment(alignment, sequences_[i].first,
                sequences_[i].second);
        } else {
            graph->add_alignment(alignment, sequences_[i].first,
                sequences_[i].second, qualities_[i].first,
                qualities_[i].second);
        }
    }

    std::vector<uint32_t> coverages;
    consensus_ = graph->generate_consensus(coverages);

    if (type_ == WindowType::kTGS) {
        uint32_t average_coverage = (sequences_.size() - 1) / 2;

        int32_t begin = 0, end = consensus_.size() - 1;
        for (; begin < static_cast<int32_t>(consensus_.size()); ++begin) {
            if (coverages[begin] >= average_coverage) {
                break;
            }
        }
        for (; end >= 0; --end) {
            if (coverages[end] >= average_coverage) {
                break;
            }
        }

        if (begin >= end) {
            fprintf(stderr, "[racon::Window::generate_consensus] warning: "
                "contig %lu might be chimeric in window %u!\n", id_, rank_);
        } else {
            consensus_ = consensus_.substr(begin, end - begin + 1);
        }

    } else if (type_ == WindowType::kNGS) {
        uint32_t i = 0;
        for (uint32_t j = 0; i < consensus_.size(); ++i) {
            if (consensus_[i] != 'N') {
                continue;
            }

            j = std::max(j, i);
            while (j < consensus_.size() && consensus_[j] == 'N') {
                ++j;
            }

            if (j >= consensus_.size()) {
                break;
            } else if (i != j) {
                consensus_[i] = consensus_[j];
                consensus_[j] = 'N';
            }
        }
        if (i < consensus_.size()) {
            consensus_.resize(i);
        }
    }

    return true;
}

}
<commit_msg>Removed Illumina postprocessing<commit_after>/*!
 * @file window.cpp
 *
 * @brief Window class source file
 */

#include <algorithm>

#include "window.hpp"

#include "spoa/spoa.hpp"

namespace racon {

std::unique_ptr<Window> createWindow(uint64_t id, uint32_t rank, WindowType type,
    const char* backbone, uint32_t backbone_length, const char* quality,
    uint32_t quality_length) {

    if (backbone_length == 0 || backbone_length != quality_length) {
        fprintf(stderr, "[racon::createWindow] error: "
            "empty backbone sequence/unequal quality length!\n");
        exit(1);
    }

    return std::unique_ptr<Window>(new Window(id, rank, type, backbone,
        backbone_length, quality, quality_length));
}

Window::Window(uint64_t id, uint32_t rank, WindowType type, const char* backbone,
    uint32_t backbone_length, const char* quality, uint32_t quality_length)
        : id_(id), rank_(rank), type_(type), consensus_(), sequences_(),
        qualities_(), positions_() {

    sequences_.emplace_back(backbone, backbone_length);
    qualities_.emplace_back(quality, quality_length);
    positions_.emplace_back(0, 0);
}

Window::~Window() {
}

void Window::add_layer(const char* sequence, uint32_t sequence_length,
    const char* quality, uint32_t quality_length, uint32_t begin, uint32_t end) {

    if (quality != nullptr && sequence_length != quality_length) {
        fprintf(stderr, "[racon::Window::add_layer] error: "
            "unequal quality size!\n");
        exit(1);
    }
    if (begin >= end || begin > sequences_.front().second || end > sequences_.front().second) {
        fprintf(stderr, "[racon::Window::add_layer] error: "
            "layer begin and end positions are invalid!\n");
        exit(1);
    }

    sequences_.emplace_back(sequence, sequence_length);
    qualities_.emplace_back(quality, quality_length);
    positions_.emplace_back(begin, end);
}

bool Window::generate_consensus(std::shared_ptr<spoa::AlignmentEngine> alignment_engine) {

    if (sequences_.size() < 3) {
        consensus_ = std::string(sequences_.front().first, sequences_.front().second);
        return false;
    }

    auto graph = spoa::createGraph();
    graph->add_alignment(spoa::Alignment(), sequences_.front().first,
        sequences_.front().second, qualities_.front().first,
        qualities_.front().second);

    std::vector<uint32_t> rank;
    rank.reserve(sequences_.size());
    for (uint32_t i = 0; i < sequences_.size(); ++i) {
        rank.emplace_back(i);
    }

    std::sort(rank.begin() + 1, rank.end(), [&](uint32_t lhs, uint32_t rhs) {
        return positions_[lhs].first < positions_[rhs].first; });

    uint32_t offset = 0.01 * sequences_.front().second;
    for (uint32_t j = 1; j < sequences_.size(); ++j) {
        uint32_t i = rank[j];

        spoa::Alignment alignment;
        if (positions_[i].first < offset && positions_[i].second >
            sequences_.front().second - offset) {
            alignment = alignment_engine->align_sequence_with_graph(
                sequences_[i].first, sequences_[i].second, graph);
        } else {
            std::vector<int32_t> mapping;
            auto subgraph = graph->subgraph(positions_[i].first,
                positions_[i].second, mapping);
            alignment = alignment_engine->align_sequence_with_graph(
                sequences_[i].first, sequences_[i].second, subgraph);
            subgraph->update_alignment(alignment, mapping);
        }

        if (qualities_[i].first == nullptr) {
            graph->add_alignment(alignment, sequences_[i].first,
                sequences_[i].second);
        } else {
            graph->add_alignment(alignment, sequences_[i].first,
                sequences_[i].second, qualities_[i].first,
                qualities_[i].second);
        }
    }

    std::vector<uint32_t> coverages;
    consensus_ = graph->generate_consensus(coverages);

    if (type_ == WindowType::kTGS) {
        uint32_t average_coverage = (sequences_.size() - 1) / 2;

        int32_t begin = 0, end = consensus_.size() - 1;
        for (; begin < static_cast<int32_t>(consensus_.size()); ++begin) {
            if (coverages[begin] >= average_coverage) {
                break;
            }
        }
        for (; end >= 0; --end) {
            if (coverages[end] >= average_coverage) {
                break;
            }
        }

        if (begin >= end) {
            fprintf(stderr, "[racon::Window::generate_consensus] warning: "
                "contig %lu might be chimeric in window %u!\n", id_, rank_);
        } else {
            consensus_ = consensus_.substr(begin, end - begin + 1);
        }
    }

    return true;
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2014, Baidu.com, Inc. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Author: yanshiguang02@baidu.com

#include "logging.h"

#include <assert.h>
#include <boost/bind.hpp>
#include <queue>
#include <set>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <syscall.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>

#include "mutex.h"
#include "thread.h"
#include "timer.h"

namespace baidu {
namespace common {

int g_log_level = INFO;
int64_t g_log_size = 0;
int32_t g_log_count = 0;
FILE* g_log_file = stdout;
std::string g_log_file_name;
FILE* g_warning_file = NULL;
int64_t g_total_size_limit = 0;

std::set<std::string> g_log_set;
int64_t current_total_size = 0;

bool GetNewLog(bool append) {
    char buf[30];
    struct timeval tv;
    gettimeofday(&tv, NULL);
    const time_t seconds = tv.tv_sec;
    struct tm t;
    localtime_r(&seconds, &t);
    snprintf(buf, 30,
        "%02d-%02d.%02d:%02d:%02d.%06d",
        t.tm_mon + 1,
        t.tm_mday,
        t.tm_hour,
        t.tm_min,
        t.tm_sec,
        static_cast<int>(tv.tv_usec));
    std::string full_path(g_log_file_name + ".");
    full_path.append(buf);
    size_t idx = full_path.rfind('/');
    if (idx == std::string::npos) {
        idx = 0;
    } else {
        idx += 1;
    }
    const char* mode = append ? "ab" : "wb";
    FILE* fp = fopen(full_path.c_str(), mode);
    if (fp == NULL) {
        return false;
    }
    if (g_log_file != stdout) {
        fclose(g_log_file);
    }
    g_log_file = fp;
    remove(g_log_file_name.c_str());
    symlink(full_path.substr(idx).c_str(), g_log_file_name.c_str());
    g_log_set.insert(full_path);
    while ((g_log_count && static_cast<int64_t>(g_log_set.size()) > g_log_count)
            || (g_total_size_limit && current_total_size > g_total_size_limit)) {
        std::set<std::string>::iterator it = g_log_set.begin();
        if (it != g_log_set.end()) {
            struct stat sta;
            if (-1 == lstat(it->c_str(), &sta)) {
                return false;
            }
            remove(it->c_str());
            current_total_size -= sta.st_size;
            g_log_set.erase(it++);
        }
    }
    return true;
}

void SetLogLevel(int level) {
    g_log_level = level;
}

class AsyncLogger {
public:
    AsyncLogger()
      : jobs_(&mu_), done_(&mu_), stopped_(false), size_(0) {
        thread_.Start(boost::bind(&AsyncLogger::AsyncWriter, this));
    }
    ~AsyncLogger() {
        stopped_ = true;
        {
            MutexLock lock(&mu_);
            jobs_.Signal();
        }
        thread_.Join();
        // close fd
    }
    void WriteLog(int log_level, const char* buffer, int32_t len) {
        std::string* log_str = new std::string(buffer, len);
        MutexLock lock(&mu_);
        buffer_queue_.push(make_pair(log_level, log_str));
        jobs_.Signal();
    }
    void AsyncWriter() {
        MutexLock lock(&mu_);
        while (1) {
            int loglen = 0;
            int wflen = 0;
            while (!buffer_queue_.empty()) {
                int log_level = buffer_queue_.front().first;
                std::string* str = buffer_queue_.front().second;
                buffer_queue_.pop();
                if (g_log_file != stdout && g_log_size && str &&
                        static_cast<int64_t>(size_ + str->length()) > g_log_size) {
                    current_total_size += static_cast<int64_t>(size_ + str->length());
                    mu_.Unlock();
                    GetNewLog(false);
                    mu_.Lock();
                    size_ = 0;
                }
                mu_.Unlock();
                if (str && !str->empty()) {
                    fwrite(str->data(), 1, str->size(), g_log_file);
                    loglen += str->size();
                    if (g_warning_file && log_level >= 8) {
                        fwrite(str->data(), 1, str->size(), g_warning_file);
                        wflen += str->size();
                    }
                    if (g_log_size) size_ += str->length();
                }
                delete str;
                mu_.Lock();
            }
            if (loglen) fflush(g_log_file);
            if (wflen) fflush(g_warning_file);
            if (stopped_) {
                break;
            }
            done_.Broadcast();
            jobs_.Wait();
        }
    }
    void Flush() {
        MutexLock lock(&mu_);
        buffer_queue_.push(std::make_pair(0, reinterpret_cast<std::string*>(NULL)));
        jobs_.Signal();
        done_.Wait();
    }
private:
    Mutex mu_;
    CondVar jobs_;
    CondVar done_;
    bool stopped_;
    int64_t size_;
    Thread thread_;
    std::queue<std::pair<int, std::string*> > buffer_queue_;
};

AsyncLogger g_logger;

bool SetWarningFile(const char* path, bool append) {
    const char* mode = append ? "ab" : "wb";
    FILE* fp = fopen(path, mode);
    if (fp == NULL) {
        return false;
    }
    if (g_warning_file) {
        fclose(g_warning_file);
    }
    g_warning_file = fp;
    return true;
}

bool RecoverHistory(const char* path) {
    std::string log_path(path);
    size_t idx = log_path.rfind('/');
    std::string dir = "./";
    std::string log(path);
    if (idx != std::string::npos) {
        dir = log_path.substr(0, idx + 1);
        log = log_path.substr(idx + 1);
    }
    struct dirent *entry = NULL;
    DIR *dir_ptr = opendir(dir.c_str());
    if (dir_ptr == NULL) {
        return false;
    }
    std::vector<std::string> loglist;
    while (entry = readdir(dir_ptr)) {
        if (std::string(entry->d_name).find(log) != std::string::npos) {
            std::string file_name = dir + std::string(entry->d_name);
            struct stat sta;
            if (-1 == lstat(file_name.c_str(), &sta)) {
                return false;
            }
            if (S_ISREG(sta.st_mode)) {
                loglist.push_back(dir + std::string(entry->d_name));
                current_total_size += sta.st_size;
            }
        }
    }
    closedir(dir_ptr);
    std::sort(loglist.begin(), loglist.end());
    for (std::vector<std::string>::iterator it = loglist.begin(); it != loglist.end();
            ++it) {
        g_log_set.insert(*it);
    }
    while ( (g_log_count && static_cast<int64_t>(g_log_set.size()) > g_log_count)
            || (g_total_size_limit && current_total_size > g_total_size_limit)) {
        std::set<std::string>::iterator it = g_log_set.begin();
        if (it != g_log_set.end()) {
            struct stat sta;
            if (-1 == lstat(it->c_str(), &sta)) {
                return false;
            }
            remove(it->c_str());
            current_total_size -= sta.st_size;
            g_log_set.erase(it++);
        }
    }
    return true;
}

bool SetLogFile(const char* path, bool append) {
    g_log_file_name.assign(path);
    return GetNewLog(append);
}

bool SetLogSize(int size) {
    if (size < 0) {
        return false;
    }
    g_log_size = static_cast<int64_t>(size) << 20;
    return true;
}

bool SetLogCount(int count) {
    if (count < 0 || g_total_size_limit != 0) {
        return false;
    }
    g_log_count = count;
    if (!RecoverHistory(g_log_file_name.c_str())) {
        return false;
    }
    return true;
}

bool SetLogSizeLimit(int size) {
    if (size < 0 || g_log_count != 0) {
        return false;
    }
    g_total_size_limit = static_cast<int64_t>(size) << 20;
    if (!RecoverHistory(g_log_file_name.c_str())) {
        return false;
    }
    return true;
}

void Logv(int log_level, const char* format, va_list ap) {
    static __thread uint64_t thread_id = 0;
    if (thread_id == 0) {
        thread_id = syscall(__NR_gettid);
    }

    // We try twice: the first time with a fixed-size stack allocated buffer,
    // and the second time with a much larger dynamically allocated buffer.
    char buffer[500];
    for (int iter = 0; iter < 2; iter++) {
        char* base;
        int bufsize;
        if (iter == 0) {
            bufsize = sizeof(buffer);
            base = buffer;
        } else {
            bufsize = 30000;
            base = new char[bufsize];
        }
        char* p = base;
        char* limit = base + bufsize;

        int32_t rlen = timer::now_time_str(p, limit - p);
        p += rlen;
        p += snprintf(p, limit - p, " %lld ", static_cast<long long unsigned int>(thread_id));

        // Print the message
        if (p < limit) {
            va_list backup_ap;
            va_copy(backup_ap, ap);
            p += vsnprintf(p, limit - p, format, backup_ap);
            va_end(backup_ap);
        }

        // Truncate to available space if necessary
        if (p >= limit) {
            if (iter == 0) {
                continue;       // Try again with larger buffer
            } else {
                p = limit - 1;
            }
        }

        // Add newline if necessary
        if (p == base || p[-1] != '\n') {
            *p++ = '\n';
        }

        assert(p <= limit);
        //fwrite(base, 1, p - base, g_log_file);
        //fflush(g_log_file);
        //if (g_warning_file && log_level >= 8) {
        //    fwrite(base, 1, p - base, g_warning_file);
        //    fflush(g_warning_file);
        //}
        g_logger.WriteLog(log_level, base, p - base);
        if (log_level == FATAL) {
            g_logger.Flush();
        }
        if (base != buffer) {
            delete[] base;
        }
        break;
    }
}

void Log(int level, const char* fmt, ...) {
    va_list ap;
    va_start(ap, fmt);

    if (level >= g_log_level) {
        Logv(level, fmt, ap);
    }
    va_end(ap);
    if (level == FATAL) {
        abort();
    }
}

LogStream::LogStream(int level) : level_(level) {}

LogStream::~LogStream() {
    Log(level_, "%s", oss_.str().c_str());
}

} // namespace common
} // namespace baidu

/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
<commit_msg>fix file len<commit_after>// Copyright (c) 2014, Baidu.com, Inc. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Author: yanshiguang02@baidu.com

#include "logging.h"

#include <assert.h>
#include <boost/bind.hpp>
#include <queue>
#include <set>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <syscall.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>

#include "mutex.h"
#include "thread.h"
#include "timer.h"

namespace baidu {
namespace common {

int g_log_level = INFO;
int64_t g_log_size = 0;
int32_t g_log_count = 0;
FILE* g_log_file = stdout;
std::string g_log_file_name;
FILE* g_warning_file = NULL;
int64_t g_total_size_limit = 0;

std::set<std::string> g_log_set;
int64_t current_total_size = 0;

bool GetNewLog(bool append) {
    char buf[30];
    struct timeval tv;
    gettimeofday(&tv, NULL);
    const time_t seconds = tv.tv_sec;
    struct tm t;
    localtime_r(&seconds, &t);
    snprintf(buf, 30,
        "%02d-%02d.%02d:%02d:%02d.%06d",
        t.tm_mon + 1,
        t.tm_mday,
        t.tm_hour,
        t.tm_min,
        t.tm_sec,
        static_cast<int>(tv.tv_usec));
    std::string full_path(g_log_file_name + ".");
    full_path.append(buf);
    size_t idx = full_path.rfind('/');
    if (idx == std::string::npos) {
        idx = 0;
    } else {
        idx += 1;
    }
    const char* mode = append ? "ab" : "wb";
    FILE* fp = fopen(full_path.c_str(), mode);
    if (fp == NULL) {
        return false;
    }
    if (g_log_file != stdout) {
        fclose(g_log_file);
    }
    g_log_file = fp;
    remove(g_log_file_name.c_str());
    symlink(full_path.substr(idx).c_str(), g_log_file_name.c_str());
    g_log_set.insert(full_path);
    while ((g_log_count && static_cast<int64_t>(g_log_set.size()) > g_log_count)
            || (g_total_size_limit && current_total_size > g_total_size_limit)) {
        std::set<std::string>::iterator it = g_log_set.begin();
        if (it != g_log_set.end()) {
            struct stat sta;
            if (-1 == lstat(it->c_str(), &sta)) {
                return false;
            }
            remove(it->c_str());
            current_total_size -= sta.st_size;
            g_log_set.erase(it++);
        } else {
            break;
        }
    }
    return true;
}

void SetLogLevel(int level) {
    g_log_level = level;
}

class AsyncLogger {
public:
    AsyncLogger()
      : jobs_(&mu_), done_(&mu_), stopped_(false), size_(0) {
        thread_.Start(boost::bind(&AsyncLogger::AsyncWriter, this));
    }
    ~AsyncLogger() {
        stopped_ = true;
        {
            MutexLock lock(&mu_);
            jobs_.Signal();
        }
        thread_.Join();
        // close fd
    }
    void WriteLog(int log_level, const char* buffer, int32_t len) {
        std::string* log_str = new std::string(buffer, len);
        MutexLock lock(&mu_);
        buffer_queue_.push(make_pair(log_level, log_str));
        jobs_.Signal();
    }
    void AsyncWriter() {
        MutexLock lock(&mu_);
        while (1) {
            int loglen = 0;
            int wflen = 0;
            while (!buffer_queue_.empty()) {
                int log_level = buffer_queue_.front().first;
                std::string* str = buffer_queue_.front().second;
                buffer_queue_.pop();
                if (g_log_file != stdout && g_log_size && str &&
                        static_cast<int64_t>(size_ + str->length()) > g_log_size) {
                    current_total_size += static_cast<int64_t>(size_ + str->length());
                    mu_.Unlock();
                    GetNewLog(false);
                    mu_.Lock();
                    size_ = 0;
                }
                mu_.Unlock();
                if (str && !str->empty()) {
                    size_t lret = fwrite(str->data(), 1, str->size(), g_log_file);
                    loglen += lret;
                    if (g_warning_file && log_level >= 8) {
                        size_t wret = fwrite(str->data(), 1, str->size(), g_warning_file);
                        wflen += wret;
                    }
                    if (g_log_size) size_ += lret;
                }
                delete str;
                mu_.Lock();
            }
            if (loglen) fflush(g_log_file);
            if (wflen) fflush(g_warning_file);
            if (stopped_) {
                break;
            }
            done_.Broadcast();
            jobs_.Wait();
        }
    }
    void Flush() {
        MutexLock lock(&mu_);
        buffer_queue_.push(std::make_pair(0, reinterpret_cast<std::string*>(NULL)));
        jobs_.Signal();
        done_.Wait();
    }
private:
    Mutex mu_;
    CondVar jobs_;
    CondVar done_;
    bool stopped_;
    int64_t size_;
    Thread thread_;
    std::queue<std::pair<int, std::string*> > buffer_queue_;
};

AsyncLogger g_logger;

bool SetWarningFile(const char* path, bool append) {
    const char* mode = append ? "ab" : "wb";
    FILE* fp = fopen(path, mode);
    if (fp == NULL) {
        return false;
    }
    if (g_warning_file) {
        fclose(g_warning_file);
    }
    g_warning_file = fp;
    return true;
}

bool RecoverHistory(const char* path) {
    std::string log_path(path);
    size_t idx = log_path.rfind('/');
    std::string dir = "./";
    std::string log(path);
    if (idx != std::string::npos) {
        dir = log_path.substr(0, idx + 1);
        log = log_path.substr(idx + 1);
    }
    struct dirent *entry = NULL;
    DIR *dir_ptr = opendir(dir.c_str());
    if (dir_ptr == NULL) {
        return false;
    }
    std::vector<std::string> loglist;
    while (entry = readdir(dir_ptr)) {
        if (std::string(entry->d_name).find(log) != std::string::npos) {
            std::string file_name = dir + std::string(entry->d_name);
            struct stat sta;
            if (-1 == lstat(file_name.c_str(), &sta)) {
                return false;
            }
            if (S_ISREG(sta.st_mode)) {
                loglist.push_back(dir + std::string(entry->d_name));
                current_total_size += sta.st_size;
            }
        }
    }
    closedir(dir_ptr);
    std::sort(loglist.begin(), loglist.end());
    for (std::vector<std::string>::iterator it = loglist.begin(); it != loglist.end();
            ++it) {
        g_log_set.insert(*it);
    }
    while ( (g_log_count && static_cast<int64_t>(g_log_set.size()) > g_log_count)
            || (g_total_size_limit && current_total_size > g_total_size_limit)) {
        std::set<std::string>::iterator it = g_log_set.begin();
        if (it != g_log_set.end()) {
            struct stat sta;
            if (-1 == lstat(it->c_str(), &sta)) {
                return false;
            }
            remove(it->c_str());
            current_total_size -= sta.st_size;
            g_log_set.erase(it++);
        }
    }
    return true;
}

bool SetLogFile(const char* path, bool append) {
    g_log_file_name.assign(path);
    return GetNewLog(append);
}

bool SetLogSize(int size) {
    if (size < 0) {
        return false;
    }
    g_log_size = static_cast<int64_t>(size) << 20;
    return true;
}

bool SetLogCount(int count) {
    if (count < 0 || g_total_size_limit != 0) {
        return false;
    }
    g_log_count = count;
    if (!RecoverHistory(g_log_file_name.c_str())) {
        return false;
    }
    return true;
}

bool SetLogSizeLimit(int size) {
    if (size < 0 || g_log_count != 0) {
        return false;
    }
    g_total_size_limit = static_cast<int64_t>(size) << 20;
    if (!RecoverHistory(g_log_file_name.c_str())) {
        return false;
    }
    return true;
}

void Logv(int log_level, const char* format, va_list ap) {
    static __thread uint64_t thread_id = 0;
    if (thread_id == 0) {
        thread_id = syscall(__NR_gettid);
    }

    // We try twice: the first time with a fixed-size stack allocated buffer,
    // and the second time with a much larger dynamically allocated buffer.
    char buffer[500];
    for (int iter = 0; iter < 2; iter++) {
        char* base;
        int bufsize;
        if (iter == 0) {
            bufsize = sizeof(buffer);
            base = buffer;
        } else {
            bufsize = 30000;
            base = new char[bufsize];
        }
        char* p = base;
        char* limit = base + bufsize;

        int32_t rlen = timer::now_time_str(p, limit - p);
        p += rlen;
        p += snprintf(p, limit - p, " %lld ", static_cast<long long unsigned int>(thread_id));

        // Print the message
        if (p < limit) {
            va_list backup_ap;
            va_copy(backup_ap, ap);
            p += vsnprintf(p, limit - p, format, backup_ap);
            va_end(backup_ap);
        }

        // Truncate to available space if necessary
        if (p >= limit) {
            if (iter == 0) {
                continue;       // Try again with larger buffer
            } else {
                p = limit - 1;
            }
        }

        // Add newline if necessary
        if (p == base || p[-1] != '\n') {
            *p++ = '\n';
        }

        assert(p <= limit);
        //fwrite(base, 1, p - base, g_log_file);
        //fflush(g_log_file);
        //if (g_warning_file && log_level >= 8) {
        //    fwrite(base, 1, p - base, g_warning_file);
        //    fflush(g_warning_file);
        //}
        g_logger.WriteLog(log_level, base, p - base);
        if (log_level == FATAL) {
            g_logger.Flush();
        }
        if (base != buffer) {
            delete[] base;
        }
        break;
    }
}

void Log(int level, const char* fmt, ...) {
    va_list ap;
    va_start(ap, fmt);

    if (level >= g_log_level) {
        Logv(level, fmt, ap);
    }
    va_end(ap);
    if (level == FATAL) {
        abort();
    }
}

LogStream::LogStream(int level) : level_(level) {}

LogStream::~LogStream() {
    Log(level_, "%s", oss_.str().c_str());
}

} // namespace common
} // namespace baidu

/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
<|endoftext|>