<commit_before>#include "FileEvent.h"

// PUT
#include <specialized/osdetect.h>

#if defined(__linux__) && KERNEL_VERSION_CODE >= KERNEL_VERSION(2,6,13) /* Linux 2.6.13+ */

// POSIX++
# include <cstring>
# include <cassert>

// Linux
# include <sys/inotify.h>

// PUT
# include <cxxutils/vterm.h>

// file/directory flags
static constexpr uint8_t from_native_flags(const native_flags_t flags) noexcept
{
  return
      (flags & IN_ACCESS      ? FileEvent::ReadEvent     : 0) |
      (flags & IN_MODIFY      ? FileEvent::WriteEvent    : 0) |
      (flags & IN_ATTRIB      ? FileEvent::AttributeMod  : 0) |
      (flags & IN_MOVE_SELF   ? FileEvent::Moved         : 0) |
      (flags & IN_DELETE_SELF ? FileEvent::Deleted       : 0) ;
  //data.flags.SubCreated   = flags & IN_CREATE      ? 1 : 0;
  //data.flags.SubMoved     = flags & IN_MOVE        ? 1 : 0;
  //data.flags.SubDeleted   = flags & IN_DELETE      ? 1 : 0;
}

static constexpr native_flags_t to_native_flags(const uint8_t flags) noexcept
{
  return
      (flags & FileEvent::ReadEvent    ? native_flags_t(IN_ACCESS     ) : 0) | // File was accessed (read) (*).
      (flags & FileEvent::WriteEvent   ? native_flags_t(IN_MODIFY     ) : 0) | // File was modified (*).
      (flags & FileEvent::AttributeMod ? native_flags_t(IN_ATTRIB     ) : 0) | // Metadata changed, e.g., permissions, timestamps, extended attributes, link count (since Linux 2.6.25), UID, GID, etc. (*).
      (flags & FileEvent::Moved        ? native_flags_t(IN_MOVE_SELF  ) : 0) | // Watched File was moved.
      (flags & FileEvent::Deleted      ? native_flags_t(IN_DELETE_SELF) : 0);  // Watched File was deleted.
//        (flags & FileEvent::SubCreated   ? native_flags_t(IN_CREATE     ) : 0) | // File created in watched dir.
//        (flags & FileEvent::SubMoved     ? native_flags_t(IN_MOVE       ) : 0) | // File moved in watched dir.
//        (flags & FileEvent::SubDeleted   ? native_flags_t(IN_DELETE     ) : 0) ; // File deleted in watched dir.
}

struct FileEvent::platform_dependant // file notification (inotify)
{
  posix::fd_t fd;

  platform_dependant(void) noexcept
    : fd(posix::invalid_descriptor)
  {
    fd = ::inotify_init();
    flaw(fd == posix::invalid_descriptor,
         terminal::severe,,,
         "Unable to create an instance of inotify!: %s", std::strerror(errno));
    posix::fcntl(fd, F_SETFD, FD_CLOEXEC); // close on exec*()
  }

  ~platform_dependant(void) noexcept
  {
    posix::close(fd);
    fd = posix::invalid_descriptor;
  }

  posix::fd_t add(const char* path, FileEvent::Flags_t flags) noexcept
  {
    return ::inotify_add_watch(fd, path, to_native_flags(flags));
  }

  bool remove(posix::fd_t wd) noexcept
  {
    return ::inotify_rm_watch(fd, wd) == posix::success_response;
  }

  struct return_data
  {
    const char* name;
    FileEvent::Flags_t flags;
  };

#define INOTIFY_EVENT_SIZE   (sizeof(inotify_event) + NAME_MAX + 1)
  return_data read(posix::fd_t wd) const noexcept
  {
    static uint8_t buffer[INOTIFY_EVENT_SIZE * 16]; // buffer (holds a minimum of 16 inotify events)
    union {
      uint8_t* pos;
      inotify_event* event;
    };
    uint8_t* end;
    pos = buffer;
    do
    {
      end = pos + posix::read(wd, pos, sizeof(buffer) - (buffer - pos)); // read new chunk of inotify events
      while(pos < end) // iterate through the inotify events
      {
        if(event->wd == wd)
          return { event->name, from_native_flags(event->mask) };
        if(pos + sizeof(inotify_event) + event->len >= end) // check if next entry exceeds buffer
        {
          std::memmove(buffer, pos, end - pos); // move partial entry
          pos = buffer + (end - pos); // move to end of partial entry
          end = pos; // ensure exit
        }
        else
          pos += sizeof(inotify_event) + event->len; // move to next event
      }
    } while(end != buffer); // while there is still more to read
    return { nullptr, 0 }; // read the entire buffer and the event was never found!
  }

} FileEvent::s_platform;

FileEvent::FileEvent(const std::string& _file, Flags_t _flags) noexcept
  : m_file(_file),
    m_flags(_flags),
    m_fd(posix::invalid_descriptor)
{
  m_fd = s_platform.add(m_file.c_str(), m_flags);
  EventBackend::add(m_fd, EventBackend::SimplePollReadFlags,
                    [this](posix::fd_t lambda_fd, native_flags_t) noexcept
                    {
                      platform_dependant::return_data data = s_platform.read(lambda_fd);
                      assert(data.name != nullptr); // entry was found
                      assert(m_flags & data.flags); // flags match
                      assert(m_file == data.name); // name matches
                      if(data.name != nullptr) // just in case (should never be false)
                        Object::enqueue_copy<std::string, Flags_t>(activated, data.name, data.flags);
                    });
}

FileEvent::~FileEvent(void) noexcept
{
  assert(EventBackend::remove(m_fd, EventBackend::SimplePollReadFlags));
  assert(s_platform.remove(m_fd));
}

#elif defined(__darwin__)     /* Darwin 7+     */ || \
      defined(__DragonFly__)  /* DragonFly BSD */ || \
      (defined(__FreeBSD__) && KERNEL_VERSION_CODE >= KERNEL_VERSION(4,1,0))  /* FreeBSD 4.1+  */ || \
      (defined(__OpenBSD__) && KERNEL_VERSION_CODE >= KERNEL_VERSION(2,9,0))  /* OpenBSD 2.9+  */ || \
      (defined(__NetBSD__)  && KERNEL_VERSION_CODE >= KERNEL_VERSION(2,0,0))  /* NetBSD 2+     */

# include <sys/event.h> // kqueue

static constexpr native_flags_t composite_flag(uint16_t actions, int16_t filters, uint32_t flags) noexcept
  { return native_flags_t(actions) | (native_flags_t(uint16_t(filters)) << 16) | (native_flags_t(flags) << 32); }

static constexpr bool flag_subset(native_flags_t flags, native_flags_t subset)
  { return (flags & subset) == subset; }

// file flags
static constexpr uint8_t from_native_flags(const native_flags_t flags) noexcept
{
  return
#if defined(NOTE_READ)
      (flag_subset(flags, composite_flag(0, EVFILT_VNODE, NOTE_READ  )) ? FileEvent::ReadEvent    : 0) |
#endif
      (flag_subset(flags, composite_flag(0, EVFILT_VNODE, NOTE_WRITE )) ? FileEvent::WriteEvent   : 0) |
      (flag_subset(flags, composite_flag(0, EVFILT_VNODE, NOTE_ATTRIB)) ? FileEvent::AttributeMod : 0) |
      (flag_subset(flags, composite_flag(0, EVFILT_VNODE, NOTE_RENAME)) ? FileEvent::Moved        : 0) |
      (flag_subset(flags, composite_flag(0, EVFILT_VNODE, NOTE_DELETE)) ? FileEvent::Deleted      : 0) ;
}

static constexpr native_flags_t to_native_flags(const uint8_t flags) noexcept
{
  return
#if defined(NOTE_READ)
      (flags & FileEvent::ReadEvent     ? composite_flag(0, EVFILT_VNODE, NOTE_READ  ) : 0) |
#endif
      (flags & FileEvent::WriteEvent    ? composite_flag(0, EVFILT_VNODE, NOTE_WRITE ) : 0) |
      (flags & FileEvent::AttributeMod  ? composite_flag(0, EVFILT_VNODE, NOTE_ATTRIB) : 0) |
      (flags & FileEvent::Moved         ? composite_flag(0, EVFILT_VNODE, NOTE_RENAME) : 0) |
      (flags & FileEvent::Deleted       ? composite_flag(0, EVFILT_VNODE, NOTE_DELETE) : 0) ;
}

FileEvent::FileEvent(const std::string& _file, Flags_t _flags) noexcept
  : m_file(_file),
    m_flags(_flags),
    m_fd(posix::invalid_descriptor)
{
  m_fd = posix::open(m_file.c_str(), O_EVTONLY);
  EventBackend::add(m_fd, to_native_flags(m_flags), // connect FD with flags to signal
                    [this](posix::fd_t lambda_fd, native_flags_t lambda_flags) noexcept
                    { Object::enqueue_copy<std::string, Flags_t>(activated, m_file, from_native_flags(lambda_flags)); });
}

FileEvent::~FileEvent(void) noexcept
{
  EventBackend::remove(m_fd, to_native_flags(m_flags)); // disconnect FD with flags from signal
  posix::close(m_fd);
  m_fd = posix::invalid_descriptor;
}

#else
// POSIX++
# include <cstring>
# include <cassert>

// POSIX
# include <sys/stat.h>

// PUT
# include <cxxutils/vterm.h>
# include <specialized/TimerEvent.h>

enum {
  Read = 0,
  Write = 1,
};

template<typename T>
static inline bool data_identical(T& a, T& b) noexcept
{ return std::memcmp(&a, &b, sizeof(T)) == 0; }

struct FileEvent::platform_dependant // file notification (TimerEvent)
{
  struct eventinfo_t
  {
    posix::fd_t fd[2]; // two fds for pipe based communication
    const char* file;
    Flags_t flags;
    struct stat status;
    TimerEvent timer;
    uint32_t test_count;
  };

  std::unordered_map<posix::fd_t, eventinfo_t> events;

  posix::fd_t add(const char* file, Flags_t flags) noexcept
  {
    eventinfo_t data;
    data.file = file;
    data.flags = flags;
    data.test_count = 0;

    if(::lstat(file, &data.status) == posix::error_response ||
       !posix::pipe(data.fd))
      return posix::invalid_descriptor;

    posix::fd_t& readfd = data.fd[Read];
    posix::fcntl(readfd, F_SETFD, FD_CLOEXEC); // close on exec*()
    posix::donotblock(readfd); // don't block

    auto pair = events.emplace(readfd, data);
    if(!pair.second) // emplace failed
      return posix::invalid_descriptor;

    Object::connect(data.timer.expired,
                    Object::fslot_t<void>([this, pair](void) noexcept
                      { update(pair.first->second); }));

    data.timer.start(1000, true);
    return readfd;
  }

  void update(eventinfo_t& data) noexcept
  {
    Flags_t flags;
    struct stat status;
    if(::lstat(data.file, &status) == posix::success_response &&
       !data_identical(data.status, status))
    {
      flags.ReadEvent    = data_identical(data.status.st_atim, status.st_atim) ? 0 : 1;
      flags.WriteEvent   = data_identical(data.status.st_mtim, status.st_mtim) ? 0 : 1;
      flags.AttributeMod = data.status.st_mode == status.st_mode &&
                           data.status.st_uid  == status.st_uid &&
                           data.status.st_gid  == status.st_gid &&
                           data.status.st_rdev == status.st_rdev ? 0 : 1;
      flags.Moved        = data.status.st_dev  == status.st_dev &&
                           data.status.st_ino  == status.st_ino  ? 0 : 1;
    }
    else
    {
      switch(errno)
      {
        case EACCES: flags.AttributeMod = 1; break;
        case ENOTDIR:
        case ENOENT: flags.Deleted = 1; break; // file may be moved but assume it's deleted
      }
    }
    if(flags)
    {
      data.test_count = 0;
      posix::write(data.fd[Write], &flags, sizeof(flags));
    }
    if(flags.Deleted)
      remove(data.fd[Read]);
    else
    {
      if(data.test_count == 0)
        data.timer.start(1000, true); // test once per second
      else if(data.test_count == 10)
        data.timer.start(10000, true); // test every 10 seconds
      else if(data.test_count == 100)
        data.timer.start(100000, true); // test every 100 seconds
      data.test_count++;
    }
  }

  bool remove(posix::fd_t fd) noexcept
  {
    auto iter = events.find(fd);
    if(iter != events.end())
    {
      posix::close(iter->second.fd[Read]);
      posix::close(iter->second.fd[Write]);
      events.erase(iter);
      return true;
    }
    return false;
  }
} FileEvent::s_platform;

FileEvent::FileEvent(const std::string& _file, Flags_t _flags) noexcept
  : m_file(_file),
    m_flags(_flags),
    m_fd(posix::invalid_descriptor)
{
  m_fd = s_platform.add(m_file.c_str(), m_flags);
  EventBackend::add(m_fd, EventBackend::SimplePollReadFlags,
                    [this](posix::fd_t lambda_fd, native_flags_t) noexcept
                    {
                      Flags_t event_flags, new_flags;
                      while(posix::read(lambda_fd, &new_flags, sizeof(event_flags)) != posix::error_response) // read all events
                        event_flags = event_flags | new_flags; // compose new flag result
                      assert(m_flags & event_flags); // at least one flag matches
                      Object::enqueue(activated, m_file, event_flags);
                    });
}

FileEvent::~FileEvent(void) noexcept
{
  assert(EventBackend::remove(m_fd, EventBackend::SimplePollReadFlags));
  s_platform.remove(m_fd); // may already be deleted
}
#endif
<commit_msg>don't use lstate<commit_after>#include "FileEvent.h"

// PUT
#include <specialized/osdetect.h>

#if defined(__linux__) && KERNEL_VERSION_CODE >= KERNEL_VERSION(2,6,13) /* Linux 2.6.13+ */

// POSIX++
# include <cstring>
# include <cassert>

// Linux
# include <sys/inotify.h>

// PUT
# include <cxxutils/vterm.h>

// file/directory flags
static constexpr uint8_t from_native_flags(const native_flags_t flags) noexcept
{
  return
      (flags & IN_ACCESS      ? FileEvent::ReadEvent     : 0) |
      (flags & IN_MODIFY      ? FileEvent::WriteEvent    : 0) |
      (flags & IN_ATTRIB      ? FileEvent::AttributeMod  : 0) |
      (flags & IN_MOVE_SELF   ? FileEvent::Moved         : 0) |
      (flags & IN_DELETE_SELF ? FileEvent::Deleted       : 0) ;
  //data.flags.SubCreated   = flags & IN_CREATE      ? 1 : 0;
  //data.flags.SubMoved     = flags & IN_MOVE        ? 1 : 0;
  //data.flags.SubDeleted   = flags & IN_DELETE      ? 1 : 0;
}

static constexpr native_flags_t to_native_flags(const uint8_t flags) noexcept
{
  return
      (flags & FileEvent::ReadEvent    ? native_flags_t(IN_ACCESS     ) : 0) | // File was accessed (read) (*).
      (flags & FileEvent::WriteEvent   ? native_flags_t(IN_MODIFY     ) : 0) | // File was modified (*).
      (flags & FileEvent::AttributeMod ? native_flags_t(IN_ATTRIB     ) : 0) | // Metadata changed, e.g., permissions, timestamps, extended attributes, link count (since Linux 2.6.25), UID, GID, etc. (*).
      (flags & FileEvent::Moved        ? native_flags_t(IN_MOVE_SELF  ) : 0) | // Watched File was moved.
      (flags & FileEvent::Deleted      ? native_flags_t(IN_DELETE_SELF) : 0);  // Watched File was deleted.
//        (flags & FileEvent::SubCreated   ? native_flags_t(IN_CREATE     ) : 0) | // File created in watched dir.
//        (flags & FileEvent::SubMoved     ? native_flags_t(IN_MOVE       ) : 0) | // File moved in watched dir.
//        (flags & FileEvent::SubDeleted   ? native_flags_t(IN_DELETE     ) : 0) ; // File deleted in watched dir.
}

struct FileEvent::platform_dependant // file notification (inotify)
{
  posix::fd_t fd;

  platform_dependant(void) noexcept
    : fd(posix::invalid_descriptor)
  {
    fd = ::inotify_init();
    flaw(fd == posix::invalid_descriptor,
         terminal::severe,,,
         "Unable to create an instance of inotify!: %s", std::strerror(errno));
    posix::fcntl(fd, F_SETFD, FD_CLOEXEC); // close on exec*()
  }

  ~platform_dependant(void) noexcept
  {
    posix::close(fd);
    fd = posix::invalid_descriptor;
  }

  posix::fd_t add(const char* path, FileEvent::Flags_t flags) noexcept
  {
    return ::inotify_add_watch(fd, path, to_native_flags(flags));
  }

  bool remove(posix::fd_t wd) noexcept
  {
    return ::inotify_rm_watch(fd, wd) == posix::success_response;
  }

  struct return_data
  {
    const char* name;
    FileEvent::Flags_t flags;
  };

#define INOTIFY_EVENT_SIZE   (sizeof(inotify_event) + NAME_MAX + 1)
  return_data read(posix::fd_t wd) const noexcept
  {
    static uint8_t buffer[INOTIFY_EVENT_SIZE * 16]; // buffer (holds a minimum of 16 inotify events)
    union {
      uint8_t* pos;
      inotify_event* event;
    };
    uint8_t* end;
    pos = buffer;
    do
    {
      end = pos + posix::read(wd, pos, sizeof(buffer) - (buffer - pos)); // read new chunk of inotify events
      while(pos < end) // iterate through the inotify events
      {
        if(event->wd == wd)
          return { event->name, from_native_flags(event->mask) };
        if(pos + sizeof(inotify_event) + event->len >= end) // check if next entry exceeds buffer
        {
          std::memmove(buffer, pos, end - pos); // move partial entry
          pos = buffer + (end - pos); // move to end of partial entry
          end = pos; // ensure exit
        }
        else
          pos += sizeof(inotify_event) + event->len; // move to next event
      }
    } while(end != buffer); // while there is still more to read
    return { nullptr, 0 }; // read the entire buffer and the event was never found!
  }

} FileEvent::s_platform;

FileEvent::FileEvent(const std::string& _file, Flags_t _flags) noexcept
  : m_file(_file),
    m_flags(_flags),
    m_fd(posix::invalid_descriptor)
{
  m_fd = s_platform.add(m_file.c_str(), m_flags);
  EventBackend::add(m_fd, EventBackend::SimplePollReadFlags,
                    [this](posix::fd_t lambda_fd, native_flags_t) noexcept
                    {
                      platform_dependant::return_data data = s_platform.read(lambda_fd);
                      assert(data.name != nullptr); // entry was found
                      assert(m_flags & data.flags); // flags match
                      assert(m_file == data.name); // name matches
                      if(data.name != nullptr) // just in case (should never be false)
                        Object::enqueue_copy<std::string, Flags_t>(activated, data.name, data.flags);
                    });
}

FileEvent::~FileEvent(void) noexcept
{
  assert(EventBackend::remove(m_fd, EventBackend::SimplePollReadFlags));
  assert(s_platform.remove(m_fd));
}

#elif defined(__darwin__)     /* Darwin 7+     */ || \
      defined(__DragonFly__)  /* DragonFly BSD */ || \
      (defined(__FreeBSD__) && KERNEL_VERSION_CODE >= KERNEL_VERSION(4,1,0))  /* FreeBSD 4.1+  */ || \
      (defined(__OpenBSD__) && KERNEL_VERSION_CODE >= KERNEL_VERSION(2,9,0))  /* OpenBSD 2.9+  */ || \
      (defined(__NetBSD__)  && KERNEL_VERSION_CODE >= KERNEL_VERSION(2,0,0))  /* NetBSD 2+     */

# include <sys/event.h> // kqueue

static constexpr native_flags_t composite_flag(uint16_t actions, int16_t filters, uint32_t flags) noexcept
  { return native_flags_t(actions) | (native_flags_t(uint16_t(filters)) << 16) | (native_flags_t(flags) << 32); }

static constexpr bool flag_subset(native_flags_t flags, native_flags_t subset)
  { return (flags & subset) == subset; }

// file flags
static constexpr uint8_t from_native_flags(const native_flags_t flags) noexcept
{
  return
#if defined(NOTE_READ)
      (flag_subset(flags, composite_flag(0, EVFILT_VNODE, NOTE_READ  )) ? FileEvent::ReadEvent    : 0) |
#endif
      (flag_subset(flags, composite_flag(0, EVFILT_VNODE, NOTE_WRITE )) ? FileEvent::WriteEvent   : 0) |
      (flag_subset(flags, composite_flag(0, EVFILT_VNODE, NOTE_ATTRIB)) ? FileEvent::AttributeMod : 0) |
      (flag_subset(flags, composite_flag(0, EVFILT_VNODE, NOTE_RENAME)) ? FileEvent::Moved        : 0) |
      (flag_subset(flags, composite_flag(0, EVFILT_VNODE, NOTE_DELETE)) ? FileEvent::Deleted      : 0) ;
}

static constexpr native_flags_t to_native_flags(const uint8_t flags) noexcept
{
  return
#if defined(NOTE_READ)
      (flags & FileEvent::ReadEvent     ? composite_flag(0, EVFILT_VNODE, NOTE_READ  ) : 0) |
#endif
      (flags & FileEvent::WriteEvent    ? composite_flag(0, EVFILT_VNODE, NOTE_WRITE ) : 0) |
      (flags & FileEvent::AttributeMod  ? composite_flag(0, EVFILT_VNODE, NOTE_ATTRIB) : 0) |
      (flags & FileEvent::Moved         ? composite_flag(0, EVFILT_VNODE, NOTE_RENAME) : 0) |
      (flags & FileEvent::Deleted       ? composite_flag(0, EVFILT_VNODE, NOTE_DELETE) : 0) ;
}

FileEvent::FileEvent(const std::string& _file, Flags_t _flags) noexcept
  : m_file(_file),
    m_flags(_flags),
    m_fd(posix::invalid_descriptor)
{
  m_fd = posix::open(m_file.c_str(), O_EVTONLY);
  EventBackend::add(m_fd, to_native_flags(m_flags), // connect FD with flags to signal
                    [this](posix::fd_t lambda_fd, native_flags_t lambda_flags) noexcept
                    { Object::enqueue_copy<std::string, Flags_t>(activated, m_file, from_native_flags(lambda_flags)); });
}

FileEvent::~FileEvent(void) noexcept
{
  EventBackend::remove(m_fd, to_native_flags(m_flags)); // disconnect FD with flags from signal
  posix::close(m_fd);
  m_fd = posix::invalid_descriptor;
}

#else
// POSIX++
# include <cstring>
# include <cassert>

// POSIX
# include <sys/stat.h>

// PUT
# include <cxxutils/vterm.h>
# include <specialized/TimerEvent.h>

enum {
  Read = 0,
  Write = 1,
};

template<typename T>
static inline bool data_identical(T& a, T& b) noexcept
{ return std::memcmp(&a, &b, sizeof(T)) == 0; }

struct FileEvent::platform_dependant // file notification (TimerEvent)
{
  struct eventinfo_t
  {
    posix::fd_t fd[2]; // two fds for pipe based communication
    const char* file;
    Flags_t flags;
    struct stat status;
    TimerEvent timer;
    uint32_t test_count;
  };

  std::unordered_map<posix::fd_t, eventinfo_t> events;

  posix::fd_t add(const char* file, Flags_t flags) noexcept
  {
    eventinfo_t data;
    data.file = file;
    data.flags = flags;
    data.test_count = 0;

    if(::stat(file, &data.status) == posix::error_response ||
       !posix::pipe(data.fd))
      return posix::invalid_descriptor;

    posix::fd_t& readfd = data.fd[Read];
    posix::fcntl(readfd, F_SETFD, FD_CLOEXEC); // close on exec*()
    posix::donotblock(readfd); // don't block

    auto pair = events.emplace(readfd, data);
    if(!pair.second) // emplace failed
      return posix::invalid_descriptor;

    Object::connect(data.timer.expired,
                    Object::fslot_t<void>([this, pair](void) noexcept
                      { update(pair.first->second); }));

    data.timer.start(1000, true);
    return readfd;
  }

  void update(eventinfo_t& data) noexcept
  {
    Flags_t flags;
    struct stat status;
    if(::stat(data.file, &status) == posix::success_response &&
       !data_identical(data.status, status))
    {
      flags.ReadEvent    = data_identical(data.status.st_atim, status.st_atim) ? 0 : 1;
      flags.WriteEvent   = data_identical(data.status.st_mtim, status.st_mtim) ? 0 : 1;
      flags.AttributeMod = data.status.st_mode == status.st_mode &&
                           data.status.st_uid  == status.st_uid &&
                           data.status.st_gid  == status.st_gid &&
                           data.status.st_rdev == status.st_rdev ? 0 : 1;
      flags.Moved        = data.status.st_dev  == status.st_dev &&
                           data.status.st_ino  == status.st_ino  ? 0 : 1;
    }
    else
    {
      switch(errno)
      {
        case EACCES: flags.AttributeMod = 1; break;
        case ENOTDIR:
        case ENOENT: flags.Deleted = 1; break; // file may be moved but assume it's deleted
      }
    }
    if(flags)
    {
      data.test_count = 0;
      posix::write(data.fd[Write], &flags, sizeof(flags));
    }
    if(flags.Deleted)
      remove(data.fd[Read]);
    else
    {
      if(data.test_count == 0)
        data.timer.start(1000, true); // test once per second
      else if(data.test_count == 10)
        data.timer.start(10000, true); // test every 10 seconds
      else if(data.test_count == 100)
        data.timer.start(100000, true); // test every 100 seconds
      data.test_count++;
    }
  }

  bool remove(posix::fd_t fd) noexcept
  {
    auto iter = events.find(fd);
    if(iter != events.end())
    {
      posix::close(iter->second.fd[Read]);
      posix::close(iter->second.fd[Write]);
      events.erase(iter);
      return true;
    }
    return false;
  }
} FileEvent::s_platform;

FileEvent::FileEvent(const std::string& _file, Flags_t _flags) noexcept
  : m_file(_file),
    m_flags(_flags),
    m_fd(posix::invalid_descriptor)
{
  m_fd = s_platform.add(m_file.c_str(), m_flags);
  EventBackend::add(m_fd, EventBackend::SimplePollReadFlags,
                    [this](posix::fd_t lambda_fd, native_flags_t) noexcept
                    {
                      Flags_t event_flags, new_flags;
                      while(posix::read(lambda_fd, &new_flags, sizeof(event_flags)) != posix::error_response) // read all events
                        event_flags = event_flags | new_flags; // compose new flag result
                      assert(m_flags & event_flags); // at least one flag matches
                      Object::enqueue(activated, m_file, event_flags);
                    });
}

FileEvent::~FileEvent(void) noexcept
{
  assert(EventBackend::remove(m_fd, EventBackend::SimplePollReadFlags));
  s_platform.remove(m_fd); // may already be deleted
}
#endif
<|endoftext|>


<commit_before>//  main_lbdrec_primaldual_tvl1.cpp
//
//	Copyright (C) 2011-2012  Signal Processing Laboratory 2 (LTS2), EPFL,
//	Emmanuel d'Angelo (emmanuel.dangelo@epfl.ch),
//	Laurent Jacques (laurent.jacques@uclouvain.be)
//	Alexandre Alahi (alahi@stanford.edu)
//	and Pierre Vandergheynst (pierre.vandergheynst@epfl.ch)
//
//  Redistribution and use in source and binary forms, with or without modification,
//  are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
//  This software is provided by the copyright holders and contributors "as is" and
//  any express or implied warranties, including, but not limited to, the implied
//  warranties of merchantability and fitness for a particular purpose are disclaimed.
//  In no event shall the Intel Corporation or contributors be liable for any direct,
//  indirect, incidental, special, exemplary, or consequential damages
//  (including, but not limited to, procurement of substitute goods or services;
//  loss of use, data, or profits; or business interruption) however caused
//  and on any theory of liability, whether in contract, strict liability,
//  or tort (including negligence or otherwise) arising in any way out of
//  the use of this software, even if advised of the possibility of such damage.

#include <iostream>
#include <getopt.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include "ILBDOperator.hpp"
#include "reconstruction.h"

void print_usage(FILE *stream, char **argv)
{
  fprintf(stream, "Usage: %s ", argv[0]);
  fprintf(stream, "[--lbd=freak|brief|rfreak|exfreak] ");
  fprintf(stream, "[--fast] ");
  fprintf(stream, "[--interactive] ");
  fprintf(stream, "[--norm=operator_norm (100.0) ");
  fprintf(stream, "[-i iterations = 1000] ");
  fprintf(stream, "[-l lambda = 0.1] ");
  fprintf(stream, "[-p psize = 32] ");
  fprintf(stream, "[-o offset] ");
  fprintf(stream, "input_image result_image\n");
}

int main(int argc, char **argv)
{
  if (argc < 2)
  {
    print_usage(stdout, argv);
    return 0;
  }

  int lbdType = 0;
  int pside = 32;
  int iterations = 1000;
  float lambda = 0.1;
  int offset = 0;
  int process_only_fast = 0;
  int interactive = 0;
  float operator_norm = 10.0;

  static struct option long_options[] = {
    {"lbd", required_argument, 0, 0},
    {"fast", no_argument, &process_only_fast, 1},
    {"interactive", no_argument, &interactive, 1},
    {"norm", required_argument, 0, 0},
    {0, 0, 0, 0}
  };

  int optionIndex;
  int c = getopt_long(argc, argv, "i:l:o:p:", long_options, &optionIndex);

  while (c != -1)
  {
    switch (c)
    {
    case 0:
      if (optionIndex == 0)
      {
        if (strncmp(optarg, "freak", 5) == 0) lbdType = (int)lbd::eTypeFreak;
        else if (strncmp(optarg, "brief", 5) == 0) lbdType = (int)lbd::eTypeBrief;
        else if (strncmp(optarg, "exfreak", 7) == 0) lbdType = (int)lbd::eTypeExFreaks;
        else lbdType = lbd::eTypeRandomFreak;
      }
      if (optionIndex == 3)
      {
        operator_norm = (float)atof(optarg);
      }
      break;

    case 'i':
      iterations = atoi(optarg);
      break;

    case 'l':
      lambda = (float)atof(optarg);
      break;

    case 'p':
      pside = atoi(optarg);
      pside += (pside % 2);   // Enforce even size
      break;

    case 'o':
      offset = atoi(optarg);
      break;

    case '?':
      std::cerr << "Unknown option: -" << c << " (ignored)\n";
      break;

    default:
      break;
    }

    c = getopt_long(argc, argv, "i:l:o:p:", long_options, &optionIndex);
  }

  std::string filename = (interactive == 0 ? argv[argc-2] : argv[argc-1]);
  cv::Mat testImage = cv::imread(filename, 0);
  if (!testImage.data)
  {
    std::cerr << "Error opening image: " << filename << std::endl;
    print_usage(stderr, argv);
    return EXIT_FAILURE;
  }

  cv::Mat testImagef;
  testImage.convertTo(testImagef, CV_32F, 1.0/255.0);

  cv::Size patchSize(pside,pside);
  if (offset == 0) offset = pside;
  cv::Point patchOffset(offset,offset);

  lts2::LBDOperator *LBD = lts2::CreateLbdOperator(lbdType);
  LBD->initWithPatchSize(patchSize);
  LBD->setNorm(operator_norm);

  cv::Mat result;

  if (process_only_fast == 0)
    lts2::PerformTVL1OnImage(testImagef, patchSize, patchOffset, *LBD, result, iterations, lambda);
  else
    lts2::PerformTVL1OnImageFAST(testImagef, patchSize, *LBD, result, iterations, lambda);

  std::stringstream windowNameStr;
  windowNameStr << "Primal-Dual (TVL1)" << " ";
  if (process_only_fast != 0)
    windowNameStr << "FAST " << " ";

  switch (lbdType)
  {
  case lbd::eTypeFreak:
    windowNameStr << "FREAK";
    break;

  case lbd::eTypeRandomFreak:
    windowNameStr << "Randomized FREAK";
    break;

  case lbd::eTypeBrief:
    windowNameStr << "BRIEF";
    break;

  case lbd::eTypeExFreaks:
    windowNameStr << "Ex-FREAK";
    break;
  }

  cv::Mat res8;
  result.convertTo(res8, CV_8U, 255.0);

  if (interactive > 0)
  {
    cv::imshow(windowNameStr.str(), res8);
    cv::waitKey();
  }
  else cv::imwrite(argv[argc-1], res8);

  return EXIT_SUCCESS;
}
<commit_msg>Bugfix: an input option was not getting a valid enum value<commit_after>//  main_lbdrec_primaldual_tvl1.cpp
//
//	Copyright (C) 2011-2012  Signal Processing Laboratory 2 (LTS2), EPFL,
//	Emmanuel d'Angelo (emmanuel.dangelo@epfl.ch),
//	Laurent Jacques (laurent.jacques@uclouvain.be)
//	Alexandre Alahi (alahi@stanford.edu)
//	and Pierre Vandergheynst (pierre.vandergheynst@epfl.ch)
//
//  Redistribution and use in source and binary forms, with or without modification,
//  are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
//  This software is provided by the copyright holders and contributors "as is" and
//  any express or implied warranties, including, but not limited to, the implied
//  warranties of merchantability and fitness for a particular purpose are disclaimed.
//  In no event shall the Intel Corporation or contributors be liable for any direct,
//  indirect, incidental, special, exemplary, or consequential damages
//  (including, but not limited to, procurement of substitute goods or services;
//  loss of use, data, or profits; or business interruption) however caused
//  and on any theory of liability, whether in contract, strict liability,
//  or tort (including negligence or otherwise) arising in any way out of
//  the use of this software, even if advised of the possibility of such damage.

#include <iostream>
#include <getopt.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include "ILBDOperator.hpp"
#include "reconstruction.h"

void print_usage(FILE *stream, char **argv)
{
  fprintf(stream, "Usage: %s ", argv[0]);
  fprintf(stream, "[--lbd=freak|brief|rfreak|exfreak] ");
  fprintf(stream, "[--fast] ");
  fprintf(stream, "[--interactive] ");
  fprintf(stream, "[--norm=operator_norm (100.0) ");
  fprintf(stream, "[-i iterations = 1000] ");
  fprintf(stream, "[-l lambda = 0.1] ");
  fprintf(stream, "[-p psize = 32] ");
  fprintf(stream, "[-o offset] ");
  fprintf(stream, "input_image result_image\n");
}

int main(int argc, char **argv)
{
  if (argc < 2)
  {
    print_usage(stdout, argv);
    return 0;
  }

  int lbdType = 0;
  int pside = 32;
  int iterations = 1000;
  float lambda = 0.1;
  int offset = 0;
  int process_only_fast = 0;
  int interactive = 0;
  float operator_norm = 10.0;

  static struct option long_options[] = {
    {"lbd", required_argument, 0, 0},
    {"fast", no_argument, &process_only_fast, 1},
    {"interactive", no_argument, &interactive, 1},
    {"norm", required_argument, 0, 0},
    {0, 0, 0, 0}
  };

  int optionIndex;
  int c = getopt_long(argc, argv, "i:l:o:p:", long_options, &optionIndex);

  while (c != -1)
  {
    switch (c)
    {
    case 0:
      if (optionIndex == 0)
      {
        if (strncmp(optarg, "freak", 5) == 0) lbdType = (int)lbd::eTypeFreak;
        else if (strncmp(optarg, "brief", 5) == 0) lbdType = (int)lbd::eTypeBrief;
        else if (strncmp(optarg, "exfreak", 7) == 0) lbdType = (int)lbd::eTypeExFreak;
        else lbdType = lbd::eTypeRandomFreak;
      }
      if (optionIndex == 3)
      {
        operator_norm = (float)atof(optarg);
      }
      break;

    case 'i':
      iterations = atoi(optarg);
      break;

    case 'l':
      lambda = (float)atof(optarg);
      break;

    case 'p':
      pside = atoi(optarg);
      pside += (pside % 2);   // Enforce even size
      break;

    case 'o':
      offset = atoi(optarg);
      break;

    case '?':
      std::cerr << "Unknown option: -" << c << " (ignored)\n";
      break;

    default:
      break;
    }

    c = getopt_long(argc, argv, "i:l:o:p:", long_options, &optionIndex);
  }

  std::string filename = (interactive == 0 ? argv[argc-2] : argv[argc-1]);
  cv::Mat testImage = cv::imread(filename, 0);
  if (!testImage.data)
  {
    std::cerr << "Error opening image: " << filename << std::endl;
    print_usage(stderr, argv);
    return EXIT_FAILURE;
  }

  cv::Mat testImagef;
  testImage.convertTo(testImagef, CV_32F, 1.0/255.0);

  cv::Size patchSize(pside,pside);
  if (offset == 0) offset = pside;
  cv::Point patchOffset(offset,offset);

  lts2::LBDOperator *LBD = lts2::CreateLbdOperator(lbdType);
  LBD->initWithPatchSize(patchSize);
  LBD->setNorm(operator_norm);

  cv::Mat result;

  if (process_only_fast == 0)
    lts2::PerformTVL1OnImage(testImagef, patchSize, patchOffset, *LBD, result, iterations, lambda);
  else
    lts2::PerformTVL1OnImageFAST(testImagef, patchSize, *LBD, result, iterations, lambda);

  std::stringstream windowNameStr;
  windowNameStr << "Primal-Dual (TVL1)" << " ";
  if (process_only_fast != 0)
    windowNameStr << "FAST " << " ";

  switch (lbdType)
  {
  case lbd::eTypeFreak:
    windowNameStr << "FREAK";
    break;

  case lbd::eTypeRandomFreak:
    windowNameStr << "Randomized FREAK";
    break;

  case lbd::eTypeBrief:
    windowNameStr << "BRIEF";
    break;

  case lbd::eTypeExFreak:
    windowNameStr << "Ex-FREAK";
    break;
  }

  cv::Mat res8;
  result.convertTo(res8, CV_8U, 255.0);

  if (interactive > 0)
  {
    cv::imshow(windowNameStr.str(), res8);
    cv::waitKey();
  }
  else cv::imwrite(argv[argc-1], res8);

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// Copyright © 2011, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifndef __COREBUILDERS_H
#define __COREBUILDERS_H

#include "mozartcore-decl.hh"

#include "coredatatypes-decl.hh"

#ifndef MOZART_GENERATOR

namespace mozart {

/**
 * Build unstable nodes from primitive C++ values
 *
 * The build() functions are a bunch of overloads for creating an
 * UnstableNode from a primitive C++ value.
 * E.g., applying build() on a nativeint will return a node whose type
 * is SmallInt.
 *
 * It is useful to have these methods be overloads, so that they can be used
 * in templated code. See buildTuple() for a not-so-trivial example.
 */

inline
UnstableNode build(VM vm, nativeint value) {
  return SmallInt::build(vm, value);
}

inline
UnstableNode build(VM vm, size_t value) {
  return SmallInt::build(vm, value);
}

namespace internal {
  struct AlternativeToInt {
    operator nativeint() { return 0; }
  };

  struct AlternativeToInt64 {
    operator nativeint() { return 0; }
  };

  typedef typename std::conditional<
    std::is_same<int, nativeint>::value,
    AlternativeToInt, int>::type intIfDifferentFromNativeInt;

  typedef typename std::conditional<
    std::is_same<std::int64_t, nativeint>::value,
    AlternativeToInt64, std::int64_t>::type int64IfDifferentFromNativeInt;
}

inline
UnstableNode build(VM vm, internal::intIfDifferentFromNativeInt value) {
  return SmallInt::build(vm, value);
}

inline
UnstableNode build(VM vm, internal::int64IfDifferentFromNativeInt value) {
  // TODO Use BigInt if necessary
  return SmallInt::build(vm, (nativeint) value);
}

template <typename T>
inline
auto build(VM vm, T value)
    -> typename std::enable_if<std::is_same<T, bool>::value, UnstableNode>::type {
  return Boolean::build(vm, value);
}

inline
UnstableNode build(VM vm, unit_t value) {
  return Unit::build(vm);
}

inline
UnstableNode build(VM vm, double value) {
  return Float::build(vm, value);
}

inline
UnstableNode build(VM vm, const nchar* value) {
  return Atom::build(vm, value);
}

// build an atom from a 'const char*' (as UTF string).
// Only exists when 'nchar != char'.
template <typename T>
inline
auto build(VM vm, T value)
    -> typename std::enable_if<std::is_convertible<T, const char*>::value &&
                               !std::is_same<nchar, char>::value, UnstableNode>::type {
  auto src = makeLString(value);
  auto dest = toUTF<nchar>(src);
  return Atom::build(vm, dest.length, dest.string);
}

inline
UnstableNode build(VM vm, atom_t value) {
  return Atom::build(vm, value);
}

inline
UnstableNode build(VM vm, unique_name_t value) {
  return UniqueName::build(vm, value);
}

inline
UnstableNode build(VM vm, builtins::BaseBuiltin& builtin) {
  return BuiltinProcedure::build(vm, builtin);
}

template <class T>
inline
UnstableNode build(VM vm, const std::shared_ptr<T>& value) {
  return ForeignPointer::build(vm, value);
}

inline
UnstableNode build(VM vm, UnstableNode&& node) {
  return std::move(node);
}

inline
UnstableNode build(VM vm, UnstableNode& node) {
  return UnstableNode(vm, node);
}

inline
UnstableNode build(VM vm, StableNode& node) {
  return UnstableNode(vm, node);
}

inline
UnstableNode build(VM vm, RichNode node) {
  return UnstableNode(vm, node);
}

// Initialize the elements of an aggregate

template <size_t i, class T, class U>
inline
void staticInitElement(VM vm, TypedRichNode<T> aggregate, U&& value) {
  UnstableNode valueNode = build(vm, std::forward<U>(value));
  aggregate.initElement(vm, i, valueNode);
}

template <size_t i, class T>
inline
void staticInitElementsInner(VM vm, TypedRichNode<T> aggregate) {
}

template <size_t i, class T, class U, class... Rest>
inline
void staticInitElementsInner(VM vm, TypedRichNode<T> aggregate,
                             U&& ithValue, Rest&&... rest) {
  staticInitElement<i, T, U>(vm, aggregate, std::forward<U>(ithValue));
  staticInitElementsInner<i+1, T>(vm, aggregate, std::forward<Rest>(rest)...);
}

/**
 * Initialize statically the elements of an aggregate (e.g., tuple)
 * @param vm          Contextual VM
 * @param aggregate   The aggregate to initialize, as a typed RichNode.
 * @param args...     The elements to initialize
 *                    (in any form supported by build())
 */
template <class T, class... Args>
inline
void staticInitElements(VM vm, TypedRichNode<T> aggregate, Args&&... args) {
  staticInitElementsInner<0, T>(vm, aggregate, std::forward<Args>(args)...);
}

// Build a tuple

template <class LT>
inline
UnstableNode buildTuple(VM vm, LT&& label) {
  // Degenerated case, which is just an atom
  return build(vm, std::forward<LT>(label));
}

/**
 * Build an Oz tuple inside a node, with its label and fields
 * The label and the arguments can be in any form supported by build().
 * @param vm        Contextual VM
 * @param label     Label of the tuple
 * @param args...   Fields of the tuple
 */
template <class LT, class... Args>
inline
UnstableNode buildTuple(VM vm, LT&& label, Args&&... args) {
  UnstableNode labelNode = build(vm, std::forward<LT>(label));
  UnstableNode result = Tuple::build(vm, sizeof...(args), labelNode);
  staticInitElements<Tuple>(vm, RichNode(result).as<Tuple>(),
                            std::forward<Args>(args)...);
  return result;
}

/**
 * Build an Oz cons pair, with a head and a tail
 * The head and tail can be in any form supported by build().
 * @param vm     Contextual VM
 * @param head   Head of the cons
 * @param tail   Tail of the cons
 */
template <class HT, class TT>
inline
UnstableNode buildCons(VM vm, HT&& head, TT&& tail) {
  UnstableNode headNode = build(vm, std::forward<HT>(head));
  UnstableNode tailNode = build(vm, std::forward<TT>(tail));
  return Cons::build(vm, headNode, tailNode);
}

/**
 * Build the atom 'nil'
 */
inline
UnstableNode buildNil(VM vm) {
  return build(vm, vm->coreatoms.nil);
}

// Build a list

inline
UnstableNode buildList(VM vm) {
  return buildNil(vm);
}

/**
 * Build an Oz list with a statically known number of elements
 * The elements can be in any form supported by build().
 */
template <class Head, class... Tail>
inline
UnstableNode buildList(VM vm, Head&& head, Tail&&... tail) {
  return buildCons(vm, std::forward<Head>(head),
                   buildList(vm, std::forward<Tail>(tail)...));
}

/**
 * Build a constant arity, with its label and features
 * The label and the features can be in any form supported by build().
 * @param vm        Contextual VM
 * @param label     Label of the arity
 * @param args...   Features of the arity
 */
template <class LT, class... Args>
inline
UnstableNode buildArity(VM vm, LT&& label, Args&&... args) {
  UnstableNode labelNode = build(vm, std::forward<LT>(label));
  UnstableNode result = Arity::build(vm, sizeof...(args), labelNode);
  staticInitElements<Arity>(vm, RichNode(result).as<Arity>(),
                            std::forward<Args>(args)...);
  return result;
}

/**
 * Build an Oz record inside a node, with its arity and fields
 * The arity and the arguments can be in any form supported by build().
 * @param vm        Contextual VM
 * @param arity     Arity of the record
 * @param args...   Fields of the record
 */
template <class AT, class... Args>
inline
UnstableNode buildRecord(VM vm, AT&& arity, Args&&... args) {
  UnstableNode arityNode = build(vm, std::forward<AT>(arity));
  UnstableNode result = Record::build(vm, sizeof...(args), arityNode);
  staticInitElements<Record>(vm, RichNode(result).as<Record>(),
                             std::forward<Args>(args)...);
  return result;
}

inline
UnstableNode buildPatMatConjunction(VM vm) {
  // Degenerated case, which is just a wildcard
  return PatMatCapture::build(vm, -1);
}

template <class PT>
inline
UnstableNode buildPatMatConjunction(VM vm, PT&& part) {
  // Degenerated case, which is just the only part
  return build(vm, std::forward<PT>(part));
}

/**
 * Build a pattern conjunction
 * The parts can be in any form supported by build().
 * @param vm         Contextual VM
 * @param parts...   Parts of the conjunction
 */
template <class... Args>
inline
UnstableNode buildPatMatConjunction(VM vm, Args&&... parts) {
  UnstableNode result = PatMatConjunction::build(vm, sizeof...(parts));
  staticInitElements<PatMatConjunction>(
    vm, RichNode(result).as<PatMatConjunction>(), std::forward<Args>(parts)...);
  return result;
}

/**
 * Build an patmat open record inside a node, with its arity and fields
 * The arity and the arguments can be in any form supported by build().
 * @param vm        Contextual VM
 * @param arity     Arity of the open record
 * @param args...   Fields of the open record
 */
template <class AT, class... Args>
inline
UnstableNode buildPatMatOpenRecord(VM vm, AT&& arity, Args&&... args) {
  UnstableNode arityNode = build(vm, std::forward<AT>(arity));
  UnstableNode result = PatMatOpenRecord::build(vm, sizeof...(args), arityNode);
  staticInitElements<PatMatOpenRecord>(
    vm, RichNode(result).as<PatMatOpenRecord>(), std::forward<Args>(args)...);
  return result;
}

}

#endif // MOZART_GENERATOR

#endif // __COREBUILDERS_H
<commit_msg>Finally added buildSharp() builder.<commit_after>// Copyright © 2011, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#ifndef __COREBUILDERS_H
#define __COREBUILDERS_H

#include "mozartcore-decl.hh"

#include "coredatatypes-decl.hh"

#ifndef MOZART_GENERATOR

namespace mozart {

/**
 * Build unstable nodes from primitive C++ values
 *
 * The build() functions are a bunch of overloads for creating an
 * UnstableNode from a primitive C++ value.
 * E.g., applying build() on a nativeint will return a node whose type
 * is SmallInt.
 *
 * It is useful to have these methods be overloads, so that they can be used
 * in templated code. See buildTuple() for a not-so-trivial example.
 */

inline
UnstableNode build(VM vm, nativeint value) {
  return SmallInt::build(vm, value);
}

inline
UnstableNode build(VM vm, size_t value) {
  return SmallInt::build(vm, value);
}

namespace internal {
  struct AlternativeToInt {
    operator nativeint() { return 0; }
  };

  struct AlternativeToInt64 {
    operator nativeint() { return 0; }
  };

  typedef typename std::conditional<
    std::is_same<int, nativeint>::value,
    AlternativeToInt, int>::type intIfDifferentFromNativeInt;

  typedef typename std::conditional<
    std::is_same<std::int64_t, nativeint>::value,
    AlternativeToInt64, std::int64_t>::type int64IfDifferentFromNativeInt;
}

inline
UnstableNode build(VM vm, internal::intIfDifferentFromNativeInt value) {
  return SmallInt::build(vm, value);
}

inline
UnstableNode build(VM vm, internal::int64IfDifferentFromNativeInt value) {
  // TODO Use BigInt if necessary
  return SmallInt::build(vm, (nativeint) value);
}

template <typename T>
inline
auto build(VM vm, T value)
    -> typename std::enable_if<std::is_same<T, bool>::value, UnstableNode>::type {
  return Boolean::build(vm, value);
}

inline
UnstableNode build(VM vm, unit_t value) {
  return Unit::build(vm);
}

inline
UnstableNode build(VM vm, double value) {
  return Float::build(vm, value);
}

inline
UnstableNode build(VM vm, const nchar* value) {
  return Atom::build(vm, value);
}

// build an atom from a 'const char*' (as UTF string).
// Only exists when 'nchar != char'.
template <typename T>
inline
auto build(VM vm, T value)
    -> typename std::enable_if<std::is_convertible<T, const char*>::value &&
                               !std::is_same<nchar, char>::value, UnstableNode>::type {
  auto src = makeLString(value);
  auto dest = toUTF<nchar>(src);
  return Atom::build(vm, dest.length, dest.string);
}

inline
UnstableNode build(VM vm, atom_t value) {
  return Atom::build(vm, value);
}

inline
UnstableNode build(VM vm, unique_name_t value) {
  return UniqueName::build(vm, value);
}

inline
UnstableNode build(VM vm, builtins::BaseBuiltin& builtin) {
  return BuiltinProcedure::build(vm, builtin);
}

template <class T>
inline
UnstableNode build(VM vm, const std::shared_ptr<T>& value) {
  return ForeignPointer::build(vm, value);
}

inline
UnstableNode build(VM vm, UnstableNode&& node) {
  return std::move(node);
}

inline
UnstableNode build(VM vm, UnstableNode& node) {
  return UnstableNode(vm, node);
}

inline
UnstableNode build(VM vm, StableNode& node) {
  return UnstableNode(vm, node);
}

inline
UnstableNode build(VM vm, RichNode node) {
  return UnstableNode(vm, node);
}

// Initialize the elements of an aggregate

template <size_t i, class T, class U>
inline
void staticInitElement(VM vm, TypedRichNode<T> aggregate, U&& value) {
  UnstableNode valueNode = build(vm, std::forward<U>(value));
  aggregate.initElement(vm, i, valueNode);
}

template <size_t i, class T>
inline
void staticInitElementsInner(VM vm, TypedRichNode<T> aggregate) {
}

template <size_t i, class T, class U, class... Rest>
inline
void staticInitElementsInner(VM vm, TypedRichNode<T> aggregate,
                             U&& ithValue, Rest&&... rest) {
  staticInitElement<i, T, U>(vm, aggregate, std::forward<U>(ithValue));
  staticInitElementsInner<i+1, T>(vm, aggregate, std::forward<Rest>(rest)...);
}

/**
 * Initialize statically the elements of an aggregate (e.g., tuple)
 * @param vm          Contextual VM
 * @param aggregate   The aggregate to initialize, as a typed RichNode.
 * @param args...     The elements to initialize
 *                    (in any form supported by build())
 */
template <class T, class... Args>
inline
void staticInitElements(VM vm, TypedRichNode<T> aggregate, Args&&... args) {
  staticInitElementsInner<0, T>(vm, aggregate, std::forward<Args>(args)...);
}

// Build a tuple

template <class LT>
inline
UnstableNode buildTuple(VM vm, LT&& label) {
  // Degenerated case, which is just an atom
  return build(vm, std::forward<LT>(label));
}

/**
 * Build an Oz tuple inside a node, with its label and fields
 * The label and the arguments can be in any form supported by build().
 * @param vm        Contextual VM
 * @param label     Label of the tuple
 * @param args...   Fields of the tuple
 */
template <class LT, class... Args>
inline
UnstableNode buildTuple(VM vm, LT&& label, Args&&... args) {
  UnstableNode labelNode = build(vm, std::forward<LT>(label));
  UnstableNode result = Tuple::build(vm, sizeof...(args), labelNode);
  staticInitElements<Tuple>(vm, RichNode(result).as<Tuple>(),
                            std::forward<Args>(args)...);
  return result;
}

/**
 * Build an Oz #-tuple inside a node, with its fields
 * The arguments can be in any form supported by build().
 * @param vm        Contextual VM
 * @param args...   Fields of the #-tuple
 */
template <class... Args>
inline
UnstableNode buildSharp(VM vm, Args&&... args) {
  return buildTuple(vm, vm->coreatoms.sharp, std::forward<Args>(args)...);
}

/**
 * Build an Oz cons pair, with a head and a tail
 * The head and tail can be in any form supported by build().
 * @param vm     Contextual VM
 * @param head   Head of the cons
 * @param tail   Tail of the cons
 */
template <class HT, class TT>
inline
UnstableNode buildCons(VM vm, HT&& head, TT&& tail) {
  UnstableNode headNode = build(vm, std::forward<HT>(head));
  UnstableNode tailNode = build(vm, std::forward<TT>(tail));
  return Cons::build(vm, headNode, tailNode);
}

/**
 * Build the atom 'nil'
 */
inline
UnstableNode buildNil(VM vm) {
  return build(vm, vm->coreatoms.nil);
}

// Build a list

inline
UnstableNode buildList(VM vm) {
  return buildNil(vm);
}

/**
 * Build an Oz list with a statically known number of elements
 * The elements can be in any form supported by build().
 */
template <class Head, class... Tail>
inline
UnstableNode buildList(VM vm, Head&& head, Tail&&... tail) {
  return buildCons(vm, std::forward<Head>(head),
                   buildList(vm, std::forward<Tail>(tail)...));
}

/**
 * Build a constant arity, with its label and features
 * The label and the features can be in any form supported by build().
 * @param vm        Contextual VM
 * @param label     Label of the arity
 * @param args...   Features of the arity
 */
template <class LT, class... Args>
inline
UnstableNode buildArity(VM vm, LT&& label, Args&&... args) {
  UnstableNode labelNode = build(vm, std::forward<LT>(label));
  UnstableNode result = Arity::build(vm, sizeof...(args), labelNode);
  staticInitElements<Arity>(vm, RichNode(result).as<Arity>(),
                            std::forward<Args>(args)...);
  return result;
}

/**
 * Build an Oz record inside a node, with its arity and fields
 * The arity and the arguments can be in any form supported by build().
 * @param vm        Contextual VM
 * @param arity     Arity of the record
 * @param args...   Fields of the record
 */
template <class AT, class... Args>
inline
UnstableNode buildRecord(VM vm, AT&& arity, Args&&... args) {
  UnstableNode arityNode = build(vm, std::forward<AT>(arity));
  UnstableNode result = Record::build(vm, sizeof...(args), arityNode);
  staticInitElements<Record>(vm, RichNode(result).as<Record>(),
                             std::forward<Args>(args)...);
  return result;
}

inline
UnstableNode buildPatMatConjunction(VM vm) {
  // Degenerated case, which is just a wildcard
  return PatMatCapture::build(vm, -1);
}

template <class PT>
inline
UnstableNode buildPatMatConjunction(VM vm, PT&& part) {
  // Degenerated case, which is just the only part
  return build(vm, std::forward<PT>(part));
}

/**
 * Build a pattern conjunction
 * The parts can be in any form supported by build().
 * @param vm         Contextual VM
 * @param parts...   Parts of the conjunction
 */
template <class... Args>
inline
UnstableNode buildPatMatConjunction(VM vm, Args&&... parts) {
  UnstableNode result = PatMatConjunction::build(vm, sizeof...(parts));
  staticInitElements<PatMatConjunction>(
    vm, RichNode(result).as<PatMatConjunction>(), std::forward<Args>(parts)...);
  return result;
}

/**
 * Build an patmat open record inside a node, with its arity and fields
 * The arity and the arguments can be in any form supported by build().
 * @param vm        Contextual VM
 * @param arity     Arity of the open record
 * @param args...   Fields of the open record
 */
template <class AT, class... Args>
inline
UnstableNode buildPatMatOpenRecord(VM vm, AT&& arity, Args&&... args) {
  UnstableNode arityNode = build(vm, std::forward<AT>(arity));
  UnstableNode result = PatMatOpenRecord::build(vm, sizeof...(args), arityNode);
  staticInitElements<PatMatOpenRecord>(
    vm, RichNode(result).as<PatMatOpenRecord>(), std::forward<Args>(args)...);
  return result;
}

}

#endif // MOZART_GENERATOR

#endif // __COREBUILDERS_H
<|endoftext|>


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

#include "memory.hpp"

std::unique_ptr<cvk_mem> cvk_mem::create(cvk_context *context, cl_mem_flags flags, size_t size, void *host_ptr, cl_int *errcode_ret
){
    auto mem = std::make_unique<cvk_mem>(context, flags, size, host_ptr, nullptr, 0);

    if (!mem->init()) {
        *errcode_ret = CL_OUT_OF_RESOURCES;
        return nullptr;
    }

    *errcode_ret = CL_SUCCESS;
    return mem;
}

bool cvk_mem::init()
{
    auto device = m_context->device();
    auto vkdev = device->vulkan_device();

    // Create the buffer
    const VkBufferCreateInfo createInfo = {
        VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // sType
        nullptr, // pNext
        0, // flags
        m_size,
        cvk_mem::USAGE_FLAGS, // usage
        VK_SHARING_MODE_EXCLUSIVE,
        0, // queueFamilyIndexCount
        nullptr, // pQueueFamilyIndices
    };

    VkResult res = vkCreateBuffer(vkdev, &createInfo, nullptr, &m_buffer);

    if (res != VK_SUCCESS) {
        return false;
    }

    cvk_debug_fn("created Vk buffer handle = %p", m_buffer);

    // Get memory requirements
    VkMemoryRequirements memreqs;
    vkGetBufferMemoryRequirements(vkdev, m_buffer, &memreqs);

    // Select memory type
    uint32_t memoryTypeIndex = device->memory_type_index();

    if (memoryTypeIndex == VK_MAX_MEMORY_TYPES) {
        return false;
    }

    // Check against the memory requirements
    // TODO get the type index from the requirements
    if (!((1 << memoryTypeIndex) & memreqs.memoryTypeBits)) {
        return false;
    }

    // Allocate memory
    const VkMemoryAllocateInfo memoryAllocateInfo = {
        VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
        nullptr,
        memreqs.size,
        memoryTypeIndex,
    };

    res = vkAllocateMemory(vkdev, &memoryAllocateInfo, 0, &m_memory);

    if(res != VK_SUCCESS) {
        return false;
    }

    // Bind the buffer to memory
    res = vkBindBufferMemory(vkdev, m_buffer, m_memory, 0);

    if(res != VK_SUCCESS) {
        return false;
    }

    if ((m_flags & CL_MEM_COPY_HOST_PTR) || (m_flags & CL_MEM_USE_HOST_PTR)) {
        if (!copy_from(m_host_ptr, 0, m_size)) {
            return false;
        }
    }

    return true;
}

cvk_mem* cvk_mem::create_subbuffer(cl_mem_flags flags, size_t origin, size_t size)
{
    std::unique_ptr<cvk_mem> mem(new cvk_mem(m_context, flags, size, nullptr, this, origin));

    if (!mem->init_subbuffer()) {
        return nullptr;
    }

    return mem.release();
}

bool cvk_mem::init_subbuffer() {

    // Create the buffer
    const VkBufferCreateInfo createInfo = {
        VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // sType
        nullptr, // pNext
        0, // flags
        m_size,
        cvk_mem::USAGE_FLAGS, // usage
        VK_SHARING_MODE_EXCLUSIVE,
        0, // queueFamilyIndexCount
        nullptr, // pQueueFamilyIndices
    };

    auto vkdev = m_context->device()->vulkan_device();
    VkResult res = vkCreateBuffer(vkdev, &createInfo, nullptr, &m_buffer);

    if (res != VK_SUCCESS) {
        return false;
    }

    cvk_debug_fn("created Vk buffer handle = %p", m_buffer);

    // Get memory requirements
    VkMemoryRequirements memreqs;
    vkGetBufferMemoryRequirements(vkdev, m_buffer, &memreqs);

    if (m_size != memreqs.size) {
        cvk_warn_fn("Sub-buffer %p requires more memory than its size, you're on your own!", this);
    }

    if (m_parent_offset % memreqs.alignment != 0) {
        cvk_warn_fn("Sub-buffer %p offset (%zu) does not satisfy the alignment "
                    "requirements (%lu) of the Vulkan implementation, "
                    "you're on your own!", this, m_parent_offset, memreqs.alignment);
    }

    // Bind the buffer to memory
    res = vkBindBufferMemory(vkdev, m_buffer, m_parent->m_memory, m_parent_offset);

    if(res != VK_SUCCESS) {
        return false;
    }

    return true;
}
<commit_msg>Use has_any_flag in one more place<commit_after>// Copyright 2018 The clvk authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "memory.hpp"

std::unique_ptr<cvk_mem> cvk_mem::create(cvk_context *context, cl_mem_flags flags, size_t size, void *host_ptr, cl_int *errcode_ret
){
    auto mem = std::make_unique<cvk_mem>(context, flags, size, host_ptr, nullptr, 0);

    if (!mem->init()) {
        *errcode_ret = CL_OUT_OF_RESOURCES;
        return nullptr;
    }

    *errcode_ret = CL_SUCCESS;
    return mem;
}

bool cvk_mem::init()
{
    auto device = m_context->device();
    auto vkdev = device->vulkan_device();

    // Create the buffer
    const VkBufferCreateInfo createInfo = {
        VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // sType
        nullptr, // pNext
        0, // flags
        m_size,
        cvk_mem::USAGE_FLAGS, // usage
        VK_SHARING_MODE_EXCLUSIVE,
        0, // queueFamilyIndexCount
        nullptr, // pQueueFamilyIndices
    };

    VkResult res = vkCreateBuffer(vkdev, &createInfo, nullptr, &m_buffer);

    if (res != VK_SUCCESS) {
        return false;
    }

    cvk_debug_fn("created Vk buffer handle = %p", m_buffer);

    // Get memory requirements
    VkMemoryRequirements memreqs;
    vkGetBufferMemoryRequirements(vkdev, m_buffer, &memreqs);

    // Select memory type
    uint32_t memoryTypeIndex = device->memory_type_index();

    if (memoryTypeIndex == VK_MAX_MEMORY_TYPES) {
        return false;
    }

    // Check against the memory requirements
    // TODO get the type index from the requirements
    if (!((1 << memoryTypeIndex) & memreqs.memoryTypeBits)) {
        return false;
    }

    // Allocate memory
    const VkMemoryAllocateInfo memoryAllocateInfo = {
        VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
        nullptr,
        memreqs.size,
        memoryTypeIndex,
    };

    res = vkAllocateMemory(vkdev, &memoryAllocateInfo, 0, &m_memory);

    if(res != VK_SUCCESS) {
        return false;
    }

    // Bind the buffer to memory
    res = vkBindBufferMemory(vkdev, m_buffer, m_memory, 0);

    if(res != VK_SUCCESS) {
        return false;
    }

    if (has_any_flag(CL_MEM_COPY_HOST_PTR | CL_MEM_USE_HOST_PTR)) {
        if (!copy_from(m_host_ptr, 0, m_size)) {
            return false;
        }
    }

    return true;
}

cvk_mem* cvk_mem::create_subbuffer(cl_mem_flags flags, size_t origin, size_t size)
{
    std::unique_ptr<cvk_mem> mem(new cvk_mem(m_context, flags, size, nullptr, this, origin));

    if (!mem->init_subbuffer()) {
        return nullptr;
    }

    return mem.release();
}

bool cvk_mem::init_subbuffer() {

    // Create the buffer
    const VkBufferCreateInfo createInfo = {
        VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // sType
        nullptr, // pNext
        0, // flags
        m_size,
        cvk_mem::USAGE_FLAGS, // usage
        VK_SHARING_MODE_EXCLUSIVE,
        0, // queueFamilyIndexCount
        nullptr, // pQueueFamilyIndices
    };

    auto vkdev = m_context->device()->vulkan_device();
    VkResult res = vkCreateBuffer(vkdev, &createInfo, nullptr, &m_buffer);

    if (res != VK_SUCCESS) {
        return false;
    }

    cvk_debug_fn("created Vk buffer handle = %p", m_buffer);

    // Get memory requirements
    VkMemoryRequirements memreqs;
    vkGetBufferMemoryRequirements(vkdev, m_buffer, &memreqs);

    if (m_size != memreqs.size) {
        cvk_warn_fn("Sub-buffer %p requires more memory than its size, you're on your own!", this);
    }

    if (m_parent_offset % memreqs.alignment != 0) {
        cvk_warn_fn("Sub-buffer %p offset (%zu) does not satisfy the alignment "
                    "requirements (%lu) of the Vulkan implementation, "
                    "you're on your own!", this, m_parent_offset, memreqs.alignment);
    }

    // Bind the buffer to memory
    res = vkBindBufferMemory(vkdev, m_buffer, m_parent->m_memory, m_parent_offset);

    if(res != VK_SUCCESS) {
        return false;
    }

    return true;
}
<|endoftext|>


<commit_before>#include "Arduino.h"
#include "io.h"
#include "mx7219.h"
#include "pins.h"

// A simple font for the MAX7219. Bits, MSB to LSB, correspond to segments DP,
// A, B, C, D, E, F and G with the following arrangement:
//
//       ___
//        A
//   F | ___ | B
//        G
//   E | ___ | C
//        D       . DP
//
byte MX7219_FONT[] = {
    // 0-9
    0x7E, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70, 0x7F, 0x7B,

    // A-F
    0x77, 0x1F, 0x4E, 0x3D, 0x4F, 0x47,

    // H, L, n, o, P, r, S, t, u, Y
    0x37, 0x0E, 0x15, 0x1D, 0x67, 0x05, 0x5B, 0x0F, 0x1C, 0x3B,

    // Space
    0x00,

    // Individual segments
    0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00,
};

// Number of characters in the MX7219 font.
const int MX7219_FONT_N_CHARS = sizeof(MX7219_FONT)/sizeof(byte);

void setMX7219Reg(byte reg, byte value) {
    // Shift reg then byte since MX7219 expects data in MSB order.
    digitalWrite(DLOAD, LOW);
    sendAndReceive(reg, MSB_FIRST);
    sendAndReceive(value, MSB_FIRST);

    // Pulse DLOAD
    digitalWrite(DLOAD, HIGH);
    digitalWrite(DLOAD, LOW);
}

void setupMX7219() {
    setMX7219Reg(MX7219_DECODE_MODE, 0x00); // No decode
    setMX7219Reg(MX7219_INTENSITY, 0xFF);   // Maximum intensity
    setMX7219Reg(MX7219_SCN_LIMIT, 0x05);   // Scan digits 0-5
    setMX7219Reg(MX7219_DPLY_TEST, 0x00);   // No display test
    setMX7219Reg(MX7219_SHUTDOWN, 0x01);    // Normal operation
}
<commit_msg>mx7219: tidy up comments on font<commit_after>#include "Arduino.h"
#include "io.h"
#include "mx7219.h"
#include "pins.h"

// A simple font for the MAX7219. Bits, MSB to LSB, correspond to segments DP,
// A, B, C, D, E, F and G with the following arrangement:
//
//       ___
//        A
//   F | ___ | B
//        G
//   E | ___ | C
//        D       . DP
//
byte MX7219_FONT[] = {
    // 0-9, A-F
    0x7E, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70, 0x7F, 0x7B,
    0x77, 0x1F, 0x4E, 0x3D, 0x4F, 0x47,

    // H, L, n, o, P, r, S, t, u, Y
    0x37, 0x0E, 0x15, 0x1D, 0x67, 0x05, 0x5B, 0x0F, 0x1C, 0x3B,

    // Space
    0x00,

    // Individual segments
    0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00,
};

// Number of characters in the MX7219 font.
const int MX7219_FONT_N_CHARS = sizeof(MX7219_FONT)/sizeof(byte);

void setMX7219Reg(byte reg, byte value) {
    // Shift reg then byte since MX7219 expects data in MSB order.
    digitalWrite(DLOAD, LOW);
    sendAndReceive(reg, MSB_FIRST);
    sendAndReceive(value, MSB_FIRST);

    // Pulse DLOAD
    digitalWrite(DLOAD, HIGH);
    digitalWrite(DLOAD, LOW);
}

void setupMX7219() {
    setMX7219Reg(MX7219_DECODE_MODE, 0x00); // No decode
    setMX7219Reg(MX7219_INTENSITY, 0xFF);   // Maximum intensity
    setMX7219Reg(MX7219_SCN_LIMIT, 0x05);   // Scan digits 0-5
    setMX7219Reg(MX7219_DPLY_TEST, 0x00);   // No display test
    setMX7219Reg(MX7219_SHUTDOWN, 0x01);    // Normal operation
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Manjeet Dahiya
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "QXmppEntityTimeManager.h"

#include <QDomElement>
#include <QDateTime>

#include "QXmppConstants.h"
#include "QXmppOutgoingClient.h"
#include "QXmppEntityTimeIq.h"
#include "QXmppUtils.h"

void QXmppEntityTimeManager::requestTime(const QString& jid)
{
    QXmppEntityTimeIq request;
    request.setType(QXmppIq::Get);
    request.setFrom(client()->configuration().jid());
    request.setTo(jid);
    client()->sendPacket(request);
}

QStringList QXmppEntityTimeManager::discoveryFeatures() const
{
    return QStringList() << ns_entity_time;
}

bool QXmppEntityTimeManager::handleStanza(QXmppStream *stream, const QDomElement &element)
{
    if(element.tagName() == "iq" && QXmppEntityTimeIq::isEntityTimeIq(element))
    {
        QXmppEntityTimeIq entityTime;
        entityTime.parse(element);

        if(entityTime.type() == QXmppIq::Get)
        {
            // respond to query
            QXmppEntityTimeIq responseIq;
            responseIq.setType(QXmppIq::Result);
            responseIq.setId(entityTime.id());
            responseIq.setTo(entityTime.from());

            QDateTime currentTime = QDateTime::currentDateTime();
            QDateTime utc = currentTime.toUTC();
            responseIq.setUtc(datetimeToString(utc));

            currentTime.setTimeSpec(Qt::UTC);
            int tzo_sec = currentTime.secsTo(utc);
            QTime tzo_time;
            if(tzo_sec < 0)
                tzo_time = tzo_time.addSecs(-tzo_sec);
            else
                tzo_time = tzo_time.addSecs(tzo_sec);
            QString tzo;
            if(tzo_sec < 0)
                tzo = "-" + tzo_time.toString("hh:mm");
            else
                tzo = "+" + tzo_time.toString("hh:mm");

            responseIq.setTzo(tzo);

            stream->sendPacket(responseIq);
        }

        emit timeReceived(entityTime);
        return true;
    }

    return false;
}
<commit_msg>bug fix<commit_after>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Manjeet Dahiya
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "QXmppEntityTimeManager.h"

#include <QDomElement>
#include <QDateTime>

#include "QXmppConstants.h"
#include "QXmppOutgoingClient.h"
#include "QXmppEntityTimeIq.h"
#include "QXmppUtils.h"

void QXmppEntityTimeManager::requestTime(const QString& jid)
{
    QXmppEntityTimeIq request;
    request.setType(QXmppIq::Get);
    request.setFrom(client()->configuration().jid());
    request.setTo(jid);
    client()->sendPacket(request);
}

QStringList QXmppEntityTimeManager::discoveryFeatures() const
{
    return QStringList() << ns_entity_time;
}

bool QXmppEntityTimeManager::handleStanza(QXmppStream *stream, const QDomElement &element)
{
    if(element.tagName() == "iq" && QXmppEntityTimeIq::isEntityTimeIq(element))
    {
        QXmppEntityTimeIq entityTime;
        entityTime.parse(element);

        if(entityTime.type() == QXmppIq::Get)
        {
            // respond to query
            QXmppEntityTimeIq responseIq;
            responseIq.setType(QXmppIq::Result);
            responseIq.setId(entityTime.id());
            responseIq.setTo(entityTime.from());

            QDateTime currentTime = QDateTime::currentDateTime();
            QDateTime utc = currentTime.toUTC();
            responseIq.setUtc(datetimeToString(utc));

            currentTime.setTimeSpec(Qt::UTC);
            int tzo_sec = utc.secsTo(currentTime);
            QTime tzo_time;
            if(tzo_sec < 0)
                tzo_time = tzo_time.addSecs(-tzo_sec);
            else
                tzo_time = tzo_time.addSecs(tzo_sec);
            QString tzo;
            if(tzo_sec < 0)
                tzo = "-" + tzo_time.toString("hh:mm");
            else
                tzo = "+" + tzo_time.toString("hh:mm");

            responseIq.setTzo(tzo);

            stream->sendPacket(responseIq);
        }

        emit timeReceived(entityTime);
        return true;
    }

    return false;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Manjeet Dahiya
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "QXmppEntityTimeManager.h"

#include <QDomElement>

#include "QXmppConstants.h"
#include "QXmppOutgoingClient.h"
#include "QXmppEntityTimeIq.h"

void QXmppEntityTimeManager::requestTime(const QString& jid)
{
    QXmppEntityTimeIq request;
    request.setType(QXmppIq::Get);
    request.setFrom(client()->configuration().jid());
    request.setTo(jid);
    client()->sendPacket(request);
}

QStringList QXmppEntityTimeManager::discoveryFeatures() const
{
    return QStringList() << ns_entity_time;
}

bool QXmppEntityTimeManager::handleStanza(QXmppStream *stream, const QDomElement &element)
{
    if(element.tagName() == "iq" && QXmppEntityTimeIq::isEntityTimeIq(element))
    {
        QXmppEntityTimeIq entityTime;
        entityTime.parse(element);

        if(entityTime.type() == QXmppIq::Get)
        {
            // respond to query
            QXmppEntityTimeIq responseIq;
            responseIq.setType(QXmppIq::Result);
            responseIq.setId(entityTime.id());
            responseIq.setTo(entityTime.from());

            // TODO: set valid values
            responseIq.setTzo("");
            responseIq.setUtc("");

            stream->sendPacket(responseIq);
        }

        emit timeReceived(entityTime);
        return true;
    }

    return false;
}
<commit_msg>populate the result Iq<commit_after>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Manjeet Dahiya
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "QXmppEntityTimeManager.h"

#include <QDomElement>
#include <QDateTime>

#include "QXmppConstants.h"
#include "QXmppOutgoingClient.h"
#include "QXmppEntityTimeIq.h"
#include "QXmppUtils.h"

void QXmppEntityTimeManager::requestTime(const QString& jid)
{
    QXmppEntityTimeIq request;
    request.setType(QXmppIq::Get);
    request.setFrom(client()->configuration().jid());
    request.setTo(jid);
    client()->sendPacket(request);
}

QStringList QXmppEntityTimeManager::discoveryFeatures() const
{
    return QStringList() << ns_entity_time;
}

bool QXmppEntityTimeManager::handleStanza(QXmppStream *stream, const QDomElement &element)
{
    if(element.tagName() == "iq" && QXmppEntityTimeIq::isEntityTimeIq(element))
    {
        QXmppEntityTimeIq entityTime;
        entityTime.parse(element);

        if(entityTime.type() == QXmppIq::Get)
        {
            // respond to query
            QXmppEntityTimeIq responseIq;
            responseIq.setType(QXmppIq::Result);
            responseIq.setId(entityTime.id());
            responseIq.setTo(entityTime.from());

            // TODO: set valid values
            QDateTime currentTime = QDateTime::currentDateTime();
            QDateTime utc = currentTime.toUTC();
            responseIq.setUtc(datetimeToString(utc));

            currentTime.setTimeSpec(Qt::UTC);
            int tzo_sec = currentTime.secsTo(utc);
            QTime tzo_time;
            if(tzo_sec < 0)
                tzo_time.addSecs(-tzo_sec);
            else
                tzo_time.addSecs(tzo_sec);
            QString tzo;
            if(tzo_sec < 0)
                tzo = "-" + tzo_time.toString("hh:mm");
            else
                tzo = "+" + tzo_time.toString("hh:mm");

            responseIq.setTzo(tzo);

            stream->sendPacket(responseIq);
        }

        emit timeReceived(entityTime);
        return true;
    }

    return false;
}
<|endoftext|>


<commit_before>// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
#include <Rmath.h>

#include <vector>
#include <cassert>

#include "vmat.h"
#include "gmat.h"
#include "DataPairs.h"
#include "quadrule.h"
#include "pn.h"
#include "functions.h"

using namespace Rcpp;
using namespace arma;
using namespace std;

const double twopi = 2*datum::pi;

/////////////////////////////////////////////////////////////////////////////////////////////////
/* Full loglikelihood */
double loglikfull(unsigned row, DataPairs &data, const gmat &sigmaMarg, const gmat &sigmaJoint, const gmat &sigmaCond, vmat sigmaU, vec u, bool full=1){

  data.pi_gen(row, u); // Estimation of pi based on u

  irowvec causes = data.causes_get(row); // Failure causes for pair in question

  double res = 0; // Initialising output (loglik contribution)

  if ((causes(0) > 0) & (causes(1) > 0)){
    /* Both individuals experience failure */
    res = logdF2(row, causes, data, sigmaJoint, u);
  }
  else if((causes(0) <= 0) & (causes(1) <= 0)){
    /* Neither individual experience failure */

    if ((causes(0) < 0) & (causes(1) < 0)){
      // Full follow-up for both individuals
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data);
	  lik -= prob;
	}
	res += log(lik);
      }
    }
    else if (((causes(0) < 0) & (causes(1) == 0)) | ((causes(0) == 0) & (causes(1) < 0))){
      // Full follow-up for only one individual
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  if (causes(i-1) < 0){
	    double prob = F1(row, j, i, data);
	    lik -= prob;
	  }
	  else {
	    double prob = F1(row, j, i, data, sigmaMarg, u);
	    lik -= prob;
	  }
	}
	res += log(lik);
      }
    }
    else {
      // Full follow-up for neither individual
      double lik = 1;
      // Marginal probabilities
      for (unsigned i=1; i<=2; i++){ // Over individuals
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data, sigmaMarg, u);
	  lik -= prob; // Subtracting
	}
      }
      // Bivariate probabilities
      for (unsigned k=1; k<=data.ncauses; k++){ // Over failure causes
	for (unsigned l=1; l<=data.ncauses; l++){
	  irowvec vcauses(2);
	  vcauses(0) = k; vcauses(1) = l;
	  double prob = F2(row, vcauses, data, sigmaJoint, u);
	  lik += prob; // Adding
	}
      }
      res = log(lik);
    }
  }
  else {
    /* One individual experiences failure the other does not */
    for (unsigned i=1; i<=2; i++){ // Over individuals
      unsigned cause = causes(i-1);
      if (cause > 0){
	// Marginal probability of failure
	res += logdF1(row, cause, i, data, sigmaMarg, u);
      }
      else {
	// Marginal probability of no failure
	unsigned cond_cause;
	if (i==1){
	  cond_cause = causes(1);
	}
	else {
	  cond_cause = causes(0);
	}
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double lik = 1;
	  if (cause < 0){
	    // Unconditional
	    double prob = F1(row, j, i, data);
	    lik -= prob;
	  }
	  else {
	    // Conditional
	    double prob = F1(row, j, i, cond_cause, data, sigmaCond, u);
	    lik -= prob;
	  }
	  res += log(lik);
	}
      }
    }
  }
  /* Contribution from u */
  if (full){
    vmat sig = sigmaU; // Variance-covariance matrix of u
    double inner = as_scalar(u*sig.inv*u.t());

    // PDF of u
    double logpdfu = log(pow(twopi,-(data.ncauses/2))) + sig.loginvsqdet - 0.5*inner;

    // Adding to the loglik
    res += logpdfu;
  }

  /* Return */
  return(res);
}

/////////////////////////////////////////////////////////////////////////////////////////////////
/* Score function of full loglikelihood */
rowvec Dloglikfull(unsigned row, DataPairs &data, const gmat &sigmaMarg, const gmat &sigmaJoint, const gmat &sigmaCond, vmat sigmaU, vec u, bool full=1){

  /* Estimation of pi, dpidu and dlogpidu */
  data.pi_gen(row, u);
  data.dpidu_gen(row, u);
  data.dlogpidu_gen(row, u);

  irowvec causes = data.causes_get(row); // Failure causes for pair in question

  rowvec res = zeros<rowvec>(data.ncauses); // Initialising output (score contribution)

  if ((causes(0) > 0) & (causes(1) > 0)){
    /* Both individuals experience failure */
    res = dlogdF2du(row, causes, data, sigmaJoint, u);
  }
  else if((causes(0) <= 0) & (causes(1) <= 0)){
    /* Neither individual experience failure */

    if ((causes(0) < 0) & (causes(1) < 0)){
      // Full follow-up for both individuals
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	rowvec likdu = zeros<rowvec>(data.ncauses);
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data);
	  rowvec probdu = dF1du(row, j, i, data);
	  lik -= prob;
	  likdu -= probdu;
	}
	res += (1/lik)*likdu;
      }
    }
    else if (((causes(0) < 0) & (causes(1) == 0)) | ((causes(0) == 0) & (causes(1) < 0))){
      // Full follow-up for only one individual
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	rowvec likdu = zeros<rowvec>(data.ncauses);
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  if (causes(i-1) < 0){
	    double prob = F1(row, j, i, data);
	    rowvec probdu = dF1du(row, j, i, data);
	    lik -= prob;
	    likdu -= probdu;
	  }
	  else {
	    double prob = F1(row, j, i, data, sigmaMarg, u);
	    rowvec probdu = dF1du(row, j, i, data, sigmaMarg, u);
	    lik -= prob;
	    likdu -= probdu;
	  }
	}
	res += (1/lik)*likdu;
      }
    }
    else {
      // Full follow-up for neither individual
      double lik = 1;
      rowvec likdu = zeros<rowvec>(data.ncauses);
      // Marginal probabilities
      for (unsigned i=1; i<=2; i++){ // Over individuals
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data, sigmaMarg, u);
	  rowvec probdu = dF1du(row, j, i, data, sigmaMarg, u);
	  lik -= prob; // Subtracting
	  likdu -= probdu;
	}
      }
      // Bivariate probabilities
      for (unsigned k=1; k<=data.ncauses; k++){ // Over failure causes
	for (unsigned l=1; l<=data.ncauses; l++){
	  irowvec vcauses(2);
	  vcauses(0) = k; vcauses(1) = l;
	  double prob = F2(row, vcauses, data, sigmaJoint, u);
	  rowvec probdu = dF2du(row, vcauses, data, sigmaJoint, u);
	  lik += prob; // Adding
	  likdu += probdu;
	}
      }
      res = (1/lik)*likdu;
    }
  }
  else {
    /* One individual experiences failure the other does not */
    for (unsigned i=1; i<=2; i++){ // Over individuals
      unsigned cause = causes(i-1);
      if (cause > 0){
	// Marginal probability of failure
	res += dlogdF1du(row, cause, i, data, sigmaMarg, u);
      }
      else {
	// Marginal probability of no failure
	unsigned cond_cause;
	if (i==1){
	  cond_cause = causes(1);
	}
	else {
	  cond_cause = causes(0);
	}
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double lik = 1;
	  rowvec likdu = zeros<rowvec>(data.ncauses);
	  if (cause < 0){ // Uncondtional
	    double prob = F1(row, j, i, data);
	    rowvec probdu = dF1du(row, j, i, data);
	    lik -= prob;
	    likdu -= probdu;
	  }
	  else { // Conditional
	    double prob = F1(row, j, i, cond_cause, data, sigmaCond, u);
	    rowvec probdu = dF1du(row, j, i, cond_cause, data, sigmaCond, u);
	    lik -= prob;
	    likdu -= probdu;
	  }
	  res += (1/lik)*likdu;
	}
      }
    }
  }
  /* Contribution from u */
  if (full){

    vmat sig = sigmaU; // Variance-covariance matrix etc. of u

    // Adding to the score
    res += -u.t()*sig.inv;
  };
  return(res);
}

/////////////////////////////////////////////////////////////////////////////
// FOR TESTING

// [[Rcpp::export]]
double loglikout(mat sigma, vec u, int ncauses, imat causes, mat alpha, mat dalpha, mat beta, mat gamma){

  // Initialising gmats of sigma (Joint, Cond)
  gmat sigmaJoint = gmat(ncauses, ncauses);
  gmat sigmaCond = gmat(ncauses, ncauses);
  gmat sigmaMarg = gmat(ncauses, 1);

  // Vectors for extracting rows and columns from sigma
  uvec rcJ(2); /* for joint */
  uvec rc1(1); /* for conditional */
  uvec rc2(ncauses+1); /* for conditional */
  uvec rcu(ncauses);
  for (int h=0; h<ncauses; h++){
    rcu(h) = ncauses + h;
  };

  // Calculating and setting sigmaJoint
  for (int h=0; h<ncauses; h++){
    for (int i=0; i<ncauses; i++){
      rcJ(0)=h;
      rcJ(1)=ncauses+i;
      vmat x = vmat(sigma, rcJ, rcu);
      sigmaJoint.set(h,i,x);
    };
  };

  // Calculating and setting sigmaMarg
  for (int h=0; h<ncauses; h++){
    rc1(0) = h;
    vmat x = vmat(sigma, rc1, rcu);
    sigmaMarg.set(h,1,x);
  };

  // Calculating and setting sigmaCond
  for (int h=0; h<ncauses; h++){
    for (int i=0; i<ncauses; i++){
      rc1(0) = h;
      rc2(0) = i;
      for (int j=0; j<ncauses; j++){
	rc2(j+1) = rcu(j);
      };
      vmat x = vmat(sigma, rc1, rc2);
      sigmaCond.set(h,i,x);
    };
  };

  // vmat of the us
  mat matU = sigma.submat(rcu,rcu);
  vmat sigmaU = vmat(matU);

  // Generating DataPairs
  DataPairs data = DataPairs(ncauses, causes, alpha, dalpha, beta, gamma);

  unsigned row = 1;

  // Estimating likelihood contribution
  double loglik = loglikfull(row, data, sigmaMarg, sigmaJoint, sigmaCond, sigmaU, u);

  // Return
  return loglik;
};

//rowvec Dloglikout(unsigned row, mat sigma, mat data, vec u){

  // Generating gmats of sigma (Marg, Joint, MargCond, sigU)

  // Generating DataPairs

  // Estimating score contribution
//  rowvec score = Dloglikfull(unsigned row, DataPairs data, gmat sigmaJoint, gmat sigmaMargCond, vmat sigmaU, vec u, bool full=1);

  // Return
//  return score;
//};
<commit_msg>export<commit_after>// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
#include <Rmath.h>

#include <vector>
#include <cassert>

#include "vmat.h"
#include "gmat.h"
#include "DataPairs.h"
#include "quadrule.h"
#include "pn.h"
#include "functions.h"

using namespace Rcpp;
using namespace arma;
using namespace std;

const double twopi = 2*datum::pi;

/////////////////////////////////////////////////////////////////////////////////////////////////
/* Full loglikelihood */
double loglikfull(unsigned row, DataPairs &data, const gmat &sigmaMarg, const gmat &sigmaJoint, const gmat &sigmaCond, vmat sigmaU, vec u, bool full=1){

  data.pi_gen(row, u); // Estimation of pi based on u

  irowvec causes = data.causes_get(row); // Failure causes for pair in question

  double res = 0; // Initialising output (loglik contribution)

  if ((causes(0) > 0) & (causes(1) > 0)){
    /* Both individuals experience failure */
    res = logdF2(row, causes, data, sigmaJoint, u);
  }
  else if((causes(0) <= 0) & (causes(1) <= 0)){
    /* Neither individual experience failure */

    if ((causes(0) < 0) & (causes(1) < 0)){
      // Full follow-up for both individuals
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data);
	  lik -= prob;
	}
	res += log(lik);
      }
    }
    else if (((causes(0) < 0) & (causes(1) == 0)) | ((causes(0) == 0) & (causes(1) < 0))){
      // Full follow-up for only one individual
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  if (causes(i-1) < 0){
	    double prob = F1(row, j, i, data);
	    lik -= prob;
	  }
	  else {
	    double prob = F1(row, j, i, data, sigmaMarg, u);
	    lik -= prob;
	  }
	}
	res += log(lik);
      }
    }
    else {
      // Full follow-up for neither individual
      double lik = 1;
      // Marginal probabilities
      for (unsigned i=1; i<=2; i++){ // Over individuals
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data, sigmaMarg, u);
	  lik -= prob; // Subtracting
	}
      }
      // Bivariate probabilities
      for (unsigned k=1; k<=data.ncauses; k++){ // Over failure causes
	for (unsigned l=1; l<=data.ncauses; l++){
	  irowvec vcauses(2);
	  vcauses(0) = k; vcauses(1) = l;
	  double prob = F2(row, vcauses, data, sigmaJoint, u);
	  lik += prob; // Adding
	}
      }
      res = log(lik);
    }
  }
  else {
    /* One individual experiences failure the other does not */
    for (unsigned i=1; i<=2; i++){ // Over individuals
      unsigned cause = causes(i-1);
      if (cause > 0){
	// Marginal probability of failure
	res += logdF1(row, cause, i, data, sigmaMarg, u);
      }
      else {
	// Marginal probability of no failure
	unsigned cond_cause;
	if (i==1){
	  cond_cause = causes(1);
	}
	else {
	  cond_cause = causes(0);
	}
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double lik = 1;
	  if (cause < 0){
	    // Unconditional
	    double prob = F1(row, j, i, data);
	    lik -= prob;
	  }
	  else {
	    // Conditional
	    double prob = F1(row, j, i, cond_cause, data, sigmaCond, u);
	    lik -= prob;
	  }
	  res += log(lik);
	}
      }
    }
  }
  /* Contribution from u */
  if (full){
    vmat sig = sigmaU; // Variance-covariance matrix of u
    double inner = as_scalar(u*sig.inv*u.t());

    // PDF of u
    double logpdfu = log(pow(twopi,-(data.ncauses/2))) + sig.loginvsqdet - 0.5*inner;

    // Adding to the loglik
    res += logpdfu;
  }

  /* Return */
  return(res);
}

/////////////////////////////////////////////////////////////////////////////////////////////////
/* Score function of full loglikelihood */
rowvec Dloglikfull(unsigned row, DataPairs &data, const gmat &sigmaMarg, const gmat &sigmaJoint, const gmat &sigmaCond, vmat sigmaU, vec u, bool full=1){

  /* Estimation of pi, dpidu and dlogpidu */
  data.pi_gen(row, u);
  data.dpidu_gen(row, u);
  data.dlogpidu_gen(row, u);

  irowvec causes = data.causes_get(row); // Failure causes for pair in question

  rowvec res = zeros<rowvec>(data.ncauses); // Initialising output (score contribution)

  if ((causes(0) > 0) & (causes(1) > 0)){
    /* Both individuals experience failure */
    res = dlogdF2du(row, causes, data, sigmaJoint, u);
  }
  else if((causes(0) <= 0) & (causes(1) <= 0)){
    /* Neither individual experience failure */

    if ((causes(0) < 0) & (causes(1) < 0)){
      // Full follow-up for both individuals
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	rowvec likdu = zeros<rowvec>(data.ncauses);
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data);
	  rowvec probdu = dF1du(row, j, i, data);
	  lik -= prob;
	  likdu -= probdu;
	}
	res += (1/lik)*likdu;
      }
    }
    else if (((causes(0) < 0) & (causes(1) == 0)) | ((causes(0) == 0) & (causes(1) < 0))){
      // Full follow-up for only one individual
      for (unsigned i=1; i<=2; i++){ // Over individuals
	double lik = 1;
	rowvec likdu = zeros<rowvec>(data.ncauses);
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  if (causes(i-1) < 0){
	    double prob = F1(row, j, i, data);
	    rowvec probdu = dF1du(row, j, i, data);
	    lik -= prob;
	    likdu -= probdu;
	  }
	  else {
	    double prob = F1(row, j, i, data, sigmaMarg, u);
	    rowvec probdu = dF1du(row, j, i, data, sigmaMarg, u);
	    lik -= prob;
	    likdu -= probdu;
	  }
	}
	res += (1/lik)*likdu;
      }
    }
    else {
      // Full follow-up for neither individual
      double lik = 1;
      rowvec likdu = zeros<rowvec>(data.ncauses);
      // Marginal probabilities
      for (unsigned i=1; i<=2; i++){ // Over individuals
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double prob = F1(row, j, i, data, sigmaMarg, u);
	  rowvec probdu = dF1du(row, j, i, data, sigmaMarg, u);
	  lik -= prob; // Subtracting
	  likdu -= probdu;
	}
      }
      // Bivariate probabilities
      for (unsigned k=1; k<=data.ncauses; k++){ // Over failure causes
	for (unsigned l=1; l<=data.ncauses; l++){
	  irowvec vcauses(2);
	  vcauses(0) = k; vcauses(1) = l;
	  double prob = F2(row, vcauses, data, sigmaJoint, u);
	  rowvec probdu = dF2du(row, vcauses, data, sigmaJoint, u);
	  lik += prob; // Adding
	  likdu += probdu;
	}
      }
      res = (1/lik)*likdu;
    }
  }
  else {
    /* One individual experiences failure the other does not */
    for (unsigned i=1; i<=2; i++){ // Over individuals
      unsigned cause = causes(i-1);
      if (cause > 0){
	// Marginal probability of failure
	res += dlogdF1du(row, cause, i, data, sigmaMarg, u);
      }
      else {
	// Marginal probability of no failure
	unsigned cond_cause;
	if (i==1){
	  cond_cause = causes(1);
	}
	else {
	  cond_cause = causes(0);
	}
	for (unsigned j=1; j<=data.ncauses; j++){ // Over failure causes
	  double lik = 1;
	  rowvec likdu = zeros<rowvec>(data.ncauses);
	  if (cause < 0){ // Uncondtional
	    double prob = F1(row, j, i, data);
	    rowvec probdu = dF1du(row, j, i, data);
	    lik -= prob;
	    likdu -= probdu;
	  }
	  else { // Conditional
	    double prob = F1(row, j, i, cond_cause, data, sigmaCond, u);
	    rowvec probdu = dF1du(row, j, i, cond_cause, data, sigmaCond, u);
	    lik -= prob;
	    likdu -= probdu;
	  }
	  res += (1/lik)*likdu;
	}
      }
    }
  }
  /* Contribution from u */
  if (full){

    vmat sig = sigmaU; // Variance-covariance matrix etc. of u

    // Adding to the score
    res += -u.t()*sig.inv;
  };
  return(res);
}

/////////////////////////////////////////////////////////////////////////////
// FOR TESTING

// [[Rcpp::export]]
double loglikout(mat sigma, vec u, int ncauses, imat causes, mat alpha, mat dalpha, mat beta, mat gamma){

  // Initialising gmats of sigma (Joint, Cond)
  gmat sigmaJoint = gmat(ncauses, ncauses);
  gmat sigmaCond = gmat(ncauses, ncauses);
  gmat sigmaMarg = gmat(ncauses, 1);

  // Vectors for extracting rows and columns from sigma
  uvec rcJ(2); /* for joint */
  uvec rc1(1); /* for conditional */
  uvec rc2(ncauses+1); /* for conditional */
  uvec rcu(ncauses);
  for (int h=0; h<ncauses; h++){
    rcu(h) = ncauses + h;
  };

  // Calculating and setting sigmaJoint
  for (int h=0; h<ncauses; h++){
    for (int i=0; i<ncauses; i++){
      rcJ(0)=h;
      rcJ(1)=ncauses+i;
      vmat x = vmat(sigma, rcJ, rcu);
      sigmaJoint.set(h,i,x);
    };
  };

  // Calculating and setting sigmaMarg
  for (int h=0; h<ncauses; h++){
    rc1(0) = h;
    vmat x = vmat(sigma, rc1, rcu);
    sigmaMarg.set(h,1,x);
  };

  // Calculating and setting sigmaCond
  for (int h=0; h<ncauses; h++){
    for (int i=0; i<ncauses; i++){
      rc1(0) = h;
      rc2(0) = i;
      for (int j=0; j<ncauses; j++){
	rc2(j+1) = rcu(j);
      };
      vmat x = vmat(sigma, rc1, rc2);
      sigmaCond.set(h,i,x);
    };
  };

  Rcpp::Rcout << "here " <<std::endl;

  // vmat of the us
  mat matU = sigma.submat(rcu,rcu);
  vmat sigmaU = vmat(matU);

  Rcpp::Rcout << "there " <<std::endl;

  // Generating DataPairs
  DataPairs data = DataPairs(ncauses, causes, alpha, dalpha, beta, gamma);

  unsigned row = 1;

  // Estimating likelihood contribution
  double loglik = loglikfull(row, data, sigmaMarg, sigmaJoint, sigmaCond, sigmaU, u);

  Rcpp::Rcout << "everywhere " <<std::endl;

  // Return
  return loglik;
};

//rowvec Dloglikout(unsigned row, mat sigma, mat data, vec u){

  // Generating gmats of sigma (Marg, Joint, MargCond, sigU)

  // Generating DataPairs

  // Estimating score contribution
//  rowvec score = Dloglikfull(unsigned row, DataPairs data, gmat sigmaJoint, gmat sigmaMargCond, vmat sigmaU, vec u, bool full=1);

  // Return
//  return score;
//};
<|endoftext|>