<commit_before>/*
 *  Copyright (C) 2007 Austin Robot Technology, Patrick Beeson
 *  Copyright (C) 2009, 2010 Austin Robot Technology, Jack O'Quin
 *
 *  License: Modified BSD Software License Agreement
 *
 *  $Id$
 */

/** \file
 *
 *  Input classes for the Velodyne HDL-64E 3D LIDAR:
 *
 *     Input -- virtual base class than can be used to access the data
 *              independently of its source
 *
 *     InputSocket -- derived class reads live data from the device
 *              via a UDP socket
 *
 *     InputPCAP -- derived class provides a similar interface from a
 *              PCAP dump
 */

#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <poll.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/file.h>
#include <velodyne_driver/input.h>

namespace velodyne_driver
{
  static const size_t packet_size = sizeof(velodyne_msgs::VelodynePacket::data);

  ////////////////////////////////////////////////////////////////////////
  // InputSocket class implementation
  ////////////////////////////////////////////////////////////////////////

  /** @brief constructor
   *
   *  @param private_nh private node handle for driver
   *  @param udp_port UDP port number to connect
   */
  InputSocket::InputSocket(ros::NodeHandle private_nh, uint16_t udp_port):
    Input()
  {
    sockfd_ = -1;

    // connect to Velodyne UDP port
    ROS_INFO_STREAM("Opening UDP socket: port " << udp_port);
    sockfd_ = socket(PF_INET, SOCK_DGRAM, 0);
    if (sockfd_ == -1)
      {
        perror("socket");               // TODO: ROS_ERROR errno
        return;
      }

    sockaddr_in my_addr;                     // my address information
    memset(&my_addr, 0, sizeof(my_addr));    // initialize to zeros
    my_addr.sin_family = AF_INET;            // host byte order
    my_addr.sin_port = htons(udp_port);      // short, in network byte order
    my_addr.sin_addr.s_addr = INADDR_ANY;    // automatically fill in my IP

    if (bind(sockfd_, (sockaddr *)&my_addr, sizeof(sockaddr)) == -1)
      {
        perror("bind");                 // TODO: ROS_ERROR errno
        return;
      }

    if (fcntl(sockfd_,F_SETFL, O_NONBLOCK|FASYNC) < 0)
      {
        perror("non-block");
        return;
      }

    ROS_DEBUG("Velodyne socket fd is %d\n", sockfd_);
  }

  /** @brief destructor */
  InputSocket::~InputSocket(void)
  {
    (void) close(sockfd_);
  }

  /** @brief Get one velodyne packet. */
  int InputSocket::getPacket(velodyne_msgs::VelodynePacket *pkt)
  {
    double time1 = ros::Time::now().toSec();

    struct pollfd fds[1];
    fds[0].fd = sockfd_;
    fds[0].events = POLLIN;
    static const int POLL_TIMEOUT = 1000; // one second (in msec)

    while (true)
      {
        // Unfortunately, the Linux kernel recvfrom() implementation
        // uses a non-interruptible sleep() when waiting for data,
        // which would cause this method to hang if the device is not
        // providing data.  We poll() the device first to make sure
        // the recvfrom() will not block.
        //
        // Note, however, that there is a known Linux kernel bug:
        //
        //   Under Linux, select() may report a socket file descriptor
        //   as "ready for reading", while nevertheless a subsequent
        //   read blocks.  This could for example happen when data has
        //   arrived but upon examination has wrong checksum and is
        //   discarded.  There may be other circumstances in which a
        //   file descriptor is spuriously reported as ready.  Thus it
        //   may be safer to use O_NONBLOCK on sockets that should not
        //   block.

        // poll() until input available
        do
          {
            int retval = poll(fds, 1, POLL_TIMEOUT);
            if (retval < 0)             // poll() error?
              {
                if (errno != EINTR)
                  ROS_ERROR("poll() error: %s", strerror(errno));
                return 1;
              }
            if (retval == 0)            // poll() timeout?
              {
                ROS_WARN("Velodyne poll() timeout");
                return 1;
              }
            if ((fds[0].revents & POLLERR)
                || (fds[0].revents & POLLHUP)
                || (fds[0].revents & POLLNVAL)) // device error?
              {
                ROS_ERROR("poll() reports Velodyne error");
                return 1;
              }
          } while ((fds[0].revents & POLLIN) == 0);

        // Receive packets that should now be available from the
        // socket using a blocking read.
        ssize_t nbytes = recvfrom(sockfd_, &pkt->data[0],
                                  packet_size,  0, NULL, NULL);

	if (nbytes < 0)
	  {
            if (errno != EWOULDBLOCK)
 	      {
                perror("recvfail");
		ROS_INFO("recvfail");
                return 1;
	      }
	  }
	else if ((size_t) nbytes == packet_size)
          {
            // read successful, done now
            break;
          }

        ROS_DEBUG_STREAM("incomplete Velodyne packet read: "
                         << nbytes << " bytes");
      }

    // Average the times at which we begin and end reading.  Use that to
    // estimate when the scan occurred.
    double time2 = ros::Time::now().toSec();
    pkt->stamp = ros::Time((time2 + time1) / 2.0);

    return 0;
  }

  ////////////////////////////////////////////////////////////////////////
  // InputPCAP class implementation
  ////////////////////////////////////////////////////////////////////////

  /** @brief constructor
   *
   *  @param private_nh private node handle for driver
   *  @param packet_rate expected device packet frequency (Hz)
   *  @param filename PCAP dump file name
   *  @param read_once read PCAP in a loop, unless false
   *  @param read_fast read PCAP at device rate, unless false
   *  @param repeat_delay time to wait before repeating PCAP data
   */
  InputPCAP::InputPCAP(ros::NodeHandle private_nh,
                       double packet_rate,
                       std::string filename,
                       bool read_once,
                       bool read_fast,
                       double repeat_delay):
    Input(),
    packet_rate_(packet_rate)
  {
    filename_ = filename;
    fp_ = NULL;
    pcap_ = NULL;
    empty_ = true;

    // get parameters using private node handle
    private_nh.param("read_once", read_once_, read_once);
    private_nh.param("read_fast", read_fast_, read_fast);
    private_nh.param("repeat_delay", repeat_delay_, repeat_delay);

    if (read_once_)
      ROS_INFO("Read input file only once.");
    if (read_fast_)
      ROS_INFO("Read input file as quickly as possible.");
    if (repeat_delay_ > 0.0)
      ROS_INFO("Delay %.3f seconds before repeating input file.",
               repeat_delay_);

    // Open the PCAP dump file
    ROS_INFO("Opening PCAP file \"%s\"", filename_.c_str());
    if ((pcap_ = pcap_open_offline(filename_.c_str(), errbuf_) ) == NULL)
      {
        ROS_FATAL("Error opening Velodyne socket dump file.");
        return;
      }
  }

  /** destructor */
  InputPCAP::~InputPCAP(void)
  {
    pcap_close(pcap_);
  }

  /** @brief Get one velodyne packet. */
  int InputPCAP::getPacket(velodyne_msgs::VelodynePacket *pkt)
  {
    struct pcap_pkthdr *header;
    const u_char *pkt_data;

    while (true)
      {
        int res;
        if ((res = pcap_next_ex(pcap_, &header, &pkt_data)) >= 0)
          {
            // Keep the reader from blowing through the file.  The
            // actual device generates either 2600 (64E) or 1808 (32E)
            // packets per second at 600 RPM.
            if (read_fast_ == false)
              packet_rate_.sleep();

            memcpy(&pkt->data[0], pkt_data+42, packet_size);
            pkt->stamp = ros::Time::now();
            empty_ = false;
            return 0;                   // success
          }

        if (empty_)                 // no data in file?
          {
            ROS_WARN("Error %d reading Velodyne packet: %s",
                     res, pcap_geterr(pcap_));
            return -1;
          }

        if (read_once_)
          {
            ROS_INFO("end of file reached -- done reading.");
            return -1;
          }

        if (repeat_delay_ > 0.0)
          {
            ROS_INFO("end of file reached -- delaying %.3f seconds.",
                     repeat_delay_);
            usleep(rint(repeat_delay_ * 1000000.0));
          }

        ROS_DEBUG("replaying Velodyne dump file");

        // I can't figure out how to rewind the file, because it
        // starts with some kind of header.  So, close the file
        // and reopen it with pcap.
        pcap_close(pcap_);
        pcap_ = pcap_open_offline(filename_.c_str(), errbuf_);
        empty_ = true;              // maybe the file disappeared?
      } // loop back and try again
  }

} // velodyne namespace
<commit_msg>driver: fixes a compile error on OS X<commit_after>/*
 *  Copyright (C) 2007 Austin Robot Technology, Patrick Beeson
 *  Copyright (C) 2009, 2010 Austin Robot Technology, Jack O'Quin
 *
 *  License: Modified BSD Software License Agreement
 *
 *  $Id$
 */

/** \file
 *
 *  Input classes for the Velodyne HDL-64E 3D LIDAR:
 *
 *     Input -- virtual base class than can be used to access the data
 *              independently of its source
 *
 *     InputSocket -- derived class reads live data from the device
 *              via a UDP socket
 *
 *     InputPCAP -- derived class provides a similar interface from a
 *              PCAP dump
 */

#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <poll.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/file.h>
#include <velodyne_driver/input.h>

namespace velodyne_driver
{
  static const size_t packet_size = sizeof(velodyne_msgs::VelodynePacket().data);

  ////////////////////////////////////////////////////////////////////////
  // InputSocket class implementation
  ////////////////////////////////////////////////////////////////////////

  /** @brief constructor
   *
   *  @param private_nh private node handle for driver
   *  @param udp_port UDP port number to connect
   */
  InputSocket::InputSocket(ros::NodeHandle private_nh, uint16_t udp_port):
    Input()
  {
    sockfd_ = -1;

    // connect to Velodyne UDP port
    ROS_INFO_STREAM("Opening UDP socket: port " << udp_port);
    sockfd_ = socket(PF_INET, SOCK_DGRAM, 0);
    if (sockfd_ == -1)
      {
        perror("socket");               // TODO: ROS_ERROR errno
        return;
      }

    sockaddr_in my_addr;                     // my address information
    memset(&my_addr, 0, sizeof(my_addr));    // initialize to zeros
    my_addr.sin_family = AF_INET;            // host byte order
    my_addr.sin_port = htons(udp_port);      // short, in network byte order
    my_addr.sin_addr.s_addr = INADDR_ANY;    // automatically fill in my IP

    if (bind(sockfd_, (sockaddr *)&my_addr, sizeof(sockaddr)) == -1)
      {
        perror("bind");                 // TODO: ROS_ERROR errno
        return;
      }

    if (fcntl(sockfd_,F_SETFL, O_NONBLOCK|FASYNC) < 0)
      {
        perror("non-block");
        return;
      }

    ROS_DEBUG("Velodyne socket fd is %d\n", sockfd_);
  }

  /** @brief destructor */
  InputSocket::~InputSocket(void)
  {
    (void) close(sockfd_);
  }

  /** @brief Get one velodyne packet. */
  int InputSocket::getPacket(velodyne_msgs::VelodynePacket *pkt)
  {
    double time1 = ros::Time::now().toSec();

    struct pollfd fds[1];
    fds[0].fd = sockfd_;
    fds[0].events = POLLIN;
    static const int POLL_TIMEOUT = 1000; // one second (in msec)

    while (true)
      {
        // Unfortunately, the Linux kernel recvfrom() implementation
        // uses a non-interruptible sleep() when waiting for data,
        // which would cause this method to hang if the device is not
        // providing data.  We poll() the device first to make sure
        // the recvfrom() will not block.
        //
        // Note, however, that there is a known Linux kernel bug:
        //
        //   Under Linux, select() may report a socket file descriptor
        //   as "ready for reading", while nevertheless a subsequent
        //   read blocks.  This could for example happen when data has
        //   arrived but upon examination has wrong checksum and is
        //   discarded.  There may be other circumstances in which a
        //   file descriptor is spuriously reported as ready.  Thus it
        //   may be safer to use O_NONBLOCK on sockets that should not
        //   block.

        // poll() until input available
        do
          {
            int retval = poll(fds, 1, POLL_TIMEOUT);
            if (retval < 0)             // poll() error?
              {
                if (errno != EINTR)
                  ROS_ERROR("poll() error: %s", strerror(errno));
                return 1;
              }
            if (retval == 0)            // poll() timeout?
              {
                ROS_WARN("Velodyne poll() timeout");
                return 1;
              }
            if ((fds[0].revents & POLLERR)
                || (fds[0].revents & POLLHUP)
                || (fds[0].revents & POLLNVAL)) // device error?
              {
                ROS_ERROR("poll() reports Velodyne error");
                return 1;
              }
          } while ((fds[0].revents & POLLIN) == 0);

        // Receive packets that should now be available from the
        // socket using a blocking read.
        ssize_t nbytes = recvfrom(sockfd_, &pkt->data[0],
                                  packet_size,  0, NULL, NULL);

	if (nbytes < 0)
	  {
            if (errno != EWOULDBLOCK)
 	      {
                perror("recvfail");
		ROS_INFO("recvfail");
                return 1;
	      }
	  }
	else if ((size_t) nbytes == packet_size)
          {
            // read successful, done now
            break;
          }

        ROS_DEBUG_STREAM("incomplete Velodyne packet read: "
                         << nbytes << " bytes");
      }

    // Average the times at which we begin and end reading.  Use that to
    // estimate when the scan occurred.
    double time2 = ros::Time::now().toSec();
    pkt->stamp = ros::Time((time2 + time1) / 2.0);

    return 0;
  }

  ////////////////////////////////////////////////////////////////////////
  // InputPCAP class implementation
  ////////////////////////////////////////////////////////////////////////

  /** @brief constructor
   *
   *  @param private_nh private node handle for driver
   *  @param packet_rate expected device packet frequency (Hz)
   *  @param filename PCAP dump file name
   *  @param read_once read PCAP in a loop, unless false
   *  @param read_fast read PCAP at device rate, unless false
   *  @param repeat_delay time to wait before repeating PCAP data
   */
  InputPCAP::InputPCAP(ros::NodeHandle private_nh,
                       double packet_rate,
                       std::string filename,
                       bool read_once,
                       bool read_fast,
                       double repeat_delay):
    Input(),
    packet_rate_(packet_rate)
  {
    filename_ = filename;
    fp_ = NULL;
    pcap_ = NULL;
    empty_ = true;

    // get parameters using private node handle
    private_nh.param("read_once", read_once_, read_once);
    private_nh.param("read_fast", read_fast_, read_fast);
    private_nh.param("repeat_delay", repeat_delay_, repeat_delay);

    if (read_once_)
      ROS_INFO("Read input file only once.");
    if (read_fast_)
      ROS_INFO("Read input file as quickly as possible.");
    if (repeat_delay_ > 0.0)
      ROS_INFO("Delay %.3f seconds before repeating input file.",
               repeat_delay_);

    // Open the PCAP dump file
    ROS_INFO("Opening PCAP file \"%s\"", filename_.c_str());
    if ((pcap_ = pcap_open_offline(filename_.c_str(), errbuf_) ) == NULL)
      {
        ROS_FATAL("Error opening Velodyne socket dump file.");
        return;
      }
  }

  /** destructor */
  InputPCAP::~InputPCAP(void)
  {
    pcap_close(pcap_);
  }

  /** @brief Get one velodyne packet. */
  int InputPCAP::getPacket(velodyne_msgs::VelodynePacket *pkt)
  {
    struct pcap_pkthdr *header;
    const u_char *pkt_data;

    while (true)
      {
        int res;
        if ((res = pcap_next_ex(pcap_, &header, &pkt_data)) >= 0)
          {
            // Keep the reader from blowing through the file.  The
            // actual device generates either 2600 (64E) or 1808 (32E)
            // packets per second at 600 RPM.
            if (read_fast_ == false)
              packet_rate_.sleep();

            memcpy(&pkt->data[0], pkt_data+42, packet_size);
            pkt->stamp = ros::Time::now();
            empty_ = false;
            return 0;                   // success
          }

        if (empty_)                 // no data in file?
          {
            ROS_WARN("Error %d reading Velodyne packet: %s",
                     res, pcap_geterr(pcap_));
            return -1;
          }

        if (read_once_)
          {
            ROS_INFO("end of file reached -- done reading.");
            return -1;
          }

        if (repeat_delay_ > 0.0)
          {
            ROS_INFO("end of file reached -- delaying %.3f seconds.",
                     repeat_delay_);
            usleep(rint(repeat_delay_ * 1000000.0));
          }

        ROS_DEBUG("replaying Velodyne dump file");

        // I can't figure out how to rewind the file, because it
        // starts with some kind of header.  So, close the file
        // and reopen it with pcap.
        pcap_close(pcap_);
        pcap_ = pcap_open_offline(filename_.c_str(), errbuf_);
        empty_ = true;              // maybe the file disappeared?
      } // loop back and try again
  }

} // velodyne namespace
<|endoftext|>


<commit_before>#include "rhodes/JNIRhodes.h"

#include "rhodes/jni/com_rhomobile_rhodes_alert_Alert.h"

#include <common/rhoparams.h>
#include <common/RhodesApp.h>

#undef DEFAULT_LOGCATEGORY
#define DEFAULT_LOGCATEGORY "Alert"

RHO_GLOBAL void JNICALL Java_com_rhomobile_rhodes_alert_Alert_doCallback
  (JNIEnv *env, jclass, jstring url, jstring id, jstring title)
{
    rho_rhodesapp_callPopupCallback(rho_cast<std::string>(env, url).c_str(),
        rho_cast<std::string>(env, id).c_str(), rho_cast<std::string>(env, title).c_str());
}

RHO_GLOBAL void alert_show_status(const char* szTitle, const char* szMessage, const char* szHide)
{
    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_ALERT);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "showStatusPopup", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
    if (!mid) return;

    RAWLOG_INFO("alert_show_status");

    jstring strMsg = rho_cast<jstring>(szMessage);
    jstring strHide = rho_cast<jstring>(szHide);
    jstring strTitle = rho_cast<jstring>(szTitle);

    env->CallStaticVoidMethod(cls, mid, strTitle, strMsg, strHide);
    env->DeleteLocalRef(strMsg);
}

RHO_GLOBAL void alert_show_popup(rho_param *p)
{
    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_ALERT);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "showPopup", "(Ljava/lang/Object;)V");
    if (!mid) return;

    if (p->type != RHO_PARAM_STRING && p->type != RHO_PARAM_HASH) {
        RAWLOG_ERROR("show_popup: wrong input parameter (expect String or Hash)");
        return;
    }

    jobject paramsObj = RhoValueConverter(env).createObject(p);
    env->CallStaticVoidMethod(cls, mid, paramsObj);
    env->DeleteLocalRef(paramsObj);
}

RHO_GLOBAL void alert_hide_popup()
{
    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_ALERT);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "hidePopup", "()V");
    if (!mid) return;
    env->CallStaticVoidMethod(cls, mid);
}

RHO_GLOBAL void alert_vibrate(void *arg)
{
    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_ALERT);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "vibrate", "(I)V");
    if (!mid) return;

    jint duration = 2500;
    if (arg)
        duration = (jint)arg;
    env->CallStaticVoidMethod(cls, mid, duration);
}

RHO_GLOBAL void alert_play_file(char* file_name, char *media_type)
{
    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_ALERT);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "playFile", "(Ljava/lang/String;Ljava/lang/String;)V");
    if (!mid) return;

    jstring objFileName = rho_cast<jstring>(file_name);
    jstring objMediaType = media_type ? rho_cast<jstring>(media_type) : NULL;
    env->CallStaticVoidMethod(cls, mid, objFileName, objMediaType);
    env->DeleteLocalRef(objFileName);
    if (objMediaType) env->DeleteLocalRef(objMediaType);
}

<commit_msg>Fix JNI string leaks on Android<commit_after>#include "rhodes/JNIRhodes.h"

#include "rhodes/jni/com_rhomobile_rhodes_alert_Alert.h"

#include <common/rhoparams.h>
#include <common/RhodesApp.h>

#undef DEFAULT_LOGCATEGORY
#define DEFAULT_LOGCATEGORY "Alert"

RHO_GLOBAL void JNICALL Java_com_rhomobile_rhodes_alert_Alert_doCallback
  (JNIEnv *env, jclass, jstring url, jstring id, jstring title)
{
    rho_rhodesapp_callPopupCallback(rho_cast<std::string>(env, url).c_str(),
        rho_cast<std::string>(env, id).c_str(), rho_cast<std::string>(env, title).c_str());
}

RHO_GLOBAL void alert_show_status(const char* szTitle, const char* szMessage, const char* szHide)
{
    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_ALERT);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "showStatusPopup", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
    if (!mid) return;

    RAWLOG_INFO("alert_show_status");

    jstring strMsg = rho_cast<jstring>(szMessage);
    jstring strHide = rho_cast<jstring>(szHide);
    jstring strTitle = rho_cast<jstring>(szTitle);

    env->CallStaticVoidMethod(cls, mid, strTitle, strMsg, strHide);
    env->DeleteLocalRef(strTitle);
    env->DeleteLocalRef(strHide);
    env->DeleteLocalRef(strMsg);
}

RHO_GLOBAL void alert_show_popup(rho_param *p)
{
    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_ALERT);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "showPopup", "(Ljava/lang/Object;)V");
    if (!mid) return;

    if (p->type != RHO_PARAM_STRING && p->type != RHO_PARAM_HASH) {
        RAWLOG_ERROR("show_popup: wrong input parameter (expect String or Hash)");
        return;
    }

    jobject paramsObj = RhoValueConverter(env).createObject(p);
    env->CallStaticVoidMethod(cls, mid, paramsObj);
    env->DeleteLocalRef(paramsObj);
}

RHO_GLOBAL void alert_hide_popup()
{
    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_ALERT);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "hidePopup", "()V");
    if (!mid) return;
    env->CallStaticVoidMethod(cls, mid);
}

RHO_GLOBAL void alert_vibrate(void *arg)
{
    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_ALERT);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "vibrate", "(I)V");
    if (!mid) return;

    jint duration = 2500;
    if (arg)
        duration = (jint)arg;
    env->CallStaticVoidMethod(cls, mid, duration);
}

RHO_GLOBAL void alert_play_file(char* file_name, char *media_type)
{
    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_ALERT);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "playFile", "(Ljava/lang/String;Ljava/lang/String;)V");
    if (!mid) return;

    jstring objFileName = rho_cast<jstring>(file_name);
    jstring objMediaType = media_type ? rho_cast<jstring>(media_type) : NULL;
    env->CallStaticVoidMethod(cls, mid, objFileName, objMediaType);
    env->DeleteLocalRef(objFileName);
    if (objMediaType) env->DeleteLocalRef(objMediaType);
}

<|endoftext|>


<commit_before>#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>

#include "../../system/itimer.c"
#include "CoreTimer.cpp"

Scheduler sched;

class Node
{
public:
	Node(): timer_ping(&sched) {

		// 第一种写法 std::function 调用成员函数
		timer_ping.callback = [this](Timer *timer) {
			on_timer(timer);
		};

		// 第二种写法 std::function 直接指向成员函数
		timer_ping.callback = std::bind(&Node::on_timer, this, std::placeholders::_1);

		timer_ping.start(1000, 5);
	}

	void on_timer(Timer *timer) {
		printf("ping remain: %d  ts: %d\n", timer->remain(), timer->timestamp);
	}

private:
	Timer timer_ping;
};

int main()
{
	Node node;
	while (1) {
		Sleep(10);
		sched.update(timeGetTime());
	}
	return 0;
}

<commit_msg>update main.cpp<commit_after>#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>

#include "../../system/itimer.c"
#include "CoreTimer.cpp"

Scheduler sched(1);

class Node
{
public:
	Node(): timer_ping(&sched) {

		// 第一种写法 std::function 调用成员函数
		timer_ping.callback = [this](Timer *timer) {
			on_timer(timer);
		};

		// 第二种写法 std::function 直接指向成员函数
		timer_ping.callback = std::bind(&Node::on_timer, this, std::placeholders::_1);

		timer_ping.start(1000, 5);
	}

	void on_timer(Timer *timer) {
		printf("ping remain: %d  ts: %d\n", timer->remain(), timer->timestamp);
	}

private:
	Timer timer_ping;
};

int main()
{
	Node node;
	while (1) {
		Sleep(10);
		sched.update(timeGetTime());
	}
	return 0;
}

<|endoftext|>


<commit_before>/****************************************************************************
 **
 ** Copyright (C) Qxt Foundation. Some rights reserved.
 **
 ** This file is part of the QxtGui module of the Qxt library.
 **
 ** This library is free software; you can redistribute it and/or modify it
 ** under the terms of the Common Public License, version 1.0, as published
 ** by IBM, and/or under the terms of the GNU Lesser General Public License,
 ** version 2.1, as published by the Free Software Foundation.
 **
 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
 ** FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** You should have received a copy of the CPL and the LGPL along with this
 ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
 ** included with the source distribution for more information.
 ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
 **
 ** <http://libqxt.org>  <foundation@libqxt.org>
 **
 ****************************************************************************/
#include "qxtcheckcombobox.h"
#include "qxtcheckcombobox_p.h"
#include <QLineEdit>
#include <QKeyEvent>

QxtCheckComboBoxPrivate::QxtCheckComboBoxPrivate() : containerMousePress(false)
{
    separator = QLatin1String(",");
}

bool QxtCheckComboBoxPrivate::eventFilter(QObject* receiver, QEvent* event)
{
    switch (event->type())
    {
    case QEvent::KeyPress:
    case QEvent::KeyRelease:
    {
        QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
        if (receiver == &qxt_p() && (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down))
        {
            qxt_p().showPopup();
            return true;
        }
        else if (keyEvent->key() == Qt::Key_Enter ||
                 keyEvent->key() == Qt::Key_Return ||
                 keyEvent->key() == Qt::Key_Escape)
        {
            // it is important to call QComboBox implementation
            qxt_p().QComboBox::hidePopup();
            if (keyEvent->key() != Qt::Key_Escape)
                return true;
        }
    }
    case QEvent::MouseButtonPress:
        containerMousePress = (receiver == qxt_p().view()->window());
        break;
    case QEvent::MouseButtonRelease:
        containerMousePress = false;;
        break;
    default:
        break;
    }
    return false;
}

void QxtCheckComboBoxPrivate::updateCheckedItems()
{
    QStringList items = qxt_p().checkedItems();
    if (items.isEmpty())
        qxt_p().setEditText(defaultText);
    else
        qxt_p().setEditText(items.join(separator));

    // TODO: find a way to recalculate a meaningful size hint

    emit qxt_p().checkedItemsChanged(items);
}

void QxtCheckComboBoxPrivate::toggleCheckState(int index)
{
    QVariant value = qxt_p().itemData(index, Qt::CheckStateRole);
    if (value.isValid())
    {
        Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
        qxt_p().setItemData(index, (state == Qt::Unchecked ? Qt::Checked : Qt::Unchecked), Qt::CheckStateRole);
    }
}

QxtCheckComboModel::QxtCheckComboModel(QObject* parent)
        : QStandardItemModel(0, 1, parent) // rows,cols
{
}

Qt::ItemFlags QxtCheckComboModel::flags(const QModelIndex& index) const
{
    return QStandardItemModel::flags(index) | Qt::ItemIsUserCheckable;
}

QVariant QxtCheckComboModel::data(const QModelIndex& index, int role) const
{
    QVariant value = QStandardItemModel::data(index, role);
    if (index.isValid() && role == Qt::CheckStateRole && !value.isValid())
        value = Qt::Unchecked;
    return value;
}

bool QxtCheckComboModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
    bool ok = QStandardItemModel::setData(index, value, role);
    if (ok && role == Qt::CheckStateRole)
    {
        emit dataChanged(index, index);
        emit checkStateChanged();
    }
    return ok;
}

/*!
    \class QxtCheckComboBox
    \inmodule QxtGui
    \brief The QxtCheckComboBox widget is an extended QComboBox with checkable items.

    QxtComboBox is a specialized combo box with checkable items.
    Checked items are collected together in the line edit.

    \code
    QxtCheckComboBox* comboBox = new QxtCheckComboBox(this);
    comboBox->addItems(...);
    comboBox->setItemCheckState(2, Qt::Checked);
    comboBox->setItemCheckState(4, Qt::Checked);
    // OR
    comboBox->setCheckedItems(QStringList() << "dolor" << "amet");
    \endcode

    \image qxtcheckcombobox.png "QxtCheckComboBox in Plastique style."
 */

/*!
    \fn QxtCheckComboBox::checkedItemsChanged(const QStringList& items)

    This signal is emitted whenever the checked \a items have been changed.
 */

/*!
    Constructs a new QxtCheckComboBox with \a parent.
 */
QxtCheckComboBox::QxtCheckComboBox(QWidget* parent) : QComboBox(parent)
{
    QXT_INIT_PRIVATE(QxtCheckComboBox);
    setModel(new QxtCheckComboModel(this));
    connect(this, SIGNAL(activated(int)), &qxt_d(), SLOT(toggleCheckState(int)));
    connect(model(), SIGNAL(checkStateChanged()), &qxt_d(), SLOT(updateCheckedItems()));
    connect(model(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), &qxt_d(), SLOT(updateCheckedItems()));
    connect(model(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)), &qxt_d(), SLOT(updateCheckedItems()));

    // read-only contents
    QLineEdit* lineEdit = new QLineEdit(this);
    lineEdit->setReadOnly(true);
    setLineEdit(lineEdit);
    setInsertPolicy(QComboBox::NoInsert);

    view()->installEventFilter(&qxt_d());
    view()->window()->installEventFilter(&qxt_d());
    view()->viewport()->installEventFilter(&qxt_d());
    this->installEventFilter(&qxt_d());
}

/*!
    Destructs the combo box.
 */
QxtCheckComboBox::~QxtCheckComboBox()
{
}

/*!
    \reimp
 */
void QxtCheckComboBox::hidePopup()
{
    if (qxt_d().containerMousePress)
        QComboBox::hidePopup();
}

/*!
    Returns the check state of the item at \a index.
 */
Qt::CheckState QxtCheckComboBox::itemCheckState(int index) const
{
    return static_cast<Qt::CheckState>(itemData(index, Qt::CheckStateRole).toInt());
}

/*!
    Sets the check \a state of the item at \a index.
 */
void QxtCheckComboBox::setItemCheckState(int index, Qt::CheckState state)
{
    setItemData(index, state, Qt::CheckStateRole);
}

/*!
    \property QxtCheckComboBox::checkedItems
    \brief the checked items.
 */
QStringList QxtCheckComboBox::checkedItems() const
{
    QStringList items;
    if (model())
    {
        QModelIndex index = model()->index(0, modelColumn(), rootModelIndex());
        QModelIndexList indexes = model()->match(index, Qt::CheckStateRole, Qt::Checked, -1, Qt::MatchExactly);
        foreach(const QModelIndex& index, indexes)
        items += index.data().toString();
    }
    return items;
}

void QxtCheckComboBox::setCheckedItems(const QStringList& items)
{
    // not the most efficient solution but most likely nobody
    // will put too many items into a combo box anyway so...
    foreach(const QString& text, items)
    {
        const int index = findText(text);
        setItemCheckState(index, index != -1 ? Qt::Checked : Qt::Unchecked);
    }
}

/*!
    \property QxtCheckComboBox::defaultText
    \brief the default text.

    The default text is shown when there are no checked items.
    The default value is an empty string.
 */
QString QxtCheckComboBox::defaultText() const
{
    return qxt_d().defaultText;
}

void QxtCheckComboBox::setDefaultText(const QString& text)
{
    if (qxt_d().defaultText != text)
    {
        qxt_d().defaultText = text;
        qxt_d().updateCheckedItems();
    }
}

/*!
    \property QxtCheckComboBox::separator
    \brief the default separator.

    The checked items are joined together with the separator string.
    The default value is a comma (",").
 */
QString QxtCheckComboBox::separator() const
{
    return qxt_d().separator;
}

void QxtCheckComboBox::setSeparator(const QString& separator)
{
    if (qxt_d().separator != separator)
    {
        qxt_d().separator = separator;
        qxt_d().updateCheckedItems();
    }
}
<commit_msg>Fixed #63 QxtCheckComboBox display not correct<commit_after>/****************************************************************************
 **
 ** Copyright (C) Qxt Foundation. Some rights reserved.
 **
 ** This file is part of the QxtGui module of the Qxt library.
 **
 ** This library is free software; you can redistribute it and/or modify it
 ** under the terms of the Common Public License, version 1.0, as published
 ** by IBM, and/or under the terms of the GNU Lesser General Public License,
 ** version 2.1, as published by the Free Software Foundation.
 **
 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
 ** FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** You should have received a copy of the CPL and the LGPL along with this
 ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
 ** included with the source distribution for more information.
 ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
 **
 ** <http://libqxt.org>  <foundation@libqxt.org>
 **
 ****************************************************************************/
#include "qxtcheckcombobox.h"
#include "qxtcheckcombobox_p.h"
#include <QLineEdit>
#include <QKeyEvent>

QxtCheckComboBoxPrivate::QxtCheckComboBoxPrivate() : containerMousePress(false)
{
    separator = QLatin1String(",");
}

bool QxtCheckComboBoxPrivate::eventFilter(QObject* receiver, QEvent* event)
{
    switch (event->type())
    {
    case QEvent::KeyPress:
    case QEvent::KeyRelease:
    {
        QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
        if (receiver == &qxt_p() && (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down))
        {
            qxt_p().showPopup();
            return true;
        }
        else if (keyEvent->key() == Qt::Key_Enter ||
                 keyEvent->key() == Qt::Key_Return ||
                 keyEvent->key() == Qt::Key_Escape)
        {
            // it is important to call QComboBox implementation
            qxt_p().QComboBox::hidePopup();
            if (keyEvent->key() != Qt::Key_Escape)
                return true;
        }
    }
    case QEvent::MouseButtonPress:
        containerMousePress = (receiver == qxt_p().view()->window());
        break;
    case QEvent::MouseButtonRelease:
        containerMousePress = false;;
        break;
    default:
        break;
    }
    return false;
}

void QxtCheckComboBoxPrivate::updateCheckedItems()
{
    QStringList items = qxt_p().checkedItems();
    if (items.isEmpty())
        qxt_p().setEditText(defaultText);
    else
        qxt_p().setEditText(items.join(separator));

    // TODO: find a way to recalculate a meaningful size hint

    emit qxt_p().checkedItemsChanged(items);
}

void QxtCheckComboBoxPrivate::toggleCheckState(int index)
{
    QVariant value = qxt_p().itemData(index, Qt::CheckStateRole);
    if (value.isValid())
    {
        Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
        qxt_p().setItemData(index, (state == Qt::Unchecked ? Qt::Checked : Qt::Unchecked), Qt::CheckStateRole);
    }
}

QxtCheckComboModel::QxtCheckComboModel(QObject* parent)
        : QStandardItemModel(0, 1, parent) // rows,cols
{
}

Qt::ItemFlags QxtCheckComboModel::flags(const QModelIndex& index) const
{
    return QStandardItemModel::flags(index) | Qt::ItemIsUserCheckable;
}

QVariant QxtCheckComboModel::data(const QModelIndex& index, int role) const
{
    QVariant value = QStandardItemModel::data(index, role);
    if (index.isValid() && role == Qt::CheckStateRole && !value.isValid())
        value = Qt::Unchecked;
    return value;
}

bool QxtCheckComboModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
    bool ok = QStandardItemModel::setData(index, value, role);
    if (ok && role == Qt::CheckStateRole)
    {
        emit dataChanged(index, index);
        emit checkStateChanged();
    }
    return ok;
}

/*!
    \class QxtCheckComboBox
    \inmodule QxtGui
    \brief The QxtCheckComboBox widget is an extended QComboBox with checkable items.

    QxtComboBox is a specialized combo box with checkable items.
    Checked items are collected together in the line edit.

    \code
    QxtCheckComboBox* comboBox = new QxtCheckComboBox(this);
    comboBox->addItems(...);
    comboBox->setItemCheckState(2, Qt::Checked);
    comboBox->setItemCheckState(4, Qt::Checked);
    // OR
    comboBox->setCheckedItems(QStringList() << "dolor" << "amet");
    \endcode

    \image qxtcheckcombobox.png "QxtCheckComboBox in Plastique style."
 */

/*!
    \fn QxtCheckComboBox::checkedItemsChanged(const QStringList& items)

    This signal is emitted whenever the checked \a items have been changed.
 */

/*!
    Constructs a new QxtCheckComboBox with \a parent.
 */
QxtCheckComboBox::QxtCheckComboBox(QWidget* parent) : QComboBox(parent)
{
    QXT_INIT_PRIVATE(QxtCheckComboBox);
    setModel(new QxtCheckComboModel(this));
    connect(this, SIGNAL(activated(int)), &qxt_d(), SLOT(toggleCheckState(int)));
    connect(model(), SIGNAL(checkStateChanged()), &qxt_d(), SLOT(updateCheckedItems()));
    connect(model(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), &qxt_d(), SLOT(updateCheckedItems()));
    connect(model(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)), &qxt_d(), SLOT(updateCheckedItems()));

    // read-only contents
    QLineEdit* lineEdit = new QLineEdit(this);
    lineEdit->setReadOnly(true);
    setLineEdit(lineEdit);
    lineEdit->disconnect(this);
    setInsertPolicy(QComboBox::NoInsert);

    view()->installEventFilter(&qxt_d());
    view()->window()->installEventFilter(&qxt_d());
    view()->viewport()->installEventFilter(&qxt_d());
    this->installEventFilter(&qxt_d());
}

/*!
    Destructs the combo box.
 */
QxtCheckComboBox::~QxtCheckComboBox()
{
}

/*!
    \reimp
 */
void QxtCheckComboBox::hidePopup()
{
    if (qxt_d().containerMousePress)
        QComboBox::hidePopup();
}

/*!
    Returns the check state of the item at \a index.
 */
Qt::CheckState QxtCheckComboBox::itemCheckState(int index) const
{
    return static_cast<Qt::CheckState>(itemData(index, Qt::CheckStateRole).toInt());
}

/*!
    Sets the check \a state of the item at \a index.
 */
void QxtCheckComboBox::setItemCheckState(int index, Qt::CheckState state)
{
    setItemData(index, state, Qt::CheckStateRole);
}

/*!
    \property QxtCheckComboBox::checkedItems
    \brief the checked items.
 */
QStringList QxtCheckComboBox::checkedItems() const
{
    QStringList items;
    if (model())
    {
        QModelIndex index = model()->index(0, modelColumn(), rootModelIndex());
        QModelIndexList indexes = model()->match(index, Qt::CheckStateRole, Qt::Checked, -1, Qt::MatchExactly);
        foreach(const QModelIndex& index, indexes)
        items += index.data().toString();
    }
    return items;
}

void QxtCheckComboBox::setCheckedItems(const QStringList& items)
{
    // not the most efficient solution but most likely nobody
    // will put too many items into a combo box anyway so...
    foreach(const QString& text, items)
    {
        const int index = findText(text);
        setItemCheckState(index, index != -1 ? Qt::Checked : Qt::Unchecked);
    }
}

/*!
    \property QxtCheckComboBox::defaultText
    \brief the default text.

    The default text is shown when there are no checked items.
    The default value is an empty string.
 */
QString QxtCheckComboBox::defaultText() const
{
    return qxt_d().defaultText;
}

void QxtCheckComboBox::setDefaultText(const QString& text)
{
    if (qxt_d().defaultText != text)
    {
        qxt_d().defaultText = text;
        qxt_d().updateCheckedItems();
    }
}

/*!
    \property QxtCheckComboBox::separator
    \brief the default separator.

    The checked items are joined together with the separator string.
    The default value is a comma (",").
 */
QString QxtCheckComboBox::separator() const
{
    return qxt_d().separator;
}

void QxtCheckComboBox::setSeparator(const QString& separator)
{
    if (qxt_d().separator != separator)
    {
        qxt_d().separator = separator;
        qxt_d().updateCheckedItems();
    }
}
<|endoftext|>


<commit_before>#include "001.h"
#include "cartridge.h"

bool M001::on_cpu_read(address_t addr, byte_t& value)
{
    if (addr >= 0x8000 && addr < 0xC000)
    {
        value = *(prg_l_ + (addr & 0x3FFF));
        return true;
    }

    if (addr >= 0xC000)
    {
        value = *(prg_h_ + (addr & 0x3FFF));
        return true;
    }

    return false;
}

bool M001::on_cpu_write(address_t addr, byte_t value)
{
    if (addr >= 0x8000)
    {
        bool full = register_ & 0b1;
        (register_ >>= 1) |= ((0x1 & value) << 4);
        bool reset = (0x80 & value);

        if (full || reset)
        {
            int op = (addr >> 13) & 0b11;
            switch (op)
            {
            case 0: // control
            {
                if (full)
                    control_ = register_;
                else
                    control_ |= 0xC;
            }
            break;

            case 1: // CHR bank 0
                chr_switch(true);
                break;

            case 2: // CHR bank 1
                chr_switch(false);
                break;

            case 3: // PRG bank
            {
                if (reset)
                    prg_h_ = cart_->prg_rom_.back().data();
                else
                    prg_switch();
            }
            break;
            }

            register_ = 0b10000;
        }

        return true;
    }
    return false;
}

bool M001::on_ppu_read(address_t addr, byte_t& value)
{
    if (addr < 0x1000 && chr_l_ != nullptr)
    {
        value = *(chr_l_ + addr);
        return true;
    }
    else if (addr >= 0x1000 && addr < 0x2000 && chr_h_ != nullptr)
    {
        value = *(chr_h_ + (addr & 0xFFF));
        return true;
    }

    return false;
}

bool M001::on_ppu_write(address_t addr, byte_t value)
{
    return false;
}

std::pair<byte_t*, address_t> M001::get_bank(address_t addr) const
{
    if (addr >= 0x8000)
    {
        return  std::make_pair((addr < 0xC000) ? prg_l_ : prg_h_, addr & 0x3FFF);
    }

    return std::make_pair(nullptr, 0u);
}

void M001::chr_switch(bool low)
{
    bool mod_4kb = (control_ >> 4) == 1;

    if (mod_4kb)
    {
        int idx = register_ / 2;
        address_t offset = (register_ % 2 != 0) ? 0x1000 : 0;

        byte_t *& chr = (low) ? chr_l_ : chr_h_;
        chr = cart_->chr_rom_[idx].data() + offset;
    }
    else if (low)
    {
        chr_l_ = cart_->chr_rom_[register_].data();
        chr_h_ = chr_l_ + 0x1000;
    }
}

void M001::prg_switch()
{
    byte_t mode = (control_ >> 2) & 0b11;
    byte_t idx = register_ & 0b1111;

    switch (mode)
    {
    case 0:
    case 1:
    {
        idx = idx >> 1;
        prg_l_ = cart_->prg_rom_[idx].data();
        prg_h_ = (cart_->prg_rom_.size() > idx) ? cart_->prg_rom_[idx + 1].data() : prg_l_;
    }
    break;

    case 2:
    {
        prg_l_ = cart_->prg_rom_[0].data();

        idx = idx / 2;
        address_t offset = (idx % 2 != 0) ? 0x2000 : 0;
        prg_h_ = cart_->prg_rom_[idx].data() + offset;
    }
    break;

    case 3:
    {
        prg_h_ = cart_->prg_rom_.back().data();

        idx = idx / 2;
        address_t offset = (idx % 2 != 0) ? 0x2000 : 0;
        prg_l_ = cart_->prg_rom_[idx].data() + offset;
    }
    break;
    }
}<commit_msg>Trying to fix some issues with mapper 001<commit_after>#include "001.h"
#include "cartridge.h"

bool M001::on_cpu_read(address_t addr, byte_t& value)
{
    if (addr >= 0x6000 && addr < 0x8000)
    {
        value = cart_->wram_[addr & 0x1FFF];
        return true;
    }

    if (addr >= 0x8000 && addr < 0xC000)
    {
        value = *(prg_l_ + (addr & 0x3FFF));
        return true;
    }

    if (addr >= 0xC000)
    {
        value = *(prg_h_ + (addr & 0x3FFF));
        return true;
    }

    return false;
}

bool M001::on_cpu_write(address_t addr, byte_t value)
{
    if (addr >= 0x6000 && addr < 0x8000)
    {
        cart_->wram_[addr & 0x1FFF] = value;
        return true;
    }

    if (addr >= 0x8000)
    {
        bool full = register_ & 0b1;
        (register_ >>= 1) |= ((0x1 & value) << 4);
        bool reset = (0x80 & value);

        if (full || reset)
        {
            int op = (addr >> 13) & 0b11;
            switch (op)
            {
            case 0: // control
            {
                if (full)
                    control_ = register_;
                else
                    control_ |= 0xC;
            }
            break;

            case 1: // CHR bank 0
                chr_switch(true);
                break;

            case 2: // CHR bank 1
                chr_switch(false);
                break;

            case 3: // PRG bank
            {
                if (reset)
                    prg_h_ = cart_->prg_rom_.back().data();
                else
                    prg_switch();
            }
            break;
            }

            register_ = 0b10000;
        }

        return true;
    }
    return false;
}

bool M001::on_ppu_read(address_t addr, byte_t& value)
{
    if (addr < 0x1000 && chr_l_ != nullptr)
    {
        value = *(chr_l_ + addr);
        return true;
    }
    else if (addr >= 0x1000 && addr < 0x2000 && chr_h_ != nullptr)
    {
        value = *(chr_h_ + (addr & 0xFFF));
        return true;
    }

    return false;
}

bool M001::on_ppu_write(address_t addr, byte_t value)
{
    return false;
}

std::pair<byte_t*, address_t> M001::get_bank(address_t addr) const
{
    if (addr >= 0x8000)
    {
        return  std::make_pair((addr < 0xC000) ? prg_l_ : prg_h_, addr & 0x3FFF);
    }

    return std::make_pair(nullptr, 0u);
}

void M001::chr_switch(bool low)
{
    bool mod_4kb = (control_ >> 4) == 1;

    if (mod_4kb)
    {
        int idx = register_ / 2;
        address_t offset = (register_ % 2 != 0) ? 0x1000 : 0;

        byte_t *& chr = (low) ? chr_l_ : chr_h_;
        chr = cart_->chr_rom_[idx].data() + offset;
    }
    else if (low && cart_->chr_rom_.size() > 0)
    {
        chr_l_ = cart_->chr_rom_[register_].data();
        chr_h_ = chr_l_ + 0x1000;
    }
}

void M001::prg_switch()
{
    byte_t mode = (control_ >> 2) & 0b11;
    byte_t idx = register_ & 0b1111;

    switch (mode)
    {
    case 0:
    case 1:
    {
        idx = idx >> 1;
        prg_l_ = cart_->prg_rom_[idx].data();
        prg_h_ = (cart_->prg_rom_.size() > idx) ? cart_->prg_rom_[idx + 1].data() : prg_l_;
    }
    break;

    case 2:
    {
        prg_l_ = cart_->prg_rom_.front().data();
        prg_h_ = cart_->prg_rom_[idx].data();
    }
    break;

    case 3:
    {
        prg_h_ = cart_->prg_rom_.back().data();
        prg_l_ = cart_->prg_rom_[idx].data();
    }
    break;
    }
}<|endoftext|>


<commit_before>#include <stdio.h>
#include <time.h>

#include "../headers/geom.h"
#include "../headers/bigtest.h"
#include "../headers/io.h"

/**
 * Run relate between two large geometries to test the performance
 * of the sweepline intersection detection algorithm
*/

void run(int nPts, GeometryFactory *fact) {
	clock_t startTime, endTime;
	double size=100.0;
	double armLen=50.0;
	int nArms=10;
	Polygon *poly=GeometryTestFactory::createSineStar(fact,0.0,0.0,size,armLen,nArms,nPts);
	Polygon *box=GeometryTestFactory::createSineStar(fact,0.0,size/2,size,armLen,nArms,nPts);
//	Polygon *box=GeometryTestFactory::createBox(fact,0,0,1,100.0);

	startTime=clock();
    poly->intersects(box);
    endTime=clock();
	double totalTime=(double)(endTime-startTime);
	printf( "n Pts: %i  Executed in %6.0f ms.\n",nPts,totalTime);
//	cout << "n Pts: " << nPts << "   Executed in " << totalTime << endl;
}

int main(int argC, char* argV[]) {

	GeometryFactory *fact=new GeometryFactory();

	run(1000,fact);
	run(2000,fact);
	run(4000,fact);
	run(8000,fact);
	run(16000,fact);
	run(32000,fact);
	run(64000,fact);
	run(128000,fact);
	run(256000,fact);
	run(512000,fact);
	run(1024000,fact);

	cout << "Done" << endl;
}
<commit_msg>Added return value.<commit_after>#include <stdio.h>
#include <time.h>

#include "../headers/geom.h"
#include "../headers/bigtest.h"
#include "../headers/io.h"

/**
 * Run relate between two large geometries to test the performance
 * of the sweepline intersection detection algorithm
*/

void run(int nPts, GeometryFactory *fact) {
	clock_t startTime, endTime;
	double size=100.0;
	double armLen=50.0;
	int nArms=10;
	Polygon *poly=GeometryTestFactory::createSineStar(fact,0.0,0.0,size,armLen,nArms,nPts);
	Polygon *box=GeometryTestFactory::createSineStar(fact,0.0,size/2,size,armLen,nArms,nPts);
//	Polygon *box=GeometryTestFactory::createBox(fact,0,0,1,100.0);

	startTime=clock();
    poly->intersects(box);
    endTime=clock();
	double totalTime=(double)(endTime-startTime);
	printf( "n Pts: %i  Executed in %6.0f ms.\n",nPts,totalTime);
//	cout << "n Pts: " << nPts << "   Executed in " << totalTime << endl;
}

int main(int argC, char* argV[]) {

	GeometryFactory *fact=new GeometryFactory();

	run(1000,fact);
	run(2000,fact);
	run(4000,fact);
	run(8000,fact);
	run(16000,fact);
	run(32000,fact);
	run(64000,fact);
	run(128000,fact);
	run(256000,fact);
	run(512000,fact);
	run(1024000,fact);

	cout << "Done" << endl;

	return 0;
}
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

This program 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 of the License, or (at your option) any later
version.

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

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"
#include "OgreResourceManager.h"

#include "OgreException.h"
#include "OgreArchive.h"
#include "OgreArchiveManager.h"
#include "OgreStringVector.h"
#include "OgreStringConverter.h"
#include "OgreResourceGroupManager.h"

namespace Ogre {

    //-----------------------------------------------------------------------
    ResourceManager::ResourceManager()
		: mNextHandle(1), mMemoryUsage(0), mLoadOrder(0), mVerbose(true)
    {
        // Init memory limit & usage
        mMemoryBudget = std::numeric_limits<unsigned long>::max();
    }
    //-----------------------------------------------------------------------
    ResourceManager::~ResourceManager()
    {
        removeAll();
    }
	//-----------------------------------------------------------------------
    ResourcePtr ResourceManager::create(const String& name, const String& group,
		bool isManual, ManualResourceLoader* loader, const NameValuePairList* params)
	{
		// Call creation implementation
		ResourcePtr ret = ResourcePtr(
            createImpl(name, getNextHandle(), group, isManual, loader, params));
        if (params)
            ret->setParameterList(*params);

		addImpl(ret);
		// Tell resource group manager
		ResourceGroupManager::getSingleton()._notifyResourceCreated(ret);
		return ret;

	}
    //-----------------------------------------------------------------------
    ResourceManager::ResourceCreateOrRetrieveResult
	ResourceManager::createOrRetrieve(
		const String& name, const String& group,
		bool isManual, ManualResourceLoader* loader,
		const NameValuePairList* params)
	{
		// Lock for the whole get / insert
		OGRE_LOCK_AUTO_MUTEX

		ResourcePtr res = getByName(name, group);
		bool created = false;
		if (res.isNull())
		{
			created = true;
			res = create(name, group, isManual, loader, params);
		}

		return ResourceCreateOrRetrieveResult(res, created);
	}
    //-----------------------------------------------------------------------
    ResourcePtr ResourceManager::prepare(const String& name,
        const String& group, bool isManual, ManualResourceLoader* loader,
        const NameValuePairList* loadParams)
    {
        ResourcePtr r = createOrRetrieve(name,group,isManual,loader,loadParams).first;
		// ensure prepared
        r->prepare();
        return r;
    }
    //-----------------------------------------------------------------------
    ResourcePtr ResourceManager::load(const String& name,
        const String& group, bool isManual, ManualResourceLoader* loader,
        const NameValuePairList* loadParams)
    {
        ResourcePtr r = createOrRetrieve(name,group,isManual,loader,loadParams).first;
		// ensure loaded
        r->load();
        return r;
    }
    //-----------------------------------------------------------------------
	void ResourceManager::addImpl( ResourcePtr& res )
	{
		OGRE_LOCK_AUTO_MUTEX

			std::pair<ResourceMap::iterator, bool> result;
		if(ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(res->getGroup()))
		{
			result = mResources.insert( ResourceMap::value_type( res->getName(), res ) );
		}
		else
		{
			ResourceWithGroupMap::iterator itGroup = mResourcesWithGroup.find(res->getGroup());

			// we will create the group if it doesn't exists in our list
			if( itGroup == mResourcesWithGroup.end())
			{
				ResourceMap dummy;
				mResourcesWithGroup.insert( ResourceWithGroupMap::value_type( res->getGroup(), dummy ) );
				itGroup = mResourcesWithGroup.find(res->getGroup());
			}
			result = itGroup->second.insert( ResourceMap::value_type( res->getName(), res ) );

		}

		if (!result.second)
		{
			// Attempt to resolve the collision
			if(ResourceGroupManager::getSingleton().getLoadingListener())
			{
				if(ResourceGroupManager::getSingleton().getLoadingListener()->resourceCollision(res.get(), this))
				{
					// Try to do the addition again, no seconds attempts to resolve collisions are allowed
					std::pair<ResourceMap::iterator, bool> result;
					if(ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(res->getGroup()))
					{
						result = mResources.insert( ResourceMap::value_type( res->getName(), res ) );
					}
					else
					{
						ResourceWithGroupMap::iterator itGroup = mResourcesWithGroup.find(res->getGroup());
						result = itGroup->second.insert( ResourceMap::value_type( res->getName(), res ) );
					}
					if (!result.second)
					{
						OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "Resource with the name " + res->getName() +
							" already exists.", "ResourceManager::add");
					}

					std::pair<ResourceHandleMap::iterator, bool> resultHandle =
						mResourcesByHandle.insert( ResourceHandleMap::value_type( res->getHandle(), res ) );
					if (!resultHandle.second)
					{
						OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "Resource with the handle " +
							StringConverter::toString((long) (res->getHandle())) +
							" already exists.", "ResourceManager::add");
					}
				}
			}
		}
		else
		{
			// Insert the handle
			std::pair<ResourceHandleMap::iterator, bool> resultHandle =
				mResourcesByHandle.insert( ResourceHandleMap::value_type( res->getHandle(), res ) );
			if (!resultHandle.second)
			{
				OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "Resource with the handle " +
					StringConverter::toString((long) (res->getHandle())) +
					" already exists.", "ResourceManager::add");
			}
		}
	}
	//-----------------------------------------------------------------------
	void ResourceManager::removeImpl( ResourcePtr& res )
	{
		OGRE_LOCK_AUTO_MUTEX

		if(ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(res->getGroup()))
		{
			ResourceMap::iterator nameIt = mResources.find(res->getName());
			if (nameIt != mResources.end())
			{
				mResources.erase(nameIt);
			}
		}
		else
		{
			ResourceWithGroupMap::iterator groupIt = mResourcesWithGroup.find(res->getGroup());
			if (groupIt != mResourcesWithGroup.end())
			{
				ResourceMap::iterator nameIt = groupIt->second.find(res->getName());
				if (nameIt != groupIt->second.end())
				{
					groupIt->second.erase(nameIt);
				}

				if (groupIt->second.empty())
				{
					mResourcesWithGroup.erase(groupIt);
				}
			}
		}

		ResourceHandleMap::iterator handleIt = mResourcesByHandle.find(res->getHandle());
		if (handleIt != mResourcesByHandle.end())
		{
			mResourcesByHandle.erase(handleIt);
		}
		// Tell resource group manager
		ResourceGroupManager::getSingleton()._notifyResourceRemoved(res);
	}
    //-----------------------------------------------------------------------
    void ResourceManager::setMemoryBudget( size_t bytes)
    {
        // Update limit & check usage
        mMemoryBudget = bytes;
        checkUsage();
    }
    //-----------------------------------------------------------------------
    size_t ResourceManager::getMemoryBudget(void) const
    {
        return mMemoryBudget;
    }
	//-----------------------------------------------------------------------
	void ResourceManager::unload(const String& name)
	{
		ResourcePtr res = getByName(name);

		if (!res.isNull())
		{
			// Unload resource
			res->unload();

		}
	}
	//-----------------------------------------------------------------------
	void ResourceManager::unload(ResourceHandle handle)
	{
		ResourcePtr res = getByHandle(handle);

		if (!res.isNull())
		{
			// Unload resource
			res->unload();

		}
	}
	//-----------------------------------------------------------------------
	void ResourceManager::unloadAll(bool reloadableOnly)
	{
		OGRE_LOCK_AUTO_MUTEX

		ResourceMap::iterator i, iend;
		iend = mResources.end();
		for (i = mResources.begin(); i != iend; ++i)
		{
			if (!reloadableOnly || i->second->isReloadable())
			{
				i->second->unload();
			}
		}

	}
	//-----------------------------------------------------------------------
	void ResourceManager::reloadAll(bool reloadableOnly)
	{
		OGRE_LOCK_AUTO_MUTEX

		ResourceMap::iterator i, iend;
		iend = mResources.end();
		for (i = mResources.begin(); i != iend; ++i)
		{
			if (!reloadableOnly || i->second->isReloadable())
			{
				i->second->reload();
			}
		}

	}
    //-----------------------------------------------------------------------
    void ResourceManager::unloadUnreferencedResources(bool reloadableOnly)
    {
        OGRE_LOCK_AUTO_MUTEX

        ResourceMap::iterator i, iend;
        iend = mResources.end();
        for (i = mResources.begin(); i != iend; ++i)
        {
            // A use count of 3 means that only RGM and RM have references
            // RGM has one (this one) and RM has 2 (by name and by handle)
            if (i->second.useCount() == ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS)
            {
                Resource* res = i->second.get();
                if (!reloadableOnly || res->isReloadable())
                {
                    res->unload();
                }
            }
        }
    }
    //-----------------------------------------------------------------------
    void ResourceManager::reloadUnreferencedResources(bool reloadableOnly)
    {
        OGRE_LOCK_AUTO_MUTEX

        ResourceMap::iterator i, iend;
        iend = mResources.end();
        for (i = mResources.begin(); i != iend; ++i)
        {
            // A use count of 3 means that only RGM and RM have references
            // RGM has one (this one) and RM has 2 (by name and by handle)
            if (i->second.useCount() == ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS)
            {
                Resource* res = i->second.get();
                if (!reloadableOnly || res->isReloadable())
                {
                    res->reload();
                }
            }
        }
    }
    //-----------------------------------------------------------------------
    void ResourceManager::remove(ResourcePtr& res)
    {
        removeImpl(res);
    }
	//-----------------------------------------------------------------------
	void ResourceManager::remove(const String& name)
	{
		ResourcePtr res = getByName(name);

		if (!res.isNull())
		{
			removeImpl(res);
		}
	}
	//-----------------------------------------------------------------------
	void ResourceManager::remove(ResourceHandle handle)
	{
		ResourcePtr res = getByHandle(handle);

		if (!res.isNull())
		{
			removeImpl(res);
		}
	}
	//-----------------------------------------------------------------------
	void ResourceManager::removeAll(void)
	{
		OGRE_LOCK_AUTO_MUTEX

		mResources.clear();
		mResourcesWithGroup.clear();
		mResourcesByHandle.clear();
		// Notify resource group manager
		ResourceGroupManager::getSingleton()._notifyAllResourcesRemoved(this);
	}
    //-----------------------------------------------------------------------
    ResourcePtr ResourceManager::getByName(const String& name, const String& groupName /* = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME */)
    {
		OGRE_LOCK_AUTO_MUTEX

		ResourcePtr res;

		// if not in the global pool - get it from the grouped pool
		if(!ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(groupName))
		{
			ResourceWithGroupMap::iterator itGroup = mResourcesWithGroup.find(groupName);

			if( itGroup != mResourcesWithGroup.end())
			{
				ResourceMap::iterator it = itGroup->second.find(name);

				if( it != itGroup->second.end())
				{
					res = it->second;
				}
			}
		}

		// if didn't find it the grouped pool - get it from the global pool
		if (res.isNull())
		{

			ResourceMap::iterator it = mResources.find(name);

			if( it != mResources.end())
			{
				res = it->second;
			}
			else
			{
				// this is the case when we need to search also in the grouped hash
				if (groupName == ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME)
				{
					ResourceWithGroupMap::iterator iter = mResourcesWithGroup.begin();
					ResourceWithGroupMap::iterator iterE = mResourcesWithGroup.end();
					for ( ; iter != iterE ; iter++ )
					{
						ResourceMap::iterator it = iter->second.find(name);

						if( it != iter->second.end())
						{
							res = it->second;
							break;
						}
					}
				}
			}
		}

		return res;

    }
    //-----------------------------------------------------------------------
    ResourcePtr ResourceManager::getByHandle(ResourceHandle handle)
    {
		OGRE_LOCK_AUTO_MUTEX

        ResourceHandleMap::iterator it = mResourcesByHandle.find(handle);
        if (it == mResourcesByHandle.end())
        {
            return ResourcePtr();
        }
        else
        {
            return it->second;
        }
    }
    //-----------------------------------------------------------------------
    ResourceHandle ResourceManager::getNextHandle(void)
    {
		OGRE_LOCK_AUTO_MUTEX

        return mNextHandle++;
    }
    //-----------------------------------------------------------------------
    void ResourceManager::checkUsage(void)
    {
        // TODO Page out here?
    }
	//-----------------------------------------------------------------------
	void ResourceManager::_notifyResourceTouched(Resource* res)
	{
		// TODO
	}
	//-----------------------------------------------------------------------
	void ResourceManager::_notifyResourceLoaded(Resource* res)
	{
		OGRE_LOCK_AUTO_MUTEX

		mMemoryUsage += res->getSize();
	}
	//-----------------------------------------------------------------------
	void ResourceManager::_notifyResourceUnloaded(Resource* res)
	{
		OGRE_LOCK_AUTO_MUTEX

		mMemoryUsage -= res->getSize();
	}
	//-----------------------------------------------------------------------

}

<commit_msg>fixed a deadlock<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

This program 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 of the License, or (at your option) any later
version.

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

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"
#include "OgreResourceManager.h"

#include "OgreException.h"
#include "OgreArchive.h"
#include "OgreArchiveManager.h"
#include "OgreStringVector.h"
#include "OgreStringConverter.h"
#include "OgreResourceGroupManager.h"

namespace Ogre {

    //-----------------------------------------------------------------------
    ResourceManager::ResourceManager()
		: mNextHandle(1), mMemoryUsage(0), mLoadOrder(0), mVerbose(true)
    {
        // Init memory limit & usage
        mMemoryBudget = std::numeric_limits<unsigned long>::max();
    }
    //-----------------------------------------------------------------------
    ResourceManager::~ResourceManager()
    {
        removeAll();
    }
	//-----------------------------------------------------------------------
    ResourcePtr ResourceManager::create(const String& name, const String& group,
		bool isManual, ManualResourceLoader* loader, const NameValuePairList* params)
	{
		// Call creation implementation
		ResourcePtr ret = ResourcePtr(
            createImpl(name, getNextHandle(), group, isManual, loader, params));
        if (params)
            ret->setParameterList(*params);

		addImpl(ret);
		// Tell resource group manager
		ResourceGroupManager::getSingleton()._notifyResourceCreated(ret);
		return ret;

	}
    //-----------------------------------------------------------------------
    ResourceManager::ResourceCreateOrRetrieveResult
	ResourceManager::createOrRetrieve(
		const String& name, const String& group,
		bool isManual, ManualResourceLoader* loader,
		const NameValuePairList* params)
	{
		// Lock for the whole get / insert
		OGRE_LOCK_AUTO_MUTEX

		ResourcePtr res = getByName(name, group);
		bool created = false;
		if (res.isNull())
		{
			created = true;
			res = create(name, group, isManual, loader, params);
		}

		return ResourceCreateOrRetrieveResult(res, created);
	}
    //-----------------------------------------------------------------------
    ResourcePtr ResourceManager::prepare(const String& name,
        const String& group, bool isManual, ManualResourceLoader* loader,
        const NameValuePairList* loadParams)
    {
        ResourcePtr r = createOrRetrieve(name,group,isManual,loader,loadParams).first;
		// ensure prepared
        r->prepare();
        return r;
    }
    //-----------------------------------------------------------------------
    ResourcePtr ResourceManager::load(const String& name,
        const String& group, bool isManual, ManualResourceLoader* loader,
        const NameValuePairList* loadParams)
    {
        ResourcePtr r = createOrRetrieve(name,group,isManual,loader,loadParams).first;
		// ensure loaded
        r->load();
        return r;
    }
    //-----------------------------------------------------------------------
	void ResourceManager::addImpl( ResourcePtr& res )
	{
		OGRE_LOCK_AUTO_MUTEX

			std::pair<ResourceMap::iterator, bool> result;
		if(ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(res->getGroup()))
		{
			result = mResources.insert( ResourceMap::value_type( res->getName(), res ) );
		}
		else
		{
			ResourceWithGroupMap::iterator itGroup = mResourcesWithGroup.find(res->getGroup());

			// we will create the group if it doesn't exists in our list
			if( itGroup == mResourcesWithGroup.end())
			{
				ResourceMap dummy;
				mResourcesWithGroup.insert( ResourceWithGroupMap::value_type( res->getGroup(), dummy ) );
				itGroup = mResourcesWithGroup.find(res->getGroup());
			}
			result = itGroup->second.insert( ResourceMap::value_type( res->getName(), res ) );

		}

		if (!result.second)
		{
			// Attempt to resolve the collision
			if(ResourceGroupManager::getSingleton().getLoadingListener())
			{
				if(ResourceGroupManager::getSingleton().getLoadingListener()->resourceCollision(res.get(), this))
				{
					// Try to do the addition again, no seconds attempts to resolve collisions are allowed
					std::pair<ResourceMap::iterator, bool> result;
					if(ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(res->getGroup()))
					{
						result = mResources.insert( ResourceMap::value_type( res->getName(), res ) );
					}
					else
					{
						ResourceWithGroupMap::iterator itGroup = mResourcesWithGroup.find(res->getGroup());
						result = itGroup->second.insert( ResourceMap::value_type( res->getName(), res ) );
					}
					if (!result.second)
					{
						OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "Resource with the name " + res->getName() +
							" already exists.", "ResourceManager::add");
					}

					std::pair<ResourceHandleMap::iterator, bool> resultHandle =
						mResourcesByHandle.insert( ResourceHandleMap::value_type( res->getHandle(), res ) );
					if (!resultHandle.second)
					{
						OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "Resource with the handle " +
							StringConverter::toString((long) (res->getHandle())) +
							" already exists.", "ResourceManager::add");
					}
				}
			}
		}
		else
		{
			// Insert the handle
			std::pair<ResourceHandleMap::iterator, bool> resultHandle =
				mResourcesByHandle.insert( ResourceHandleMap::value_type( res->getHandle(), res ) );
			if (!resultHandle.second)
			{
				OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "Resource with the handle " +
					StringConverter::toString((long) (res->getHandle())) +
					" already exists.", "ResourceManager::add");
			}
		}
	}
	//-----------------------------------------------------------------------
	void ResourceManager::removeImpl( ResourcePtr& res )
	{
		OGRE_LOCK_AUTO_MUTEX

		if(ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(res->getGroup()))
		{
			ResourceMap::iterator nameIt = mResources.find(res->getName());
			if (nameIt != mResources.end())
			{
				mResources.erase(nameIt);
			}
		}
		else
		{
			ResourceWithGroupMap::iterator groupIt = mResourcesWithGroup.find(res->getGroup());
			if (groupIt != mResourcesWithGroup.end())
			{
				ResourceMap::iterator nameIt = groupIt->second.find(res->getName());
				if (nameIt != groupIt->second.end())
				{
					groupIt->second.erase(nameIt);
				}

				if (groupIt->second.empty())
				{
					mResourcesWithGroup.erase(groupIt);
				}
			}
		}

		ResourceHandleMap::iterator handleIt = mResourcesByHandle.find(res->getHandle());
		if (handleIt != mResourcesByHandle.end())
		{
			mResourcesByHandle.erase(handleIt);
		}
		// Tell resource group manager
		ResourceGroupManager::getSingleton()._notifyResourceRemoved(res);
	}
    //-----------------------------------------------------------------------
    void ResourceManager::setMemoryBudget( size_t bytes)
    {
        // Update limit & check usage
        mMemoryBudget = bytes;
        checkUsage();
    }
    //-----------------------------------------------------------------------
    size_t ResourceManager::getMemoryBudget(void) const
    {
        return mMemoryBudget;
    }
	//-----------------------------------------------------------------------
	void ResourceManager::unload(const String& name)
	{
		ResourcePtr res = getByName(name);

		if (!res.isNull())
		{
			// Unload resource
			res->unload();

		}
	}
	//-----------------------------------------------------------------------
	void ResourceManager::unload(ResourceHandle handle)
	{
		ResourcePtr res = getByHandle(handle);

		if (!res.isNull())
		{
			// Unload resource
			res->unload();

		}
	}
	//-----------------------------------------------------------------------
	void ResourceManager::unloadAll(bool reloadableOnly)
	{
		OGRE_LOCK_AUTO_MUTEX

		ResourceMap::iterator i, iend;
		iend = mResources.end();
		for (i = mResources.begin(); i != iend; ++i)
		{
			if (!reloadableOnly || i->second->isReloadable())
			{
				i->second->unload();
			}
		}

	}
	//-----------------------------------------------------------------------
	void ResourceManager::reloadAll(bool reloadableOnly)
	{
		OGRE_LOCK_AUTO_MUTEX

		ResourceMap::iterator i, iend;
		iend = mResources.end();
		for (i = mResources.begin(); i != iend; ++i)
		{
			if (!reloadableOnly || i->second->isReloadable())
			{
				i->second->reload();
			}
		}

	}
    //-----------------------------------------------------------------------
    void ResourceManager::unloadUnreferencedResources(bool reloadableOnly)
    {
        OGRE_LOCK_AUTO_MUTEX

        ResourceMap::iterator i, iend;
        iend = mResources.end();
        for (i = mResources.begin(); i != iend; ++i)
        {
            // A use count of 3 means that only RGM and RM have references
            // RGM has one (this one) and RM has 2 (by name and by handle)
            if (i->second.useCount() == ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS)
            {
                Resource* res = i->second.get();
                if (!reloadableOnly || res->isReloadable())
                {
                    res->unload();
                }
            }
        }
    }
    //-----------------------------------------------------------------------
    void ResourceManager::reloadUnreferencedResources(bool reloadableOnly)
    {
        OGRE_LOCK_AUTO_MUTEX

        ResourceMap::iterator i, iend;
        iend = mResources.end();
        for (i = mResources.begin(); i != iend; ++i)
        {
            // A use count of 3 means that only RGM and RM have references
            // RGM has one (this one) and RM has 2 (by name and by handle)
            if (i->second.useCount() == ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS)
            {
                Resource* res = i->second.get();
                if (!reloadableOnly || res->isReloadable())
                {
                    res->reload();
                }
            }
        }
    }
    //-----------------------------------------------------------------------
    void ResourceManager::remove(ResourcePtr& res)
    {
        removeImpl(res);
    }
	//-----------------------------------------------------------------------
	void ResourceManager::remove(const String& name)
	{
		ResourcePtr res = getByName(name);

		if (!res.isNull())
		{
			removeImpl(res);
		}
	}
	//-----------------------------------------------------------------------
	void ResourceManager::remove(ResourceHandle handle)
	{
		ResourcePtr res = getByHandle(handle);

		if (!res.isNull())
		{
			removeImpl(res);
		}
	}
	//-----------------------------------------------------------------------
	void ResourceManager::removeAll(void)
	{
		OGRE_LOCK_AUTO_MUTEX

		mResources.clear();
		mResourcesWithGroup.clear();
		mResourcesByHandle.clear();
		// Notify resource group manager
		ResourceGroupManager::getSingleton()._notifyAllResourcesRemoved(this);
	}
    //-----------------------------------------------------------------------
    ResourcePtr ResourceManager::getByName(const String& name, const String& groupName /* = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME */)
    {
		ResourcePtr res;

		// if not in the global pool - get it from the grouped pool
		if(!ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(groupName))
		{
			OGRE_LOCK_AUTO_MUTEX
			ResourceWithGroupMap::iterator itGroup = mResourcesWithGroup.find(groupName);

			if( itGroup != mResourcesWithGroup.end())
			{
				ResourceMap::iterator it = itGroup->second.find(name);

				if( it != itGroup->second.end())
				{
					res = it->second;
				}
			}
		}

		// if didn't find it the grouped pool - get it from the global pool
		if (res.isNull())
		{
			OGRE_LOCK_AUTO_MUTEX

			ResourceMap::iterator it = mResources.find(name);

			if( it != mResources.end())
			{
				res = it->second;
			}
			else
			{
				// this is the case when we need to search also in the grouped hash
				if (groupName == ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME)
				{
					ResourceWithGroupMap::iterator iter = mResourcesWithGroup.begin();
					ResourceWithGroupMap::iterator iterE = mResourcesWithGroup.end();
					for ( ; iter != iterE ; iter++ )
					{
						ResourceMap::iterator it = iter->second.find(name);

						if( it != iter->second.end())
						{
							res = it->second;
							break;
						}
					}
				}
			}
		}

		return res;
    }
    //-----------------------------------------------------------------------
    ResourcePtr ResourceManager::getByHandle(ResourceHandle handle)
    {
		OGRE_LOCK_AUTO_MUTEX

        ResourceHandleMap::iterator it = mResourcesByHandle.find(handle);
        if (it == mResourcesByHandle.end())
        {
            return ResourcePtr();
        }
        else
        {
            return it->second;
        }
    }
    //-----------------------------------------------------------------------
    ResourceHandle ResourceManager::getNextHandle(void)
    {
		OGRE_LOCK_AUTO_MUTEX

        return mNextHandle++;
    }
    //-----------------------------------------------------------------------
    void ResourceManager::checkUsage(void)
    {
        // TODO Page out here?
    }
	//-----------------------------------------------------------------------
	void ResourceManager::_notifyResourceTouched(Resource* res)
	{
		// TODO
	}
	//-----------------------------------------------------------------------
	void ResourceManager::_notifyResourceLoaded(Resource* res)
	{
		OGRE_LOCK_AUTO_MUTEX

		mMemoryUsage += res->getSize();
	}
	//-----------------------------------------------------------------------
	void ResourceManager::_notifyResourceUnloaded(Resource* res)
	{
		OGRE_LOCK_AUTO_MUTEX

		mMemoryUsage -= res->getSize();
	}
	//-----------------------------------------------------------------------

}

<|endoftext|>