<commit_before>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#ifndef __BSE_BCORE_HH__
#define __BSE_BCORE_HH__

#include <sfi/platform.hh>
#include <sfi/strings.hh>
#include <sfi/glib-extra.hh>

namespace Bse {

// == type aliases ==
typedef uint8_t         uint8;          ///< An 8-bit unsigned integer.
typedef uint16_t        uint16;         ///< A 16-bit unsigned integer.
typedef uint32_t        uint32;         ///< A 32-bit unsigned integer.
typedef uint64_t        uint64;         ///< A 64-bit unsigned integer, use PRI*64 in format strings.
typedef int8_t          int8;           ///< An 8-bit signed integer.
typedef int16_t         int16;          ///< A 16-bit signed integer.
typedef int32_t         int32;          ///< A 32-bit signed integer.
typedef int64_t         int64;          ///< A 64-bit unsigned integer, use PRI*64 in format strings.
typedef uint32_t        unichar;        ///< A 32-bit unsigned integer used for Unicode characters.
static_assert (sizeof (uint8) == 1 && sizeof (uint16) == 2 && sizeof (uint32) == 4 && sizeof (uint64) == 8, "");
static_assert (sizeof (int8)  == 1 && sizeof (int16)  == 2 && sizeof (int32)  == 4 && sizeof (int64)  == 8, "");
static_assert (sizeof (int) == 4 && sizeof (uint) == 4 && sizeof (unichar) == 4, "");
using   std::map;
using   std::vector;
typedef std::string String;             ///< Convenience alias for std::string.
typedef vector<String> StringVector;    ///< Convenience alias for a std::vector<std::string>.
using   Aida::Any;
using   Aida::EventFd;
using   Rapicorn::DataKey;
using   Rapicorn::DataListContainer;

// == Diagnostics ==
template<class... Args> String      string_format        (const char *format, const Args &...args) BSE_PRINTF (1, 0);
template<class... Args> String      string_locale_format (const char *format, const Args &...args) BSE_PRINTF (1, 0);
template<class... Args> void        printout             (const char *format, const Args &...args) BSE_PRINTF (1, 0);
template<class... Args> void        printerr             (const char *format, const Args &...args) BSE_PRINTF (1, 0);
template<class ...Args> void        fatal_error          (const char *format, const Args &...args) BSE_NORETURN;
template<class ...Args> void        warning              (const char *format, const Args &...args);
template<class ...Args> void        warn                 (const char *format, const Args &...args);
template<class ...Args> void        info                 (const char *format, const Args &...args);
template<class ...Args> inline void dump                 (const char *conditional, const char *format, const Args &...args) BSE_ALWAYS_INLINE;
template<class ...Args> inline void debug                (const char *conditional, const char *format, const Args &...args) BSE_ALWAYS_INLINE;
inline bool                         debug_enabled        (const char *conditional) BSE_ALWAYS_INLINE BSE_PURE;

// == Development Aids ==
extern inline void breakpoint () BSE_ALWAYS_INLINE;                    ///< Cause a debugging breakpoint, for development only.

// == Binary Lookups ==
template<typename RandIter, class Cmp, typename Arg, int case_lookup_or_sibling_or_insertion>
extern inline std::pair<RandIter,bool>
binary_lookup_fuzzy (RandIter begin, RandIter end, Cmp cmp_elements, const Arg &arg)
{
  RandIter current = end;
  size_t n_elements = end - begin, offs = 0;
  const bool want_lookup = case_lookup_or_sibling_or_insertion == 0;
  // const bool want_sibling = case_lookup_or_sibling_or_insertion == 1;
  const bool want_insertion_pos = case_lookup_or_sibling_or_insertion > 1;
  ssize_t cmp = 0;
  while (offs < n_elements)
    {
      size_t i = (offs + n_elements) >> 1;
      current = begin + i;
      cmp = cmp_elements (arg, *current);
      if (cmp == 0)
        return want_insertion_pos ? std::make_pair (current, true) : std::make_pair (current, /*ignored*/ false);
      else if (cmp < 0)
        n_elements = i;
      else /* (cmp > 0) */
        offs = i + 1;
    }
  /* check is last mismatch, cmp > 0 indicates greater key */
  return (want_lookup
          ? std::make_pair (end, /*ignored*/ false)
          : (want_insertion_pos && cmp > 0)
          ? std::make_pair (current + 1, false)
          : std::make_pair (current, false));
}

/** Perform a binary lookup to find the insertion position for a new element.
 * Return (end,false) for end-begin==0, or return (position,true) for exact match,
 * otherwise return (position,false) where position indicates the location for
 * the key to be inserted (and may equal end).
 */
template<typename RandIter, class Cmp, typename Arg>
extern inline std::pair<RandIter,bool>
binary_lookup_insertion_pos (RandIter begin, RandIter end, Cmp cmp_elements, const Arg &arg)
{
  return binary_lookup_fuzzy<RandIter,Cmp,Arg,2> (begin, end, cmp_elements, arg);
}

/** Perform a binary lookup to yield exact or nearest match.
 * return end for end-begin==0, otherwise return the exact match element, or,
 * if there's no such element, return the element last visited, which is pretty
 * close to an exact match (will be one off into either direction).
 */
template<typename RandIter, class Cmp, typename Arg>
extern inline RandIter
binary_lookup_sibling (RandIter begin, RandIter end, Cmp cmp_elements, const Arg &arg)
{
  return binary_lookup_fuzzy<RandIter,Cmp,Arg,1> (begin, end, cmp_elements, arg).first;
}

/** Perform binary lookup and yield exact match or @a end.
 * The arguments [ @a begin, @a end [ denote the range used for the lookup,
 * @a arg is passed along with the current element to the @a cmp_elements
 * function.
 */
template<typename RandIter, class Cmp, typename Arg>
extern inline RandIter
binary_lookup (RandIter begin, RandIter end, Cmp cmp_elements, const Arg &arg)
{
  /* return end or exact match */
  return binary_lookup_fuzzy<RandIter,Cmp,Arg,0> (begin, end, cmp_elements, arg).first;
}

/// Comparison function useful to sort lesser items first.
template<typename Value> static inline int
compare_lesser (const Value &v1, const Value &v2)
{
  return -(v1 < v2) | (v2 < v1);
}

/// Comparison function useful to sort greater items first.
template<typename Value> static inline int
compare_greater (const Value &v1, const Value &v2)
{
  return (v1 < v2) | -(v2 < v1);
}

// == Implementation Details ==
#if (defined __i386__ || defined __x86_64__)
inline void breakpoint() { __asm__ __volatile__ ("int $03"); }
#elif defined __alpha__ && !defined __osf__
inline void breakpoint() { __asm__ __volatile__ ("bpt"); }
#else   // !__i386__ && !__alpha__
inline void breakpoint() { __builtin_trap(); }
#endif

namespace Internal {
extern bool                         debug_any_enabled;  //< Indicates if $BSE_DEBUG enables some debug settings.
bool                                debug_key_enabled (const char *conditional) BSE_PURE;
void                                diagnostic        (char kind, const std::string &message);
void                                debug_diagnostic  (const char *prefix, const std::string &message);
void                                force_abort       () BSE_NORETURN;
void                                printout_string   (const String &string);
void                                printerr_string   (const String &string);
} // Internal

/// Print a message on stdout (and flush stdout) ala printf(), using the POSIX/C locale.
template<class... Args> void
printout (const char *format, const Args &...args)
{
  Internal::printout_string (string_format (format, args...));
}

/// Print a message on stderr (and flush stderr) ala printf(), using the POSIX/C locale.
template<class... Args> void
printerr (const char *format, const Args &...args)
{
  Internal::printerr_string (string_format (format, args...));
}

/// Issue a printf-like message if @a conditional is enabled by $BSE_DEBUG.
template<class ...Args> inline void BSE_ALWAYS_INLINE
dump (const char *conditional, const char *format, const Args &...args)
{
  if (BSE_UNLIKELY (Internal::debug_any_enabled) && Internal::debug_key_enabled (conditional))
    Internal::diagnostic (' ', string_format (format, args...));
}

/// Issue a printf-like debugging message if @a conditional is enabled by $BSE_DEBUG.
template<class ...Args> inline void BSE_ALWAYS_INLINE
debug (const char *conditional, const char *format, const Args &...args)
{
  if (BSE_UNLIKELY (Internal::debug_any_enabled) && Internal::debug_key_enabled (conditional))
    Internal::debug_diagnostic (conditional, string_format (format, args...));
}

/// Check if @a conditional is enabled by $BSE_DEBUG.
inline bool BSE_ALWAYS_INLINE BSE_PURE
debug_enabled (const char *conditional)
{
  if (BSE_UNLIKELY (Internal::debug_any_enabled))
    return Internal::debug_key_enabled (conditional);
  return false;
}

/** Issue a printf-like message and abort the program, this function will not return.
 * Avoid using this in library code, aborting may take precious user data with it,
 * library code should instead use info() or assert_return().
 */
template<class ...Args> void BSE_NORETURN
fatal_error (const char *format, const Args &...args)
{
  Internal::diagnostic ('F', string_format (format, args...));
  Internal::force_abort();
}

/// Issue a printf-like warning message.
template<class ...Args> void BSE_NORETURN
warn (const char *format, const Args &...args)
{
  Internal::diagnostic ('W', string_format (format, args...));
}

/// Issue a printf-like warning message.
template<class ...Args> void BSE_NORETURN
warning (const char *format, const Args &...args)
{
  Internal::diagnostic ('W', string_format (format, args...));
}

/// Issue an informative printf-like message.
template<class ...Args> void BSE_NORETURN
info (const char *format, const Args &...args)
{
  Internal::diagnostic ('I', string_format (format, args...));
}

// == Assertions ==
/// Return from the current function if @a cond is unmet and issue an assertion warning.
#define BSE_ASSERT_RETURN(cond, ...)     do { if (BSE_ISLIKELY (cond)) break; ::Bse::assertion_failed (__FILE__, __LINE__, #cond); return __VA_ARGS__; } while (0)
/// Return from the current function and issue an assertion warning.
#define BSE_ASSERT_RETURN_UNREACHED(...) do { ::Bse::assertion_failed (__FILE__, __LINE__, NULL); return __VA_ARGS__; } while (0)
#ifdef BSE_CONVENIENCE
/// Return from the current function if @a cond is unmet and issue an assertion warning.
#define assert_return(cond, ...)        BSE_ASSERT_RETURN (cond, __VA_ARGS__)
/// Return from the current function and issue an assertion warning.
#define assert_return_unreached(...)    BSE_ASSERT_RETURN_UNREACHED (__VA_ARGS__)
/// Hint to the compiler to optimize for @a cond == TRUE.
#define ISLIKELY(cond)  BSE_ISLIKELY (cond)
/// Hint to the compiler to optimize for @a cond == FALSE.
#define UNLIKELY(cond)  BSE_UNLIKELY (cond)
/// Return silently if @a cond does not evaluate to true with return value @a ...
#define return_unless(cond, ...)        BSE_RETURN_UNLESS (cond, __VA_ARGS__)
#endif // BSE_CONVENIENCE

// == Memory Utilities ==
int     fmsb          (uint64  word) BSE_CONST; ///< Find most significant bit set in a word.
void*   aligned_alloc (size_t  total_size, size_t alignment, uint8 **free_pointer);
void    aligned_free  (uint8 **free_pointer);

/// Class to maintain an array of aligned memory.
template<class T, int ALIGNMENT>
class AlignedArray {
  uint8 *unaligned_mem_;
  T     *data_;
  size_t n_elements_;
  void
  allocate_aligned_data()
  {
    static_assert (ALIGNMENT % sizeof (T) == 0, "ALIGNMENT must exactly fit a multiple of sizeof (T)");
    data_ = reinterpret_cast<T*> (aligned_alloc (n_elements_ * sizeof (T), ALIGNMENT, &unaligned_mem_));
  }
  // disallow copy constructor assignment operator
  RAPICORN_CLASS_NON_COPYABLE (AlignedArray);
public:
  AlignedArray (const vector<T>& elements) :
    n_elements_ (elements.size())
  {
    allocate_aligned_data();
    for (size_t i = 0; i < n_elements_; i++)
      new (data_ + i) T (elements[i]);
  }
  AlignedArray (size_t n_elements) :
    n_elements_ (n_elements)
  {
    allocate_aligned_data();
    for (size_t i = 0; i < n_elements_; i++)
      new (data_ + i) T();
  }
  ~AlignedArray()
  {
    // C++ destruction order: last allocated element is deleted first
    while (n_elements_)
      data_[--n_elements_].~T();
    aligned_free (&unaligned_mem_);
  }
  T&            operator[] (size_t pos)         { return data_[pos]; }
  const T&      operator[] (size_t pos) const   { return data_[pos]; }
  size_t        size       () const             { return n_elements_; }
};

// == Threading ==
/**
 * The Spinlock uses low-latency busy spinning to acquire locks.
 * This class is a thin wrapper around pthread_spin_lock() and related functions.
 * This class supports static construction.
 */
class Spinlock {
  pthread_spinlock_t spinlock_;
public:
  constexpr Spinlock    () : spinlock_ { BSE_SPINLOCK_INITIALIZER } {}
  void      lock        ()      { pthread_spin_lock (&spinlock_); }
  void      unlock      ()      { pthread_spin_unlock (&spinlock_); }
  bool      try_lock    ()      { return 0 == pthread_spin_trylock (&spinlock_); }
  typedef pthread_spinlock_t* native_handle_type;
  native_handle_type native_handle() { return &spinlock_; }
  /*ctor*/  Spinlock    (const Spinlock&) = delete;
  Spinlock& operator=   (const Spinlock&) = delete;
};

} // Bse

#endif // __BSE_BCORE_HH__
<commit_msg>SFI: import threading and memory utilities from Rapicorn into Bse<commit_after>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#ifndef __BSE_BCORE_HH__
#define __BSE_BCORE_HH__

#include <sfi/platform.hh>
#include <sfi/strings.hh>
#include <sfi/glib-extra.hh>

namespace Bse {

// == type aliases ==
typedef uint8_t         uint8;          ///< An 8-bit unsigned integer.
typedef uint16_t        uint16;         ///< A 16-bit unsigned integer.
typedef uint32_t        uint32;         ///< A 32-bit unsigned integer.
typedef uint64_t        uint64;         ///< A 64-bit unsigned integer, use PRI*64 in format strings.
typedef int8_t          int8;           ///< An 8-bit signed integer.
typedef int16_t         int16;          ///< A 16-bit signed integer.
typedef int32_t         int32;          ///< A 32-bit signed integer.
typedef int64_t         int64;          ///< A 64-bit unsigned integer, use PRI*64 in format strings.
typedef uint32_t        unichar;        ///< A 32-bit unsigned integer used for Unicode characters.
static_assert (sizeof (uint8) == 1 && sizeof (uint16) == 2 && sizeof (uint32) == 4 && sizeof (uint64) == 8, "");
static_assert (sizeof (int8)  == 1 && sizeof (int16)  == 2 && sizeof (int32)  == 4 && sizeof (int64)  == 8, "");
static_assert (sizeof (int) == 4 && sizeof (uint) == 4 && sizeof (unichar) == 4, "");
using   std::map;
using   std::vector;
typedef std::string String;             ///< Convenience alias for std::string.
typedef vector<String> StringVector;    ///< Convenience alias for a std::vector<std::string>.
using   Aida::Any;
using   Aida::EventFd;
using   Rapicorn::DataKey;
using   Rapicorn::DataListContainer;
using   Rapicorn::void_t;
using   Rapicorn::Blob;
using   Rapicorn::Res;
using   Rapicorn::TaskStatus;
using   Rapicorn::ThreadInfo;
using   Rapicorn::cpu_info;
using   Rapicorn::AsyncBlockingQueue;
namespace ThisThread = Rapicorn::ThisThread;

// == Diagnostics ==
template<class... Args> String      string_format        (const char *format, const Args &...args) BSE_PRINTF (1, 0);
template<class... Args> String      string_locale_format (const char *format, const Args &...args) BSE_PRINTF (1, 0);
template<class... Args> void        printout             (const char *format, const Args &...args) BSE_PRINTF (1, 0);
template<class... Args> void        printerr             (const char *format, const Args &...args) BSE_PRINTF (1, 0);
template<class ...Args> void        fatal_error          (const char *format, const Args &...args) BSE_NORETURN;
template<class ...Args> void        warning              (const char *format, const Args &...args);
template<class ...Args> void        warn                 (const char *format, const Args &...args);
template<class ...Args> void        info                 (const char *format, const Args &...args);
template<class ...Args> inline void dump                 (const char *conditional, const char *format, const Args &...args) BSE_ALWAYS_INLINE;
template<class ...Args> inline void debug                (const char *conditional, const char *format, const Args &...args) BSE_ALWAYS_INLINE;
inline bool                         debug_enabled        (const char *conditional) BSE_ALWAYS_INLINE BSE_PURE;

// == Development Aids ==
extern inline void breakpoint () BSE_ALWAYS_INLINE;                    ///< Cause a debugging breakpoint, for development only.

// == Binary Lookups ==
template<typename RandIter, class Cmp, typename Arg, int case_lookup_or_sibling_or_insertion>
extern inline std::pair<RandIter,bool>
binary_lookup_fuzzy (RandIter begin, RandIter end, Cmp cmp_elements, const Arg &arg)
{
  RandIter current = end;
  size_t n_elements = end - begin, offs = 0;
  const bool want_lookup = case_lookup_or_sibling_or_insertion == 0;
  // const bool want_sibling = case_lookup_or_sibling_or_insertion == 1;
  const bool want_insertion_pos = case_lookup_or_sibling_or_insertion > 1;
  ssize_t cmp = 0;
  while (offs < n_elements)
    {
      size_t i = (offs + n_elements) >> 1;
      current = begin + i;
      cmp = cmp_elements (arg, *current);
      if (cmp == 0)
        return want_insertion_pos ? std::make_pair (current, true) : std::make_pair (current, /*ignored*/ false);
      else if (cmp < 0)
        n_elements = i;
      else /* (cmp > 0) */
        offs = i + 1;
    }
  /* check is last mismatch, cmp > 0 indicates greater key */
  return (want_lookup
          ? std::make_pair (end, /*ignored*/ false)
          : (want_insertion_pos && cmp > 0)
          ? std::make_pair (current + 1, false)
          : std::make_pair (current, false));
}

/** Perform a binary lookup to find the insertion position for a new element.
 * Return (end,false) for end-begin==0, or return (position,true) for exact match,
 * otherwise return (position,false) where position indicates the location for
 * the key to be inserted (and may equal end).
 */
template<typename RandIter, class Cmp, typename Arg>
extern inline std::pair<RandIter,bool>
binary_lookup_insertion_pos (RandIter begin, RandIter end, Cmp cmp_elements, const Arg &arg)
{
  return binary_lookup_fuzzy<RandIter,Cmp,Arg,2> (begin, end, cmp_elements, arg);
}

/** Perform a binary lookup to yield exact or nearest match.
 * return end for end-begin==0, otherwise return the exact match element, or,
 * if there's no such element, return the element last visited, which is pretty
 * close to an exact match (will be one off into either direction).
 */
template<typename RandIter, class Cmp, typename Arg>
extern inline RandIter
binary_lookup_sibling (RandIter begin, RandIter end, Cmp cmp_elements, const Arg &arg)
{
  return binary_lookup_fuzzy<RandIter,Cmp,Arg,1> (begin, end, cmp_elements, arg).first;
}

/** Perform binary lookup and yield exact match or @a end.
 * The arguments [ @a begin, @a end [ denote the range used for the lookup,
 * @a arg is passed along with the current element to the @a cmp_elements
 * function.
 */
template<typename RandIter, class Cmp, typename Arg>
extern inline RandIter
binary_lookup (RandIter begin, RandIter end, Cmp cmp_elements, const Arg &arg)
{
  /* return end or exact match */
  return binary_lookup_fuzzy<RandIter,Cmp,Arg,0> (begin, end, cmp_elements, arg).first;
}

/// Comparison function useful to sort lesser items first.
template<typename Value> static inline int
compare_lesser (const Value &v1, const Value &v2)
{
  return -(v1 < v2) | (v2 < v1);
}

/// Comparison function useful to sort greater items first.
template<typename Value> static inline int
compare_greater (const Value &v1, const Value &v2)
{
  return (v1 < v2) | -(v2 < v1);
}

// == Implementation Details ==
#if (defined __i386__ || defined __x86_64__)
inline void breakpoint() { __asm__ __volatile__ ("int $03"); }
#elif defined __alpha__ && !defined __osf__
inline void breakpoint() { __asm__ __volatile__ ("bpt"); }
#else   // !__i386__ && !__alpha__
inline void breakpoint() { __builtin_trap(); }
#endif

namespace Internal {
extern bool                         debug_any_enabled;  //< Indicates if $BSE_DEBUG enables some debug settings.
bool                                debug_key_enabled (const char *conditional) BSE_PURE;
void                                diagnostic        (char kind, const std::string &message);
void                                debug_diagnostic  (const char *prefix, const std::string &message);
void                                force_abort       () BSE_NORETURN;
void                                printout_string   (const String &string);
void                                printerr_string   (const String &string);
} // Internal

/// Print a message on stdout (and flush stdout) ala printf(), using the POSIX/C locale.
template<class... Args> void
printout (const char *format, const Args &...args)
{
  Internal::printout_string (string_format (format, args...));
}

/// Print a message on stderr (and flush stderr) ala printf(), using the POSIX/C locale.
template<class... Args> void
printerr (const char *format, const Args &...args)
{
  Internal::printerr_string (string_format (format, args...));
}

/// Issue a printf-like message if @a conditional is enabled by $BSE_DEBUG.
template<class ...Args> inline void BSE_ALWAYS_INLINE
dump (const char *conditional, const char *format, const Args &...args)
{
  if (BSE_UNLIKELY (Internal::debug_any_enabled) && Internal::debug_key_enabled (conditional))
    Internal::diagnostic (' ', string_format (format, args...));
}

/// Issue a printf-like debugging message if @a conditional is enabled by $BSE_DEBUG.
template<class ...Args> inline void BSE_ALWAYS_INLINE
debug (const char *conditional, const char *format, const Args &...args)
{
  if (BSE_UNLIKELY (Internal::debug_any_enabled) && Internal::debug_key_enabled (conditional))
    Internal::debug_diagnostic (conditional, string_format (format, args...));
}

/// Check if @a conditional is enabled by $BSE_DEBUG.
inline bool BSE_ALWAYS_INLINE BSE_PURE
debug_enabled (const char *conditional)
{
  if (BSE_UNLIKELY (Internal::debug_any_enabled))
    return Internal::debug_key_enabled (conditional);
  return false;
}

/** Issue a printf-like message and abort the program, this function will not return.
 * Avoid using this in library code, aborting may take precious user data with it,
 * library code should instead use info() or assert_return().
 */
template<class ...Args> void BSE_NORETURN
fatal_error (const char *format, const Args &...args)
{
  Internal::diagnostic ('F', string_format (format, args...));
  Internal::force_abort();
}

/// Issue a printf-like warning message.
template<class ...Args> void BSE_NORETURN
warn (const char *format, const Args &...args)
{
  Internal::diagnostic ('W', string_format (format, args...));
}

/// Issue a printf-like warning message.
template<class ...Args> void BSE_NORETURN
warning (const char *format, const Args &...args)
{
  Internal::diagnostic ('W', string_format (format, args...));
}

/// Issue an informative printf-like message.
template<class ...Args> void BSE_NORETURN
info (const char *format, const Args &...args)
{
  Internal::diagnostic ('I', string_format (format, args...));
}

// == Assertions ==
/// Return from the current function if @a cond is unmet and issue an assertion warning.
#define BSE_ASSERT_RETURN(cond, ...)     do { if (BSE_ISLIKELY (cond)) break; ::Bse::assertion_failed (__FILE__, __LINE__, #cond); return __VA_ARGS__; } while (0)
/// Return from the current function and issue an assertion warning.
#define BSE_ASSERT_RETURN_UNREACHED(...) do { ::Bse::assertion_failed (__FILE__, __LINE__, NULL); return __VA_ARGS__; } while (0)
#ifdef BSE_CONVENIENCE
/// Return from the current function if @a cond is unmet and issue an assertion warning.
#define assert_return(cond, ...)        BSE_ASSERT_RETURN (cond, __VA_ARGS__)
/// Return from the current function and issue an assertion warning.
#define assert_return_unreached(...)    BSE_ASSERT_RETURN_UNREACHED (__VA_ARGS__)
/// Hint to the compiler to optimize for @a cond == TRUE.
#define ISLIKELY(cond)  BSE_ISLIKELY (cond)
/// Hint to the compiler to optimize for @a cond == FALSE.
#define UNLIKELY(cond)  BSE_UNLIKELY (cond)
/// Return silently if @a cond does not evaluate to true with return value @a ...
#define return_unless(cond, ...)        BSE_RETURN_UNLESS (cond, __VA_ARGS__)
#endif // BSE_CONVENIENCE

// == Memory Utilities ==
int     fmsb          (uint64  word) BSE_CONST; ///< Find most significant bit set in a word.
void*   aligned_alloc (size_t  total_size, size_t alignment, uint8 **free_pointer);
void    aligned_free  (uint8 **free_pointer);

/// Class to maintain an array of aligned memory.
template<class T, int ALIGNMENT>
class AlignedArray {
  uint8 *unaligned_mem_;
  T     *data_;
  size_t n_elements_;
  void
  allocate_aligned_data()
  {
    static_assert (ALIGNMENT % sizeof (T) == 0, "ALIGNMENT must exactly fit a multiple of sizeof (T)");
    data_ = reinterpret_cast<T*> (aligned_alloc (n_elements_ * sizeof (T), ALIGNMENT, &unaligned_mem_));
  }
  // disallow copy constructor assignment operator
  RAPICORN_CLASS_NON_COPYABLE (AlignedArray);
public:
  AlignedArray (const vector<T>& elements) :
    n_elements_ (elements.size())
  {
    allocate_aligned_data();
    for (size_t i = 0; i < n_elements_; i++)
      new (data_ + i) T (elements[i]);
  }
  AlignedArray (size_t n_elements) :
    n_elements_ (n_elements)
  {
    allocate_aligned_data();
    for (size_t i = 0; i < n_elements_; i++)
      new (data_ + i) T();
  }
  ~AlignedArray()
  {
    // C++ destruction order: last allocated element is deleted first
    while (n_elements_)
      data_[--n_elements_].~T();
    aligned_free (&unaligned_mem_);
  }
  T&            operator[] (size_t pos)         { return data_[pos]; }
  const T&      operator[] (size_t pos) const   { return data_[pos]; }
  size_t        size       () const             { return n_elements_; }
};

// == Threading ==
/**
 * The Spinlock uses low-latency busy spinning to acquire locks.
 * This class is a thin wrapper around pthread_spin_lock() and related functions.
 * This class supports static construction.
 */
class Spinlock {
  pthread_spinlock_t spinlock_;
public:
  constexpr Spinlock    () : spinlock_ { BSE_SPINLOCK_INITIALIZER } {}
  void      lock        ()      { pthread_spin_lock (&spinlock_); }
  void      unlock      ()      { pthread_spin_unlock (&spinlock_); }
  bool      try_lock    ()      { return 0 == pthread_spin_trylock (&spinlock_); }
  typedef pthread_spinlock_t* native_handle_type;
  native_handle_type native_handle() { return &spinlock_; }
  /*ctor*/  Spinlock    (const Spinlock&) = delete;
  Spinlock& operator=   (const Spinlock&) = delete;
};

} // Bse

#endif // __BSE_BCORE_HH__
<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <vector>
#include <list>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <utility>
#include <iostream>
#include <streambuf>
#include <tuple>

namespace NSaveLoad {

template<class T, typename E = void>
class TSerializer {
public:
    static void Save(std::ostream& out, const T& object) {
        object.Save(out);
    }
    static void Load(std::istream& in, T& object) {
        object.Load(in);
    }
};

template <class T>
static inline void Save(std::ostream& out, const T& t);

template <class T>
static inline void Load(std::istream& in, T& t);

template <class A, class B>
class TSerializer<std::pair<A, B> > {
public:
    static void Save(std::ostream& out, const std::pair<A, B>& object) {
        NSaveLoad::Save(out, object.first);
        NSaveLoad::Save(out, object.second);
    }
    static void Load(std::istream& in, std::pair<A, B>& object) {
        NSaveLoad::Load(in, object.first);
        NSaveLoad::Load(in, object.second);
    }
};

template<std::size_t> struct int_{};

template <class Tuple, size_t Pos>
void SaveTuple(std::ostream& out, const Tuple& tuple, int_<Pos>) {
    SaveTuple(out, tuple, int_<Pos-1>());
    NSaveLoad::Save(out, std::get<std::tuple_size<Tuple>::value-Pos>(tuple));
}

template <class Tuple>
void SaveTuple(std::ostream& out, const Tuple& tuple, int_<1>) {
    NSaveLoad::Save(out, std::get<std::tuple_size<Tuple>::value-1>(tuple));
}

template <class Tuple, size_t Pos>
void LoadTuple(std::istream& in, Tuple& tuple, int_<Pos>) {
    LoadTuple(in, tuple, int_<Pos-1>());
    NSaveLoad::Load(in, std::get<std::tuple_size<Tuple>::value-Pos>(tuple));
}

template <class Tuple>
void LoadTuple(std::istream& in, Tuple& tuple, int_<1>) {
    NSaveLoad::Load(in, std::get<std::tuple_size<Tuple>::value-1>(tuple));
}

template <class... Args>
class TSerializer<std::tuple<Args...>> {
public:
    static void Save(std::ostream& out, const std::tuple<Args...>& object) {
        SaveTuple(out, object, int_<sizeof...(Args)>());
    }
    static void Load(std::istream& in, std::tuple<Args...>& object) {
        LoadTuple(in, object, int_<sizeof...(Args)>());
    }
};

template<class TVec, class TObj>
class TVectorSerializer {
public:
    static inline void Save(std::ostream& out, const TVec& object) {
        uint32_t size = object.size();
        out.write((const char*)(&size), sizeof(size));
        for (const auto& obj: object) {
            NSaveLoad::Save(out, obj);
        }
    }

    static inline void Load(std::istream& in, TVec& object) {
        uint32_t size;
        in.read((char*)(&size), sizeof(size));
        object.clear();
        for (size_t i = 0; i < size; ++i) {
            TObj obj;
            NSaveLoad::Load(in, obj);
            object.push_back(std::move(obj));
        }
    }
};

template<class TVec, class TKey, class TValue>
class TMapSerializer {
public:
    static inline void Save(std::ostream& out, const TVec& object) {
        uint32_t size = object.size();
        out.write((const char*)(&size), sizeof(size));
        for (const auto& obj: object) {
            NSaveLoad::Save(out, obj);
        }
    }

    static inline void Load(std::istream& in, TVec& object) {
        uint32_t size;
        in.read((char*)(&size), sizeof(size));
        object.clear();
        for (size_t i = 0; i < size; ++i) {
            std::pair<TKey, TValue> obj;
            NSaveLoad::Load(in, obj);
            object.insert(std::move(obj));
        }
    }
};

template<class TVec, class TObj>
class TSetSerializer {
public:
    static inline void Save(std::ostream& out, const TVec& object) {
        uint32_t size = object.size();
        out.write((const char*)(&size), sizeof(size));
        for (const auto& obj: object) {
            NSaveLoad::Save(out, obj);
        }
    }

    static inline void Load(std::istream& in, TVec& object) {
        uint32_t size;
        in.read((char*)(&size), sizeof(size));
        object.clear();
        for (size_t i = 0; i < size; ++i) {
            TObj obj;
            NSaveLoad::Load(in, obj);
            object.insert(std::move(obj));
        }
    }
};

template <class T> class TSerializer<std::vector<T> >: public TVectorSerializer<std::vector<T>, T > {};
template <class T> class TSerializer<std::list<T> >: public TVectorSerializer<std::list<T>, T > {};
template <> class TSerializer<std::string>: public TVectorSerializer<std::string, char> {};
template <> class TSerializer<std::wstring>: public TVectorSerializer<std::wstring, wchar_t> {};
template <class K, class V> class TSerializer<std::map<K, V> >: public TMapSerializer<std::map<K, V>, K, V > {};
template <class K, class V, class H> class TSerializer<std::unordered_map<K, V, H> >: public TMapSerializer<std::unordered_map<K, V, H>, K, V > {};
template <class T> class TSerializer<std::set<T> >: public TSetSerializer<std::set<T>, T > {};
template <class T> class TSerializer<std::unordered_set<T> >: public TSetSerializer<std::unordered_set<T>, T > {};

template <class T>
class TPodSerializer {
public:
    static inline void Save(std::ostream& out, const T& object) {
        out.write((const char*)(&object), sizeof(T));
    }
    static inline void Load(std::istream& in, T& object) {
        in.read((char*)(&object), sizeof(T));
    }
};

template<class T>
class TSerializer<T, typename std::enable_if<!std::is_class<T>::value>::type>: public TPodSerializer<T> {};

template <class T>
static inline void Save(std::ostream& out, const T& t) {
    TSerializer<T>::Save(out, t);
}

template<class T, class... Args>
static inline void Save(std::ostream& out, T first, Args... args) {
    NSaveLoad::Save(out, first);
    NSaveLoad::Save(out, args...);
}

template <class T>
static inline void Load(std::istream& in, T& t) {
    TSerializer<T>::Load(in, t);
}

template <class T, class... Args>
static inline void Load(std::istream& in, T& first, Args&... args) {
    NSaveLoad::Load(in, first);
    NSaveLoad::Load(in, args...);
}

#define SAVELOAD(...) \
    inline virtual void Save(std::ostream& out) const { \
        NSaveLoad::Save(out, __VA_ARGS__);             \
    } \
 \
    inline virtual void Load(std::istream& in) { \
        NSaveLoad::Load(in, __VA_ARGS__);             \
    }

struct membuf: std::streambuf {
    membuf(char const* base, size_t size) {
        char* p(const_cast<char*>(base));
        this->setg(p, p, p + size);
    }
};
struct imemstream: virtual membuf, std::istream {
    imemstream(char const* base, size_t size)
        : membuf(base, size)
        , std::istream(static_cast<std::streambuf*>(this)) {
    }
};

#define SAVELOAD_POD(TypeName) template <> class TSerializer<TypeName>: public TPodSerializer<TypeName> {};

} // NSaveLoad
<commit_msg>Added reserve call to vector and unordered_map<commit_after>#pragma once

#include <string>
#include <vector>
#include <list>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <utility>
#include <iostream>
#include <streambuf>
#include <tuple>

namespace NSaveLoad {

template<class T, typename E = void>
class TSerializer {
public:
    static void Save(std::ostream& out, const T& object) {
        object.Save(out);
    }
    static void Load(std::istream& in, T& object) {
        object.Load(in);
    }
};

template <class T>
static inline void Save(std::ostream& out, const T& t);

template <class T>
static inline void Load(std::istream& in, T& t);

template <class A, class B>
class TSerializer<std::pair<A, B> > {
public:
    static void Save(std::ostream& out, const std::pair<A, B>& object) {
        NSaveLoad::Save(out, object.first);
        NSaveLoad::Save(out, object.second);
    }
    static void Load(std::istream& in, std::pair<A, B>& object) {
        NSaveLoad::Load(in, object.first);
        NSaveLoad::Load(in, object.second);
    }
};

template<std::size_t> struct int_{};

template <class Tuple, size_t Pos>
void SaveTuple(std::ostream& out, const Tuple& tuple, int_<Pos>) {
    SaveTuple(out, tuple, int_<Pos-1>());
    NSaveLoad::Save(out, std::get<std::tuple_size<Tuple>::value-Pos>(tuple));
}

template <class Tuple>
void SaveTuple(std::ostream& out, const Tuple& tuple, int_<1>) {
    NSaveLoad::Save(out, std::get<std::tuple_size<Tuple>::value-1>(tuple));
}

template <class Tuple, size_t Pos>
void LoadTuple(std::istream& in, Tuple& tuple, int_<Pos>) {
    LoadTuple(in, tuple, int_<Pos-1>());
    NSaveLoad::Load(in, std::get<std::tuple_size<Tuple>::value-Pos>(tuple));
}

template <class Tuple>
void LoadTuple(std::istream& in, Tuple& tuple, int_<1>) {
    NSaveLoad::Load(in, std::get<std::tuple_size<Tuple>::value-1>(tuple));
}

template <class... Args>
class TSerializer<std::tuple<Args...>> {
public:
    static void Save(std::ostream& out, const std::tuple<Args...>& object) {
        SaveTuple(out, object, int_<sizeof...(Args)>());
    }
    static void Load(std::istream& in, std::tuple<Args...>& object) {
        LoadTuple(in, object, int_<sizeof...(Args)>());
    }
};

template<class TVec, class TObj>
class TVectorSerializer {
public:
    static inline void Save(std::ostream& out, const TVec& object) {
        uint32_t size = object.size();
        out.write((const char*)(&size), sizeof(size));
        for (const auto& obj: object) {
            NSaveLoad::Save(out, obj);
        }
    }

    static inline void Load(std::istream& in, TVec& object) {
        uint32_t size;
        in.read((char*)(&size), sizeof(size));
        object.clear();
        object.reserve(size);
        for (size_t i = 0; i < size; ++i) {
            TObj obj;
            NSaveLoad::Load(in, obj);
            object.push_back(std::move(obj));
        }
    }
};

template<class TVec, class TKey, class TValue>
class TMapSerializer {
public:
    static inline void Save(std::ostream& out, const TVec& object) {
        uint32_t size = object.size();
        out.write((const char*)(&size), sizeof(size));
        for (const auto& obj: object) {
            NSaveLoad::Save(out, obj);
        }
    }

    static inline void Load(std::istream& in, TVec& object) {
        uint32_t size;
        in.read((char*)(&size), sizeof(size));
        object.clear();
        for (size_t i = 0; i < size; ++i) {
            std::pair<TKey, TValue> obj;
            NSaveLoad::Load(in, obj);
            object.insert(std::move(obj));
        }
    }
};

template<class TVec, class TKey, class TValue>
class TUnorderedMapSerializer {
public:
    static inline void Save(std::ostream& out, const TVec& object) {
        uint32_t size = object.size();
        out.write((const char*)(&size), sizeof(size));
        for (const auto& obj: object) {
            NSaveLoad::Save(out, obj);
        }
    }

    static inline void Load(std::istream& in, TVec& object) {
        uint32_t size;
        in.read((char*)(&size), sizeof(size));
        object.clear();
        object.reserve(size);
        for (size_t i = 0; i < size; ++i) {
            std::pair<TKey, TValue> obj;
            NSaveLoad::Load(in, obj);
            object.insert(std::move(obj));
        }
    }
};

template<class TVec, class TObj>
class TSetSerializer {
public:
    static inline void Save(std::ostream& out, const TVec& object) {
        uint32_t size = object.size();
        out.write((const char*)(&size), sizeof(size));
        for (const auto& obj: object) {
            NSaveLoad::Save(out, obj);
        }
    }

    static inline void Load(std::istream& in, TVec& object) {
        uint32_t size;
        in.read((char*)(&size), sizeof(size));
        object.clear();
        for (size_t i = 0; i < size; ++i) {
            TObj obj;
            NSaveLoad::Load(in, obj);
            object.insert(std::move(obj));
        }
    }
};

template <class T> class TSerializer<std::vector<T> >: public TVectorSerializer<std::vector<T>, T > {};
template <class T> class TSerializer<std::list<T> >: public TVectorSerializer<std::list<T>, T > {};
template <> class TSerializer<std::string>: public TVectorSerializer<std::string, char> {};
template <> class TSerializer<std::wstring>: public TVectorSerializer<std::wstring, wchar_t> {};
template <class K, class V> class TSerializer<std::map<K, V> >: public TMapSerializer<std::map<K, V>, K, V > {};
template <class K, class V, class H> class TSerializer<std::unordered_map<K, V, H> >: public TUnorderedMapSerializer<std::unordered_map<K, V, H>, K, V > {};
template <class T> class TSerializer<std::set<T> >: public TSetSerializer<std::set<T>, T > {};
template <class T> class TSerializer<std::unordered_set<T> >: public TSetSerializer<std::unordered_set<T>, T > {};

template <class T>
class TPodSerializer {
public:
    static inline void Save(std::ostream& out, const T& object) {
        out.write((const char*)(&object), sizeof(T));
    }
    static inline void Load(std::istream& in, T& object) {
        in.read((char*)(&object), sizeof(T));
    }
};

template<class T>
class TSerializer<T, typename std::enable_if<!std::is_class<T>::value>::type>: public TPodSerializer<T> {};

template <class T>
static inline void Save(std::ostream& out, const T& t) {
    TSerializer<T>::Save(out, t);
}

template<class T, class... Args>
static inline void Save(std::ostream& out, T first, Args... args) {
    NSaveLoad::Save(out, first);
    NSaveLoad::Save(out, args...);
}

template <class T>
static inline void Load(std::istream& in, T& t) {
    TSerializer<T>::Load(in, t);
}

template <class T, class... Args>
static inline void Load(std::istream& in, T& first, Args&... args) {
    NSaveLoad::Load(in, first);
    NSaveLoad::Load(in, args...);
}

#define SAVELOAD(...) \
    inline virtual void Save(std::ostream& out) const { \
        NSaveLoad::Save(out, __VA_ARGS__);             \
    } \
 \
    inline virtual void Load(std::istream& in) { \
        NSaveLoad::Load(in, __VA_ARGS__);             \
    }

struct membuf: std::streambuf {
    membuf(char const* base, size_t size) {
        char* p(const_cast<char*>(base));
        this->setg(p, p, p + size);
    }
};
struct imemstream: virtual membuf, std::istream {
    imemstream(char const* base, size_t size)
        : membuf(base, size)
        , std::istream(static_cast<std::streambuf*>(this)) {
    }
};

#define SAVELOAD_POD(TypeName) template <> class TSerializer<TypeName>: public TPodSerializer<TypeName> {};

} // NSaveLoad
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <typeinfo>
#include <typeindex>
#include <memory>
#include <string>
#include <vector>

using namespace std;

#if 0
class object_t
{
  public:
    virtual ~object_t() {}
    virtual void draw(ostream&, size_t) const = 0;
};

using document_t = vector<shared_ptr<object_t>>;

void draw(const document_t& x, ostream& out, size_t position)
{
  out << string(position, ' ') << "<document>" << endl;
  for (const auto& e : x )
    e->draw(out, position + 2);
  out << string(position, ' ') << "</document>" << endl;
}

class my_class_t : public object_t
{
  public:
    void draw(ostream &out, size_t position) const
    {
      out << string(position, ' ') << "my_class_t" << endl;
    }
};

int main(int argc, char * argv[])
{
  document_t document;
  document.emplace_back(new my_class_t{});
  draw(document,cout, 1);
  return 0;
}
#else
class object_t
{
  public:
    template<typename T>
      object_t(T x) : self_(make_shared<model<T>>(move(x))) {}
    void draw(ostream& out, size_t position) const
    {
      self_->draw_(out,position);
    }

  private:
    struct concept_t
    {
      virtual ~concept_t() = default;
      virtual void draw_(ostream&, size_t) const = 0;
    };

    template<typename T>
    struct model : concept_t
    {
      model(T x) : data_(move(x)) {}
      void draw_(ostream& out, size_t position) const
      {
        data_.draw(out,position);
      }
      T data_;
    };

    shared_ptr<const concept_t> self_;
};

using document_t = vector<object_t>;

void draw(const document_t& x, ostream& out, size_t position)
{
  out << string(position, ' ') << "<document>" << endl;
  for (const auto& e : x )
    e.draw(out, position + 2);
  out << string(position, ' ') << "</document>" << endl;
}

class my_class_t
{
  public:
    void draw(ostream& out, size_t position) const
    {
      out << string(position, ' ') << "my_class_t" << endl;
    }
};

int main()
{
  document_t document;
  document.emplace_back(my_class_t{});
  draw(document,cout,0);
}
#endif
<commit_msg>added few more classes<commit_after>#include <iostream>
#include <string>
#include <typeinfo>
#include <typeindex>
#include <memory>
#include <string>
#include <vector>

using namespace std;

#if 0
class object_t
{
  public:
    virtual ~object_t() {}
    virtual void draw(ostream&, size_t) const = 0;
};

using document_t = vector<shared_ptr<object_t>>;

void draw(const document_t& x, ostream& out, size_t position)
{
  out << string(position, ' ') << "<document>" << endl;
  for (const auto& e : x )
    e->draw(out, position + 2);
  out << string(position, ' ') << "</document>" << endl;
}

class my_class_t : public object_t
{
  public:
    void draw(ostream &out, size_t position) const
    {
      out << string(position, ' ') << "my_class_t" << endl;
    }
};

int main(int argc, char * argv[])
{
  document_t document;
  document.emplace_back(new my_class_t{});
  draw(document,cout, 1);
  return 0;
}
#else
class object_t
{
  public:
    template<typename T>
      object_t(T x) : self_(make_shared<model<T>>(move(x))) {}
    void draw(ostream& out, size_t position) const
    {
      self_->draw_(out,position);
    }

  private:
    struct concept_t
    {
      virtual ~concept_t() = default;
      virtual void draw_(ostream&, size_t) const = 0;
    };

    template<typename T>
    struct model : concept_t
    {
      model(T x) : data_(move(x)) {}
      void draw_(ostream& out, size_t position) const
      {
        data_.draw(out,position);
      }
      T data_;
    };

    shared_ptr<const concept_t> self_;
};

using document_t = vector<object_t>;

void draw(const document_t& x, ostream& out, size_t position)
{
  out << string(position, ' ') << "<document>" << endl;
  for (const auto& e : x )
    e.draw(out, position + 2);
  out << string(position, ' ') << "</document>" << endl;
}

class my_class_t
{
  public:
    void draw(ostream& out, size_t position) const
    {
      out << string(position, ' ') << "my_class_t" << endl;
    }
};

class book_t
{
  public:
  string name;
    void draw(ostream& out, size_t position) const
    {
      out << string(position, ' ') << "book_t{" << name << "}" << endl;
    }
};
class name_t
{
  public:
  string name;
    void draw(ostream& out, size_t position) const
    {
      out << string(position, ' ') << "name_t{" << name << "}" << endl;
    }
};

int main()
{
  document_t document;
  document.emplace_back(my_class_t{});
  document.emplace_back(book_t{"book1"});
  document.emplace_back(name_t{"name1"});
  document.emplace_back(book_t{"book2"});
  document.emplace_back(name_t{"name2"});
  document.emplace_back(my_class_t{});
  draw(document,cout,0);
}
#endif
<|endoftext|>


<commit_before>#include "factory.h"
#include "except.h"
#include "iobservable.h"
#include "gil.h"
#ifdef USE_OPENCV
#include "opencv_video_source.h"
#include "opencv_video_target.h"
#endif // USE_OPENCV
#ifdef USE_EPIPHANSDK
#include "epiphansdk_video_source.h"
#endif
#ifdef USE_LIBVLC
#include "vlc_video_source.h"
#endif
#ifdef USE_FFMPEG
#include "ffmpeg_video_target.h"
#endif
#include <boost/python.hpp>
#include <boost/python/exception_translator.hpp>

using namespace boost::python;

class IObservableWrapper : public gg::IObservable, public wrapper<gg::IObservable>
{
public:
    void attach(gg::IObserver & observer)
    {
        if (override f = this->get_override("attach"))
            f(boost::ref(observer));
        else
            gg::IObservable::attach(boost::ref(observer));
    }

    void default_attach(gg::IObserver & observer)
    {
        gg::IObservable::attach(observer);
    }

    void detach(gg::IObserver & observer)
    {
        if (override f = this->get_override("detach"))
            f(boost::ref(observer));
        else
            gg::IObservable::detach(boost::ref(observer));
    }

    void default_detach(gg::IObserver & observer)
    {
        gg::IObservable::detach(boost::ref(observer));
    }
};

class IVideoSourceWrapper : IVideoSource, wrapper<IVideoSource>
{
    bool get_frame_dimensions(int & width, int & height)
    {
        return this->get_override("get_frame_dimensions")(width, height);
    }

    bool get_frame(gg::VideoFrame & frame)
    {
        return this->get_override("get_frame")(frame);
    }

    double get_frame_rate()
    {
        return this->get_override("get_frame_rate")();
    }

    void set_sub_frame(int x, int y, int width, int height)
    {
        this->get_override("set_sub_frame")(x, y, width, height);
    }

    void get_full_frame()
    {
        this->get_override("get_full_frame")();
    }
};

/* The inheritance should be public, in order to preserve
 * the public accessibility of the update() method. The
 * Boost.Python examples feature struct's rather than
 * classes, and in struct's everything is public by
 * definition.
 */
class IObserverWrapper : public gg::IObserver, public wrapper<gg::IObserver>
{
public:
    IObserverWrapper()
    {
        /* Default constructor that needs to be called within
         * child Python class, e.g. super(Child, self).__init__()
         * This is normally generated by the compiler
         * automatically, but we define it here explicitly so
         * that it can serve as an example for this complex case.
         */
    }

    void update(gg::VideoFrame & frame)
    {
        gg::ScopedPythonGILLock gil_lock;
        this->get_override("update")(boost::ref(frame));
    }
};

class IVideoTargetWrapper : gg::IVideoTarget, wrapper<gg::IVideoTarget>
{
    void init(const std::string filepath, const float framerate)
    {
        this->get_override("init")(filepath, framerate);
    }

    void append(const gg::VideoFrame & frame)
    {
        this->get_override("append")(frame);
    }

    void finalise()
    {
        this->get_override("finalise")();
    }
};

void translate_VideoSourceError(gg::VideoSourceError const & e)
{
    std::string msg;
    msg.append("VideoSourceError: ").append(e.what());
    PyErr_SetString(PyExc_RuntimeError, msg.c_str());
}

void translate_DeviceNotFound(gg::DeviceNotFound const & e)
{
    std::string msg;
    msg.append("DeviceNotFound: ").append(e.what());
    PyErr_SetString(PyExc_IOError, msg.c_str());
}

void translate_DeviceOffline(gg::DeviceOffline const & e)
{
    std::string msg;
    msg.append("DeviceOffline: ").append(e.what());
    PyErr_SetString(PyExc_IOError, msg.c_str());
}

void translate_VideoTargetError(gg::VideoTargetError const & e)
{
    std::string msg;
    msg.append("VideoTargetError: ").append(e.what());
    PyErr_SetString(PyExc_RuntimeError, msg.c_str());
}

void translate_ObserverError(gg::ObserverError const & e)
{
    std::string msg;
    msg.append("ObserverError: ").append(e.what());
    PyErr_SetString(PyExc_RuntimeError, msg.c_str());
}

BOOST_PYTHON_MODULE(pygiftgrab)
{
    PyEval_InitThreads();

    register_exception_translator<gg::VideoSourceError>(&translate_VideoSourceError);
    register_exception_translator<gg::DeviceNotFound>(&translate_DeviceNotFound);
    register_exception_translator<gg::DeviceOffline>(&translate_DeviceOffline);
    register_exception_translator<gg::VideoTargetError>(&translate_VideoTargetError);
    register_exception_translator<gg::ObserverError>(&translate_ObserverError);

    enum_<gg::ColourSpace>("ColourSpace")
        .value("BGRA", gg::ColourSpace::BGRA)
        .value("I420", gg::ColourSpace::I420)
    ;

    enum_<gg::Device>("Device")
        .value("DVI2PCIeDuo_SDI", gg::Device::DVI2PCIeDuo_SDI)
        .value("DVI2PCIeDuo_DVI", gg::Device::DVI2PCIeDuo_DVI)
    ;

    enum_<gg::Storage>("Storage")
        .value("File_HEVC", gg::Storage::File_HEVC)
        .value("File_XviD", gg::Storage::File_XviD)
        .value("File_VP9", gg::Storage::File_VP9)
    ;

    class_<gg::VideoFrame>("VideoFrame", init<enum gg::ColourSpace, bool>())
        .def(init<enum gg::ColourSpace, const size_t, const size_t>())
        .def("rows", &gg::VideoFrame::rows)
        .def("cols", &gg::VideoFrame::cols)
    ;

    class_<IObservableWrapper,boost::noncopyable>("IObservable", no_init)
        .def("attach", &IObservableWrapper::attach)
        .def("detach", &IObservableWrapper::detach)
    ;

    class_<IVideoSource, bases<gg::IObservable>, boost::noncopyable>(
                "IVideoSource", no_init)
    ;

#ifdef USE_OPENCV
    class_<VideoSourceOpenCV, bases<IVideoSource>, boost::noncopyable>(
                "VideoSourceOpenCV", init<int>())
        .def(init<char *>())
        .def("get_frame", &VideoSourceOpenCV::get_frame)
        .def("get_frame_dimensions", &VideoSourceOpenCV::get_frame_dimensions)
        .def("get_frame_rate", &VideoSourceOpenCV::get_frame_rate)
        .def("set_sub_frame", &VideoSourceOpenCV::set_sub_frame)
        .def("get_full_frame", &VideoSourceOpenCV::get_full_frame)
        .def("attach", &gg::IObservable::attach, &IObservableWrapper::default_attach)
        .def("detach", &gg::IObservable::detach, &IObservableWrapper::default_detach)
    ;
#endif // USE_OPENCV

#ifdef USE_EPIPHANSDK
    class_<gg::VideoSourceEpiphanSDK, bases<IVideoSource>, boost::noncopyable>(
                "VideoSourceEpiphanSDK", init<const std::string, const V2U_INT32>())
        .def("get_frame", &gg::VideoSourceEpiphanSDK::get_frame)
        .def("get_frame_dimensions", &gg::VideoSourceEpiphanSDK::get_frame_dimensions)
        .def("get_frame_rate", &gg::VideoSourceEpiphanSDK::get_frame_rate)
        .def("set_sub_frame", &gg::VideoSourceEpiphanSDK::set_sub_frame)
        .def("get_full_frame", &gg::VideoSourceEpiphanSDK::get_full_frame)
    ;
#endif

#ifdef USE_LIBVLC
    class_<gg::VideoSourceVLC, bases<IVideoSource>, boost::noncopyable>(
                "VideoSourceVLC", init<const std::string>())
        .def("get_frame", &gg::VideoSourceVLC::get_frame)
        .def("get_frame_dimensions", &gg::VideoSourceVLC::get_frame_dimensions)
        .def("get_frame_rate", &gg::VideoSourceVLC::get_frame_rate)
        .def("set_sub_frame", &gg::VideoSourceVLC::set_sub_frame)
        .def("get_full_frame", &gg::VideoSourceVLC::get_full_frame)
    ;
#endif

    class_<IObserverWrapper, boost::noncopyable>("IObserver")
        .def("update", pure_virtual(&gg::IObserver::update))
    ;

    class_<gg::IVideoTarget, bases<gg::IObserver>, boost::noncopyable>(
                "IVideoTarget", no_init)
        .def("update", &gg::IVideoTarget::update)
    ;

#ifdef USE_FFMPEG
    class_<gg::VideoTargetFFmpeg, bases<gg::IVideoTarget>, boost::noncopyable>(
                "VideoTargetFFmpeg", init<std::string>())
        .def("init", &gg::VideoTargetFFmpeg::init)
        .def("append", &gg::VideoTargetFFmpeg::append)
        .def("finalise", &gg::VideoTargetFFmpeg::finalise)
    ;
#endif

#ifdef USE_OPENCV
    class_<gg::VideoTargetOpenCV, bases<gg::IVideoTarget>, boost::noncopyable>(
                "VideoTargetOpenCV", init<std::string>())
        .def("init", &gg::VideoTargetOpenCV::init)
        .def("append", &gg::VideoTargetOpenCV::append)
        .def("finalise", &gg::VideoTargetOpenCV::finalise)
    ;
#endif // USE_OPENCV

    class_<gg::Factory>("Factory", no_init)
        .def("connect", &gg::Factory::connect,
             /* because client should never delete returned
              * object on its own, but should rather call
              * disconnect when done
              */
             return_value_policy<reference_existing_object>())
        .staticmethod("connect")
        .def("disconnect", &gg::Factory::disconnect)
        .staticmethod("disconnect")
        .def("writer", &gg::Factory::writer,
             // because ownership is passed to client
             return_value_policy<manage_new_object>())
        .staticmethod("writer")
    ;
}
<commit_msg>Issue #86: attach and detach exposed for VLC video source as well in wrapper<commit_after>#include "factory.h"
#include "except.h"
#include "iobservable.h"
#include "gil.h"
#ifdef USE_OPENCV
#include "opencv_video_source.h"
#include "opencv_video_target.h"
#endif // USE_OPENCV
#ifdef USE_EPIPHANSDK
#include "epiphansdk_video_source.h"
#endif
#ifdef USE_LIBVLC
#include "vlc_video_source.h"
#endif
#ifdef USE_FFMPEG
#include "ffmpeg_video_target.h"
#endif
#include <boost/python.hpp>
#include <boost/python/exception_translator.hpp>

using namespace boost::python;

class IObservableWrapper : public gg::IObservable, public wrapper<gg::IObservable>
{
public:
    void attach(gg::IObserver & observer)
    {
        if (override f = this->get_override("attach"))
            f(boost::ref(observer));
        else
            gg::IObservable::attach(boost::ref(observer));
    }

    void default_attach(gg::IObserver & observer)
    {
        gg::IObservable::attach(observer);
    }

    void detach(gg::IObserver & observer)
    {
        if (override f = this->get_override("detach"))
            f(boost::ref(observer));
        else
            gg::IObservable::detach(boost::ref(observer));
    }

    void default_detach(gg::IObserver & observer)
    {
        gg::IObservable::detach(boost::ref(observer));
    }
};

class IVideoSourceWrapper : IVideoSource, wrapper<IVideoSource>
{
    bool get_frame_dimensions(int & width, int & height)
    {
        return this->get_override("get_frame_dimensions")(width, height);
    }

    bool get_frame(gg::VideoFrame & frame)
    {
        return this->get_override("get_frame")(frame);
    }

    double get_frame_rate()
    {
        return this->get_override("get_frame_rate")();
    }

    void set_sub_frame(int x, int y, int width, int height)
    {
        this->get_override("set_sub_frame")(x, y, width, height);
    }

    void get_full_frame()
    {
        this->get_override("get_full_frame")();
    }
};

/* The inheritance should be public, in order to preserve
 * the public accessibility of the update() method. The
 * Boost.Python examples feature struct's rather than
 * classes, and in struct's everything is public by
 * definition.
 */
class IObserverWrapper : public gg::IObserver, public wrapper<gg::IObserver>
{
public:
    IObserverWrapper()
    {
        /* Default constructor that needs to be called within
         * child Python class, e.g. super(Child, self).__init__()
         * This is normally generated by the compiler
         * automatically, but we define it here explicitly so
         * that it can serve as an example for this complex case.
         */
    }

    void update(gg::VideoFrame & frame)
    {
        gg::ScopedPythonGILLock gil_lock;
        this->get_override("update")(boost::ref(frame));
    }
};

class IVideoTargetWrapper : gg::IVideoTarget, wrapper<gg::IVideoTarget>
{
    void init(const std::string filepath, const float framerate)
    {
        this->get_override("init")(filepath, framerate);
    }

    void append(const gg::VideoFrame & frame)
    {
        this->get_override("append")(frame);
    }

    void finalise()
    {
        this->get_override("finalise")();
    }
};

void translate_VideoSourceError(gg::VideoSourceError const & e)
{
    std::string msg;
    msg.append("VideoSourceError: ").append(e.what());
    PyErr_SetString(PyExc_RuntimeError, msg.c_str());
}

void translate_DeviceNotFound(gg::DeviceNotFound const & e)
{
    std::string msg;
    msg.append("DeviceNotFound: ").append(e.what());
    PyErr_SetString(PyExc_IOError, msg.c_str());
}

void translate_DeviceOffline(gg::DeviceOffline const & e)
{
    std::string msg;
    msg.append("DeviceOffline: ").append(e.what());
    PyErr_SetString(PyExc_IOError, msg.c_str());
}

void translate_VideoTargetError(gg::VideoTargetError const & e)
{
    std::string msg;
    msg.append("VideoTargetError: ").append(e.what());
    PyErr_SetString(PyExc_RuntimeError, msg.c_str());
}

void translate_ObserverError(gg::ObserverError const & e)
{
    std::string msg;
    msg.append("ObserverError: ").append(e.what());
    PyErr_SetString(PyExc_RuntimeError, msg.c_str());
}

BOOST_PYTHON_MODULE(pygiftgrab)
{
    PyEval_InitThreads();

    register_exception_translator<gg::VideoSourceError>(&translate_VideoSourceError);
    register_exception_translator<gg::DeviceNotFound>(&translate_DeviceNotFound);
    register_exception_translator<gg::DeviceOffline>(&translate_DeviceOffline);
    register_exception_translator<gg::VideoTargetError>(&translate_VideoTargetError);
    register_exception_translator<gg::ObserverError>(&translate_ObserverError);

    enum_<gg::ColourSpace>("ColourSpace")
        .value("BGRA", gg::ColourSpace::BGRA)
        .value("I420", gg::ColourSpace::I420)
    ;

    enum_<gg::Device>("Device")
        .value("DVI2PCIeDuo_SDI", gg::Device::DVI2PCIeDuo_SDI)
        .value("DVI2PCIeDuo_DVI", gg::Device::DVI2PCIeDuo_DVI)
    ;

    enum_<gg::Storage>("Storage")
        .value("File_HEVC", gg::Storage::File_HEVC)
        .value("File_XviD", gg::Storage::File_XviD)
        .value("File_VP9", gg::Storage::File_VP9)
    ;

    class_<gg::VideoFrame>("VideoFrame", init<enum gg::ColourSpace, bool>())
        .def(init<enum gg::ColourSpace, const size_t, const size_t>())
        .def("rows", &gg::VideoFrame::rows)
        .def("cols", &gg::VideoFrame::cols)
    ;

    class_<IObservableWrapper,boost::noncopyable>("IObservable", no_init)
        .def("attach", &IObservableWrapper::attach)
        .def("detach", &IObservableWrapper::detach)
    ;

    class_<IVideoSource, bases<gg::IObservable>, boost::noncopyable>(
                "IVideoSource", no_init)
    ;

#ifdef USE_OPENCV
    class_<VideoSourceOpenCV, bases<IVideoSource>, boost::noncopyable>(
                "VideoSourceOpenCV", init<int>())
        .def(init<char *>())
        .def("get_frame", &VideoSourceOpenCV::get_frame)
        .def("get_frame_dimensions", &VideoSourceOpenCV::get_frame_dimensions)
        .def("get_frame_rate", &VideoSourceOpenCV::get_frame_rate)
        .def("set_sub_frame", &VideoSourceOpenCV::set_sub_frame)
        .def("get_full_frame", &VideoSourceOpenCV::get_full_frame)
        .def("attach", &gg::IObservable::attach, &IObservableWrapper::default_attach)
        .def("detach", &gg::IObservable::detach, &IObservableWrapper::default_detach)
    ;
#endif // USE_OPENCV

#ifdef USE_EPIPHANSDK
    class_<gg::VideoSourceEpiphanSDK, bases<IVideoSource>, boost::noncopyable>(
                "VideoSourceEpiphanSDK", init<const std::string, const V2U_INT32>())
        .def("get_frame", &gg::VideoSourceEpiphanSDK::get_frame)
        .def("get_frame_dimensions", &gg::VideoSourceEpiphanSDK::get_frame_dimensions)
        .def("get_frame_rate", &gg::VideoSourceEpiphanSDK::get_frame_rate)
        .def("set_sub_frame", &gg::VideoSourceEpiphanSDK::set_sub_frame)
        .def("get_full_frame", &gg::VideoSourceEpiphanSDK::get_full_frame)
    ;
#endif

#ifdef USE_LIBVLC
    class_<gg::VideoSourceVLC, bases<IVideoSource>, boost::noncopyable>(
                "VideoSourceVLC", init<const std::string>())
        .def("get_frame", &gg::VideoSourceVLC::get_frame)
        .def("get_frame_dimensions", &gg::VideoSourceVLC::get_frame_dimensions)
        .def("get_frame_rate", &gg::VideoSourceVLC::get_frame_rate)
        .def("set_sub_frame", &gg::VideoSourceVLC::set_sub_frame)
        .def("get_full_frame", &gg::VideoSourceVLC::get_full_frame)
        .def("attach", &gg::IObservable::attach, &IObservableWrapper::default_attach)
        .def("detach", &gg::IObservable::detach, &IObservableWrapper::default_detach)
    ;
#endif

    class_<IObserverWrapper, boost::noncopyable>("IObserver")
        .def("update", pure_virtual(&gg::IObserver::update))
    ;

    class_<gg::IVideoTarget, bases<gg::IObserver>, boost::noncopyable>(
                "IVideoTarget", no_init)
        .def("update", &gg::IVideoTarget::update)
    ;

#ifdef USE_FFMPEG
    class_<gg::VideoTargetFFmpeg, bases<gg::IVideoTarget>, boost::noncopyable>(
                "VideoTargetFFmpeg", init<std::string>())
        .def("init", &gg::VideoTargetFFmpeg::init)
        .def("append", &gg::VideoTargetFFmpeg::append)
        .def("finalise", &gg::VideoTargetFFmpeg::finalise)
    ;
#endif

#ifdef USE_OPENCV
    class_<gg::VideoTargetOpenCV, bases<gg::IVideoTarget>, boost::noncopyable>(
                "VideoTargetOpenCV", init<std::string>())
        .def("init", &gg::VideoTargetOpenCV::init)
        .def("append", &gg::VideoTargetOpenCV::append)
        .def("finalise", &gg::VideoTargetOpenCV::finalise)
    ;
#endif // USE_OPENCV

    class_<gg::Factory>("Factory", no_init)
        .def("connect", &gg::Factory::connect,
             /* because client should never delete returned
              * object on its own, but should rather call
              * disconnect when done
              */
             return_value_policy<reference_existing_object>())
        .staticmethod("connect")
        .def("disconnect", &gg::Factory::disconnect)
        .staticmethod("disconnect")
        .def("writer", &gg::Factory::writer,
             // because ownership is passed to client
             return_value_policy<manage_new_object>())
        .staticmethod("writer")
    ;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "cpptoolsplugin.h"

#include "cppclassesfilter.h"
#include "cppcurrentdocumentfilter.h"
#include "cppfunctionsfilter.h"
#include "cpplocatorfilter.h"
#include "cppmodelmanager.h"

#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/testdatadir.h>
#include <extensionsystem/pluginmanager.h>
#include <locator/locatorfiltertest.h>
#include <utils/fileutils.h>

#include <QDebug>
#include <QFileInfo>
#include <QtTest>

using namespace Core;
using namespace Core::Internal::Tests;
using namespace CppTools::Internal;
using namespace ExtensionSystem;
using namespace Locator;
using namespace Locator::Internal;
using namespace Locator::Internal::Tests;
using namespace Utils;

Q_DECLARE_METATYPE(ILocatorFilter *)

namespace {

class MyTestDataDir : public Core::Internal::Tests::TestDataDir
{
public:
    MyTestDataDir(const QString &testDataDirectory)
        : TestDataDir(QLatin1String(SRCDIR "/../../../tests/cpplocators/") + testDataDirectory) {}
};

class CppLocatorFilterTest : public BasicLocatorFilterTest
{
public:
    CppLocatorFilterTest(ILocatorFilter *filter, const QString &fileName)
        : BasicLocatorFilterTest(filter)
        , m_modelManager(CppModelManager::instance())
        , m_fileName(fileName)
    {
        QVERIFY(!m_fileName.isEmpty());
        m_modelManager->GC();
        QVERIFY(m_modelManager->snapshot().isEmpty());
    }

private:
    virtual void doBeforeLocatorRun()
    {
        m_modelManager->updateSourceFiles(QStringList() << m_fileName).waitForFinished();
        QVERIFY(m_modelManager->snapshot().contains(m_fileName));
        QCoreApplication::processEvents();
    }

    virtual void doAfterLocatorRun()
    {
        m_modelManager->GC();
        QVERIFY(m_modelManager->snapshot().isEmpty());
    }

    CppModelManager *m_modelManager;
    const QString m_fileName;
};

class CppCurrentDocumentFilterTest : public BasicLocatorFilterTest
{
public:
    CppCurrentDocumentFilterTest(const QString &fileName)
        : BasicLocatorFilterTest(PluginManager::getObject<CppCurrentDocumentFilter>())
        , m_modelManager(CppModelManager::instance())
        , m_editor(0)
        , m_fileName(fileName)
    {
        QVERIFY(!m_fileName.isEmpty());
        m_modelManager->GC();
        QVERIFY(m_modelManager->snapshot().isEmpty());
    }

private:
    virtual void doBeforeLocatorRun()
    {
        QVERIFY(EditorManager::documentModel()->openedDocuments().isEmpty());
        m_modelManager->GC();
        QVERIFY(m_modelManager->snapshot().isEmpty());

        m_editor = EditorManager::openEditor(m_fileName);
        QVERIFY(m_editor);
        while (!m_modelManager->snapshot().contains(m_fileName))
            QCoreApplication::processEvents();
    }

    virtual void doAfterLocatorRun()
    {
        EditorManager::instance()->closeEditor(m_editor, /*askAboutModifiedEditors=*/ false);
        QCoreApplication::processEvents();
        QVERIFY(EditorManager::documentModel()->openedDocuments().isEmpty());
        m_modelManager->GC();
        QVERIFY(m_modelManager->snapshot().isEmpty());
    }

    CppModelManager *m_modelManager;
    IEditor *m_editor;
    const QString m_fileName;
};

inline QString _(const QByteArray &ba) { return QString::fromLatin1(ba, ba.size()); }

} // anonymous namespace

void CppToolsPlugin::test_cpplocatorfilters_CppLocatorFilter()
{
    QFETCH(QString, testFile);
    QFETCH(ILocatorFilter *, filter);
    QFETCH(QString, searchText);
    QFETCH(ResultDataList, expectedResults);

    CppLocatorFilterTest test(filter, testFile);
    ResultDataList results = ResultData::fromFilterEntryList(test.matchesFor(searchText));
//    ResultData::printFilterEntries(results);
    QVERIFY(!results.isEmpty());
    QCOMPARE(expectedResults, results);
}

void CppToolsPlugin::test_cpplocatorfilters_CppLocatorFilter_data()
{
    QTest::addColumn<QString>("testFile");
    QTest::addColumn<ILocatorFilter *>("filter");
    QTest::addColumn<QString>("searchText");
    QTest::addColumn<ResultDataList>("expectedResults");

    ILocatorFilter *cppFunctionsFilter = PluginManager::getObject<CppFunctionsFilter>();
    ILocatorFilter *cppClassesFilter = PluginManager::getObject<CppClassesFilter>();
    ILocatorFilter *cppLocatorFilter = PluginManager::getObject<CppLocatorFilter>();

    MyTestDataDir testDirectory(QLatin1String("testdata_basic"));
    const QString testFile = testDirectory.file(QLatin1String("file1.cpp"));
    const QString testFileShort = FileUtils::shortNativePath(FileName::fromString(testFile));

    QTest::newRow("CppFunctionsFilter")
        << testFile
        << cppFunctionsFilter
        << QString::fromLatin1("myfunction")
        << (QList<ResultData>()
            << ResultData(_("myFunction(bool, int)"), testFileShort)
            << ResultData(_("myFunction(bool, int)"), _("MyNamespace"))
            << ResultData(_("myFunction(bool, int)"), _("<anonymous namespace>"))
           );

    QTest::newRow("CppClassesFilter")
        << testFile
        << cppClassesFilter
        << _("myclass")
        << (QList<ResultData>()
            << ResultData(_("MyClass"), testFileShort)
            << ResultData(_("MyClass"), _("MyNamespace"))
            << ResultData(_("MyClass"), _("<anonymous namespace>"))
           );

    QTest::newRow("CppLocatorFilter")
        << testFile
        << cppLocatorFilter
        << _("myclass")
        << (QList<ResultData>()
            << ResultData(_("MyClass"), testFileShort)
            << ResultData(_("MyClass::MyClass"), _("()"))
            << ResultData(_("MyClass::function2"), _("(bool, int)"))
            << ResultData(_("<anonymous namespace>::MyClass"), testFileShort)
            << ResultData(_("<anonymous namespace>::MyClass::MyClass"), _("()"))
            << ResultData(_("<anonymous namespace>::MyClass::function2"), _("(bool, int)"))
            << ResultData(_("MyNamespace::MyClass"), testFileShort)
            << ResultData(_("MyNamespace::MyClass::MyClass"), _("()"))
            << ResultData(_("MyNamespace::MyClass::function2"), _("(bool, int)"))
            );
}

void CppToolsPlugin::test_cpplocatorfilters_CppCurrentDocumentFilter()
{
    MyTestDataDir testDirectory(QLatin1String("testdata_basic"));
    const QString testFile = testDirectory.file(QLatin1String("file1.cpp"));

    QList<ResultData> expectedResults = QList<ResultData>()
        << ResultData(_("int myVariable"), _(""))
        << ResultData(_("myFunction(bool, int)"), _(""))
        << ResultData(_("MyEnum"), _(""))
        << ResultData(_("int V1"), _("MyEnum"))
        << ResultData(_("int V2"), _("MyEnum"))
        << ResultData(_("MyClass"), _(""))
        << ResultData(_("MyClass()"), _("MyClass"))
        << ResultData(_("function1()"), _("MyClass"))
        << ResultData(_("function2(bool, int)"), _("MyClass"))
        << ResultData(_("int myVariable"), _("MyNamespace"))
        << ResultData(_("myFunction(bool, int)"), _("MyNamespace"))
        << ResultData(_("MyEnum"), _("MyNamespace"))
        << ResultData(_("int V1"), _("MyNamespace::MyEnum"))
        << ResultData(_("int V2"), _("MyNamespace::MyEnum"))
        << ResultData(_("MyClass"), _("MyNamespace"))
        << ResultData(_("MyClass()"), _("MyNamespace::MyClass"))
        << ResultData(_("function1()"), _("MyNamespace::MyClass"))
        << ResultData(_("function2(bool, int)"), _("MyNamespace::MyClass"))
        << ResultData(_("int myVariable"), _("<anonymous namespace>"))
        << ResultData(_("myFunction(bool, int)"), _("<anonymous namespace>"))
        << ResultData(_("MyEnum"), _("<anonymous namespace>"))
        << ResultData(_("int V1"), _("<anonymous namespace>::MyEnum"))
        << ResultData(_("int V2"), _("<anonymous namespace>::MyEnum"))
        << ResultData(_("MyClass"), _("<anonymous namespace>"))
        << ResultData(_("MyClass()"), _("<anonymous namespace>::MyClass"))
        << ResultData(_("function1()"), _("<anonymous namespace>::MyClass"))
        << ResultData(_("function2(bool, int)"), _("<anonymous namespace>::MyClass"))
        ;

    CppCurrentDocumentFilterTest test(testFile);
    ResultDataList results = ResultData::fromFilterEntryList(test.matchesFor());
//    ResultData::printFilterEntries(results);
    QVERIFY(!results.isEmpty());
    QCOMPARE(expectedResults, results);
}
<commit_msg>CppTools: Tests: Correct input data in locator test case<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "cpptoolsplugin.h"

#include "cppclassesfilter.h"
#include "cppcurrentdocumentfilter.h"
#include "cppfunctionsfilter.h"
#include "cpplocatorfilter.h"
#include "cppmodelmanager.h"

#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/testdatadir.h>
#include <extensionsystem/pluginmanager.h>
#include <locator/locatorfiltertest.h>
#include <utils/fileutils.h>

#include <QDebug>
#include <QFileInfo>
#include <QtTest>

using namespace Core;
using namespace Core::Internal::Tests;
using namespace CppTools::Internal;
using namespace ExtensionSystem;
using namespace Locator;
using namespace Locator::Internal;
using namespace Locator::Internal::Tests;
using namespace Utils;

Q_DECLARE_METATYPE(ILocatorFilter *)

namespace {

class MyTestDataDir : public Core::Internal::Tests::TestDataDir
{
public:
    MyTestDataDir(const QString &testDataDirectory)
        : TestDataDir(QLatin1String(SRCDIR "/../../../tests/cpplocators/") + testDataDirectory) {}
};

class CppLocatorFilterTest : public BasicLocatorFilterTest
{
public:
    CppLocatorFilterTest(ILocatorFilter *filter, const QString &fileName)
        : BasicLocatorFilterTest(filter)
        , m_modelManager(CppModelManager::instance())
        , m_fileName(fileName)
    {
        QVERIFY(!m_fileName.isEmpty());
        m_modelManager->GC();
        QVERIFY(m_modelManager->snapshot().isEmpty());
    }

private:
    virtual void doBeforeLocatorRun()
    {
        m_modelManager->updateSourceFiles(QStringList() << m_fileName).waitForFinished();
        QVERIFY(m_modelManager->snapshot().contains(m_fileName));
        QCoreApplication::processEvents();
    }

    virtual void doAfterLocatorRun()
    {
        m_modelManager->GC();
        QVERIFY(m_modelManager->snapshot().isEmpty());
    }

    CppModelManager *m_modelManager;
    const QString m_fileName;
};

class CppCurrentDocumentFilterTest : public BasicLocatorFilterTest
{
public:
    CppCurrentDocumentFilterTest(const QString &fileName)
        : BasicLocatorFilterTest(PluginManager::getObject<CppCurrentDocumentFilter>())
        , m_modelManager(CppModelManager::instance())
        , m_editor(0)
        , m_fileName(fileName)
    {
        QVERIFY(!m_fileName.isEmpty());
        m_modelManager->GC();
        QVERIFY(m_modelManager->snapshot().isEmpty());
    }

private:
    virtual void doBeforeLocatorRun()
    {
        QVERIFY(EditorManager::documentModel()->openedDocuments().isEmpty());
        m_modelManager->GC();
        QVERIFY(m_modelManager->snapshot().isEmpty());

        m_editor = EditorManager::openEditor(m_fileName);
        QVERIFY(m_editor);
        while (!m_modelManager->snapshot().contains(m_fileName))
            QCoreApplication::processEvents();
    }

    virtual void doAfterLocatorRun()
    {
        EditorManager::instance()->closeEditor(m_editor, /*askAboutModifiedEditors=*/ false);
        QCoreApplication::processEvents();
        QVERIFY(EditorManager::documentModel()->openedDocuments().isEmpty());
        m_modelManager->GC();
        QVERIFY(m_modelManager->snapshot().isEmpty());
    }

    CppModelManager *m_modelManager;
    IEditor *m_editor;
    const QString m_fileName;
};

inline QString _(const QByteArray &ba) { return QString::fromLatin1(ba, ba.size()); }

} // anonymous namespace

void CppToolsPlugin::test_cpplocatorfilters_CppLocatorFilter()
{
    QFETCH(QString, testFile);
    QFETCH(ILocatorFilter *, filter);
    QFETCH(QString, searchText);
    QFETCH(ResultDataList, expectedResults);

    CppLocatorFilterTest test(filter, testFile);
    ResultDataList results = ResultData::fromFilterEntryList(test.matchesFor(searchText));
//    ResultData::printFilterEntries(results);
    QVERIFY(!results.isEmpty());
    QCOMPARE(expectedResults, results);
}

void CppToolsPlugin::test_cpplocatorfilters_CppLocatorFilter_data()
{
    QTest::addColumn<QString>("testFile");
    QTest::addColumn<ILocatorFilter *>("filter");
    QTest::addColumn<QString>("searchText");
    QTest::addColumn<ResultDataList>("expectedResults");

    ILocatorFilter *cppFunctionsFilter = PluginManager::getObject<CppFunctionsFilter>();
    ILocatorFilter *cppClassesFilter = PluginManager::getObject<CppClassesFilter>();
    ILocatorFilter *cppLocatorFilter = PluginManager::getObject<CppLocatorFilter>();

    MyTestDataDir testDirectory(QLatin1String("testdata_basic"));
    const QString testFile = testDirectory.file(QLatin1String("file1.cpp"));
    const QString testFileShort = FileUtils::shortNativePath(FileName::fromString(testFile));

    QTest::newRow("CppFunctionsFilter")
        << testFile
        << cppFunctionsFilter
        << QString::fromLatin1("myfunction")
        << (QList<ResultData>()
            << ResultData(_("myFunction(bool, int)"), testFileShort)
            << ResultData(_("myFunction(bool, int)"), _("MyNamespace"))
            << ResultData(_("myFunction(bool, int)"), _("<anonymous namespace>"))
           );

    QTest::newRow("CppClassesFilter")
        << testFile
        << cppClassesFilter
        << _("myclass")
        << (QList<ResultData>()
            << ResultData(_("MyClass"), testFileShort)
            << ResultData(_("MyClass"), _("MyNamespace"))
            << ResultData(_("MyClass"), _("<anonymous namespace>"))
           );

    QTest::newRow("CppLocatorFilter")
        << testFile
        << cppLocatorFilter
        << _("my")
        << (QList<ResultData>()
            << ResultData(_("MyClass"), testFileShort)
            << ResultData(_("MyClass::MyClass"), _("()"))
            << ResultData(_("MyClass::function2"), _("(bool, int)"))
            << ResultData(_("MyEnum"), testFileShort)
            << ResultData(_("MyNamespace::MyClass"), testFileShort)
            << ResultData(_("MyNamespace::MyClass::MyClass"), _("()"))
            << ResultData(_("MyNamespace::MyClass::function2"), _("(bool, int)"))
            << ResultData(_("MyNamespace::MyEnum"), testFileShort)
            << ResultData(_("MyNamespace::myFunction"), _("(bool, int)"))
            << ResultData(_("myFunction"), _("(bool, int)"))
            << ResultData(_("<anonymous namespace>::MyClass"), testFileShort)
            << ResultData(_("<anonymous namespace>::MyClass::MyClass"), _("()"))
            << ResultData(_("<anonymous namespace>::MyClass::function2"), _("(bool, int)"))
            << ResultData(_("<anonymous namespace>::MyEnum"), testFileShort)
            << ResultData(_("<anonymous namespace>::myFunction"), _("(bool, int)"))
            );
}

void CppToolsPlugin::test_cpplocatorfilters_CppCurrentDocumentFilter()
{
    MyTestDataDir testDirectory(QLatin1String("testdata_basic"));
    const QString testFile = testDirectory.file(QLatin1String("file1.cpp"));

    QList<ResultData> expectedResults = QList<ResultData>()
        << ResultData(_("int myVariable"), _(""))
        << ResultData(_("myFunction(bool, int)"), _(""))
        << ResultData(_("MyEnum"), _(""))
        << ResultData(_("int V1"), _("MyEnum"))
        << ResultData(_("int V2"), _("MyEnum"))
        << ResultData(_("MyClass"), _(""))
        << ResultData(_("MyClass()"), _("MyClass"))
        << ResultData(_("function1()"), _("MyClass"))
        << ResultData(_("function2(bool, int)"), _("MyClass"))
        << ResultData(_("int myVariable"), _("MyNamespace"))
        << ResultData(_("myFunction(bool, int)"), _("MyNamespace"))
        << ResultData(_("MyEnum"), _("MyNamespace"))
        << ResultData(_("int V1"), _("MyNamespace::MyEnum"))
        << ResultData(_("int V2"), _("MyNamespace::MyEnum"))
        << ResultData(_("MyClass"), _("MyNamespace"))
        << ResultData(_("MyClass()"), _("MyNamespace::MyClass"))
        << ResultData(_("function1()"), _("MyNamespace::MyClass"))
        << ResultData(_("function2(bool, int)"), _("MyNamespace::MyClass"))
        << ResultData(_("int myVariable"), _("<anonymous namespace>"))
        << ResultData(_("myFunction(bool, int)"), _("<anonymous namespace>"))
        << ResultData(_("MyEnum"), _("<anonymous namespace>"))
        << ResultData(_("int V1"), _("<anonymous namespace>::MyEnum"))
        << ResultData(_("int V2"), _("<anonymous namespace>::MyEnum"))
        << ResultData(_("MyClass"), _("<anonymous namespace>"))
        << ResultData(_("MyClass()"), _("<anonymous namespace>::MyClass"))
        << ResultData(_("function1()"), _("<anonymous namespace>::MyClass"))
        << ResultData(_("function2(bool, int)"), _("<anonymous namespace>::MyClass"))
        ;

    CppCurrentDocumentFilterTest test(testFile);
    ResultDataList results = ResultData::fromFilterEntryList(test.matchesFor());
//    ResultData::printFilterEntries(results);
    QVERIFY(!results.isEmpty());
    QCOMPARE(expectedResults, results);
}
<|endoftext|>


<commit_before>#pragma once

#include <depthai-shared/datatype/RawCameraControl.hpp>
#include <nlohmann/json.hpp>

#include "depthai-shared/common/CameraBoardSocket.hpp"
#include "depthai-shared/common/CameraImageOrientation.hpp"

namespace dai {

/**
 *  Specify properties for ColorCamera such as camera ID, ...
 */
struct ColorCameraProperties {
    static constexpr int AUTO = -1;

    struct IspScale {
        int32_t horizNumerator = 0;
        int32_t horizDenominator = 0;
        int32_t vertNumerator = 0;
        int32_t vertDenominator = 0;

        NLOHMANN_DEFINE_TYPE_INTRUSIVE(IspScale, horizNumerator, horizDenominator, vertNumerator, vertDenominator);
    };

    /**
     * Select the camera sensor resolution
     */
    enum class SensorResolution : int32_t { THE_1080_P, THE_1200_P, THE_4_K, THE_12_MP, THE_13_MP, THE_720_P, THE_800_P };

    /**
     * For 24 bit color these can be either RGB or BGR
     */
    enum class ColorOrder : int32_t { BGR, RGB };

    /*
     * Initial controls applied to ColorCamera node
     */
    RawCameraControl initialControl;

    /**
     * Which socket will color camera use
     */
    CameraBoardSocket boardSocket = CameraBoardSocket::AUTO;

    /**
     * Camera sensor image orientation / pixel readout
     */
    CameraImageOrientation imageOrientation = CameraImageOrientation::AUTO;

    /**
     * For 24 bit color these can be either RGB or BGR
     */
    ColorOrder colorOrder = ColorOrder::BGR;
    /**
     * Are colors interleaved (R1G1B1, R2G2B2, ...) or planar (R1R2..., G1G2..., B1B2)
     */
    bool interleaved = true;
    /**
     * Are values FP16 type (0.0 - 255.0)
     */
    bool fp16 = false;

    /**
     * Preview frame output height
     */
    uint32_t previewHeight = 300;
    /**
     * Preview frame output width
     */
    uint32_t previewWidth = 300;

    /**
     * Preview frame output width
     */
    int32_t videoWidth = AUTO;

    /**
     * Preview frame output height
     */
    int32_t videoHeight = AUTO;

    /**
     * Preview frame output width
     */
    int32_t stillWidth = AUTO;

    /**
     * Preview frame output height
     */
    int32_t stillHeight = AUTO;

    /**
     * Select the camera sensor resolution
     */
    SensorResolution resolution = SensorResolution::THE_1080_P;
    /**
     * Camera sensor FPS
     */
    float fps = 30.0;

    /**
     * Initial sensor crop, -1 signifies center crop
     */
    float sensorCropX = AUTO;
    float sensorCropY = AUTO;

    /**
     * Whether to wait for config at 'inputConfig' io
     */
    bool inputConfigSync = false;

    /**
     * Whether to keep aspect ratio of input (video size) or not
     */
    bool previewKeepAspectRatio = true;

    /**
     * Configure scaling for `isp` output.
     */
    IspScale ispScale;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ColorCameraProperties,
                                   initialControl,
                                   boardSocket,
                                   imageOrientation,
                                   colorOrder,
                                   interleaved,
                                   fp16,
                                   previewHeight,
                                   previewWidth,
                                   videoWidth,
                                   videoHeight,
                                   stillWidth,
                                   stillHeight,
                                   resolution,
                                   fps,
                                   sensorCropX,
                                   sensorCropY,
                                   inputConfigSync,
                                   previewKeepAspectRatio,
                                   ispScale);

}  // namespace dai
<commit_msg>Add 5MP color sensor resolution<commit_after>#pragma once

#include <depthai-shared/datatype/RawCameraControl.hpp>
#include <nlohmann/json.hpp>

#include "depthai-shared/common/CameraBoardSocket.hpp"
#include "depthai-shared/common/CameraImageOrientation.hpp"

namespace dai {

/**
 *  Specify properties for ColorCamera such as camera ID, ...
 */
struct ColorCameraProperties {
    static constexpr int AUTO = -1;

    struct IspScale {
        int32_t horizNumerator = 0;
        int32_t horizDenominator = 0;
        int32_t vertNumerator = 0;
        int32_t vertDenominator = 0;

        NLOHMANN_DEFINE_TYPE_INTRUSIVE(IspScale, horizNumerator, horizDenominator, vertNumerator, vertDenominator);
    };

    /**
     * Select the camera sensor resolution
     */
    enum class SensorResolution : int32_t { THE_1080_P, THE_1200_P, THE_4_K, THE_5_MP, THE_12_MP, THE_13_MP, THE_720_P, THE_800_P };

    /**
     * For 24 bit color these can be either RGB or BGR
     */
    enum class ColorOrder : int32_t { BGR, RGB };

    /*
     * Initial controls applied to ColorCamera node
     */
    RawCameraControl initialControl;

    /**
     * Which socket will color camera use
     */
    CameraBoardSocket boardSocket = CameraBoardSocket::AUTO;

    /**
     * Camera sensor image orientation / pixel readout
     */
    CameraImageOrientation imageOrientation = CameraImageOrientation::AUTO;

    /**
     * For 24 bit color these can be either RGB or BGR
     */
    ColorOrder colorOrder = ColorOrder::BGR;
    /**
     * Are colors interleaved (R1G1B1, R2G2B2, ...) or planar (R1R2..., G1G2..., B1B2)
     */
    bool interleaved = true;
    /**
     * Are values FP16 type (0.0 - 255.0)
     */
    bool fp16 = false;

    /**
     * Preview frame output height
     */
    uint32_t previewHeight = 300;
    /**
     * Preview frame output width
     */
    uint32_t previewWidth = 300;

    /**
     * Preview frame output width
     */
    int32_t videoWidth = AUTO;

    /**
     * Preview frame output height
     */
    int32_t videoHeight = AUTO;

    /**
     * Preview frame output width
     */
    int32_t stillWidth = AUTO;

    /**
     * Preview frame output height
     */
    int32_t stillHeight = AUTO;

    /**
     * Select the camera sensor resolution
     */
    SensorResolution resolution = SensorResolution::THE_1080_P;
    /**
     * Camera sensor FPS
     */
    float fps = 30.0;

    /**
     * Initial sensor crop, -1 signifies center crop
     */
    float sensorCropX = AUTO;
    float sensorCropY = AUTO;

    /**
     * Whether to wait for config at 'inputConfig' io
     */
    bool inputConfigSync = false;

    /**
     * Whether to keep aspect ratio of input (video size) or not
     */
    bool previewKeepAspectRatio = true;

    /**
     * Configure scaling for `isp` output.
     */
    IspScale ispScale;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ColorCameraProperties,
                                   initialControl,
                                   boardSocket,
                                   imageOrientation,
                                   colorOrder,
                                   interleaved,
                                   fp16,
                                   previewHeight,
                                   previewWidth,
                                   videoWidth,
                                   videoHeight,
                                   stillWidth,
                                   stillHeight,
                                   resolution,
                                   fps,
                                   sensorCropX,
                                   sensorCropY,
                                   inputConfigSync,
                                   previewKeepAspectRatio,
                                   ispScale);

}  // namespace dai
<|endoftext|>