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

/// \file urbi/uvalue.hh
#ifndef URBI_UVALUE_HH
# define URBI_UVALUE_HH

# include <libport/warning-push.hh>

# include <vector>

# include <libport/hash.hh>
# include <libport/preproc.hh>
# include <libport/traits.hh>
# include <libport/ufloat.h>

# include <urbi/fwd.hh>
# include <urbi/export.hh>
# include <urbi/ubinary.hh>

namespace urbi
{

  /*--------------------------.
  | Free standing functions.  |
  `--------------------------*/

  /// If a kernel version was associated to this stream, its value.
  URBI_SDK_API
  int& kernelMajor(std::ostream& o);

  /// Issue a syncline.
  /// \param srcdir   the path from here to the top-srcdir.
  ///                 Will be removed from file.
  /// \param file     __FILE__
  /// \param line     __LINE__
  URBI_SDK_API
  std::string
  syncline_push(const std::string& srcdir, std::string file, unsigned line);

#define SYNCLINE_PUSH()                                         \
  "//#push " BOOST_PP_STRINGIZE(__LINE__) " \"" __FILE__ "\"\n"

#define SYNCLINE_POP()                          \
  "//#pop\n"

#ifndef __SRCDIR__
# define __SRCDIR__ ""
#endif

#define SYNCLINE_WRAP(...)                                      \
  (::urbi::syncline_push(__SRCDIR__, __FILE__, __LINE__)        \
   + libport::format(__VA_ARGS__)                               \
   + "\n"                                                       \
   SYNCLINE_POP())

  // UValue and other related types

  /// Possible value types a UValue can contain.
  enum UDataType
  {
    DATA_BINARY = 0,
    DATA_DICTIONARY = 1,
    DATA_DOUBLE = 2,
    DATA_LIST = 3,
    // No longer supported. DATA_OBJECT = 4,
    DATA_STRING = 5,
    DATA_SLOTNAME = 6,
    DATA_VOID = 7,
  };

  /*--------.
  | UList.  |
  `--------*/

  /// Class storing URBI List type
  class URBI_SDK_API UList
  {
  public:
    UList();
    UList(const UList &b);
    ~UList();

    UList& operator=(const UList &b);

    // Assign a container to the UList
    template<typename T>
    UList& operator=(const T& container);

    UList& operator=(UVar& v);

    // Transform the UList to a container.
    template<typename T>
    T as();

    /// Iteration.
    typedef std::vector<UValue*> list_type;
    typedef list_type::iterator iterator;
    typedef list_type::const_iterator const_iterator;
    iterator begin();
    iterator end();
    const_iterator begin() const;
    const_iterator end() const;

    // Append an element to the end.
    template<typename T>
    UList&
    push_back(const T& v);

    void pop_back();

    UValue& front();

    UValue& operator[](size_t i);
    const UValue& operator[](size_t i) const;

    size_t size() const;
    void setOffset(size_t n);

    std::ostream& print(std::ostream& o) const;

    // The actual contents.
    list_type array;

  private:
    void clear();
    size_t offset;
    friend class UValue;
  };

  URBI_SDK_API
  std::ostream& operator<< (std::ostream& o, const UList& t);

  /*--------------.
  | UDictionary.  |
  `--------------*/

  typedef boost::unordered_map<std::string, UValue> UDictionary;

  URBI_SDK_API
  std::ostream& operator<<(std::ostream& s, const UDictionary& d);

  /*--------------.
  | UNamedValue.  |
  `--------------*/

  class URBI_SDK_API UNamedValue
  {
  public:
    UNamedValue(const std::string& n = "", UValue* v = 0);
    // Used on errors.
    static UNamedValue& error();
    std::string name;
    UValue* val;
  };

  /*---------.
  | UValue.  |
  `---------*/

  /** Container for a value that handles all types known to URBI.
   */
  class URBI_SDK_API UValue
  {
  public:
    UDataType type;

    ufloat val;                 ///< value if of type DATA_DOUBLE
    union
    {
      std::string* stringValue; ///< value if of type DATA_STRING
      UBinary* binary;          ///< value if of type DATA_BINARY
      UList* list;              ///< value if of type DATA_LIST
      UDictionary* dictionary;  ///< value if of type DATA_DICTIONARY
      void* storage;            ///< internal
    };

    UValue();
    UValue(const UValue&);

    ~UValue();

    UValue& operator=(const UValue&);
    /// Setter. If copy is false, binary data if present is not copied.
    /// This is dangerous, as the user must ensure that the source UValue
    /// lives longer than this one.
    UValue& set(const UValue&, bool copy=true);
    /// Delete content and reset type to void.
    void clear();
    /// A specific UValue used when we want to return an error.
    /// For instance, out-of-bound access returns this object.
    static UValue& error();

    /// We use an operator , that behaves like an assignment.  The
    /// only difference is when the rhs is void, in which case it is
    /// the regular comma which is used.  This allows to write "uval,
    /// expr" to mean "compute expr and assign its result to uval,
    /// unless expr is void".
    UValue& operator, (const UValue &b);

    /// Return a legible definition of UDataType
    const char* format_string() const;

#define CTOR_AND_ASSIGN_AND_COMMA(Type)           \
    explicit UValue(Type, bool copy=true);	  \
    UValue& operator=(Type);			  \
    UValue& operator,(Type rhs);

// Types convertibles to DATA_DOUBLE
#define URBI_DERIVED_NUMERIC_TYPES                     \
  LIBPORT_LIST(int, long, unsigned int, unsigned long, \
               unsigned long long, long long,)

#define URBI_NUMERIC_TYPES                                     \
  LIBPORT_LIST(ufloat, int, long, unsigned int, unsigned long, \
               unsigned long long, long long,)

// Types convertibles to DATA_STRING
#define URBI_STRING_TYPES \
  LIBPORT_LIST(const char*, const void*, const std::string&,)

#define URBI_MISC_TYPES                                          \
  LIBPORT_LIST(const UBinary&, const UList&, const UDictionary&, \
               const USound&, const UImage&,)

# ifndef SWIG
    LIBPORT_LIST_APPLY(CTOR_AND_ASSIGN_AND_COMMA, URBI_NUMERIC_TYPES)
    LIBPORT_LIST_APPLY(CTOR_AND_ASSIGN_AND_COMMA, URBI_STRING_TYPES)
    LIBPORT_LIST_APPLY(CTOR_AND_ASSIGN_AND_COMMA, URBI_MISC_TYPES)
# else
    // UFloats.
    CTOR_AND_ASSIGN_AND_COMMA(ufloat);
    CTOR_AND_ASSIGN_AND_COMMA(int);
    CTOR_AND_ASSIGN_AND_COMMA(long);
    CTOR_AND_ASSIGN_AND_COMMA(unsigned int);
    CTOR_AND_ASSIGN_AND_COMMA(unsigned long);
    CTOR_AND_ASSIGN_AND_COMMA(unsigned long long);
    CTOR_AND_ASSIGN_AND_COMMA(long long);

    // Strings.
    CTOR_AND_ASSIGN_AND_COMMA(const char*);
    CTOR_AND_ASSIGN_AND_COMMA(const void*);
    CTOR_AND_ASSIGN_AND_COMMA(const std::string&);

    // Others.
    CTOR_AND_ASSIGN_AND_COMMA(const UBinary&);
    CTOR_AND_ASSIGN_AND_COMMA(const UList&);
    CTOR_AND_ASSIGN_AND_COMMA(const UDictionary&);
    CTOR_AND_ASSIGN_AND_COMMA(const USound&);
    CTOR_AND_ASSIGN_AND_COMMA(const UImage&);
# endif

#undef CTOR_AND_ASSIGN_AND_COMMA

#define CAST_OPERATOR(Type) \
    operator Type() const;

# ifndef SWIG
    LIBPORT_LIST_APPLY(CAST_OPERATOR, URBI_NUMERIC_TYPES)
# else
    operator ufloat() const;
    operator std::string() const;
    operator int() const;
    operator unsigned int() const;
    operator long() const;
    operator unsigned long() const;
    operator bool() const;
# endif
#undef CAST_OPERATOR

#ifdef DOXYGEN
    // Doxygens needs a prototype for ufloat.
    operator ufloat() const;
#endif

    operator std::string() const;
    operator bool() const;

    /// Accessor. Gives us an implicit operator UBinary() const
    operator const UBinary&() const;

    /// Deep copy.
    operator UList() const;

    /// Deep copy.
    operator UDictionary() const;

    /// Shallow copy.
    operator UImage() const;

    /// Shallow copy.
    operator USound() const;

    /// This operator does nothing, but helps with the previous operator,.
    /// Indeed, when writing "uval, void_expr", the compiler complains
    /// about uval being evaluated for nothing.  Let's have it believe
    /// we're doing something...
    UValue& operator()();

    /// Parse an uvalue in current message+pos, returns pos of end of
    /// match -pos of error if error.
    int parse(const char* message,
	      int pos,
	      const binaries_type& bins,
	      binaries_type::const_iterator& binpos);

    /// Print itself on \c s, and return it.
    std::ostream& print(std::ostream& s) const;

    // Huge hack.
    static const bool copy = true;
  };

  std::ostream&
  operator<<(std::ostream& s, const UValue& v);

  /*----------.
  | Casters.  |
  `----------*/

  // For each Type, define an operator() that casts its UValue&
  // argument into Type.  We need partial specialization.

  template <typename Type>
  struct uvalue_caster
  {
  };

  // T -> UVar&  if T = UVar
  // T -> T      otherwise.
  template <typename T>
  struct uvar_ref_traits
  {
    typedef T type;
  };

  template <>
  struct uvar_ref_traits<UVar>
  {
    typedef UVar& type;
  };

  // Run the uvalue_caster<Type> on v.

  /* NM: Why exactly are we moving the const away?
   * I'm dropping it for UValue as it makes unnecessary copy.
   */

   template<typename T> struct uvalue_cast_return_type
   {
     typedef typename libport::traits::remove_reference<T>::type type;
   };

   template<> struct uvalue_cast_return_type<const UValue&>
   {
     typedef const UValue& type;
   };

  template <typename Type>
  typename uvar_ref_traits<typename uvalue_cast_return_type<Type>::type>::type
  uvalue_cast (UValue& v);

} // namespace urbi

#define URBI_STRUCT_CAST_FIELD(_, Cname, Field)                         \
  if (libport::mhas(dict, BOOST_PP_STRINGIZE(Field)))                   \
    uvalue_cast_bounce(res.Field, dict[BOOST_PP_STRINGIZE(Field)]);     \
  else                                                                  \
    GD_WARN("Serialized data for " #Cname "is missing field"            \
            BOOST_PP_STRINGIZE(Field));                                 \

#define URBI_STRUCT_BCAST_FIELD(_, Cname, Field)        \
  dict[BOOST_PP_STRINGIZE(Field)], c.Field;

#define URBI_REGISTER_STRUCT(Cname, ...)                                \
  namespace urbi                                                        \
  {                                                                     \
    template<>                                                          \
      struct uvalue_caster<Cname>                                       \
    {                                                                   \
      Cname operator()(UValue& v)                                       \
      {                                                                 \
        if (v.type != DATA_DICTIONARY)                                  \
          throw std::runtime_error("invalid cast to " #Cname "from "    \
                                   + string_cast(v));                   \
        UDictionary& dict = *v.dictionary;                              \
        Cname res;                                                      \
        LIBPORT_VAARGS_APPLY(URBI_STRUCT_CAST_FIELD, Cname, __VA_ARGS__); \
        return res;                                                     \
      }                                                                 \
    };                                                                  \
                                                                        \
    static UValue& operator,(UValue& v, const Cname &c)                 \
    {                                                                   \
      v = UDictionary();                                                \
      UDictionary& dict = *v.dictionary;                                \
      dict["$sn"] = BOOST_PP_STRINGIZE(Cname);                          \
      LIBPORT_VAARGS_APPLY(URBI_STRUCT_BCAST_FIELD, Cname, __VA_ARGS__); \
      return v;                                                         \
    }                                                                   \
  }

/** Packed data structure.
 *  This template class behaves exactly as a std::vector, except it gets
 *  serialized efficiently in a Binary, whereas std::vector is converted in
 *  an urbiscript list.
 */
template<typename T> class UPackedData: public std::vector<T>
{
public:
  UPackedData() {};
  UPackedData(const std::vector<T>& src): std::vector<T>(src) {};
  template<typename I> UPackedData(I begin, I end):std::vector<T>(begin, end){};
};

# include <urbi/uvalue.hxx>

# include <libport/warning-pop.hh>

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

/// \file urbi/uvalue.hh
#ifndef URBI_UVALUE_HH
# define URBI_UVALUE_HH

# include <libport/warning-push.hh>

# include <vector>

# include <libport/hash.hh>
# include <libport/preproc.hh>
# include <libport/traits.hh>
# include <libport/ufloat.h>

# include <urbi/fwd.hh>
# include <urbi/export.hh>
# include <urbi/ubinary.hh>

namespace urbi
{

  /*--------------------------.
  | Free standing functions.  |
  `--------------------------*/

  /// If a kernel version was associated to this stream, its value.
  URBI_SDK_API
  int& kernelMajor(std::ostream& o);

  /// Issue a syncline.
  /// \param srcdir   the path from here to the top-srcdir.
  ///                 Will be removed from file.
  /// \param file     __FILE__
  /// \param line     __LINE__
  URBI_SDK_API
  std::string
  syncline_push(const std::string& srcdir, std::string file, unsigned line);

#define SYNCLINE_PUSH()                                         \
  "//#push " BOOST_PP_STRINGIZE(__LINE__) " \"" __FILE__ "\"\n"

#define SYNCLINE_POP()                          \
  "//#pop\n"

#ifndef __SRCDIR__
# define __SRCDIR__ ""
#endif

#define SYNCLINE_WRAP(...)                                      \
  (::urbi::syncline_push(__SRCDIR__, __FILE__, __LINE__)        \
   + libport::format(__VA_ARGS__)                               \
   + "\n"                                                       \
   SYNCLINE_POP())

  // UValue and other related types

  /// Possible value types a UValue can contain.
  enum UDataType
  {
    DATA_BINARY = 0,
    DATA_DICTIONARY = 1,
    DATA_DOUBLE = 2,
    DATA_LIST = 3,
    // No longer supported. DATA_OBJECT = 4,
    DATA_STRING = 5,
    DATA_SLOTNAME = 6,
    DATA_VOID = 7,
  };

  /*--------.
  | UList.  |
  `--------*/

  /// Class storing URBI List type
  class URBI_SDK_API UList
  {
  public:
    UList();
    UList(const UList &b);
    ~UList();

    UList& operator=(const UList &b);

    // Assign a container to the UList
    template<typename T>
    UList& operator=(const T& container);

    UList& operator=(UVar& v);

    // Transform the UList to a container.
    template<typename T>
    T as();

    /// Iteration.
    typedef std::vector<UValue*> list_type;
    typedef list_type::iterator iterator;
    typedef list_type::const_iterator const_iterator;
    iterator begin();
    iterator end();
    const_iterator begin() const;
    const_iterator end() const;

    // Append an element to the end.
    template<typename T>
    UList&
    push_back(const T& v);

    void pop_back();

    UValue& front();

    UValue& operator[](size_t i);
    const UValue& operator[](size_t i) const;

    size_t size() const;
    void setOffset(size_t n);

    std::ostream& print(std::ostream& o) const;

    // The actual contents.
    list_type array;

  private:
    void clear();
    size_t offset;
    friend class UValue;
  };

  URBI_SDK_API
  std::ostream& operator<< (std::ostream& o, const UList& t);

  /*--------------.
  | UDictionary.  |
  `--------------*/

  typedef boost::unordered_map<std::string, UValue> UDictionary;

  URBI_SDK_API
  std::ostream& operator<<(std::ostream& s, const UDictionary& d);

  /*--------------.
  | UNamedValue.  |
  `--------------*/

  class URBI_SDK_API UNamedValue
  {
  public:
    UNamedValue(const std::string& n = "", UValue* v = 0);
    // Used on errors.
    static UNamedValue& error();
    std::string name;
    UValue* val;
  };

  /*---------.
  | UValue.  |
  `---------*/

  /** Container for a value that handles all types known to URBI.
   */
  class URBI_SDK_API UValue
  {
  public:
    UDataType type;

    ufloat val;                 ///< value if of type DATA_DOUBLE
    union
    {
      std::string* stringValue; ///< value if of type DATA_STRING
      UBinary* binary;          ///< value if of type DATA_BINARY
      UList* list;              ///< value if of type DATA_LIST
      UDictionary* dictionary;  ///< value if of type DATA_DICTIONARY
      void* storage;            ///< internal
    };

    UValue();
    UValue(const UValue&);

    ~UValue();

    UValue& operator=(const UValue&);
    /// Setter. If copy is false, binary data if present is not copied.
    /// This is dangerous, as the user must ensure that the source UValue
    /// lives longer than this one.
    UValue& set(const UValue&, bool copy=true);
    /// Delete content and reset type to void.
    void clear();
    /// A specific UValue used when we want to return an error.
    /// For instance, out-of-bound access returns this object.
    static UValue& error();

    /// We use an operator , that behaves like an assignment.  The
    /// only difference is when the rhs is void, in which case it is
    /// the regular comma which is used.  This allows to write "uval,
    /// expr" to mean "compute expr and assign its result to uval,
    /// unless expr is void".
    UValue& operator, (const UValue &b);

    /// Return a legible definition of UDataType
    const char* format_string() const;

#define CTOR_AND_ASSIGN_AND_COMMA(Type)           \
    explicit UValue(Type, bool copy=true);	  \
    UValue& operator=(Type);			  \
    UValue& operator,(Type rhs);

// Types convertibles to DATA_DOUBLE
#define URBI_DERIVED_NUMERIC_TYPES                     \
  LIBPORT_LIST(int, long, unsigned int, unsigned long, \
               unsigned long long, long long,)

#define URBI_NUMERIC_TYPES                                     \
  LIBPORT_LIST(ufloat, int, long, unsigned int, unsigned long, \
               unsigned long long, long long,)

// Types convertibles to DATA_STRING
#define URBI_STRING_TYPES \
  LIBPORT_LIST(const char*, const void*, const std::string&,)

#define URBI_MISC_TYPES                                          \
  LIBPORT_LIST(const UBinary&, const UList&, const UDictionary&, \
               const USound&, const UImage&,)

# ifndef SWIG
    LIBPORT_LIST_APPLY(CTOR_AND_ASSIGN_AND_COMMA, URBI_NUMERIC_TYPES)
    LIBPORT_LIST_APPLY(CTOR_AND_ASSIGN_AND_COMMA, URBI_STRING_TYPES)
    LIBPORT_LIST_APPLY(CTOR_AND_ASSIGN_AND_COMMA, URBI_MISC_TYPES)
# else
    // UFloats.
    CTOR_AND_ASSIGN_AND_COMMA(ufloat);
    CTOR_AND_ASSIGN_AND_COMMA(int);
    CTOR_AND_ASSIGN_AND_COMMA(long);
    CTOR_AND_ASSIGN_AND_COMMA(unsigned int);
    CTOR_AND_ASSIGN_AND_COMMA(unsigned long);
    CTOR_AND_ASSIGN_AND_COMMA(unsigned long long);
    CTOR_AND_ASSIGN_AND_COMMA(long long);

    // Strings.
    CTOR_AND_ASSIGN_AND_COMMA(const char*);
    CTOR_AND_ASSIGN_AND_COMMA(const void*);
    CTOR_AND_ASSIGN_AND_COMMA(const std::string&);

    // Others.
    CTOR_AND_ASSIGN_AND_COMMA(const UBinary&);
    CTOR_AND_ASSIGN_AND_COMMA(const UList&);
    CTOR_AND_ASSIGN_AND_COMMA(const UDictionary&);
    CTOR_AND_ASSIGN_AND_COMMA(const USound&);
    CTOR_AND_ASSIGN_AND_COMMA(const UImage&);
# endif

#undef CTOR_AND_ASSIGN_AND_COMMA

#define CAST_OPERATOR(Type) \
    operator Type() const;

# ifndef SWIG
    LIBPORT_LIST_APPLY(CAST_OPERATOR, URBI_NUMERIC_TYPES)
# else
    operator ufloat() const;
    operator std::string() const;
    operator int() const;
    operator unsigned int() const;
    operator long() const;
    operator unsigned long() const;
    operator bool() const;
# endif
#undef CAST_OPERATOR

#ifdef DOXYGEN
    // Doxygens needs a prototype for ufloat.
    operator ufloat() const;
#endif

    operator std::string() const;
    operator bool() const;

    /// Accessor. Gives us an implicit operator UBinary() const
    operator const UBinary&() const;

    /// Deep copy.
    operator UList() const;

    /// Deep copy.
    operator UDictionary() const;

    /// Shallow copy.
    operator UImage() const;

    /// Shallow copy.
    operator USound() const;

    /// This operator does nothing, but helps with the previous operator,.
    /// Indeed, when writing "uval, void_expr", the compiler complains
    /// about uval being evaluated for nothing.  Let's have it believe
    /// we're doing something...
    UValue& operator()();

    /// Parse an uvalue in current message+pos, returns pos of end of
    /// match -pos of error if error.
    int parse(const char* message,
	      int pos,
	      const binaries_type& bins,
	      binaries_type::const_iterator& binpos);

    /// Print itself on \c s, and return it.
    std::ostream& print(std::ostream& s) const;

    // Huge hack.
    static const bool copy = true;
  };

  std::ostream&
  operator<<(std::ostream& s, const UValue& v);

  /*----------.
  | Casters.  |
  `----------*/

  // For each Type, define an operator() that casts its UValue&
  // argument into Type.  We need partial specialization.

  template <typename Type>
  struct uvalue_caster
  {
  };

  // T -> UVar&  if T = UVar
  // T -> T      otherwise.
  template <typename T>
  struct uvar_ref_traits
  {
    typedef T type;
  };

  template <>
  struct uvar_ref_traits<UVar>
  {
    typedef UVar& type;
  };

  // Run the uvalue_caster<Type> on v.

  /* NM: Why exactly are we moving the const away?
   * I'm dropping it for UValue as it makes unnecessary copy.
   */

   template<typename T> struct uvalue_cast_return_type
   {
     typedef typename libport::traits::remove_reference<T>::type type;
   };

   template<> struct uvalue_cast_return_type<const UValue&>
   {
     typedef const UValue& type;
   };

  template <typename Type>
  typename uvar_ref_traits<typename uvalue_cast_return_type<Type>::type>::type
  uvalue_cast (UValue& v);

} // namespace urbi

#define URBI_STRUCT_CAST_FIELD(_, Cname, Field)                         \
  if (libport::mhas(dict, BOOST_PP_STRINGIZE(Field)))                   \
    uvalue_cast_bounce(res.Field, dict[BOOST_PP_STRINGIZE(Field)]);     \
  else                                                                  \
    GD_WARN("Serialized data for " #Cname "is missing field"            \
            BOOST_PP_STRINGIZE(Field));                                 \

#define URBI_STRUCT_BCAST_FIELD(_, Cname, Field)        \
  dict[BOOST_PP_STRINGIZE(Field)], c.Field;

#define URBI_REGISTER_STRUCT(Cname, ...)                                \
  namespace urbi                                                        \
  {                                                                     \
    template<>                                                          \
      struct uvalue_caster<Cname>                                       \
    {                                                                   \
      Cname operator()(UValue& v)                                       \
      {                                                                 \
        if (v.type != DATA_DICTIONARY)                                  \
          throw std::runtime_error("invalid cast to " #Cname "from "    \
                                   + string_cast(v));                   \
        UDictionary& dict = *v.dictionary;                              \
        Cname res;                                                      \
        LIBPORT_VAARGS_APPLY(URBI_STRUCT_CAST_FIELD, Cname, __VA_ARGS__); \
        return res;                                                     \
      }                                                                 \
    };                                                                  \
                                                                        \
    static UValue& operator,(UValue& v, const Cname &c)                 \
    {                                                                   \
      v = UDictionary();                                                \
      UDictionary& dict = *v.dictionary;                                \
      dict["$sn"] = BOOST_PP_STRINGIZE(Cname);                          \
      LIBPORT_VAARGS_APPLY(URBI_STRUCT_BCAST_FIELD, Cname, __VA_ARGS__); \
      return v;                                                         \
    }                                                                   \
  }

/** Packed data structure.
 *  This template class behaves exactly as a std::vector, except it gets
 *  serialized efficiently in a Binary, whereas std::vector is converted in
 *  an urbiscript list.
 */
template<typename T>
class UPackedData: public std::vector<T>
{
public:
  UPackedData()
    {};
  UPackedData(const std::vector<T>& src)
    : std::vector<T>(src)
    {};
  template<typename I>
  UPackedData(I begin, I end)
    : std::vector<T>(begin, end)
  {};
};

# include <urbi/uvalue.hxx>

# include <libport/warning-pop.hh>

#endif // ! URBI_UVALUE_HH
<|endoftext|>


<commit_before>#include <server/state.hpp>

State::State()
    : m_sequence(-1), m_timestamp(0.0)
{ }

State::State(int sequence, double timestamp)
    : m_sequence(sequence), m_timestamp(timestamp)
{ }

int State::GetSequence() const {
    return m_sequence;
}

double State::GetTimestamp() const {
    return m_timestamp;
}

std::ostream& operator<< (std::ostream& out, State const& s) {
    out << "Sequence: " << s.m_sequence << std::endl;
    out << "Timestamp: " << s.m_timestamp << std::endl;
    return out;
}

GameBoardState::GameBoardState(int sequence, double timestamp,
                                const char* board, int piece,
                                std::vector<int>* cleared)
    : State(sequence, timestamp), m_pBoard(board),
        m_piece(piece), m_pCleared(cleared)
{ }

GameBoardState::~GameBoardState() {
    if (m_pBoard != NULL) {
        delete[] m_pBoard;
        m_pBoard = NULL;
    }
    if (m_pCleared != NULL) {
        delete[] m_pCleared;
        m_pCleared = NULL;
    }
}

bool GameBoardState::ExecuteUpdates(GameState& game) const {
    GameBoard& board = game.GetBoard();
    if (m_pBoard != NULL && board.HasChanged(m_pBoard)) {
        board.Update(m_pBoard);
    }
    if (m_pCleared != NULL && m_pCleared->size() > 0) {
        game.SetLastClearedRows(*m_pCleared);
    }
    //std::cout << (*this) << std::endl;
    return false;
}

bool GameBoardState::ShouldTerminate() const {
    return false;
}

std::ostream& operator<< (std::ostream& out, GameBoardState const& s) {
    out << "My cleared: " << *(s.m_pCleared);
    return out;
}

GamePieceState::GamePieceState(int sequence, double timestamp,
                                Tetromino* tet, int number,
                                std::vector<Tetromino>* queue)
    : State(sequence, timestamp), m_pTet(tet),
        m_number(number), m_pQueue(queue)
{ }

GamePieceState::~GamePieceState() {
    if (m_pTet != NULL) {
        delete m_pTet;
        m_pTet = NULL;
    }
    if (m_pQueue != NULL) {
        delete m_pQueue;
        m_pQueue = NULL;
    }
}

bool GamePieceState::ExecuteUpdates(GameState& game) const {
    game.SetPieceInPlay(m_pTet);
    game.SetCurrentPieceNumber(m_number);
    //std::cout << (*this) << std::endl;
    return false;
}

bool GamePieceState::ShouldTerminate() const {
    return false;
}

std::ostream& operator<< (std::ostream& out, GamePieceState const& s) {
    out << "My tetronimo: ";
    if (s.m_pTet != NULL)
        out << s.m_pTet->GetType();
    else
        out << "NULL";
    out << ", ";
    out << "Queue: ";
    if (s.m_pQueue != NULL) {
        out << *(s.m_pQueue);
    }
    return out;
}

GameEnd::GameEnd(int sequence, double timestamp, bool won, int myScore)
    : State(sequence, timestamp), m_won(won), m_myScore(myScore)
{ }

bool GameEnd::ExecuteUpdates(GameState& game) const {
    GameBoard& board = game.GetBoard();
    board.ClearBoard();
    game.SetPieceInPlay(NULL);
    game.SetCurrentPieceNumber(-1);
    std::cout << (*this) << std::endl;
    return false;
}

bool GameEnd::ShouldTerminate() const {
    return false;
}

std::ostream& operator<< (std::ostream& out, GameEnd const& s) {
    if (s.m_won)
        out << "We won! ";
    else
        out << "Opponent won. ";
    out << "Score: " << s.m_myScore;
    return out;
}

bool MatchEnd::ExecuteUpdates(GameState&) const {
    std::cout << (*this) << std::endl;
    return true;
}

bool MatchEnd::ShouldTerminate() const {
    return true;
}

std::ostream& operator<< (std::ostream& out, MatchEnd const&) {
    out << "Game is over.";
    return out;
}

ErrorState::ErrorState(char const* errorMessage)
    : State(0, 0.0), m_errorMessage(errorMessage)
{ }

bool ErrorState::ExecuteUpdates(GameState&) const {
    std::cout << (*this) << std::endl;
    return false;
}

bool ErrorState::ShouldTerminate() const {
    return false;
}

std::ostream& operator<< (std::ostream& out, ErrorState const& s) {
    out << "ERROR: " << s.m_errorMessage;
    return out;
}

<commit_msg>Fixed invalid delete<commit_after>#include <server/state.hpp>

State::State()
    : m_sequence(-1), m_timestamp(0.0)
{ }

State::State(int sequence, double timestamp)
    : m_sequence(sequence), m_timestamp(timestamp)
{ }

int State::GetSequence() const {
    return m_sequence;
}

double State::GetTimestamp() const {
    return m_timestamp;
}

std::ostream& operator<< (std::ostream& out, State const& s) {
    out << "Sequence: " << s.m_sequence << std::endl;
    out << "Timestamp: " << s.m_timestamp << std::endl;
    return out;
}

GameBoardState::GameBoardState(int sequence, double timestamp,
                                const char* board, int piece,
                                std::vector<int>* cleared)
    : State(sequence, timestamp), m_pBoard(board),
        m_piece(piece), m_pCleared(cleared)
{ }

GameBoardState::~GameBoardState() {
    if (m_pBoard != NULL) {
        delete[] m_pBoard;
        m_pBoard = NULL;
    }
    if (m_pCleared != NULL) {
        delete m_pCleared;
        m_pCleared = NULL;
    }
}

bool GameBoardState::ExecuteUpdates(GameState& game) const {
    GameBoard& board = game.GetBoard();
    if (m_pBoard != NULL && board.HasChanged(m_pBoard)) {
        board.Update(m_pBoard);
    }
    if (m_pCleared != NULL && m_pCleared->size() > 0) {
        game.SetLastClearedRows(*m_pCleared);
    }
    //std::cout << (*this) << std::endl;
    return false;
}

bool GameBoardState::ShouldTerminate() const {
    return false;
}

std::ostream& operator<< (std::ostream& out, GameBoardState const& s) {
    out << "My cleared: " << *(s.m_pCleared);
    return out;
}

GamePieceState::GamePieceState(int sequence, double timestamp,
                                Tetromino* tet, int number,
                                std::vector<Tetromino>* queue)
    : State(sequence, timestamp), m_pTet(tet),
        m_number(number), m_pQueue(queue)
{ }

GamePieceState::~GamePieceState() {
    if (m_pTet != NULL) {
        delete m_pTet;
        m_pTet = NULL;
    }
    if (m_pQueue != NULL) {
        delete m_pQueue;
        m_pQueue = NULL;
    }
}

bool GamePieceState::ExecuteUpdates(GameState& game) const {
    game.SetPieceInPlay(m_pTet);
    game.SetCurrentPieceNumber(m_number);
    //std::cout << (*this) << std::endl;
    return false;
}

bool GamePieceState::ShouldTerminate() const {
    return false;
}

std::ostream& operator<< (std::ostream& out, GamePieceState const& s) {
    out << "My tetronimo: ";
    if (s.m_pTet != NULL)
        out << s.m_pTet->GetType();
    else
        out << "NULL";
    out << ", ";
    out << "Queue: ";
    if (s.m_pQueue != NULL) {
        out << *(s.m_pQueue);
    }
    return out;
}

GameEnd::GameEnd(int sequence, double timestamp, bool won, int myScore)
    : State(sequence, timestamp), m_won(won), m_myScore(myScore)
{ }

bool GameEnd::ExecuteUpdates(GameState& game) const {
    GameBoard& board = game.GetBoard();
    board.ClearBoard();
    game.SetPieceInPlay(NULL);
    game.SetCurrentPieceNumber(-1);
    std::cout << (*this) << std::endl;
    return false;
}

bool GameEnd::ShouldTerminate() const {
    return false;
}

std::ostream& operator<< (std::ostream& out, GameEnd const& s) {
    if (s.m_won)
        out << "We won! ";
    else
        out << "Opponent won. ";
    out << "Score: " << s.m_myScore;
    return out;
}

bool MatchEnd::ExecuteUpdates(GameState&) const {
    std::cout << (*this) << std::endl;
    return true;
}

bool MatchEnd::ShouldTerminate() const {
    return true;
}

std::ostream& operator<< (std::ostream& out, MatchEnd const&) {
    out << "Game is over.";
    return out;
}

ErrorState::ErrorState(char const* errorMessage)
    : State(0, 0.0), m_errorMessage(errorMessage)
{ }

bool ErrorState::ExecuteUpdates(GameState&) const {
    std::cout << (*this) << std::endl;
    return false;
}

bool ErrorState::ShouldTerminate() const {
    return false;
}

std::ostream& operator<< (std::ostream& out, ErrorState const& s) {
    out << "ERROR: " << s.m_errorMessage;
    return out;
}

<|endoftext|>


<commit_before>/*
             LUFA Library
     Copyright (C) Dean Camera, 2017.

  dean [at] fourwalledcubicle [dot] com
           www.lufa-lib.org
*/

/*
  Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com)

  Permission to use, copy, modify, distribute, and sell this
  software and its documentation for any purpose is hereby granted
  without fee, provided that the above copyright notice appear in
  all copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting
  documentation, and that the name of the author not be used in
  advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.

  The author disclaims all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

/** \file
 *
 *  Main source file for the HID class bootloader. This file contains the complete bootloader logic.
 */

#include "BootloaderHID.h"
#include "core/src/HAL/avr/PinManipulation.h"
#include "core/src/general/BitManipulation.h"
#include <util/crc16.h>
#include "board/common/constants/LEDs.h"
#include "board/avr/variants/Common.h"
#include "board/common/constants/Reboot.h"
#include "pins/Pins.h"
#include "board/common/indicators/Variables.h"
#include "board/Board.h"
#include "board/common/uart/Variables.h"
#include "interface/midi/Constants.h"

#ifdef CRC_CHECK
///
/// \brief Calculates CRC of entire flash.
/// \return True if CRC is valid, that is, if it matches CRC written in last flash address.
///
bool appCRCvalid()
{
    uint16_t crc = 0x0000;
    int16_t lastAddress = pgm_read_word_near(APP_LENGTH_LOCATION);

    for (int i=0; i<lastAddress; i++)
    {
        crc = _crc_xmodem_update(crc, pgm_read_byte_near(i));
    }

    return (crc == pgm_read_word_near(lastAddress));
}
#endif

///
/// Flag to indicate if the bootloader should be running, or should exit and allow the application code to run
/// via a soft reset. When cleared, the bootloader will abort, the USB interface will shut down and the application
/// started via a forced watchdog reset.
///
static bool RunBootloader = true;

//implementation of external variables used so that UART module can be compiled
//variables are unused in bootloader
volatile bool UARTreceived, UARTsent;

///
/// \brief Checks if application should be run.
/// This function performs two checks: hardware and software bootloader entry.
/// Hardware bootloader entry is possible if the specific board has defined button
/// which should be pressed before the MCU is turned on. If it is, bootloader is
/// entered.
/// Software bootloader entry is possible by writing special value to special EEPROM
/// address before the application is rebooted.
/// \returns True if application should be run, false if bootloader should be run.
///
bool checkApplicationRun()
{
    bool jumpToApplication = false;

    //add some delay before reading the pins to avoid incorrect state detection
    _delay_ms(100);

    #if defined(BOARD_KODAMA) || defined(BOARD_TANNIN)
    //these boards use input shift registers
    //read 8 inputs and then read only specific input used as an
    //hardware bootloader entry button
    uint16_t dInData = 0;
    setLow(SR_DIN_CLK_PORT, SR_DIN_CLK_PIN);
    setLow(SR_DIN_LATCH_PORT, SR_DIN_LATCH_PIN);
    _NOP();
    _NOP();

    setHigh(SR_DIN_LATCH_PORT, SR_DIN_LATCH_PIN);

    #ifdef BOARD_KODAMA
    //this board has two shift registers - 16 inputs in total
    for (int i=0; i<16; i++)
    #elif defined(BOARD_TANNIN)
    //single register
    for (int i=0; i<8; i++)
    #endif
    {
        setLow(SR_DIN_CLK_PORT, SR_DIN_CLK_PIN);
        _NOP();
        BIT_WRITE(dInData, i, !readPin(SR_DIN_DATA_PORT, SR_DIN_DATA_PIN));
        setHigh(SR_DIN_CLK_PORT, SR_DIN_CLK_PIN);
    }

    bool hardwareTrigger = BIT_READ(dInData, BTLDR_BUTTON_INDEX);
    #else
    #ifdef BTLDR_BUTTON_PORT
    bool hardwareTrigger = !readPin(BTLDR_BUTTON_PORT, BTLDR_BUTTON_PIN);
    #else
    //no hardware entry possible in this case
    bool hardwareTrigger = false;
    #endif
    #endif

    //check if user wants to enter bootloader
    bool softwareTrigger = eeprom_read_byte((uint8_t*)REBOOT_VALUE_EEPROM_LOCATION) == BTLDR_REBOOT_VALUE;

    //reset value in eeprom after reading
    eeprom_write_byte((uint8_t*)REBOOT_VALUE_EEPROM_LOCATION, APP_REBOOT_VALUE);

    //jump to app only if both software and hardware triggers aren't activated
    if (!hardwareTrigger && !softwareTrigger)
        jumpToApplication = true;

    //don't run the user application if the reset vector is blank (no app loaded)
    bool applicationValid = (pgm_read_word_near(0) != 0xFFFF);

    return (jumpToApplication && applicationValid);
}

///
/// \brief Run user application.
///
void runApplication()
{
    //run app
    ((void (*)(void))0x0000)();
}

///
/// \brief Main program entry point.
/// This routine configures the hardware required by the bootloader, then continuously
/// runs the bootloader processing routine until instructed to soft-exit.
///
int main(void)
{
    //clear reset source
    MCUSR &= ~(1 << EXTRF);

    //disable watchdog
    MCUSR &= ~(1 << WDRF);
    wdt_disable();

    initPins();

    if (checkApplicationRun())
        runApplication();

    //setup hardware required for the bootloader
    setupHardware();

    //enable global interrupts so that the USB stack can function
    GlobalInterruptEnable();

    while (RunBootloader)
    {
        #ifdef USB_SUPPORTED
        USB_USBTask();
        #else
        if (RingBuffer_GetCount(&rxBuffer[UART_USB_LINK_CHANNEL]) > 2)
            EVENT_UART_Device_ControlRequest();
        #endif
    }

    #ifdef USB_SUPPORTED
    //disconnect from the host - USB interface will be reset later along with the AVR
    USB_Detach();
    #endif

    //enable the watchdog and force a timeout to reset the AVR
    wdt_enable(WDTO_250MS);
    while(1);
}

///
/// \brief Configures all hardware required for the bootloader.
///
static void setupHardware(void)
{
    //disable watchdog if enabled by bootloader/fuses
    MCUSR &= ~(1 << WDRF);
    wdt_disable();

    //disable clock division
    clock_prescale_set(clock_div_1);

    //relocate the interrupt vector table to the bootloader section
    MCUCR = (1<<IVCE);
    MCUCR = (1<<IVSEL);

    #ifdef USB_SUPPORTED
    //initialize USB subsystem
    USB_Init();
    #endif

    #if defined(BOARD_A_xu2) || !defined(USB_SUPPORTED)
    Board::initUART(UART_BAUDRATE_MIDI_OD, UART_USB_LINK_CHANNEL);

    #ifndef USB_SUPPORTED
    // make sure USB link goes to bootloader mode as well
    RingBuffer_Insert(&txBuffer[UART_USB_LINK_CHANNEL], OD_FORMAT_INT_DATA_START);
    RingBuffer_Insert(&txBuffer[UART_USB_LINK_CHANNEL], cmdBtldrReboot);
    RingBuffer_Insert(&txBuffer[UART_USB_LINK_CHANNEL], 0x00);
    RingBuffer_Insert(&txBuffer[UART_USB_LINK_CHANNEL], 0x00);
    RingBuffer_Insert(&txBuffer[UART_USB_LINK_CHANNEL], 0x00);
    RingBuffer_Insert(&txBuffer[UART_USB_LINK_CHANNEL], 0x00);
    Board::uartTransmitStart(UART_USB_LINK_CHANNEL);
    #endif
    #endif
}

///
/// \brief Initializes all pins needed in bootloader mode.
///
static void initPins()
{
    //indicate that we're in bootloader mode by turning on specific leds
    //if the board uses indicator leds for midi traffic, turn them both on
    #ifdef BOARD_KODAMA
    setLow(SR_OUT_LATCH_PORT, SR_OUT_LATCH_PIN);

    for (int i=0; i<16; i++)
    {
        EXT_LED_ON(SR_OUT_DATA_PORT, SR_OUT_DATA_PIN);
        pulseHighToLow(SR_OUT_CLK_PORT, SR_OUT_CLK_PIN);
    }

    setHigh(SR_OUT_LATCH_PORT, SR_OUT_LATCH_PIN);
    #elif defined(BOARD_A_MEGA)
    //make sure internal led is turned off
    setOutput(PORTB, 7);
    setLow(PORTB, 7);
    #elif defined (LED_INDICATORS)
    setOutput(LED_IN_PORT, LED_IN_PIN);
    setOutput(LED_OUT_PORT, LED_OUT_PIN);
    INT_LED_ON(LED_IN_PORT, LED_IN_PIN);
    INT_LED_ON(LED_OUT_PORT, LED_OUT_PIN);
    #endif

    //configure bootloader entry pins
    #if defined(BOARD_TANNIN) || defined(BOARD_KODAMA)
    setInput(SR_DIN_DATA_PORT, SR_DIN_DATA_PIN);
    setOutput(SR_DIN_CLK_PORT, SR_DIN_CLK_PIN);
    setOutput(SR_DIN_LATCH_PORT, SR_DIN_LATCH_PIN);
    #ifdef BOARD_TANNIN
    //select column 6 in button matrix
    setOutput(DEC_DM_A0_PORT, DEC_DM_A0_PIN);
    setOutput(DEC_DM_A1_PORT, DEC_DM_A1_PIN);
    setOutput(DEC_DM_A2_PORT, DEC_DM_A2_PIN);
    setHigh(DEC_DM_A0_PORT, DEC_DM_A0_PIN);
    setLow(DEC_DM_A1_PORT, DEC_DM_A1_PIN);
    setHigh(DEC_DM_A2_PORT, DEC_DM_A2_PIN);
    #endif
    #else
    #ifdef BTLDR_BUTTON_PORT
    setInput(BTLDR_BUTTON_PORT, BTLDR_BUTTON_PIN);
    setHigh(BTLDR_BUTTON_PORT, BTLDR_BUTTON_PIN);
    #endif
    #endif
}

#ifdef USB_SUPPORTED
///
/// \brief Event handler for the USB_ConfigurationChanged event.
/// This configures the device's endpoints ready to relay data to and from the attached USB host.
///
void EVENT_USB_Device_ConfigurationChanged(void)
{
    //setup HID Report Endpoint
    Endpoint_ConfigureEndpoint(HID_IN_EPADDR, EP_TYPE_INTERRUPT, HID_IN_EPSIZE, 1);
}
#endif

///
/// \brief Event handler for the USB_ControlRequest event.
/// This is used to catch and process control requests sent to the device
/// from the USB host before passing along unhandled control requests to the
/// library for processing internally.
///
#ifdef USB_SUPPORTED
void EVENT_USB_Device_ControlRequest(void)
#else
void EVENT_UART_Device_ControlRequest(void)
#endif
{
    uint16_t PageAddress;

    #if !defined(USB_SUPPORTED)
    uint8_t temp = 0;
    #endif

    #ifdef USB_SUPPORTED
    //ignore any requests that aren't directed to the HID interface
    if ((USB_ControlRequest.bmRequestType & (CONTROL_REQTYPE_TYPE | CONTROL_REQTYPE_RECIPIENT)) !=
        (REQTYPE_CLASS | REQREC_INTERFACE))
    {
        return;
    }
    #else
    //target MCU
    //page address is two bytes long
    board.uartRead(UART_USB_LINK_CHANNEL, temp);
    PageAddress = temp;
    PageAddress <<= 8;
    board.uartRead(UART_USB_LINK_CHANNEL, temp);
    PageAddress |= (uint16_t)temp;
    #endif

    #ifdef USB_SUPPORTED
    //process HID specific control requests
    switch (USB_ControlRequest.bRequest)
    {
        case HID_REQ_SetReport:
        Endpoint_ClearSETUP();

        //wait until the command has been sent by the host
        while (!(Endpoint_IsOUTReceived()));
        //read in the write destination address
        PageAddress = Endpoint_Read_16_LE();
    #endif

        #ifdef BOARD_A_xu2
        //send the page info to target MCU
        //msb first
        board.uartWrite(UART_USB_LINK_CHANNEL, (PageAddress >> (uint16_t)8) & (uint16_t)0xFF);
        board.uartWrite(UART_USB_LINK_CHANNEL, (PageAddress >> (uint16_t)0) & (uint16_t)0xFF);
        #endif

        //check if the command is a program page command, or a start application command
        if (PageAddress == COMMAND_STARTAPPLICATION)
        {
            #ifdef BOARD_A_MEGA
            while(1)
            {
                setHigh(PORTB, 7);
                _delay_ms(500);
                setLow(PORTB, 7);
                _delay_ms(500);
            }
            #endif

            #if !defined(USB_SUPPORTED) || defined(BOARD_A_xu2)
            //wait until TX buffer is empty
            while (RingBuffer_GetCount(&txBuffer[UART_USB_LINK_CHANNEL]));
            runApplication();
            #else
            RunBootloader = false;
            #endif
        }
        else if (PageAddress < BOOT_START_ADDR)
        {
            #ifndef BOARD_A_xu2
            //erase the given FLASH page, ready to be programmed
            boot_page_erase(PageAddress);
            boot_spm_busy_wait();
            #endif

            //write each of the FLASH page's bytes in sequence
            for (int PageWord=0; PageWord<SPM_PAGESIZE/2; PageWord++)
            {
                #ifdef USB_SUPPORTED
                //check if endpoint is empty - if so clear it and wait until ready for next packet
                if (!(Endpoint_BytesInEndpoint()))
                {
                    Endpoint_ClearOUT();
                    while (!(Endpoint_IsOUTReceived()));
                }

                #ifndef BOARD_A_xu2
                //write the next data word to the FLASH page
                boot_page_fill(PageAddress + ((uint16_t)PageWord << 1), Endpoint_Read_16_LE());
                #else
                uint16_t dataWord = Endpoint_Read_16_LE();
                board.uartWrite(UART_USB_LINK_CHANNEL, (dataWord >> (uint16_t)8) & (uint16_t)0xFF);
                board.uartWrite(UART_USB_LINK_CHANNEL, (dataWord >> (uint16_t)0) & (uint16_t)0xFF);
                #endif
                #else
                //no usb
                board.uartRead(UART_USB_LINK_CHANNEL, temp);
                uint16_t dataWord = (uint16_t)temp << (uint16_t)8;
                board.uartRead(UART_USB_LINK_CHANNEL, temp);
                dataWord |= (uint16_t)temp;
                //write the next data word to the FLASH page
                boot_page_fill(PageAddress + ((uint16_t)PageWord << 1), dataWord);
                #endif
            }

            #ifndef BOARD_A_xu2
            //write the filled FLASH page to memory
            boot_page_write(PageAddress);
            boot_spm_busy_wait();

            //re-enable RWW section
            boot_rww_enable();
            #endif
        }

        #ifdef USB_SUPPORTED
        Endpoint_ClearOUT();
        Endpoint_ClearStatusStage();
        break;
        #endif
    #ifdef USB_SUPPORTED
    }
    #endif
}<commit_msg>ifdefs, misc<commit_after>/*
             LUFA Library
     Copyright (C) Dean Camera, 2017.

  dean [at] fourwalledcubicle [dot] com
           www.lufa-lib.org
*/

/*
  Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com)

  Permission to use, copy, modify, distribute, and sell this
  software and its documentation for any purpose is hereby granted
  without fee, provided that the above copyright notice appear in
  all copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting
  documentation, and that the name of the author not be used in
  advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.

  The author disclaims all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

/** \file
 *
 *  Main source file for the HID class bootloader. This file contains the complete bootloader logic.
 */

#include "BootloaderHID.h"
#include "core/src/HAL/avr/PinManipulation.h"
#include "core/src/general/BitManipulation.h"
#include <util/crc16.h>
#include "board/common/constants/LEDs.h"
#include "board/avr/variants/Common.h"
#include "board/common/constants/Reboot.h"
#include "pins/Pins.h"
#include "board/common/indicators/Variables.h"
#include "board/Board.h"
#include "board/common/uart/Variables.h"
#include "interface/midi/Constants.h"

#ifdef CRC_CHECK
///
/// \brief Calculates CRC of entire flash.
/// \return True if CRC is valid, that is, if it matches CRC written in last flash address.
///
bool appCRCvalid()
{
    uint16_t crc = 0x0000;
    int16_t lastAddress = pgm_read_word_near(APP_LENGTH_LOCATION);

    for (int i=0; i<lastAddress; i++)
    {
        crc = _crc_xmodem_update(crc, pgm_read_byte_near(i));
    }

    return (crc == pgm_read_word_near(lastAddress));
}
#endif

///
/// Flag to indicate if the bootloader should be running, or should exit and allow the application code to run
/// via a soft reset. When cleared, the bootloader will abort, the USB interface will shut down and the application
/// started via a forced watchdog reset.
///
static bool RunBootloader = true;

//implementation of external variables used so that UART module can be compiled
//variables are unused in bootloader
volatile bool UARTreceived, UARTsent;

///
/// \brief Checks if application should be run.
/// This function performs two checks: hardware and software bootloader entry.
/// Hardware bootloader entry is possible if the specific board has defined button
/// which should be pressed before the MCU is turned on. If it is, bootloader is
/// entered.
/// Software bootloader entry is possible by writing special value to special EEPROM
/// address before the application is rebooted.
/// \returns True if application should be run, false if bootloader should be run.
///
bool checkApplicationRun()
{
    bool jumpToApplication = false;

    //add some delay before reading the pins to avoid incorrect state detection
    _delay_ms(100);

    #if defined(BOARD_KODAMA) || defined(BOARD_TANNIN)
    //these boards use input shift registers
    //read 8 inputs and then read only specific input used as an
    //hardware bootloader entry button
    uint16_t dInData = 0;
    setLow(SR_DIN_CLK_PORT, SR_DIN_CLK_PIN);
    setLow(SR_DIN_LATCH_PORT, SR_DIN_LATCH_PIN);
    _NOP();
    _NOP();

    setHigh(SR_DIN_LATCH_PORT, SR_DIN_LATCH_PIN);

    #ifdef BOARD_KODAMA
    //this board has two shift registers - 16 inputs in total
    for (int i=0; i<16; i++)
    #elif defined(BOARD_TANNIN)
    //single register
    for (int i=0; i<8; i++)
    #endif
    {
        setLow(SR_DIN_CLK_PORT, SR_DIN_CLK_PIN);
        _NOP();
        BIT_WRITE(dInData, i, !readPin(SR_DIN_DATA_PORT, SR_DIN_DATA_PIN));
        setHigh(SR_DIN_CLK_PORT, SR_DIN_CLK_PIN);
    }

    bool hardwareTrigger = BIT_READ(dInData, BTLDR_BUTTON_INDEX);
    #else
    #ifdef BTLDR_BUTTON_PORT
    bool hardwareTrigger = !readPin(BTLDR_BUTTON_PORT, BTLDR_BUTTON_PIN);
    #else
    //no hardware entry possible in this case
    bool hardwareTrigger = false;
    #endif
    #endif

    //check if user wants to enter bootloader
    bool softwareTrigger = eeprom_read_byte((uint8_t*)REBOOT_VALUE_EEPROM_LOCATION) == BTLDR_REBOOT_VALUE;

    //reset value in eeprom after reading
    eeprom_write_byte((uint8_t*)REBOOT_VALUE_EEPROM_LOCATION, APP_REBOOT_VALUE);

    //jump to app only if both software and hardware triggers aren't activated
    if (!hardwareTrigger && !softwareTrigger)
        jumpToApplication = true;

    //don't run the user application if the reset vector is blank (no app loaded)
    bool applicationValid = (pgm_read_word_near(0) != 0xFFFF);

    return (jumpToApplication && applicationValid);
}

///
/// \brief Run user application.
///
void runApplication()
{
    //run app
    ((void (*)(void))0x0000)();
}

///
/// \brief Main program entry point.
/// This routine configures the hardware required by the bootloader, then continuously
/// runs the bootloader processing routine until instructed to soft-exit.
///
int main(void)
{
    //clear reset source
    MCUSR &= ~(1 << EXTRF);

    //disable watchdog
    MCUSR &= ~(1 << WDRF);
    wdt_disable();

    initPins();

    if (checkApplicationRun())
        runApplication();

    //setup hardware required for the bootloader
    setupHardware();

    //enable global interrupts so that the USB stack can function
    GlobalInterruptEnable();

    while (RunBootloader)
    {
        #ifdef USB_SUPPORTED
        USB_USBTask();
        #else
        if (RingBuffer_GetCount(&rxBuffer[UART_USB_LINK_CHANNEL]) > 2)
            EVENT_UART_Device_ControlRequest();
        #endif
    }

    #ifdef USB_SUPPORTED
    //disconnect from the host - USB interface will be reset later along with the AVR
    USB_Detach();
    #endif

    //enable the watchdog and force a timeout to reset the AVR
    wdt_enable(WDTO_250MS);
    while(1);
}

///
/// \brief Configures all hardware required for the bootloader.
///
static void setupHardware(void)
{
    //disable watchdog if enabled by bootloader/fuses
    MCUSR &= ~(1 << WDRF);
    wdt_disable();

    //disable clock division
    clock_prescale_set(clock_div_1);

    //relocate the interrupt vector table to the bootloader section
    MCUCR = (1<<IVCE);
    MCUCR = (1<<IVSEL);

    #ifdef USB_SUPPORTED
    //initialize USB subsystem
    USB_Init();
    #endif

    #if defined(BOARD_A_xu2) || !defined(USB_SUPPORTED)
    Board::initUART(UART_BAUDRATE_MIDI_OD, UART_USB_LINK_CHANNEL);

    #ifndef USB_SUPPORTED
    // make sure USB link goes to bootloader mode as well
    Board::uartWrite(UART_USB_LINK_CHANNEL, OD_FORMAT_INT_DATA_START);
    Board::uartWrite(UART_USB_LINK_CHANNEL, cmdBtldrReboot);
    Board::uartWrite(UART_USB_LINK_CHANNEL, 0x00);
    Board::uartWrite(UART_USB_LINK_CHANNEL, 0x00);
    Board::uartWrite(UART_USB_LINK_CHANNEL, 0x00);
    Board::uartWrite(UART_USB_LINK_CHANNEL, 0x00);
    #endif
    #endif
}

///
/// \brief Initializes all pins needed in bootloader mode.
///
static void initPins()
{
    //indicate that we're in bootloader mode by turning on specific leds
    //if the board uses indicator leds for midi traffic, turn them both on
    #ifdef BOARD_KODAMA
    setLow(SR_OUT_LATCH_PORT, SR_OUT_LATCH_PIN);

    for (int i=0; i<16; i++)
    {
        EXT_LED_ON(SR_OUT_DATA_PORT, SR_OUT_DATA_PIN);
        pulseHighToLow(SR_OUT_CLK_PORT, SR_OUT_CLK_PIN);
    }

    setHigh(SR_OUT_LATCH_PORT, SR_OUT_LATCH_PIN);
    #elif defined(BOARD_A_MEGA)
    //make sure internal led is turned off
    setOutput(PORTB, 7);
    setLow(PORTB, 7);
    #elif defined (LED_INDICATORS)
    setOutput(LED_IN_PORT, LED_IN_PIN);
    setOutput(LED_OUT_PORT, LED_OUT_PIN);
    INT_LED_ON(LED_IN_PORT, LED_IN_PIN);
    INT_LED_ON(LED_OUT_PORT, LED_OUT_PIN);
    #endif

    //configure bootloader entry pins
    #if defined(BOARD_TANNIN) || defined(BOARD_KODAMA)
    setInput(SR_DIN_DATA_PORT, SR_DIN_DATA_PIN);
    setOutput(SR_DIN_CLK_PORT, SR_DIN_CLK_PIN);
    setOutput(SR_DIN_LATCH_PORT, SR_DIN_LATCH_PIN);
    #ifdef BOARD_TANNIN
    //select column 6 in button matrix
    setOutput(DEC_DM_A0_PORT, DEC_DM_A0_PIN);
    setOutput(DEC_DM_A1_PORT, DEC_DM_A1_PIN);
    setOutput(DEC_DM_A2_PORT, DEC_DM_A2_PIN);
    setHigh(DEC_DM_A0_PORT, DEC_DM_A0_PIN);
    setLow(DEC_DM_A1_PORT, DEC_DM_A1_PIN);
    setHigh(DEC_DM_A2_PORT, DEC_DM_A2_PIN);
    #endif
    #else
    #ifdef BTLDR_BUTTON_PORT
    setInput(BTLDR_BUTTON_PORT, BTLDR_BUTTON_PIN);
    setHigh(BTLDR_BUTTON_PORT, BTLDR_BUTTON_PIN);
    #endif
    #endif
}

#ifdef USB_SUPPORTED
///
/// \brief Event handler for the USB_ConfigurationChanged event.
/// This configures the device's endpoints ready to relay data to and from the attached USB host.
///
void EVENT_USB_Device_ConfigurationChanged(void)
{
    //setup HID Report Endpoint
    Endpoint_ConfigureEndpoint(HID_IN_EPADDR, EP_TYPE_INTERRUPT, HID_IN_EPSIZE, 1);
}
#endif

///
/// \brief Event handler for the USB_ControlRequest event.
/// This is used to catch and process control requests sent to the device
/// from the USB host before passing along unhandled control requests to the
/// library for processing internally.
///
#ifdef USB_SUPPORTED
void EVENT_USB_Device_ControlRequest(void)
#else
void EVENT_UART_Device_ControlRequest(void)
#endif
{
    uint16_t PageAddress;

    #if !defined(USB_SUPPORTED)
    uint8_t temp = 0;
    #endif

    #ifdef USB_SUPPORTED
    //ignore any requests that aren't directed to the HID interface
    if ((USB_ControlRequest.bmRequestType & (CONTROL_REQTYPE_TYPE | CONTROL_REQTYPE_RECIPIENT)) !=
        (REQTYPE_CLASS | REQREC_INTERFACE))
    {
        return;
    }
    #else
    //target MCU
    //page address is two bytes long
    Board::uartRead(UART_USB_LINK_CHANNEL, temp);
    PageAddress = temp;
    PageAddress <<= 8;
    Board::uartRead(UART_USB_LINK_CHANNEL, temp);
    PageAddress |= (uint16_t)temp;
    #endif

    #ifdef USB_SUPPORTED
    //process HID specific control requests
    switch (USB_ControlRequest.bRequest)
    {
        case HID_REQ_SetReport:
        Endpoint_ClearSETUP();

        //wait until the command has been sent by the host
        while (!(Endpoint_IsOUTReceived()));
        //read in the write destination address
        PageAddress = Endpoint_Read_16_LE();
    #endif

        #ifdef BOARD_A_xu2
        //send the page info to target MCU
        //msb first
        Board::uartWrite(UART_USB_LINK_CHANNEL, (PageAddress >> (uint16_t)8) & (uint16_t)0xFF);
        Board::uartWrite(UART_USB_LINK_CHANNEL, (PageAddress >> (uint16_t)0) & (uint16_t)0xFF);
        #endif

        //check if the command is a program page command, or a start application command
        if (PageAddress == COMMAND_STARTAPPLICATION)
        {
            #ifdef BOARD_A_MEGA
            while(1)
            {
                setHigh(PORTB, 7);
                _delay_ms(500);
                setLow(PORTB, 7);
                _delay_ms(500);
            }
            #endif

            #if defined(BOARD_A_xu2)
            //wait until TX buffer is empty
            while (RingBuffer_GetCount(&txBuffer[UART_USB_LINK_CHANNEL]));
            #endif
            RunBootloader = false;
        }
        else if (PageAddress < BOOT_START_ADDR)
        {
            #ifndef BOARD_A_xu2
            //erase the given FLASH page, ready to be programmed
            boot_page_erase(PageAddress);
            boot_spm_busy_wait();
            #endif

            //write each of the FLASH page's bytes in sequence
            for (int PageWord=0; PageWord<SPM_PAGESIZE/2; PageWord++)
            {
                #ifdef USB_SUPPORTED
                //check if endpoint is empty - if so clear it and wait until ready for next packet
                if (!(Endpoint_BytesInEndpoint()))
                {
                    Endpoint_ClearOUT();
                    while (!(Endpoint_IsOUTReceived()));
                }

                #ifndef BOARD_A_xu2
                //write the next data word to the FLASH page
                boot_page_fill(PageAddress + ((uint16_t)PageWord << 1), Endpoint_Read_16_LE());
                #else
                uint16_t dataWord = Endpoint_Read_16_LE();
                Board::uartWrite(UART_USB_LINK_CHANNEL, (dataWord >> (uint16_t)8) & (uint16_t)0xFF);
                Board::uartWrite(UART_USB_LINK_CHANNEL, (dataWord >> (uint16_t)0) & (uint16_t)0xFF);
                #endif
                #else
                //no usb
                Board::uartRead(UART_USB_LINK_CHANNEL, temp);
                uint16_t dataWord = (uint16_t)temp << (uint16_t)8;
                Board::uartRead(UART_USB_LINK_CHANNEL, temp);
                dataWord |= (uint16_t)temp;
                //write the next data word to the FLASH page
                boot_page_fill(PageAddress + ((uint16_t)PageWord << 1), dataWord);
                #endif
            }

            #ifndef BOARD_A_xu2
            //write the filled FLASH page to memory
            boot_page_write(PageAddress);
            boot_spm_busy_wait();

            //re-enable RWW section
            boot_rww_enable();
            #endif
        }

        #ifdef USB_SUPPORTED
        Endpoint_ClearOUT();
        Endpoint_ClearStatusStage();
        break;
        #endif
    #ifdef USB_SUPPORTED
    }
    #endif
}<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright (C) 2015 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "auth/service.hh"
#include "exceptions/exceptions.hh"
#include "unimplemented.hh"
#include "timestamp.hh"
#include "db_clock.hh"
#include "database_fwd.hh"
#include "auth/authenticated_user.hh"
#include "auth/authenticator.hh"
#include "auth/permission.hh"
#include "tracing/tracing.hh"
#include "tracing/trace_state.hh"

namespace auth {
class resource;
}

namespace service {

/**
 * State related to a client connection.
 */
class client_state {
public:
    enum class auth_state : uint8_t {
        UNINITIALIZED, AUTHENTICATION, READY
    };

private:
    sstring _keyspace;
    tracing::trace_state_ptr _trace_state_ptr;
#if 0
    private static final Logger logger = LoggerFactory.getLogger(ClientState.class);
    public static final SemanticVersion DEFAULT_CQL_VERSION = org.apache.cassandra.cql3.QueryProcessor.CQL_VERSION;

    private static final Set<IResource> READABLE_SYSTEM_RESOURCES = new HashSet<>();
    private static final Set<IResource> PROTECTED_AUTH_RESOURCES = new HashSet<>();

    static
    {
        // We want these system cfs to be always readable to authenticated users since many tools rely on them
        // (nodetool, cqlsh, bulkloader, etc.)
        for (String cf : Iterables.concat(Arrays.asList(SystemKeyspace.LOCAL, SystemKeyspace.PEERS), LegacySchemaTables.ALL))
            READABLE_SYSTEM_RESOURCES.add(DataResource.columnFamily(SystemKeyspace.NAME, cf));

        PROTECTED_AUTH_RESOURCES.addAll(DatabaseDescriptor.getAuthenticator().protectedResources());
        PROTECTED_AUTH_RESOURCES.addAll(DatabaseDescriptor.getAuthorizer().protectedResources());
    }

    // Current user for the session
    private volatile AuthenticatedUser user;
    private volatile String keyspace;
#endif
    ::shared_ptr<auth::authenticated_user> _user;

    auth_state _auth_state = auth_state::UNINITIALIZED;

    // isInternal is used to mark ClientState as used by some internal component
    // that should have an ability to modify system keyspace.
    bool _is_internal;
    bool _is_thrift;

    // The biggest timestamp that was returned by getTimestamp/assigned to a query
    static thread_local api::timestamp_type _last_timestamp_micros;

    // Address of a client
    socket_address _remote_address;

    // Only populated for external client state.
    auth::service* _auth_service{nullptr};

public:
    struct internal_tag {};
    struct external_tag {};

    void create_tracing_session(tracing::trace_type type, tracing::trace_state_props_set props) {
        _trace_state_ptr = tracing::tracing::get_local_tracing_instance().create_session(type, props);
    }

    tracing::trace_state_ptr& get_trace_state() {
        return _trace_state_ptr;
    }

    const tracing::trace_state_ptr& get_trace_state() const {
        return _trace_state_ptr;
    }

    auth_state get_auth_state() const noexcept {
        return _auth_state;
    }

    void set_auth_state(auth_state new_state) noexcept {
        _auth_state = new_state;
    }

    client_state(external_tag, auth::service& auth_service, const socket_address& remote_address = socket_address(), bool thrift = false)
            : _is_internal(false)
            , _is_thrift(thrift)
            , _remote_address(remote_address)
            , _auth_service(&auth_service) {
        if (!auth_service.underlying_authenticator().require_authentication()) {
            _user = ::make_shared<auth::authenticated_user>();
        }
    }

    gms::inet_address get_client_address() const {
        return gms::inet_address(_remote_address);
    }

    client_state(internal_tag)
            : _keyspace("system")
            , _is_internal(true)
            , _is_thrift(false)
    {}

    client_state(client_state&) = delete;

    ///
    /// `nullptr` for internal instances.
    ///
    const auth::service* get_auth_service() const {
        return _auth_service;
    }

    bool is_thrift() const {
        return _is_thrift;
    }

    bool is_internal() const {
        return _is_internal;
    }

    /**
     * @return a ClientState object for internal C* calls (not limited by any kind of auth).
     */
    static client_state& for_internal_calls() {
        static thread_local client_state s(internal_tag{});
        return s;
    }

    /**
     * This clock guarantees that updates for the same ClientState will be ordered
     * in the sequence seen, even if multiple updates happen in the same millisecond.
     */
    api::timestamp_type get_timestamp() {
        auto current = api::new_timestamp();
        auto last = _last_timestamp_micros;
        auto result = last >= current ? last + 1 : current;
        _last_timestamp_micros = result;
        return result;
    }

    /**
     * Returns a timestamp suitable for paxos given the timestamp of the last known commit (or in progress update).
     *
     * Paxos ensures that the timestamp it uses for commits respects the serial order of those commits. It does so
     * by having each replica reject any proposal whose timestamp is not strictly greater than the last proposal it
     * accepted. So in practice, which timestamp we use for a given proposal doesn't affect correctness but it does
     * affect the chance of making progress (if we pick a timestamp lower than what has been proposed before, our
     * new proposal will just get rejected).
     *
     * As during the prepared phase replica send us the last propose they accepted, a first option would be to take
     * the maximum of those last accepted proposal timestamp plus 1 (and use a default value, say 0, if it's the
     * first known proposal for the partition). This would mostly work (giving commits the timestamp 0, 1, 2, ...
     * in the order they are commited) but with 2 important caveats:
     *   1) it would give a very poor experience when Paxos and non-Paxos updates are mixed in the same partition,
     *      since paxos operations wouldn't be using microseconds timestamps. And while you shouldn't theoretically
     *      mix the 2 kind of operations, this would still be pretty nonintuitive. And what if you started writing
     *      normal updates and realize later you should switch to Paxos to enforce a property you want?
     *   2) this wouldn't actually be safe due to the expiration set on the Paxos state table.
     *
     * So instead, we initially chose to use the current time in microseconds as for normal update. Which works in
     * general but mean that clock skew creates unavailability periods for Paxos updates (either a node has his clock
     * in the past and he may no be able to get commit accepted until its clock catch up, or a node has his clock in
     * the future and then once one of its commit his accepted, other nodes ones won't be until they catch up). This
     * is ok for small clock skew (few ms) but can be pretty bad for large one.
     *
     * Hence our current solution: we mix both approaches. That is, we compare the timestamp of the last known
     * accepted proposal and the local time. If the local time is greater, we use it, thus keeping paxos timestamps
     * locked to the current time in general (making mixing Paxos and non-Paxos more friendly, and behaving correctly
     * when the paxos state expire (as long as your maximum clock skew is lower than the Paxos state expiration
     * time)). Otherwise (the local time is lower than the last proposal, meaning that this last proposal was done
     * with a clock in the future compared to the local one), we use the last proposal timestamp plus 1, ensuring
     * progress.
     *
     * @param min_timestamp_to_use the max timestamp of the last proposal accepted by replica having responded
     * to the prepare phase of the paxos round this is for. In practice, that's the minimum timestamp this method
     * may return.
     * @return a timestamp suitable for a Paxos proposal (using the reasoning described above). Note that
     * contrary to the get_timestamp() method, the return value is not guaranteed to be unique (nor
     * monotonic) across calls since it can return it's argument (so if the same argument is passed multiple times,
     * it may be returned multiple times). Note that we still ensure Paxos "ballot" are unique (for different
     * proposal) by (securely) randomizing the non-timestamp part of the UUID.
     */
    api::timestamp_type get_timestamp_for_paxos(api::timestamp_type min_timestamp_to_use) {
        api::timestamp_type current = std::max(api::new_timestamp(), min_timestamp_to_use);
        _last_timestamp_micros = _last_timestamp_micros > current ? _last_timestamp_micros + 1 : current;
        return _last_timestamp_micros;
    }

#if 0
    public SocketAddress getRemoteAddress()
    {
        return remoteAddress;
    }
#endif

    const sstring& get_raw_keyspace() const noexcept {
        return _keyspace;
    }

    sstring& get_raw_keyspace() noexcept {
        return _keyspace;
    }

public:
    void set_keyspace(database& db, sstring keyspace);

    void set_raw_keyspace(sstring new_keyspace) noexcept {
        _keyspace = std::move(new_keyspace);
    }

    const sstring& get_keyspace() const {
        if (_keyspace.empty()) {
            throw exceptions::invalid_request_exception("No keyspace has been specified. USE a keyspace, or explicitly specify keyspace.tablename");
        }
        return _keyspace;
    }

    /**
     * Sets active user. Does _not_ validate anything
     */
    void set_login(::shared_ptr<auth::authenticated_user>);

    /// \brief A user can login if it's anonymous, or if it exists and the `LOGIN` option for the user is `true`.
    future<> check_user_can_login();

    future<> has_all_keyspaces_access(auth::permission) const;
    future<> has_keyspace_access(const sstring&, auth::permission) const;
    future<> has_column_family_access(const sstring&, const sstring&, auth::permission) const;
    future<> has_schema_access(const schema& s, auth::permission p) const;

private:
    future<> has_access(const sstring&, auth::permission, const auth::resource&) const;

public:
    future<bool> check_has_permission(auth::permission, const auth::resource&) const;
    future<> ensure_has_permission(auth::permission, const auth::resource&) const;

    /**
     * Returns an exceptional future with \ref exceptions::invalid_request_exception if the resource does not exist.
     */
    future<> ensure_exists(const auth::resource&) const;

    void validate_login() const;
    void ensure_not_anonymous() const; // unauthorized_exception on error

#if 0
    public void ensureIsSuper(String message) throws UnauthorizedException
    {
        if (DatabaseDescriptor.getAuthenticator().requireAuthentication() && (user == null || !user.isSuper()))
            throw new UnauthorizedException(message);
    }

    private static void validateKeyspace(String keyspace) throws InvalidRequestException
    {
        if (keyspace == null)
            throw new InvalidRequestException("You have not set a keyspace for this session");
    }
#endif

    ::shared_ptr<auth::authenticated_user> user() const {
        return _user;
    }

#if 0
    public static SemanticVersion[] getCQLSupportedVersion()
    {
        return new SemanticVersion[]{ QueryProcessor.CQL_VERSION };
    }

    private Set<Permission> authorize(IResource resource)
    {
        // AllowAllAuthorizer or manually disabled caching.
        if (Auth.permissionsCache == null)
            return DatabaseDescriptor.getAuthorizer().authorize(user, resource);

        try
        {
            return Auth.permissionsCache.get(Pair.create(user, resource));
        }
        catch (ExecutionException e)
        {
            throw new RuntimeException(e);
        }
    }
#endif
};

}

<commit_msg>client_state: fix get_timestamp_for_paxos() to always advance a timestamp<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright (C) 2015 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "auth/service.hh"
#include "exceptions/exceptions.hh"
#include "unimplemented.hh"
#include "timestamp.hh"
#include "db_clock.hh"
#include "database_fwd.hh"
#include "auth/authenticated_user.hh"
#include "auth/authenticator.hh"
#include "auth/permission.hh"
#include "tracing/tracing.hh"
#include "tracing/trace_state.hh"

namespace auth {
class resource;
}

namespace service {

/**
 * State related to a client connection.
 */
class client_state {
public:
    enum class auth_state : uint8_t {
        UNINITIALIZED, AUTHENTICATION, READY
    };

private:
    sstring _keyspace;
    tracing::trace_state_ptr _trace_state_ptr;
#if 0
    private static final Logger logger = LoggerFactory.getLogger(ClientState.class);
    public static final SemanticVersion DEFAULT_CQL_VERSION = org.apache.cassandra.cql3.QueryProcessor.CQL_VERSION;

    private static final Set<IResource> READABLE_SYSTEM_RESOURCES = new HashSet<>();
    private static final Set<IResource> PROTECTED_AUTH_RESOURCES = new HashSet<>();

    static
    {
        // We want these system cfs to be always readable to authenticated users since many tools rely on them
        // (nodetool, cqlsh, bulkloader, etc.)
        for (String cf : Iterables.concat(Arrays.asList(SystemKeyspace.LOCAL, SystemKeyspace.PEERS), LegacySchemaTables.ALL))
            READABLE_SYSTEM_RESOURCES.add(DataResource.columnFamily(SystemKeyspace.NAME, cf));

        PROTECTED_AUTH_RESOURCES.addAll(DatabaseDescriptor.getAuthenticator().protectedResources());
        PROTECTED_AUTH_RESOURCES.addAll(DatabaseDescriptor.getAuthorizer().protectedResources());
    }

    // Current user for the session
    private volatile AuthenticatedUser user;
    private volatile String keyspace;
#endif
    ::shared_ptr<auth::authenticated_user> _user;

    auth_state _auth_state = auth_state::UNINITIALIZED;

    // isInternal is used to mark ClientState as used by some internal component
    // that should have an ability to modify system keyspace.
    bool _is_internal;
    bool _is_thrift;

    // The biggest timestamp that was returned by getTimestamp/assigned to a query
    static thread_local api::timestamp_type _last_timestamp_micros;

    // Address of a client
    socket_address _remote_address;

    // Only populated for external client state.
    auth::service* _auth_service{nullptr};

public:
    struct internal_tag {};
    struct external_tag {};

    void create_tracing_session(tracing::trace_type type, tracing::trace_state_props_set props) {
        _trace_state_ptr = tracing::tracing::get_local_tracing_instance().create_session(type, props);
    }

    tracing::trace_state_ptr& get_trace_state() {
        return _trace_state_ptr;
    }

    const tracing::trace_state_ptr& get_trace_state() const {
        return _trace_state_ptr;
    }

    auth_state get_auth_state() const noexcept {
        return _auth_state;
    }

    void set_auth_state(auth_state new_state) noexcept {
        _auth_state = new_state;
    }

    client_state(external_tag, auth::service& auth_service, const socket_address& remote_address = socket_address(), bool thrift = false)
            : _is_internal(false)
            , _is_thrift(thrift)
            , _remote_address(remote_address)
            , _auth_service(&auth_service) {
        if (!auth_service.underlying_authenticator().require_authentication()) {
            _user = ::make_shared<auth::authenticated_user>();
        }
    }

    gms::inet_address get_client_address() const {
        return gms::inet_address(_remote_address);
    }

    client_state(internal_tag)
            : _keyspace("system")
            , _is_internal(true)
            , _is_thrift(false)
    {}

    client_state(client_state&) = delete;

    ///
    /// `nullptr` for internal instances.
    ///
    const auth::service* get_auth_service() const {
        return _auth_service;
    }

    bool is_thrift() const {
        return _is_thrift;
    }

    bool is_internal() const {
        return _is_internal;
    }

    /**
     * @return a ClientState object for internal C* calls (not limited by any kind of auth).
     */
    static client_state& for_internal_calls() {
        static thread_local client_state s(internal_tag{});
        return s;
    }

    /**
     * This clock guarantees that updates for the same ClientState will be ordered
     * in the sequence seen, even if multiple updates happen in the same millisecond.
     */
    api::timestamp_type get_timestamp() {
        auto current = api::new_timestamp();
        auto last = _last_timestamp_micros;
        auto result = last >= current ? last + 1 : current;
        _last_timestamp_micros = result;
        return result;
    }

    /**
     * Returns a timestamp suitable for paxos given the timestamp of the last known commit (or in progress update).
     *
     * Paxos ensures that the timestamp it uses for commits respects the serial order of those commits. It does so
     * by having each replica reject any proposal whose timestamp is not strictly greater than the last proposal it
     * accepted. So in practice, which timestamp we use for a given proposal doesn't affect correctness but it does
     * affect the chance of making progress (if we pick a timestamp lower than what has been proposed before, our
     * new proposal will just get rejected).
     *
     * As during the prepared phase replica send us the last propose they accepted, a first option would be to take
     * the maximum of those last accepted proposal timestamp plus 1 (and use a default value, say 0, if it's the
     * first known proposal for the partition). This would mostly work (giving commits the timestamp 0, 1, 2, ...
     * in the order they are commited) but with 2 important caveats:
     *   1) it would give a very poor experience when Paxos and non-Paxos updates are mixed in the same partition,
     *      since paxos operations wouldn't be using microseconds timestamps. And while you shouldn't theoretically
     *      mix the 2 kind of operations, this would still be pretty nonintuitive. And what if you started writing
     *      normal updates and realize later you should switch to Paxos to enforce a property you want?
     *   2) this wouldn't actually be safe due to the expiration set on the Paxos state table.
     *
     * So instead, we initially chose to use the current time in microseconds as for normal update. Which works in
     * general but mean that clock skew creates unavailability periods for Paxos updates (either a node has his clock
     * in the past and he may no be able to get commit accepted until its clock catch up, or a node has his clock in
     * the future and then once one of its commit his accepted, other nodes ones won't be until they catch up). This
     * is ok for small clock skew (few ms) but can be pretty bad for large one.
     *
     * Hence our current solution: we mix both approaches. That is, we compare the timestamp of the last known
     * accepted proposal and the local time. If the local time is greater, we use it, thus keeping paxos timestamps
     * locked to the current time in general (making mixing Paxos and non-Paxos more friendly, and behaving correctly
     * when the paxos state expire (as long as your maximum clock skew is lower than the Paxos state expiration
     * time)). Otherwise (the local time is lower than the last proposal, meaning that this last proposal was done
     * with a clock in the future compared to the local one), we use the last proposal timestamp plus 1, ensuring
     * progress.
     *
     * @param min_timestamp_to_use the max timestamp of the last proposal accepted by replica having responded
     * to the prepare phase of the paxos round this is for. In practice, that's the minimum timestamp this method
     * may return.
     * @return a timestamp suitable for a Paxos proposal (using the reasoning described above). Note that
     * contrary to the get_timestamp() method, the return value is not guaranteed to be unique (nor
     * monotonic) across calls since it can return it's argument (so if the same argument is passed multiple times,
     * it may be returned multiple times). Note that we still ensure Paxos "ballot" are unique (for different
     * proposal) by (securely) randomizing the non-timestamp part of the UUID.
     */
    api::timestamp_type get_timestamp_for_paxos(api::timestamp_type min_timestamp_to_use) {
        api::timestamp_type current = std::max(api::new_timestamp(), min_timestamp_to_use);
        _last_timestamp_micros = _last_timestamp_micros >= current ? _last_timestamp_micros + 1 : current;
        return _last_timestamp_micros;
    }

#if 0
    public SocketAddress getRemoteAddress()
    {
        return remoteAddress;
    }
#endif

    const sstring& get_raw_keyspace() const noexcept {
        return _keyspace;
    }

    sstring& get_raw_keyspace() noexcept {
        return _keyspace;
    }

public:
    void set_keyspace(database& db, sstring keyspace);

    void set_raw_keyspace(sstring new_keyspace) noexcept {
        _keyspace = std::move(new_keyspace);
    }

    const sstring& get_keyspace() const {
        if (_keyspace.empty()) {
            throw exceptions::invalid_request_exception("No keyspace has been specified. USE a keyspace, or explicitly specify keyspace.tablename");
        }
        return _keyspace;
    }

    /**
     * Sets active user. Does _not_ validate anything
     */
    void set_login(::shared_ptr<auth::authenticated_user>);

    /// \brief A user can login if it's anonymous, or if it exists and the `LOGIN` option for the user is `true`.
    future<> check_user_can_login();

    future<> has_all_keyspaces_access(auth::permission) const;
    future<> has_keyspace_access(const sstring&, auth::permission) const;
    future<> has_column_family_access(const sstring&, const sstring&, auth::permission) const;
    future<> has_schema_access(const schema& s, auth::permission p) const;

private:
    future<> has_access(const sstring&, auth::permission, const auth::resource&) const;

public:
    future<bool> check_has_permission(auth::permission, const auth::resource&) const;
    future<> ensure_has_permission(auth::permission, const auth::resource&) const;

    /**
     * Returns an exceptional future with \ref exceptions::invalid_request_exception if the resource does not exist.
     */
    future<> ensure_exists(const auth::resource&) const;

    void validate_login() const;
    void ensure_not_anonymous() const; // unauthorized_exception on error

#if 0
    public void ensureIsSuper(String message) throws UnauthorizedException
    {
        if (DatabaseDescriptor.getAuthenticator().requireAuthentication() && (user == null || !user.isSuper()))
            throw new UnauthorizedException(message);
    }

    private static void validateKeyspace(String keyspace) throws InvalidRequestException
    {
        if (keyspace == null)
            throw new InvalidRequestException("You have not set a keyspace for this session");
    }
#endif

    ::shared_ptr<auth::authenticated_user> user() const {
        return _user;
    }

#if 0
    public static SemanticVersion[] getCQLSupportedVersion()
    {
        return new SemanticVersion[]{ QueryProcessor.CQL_VERSION };
    }

    private Set<Permission> authorize(IResource resource)
    {
        // AllowAllAuthorizer or manually disabled caching.
        if (Auth.permissionsCache == null)
            return DatabaseDescriptor.getAuthorizer().authorize(user, resource);

        try
        {
            return Auth.permissionsCache.get(Pair.create(user, resource));
        }
        catch (ExecutionException e)
        {
            throw new RuntimeException(e);
        }
    }
#endif
};

}

<|endoftext|>


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

#include "motive/engine.h"
#include "motive/processor.h"
#include "motive/version.h"
#include "motive/util/benchmark.h"

namespace motive {

// If we benchmark other stuff besides the MotiveProcessor::AdvanceFrame(),
// we'll have to move this to an enum of benchmarking ids.
static const int kBenchmarkIdOfFirstProcessor = 0;

// static
MotiveEngine::FunctionMap MotiveEngine::function_map_;

// static
void MotiveEngine::RegisterProcessorFactory(
    MotivatorType type, const MotiveProcessorFunctions& fns) {
  function_map_.insert(FunctionPair(type, fns));
}

// Prevent the version string from being stripped from the binary by keeping
// a reference to it here.
MotiveEngine::MotiveEngine()
  : version_(&Version()) {}

void MotiveEngine::Reset() {
  for (ProcessorMap::iterator it = mapped_processors_.begin();
       it != mapped_processors_.end(); ++it) {
    // Get the factory for each processor. Factory must exist since it is what
    // created the processor in the first place.
    const MotiveProcessorFunctions& fns = function_map_.find(it->first)->second;

    // Destroy each processor in turn.
    fns.destroy(it->second);
    it->second = nullptr;
  }

  // Remove all elements from the map. Their processors have all been destroyed.
  mapped_processors_.clear();
}

MotiveProcessor* MotiveEngine::Processor(MotivatorType type) {
  // If processor already exists, return it.
  ProcessorMap::iterator it = mapped_processors_.find(type);
  if (it != mapped_processors_.end()) return it->second;

  // Look up the processor-creation-function in the registry.
  const auto function_pair = function_map_.find(type);
  if (function_pair == function_map_.end()) return nullptr;
  const MotiveProcessorFunctions& fns = function_pair->second;

  // Remember processor for next time. We only want at most one processor per
  // type in an engine
  ProcessorDetails details;
  details.processor = fns.create();
  details.processor->RegisterBenchmarks();
  mapped_processors_.insert(ProcessorPair(type, details.processor));
  sorted_processors_.insert(details);

  return details.processor;
}

void MotiveEngine::AdvanceFrame(MotiveTime delta_time) {
  // Advance the simulation in each processor.
  // TODO: At some point, we'll want to do several passes. An item in
  // processor A might depend on the output of an item in processor B,
  // which might in turn depend on the output of a *different* item in
  // processor A. In this case, we have to do two passes. For now, just
  // assume that one pass is sufficient.
  for (ProcessorSet::iterator it = sorted_processors_.begin();
       it != sorted_processors_.end(); ++it) {
    const fpl::Benchmark b(it->processor->benchmark_id_for_advance_frame());
    it->processor->AdvanceFrame(delta_time);
  }
}

}  // namespace motive

<commit_msg>Fix Mac build.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "motive/engine.h"
#include "motive/processor.h"
#include "motive/version.h"
#include "motive/util/benchmark.h"

namespace motive {

// static
MotiveEngine::FunctionMap MotiveEngine::function_map_;

// static
void MotiveEngine::RegisterProcessorFactory(
    MotivatorType type, const MotiveProcessorFunctions& fns) {
  function_map_.insert(FunctionPair(type, fns));
}

// Prevent the version string from being stripped from the binary by keeping
// a reference to it here.
MotiveEngine::MotiveEngine()
  : version_(&Version()) {}

void MotiveEngine::Reset() {
  for (ProcessorMap::iterator it = mapped_processors_.begin();
       it != mapped_processors_.end(); ++it) {
    // Get the factory for each processor. Factory must exist since it is what
    // created the processor in the first place.
    const MotiveProcessorFunctions& fns = function_map_.find(it->first)->second;

    // Destroy each processor in turn.
    fns.destroy(it->second);
    it->second = nullptr;
  }

  // Remove all elements from the map. Their processors have all been destroyed.
  mapped_processors_.clear();
}

MotiveProcessor* MotiveEngine::Processor(MotivatorType type) {
  // If processor already exists, return it.
  ProcessorMap::iterator it = mapped_processors_.find(type);
  if (it != mapped_processors_.end()) return it->second;

  // Look up the processor-creation-function in the registry.
  const auto function_pair = function_map_.find(type);
  if (function_pair == function_map_.end()) return nullptr;
  const MotiveProcessorFunctions& fns = function_pair->second;

  // Remember processor for next time. We only want at most one processor per
  // type in an engine
  ProcessorDetails details;
  details.processor = fns.create();
  details.processor->RegisterBenchmarks();
  mapped_processors_.insert(ProcessorPair(type, details.processor));
  sorted_processors_.insert(details);

  return details.processor;
}

void MotiveEngine::AdvanceFrame(MotiveTime delta_time) {
  // Advance the simulation in each processor.
  // TODO: At some point, we'll want to do several passes. An item in
  // processor A might depend on the output of an item in processor B,
  // which might in turn depend on the output of a *different* item in
  // processor A. In this case, we have to do two passes. For now, just
  // assume that one pass is sufficient.
  for (ProcessorSet::iterator it = sorted_processors_.begin();
       it != sorted_processors_.end(); ++it) {
    const fpl::Benchmark b(it->processor->benchmark_id_for_advance_frame());
    it->processor->AdvanceFrame(delta_time);
  }
}

}  // namespace motive

<|endoftext|>


<commit_before>/*
  This file is part of Ingen.
  Copyright 2007-2012 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

  Ingen 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 Affero General Public License for details.

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "ingen/shared/LV2URIMap.hpp"
#include "ingen/client/PortModel.hpp"
#include "ingen/client/NodeModel.hpp"

namespace Ingen {
namespace Client {

void
PortModel::on_property(const Raul::URI& uri, const Raul::Atom& value)
{
	if (uri == _uris.ingen_value) {
		this->value(value);
	} else if (uri == _uris.ingen_activity) {
		signal_activity().emit(value);
	}
	ObjectModel::on_property(uri, value);
}

bool
PortModel::supports(const Raul::URI& value_type) const
{
	return has_property(_uris.atom_supports,
	                    _uris.forge.alloc_uri(value_type.str()));
}

bool
PortModel::port_property(const Raul::URI& uri) const
{
	return has_property(_uris.lv2_portProperty,
	                    _uris.forge.alloc_uri(uri.str()));
}

void
PortModel::set(SharedPtr<ObjectModel> model)
{
	SharedPtr<PortModel> port = PtrCast<PortModel>(model);
	if (port) {
		_index = port->_index;
		_direction = port->_direction;
		_current_val = port->_current_val;
		_connections = port->_connections;
		_signal_value_changed.emit(_current_val);
	}

	ObjectModel::set(model);
}

} // namespace Client
} // namespace Ingen
<commit_msg>Don't save ingen:activity property, which is transient.<commit_after>/*
  This file is part of Ingen.
  Copyright 2007-2012 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

  Ingen 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 Affero General Public License for details.

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "ingen/shared/LV2URIMap.hpp"
#include "ingen/client/PortModel.hpp"
#include "ingen/client/NodeModel.hpp"

namespace Ingen {
namespace Client {

void
PortModel::on_property(const Raul::URI& uri, const Raul::Atom& value)
{
	if (uri == _uris.ingen_activity) {
		signal_activity().emit(value);
	} else {
		if (uri == _uris.ingen_value) {
			this->value(value);
		}
	}
	ObjectModel::on_property(uri, value);
}

bool
PortModel::supports(const Raul::URI& value_type) const
{
	return has_property(_uris.atom_supports,
	                    _uris.forge.alloc_uri(value_type.str()));
}

bool
PortModel::port_property(const Raul::URI& uri) const
{
	return has_property(_uris.lv2_portProperty,
	                    _uris.forge.alloc_uri(uri.str()));
}

void
PortModel::set(SharedPtr<ObjectModel> model)
{
	SharedPtr<PortModel> port = PtrCast<PortModel>(model);
	if (port) {
		_index = port->_index;
		_direction = port->_direction;
		_current_val = port->_current_val;
		_connections = port->_connections;
		_signal_value_changed.emit(_current_val);
	}

	ObjectModel::set(model);
}

} // namespace Client
} // namespace Ingen
<|endoftext|>