<commit_before>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <algorithm>
#include <limits>
#include <vector>

#include "webrtc/modules/remote_bitrate_estimator/include/send_time_history.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc/test/gtest.h"

namespace webrtc {
namespace test {

static const int kDefaultHistoryLengthMs = 1000;

class SendTimeHistoryTest : public ::testing::Test {
 protected:
  SendTimeHistoryTest()
      : clock_(0), history_(&clock_, kDefaultHistoryLengthMs) {}
  ~SendTimeHistoryTest() {}

  virtual void SetUp() {}

  virtual void TearDown() {}

  void AddPacketWithSendTime(uint16_t sequence_number,
                             size_t length,
                             int64_t send_time_ms,
                             const PacedPacketInfo& pacing_info) {
    PacketFeedback packet(clock_.TimeInMilliseconds(), sequence_number, length,
                          0, 0, pacing_info);
    history_.AddAndRemoveOld(packet);
    history_.OnSentPacket(sequence_number, send_time_ms);
  }

  webrtc::SimulatedClock clock_;
  SendTimeHistory history_;
};

TEST_F(SendTimeHistoryTest, SaveAndRestoreNetworkId) {
  const PacedPacketInfo kPacingInfo(0, 5, 1200);
  uint16_t sequence_number = 0;
  int64_t now_ms = clock_.TimeInMilliseconds();
  for (int i = 1; i < 5; ++i) {
    PacketFeedback packet(now_ms, sequence_number++, 1000, i, i - 1,
                          kPacingInfo);
    history_.AddAndRemoveOld(packet);
    history_.OnSentPacket(sequence_number, now_ms);
    PacketFeedback restored(now_ms, sequence_number);
    EXPECT_TRUE(history_.GetFeedback(&restored, sequence_number));
    EXPECT_EQ(packet.local_net_id, restored.local_net_id);
    EXPECT_EQ(packet.remote_net_id, restored.remote_net_id);
  }
}

TEST_F(SendTimeHistoryTest, AddRemoveOne) {
  const uint16_t kSeqNo = 10;
  // TODO(philipel): Fix PacedPacketInfo constructor?
  const PacedPacketInfo kPacingInfo(0, 5, 1200);
  const PacketFeedback kSentPacket(0, 1, kSeqNo, 1, kPacingInfo);
  AddPacketWithSendTime(kSeqNo, 1, 1, kPacingInfo);

  PacketFeedback received_packet(0, 0, kSeqNo, 0, kPacingInfo);
  EXPECT_TRUE(history_.GetFeedback(&received_packet, false));
  EXPECT_EQ(kSentPacket, received_packet);

  PacketFeedback received_packet2(0, 0, kSeqNo, 0, kPacingInfo);
  EXPECT_TRUE(history_.GetFeedback(&received_packet2, true));
  EXPECT_EQ(kSentPacket, received_packet2);

  PacketFeedback received_packet3(0, 0, kSeqNo, 0, kPacingInfo);
  EXPECT_FALSE(history_.GetFeedback(&received_packet3, true));
}

TEST_F(SendTimeHistoryTest, PopulatesExpectedFields) {
  const uint16_t kSeqNo = 10;
  const int64_t kSendTime = 1000;
  const int64_t kReceiveTime = 2000;
  const size_t kPayloadSize = 42;
  const PacedPacketInfo kPacingInfo(3, 10, 1212);

  AddPacketWithSendTime(kSeqNo, kPayloadSize, kSendTime, kPacingInfo);

  PacketFeedback packet_feedback(kReceiveTime, kSeqNo);
  EXPECT_TRUE(history_.GetFeedback(&packet_feedback, true));
  EXPECT_EQ(kReceiveTime, packet_feedback.arrival_time_ms);
  EXPECT_EQ(kSendTime, packet_feedback.send_time_ms);
  EXPECT_EQ(kSeqNo, packet_feedback.sequence_number);
  EXPECT_EQ(kPayloadSize, packet_feedback.payload_size);
  EXPECT_EQ(kPacingInfo, packet_feedback.pacing_info);
}

TEST_F(SendTimeHistoryTest, AddThenRemoveOutOfOrder) {
  std::vector<PacketFeedback> sent_packets;
  std::vector<PacketFeedback> received_packets;
  const size_t num_items = 100;
  const size_t kPacketSize = 400;
  const size_t kTransmissionTime = 1234;
  const PacedPacketInfo kPacingInfo(1, 2, 200);
  for (size_t i = 0; i < num_items; ++i) {
    sent_packets.push_back(PacketFeedback(0, static_cast<int64_t>(i),
                                          static_cast<uint16_t>(i), kPacketSize,
                                          kPacingInfo));
    received_packets.push_back(PacketFeedback(
        static_cast<int64_t>(i) + kTransmissionTime, 0,
        static_cast<uint16_t>(i), kPacketSize, PacedPacketInfo()));
  }
  for (size_t i = 0; i < num_items; ++i) {
    PacketFeedback packet = sent_packets[i];
    packet.arrival_time_ms = -1;
    packet.send_time_ms = -1;
    history_.AddAndRemoveOld(packet);
  }
  for (size_t i = 0; i < num_items; ++i)
    history_.OnSentPacket(sent_packets[i].sequence_number,
                          sent_packets[i].send_time_ms);
  std::random_shuffle(received_packets.begin(), received_packets.end());
  for (size_t i = 0; i < num_items; ++i) {
    PacketFeedback packet = received_packets[i];
    EXPECT_TRUE(history_.GetFeedback(&packet, false));
    PacketFeedback sent_packet = sent_packets[packet.sequence_number];
    sent_packet.arrival_time_ms = packet.arrival_time_ms;
    EXPECT_EQ(sent_packet, packet);
    EXPECT_TRUE(history_.GetFeedback(&packet, true));
  }
  for (PacketFeedback packet : sent_packets)
    EXPECT_FALSE(history_.GetFeedback(&packet, false));
}

TEST_F(SendTimeHistoryTest, HistorySize) {
  const int kItems = kDefaultHistoryLengthMs / 100;
  for (int i = 0; i < kItems; ++i) {
    clock_.AdvanceTimeMilliseconds(100);
    AddPacketWithSendTime(i, 0, i * 100, PacedPacketInfo());
  }
  for (int i = 0; i < kItems; ++i) {
    PacketFeedback packet(0, 0, static_cast<uint16_t>(i), 0, PacedPacketInfo());
    EXPECT_TRUE(history_.GetFeedback(&packet, false));
    EXPECT_EQ(i * 100, packet.send_time_ms);
  }
  clock_.AdvanceTimeMilliseconds(101);
  AddPacketWithSendTime(kItems, 0, kItems * 101, PacedPacketInfo());
  PacketFeedback packet(0, 0, 0, 0, PacedPacketInfo());
  EXPECT_FALSE(history_.GetFeedback(&packet, false));
  for (int i = 1; i < (kItems + 1); ++i) {
    PacketFeedback packet2(0, 0, static_cast<uint16_t>(i), 0,
                           PacedPacketInfo());
    EXPECT_TRUE(history_.GetFeedback(&packet2, false));
    int64_t expected_time_ms = (i == kItems) ? i * 101 : i * 100;
    EXPECT_EQ(expected_time_ms, packet2.send_time_ms);
  }
}

TEST_F(SendTimeHistoryTest, HistorySizeWithWraparound) {
  const uint16_t kMaxSeqNo = std::numeric_limits<uint16_t>::max();
  AddPacketWithSendTime(kMaxSeqNo - 2, 0, 0, PacedPacketInfo());

  clock_.AdvanceTimeMilliseconds(100);
  AddPacketWithSendTime(kMaxSeqNo - 1, 1, 100, PacedPacketInfo());

  clock_.AdvanceTimeMilliseconds(100);
  AddPacketWithSendTime(kMaxSeqNo, 0, 200, PacedPacketInfo());

  clock_.AdvanceTimeMilliseconds(kDefaultHistoryLengthMs - 200 + 1);
  AddPacketWithSendTime(0, 0, kDefaultHistoryLengthMs, PacedPacketInfo());

  PacketFeedback packet(0, static_cast<uint16_t>(kMaxSeqNo - 2));
  EXPECT_FALSE(history_.GetFeedback(&packet, false));
  PacketFeedback packet2(0, static_cast<uint16_t>(kMaxSeqNo - 1));
  EXPECT_TRUE(history_.GetFeedback(&packet2, false));
  PacketFeedback packet3(0, static_cast<uint16_t>(kMaxSeqNo));
  EXPECT_TRUE(history_.GetFeedback(&packet3, false));
  PacketFeedback packet4(0, 0);
  EXPECT_TRUE(history_.GetFeedback(&packet4, false));

  // Create a gap (kMaxSeqNo - 1) -> 0.
  PacketFeedback packet5(0, kMaxSeqNo);
  EXPECT_TRUE(history_.GetFeedback(&packet5, true));

  clock_.AdvanceTimeMilliseconds(100);
  AddPacketWithSendTime(1, 0, 1100, PacedPacketInfo());

  PacketFeedback packet6(0, static_cast<uint16_t>(kMaxSeqNo - 2));
  EXPECT_FALSE(history_.GetFeedback(&packet6, false));
  PacketFeedback packet7(0, static_cast<uint16_t>(kMaxSeqNo - 1));
  EXPECT_FALSE(history_.GetFeedback(&packet7, false));
  PacketFeedback packet8(0, kMaxSeqNo);
  EXPECT_FALSE(history_.GetFeedback(&packet8, false));
  PacketFeedback packet9(0, 0);
  EXPECT_TRUE(history_.GetFeedback(&packet9, false));
  PacketFeedback packet10(0, 1);
  EXPECT_TRUE(history_.GetFeedback(&packet10, false));
}

TEST_F(SendTimeHistoryTest, InterlievedGetAndRemove) {
  const uint16_t kSeqNo = 1;
  const int64_t kTimestamp = 2;
  const PacedPacketInfo kPacingInfo1(1, 1, 100);
  const PacedPacketInfo kPacingInfo2(2, 2, 200);
  const PacedPacketInfo kPacingInfo3(3, 3, 300);
  PacketFeedback packets[3] = {
      {0, kTimestamp, kSeqNo, 0, kPacingInfo1},
      {0, kTimestamp + 1, kSeqNo + 1, 0, kPacingInfo2},
      {0, kTimestamp + 2, kSeqNo + 2, 0, kPacingInfo3}};

  AddPacketWithSendTime(packets[0].sequence_number, packets[0].payload_size,
                        packets[0].send_time_ms, packets[0].pacing_info);
  AddPacketWithSendTime(packets[1].sequence_number, packets[1].payload_size,
                        packets[1].send_time_ms, packets[1].pacing_info);
  PacketFeedback packet(0, 0, packets[0].sequence_number, 0, PacedPacketInfo());
  EXPECT_TRUE(history_.GetFeedback(&packet, true));
  EXPECT_EQ(packets[0], packet);

  AddPacketWithSendTime(packets[2].sequence_number, packets[2].payload_size,
                        packets[2].send_time_ms, packets[2].pacing_info);

  PacketFeedback packet2(0, 0, packets[1].sequence_number, 0, kPacingInfo1);
  EXPECT_TRUE(history_.GetFeedback(&packet2, true));
  EXPECT_EQ(packets[1], packet2);

  PacketFeedback packet3(0, 0, packets[2].sequence_number, 0, kPacingInfo2);
  EXPECT_TRUE(history_.GetFeedback(&packet3, true));
  EXPECT_EQ(packets[2], packet3);
}
}  // namespace test
}  // namespace webrtc
<commit_msg>Fix broken test landed in r17243.<commit_after>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <algorithm>
#include <limits>
#include <vector>

#include "webrtc/modules/remote_bitrate_estimator/include/send_time_history.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc/test/gtest.h"

namespace webrtc {
namespace test {

static const int kDefaultHistoryLengthMs = 1000;

class SendTimeHistoryTest : public ::testing::Test {
 protected:
  SendTimeHistoryTest()
      : clock_(0), history_(&clock_, kDefaultHistoryLengthMs) {}
  ~SendTimeHistoryTest() {}

  virtual void SetUp() {}

  virtual void TearDown() {}

  void AddPacketWithSendTime(uint16_t sequence_number,
                             size_t length,
                             int64_t send_time_ms,
                             const PacedPacketInfo& pacing_info) {
    PacketFeedback packet(clock_.TimeInMilliseconds(), sequence_number, length,
                          0, 0, pacing_info);
    history_.AddAndRemoveOld(packet);
    history_.OnSentPacket(sequence_number, send_time_ms);
  }

  webrtc::SimulatedClock clock_;
  SendTimeHistory history_;
};

TEST_F(SendTimeHistoryTest, SaveAndRestoreNetworkId) {
  const PacedPacketInfo kPacingInfo(0, 5, 1200);
  uint16_t sequence_number = 0;
  int64_t now_ms = clock_.TimeInMilliseconds();
  for (int i = 1; i < 5; ++i) {
    PacketFeedback packet(now_ms, sequence_number, 1000, i, i - 1,
                          kPacingInfo);
    history_.AddAndRemoveOld(packet);
    history_.OnSentPacket(sequence_number, now_ms);
    PacketFeedback restored(now_ms, sequence_number);
    EXPECT_TRUE(history_.GetFeedback(&restored, sequence_number++));
    EXPECT_EQ(packet.local_net_id, restored.local_net_id);
    EXPECT_EQ(packet.remote_net_id, restored.remote_net_id);
  }
}

TEST_F(SendTimeHistoryTest, AddRemoveOne) {
  const uint16_t kSeqNo = 10;
  // TODO(philipel): Fix PacedPacketInfo constructor?
  const PacedPacketInfo kPacingInfo(0, 5, 1200);
  const PacketFeedback kSentPacket(0, 1, kSeqNo, 1, kPacingInfo);
  AddPacketWithSendTime(kSeqNo, 1, 1, kPacingInfo);

  PacketFeedback received_packet(0, 0, kSeqNo, 0, kPacingInfo);
  EXPECT_TRUE(history_.GetFeedback(&received_packet, false));
  EXPECT_EQ(kSentPacket, received_packet);

  PacketFeedback received_packet2(0, 0, kSeqNo, 0, kPacingInfo);
  EXPECT_TRUE(history_.GetFeedback(&received_packet2, true));
  EXPECT_EQ(kSentPacket, received_packet2);

  PacketFeedback received_packet3(0, 0, kSeqNo, 0, kPacingInfo);
  EXPECT_FALSE(history_.GetFeedback(&received_packet3, true));
}

TEST_F(SendTimeHistoryTest, PopulatesExpectedFields) {
  const uint16_t kSeqNo = 10;
  const int64_t kSendTime = 1000;
  const int64_t kReceiveTime = 2000;
  const size_t kPayloadSize = 42;
  const PacedPacketInfo kPacingInfo(3, 10, 1212);

  AddPacketWithSendTime(kSeqNo, kPayloadSize, kSendTime, kPacingInfo);

  PacketFeedback packet_feedback(kReceiveTime, kSeqNo);
  EXPECT_TRUE(history_.GetFeedback(&packet_feedback, true));
  EXPECT_EQ(kReceiveTime, packet_feedback.arrival_time_ms);
  EXPECT_EQ(kSendTime, packet_feedback.send_time_ms);
  EXPECT_EQ(kSeqNo, packet_feedback.sequence_number);
  EXPECT_EQ(kPayloadSize, packet_feedback.payload_size);
  EXPECT_EQ(kPacingInfo, packet_feedback.pacing_info);
}

TEST_F(SendTimeHistoryTest, AddThenRemoveOutOfOrder) {
  std::vector<PacketFeedback> sent_packets;
  std::vector<PacketFeedback> received_packets;
  const size_t num_items = 100;
  const size_t kPacketSize = 400;
  const size_t kTransmissionTime = 1234;
  const PacedPacketInfo kPacingInfo(1, 2, 200);
  for (size_t i = 0; i < num_items; ++i) {
    sent_packets.push_back(PacketFeedback(0, static_cast<int64_t>(i),
                                          static_cast<uint16_t>(i), kPacketSize,
                                          kPacingInfo));
    received_packets.push_back(PacketFeedback(
        static_cast<int64_t>(i) + kTransmissionTime, 0,
        static_cast<uint16_t>(i), kPacketSize, PacedPacketInfo()));
  }
  for (size_t i = 0; i < num_items; ++i) {
    PacketFeedback packet = sent_packets[i];
    packet.arrival_time_ms = -1;
    packet.send_time_ms = -1;
    history_.AddAndRemoveOld(packet);
  }
  for (size_t i = 0; i < num_items; ++i)
    history_.OnSentPacket(sent_packets[i].sequence_number,
                          sent_packets[i].send_time_ms);
  std::random_shuffle(received_packets.begin(), received_packets.end());
  for (size_t i = 0; i < num_items; ++i) {
    PacketFeedback packet = received_packets[i];
    EXPECT_TRUE(history_.GetFeedback(&packet, false));
    PacketFeedback sent_packet = sent_packets[packet.sequence_number];
    sent_packet.arrival_time_ms = packet.arrival_time_ms;
    EXPECT_EQ(sent_packet, packet);
    EXPECT_TRUE(history_.GetFeedback(&packet, true));
  }
  for (PacketFeedback packet : sent_packets)
    EXPECT_FALSE(history_.GetFeedback(&packet, false));
}

TEST_F(SendTimeHistoryTest, HistorySize) {
  const int kItems = kDefaultHistoryLengthMs / 100;
  for (int i = 0; i < kItems; ++i) {
    clock_.AdvanceTimeMilliseconds(100);
    AddPacketWithSendTime(i, 0, i * 100, PacedPacketInfo());
  }
  for (int i = 0; i < kItems; ++i) {
    PacketFeedback packet(0, 0, static_cast<uint16_t>(i), 0, PacedPacketInfo());
    EXPECT_TRUE(history_.GetFeedback(&packet, false));
    EXPECT_EQ(i * 100, packet.send_time_ms);
  }
  clock_.AdvanceTimeMilliseconds(101);
  AddPacketWithSendTime(kItems, 0, kItems * 101, PacedPacketInfo());
  PacketFeedback packet(0, 0, 0, 0, PacedPacketInfo());
  EXPECT_FALSE(history_.GetFeedback(&packet, false));
  for (int i = 1; i < (kItems + 1); ++i) {
    PacketFeedback packet2(0, 0, static_cast<uint16_t>(i), 0,
                           PacedPacketInfo());
    EXPECT_TRUE(history_.GetFeedback(&packet2, false));
    int64_t expected_time_ms = (i == kItems) ? i * 101 : i * 100;
    EXPECT_EQ(expected_time_ms, packet2.send_time_ms);
  }
}

TEST_F(SendTimeHistoryTest, HistorySizeWithWraparound) {
  const uint16_t kMaxSeqNo = std::numeric_limits<uint16_t>::max();
  AddPacketWithSendTime(kMaxSeqNo - 2, 0, 0, PacedPacketInfo());

  clock_.AdvanceTimeMilliseconds(100);
  AddPacketWithSendTime(kMaxSeqNo - 1, 1, 100, PacedPacketInfo());

  clock_.AdvanceTimeMilliseconds(100);
  AddPacketWithSendTime(kMaxSeqNo, 0, 200, PacedPacketInfo());

  clock_.AdvanceTimeMilliseconds(kDefaultHistoryLengthMs - 200 + 1);
  AddPacketWithSendTime(0, 0, kDefaultHistoryLengthMs, PacedPacketInfo());

  PacketFeedback packet(0, static_cast<uint16_t>(kMaxSeqNo - 2));
  EXPECT_FALSE(history_.GetFeedback(&packet, false));
  PacketFeedback packet2(0, static_cast<uint16_t>(kMaxSeqNo - 1));
  EXPECT_TRUE(history_.GetFeedback(&packet2, false));
  PacketFeedback packet3(0, static_cast<uint16_t>(kMaxSeqNo));
  EXPECT_TRUE(history_.GetFeedback(&packet3, false));
  PacketFeedback packet4(0, 0);
  EXPECT_TRUE(history_.GetFeedback(&packet4, false));

  // Create a gap (kMaxSeqNo - 1) -> 0.
  PacketFeedback packet5(0, kMaxSeqNo);
  EXPECT_TRUE(history_.GetFeedback(&packet5, true));

  clock_.AdvanceTimeMilliseconds(100);
  AddPacketWithSendTime(1, 0, 1100, PacedPacketInfo());

  PacketFeedback packet6(0, static_cast<uint16_t>(kMaxSeqNo - 2));
  EXPECT_FALSE(history_.GetFeedback(&packet6, false));
  PacketFeedback packet7(0, static_cast<uint16_t>(kMaxSeqNo - 1));
  EXPECT_FALSE(history_.GetFeedback(&packet7, false));
  PacketFeedback packet8(0, kMaxSeqNo);
  EXPECT_FALSE(history_.GetFeedback(&packet8, false));
  PacketFeedback packet9(0, 0);
  EXPECT_TRUE(history_.GetFeedback(&packet9, false));
  PacketFeedback packet10(0, 1);
  EXPECT_TRUE(history_.GetFeedback(&packet10, false));
}

TEST_F(SendTimeHistoryTest, InterlievedGetAndRemove) {
  const uint16_t kSeqNo = 1;
  const int64_t kTimestamp = 2;
  const PacedPacketInfo kPacingInfo1(1, 1, 100);
  const PacedPacketInfo kPacingInfo2(2, 2, 200);
  const PacedPacketInfo kPacingInfo3(3, 3, 300);
  PacketFeedback packets[3] = {
      {0, kTimestamp, kSeqNo, 0, kPacingInfo1},
      {0, kTimestamp + 1, kSeqNo + 1, 0, kPacingInfo2},
      {0, kTimestamp + 2, kSeqNo + 2, 0, kPacingInfo3}};

  AddPacketWithSendTime(packets[0].sequence_number, packets[0].payload_size,
                        packets[0].send_time_ms, packets[0].pacing_info);
  AddPacketWithSendTime(packets[1].sequence_number, packets[1].payload_size,
                        packets[1].send_time_ms, packets[1].pacing_info);
  PacketFeedback packet(0, 0, packets[0].sequence_number, 0, PacedPacketInfo());
  EXPECT_TRUE(history_.GetFeedback(&packet, true));
  EXPECT_EQ(packets[0], packet);

  AddPacketWithSendTime(packets[2].sequence_number, packets[2].payload_size,
                        packets[2].send_time_ms, packets[2].pacing_info);

  PacketFeedback packet2(0, 0, packets[1].sequence_number, 0, kPacingInfo1);
  EXPECT_TRUE(history_.GetFeedback(&packet2, true));
  EXPECT_EQ(packets[1], packet2);

  PacketFeedback packet3(0, 0, packets[2].sequence_number, 0, kPacingInfo2);
  EXPECT_TRUE(history_.GetFeedback(&packet3, true));
  EXPECT_EQ(packets[2], packet3);
}
}  // namespace test
}  // namespace webrtc
<|endoftext|>


<commit_before>#include <gecode/driver.hh>
#include <gecode/int.hh>
#include <gecode/minimodel.hh>
#include <gecode/gist.hh>
#include <gecode/search.hh>

#include "dep_selector_to_gecode.h"

#include <limits>
#include <iostream>
#include <vector>

#define DEBUG

using namespace Gecode;
const int VersionProblem::UNRESOLVED_VARIABLE = INT_MIN;
const int VersionProblem::MIN_TRUST_LEVEL = 0;
const int VersionProblem::MAX_TRUST_LEVEL = 10;

VersionProblem::VersionProblem(int packageCount)
  : size(packageCount), finalized(false), cur_package(0), package_versions(*this, packageCount),
    disabled_package_variables(*this, packageCount, 0, 1), total_disabled(*this, 0, packageCount*MAX_TRUST_LEVEL),
    disabled_package_weights(new int[packageCount]), preferred_at_latest(*this, packageCount, 0, 1),
    total_preferred_at_latest(*this, 0, packageCount), preferred_at_latest_weights(new int[packageCount])
{
  for (int i = 0; i < packageCount; i++)
  {
    disabled_package_weights[i] = MAX_TRUST_LEVEL;
    preferred_at_latest_weights[i] = 0;
  }
}

VersionProblem::VersionProblem(bool share, VersionProblem & s)
  : Space(share, s), size(s.size),
    finalized(s.finalized), cur_package(s.cur_package),
    disabled_package_variables(s.disabled_package_variables), total_disabled(s.total_disabled),
    disabled_package_weights(NULL), preferred_at_latest(s.preferred_at_latest),
    total_preferred_at_latest(s.total_preferred_at_latest), preferred_at_latest_weights(NULL)
{
  package_versions.update(*this, share, s.package_versions);
  disabled_package_variables.update(*this, share, s.disabled_package_variables);
  total_disabled.update(*this, share, s.total_disabled);
  preferred_at_latest.update(*this, share, s.preferred_at_latest);
  total_preferred_at_latest.update(*this, share, s.total_preferred_at_latest);
}

// Support for gecode
Space* VersionProblem::copy(bool share)
{
  return new VersionProblem(share,*this);
}

VersionProblem::~VersionProblem()
{
  delete[] disabled_package_weights;
  delete[] preferred_at_latest_weights;
}

int VersionProblem::Size()
{
  return size;
}

int VersionProblem::PackageCount()
{
  return cur_package;
}

int
VersionProblem::AddPackage(int minVersion, int maxVersion, int currentVersion)
{
  if (cur_package == size) {
    return -1;
  }

#ifdef DEBUG
  std::cout << "Adding package id " << cur_package << '/' << size << ": min = " << minVersion << ", max = " << maxVersion << ", current verison " << currentVersion << std::endl;
  std::cout.flush();
#endif // DEBUG
  int index = cur_package;
  cur_package++;
  //  IntVar version(*this, minVersion, maxVersion);
  package_versions[index] = IntVar(*this, minVersion, maxVersion);

  // register the binding of package to version that corresponds to the package's latest
  rel(*this, package_versions[index], IRT_EQ, maxVersion, preferred_at_latest[index]);

  return index;
}

bool
VersionProblem::AddVersionConstraint(int packageId, int version,
				     int dependentPackageId, int minDependentVersion, int maxDependentVersion)
{
  BoolVar version_match(*this, 0, 1);
  BoolVar depend_match(*this, 0, 1);
  BoolVar predicated_depend_match(*this, 0, 1);

#ifdef DEBUG
  std::cout << "Add VC for " << packageId << " @ " << version << " depPkg " << dependentPackageId;
  std::cout << " [ " << minDependentVersion << ", " << maxDependentVersion << " ]" << std::endl;
  std::cout.flush();
#endif // DEBUG

  //version_flags << version_match;
  // Constrain pred to reify package @ version
  rel(*this, package_versions[packageId], IRT_EQ, version, version_match);
  // Add the predicated version constraints imposed on dependent package

  // package_versions[dependendPackageId] in domain [minDependentVersion,maxDependentVersion] <=> depend_match
  dom(*this, package_versions[dependentPackageId], minDependentVersion, maxDependentVersion, depend_match);

  // disabled_package_variables[dependentPackageId] OR depend_match <=> predicated_depend_match
  // rel(*this, disabled_package_variables[dependentPackageId], BOT_OR, depend_match, version_match);

  rel(*this, disabled_package_variables[dependentPackageId], BOT_OR, depend_match, predicated_depend_match);
  rel(*this, version_match, BOT_IMP, predicated_depend_match, 1);
}

void
VersionProblem::MarkPackageSuspicious(int packageId, int trustLevel)
{
  disabled_package_weights[packageId] = std::max(MIN_TRUST_LEVEL, std::min(disabled_package_weights[packageId], trustLevel));
}

void
VersionProblem::MarkPackagePreferredToBeAtLatest(int packageId, int weight)
{
  preferred_at_latest_weights[packageId] = weight;
}

void VersionProblem::Finalize()
{
#ifdef DEBUG
  std::cout << "Finalization Started" << std::endl;
  std::cout.flush();
#endif // DEBUG
  finalized = true;

  // Setup constraint for cost
  //  linear(*this, disabled_package_weights, disabled_package_variables,  IRT_EQ, total_disabled);
  IntArgs disabled_package_weights_args(size, disabled_package_weights);
  //IntArgs package_weights = IntArgs::create(size, 1, 0);

#ifdef DEBUG
  std::cout << "disabled_package_weights_args: " << disabled_package_weights_args << std::endl;
#endif DEBUG
  linear(*this, disabled_package_weights_args, disabled_package_variables,  IRT_EQ, total_disabled);
  // linear(*this, disabled_package_variables,  IRT_EQ, total_disabled);

  IntArgs preferred_at_latest_weights_args(size, preferred_at_latest_weights);
  linear(*this, preferred_at_latest_weights_args, preferred_at_latest, IRT_EQ, total_preferred_at_latest);

  // Assign a dummy variable to elements greater than actually used.
  for (int i = cur_package; i < size; i++) {
    package_versions[i] = IntVar(*this, -1, -1);
    disabled_package_variables[i] = BoolVar(*this, 1, 1);
  }
#ifdef DEBUG
  std::cout << "preferred_at_latest_weights_args: " << preferred_at_latest_weights_args << std::endl;
  std::cout << "Adding branching" << std::endl;
  std::cout.flush();
#endif // DEBUG
  branch(*this, disabled_package_variables, INT_VAR_SIZE_MIN, INT_VAL_MIN);
  branch(*this, package_versions, INT_VAR_SIZE_MIN, INT_VAL_MAX);
  branch(*this, total_disabled, INT_VAL_MIN);
  branch(*this, preferred_at_latest, INT_VAR_SIZE_MIN, INT_VAL_MAX);
  branch(*this, total_preferred_at_latest, INT_VAL_MAX);
#ifdef DEBUG
  std::cout << "Finalization Done" << std::endl;
  std::cout.flush();
#endif // DEBUG
}

// _best_known_soln is the most recent satisfying assignment of
// variables that Gecode has found. This method examines the solution
// and adds additional constraints that are applied after restarting
// the search, which means that the next time a solution that's found
// must be strictly better than the current best known solution.
//
// Our model requires us to have a series of objective functions where
// each successive objective function is evaluated if and only if all
// higher precedent objective functions are tied.
//
// [TODO: DESCRIBE WHAT THE ACTUAL SERIES OF OBJECTIVE FUNCTIONS IS]
//
// Lower precedent objective functions are modeled as the consequent
// of an implication whose antecedent is the conjunction of all the
// higher precedent objective functions being assigned to their best
// known value; thus, the optimal value of an objection function
// "activates" the next highest objective function. This has the
// effect of isolating the logic of each objective function such that
// it is only applied to the set of equally preferable solutions under
// the higher precedent objective functions. The objective function
// then applies its constraints, the solution space is restarted and
// walks the space until it finds another, more constrained solution.
void VersionProblem::constrain(const Space & _best_known_solution)
{
  const VersionProblem& best_known_solution = static_cast<const VersionProblem &>(_best_known_solution);

  // add first-level objective function minimization (failing packages, weighted)
  // new constraint: total_disabled < best_known_total_disabled_value)
  int best_known_total_disabled_value = best_known_solution.total_disabled.val();
  rel(*this, total_disabled, IRT_LE, best_known_total_disabled_value);

  // add second-level objective function maximization (preferred packages are at latest, weighted)
  AddPackagesPreferredToBeAtLatestObjectiveFunction(best_known_solution);

#ifdef DEBUG
  std::cout << "best_known_total_disabled_value: " << best_known_total_disabled_value << std::endl;
#endif
}

void VersionProblem::AddPackagesPreferredToBeAtLatestObjectiveFunction(const VersionProblem & best_known_solution)
{
  // Make sure we respect total_disabled first by only constraining on
  // latestness of preferred packages if the solution's total_disabled
  // is equivalent to the best known, which is what
  // is_at_best_known_disabled_value represents.

  // is_at_best_known_disabled_value <=> (total_disabled == best_known_total_disabled_value)
  BoolVar is_at_best_known_disabled_value(*this, 0, 1);
  rel(*this, total_disabled, IRT_EQ, best_known_solution.total_disabled.val(), is_at_best_known_disabled_value);

  // is_better_total_preferred_at_latest <=> (total_preferred_at_latest > best_known_total_preferred_at_latest_value)
  int best_known_total_preferred_at_latest_value = best_known_solution.total_preferred_at_latest.val();
  BoolVar is_better_total_preferred_at_latest(*this, 0, 1);
  rel(*this, total_preferred_at_latest, IRT_GR, best_known_total_preferred_at_latest_value, is_better_total_preferred_at_latest);

  // new constraint: is_at_best_known_disabled_value -> is_better_total_preferred_at_latest
  rel(*this, is_at_best_known_disabled_value, BOT_IMP, is_better_total_preferred_at_latest, 1);

#ifdef DEBUG
  std::cout << "best_known_total_preferred_at_latest_value: " << best_known_total_preferred_at_latest_value << std::endl;
#endif
}

IntVar & VersionProblem::GetPackageVersionVar(int packageId)
{
  if (packageId < cur_package) {
    return package_versions[packageId];
  } else {
#ifdef DEBUG
    std::cout << "Bad package Id " << packageId << " >= " << cur_package << std::endl;
    std::cout.flush();
#endif //DEBUG
    //    return 0;
  }
}

int VersionProblem::GetPackageVersion(int packageId)
{
  IntVar & var = GetPackageVersionVar(packageId);
  if (1 == var.size()) return var.val();
  return UNRESOLVED_VARIABLE;
}
bool VersionProblem::GetPackageDisabledState(int packageId)
{
  return disabled_package_variables[packageId].val() == 1;
}

int VersionProblem::GetAFC(int packageId)
{
  return GetPackageVersionVar(packageId).afc();
}

int VersionProblem::GetMax(int packageId)
{
  return GetPackageVersionVar(packageId).max();
}
int VersionProblem::GetMin(int packageId)
{
  return GetPackageVersionVar(packageId).min();
}

int VersionProblem::GetDisabledVariableCount()
{
  if (total_disabled.min() == total_disabled.max()) {
    return total_disabled.min();
  } else {
    return UNRESOLVED_VARIABLE;
  }
}

// Utility
void VersionProblem::Print(std::ostream & out)
{
  out << "Version problem dump:      " << cur_package << "/" << size << " packages used/allocated" << std::endl;
  out << "Disabled Variables:        " << disabled_package_variables << std::endl;
  out << "Total Disabled variables:  " << total_disabled << std::endl;
  out << "preferred_at_latest:       " << preferred_at_latest << std::endl;
  out << "total_preferred_at_latest: " << total_preferred_at_latest << std::endl;

  for (int i = 0; i < cur_package; i++) {
    out << "\t";
    PrintPackageVar(out, i);
    out << std::endl;
  }
  out.flush();
}

// TODO: Validate package ids !

void VersionProblem::PrintPackageVar(std::ostream & out, int packageId)
{
  // Hack Alert: we could have the package variable in one of two places, but we don't clearly distinguish where.
  IntVar & var = GetPackageVersionVar(packageId);
  out << "PackageId: " << packageId <<  " Sltn: " << var << " afc: " << var.afc();
  out << " disabled: " << disabled_package_variables[packageId];
}

bool VersionProblem::CheckPackageId(int id)
{
  return (id < size);
}

VersionProblem * VersionProblem::Solve(VersionProblem * problem)
{
  problem->Finalize();
  problem->status();
#ifdef DEBUG
  std::cout << "Before solve" << std::endl;
  problem->Print(std::cout);
#endif //DEBUG

  Restart<VersionProblem> solver(problem);

  VersionProblem *best_solution = NULL;
  while (VersionProblem *solution = solver.next())
    {
      if (best_solution != NULL)
	{
	  delete best_solution;
	}
      best_solution = solution;
      ++i;
#ifdef DEBUG
      std::cout << "Trial Solution #" << i << "===============================" << std::endl;
      const Search::Statistics & stats = solver.statistics();
      std::cout << "Solver stats: Prop:" << stats.propagate << " Fail:" << stats.fail << " Node:" << stats.node;
      std::cout << " Depth:" << stats.depth << " memory:" << stats.memory << std::endl;
      //      std::cout << stats << std::endl;
      solution->Print(std::cout);
#endif //DEBUG
    }
  return best_solution;
}

//
//
//

//
// Version Problem
//
//
//
//
<commit_msg>More descriptive output, and fix missing variable decl<commit_after>#include <gecode/driver.hh>
#include <gecode/int.hh>
#include <gecode/minimodel.hh>
#include <gecode/gist.hh>
#include <gecode/search.hh>

#include "dep_selector_to_gecode.h"

#include <limits>
#include <iostream>
#include <vector>

#define DEBUG

using namespace Gecode;
const int VersionProblem::UNRESOLVED_VARIABLE = INT_MIN;
const int VersionProblem::MIN_TRUST_LEVEL = 0;
const int VersionProblem::MAX_TRUST_LEVEL = 10;

VersionProblem::VersionProblem(int packageCount)
  : size(packageCount), finalized(false), cur_package(0), package_versions(*this, packageCount),
    disabled_package_variables(*this, packageCount, 0, 1), total_disabled(*this, 0, packageCount*MAX_TRUST_LEVEL),
    disabled_package_weights(new int[packageCount]), preferred_at_latest(*this, packageCount, 0, 1),
    total_preferred_at_latest(*this, 0, packageCount), preferred_at_latest_weights(new int[packageCount])
{
  for (int i = 0; i < packageCount; i++)
  {
    disabled_package_weights[i] = MAX_TRUST_LEVEL;
    preferred_at_latest_weights[i] = 0;
  }
}

VersionProblem::VersionProblem(bool share, VersionProblem & s)
  : Space(share, s), size(s.size),
    finalized(s.finalized), cur_package(s.cur_package),
    disabled_package_variables(s.disabled_package_variables), total_disabled(s.total_disabled),
    disabled_package_weights(NULL), preferred_at_latest(s.preferred_at_latest),
    total_preferred_at_latest(s.total_preferred_at_latest), preferred_at_latest_weights(NULL)
{
  package_versions.update(*this, share, s.package_versions);
  disabled_package_variables.update(*this, share, s.disabled_package_variables);
  total_disabled.update(*this, share, s.total_disabled);
  preferred_at_latest.update(*this, share, s.preferred_at_latest);
  total_preferred_at_latest.update(*this, share, s.total_preferred_at_latest);
}

// Support for gecode
Space* VersionProblem::copy(bool share)
{
  return new VersionProblem(share,*this);
}

VersionProblem::~VersionProblem()
{
  delete[] disabled_package_weights;
  delete[] preferred_at_latest_weights;
}

int VersionProblem::Size()
{
  return size;
}

int VersionProblem::PackageCount()
{
  return cur_package;
}

int
VersionProblem::AddPackage(int minVersion, int maxVersion, int currentVersion)
{
  if (cur_package == size) {
    return -1;
  }

#ifdef DEBUG
  std::cout << "Adding package id " << cur_package << '/' << size << ": min = " << minVersion << ", max = " << maxVersion << ", current verison " << currentVersion << std::endl;
  std::cout.flush();
#endif // DEBUG
  int index = cur_package;
  cur_package++;
  //  IntVar version(*this, minVersion, maxVersion);
  package_versions[index] = IntVar(*this, minVersion, maxVersion);

  // register the binding of package to version that corresponds to the package's latest
  rel(*this, package_versions[index], IRT_EQ, maxVersion, preferred_at_latest[index]);

  return index;
}

bool
VersionProblem::AddVersionConstraint(int packageId, int version,
				     int dependentPackageId, int minDependentVersion, int maxDependentVersion)
{
  BoolVar version_match(*this, 0, 1);
  BoolVar depend_match(*this, 0, 1);
  BoolVar predicated_depend_match(*this, 0, 1);

#ifdef DEBUG
  std::cout << "Add VC for " << packageId << " @ " << version << " depPkg " << dependentPackageId;
  std::cout << " [ " << minDependentVersion << ", " << maxDependentVersion << " ]" << std::endl;
  std::cout.flush();
#endif // DEBUG

  //version_flags << version_match;
  // Constrain pred to reify package @ version
  rel(*this, package_versions[packageId], IRT_EQ, version, version_match);
  // Add the predicated version constraints imposed on dependent package

  // package_versions[dependendPackageId] in domain [minDependentVersion,maxDependentVersion] <=> depend_match
  dom(*this, package_versions[dependentPackageId], minDependentVersion, maxDependentVersion, depend_match);

  // disabled_package_variables[dependentPackageId] OR depend_match <=> predicated_depend_match
  // rel(*this, disabled_package_variables[dependentPackageId], BOT_OR, depend_match, version_match);

  rel(*this, disabled_package_variables[dependentPackageId], BOT_OR, depend_match, predicated_depend_match);
  rel(*this, version_match, BOT_IMP, predicated_depend_match, 1);
}

void
VersionProblem::MarkPackageSuspicious(int packageId, int trustLevel)
{
  disabled_package_weights[packageId] = std::max(MIN_TRUST_LEVEL, std::min(disabled_package_weights[packageId], trustLevel));
}

void
VersionProblem::MarkPackagePreferredToBeAtLatest(int packageId, int weight)
{
  preferred_at_latest_weights[packageId] = weight;
}

void VersionProblem::Finalize()
{
#ifdef DEBUG
  std::cout << "Finalization Started" << std::endl;
  std::cout.flush();
#endif // DEBUG
  finalized = true;

  // Setup constraint for cost
  //  linear(*this, disabled_package_weights, disabled_package_variables,  IRT_EQ, total_disabled);
  IntArgs disabled_package_weights_args(size, disabled_package_weights);
  //IntArgs package_weights = IntArgs::create(size, 1, 0);

#ifdef DEBUG
  std::cout << "disabled_package_weights_args: " << disabled_package_weights_args << std::endl;
#endif DEBUG
  linear(*this, disabled_package_weights_args, disabled_package_variables,  IRT_EQ, total_disabled);
  // linear(*this, disabled_package_variables,  IRT_EQ, total_disabled);

  IntArgs preferred_at_latest_weights_args(size, preferred_at_latest_weights);
  linear(*this, preferred_at_latest_weights_args, preferred_at_latest, IRT_EQ, total_preferred_at_latest);

  // Assign a dummy variable to elements greater than actually used.
  for (int i = cur_package; i < size; i++) {
    package_versions[i] = IntVar(*this, -1, -1);
    disabled_package_variables[i] = BoolVar(*this, 1, 1);
  }
#ifdef DEBUG
  std::cout << "preferred_at_latest_weights_args: " << preferred_at_latest_weights_args << std::endl;
  std::cout << "Adding branching" << std::endl;
  std::cout.flush();
#endif // DEBUG
  branch(*this, disabled_package_variables, INT_VAR_SIZE_MIN, INT_VAL_MIN);
  branch(*this, package_versions, INT_VAR_SIZE_MIN, INT_VAL_MAX);
  branch(*this, total_disabled, INT_VAL_MIN);
  branch(*this, preferred_at_latest, INT_VAR_SIZE_MIN, INT_VAL_MAX);
  branch(*this, total_preferred_at_latest, INT_VAL_MAX);
#ifdef DEBUG
  std::cout << "Finalization Done" << std::endl;
  std::cout.flush();
#endif // DEBUG
}

// _best_known_soln is the most recent satisfying assignment of
// variables that Gecode has found. This method examines the solution
// and adds additional constraints that are applied after restarting
// the search, which means that the next time a solution that's found
// must be strictly better than the current best known solution.
//
// Our model requires us to have a series of objective functions where
// each successive objective function is evaluated if and only if all
// higher precedent objective functions are tied.
//
// [TODO: DESCRIBE WHAT THE ACTUAL SERIES OF OBJECTIVE FUNCTIONS IS]
//
// Lower precedent objective functions are modeled as the consequent
// of an implication whose antecedent is the conjunction of all the
// higher precedent objective functions being assigned to their best
// known value; thus, the optimal value of an objection function
// "activates" the next highest objective function. This has the
// effect of isolating the logic of each objective function such that
// it is only applied to the set of equally preferable solutions under
// the higher precedent objective functions. The objective function
// then applies its constraints, the solution space is restarted and
// walks the space until it finds another, more constrained solution.
void VersionProblem::constrain(const Space & _best_known_solution)
{
  const VersionProblem& best_known_solution = static_cast<const VersionProblem &>(_best_known_solution);

  // add first-level objective function minimization (failing packages, weighted)
  // new constraint: total_disabled < best_known_total_disabled_value)
  int best_known_total_disabled_value = best_known_solution.total_disabled.val();
  rel(*this, total_disabled, IRT_LE, best_known_total_disabled_value);
#ifdef DEBUG
  std::cout << "Constrain: best_known_total_disabled_value: " << best_known_total_disabled_value << std::endl;
#endif

  // add second-level objective function maximization (preferred packages are at latest, weighted)
  AddPackagesPreferredToBeAtLatestObjectiveFunction(best_known_solution);
}

void VersionProblem::AddPackagesPreferredToBeAtLatestObjectiveFunction(const VersionProblem & best_known_solution)
{
  // Make sure we respect total_disabled first by only constraining on
  // latestness of preferred packages if the solution's total_disabled
  // is equivalent to the best known, which is what
  // is_at_best_known_disabled_value represents.

  // is_at_best_known_disabled_value <=> (total_disabled == best_known_total_disabled_value)
  BoolVar is_at_best_known_disabled_value(*this, 0, 1);
  rel(*this, total_disabled, IRT_EQ, best_known_solution.total_disabled.val(), is_at_best_known_disabled_value);

  // is_better_total_preferred_at_latest <=> (total_preferred_at_latest > best_known_total_preferred_at_latest_value)
  int best_known_total_preferred_at_latest_value = best_known_solution.total_preferred_at_latest.val();
  BoolVar is_better_total_preferred_at_latest(*this, 0, 1);
  rel(*this, total_preferred_at_latest, IRT_GR, best_known_total_preferred_at_latest_value, is_better_total_preferred_at_latest);

  // new constraint: is_at_best_known_disabled_value -> is_better_total_preferred_at_latest
  rel(*this, is_at_best_known_disabled_value, BOT_IMP, is_better_total_preferred_at_latest, 1);

#ifdef DEBUG
  std::cout << "Constrain: best_known_total_preferred_at_latest_value: " << best_known_total_preferred_at_latest_value << std::endl;
#endif
}

IntVar & VersionProblem::GetPackageVersionVar(int packageId)
{
  if (packageId < cur_package) {
    return package_versions[packageId];
  } else {
#ifdef DEBUG
    std::cout << "Bad package Id " << packageId << " >= " << cur_package << std::endl;
    std::cout.flush();
#endif //DEBUG
    //    return 0;
  }
}

int VersionProblem::GetPackageVersion(int packageId)
{
  IntVar & var = GetPackageVersionVar(packageId);
  if (1 == var.size()) return var.val();
  return UNRESOLVED_VARIABLE;
}
bool VersionProblem::GetPackageDisabledState(int packageId)
{
  return disabled_package_variables[packageId].val() == 1;
}

int VersionProblem::GetAFC(int packageId)
{
  return GetPackageVersionVar(packageId).afc();
}

int VersionProblem::GetMax(int packageId)
{
  return GetPackageVersionVar(packageId).max();
}
int VersionProblem::GetMin(int packageId)
{
  return GetPackageVersionVar(packageId).min();
}

int VersionProblem::GetDisabledVariableCount()
{
  if (total_disabled.min() == total_disabled.max()) {
    return total_disabled.min();
  } else {
    return UNRESOLVED_VARIABLE;
  }
}

// Utility
void VersionProblem::Print(std::ostream & out)
{
  out << "Version problem dump:      " << cur_package << "/" << size << " packages used/allocated" << std::endl;
  out << "Disabled Variables:        " << disabled_package_variables << std::endl;
  out << "Total Disabled variables:  " << total_disabled << std::endl;
  out << "preferred_at_latest:       " << preferred_at_latest << std::endl;
  out << "total_preferred_at_latest: " << total_preferred_at_latest << std::endl;

  for (int i = 0; i < cur_package; i++) {
    out << "\t";
    PrintPackageVar(out, i);
    out << std::endl;
  }
  out.flush();
}

// TODO: Validate package ids !

void VersionProblem::PrintPackageVar(std::ostream & out, int packageId)
{
  // Hack Alert: we could have the package variable in one of two places, but we don't clearly distinguish where.
  IntVar & var = GetPackageVersionVar(packageId);
  out << "PackageId: " << packageId <<  " Sltn: " << var << " afc: " << var.afc();
  out << " disabled: " << disabled_package_variables[packageId];
}

bool VersionProblem::CheckPackageId(int id)
{
  return (id < size);
}

VersionProblem * VersionProblem::Solve(VersionProblem * problem)
{
  problem->Finalize();
  problem->status();
#ifdef DEBUG
  std::cout << "Before solve" << std::endl;
  problem->Print(std::cout);
#endif //DEBUG

  Restart<VersionProblem> solver(problem);
  int i = 0;
  VersionProblem *best_solution = NULL;
  while (VersionProblem *solution = solver.next())
    {
      if (best_solution != NULL)
	{
	  delete best_solution;
	}
      best_solution = solution;
      ++i;
#ifdef DEBUG
      std::cout << "Trial Solution #" << i << "===============================" << std::endl;
      const Search::Statistics & stats = solver.statistics();
      std::cout << "Solver stats: Prop:" << stats.propagate << " Fail:" << stats.fail << " Node:" << stats.node;
      std::cout << " Depth:" << stats.depth << " memory:" << stats.memory << std::endl;
      //      std::cout << stats << std::endl;
      solution->Print(std::cout);
#endif //DEBUG
    }
  return best_solution;
}

//
//
//

//
// Version Problem
//
//
//
//
<|endoftext|>


<commit_before>#include <SDL.h>
#include <iostream>
#include <math.h>
#include <vector>
#include <map>
#include <functional>
#include <algorithm>
#include <lua.hpp>
#include <LuaBridge.h>
#include "types.h"
#include "wrappers.h"
#include "auxiliary.h"
#include "entity.h"
#include "commands.h"
#include "player.h"

using namespace te;

namespace te
{
    class LuaGameState
    {
    public:
        LuaGameState(const std::string& filename = "init.lua")
            : mpL(luaL_newstate(), [](lua_State* L){ lua_close(L); })
            , mHandleCount(0)
            , mEntities()
            , mPositionMap()
            , mVelocityMap()
            , mBoundingBoxMap()
            , mDimensionMap()
            , mKeyPressTable(luabridge::newTable(mpL.get()))
            , mKeyReleaseTable(luabridge::newTable(mpL.get()))
            , mCollisionHandlerMap()
        {
            lua_State* pL = mpL.get();
            luaL_openlibs(pL);

            luabridge::getGlobalNamespace(pL)
                .beginClass<LuaGameState>("GameState")
                .addFunction("createEntity", &LuaGameState::createEntity)
                .addFunction("setPosition", &LuaGameState::setPosition)
                .addFunction("getPosition", &LuaGameState::getPosition)
                .addFunction("setVelocity", &LuaGameState::setVelocity)
                .addFunction("getVelocity", &LuaGameState::getVelocity)
                .addFunction("setBoundingBox", &LuaGameState::setBoundingBox)
                .addFunction("getBoundingBox", &LuaGameState::getBoundingBox)
                .addFunction("getIntersection", &LuaGameState::getIntersection)
                .addFunction("setSprite", &LuaGameState::setSprite)
                .addFunction("handleCollision", &LuaGameState::handleCollision)
                .addFunction("destroyEntity", &LuaGameState::destroyEntity)
                .addFunction("registerKeyPressTable", &LuaGameState::registerKeyPressTable)
                .addFunction("registerKeyReleaseTable", &LuaGameState::registerKeyReleaseTable)
                .endClass()
                .beginClass<Vector2f>("Vector2")
                .addConstructor<void(*)(void)>()
                .addConstructor<void(*)(float, float)>()
                .addData("x", &te::Vector2f::x)
                .addData("y", &te::Vector2f::y)
                .endClass()
                .addFunction<te::Vector2f(*)(te::Vector2f, te::Vector2f)>("addV", &te::operator+)
                .addFunction<te::Vector2f(*)(te::Vector2f, te::Vector2f)>("subtractV", &te::operator-)
                .addFunction<te::Vector2f(*)(float, te::Vector2f)>("multiplyV", &te::operator*)
                .addFunction<te::Vector2f(*)(te::Vector2f, float)>("divideV", &te::operator/)
                .addFunction<float(*)(te::Vector2f)>("lengthV", &te::length)
                .addFunction<te::Vector2f(*)(te::Vector2f)>("normalizeV", &te::normalize)
                .beginClass<SDL_Rect>("Rect")
                .addData("h", &SDL_Rect::h)
                .addData("w", &SDL_Rect::w)
                .addData("x", &SDL_Rect::x)
                .addData("y", &SDL_Rect::y)
                .endClass();
            luabridge::push(pL, this);
            lua_setglobal(pL, "game");

            luaL_dofile(pL, filename.c_str());
            luabridge::getGlobal(pL, "main")();
        }

        typedef unsigned int EntityHandle;
        typedef std::pair<EntityHandle, EntityHandle> EntityPair;

        EntityHandle createEntity(const Vector2f& position, const Vector2f& velocity)
        {
            EntityHandle handle = mHandleCount++;
            mEntities.push_back(handle);
            mPositionMap.insert(std::make_pair(handle, position));
            mVelocityMap.insert(std::make_pair(handle, velocity));
            mBoundingBoxMap.insert(std::make_pair(handle, Vector2i(0, 0)));
            return handle;
        }

        void setPosition(EntityHandle handle, const Vector2f& position)
        {
            if (!exists(handle)) return;

            mPositionMap[handle] = position;
        }

        Vector2f getPosition(EntityHandle handle)
        {
            if (!exists(handle)) return Vector2f(0.f, 0.f);

            return mPositionMap[handle];
        }

        void setVelocity(EntityHandle handle, const Vector2f& velocity)
        {
            if (!exists(handle)) return;

            mVelocityMap[handle] = velocity;
        }

        Vector2f getVelocity(EntityHandle handle)
        {
            if (!exists(handle)) return Vector2f(0.f, 0.f);

            return mVelocityMap[handle];
        }

        void setBoundingBox(EntityHandle handle, const Vector2f& dimensions)
        {
            if (!exists(handle)) return;

            mBoundingBoxMap[handle] = convertVector2<int>(dimensions);
        }

        void setSprite(EntityHandle handle, const Vector2f& dimensions)
        {
            if (!exists(handle)) return;

            insertOrAssign(mDimensionMap, std::make_pair(
                handle, convertVector2<int>(dimensions)));
        }

        void handleCollision(EntityHandle e1, EntityHandle e2, luabridge::LuaRef handler)
        {
            if (!exists(e1) || !exists(e2)) return;

            auto key = std::make_pair(e1, e2);
            auto it = mCollisionHandlerMap.find(key);
            if (it == mCollisionHandlerMap.end())
            {
                mCollisionHandlerMap.insert(std::make_pair(
                    key,
                    handler));
            }
            else
            {
                it->second = handler;
            }
        }

        void registerKeyPressTable(luabridge::LuaRef table)
        {
            mKeyPressTable = table;
        }

        void registerKeyReleaseTable(luabridge::LuaRef table)
        {
            mKeyReleaseTable = table;
        }

        bool exists(EntityHandle handle)
        {
            auto it = std::find(std::begin(mEntities), std::end(mEntities), handle);
            return it != std::end(mEntities);
        }

        void destroyEntity(EntityHandle handle)
        {
            mEntities.erase(
                std::remove(mEntities.begin(), mEntities.end(), handle),
                mEntities.end());
            auto positionIt = mPositionMap.find(handle);
            if (positionIt != mPositionMap.end())
            {
                mPositionMap.erase(positionIt);
            }
            auto velocityIt = mVelocityMap.find(handle);
            if (velocityIt != mVelocityMap.end())
            {
                mVelocityMap.erase(velocityIt);
            }
            auto boundingBoxIt = mBoundingBoxMap.find(handle);
            if (boundingBoxIt != mBoundingBoxMap.end())
            {
                mBoundingBoxMap.erase(boundingBoxIt);
            }
            auto dimensionIt = mDimensionMap.find(handle);
            if (dimensionIt != mDimensionMap.end())
            {
                mDimensionMap.erase(dimensionIt);
            }
        }

        void processInput(const SDL_Event& evt)
        {
            if (evt.type == SDL_KEYDOWN)
            {
                if (mKeyPressTable[evt.key.keysym.sym].isFunction())
                {
                    mKeyPressTable[evt.key.keysym.sym]();
                }
            }
            else if (evt.type == SDL_KEYUP)
            {
                if (mKeyReleaseTable[evt.key.keysym.sym].isFunction())
                {
                    mKeyReleaseTable[evt.key.keysym.sym]();
                }
            }
        }

        void update(float dt)
        {
            forEachEntity([&](const EntityHandle& handle)
            {
                mPositionMap[handle] += dt * mVelocityMap[handle];
            });
            std::for_each(
                mCollisionHandlerMap.begin(),
                mCollisionHandlerMap.end(),
                [&](std::pair<const EntityPair, luabridge::LuaRef> kv)
            {
                if (checkCollision(
                    getBoundingBox(kv.first.first),
                    getBoundingBox(kv.first.second)))
                {
                    kv.second(kv.first.first, kv.first.second, dt);
                }
            });
        }

        SDL_Rect getBoundingBox(EntityHandle handle)
        {
            Vector2f position = mPositionMap[handle];
            Vector2i boundingBox = mBoundingBoxMap[handle];
            return SDL_Rect{
                (int)position.x - (boundingBox.x / 2),
                (int)position.y - (boundingBox.y / 2),
                boundingBox.x,
                boundingBox.y
            };
        }

        SDL_Rect getIntersection(EntityHandle a, EntityHandle b)
        {
            SDL_Rect aRect = getBoundingBox(a);
            SDL_Rect bRect = getBoundingBox(b);
            return te::getIntersection(aRect, bRect);
        }

        void draw(RendererPtr pRenderer)
        {
            forEachEntity([&](const EntityHandle& handle)
            {
                auto positionIt = mPositionMap.find(handle);
                auto spriteIt = mDimensionMap.find(handle);
                if (spriteIt != mDimensionMap.end())
                {
                    Vector2f& pos = positionIt->second;
                    Vector2i& dim = spriteIt->second;
                    SDL_SetRenderDrawColor(pRenderer.get(), 0xFF, 0xFF, 0xFF, 0xFF);
                    SDL_Rect rect = {
                        (int)pos.x - (dim.x / 2),
                        (int)pos.y - (dim.y / 2),
                        dim.x,
                        dim.y
                    };
                    SDL_RenderFillRect(pRenderer.get(), &rect);
                }
            });
        }

        void forEachEntity(const std::function<void(const EntityHandle&)>& func)
        {
            std::for_each(mEntities.begin(), mEntities.end(), func);
        }

    private:
        std::shared_ptr<lua_State> mpL;
        EntityHandle mHandleCount;

        std::vector<EntityHandle> mEntities;

        std::map<EntityHandle, Vector2f> mPositionMap;
        std::map<EntityHandle, Vector2f> mVelocityMap;
        std::map<EntityHandle, Vector2i> mBoundingBoxMap;
        std::map<EntityHandle, Vector2i> mDimensionMap;

        luabridge::LuaRef mKeyPressTable;
        luabridge::LuaRef mKeyReleaseTable;
        std::map<EntityPair, luabridge::LuaRef> mCollisionHandlerMap;
    };
}

int main(int argc, char** argv)
{
    te::Initialization init;

    LuaGameState state;

    const int WIDTH = 640;
    const int HEIGHT = 480;

    te::WindowPtr pWindow = te::wrapWindow(
        SDL_CreateWindow("Pong", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN)
    );
    te::RendererPtr pRenderer = te::createRenderer(pWindow);

    SDL_Event e;
    bool running = true;

    Uint32 FPS = 60;
    Uint32 TIME_PER_FRAME = 1000 / FPS;

    Uint64 t0 = SDL_GetPerformanceCounter();

    while (running)
    {
        while (SDL_PollEvent(&e) != 0)
        {
            if (e.type == SDL_QUIT)
            {
                running = false;
            }
            state.processInput(e);
        }

        Uint64 now = SDL_GetPerformanceCounter();
        float dt = (float)(now - t0) / SDL_GetPerformanceFrequency();

        state.update(dt);

        SDL_SetRenderDrawColor(pRenderer.get(), 0x00, 0x00, 0x00, 0xFF);
        SDL_RenderClear(pRenderer.get());

        state.draw(pRenderer);

        SDL_RenderPresent(pRenderer.get());
        t0 = now;
    }

    return 0;
}
<commit_msg>Destroy entities safely with pending queue<commit_after>#include <SDL.h>
#include <iostream>
#include <math.h>
#include <vector>
#include <map>
#include <functional>
#include <algorithm>
#include <lua.hpp>
#include <LuaBridge.h>
#include "types.h"
#include "wrappers.h"
#include "auxiliary.h"
#include "entity.h"
#include "commands.h"
#include "player.h"

using namespace te;

namespace te
{
    class LuaGameState
    {
    public:
        LuaGameState(const std::string& filename = "init.lua")
            : mpL(luaL_newstate(), [](lua_State* L){ lua_close(L); })
            , mHandleCount(0)
            , mEntities()
            , mPositionMap()
            , mVelocityMap()
            , mBoundingBoxMap()
            , mDimensionMap()
            , mPendingDestroys()
            , mKeyPressTable(luabridge::newTable(mpL.get()))
            , mKeyReleaseTable(luabridge::newTable(mpL.get()))
            , mCollisionHandlerMap()
        {
            lua_State* pL = mpL.get();
            luaL_openlibs(pL);

            luabridge::getGlobalNamespace(pL)
                .beginClass<LuaGameState>("GameState")
                .addFunction("createEntity", &LuaGameState::createEntity)
                .addFunction("setPosition", &LuaGameState::setPosition)
                .addFunction("getPosition", &LuaGameState::getPosition)
                .addFunction("setVelocity", &LuaGameState::setVelocity)
                .addFunction("getVelocity", &LuaGameState::getVelocity)
                .addFunction("setBoundingBox", &LuaGameState::setBoundingBox)
                .addFunction("getBoundingBox", &LuaGameState::getBoundingBox)
                .addFunction("getIntersection", &LuaGameState::getIntersection)
                .addFunction("setSprite", &LuaGameState::setSprite)
                .addFunction("handleCollision", &LuaGameState::handleCollision)
                .addFunction("destroyEntity", &LuaGameState::addPendingDestroy)
                .addFunction("registerKeyPressTable", &LuaGameState::registerKeyPressTable)
                .addFunction("registerKeyReleaseTable", &LuaGameState::registerKeyReleaseTable)
                .endClass()
                .beginClass<Vector2f>("Vector2")
                .addConstructor<void(*)(void)>()
                .addConstructor<void(*)(float, float)>()
                .addData("x", &te::Vector2f::x)
                .addData("y", &te::Vector2f::y)
                .endClass()
                .addFunction<te::Vector2f(*)(te::Vector2f, te::Vector2f)>("addV", &te::operator+)
                .addFunction<te::Vector2f(*)(te::Vector2f, te::Vector2f)>("subtractV", &te::operator-)
                .addFunction<te::Vector2f(*)(float, te::Vector2f)>("multiplyV", &te::operator*)
                .addFunction<te::Vector2f(*)(te::Vector2f, float)>("divideV", &te::operator/)
                .addFunction<float(*)(te::Vector2f)>("lengthV", &te::length)
                .addFunction<te::Vector2f(*)(te::Vector2f)>("normalizeV", &te::normalize)
                .beginClass<SDL_Rect>("Rect")
                .addData("h", &SDL_Rect::h)
                .addData("w", &SDL_Rect::w)
                .addData("x", &SDL_Rect::x)
                .addData("y", &SDL_Rect::y)
                .endClass();
            luabridge::push(pL, this);
            lua_setglobal(pL, "game");

            luaL_dofile(pL, filename.c_str());
            luabridge::getGlobal(pL, "main")();
        }

        typedef unsigned int EntityHandle;
        typedef std::pair<EntityHandle, EntityHandle> EntityPair;

        EntityHandle createEntity(const Vector2f& position, const Vector2f& velocity)
        {
            EntityHandle handle = mHandleCount++;
            mEntities.push_back(handle);
            mPositionMap.insert(std::make_pair(handle, position));
            mVelocityMap.insert(std::make_pair(handle, velocity));
            mBoundingBoxMap.insert(std::make_pair(handle, Vector2i(0, 0)));
            return handle;
        }

        void setPosition(EntityHandle handle, const Vector2f& position)
        {
            if (!exists(handle)) return;

            mPositionMap[handle] = position;
        }

        Vector2f getPosition(EntityHandle handle)
        {
            if (!exists(handle)) return Vector2f(0.f, 0.f);

            return mPositionMap[handle];
        }

        void setVelocity(EntityHandle handle, const Vector2f& velocity)
        {
            if (!exists(handle)) return;

            mVelocityMap[handle] = velocity;
        }

        Vector2f getVelocity(EntityHandle handle)
        {
            if (!exists(handle)) return Vector2f(0.f, 0.f);

            return mVelocityMap[handle];
        }

        void setBoundingBox(EntityHandle handle, const Vector2f& dimensions)
        {
            if (!exists(handle)) return;

            mBoundingBoxMap[handle] = convertVector2<int>(dimensions);
        }

        void setSprite(EntityHandle handle, const Vector2f& dimensions)
        {
            if (!exists(handle)) return;

            insertOrAssign(mDimensionMap, std::make_pair(
                handle, convertVector2<int>(dimensions)));
        }

        void handleCollision(EntityHandle e1, EntityHandle e2, luabridge::LuaRef handler)
        {
            if (!exists(e1) || !exists(e2)) return;

            auto key = std::make_pair(e1, e2);
            auto it = mCollisionHandlerMap.find(key);
            if (it == mCollisionHandlerMap.end())
            {
                mCollisionHandlerMap.insert(std::make_pair(
                    key,
                    handler));
            }
            else
            {
                it->second = handler;
            }
        }

        void registerKeyPressTable(luabridge::LuaRef table)
        {
            mKeyPressTable = table;
        }

        void registerKeyReleaseTable(luabridge::LuaRef table)
        {
            mKeyReleaseTable = table;
        }

        bool exists(EntityHandle handle)
        {
            auto it = std::find(std::begin(mEntities), std::end(mEntities), handle);
            return it != std::end(mEntities);
        }

        void addPendingDestroy(EntityHandle handle)
        {
            mPendingDestroys.push_back(handle);
        }

        void destroyEntity(EntityHandle handle)
        {
            if (!exists(handle)) return;

            auto positionIt = mPositionMap.find(handle);
            if (positionIt != mPositionMap.end())
            {
                mPositionMap.erase(positionIt);
            }
            auto velocityIt = mVelocityMap.find(handle);
            if (velocityIt != mVelocityMap.end())
            {
                mVelocityMap.erase(velocityIt);
            }
            auto boundingBoxIt = mBoundingBoxMap.find(handle);
            if (boundingBoxIt != mBoundingBoxMap.end())
            {
                mBoundingBoxMap.erase(boundingBoxIt);
            }
            auto dimensionIt = mDimensionMap.find(handle);
            if (dimensionIt != mDimensionMap.end())
            {
                mDimensionMap.erase(dimensionIt);
            }
            mEntities.erase(
                std::remove(mEntities.begin(), mEntities.end(), handle),
                mEntities.end());
        }

        void destroyEntities()
        {
            std::for_each(
                mPendingDestroys.begin(),
                mPendingDestroys.end(),
                [&](const EntityHandle& handle)
            {
                destroyEntity(handle);
            });
            mPendingDestroys.clear();
        }

        void processInput(const SDL_Event& evt)
        {
            if (evt.type == SDL_KEYDOWN)
            {
                if (mKeyPressTable[evt.key.keysym.sym].isFunction())
                {
                    mKeyPressTable[evt.key.keysym.sym]();
                }
            }
            else if (evt.type == SDL_KEYUP)
            {
                if (mKeyReleaseTable[evt.key.keysym.sym].isFunction())
                {
                    mKeyReleaseTable[evt.key.keysym.sym]();
                }
            }
        }

        void update(float dt)
        {
            forEachEntity([&](const EntityHandle& handle)
            {
                mPositionMap[handle] += dt * mVelocityMap[handle];
            });
            std::for_each(
                mCollisionHandlerMap.begin(),
                mCollisionHandlerMap.end(),
                [&](std::pair<const EntityPair, luabridge::LuaRef> kv)
            {
                if (checkCollision(
                    getBoundingBox(kv.first.first),
                    getBoundingBox(kv.first.second)))
                {
                    kv.second(kv.first.first, kv.first.second, dt);
                }
            });
            destroyEntities();
        }

        SDL_Rect getBoundingBox(EntityHandle handle)
        {
            Vector2f position = mPositionMap[handle];
            Vector2i boundingBox = mBoundingBoxMap[handle];
            return SDL_Rect{
                (int)position.x - (boundingBox.x / 2),
                (int)position.y - (boundingBox.y / 2),
                boundingBox.x,
                boundingBox.y
            };
        }

        SDL_Rect getIntersection(EntityHandle a, EntityHandle b)
        {
            SDL_Rect aRect = getBoundingBox(a);
            SDL_Rect bRect = getBoundingBox(b);
            return te::getIntersection(aRect, bRect);
        }

        void draw(RendererPtr pRenderer)
        {
            forEachEntity([&](const EntityHandle& handle)
            {
                auto positionIt = mPositionMap.find(handle);
                auto spriteIt = mDimensionMap.find(handle);
                if (spriteIt != mDimensionMap.end())
                {
                    Vector2f& pos = positionIt->second;
                    Vector2i& dim = spriteIt->second;
                    SDL_SetRenderDrawColor(pRenderer.get(), 0xFF, 0xFF, 0xFF, 0xFF);
                    SDL_Rect rect = {
                        (int)pos.x - (dim.x / 2),
                        (int)pos.y - (dim.y / 2),
                        dim.x,
                        dim.y
                    };
                    SDL_RenderFillRect(pRenderer.get(), &rect);
                }
            });
        }

        void forEachEntity(const std::function<void(const EntityHandle&)>& func)
        {
            std::for_each(mEntities.begin(), mEntities.end(), func);
        }

    private:
        std::shared_ptr<lua_State> mpL;
        EntityHandle mHandleCount;

        std::vector<EntityHandle> mEntities;

        std::map<EntityHandle, Vector2f> mPositionMap;
        std::map<EntityHandle, Vector2f> mVelocityMap;
        std::map<EntityHandle, Vector2i> mBoundingBoxMap;
        std::map<EntityHandle, Vector2i> mDimensionMap;

        std::vector<EntityHandle> mPendingDestroys;

        luabridge::LuaRef mKeyPressTable;
        luabridge::LuaRef mKeyReleaseTable;
        std::map<EntityPair, luabridge::LuaRef> mCollisionHandlerMap;
    };
}

int main(int argc, char** argv)
{
    te::Initialization init;

    LuaGameState state;

    const int WIDTH = 640;
    const int HEIGHT = 480;

    te::WindowPtr pWindow = te::wrapWindow(
        SDL_CreateWindow("Pong", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN)
    );
    te::RendererPtr pRenderer = te::createRenderer(pWindow);

    SDL_Event e;
    bool running = true;

    Uint32 FPS = 60;
    Uint32 TIME_PER_FRAME = 1000 / FPS;

    Uint64 t0 = SDL_GetPerformanceCounter();

    while (running)
    {
        while (SDL_PollEvent(&e) != 0)
        {
            if (e.type == SDL_QUIT)
            {
                running = false;
            }
            state.processInput(e);
        }

        Uint64 now = SDL_GetPerformanceCounter();
        float dt = (float)(now - t0) / SDL_GetPerformanceFrequency();

        state.update(dt);

        SDL_SetRenderDrawColor(pRenderer.get(), 0x00, 0x00, 0x00, 0xFF);
        SDL_RenderClear(pRenderer.get());

        state.draw(pRenderer);

        SDL_RenderPresent(pRenderer.get());
        t0 = now;
    }

    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/stringprintf.h"
#include "chrome/browser/sync/profile_sync_service_harness.h"
#include "chrome/browser/sync/test/integration/extensions_helper.h"
#include "chrome/browser/sync/test/integration/performance/sync_timing_helper.h"
#include "chrome/browser/sync/test/integration/sync_test.h"

using extensions_helper::AllProfilesHaveSameExtensions;
using extensions_helper::AllProfilesHaveSameExtensionsAsVerifier;
using extensions_helper::DisableExtension;
using extensions_helper::EnableExtension;
using extensions_helper::GetInstalledExtensions;
using extensions_helper::InstallExtension;
using extensions_helper::InstallExtensionsPendingForSync;
using extensions_helper::IsExtensionEnabled;
using extensions_helper::UninstallExtension;

// TODO(braffert): Replicate these tests for apps.

static const int kNumExtensions = 150;

class ExtensionsSyncPerfTest : public SyncTest {
 public:
  ExtensionsSyncPerfTest()
      : SyncTest(TWO_CLIENT),
        extension_number_(0) {}

  // Adds |num_extensions| new unique extensions to |profile|.
  void AddExtensions(int profile, int num_extensions);

  // Updates the enabled/disabled state for all extensions in |profile|.
  void UpdateExtensions(int profile);

  // Uninstalls all currently installed extensions from |profile|.
  void RemoveExtensions(int profile);

  // Returns the number of currently installed extensions for |profile|.
  int GetExtensionCount(int profile);

 private:
  int extension_number_;
  DISALLOW_COPY_AND_ASSIGN(ExtensionsSyncPerfTest);
};

void ExtensionsSyncPerfTest::AddExtensions(int profile, int num_extensions) {
  for (int i = 0; i < num_extensions; ++i) {
    InstallExtension(GetProfile(profile), extension_number_++);
  }
}

void ExtensionsSyncPerfTest::UpdateExtensions(int profile) {
  std::vector<int> extensions = GetInstalledExtensions(GetProfile(profile));
  for (std::vector<int>::iterator it = extensions.begin();
       it != extensions.end(); ++it) {
    if (IsExtensionEnabled(GetProfile(profile), *it)) {
      DisableExtension(GetProfile(profile), *it);
    } else {
      EnableExtension(GetProfile(profile), *it);
    }
  }
}

int ExtensionsSyncPerfTest::GetExtensionCount(int profile) {
  return GetInstalledExtensions(GetProfile(profile)).size();
}

void ExtensionsSyncPerfTest::RemoveExtensions(int profile) {
  std::vector<int> extensions = GetInstalledExtensions(GetProfile(profile));
  for (std::vector<int>::iterator it = extensions.begin();
       it != extensions.end(); ++it) {
    UninstallExtension(GetProfile(profile), *it);
  }
}

IN_PROC_BROWSER_TEST_F(ExtensionsSyncPerfTest, P0) {
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  int num_default_extensions = GetExtensionCount(0);
  int expected_extension_count = num_default_extensions + kNumExtensions;

  // TCM ID - 7563874.
  AddExtensions(0, kNumExtensions);
  base::TimeDelta dt =
      SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1));
  InstallExtensionsPendingForSync(GetProfile(1));
  ASSERT_EQ(expected_extension_count, GetExtensionCount(1));
  SyncTimingHelper::PrintResult("extensions", "add_extensions", dt);

  // TCM ID - 7655397.
  UpdateExtensions(0);
  dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1));
  ASSERT_EQ(expected_extension_count, GetExtensionCount(1));
  SyncTimingHelper::PrintResult("extensions", "update_extensions", dt);

  // TCM ID - 7567721.
  RemoveExtensions(0);
  dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1));
  ASSERT_EQ(num_default_extensions, GetExtensionCount(1));
  SyncTimingHelper::PrintResult("extensions", "delete_extensions", dt);
}
<commit_msg>Performance - Disabled ExtensionsSyncPerfTest on Windows to fix the windows performance bots to go green<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/stringprintf.h"
#include "chrome/browser/sync/profile_sync_service_harness.h"
#include "chrome/browser/sync/test/integration/extensions_helper.h"
#include "chrome/browser/sync/test/integration/performance/sync_timing_helper.h"
#include "chrome/browser/sync/test/integration/sync_test.h"

using extensions_helper::AllProfilesHaveSameExtensions;
using extensions_helper::AllProfilesHaveSameExtensionsAsVerifier;
using extensions_helper::DisableExtension;
using extensions_helper::EnableExtension;
using extensions_helper::GetInstalledExtensions;
using extensions_helper::InstallExtension;
using extensions_helper::InstallExtensionsPendingForSync;
using extensions_helper::IsExtensionEnabled;
using extensions_helper::UninstallExtension;

// TODO(braffert): Replicate these tests for apps.

static const int kNumExtensions = 150;

class ExtensionsSyncPerfTest : public SyncTest {
 public:
  ExtensionsSyncPerfTest()
      : SyncTest(TWO_CLIENT),
        extension_number_(0) {}

  // Adds |num_extensions| new unique extensions to |profile|.
  void AddExtensions(int profile, int num_extensions);

  // Updates the enabled/disabled state for all extensions in |profile|.
  void UpdateExtensions(int profile);

  // Uninstalls all currently installed extensions from |profile|.
  void RemoveExtensions(int profile);

  // Returns the number of currently installed extensions for |profile|.
  int GetExtensionCount(int profile);

 private:
  int extension_number_;
  DISALLOW_COPY_AND_ASSIGN(ExtensionsSyncPerfTest);
};

void ExtensionsSyncPerfTest::AddExtensions(int profile, int num_extensions) {
  for (int i = 0; i < num_extensions; ++i) {
    InstallExtension(GetProfile(profile), extension_number_++);
  }
}

void ExtensionsSyncPerfTest::UpdateExtensions(int profile) {
  std::vector<int> extensions = GetInstalledExtensions(GetProfile(profile));
  for (std::vector<int>::iterator it = extensions.begin();
       it != extensions.end(); ++it) {
    if (IsExtensionEnabled(GetProfile(profile), *it)) {
      DisableExtension(GetProfile(profile), *it);
    } else {
      EnableExtension(GetProfile(profile), *it);
    }
  }
}

int ExtensionsSyncPerfTest::GetExtensionCount(int profile) {
  return GetInstalledExtensions(GetProfile(profile)).size();
}

void ExtensionsSyncPerfTest::RemoveExtensions(int profile) {
  std::vector<int> extensions = GetInstalledExtensions(GetProfile(profile));
  for (std::vector<int>::iterator it = extensions.begin();
       it != extensions.end(); ++it) {
    UninstallExtension(GetProfile(profile), *it);
  }
}

// Flaky on Windows, see http://crbug.com/111072
#if defined(OS_WIN)
#define MAYBE_P0 DISABLED_P0
#else
#define MAYBE_P0 P0
#endif

IN_PROC_BROWSER_TEST_F(ExtensionsSyncPerfTest, MAYBE_P0) {
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  int num_default_extensions = GetExtensionCount(0);
  int expected_extension_count = num_default_extensions + kNumExtensions;

  // TCM ID - 7563874.
  AddExtensions(0, kNumExtensions);
  base::TimeDelta dt =
      SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1));
  InstallExtensionsPendingForSync(GetProfile(1));
  ASSERT_EQ(expected_extension_count, GetExtensionCount(1));
  SyncTimingHelper::PrintResult("extensions", "add_extensions", dt);

  // TCM ID - 7655397.
  UpdateExtensions(0);
  dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1));
  ASSERT_EQ(expected_extension_count, GetExtensionCount(1));
  SyncTimingHelper::PrintResult("extensions", "update_extensions", dt);

  // TCM ID - 7567721.
  RemoveExtensions(0);
  dt = SyncTimingHelper::TimeMutualSyncCycle(GetClient(0), GetClient(1));
  ASSERT_EQ(num_default_extensions, GetExtensionCount(1));
  SyncTimingHelper::PrintResult("extensions", "delete_extensions", dt);
}
<|endoftext|>


<commit_before>#include "gc.hh"
#include "atomic.hh"
#include "radix.hh"
#include "cpputil.hh"
#include "hwvm.hh"
#include "uwq.hh"
#include "distref.hh"
#include "bit_spinlock.hh"
#include "radix_array.hh"
#include "kalloc.hh"
#include "page_info.hh"

struct padded_length;

using std::atomic;

// A virtual memory descriptor that maintains metadata for pages in an
// address space.  This plays a similar role to the more traditional
// "virtual memory area," but this does not know its size (it could
// represent a single page or the entire address space).
struct vmdesc
{
  enum {
    // Bit used for radix tree range locking
    FLAG_LOCK_BIT = 0,
    FLAG_LOCK = 1<<FLAG_LOCK_BIT,

    // Set if this virtual page frame has been mapped
    FLAG_MAPPED = 1<<1,

    // Set if this virtual page frame is copy-on-write.  A write fault
    // to this page frame should copy page and unset the COW bit.  A
    // read fault should map the existing page read-only.  This flag
    // should be zero if this VPF has no backing page.
    FLAG_COW = 1<<2,

    // Set if this page frame maps anonymous memory.  Cleared if this
    // page frame maps a file (in which case ip and start are used).
    FLAG_ANON = 1<<3,
  };

  // Flags
  u64 flags;

  // The physical page mapped in this frame, or null if no page has
  // been allocated for this frame.
  sref<class page_info> page;

  // XXX We could pack the following fields into a union if there's
  // anything we can overlap with them for anonymous memory.  However,
  // then we have to use C++11 unrestricted unions because of the
  // sref, so we'd have to define all of vmdesc's special methods
  // ourselves.

  // The file mapped at this page frame.
  sref<struct inode> inode;

  // If a file is mapped at this page frame, the virtual address of
  // that file's 0 byte.  For anonymous memory, this must be 0.  We
  // record this instead of the page frame's offset in the file so
  // that a range of page frames mapping a sequence of pages from a
  // file will be identical (and hence compressable in the radix
  // tree).
  intptr_t start;

  // Construct a descriptor for unmapped memory.
  vmdesc() : flags(0), start(0) { }

  // Construct a descriptor that maps the beginning of ip's file to
  // virtual address start (which may be negative).
  vmdesc(const sref<struct inode> &ip, intptr_t start)
    : flags(FLAG_MAPPED), inode(ip), start(start) { }

  // The anonymous memory descriptor.
  static struct vmdesc anon_desc;

  // Radix_array element methods

  bit_spinlock get_lock()
  {
    return bit_spinlock(&flags, FLAG_LOCK_BIT);
  }

  bool is_set() const
  {
    return flags & FLAG_MAPPED;
  }

private:
  vmdesc(u64 flags)
    : flags(flags), page(), inode(), start() { }
};

void to_stream(class print_stream *s, const vmdesc &vmd);

// An address space. This manages the mapping from virtual addresses
// to virtual memory descriptors.
struct vmap {
  struct radix vmas;

  static vmap* alloc();

  atomic<u64> ref;
  char *const kshared;

  void decref();
  void incref();

  // Copy this vmap's structure and share pages copy-on-write.
  vmap* copy(proc_pgmap* pgmap);

  // Map desc from virtual addresses start to start+len.
  long insert(const vmdesc &desc, uptr start, uptr len, proc_pgmap* pgmap,
              bool dotlb = true);

  // Unmap from virtual addresses start to start+len.
  int remove(uptr start, uptr len, proc_pgmap* pgmap);

  int pagefault(uptr va, u32 err, proc_pgmap* pgmap);

  // Map virtual address va in this address space to a kernel virtual
  // address, performing the equivalent of a read page fault if
  // necessary.  Returns nullptr if va is not mapped.  Needless to
  // say, this mapping is only valid within the returned page.
  void* pagelookup(uptr va);

  // Copy len bytes from p to user address va in vmap.  Most useful
  // when vmap is not the current page table.
  int copyout(uptr va, void *p, u64 len);
  int sbrk(ssize_t n, uptr *addr);

  void add_pgmap(proc_pgmap* pgmap);
  void rem_pgmap(proc_pgmap* pgmap);

  // Print this vmap to the console
  void dump();

  uptr brk_;                    // Top of heap

private:
  vmap();
  vmap(const vmap&);
  vmap& operator=(const vmap&);
  ~vmap();
  NEW_DELETE_OPS(vmap)
  uptr unmapped_area(size_t n);

  // Virtual page frames
  typedef radix_array<vmdesc, USERTOP / PGSIZE, PGSIZE,
                      kalloc_allocator<vmdesc> > vpf_array;
  vpf_array vpfs_;

  struct spinlock brklock_;

  enum class access_type
  {
    READ, WRITE
  };

  // Ensure there is a backing page at @c it.  The caller is
  // responsible for ensuring that there is a mapping at @c it and for
  // locking vpfs_ at @c it.  This throws bad_alloc if a page must be
  // allocated and cannot be.
  page_info *ensure_page(const vpf_array::iterator &it, access_type type);

  // XXX(sbw) most likely an awful hash function
  static u64 proc_pgmap_hash(proc_pgmap* const & p)
  {
    return (u64) p;
  }
  xns<proc_pgmap*, proc_pgmap*, proc_pgmap_hash> pgmap_list_;
};
<commit_msg>vm: Fix crash with large mappings<commit_after>#include "gc.hh"
#include "atomic.hh"
#include "radix.hh"
#include "cpputil.hh"
#include "hwvm.hh"
#include "uwq.hh"
#include "distref.hh"
#include "bit_spinlock.hh"
#include "radix_array.hh"
#include "kalloc.hh"
#include "page_info.hh"

struct padded_length;

using std::atomic;

// A virtual memory descriptor that maintains metadata for pages in an
// address space.  This plays a similar role to the more traditional
// "virtual memory area," but this does not know its size (it could
// represent a single page or the entire address space).
struct vmdesc
{
  enum {
    // Bit used for radix tree range locking
    FLAG_LOCK_BIT = 0,
    FLAG_LOCK = 1<<FLAG_LOCK_BIT,

    // Set if this virtual page frame has been mapped
    FLAG_MAPPED = 1<<1,

    // Set if this virtual page frame is copy-on-write.  A write fault
    // to this page frame should copy page and unset the COW bit.  A
    // read fault should map the existing page read-only.  This flag
    // should be zero if this VPF has no backing page.
    FLAG_COW = 1<<2,

    // Set if this page frame maps anonymous memory.  Cleared if this
    // page frame maps a file (in which case ip and start are used).
    FLAG_ANON = 1<<3,
  };

  // Flags
  u64 flags;

  // The physical page mapped in this frame, or null if no page has
  // been allocated for this frame.
  sref<class page_info> page;

  // XXX We could pack the following fields into a union if there's
  // anything we can overlap with them for anonymous memory.  However,
  // then we have to use C++11 unrestricted unions because of the
  // sref, so we'd have to define all of vmdesc's special methods
  // ourselves.

  // The file mapped at this page frame.
  sref<struct inode> inode;

  // If a file is mapped at this page frame, the virtual address of
  // that file's 0 byte.  For anonymous memory, this must be 0.  We
  // record this instead of the page frame's offset in the file so
  // that a range of page frames mapping a sequence of pages from a
  // file will be identical (and hence compressable in the radix
  // tree).
  intptr_t start;

  // Construct a descriptor for unmapped memory.
  vmdesc() : flags(0), start(0) { }

  // Construct a descriptor that maps the beginning of ip's file to
  // virtual address start (which may be negative).
  vmdesc(const sref<struct inode> &ip, intptr_t start)
    : flags(FLAG_MAPPED), inode(ip), start(start) { }

  // The anonymous memory descriptor.
  static struct vmdesc anon_desc;

  // Radix_array element methods

  bit_spinlock get_lock()
  {
    return bit_spinlock(&flags, FLAG_LOCK_BIT);
  }

  bool is_set() const
  {
    return flags & FLAG_MAPPED;
  }

  // We need new/delete so the radix_array can allocate external nodes
  // when performing node compression.
  NEW_DELETE_OPS(vmdesc)

private:
  vmdesc(u64 flags)
    : flags(flags), page(), inode(), start() { }
};

void to_stream(class print_stream *s, const vmdesc &vmd);

// An address space. This manages the mapping from virtual addresses
// to virtual memory descriptors.
struct vmap {
  struct radix vmas;

  static vmap* alloc();

  atomic<u64> ref;
  char *const kshared;

  void decref();
  void incref();

  // Copy this vmap's structure and share pages copy-on-write.
  vmap* copy(proc_pgmap* pgmap);

  // Map desc from virtual addresses start to start+len.
  long insert(const vmdesc &desc, uptr start, uptr len, proc_pgmap* pgmap,
              bool dotlb = true);

  // Unmap from virtual addresses start to start+len.
  int remove(uptr start, uptr len, proc_pgmap* pgmap);

  int pagefault(uptr va, u32 err, proc_pgmap* pgmap);

  // Map virtual address va in this address space to a kernel virtual
  // address, performing the equivalent of a read page fault if
  // necessary.  Returns nullptr if va is not mapped.  Needless to
  // say, this mapping is only valid within the returned page.
  void* pagelookup(uptr va);

  // Copy len bytes from p to user address va in vmap.  Most useful
  // when vmap is not the current page table.
  int copyout(uptr va, void *p, u64 len);
  int sbrk(ssize_t n, uptr *addr);

  void add_pgmap(proc_pgmap* pgmap);
  void rem_pgmap(proc_pgmap* pgmap);

  // Print this vmap to the console
  void dump();

  uptr brk_;                    // Top of heap

private:
  vmap();
  vmap(const vmap&);
  vmap& operator=(const vmap&);
  ~vmap();
  NEW_DELETE_OPS(vmap)
  uptr unmapped_area(size_t n);

  // Virtual page frames
  typedef radix_array<vmdesc, USERTOP / PGSIZE, PGSIZE,
                      kalloc_allocator<vmdesc> > vpf_array;
  vpf_array vpfs_;

  struct spinlock brklock_;

  enum class access_type
  {
    READ, WRITE
  };

  // Ensure there is a backing page at @c it.  The caller is
  // responsible for ensuring that there is a mapping at @c it and for
  // locking vpfs_ at @c it.  This throws bad_alloc if a page must be
  // allocated and cannot be.
  page_info *ensure_page(const vpf_array::iterator &it, access_type type);

  // XXX(sbw) most likely an awful hash function
  static u64 proc_pgmap_hash(proc_pgmap* const & p)
  {
    return (u64) p;
  }
  xns<proc_pgmap*, proc_pgmap*, proc_pgmap_hash> pgmap_list_;
};
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "LogQueryImpl.h"
#include "LogItem.h"
#include "LogQueryResult.h"
#include "FilterParser.h"
#include "PatternServiceImpl.h"

using namespace mrl::utility;

LogQueryImpl::LogQueryImpl()
	: taskWnd(new SimpleTaskMessageWindow())
	, monitorThread(NULL)
	, monitoring(false) {
}

LogQueryImpl::~LogQueryImpl() {
	if (monitoring && monitorThread) {
		monitoring = false;
		monitorThread->join();
		delete monitorThread;
	}
	reset();

	delete taskWnd;
}

bool LogQueryImpl::load(const tstring& filePath) {
	this->filePath = filePath;
	startMonitor();
	return true;
}

const tstring& LogQueryImpl::getFilePath() const {
	return filePath;
}

void LogQueryImpl::setSelected(const LogItem* item) {
	for (unsigned j = 0; j < logItems.size(); j++) {
		LogItem* p = logItems[j];
		p->selected = (item == p);
	}
	notifyGeneralDataChanged();
}

LogItem* LogQueryImpl::getSelected() const {
	auto i = find_if(logItems.begin(), logItems.end(), [] (LogItem* p) {
		return p->selected;
	});
	if (i != logItems.end()) {
		return *i;
	} else {
		return NULL;
	}
}

LogQueryResult* LogQueryImpl::query(const tstring& criteria, bool quiet) {
	LogQueryResult* cachedResult = queryCache[criteria];
	if (!cachedResult) {
		cachedResult = queryImpl(criteria);
		if (cachedResult) {
			queryCache[criteria] = cachedResult;
		}
	}
	if (!quiet) notifyQueryResultChanged(criteria, cachedResult);
	return cachedResult;
}

LogQueryResult* LogQueryImpl::queryImpl(const tstring& criteria) {
// UNDONE: 把parser改为tstring兼容
#ifdef _UNICODE
	string filter = mrl::utility::codeconv::unicodeToAscii(criteria);
#else
	string filter& = criteria;
#endif
	try {
		FilterParser parser;
		parser.compile(filter);

		vector<LogItem*> queryResult;
		for (auto i = logItems.begin(); i != logItems.end(); i++) {
			LogItem* item = *i;
#ifdef _UNICODE
			string line = mrl::utility::codeconv::unicodeToAscii(item->text);
#else
			string line& = item->text;
#endif
			if (parser.rootNode()->match(line)) {
				queryResult.push_back(item);
			}
		}
		return new LogQueryResult(queryResult);
	} catch (...) {
		return nullptr;
	}
}

void LogQueryImpl::startMonitor() {
	monitorThread = new boost::thread(([this] () {
		monitoring = true;
		while (monitoring) {
			// UNDONE: 优化
			::Sleep(500);
			vector<LogItem*> logItems;
			loadFile(logItems);
			// UNDONE: 简单比较
			if (this->logItems.size() != logItems.size()) {
				DEBUG_INFO(_T("监测到文件变化"));
				LogQueryImpl* that = this;
				taskWnd->post(new SimpleTask([that, logItems] () {
					that->reset(logItems);
				}))->wait();
			} else {
				for_each(logItems.begin(), logItems.end(), [] (LogItem* p) {
					delete p;
				});
			}
		} // while monitoring
		DEBUG_INFO(_T("监控线程退出！"));
	}));
}

void LogQueryImpl::reset(const vector<LogItem*>& logItems) {
	for_each(this->logItems.begin(), this->logItems.end(), [] (LogItem* p) {
		delete p;
	});
	this->logItems = logItems;

	for_each(this->queryCache.begin(), this->queryCache.end(), [] (const pair<tstring, LogQueryResult*>& p) {
		delete p.second;
	});
	queryCache.clear();

	notifyFileChanged();
}

void LogQueryImpl::reset() {
	reset(vector<LogItem*>());
}

void LogQueryImpl::loadFile(vector<LogItem*>& logItems) {
	HANDLE file = ::CreateFile(filePath.c_str(), GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
	                           NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (file != INVALID_HANDLE_VALUE) {
		DWORD fileSize = ::GetFileSize(file, NULL);
		char* buffer = new char[fileSize + 1];
		DWORD readSize = 0;
		// 从头重新读取文件
		::SetFilePointer(file, 0, NULL, FILE_BEGIN);
		if (::ReadFile(file, buffer, fileSize + 1, &readSize, NULL)) {
			buffer[readSize] = 0;
			istringstream iss(buffer);

			string line;
			unsigned lineNum = 0;
			while (iss.good()) {
				std::getline(iss, line);
				LogItem* item = new LogItem();
				item->line = lineNum++;
#ifdef _UNICODE
				item->text = mrl::utility::codeconv::asciiToUnicode(line);
#else
				item->text = line;
#endif
				item->selected = false;
				logItems.push_back(item);
			}
		}
		delete[] buffer;
		::CloseHandle(file);
	}
}<commit_msg>使用GetFileSize大幅提升监控性能<commit_after>#include "stdafx.h"
#include "LogQueryImpl.h"
#include "LogItem.h"
#include "LogQueryResult.h"
#include "FilterParser.h"
#include "PatternServiceImpl.h"

using namespace mrl::utility;

LogQueryImpl::LogQueryImpl()
	: taskWnd(new SimpleTaskMessageWindow())
	, monitorThread(NULL)
	, monitoring(false) {
}

LogQueryImpl::~LogQueryImpl() {
	if (monitoring && monitorThread) {
		monitoring = false;
		monitorThread->join();
		delete monitorThread;
	}
	reset();

	delete taskWnd;
}

bool LogQueryImpl::load(const tstring& filePath) {
	this->filePath = filePath;
	startMonitor();
	return true;
}

const tstring& LogQueryImpl::getFilePath() const {
	return filePath;
}

void LogQueryImpl::setSelected(const LogItem* item) {
	for (unsigned j = 0; j < logItems.size(); j++) {
		LogItem* p = logItems[j];
		p->selected = (item == p);
	}
	notifyGeneralDataChanged();
}

LogItem* LogQueryImpl::getSelected() const {
	auto i = find_if(logItems.begin(), logItems.end(), [] (LogItem* p) {
		return p->selected;
	});
	if (i != logItems.end()) {
		return *i;
	} else {
		return NULL;
	}
}

LogQueryResult* LogQueryImpl::query(const tstring& criteria, bool quiet) {
	LogQueryResult* cachedResult = queryCache[criteria];
	if (!cachedResult) {
		cachedResult = queryImpl(criteria);
		if (cachedResult) {
			queryCache[criteria] = cachedResult;
		}
	}
	if (!quiet) notifyQueryResultChanged(criteria, cachedResult);
	return cachedResult;
}

LogQueryResult* LogQueryImpl::queryImpl(const tstring& criteria) {
// UNDONE: 把parser改为tstring兼容
#ifdef _UNICODE
	string filter = mrl::utility::codeconv::unicodeToAscii(criteria);
#else
	string filter& = criteria;
#endif
	try {
		FilterParser parser;
		parser.compile(filter);

		vector<LogItem*> queryResult;
		for (auto i = logItems.begin(); i != logItems.end(); i++) {
			LogItem* item = *i;
#ifdef _UNICODE
			string line = mrl::utility::codeconv::unicodeToAscii(item->text);
#else
			string line& = item->text;
#endif
			if (parser.rootNode()->match(line)) {
				queryResult.push_back(item);
			}
		}
		return new LogQueryResult(queryResult);
	} catch (...) {
		return nullptr;
	}
}

unsigned getFileSize(const tstring& filePath) {
	HANDLE file = ::CreateFile(filePath.c_str(), GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	DWORD ret = ::GetFileSize(file, NULL);
	::CloseHandle(file);
	return ret;
}

void LogQueryImpl::startMonitor() {
	monitorThread = new boost::thread(([this] () {
		monitoring = true;
		unsigned lastSize = 0;
		while (monitoring) {
			// UNDONE: 优化
			::Sleep(500);
			unsigned size = getFileSize(filePath);
			if (size == lastSize) continue;
			lastSize = size;

			vector<LogItem*> logItems;
			loadFile(logItems);
			// UNDONE: 简单比较
			if (this->logItems.size() != logItems.size()) {
				DEBUG_INFO(_T("监测到文件变化"));
				LogQueryImpl* that = this;
				taskWnd->post(new SimpleTask([that, logItems] () {
					that->reset(logItems);
				}))->wait();
			} else {
				for_each(logItems.begin(), logItems.end(), [] (LogItem* p) {
					delete p;
				});
			}
		} // while monitoring
		DEBUG_INFO(_T("监控线程退出！"));
	}));
}

void LogQueryImpl::reset(const vector<LogItem*>& logItems) {
	for_each(this->logItems.begin(), this->logItems.end(), [] (LogItem* p) {
		delete p;
	});
	this->logItems = logItems;

	for_each(this->queryCache.begin(), this->queryCache.end(), [] (const pair<tstring, LogQueryResult*>& p) {
		delete p.second;
	});
	queryCache.clear();

	notifyFileChanged();
}

void LogQueryImpl::reset() {
	reset(vector<LogItem*>());
}

void LogQueryImpl::loadFile(vector<LogItem*>& logItems) {
	HANDLE file = ::CreateFile(filePath.c_str(), GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
	                           NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (file != INVALID_HANDLE_VALUE) {
		DWORD fileSize = ::GetFileSize(file, NULL);
		char* buffer = new char[fileSize + 1];
		DWORD readSize = 0;
		// 从头重新读取文件
		::SetFilePointer(file, 0, NULL, FILE_BEGIN);
		if (::ReadFile(file, buffer, fileSize + 1, &readSize, NULL)) {
			buffer[readSize] = 0;
			istringstream iss(buffer);

			string line;
			unsigned lineNum = 0;
			while (iss.good()) {
				std::getline(iss, line);
				LogItem* item = new LogItem();
				item->line = lineNum++;
#ifdef _UNICODE
				item->text = mrl::utility::codeconv::asciiToUnicode(line);
#else
				item->text = line;
#endif
				item->selected = false;
				logItems.push_back(item);
			}
		}
		delete[] buffer;
		::CloseHandle(file);
	}
}<|endoftext|>