<commit_before>/*
 *  Copyright (c) 2012 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.
 */

// This file includes unit tests for ViERemb.

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
#include "modules/utility/interface/process_thread.h"
#include "system_wrappers/interface/scoped_ptr.h"
#include "system_wrappers/interface/sleep.h"
#include "video_engine/vie_remb.h"

using ::testing::_;
using ::testing::AnyNumber;
using ::testing::Return;

namespace webrtc {

// TODO(mflodman) Make a trigger function for this class to fake a clock and
// remove sleeps in the test.
class TestProcessThread : public ProcessThread {
 public:
  explicit TestProcessThread() {}
  ~TestProcessThread() {}
  virtual WebRtc_Word32 Start() { return 0; }
  virtual WebRtc_Word32 Stop() { return 0; }
  virtual WebRtc_Word32 RegisterModule(const Module* module) { return 0; }
  virtual WebRtc_Word32 DeRegisterModule(const Module* module) { return 0; }
};

class ViERembTest : public ::testing::Test {
 protected:
  virtual void SetUp() {
    process_thread_.reset(new TestProcessThread);
    vie_remb_.reset(new VieRemb(process_thread_.get()));
  }
  scoped_ptr<TestProcessThread> process_thread_;
  scoped_ptr<VieRemb> vie_remb_;
};

TEST_F(ViERembTest, OneModuleTestForSendingRemb) {
  MockRtpRtcp rtp;
  vie_remb_->AddReceiveChannel(&rtp);
  vie_remb_->AddRembSender(&rtp);

  const unsigned int bitrate_estimate = 456;
  unsigned int ssrc = 1234;

  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  EXPECT_CALL(rtp, RemoteSSRC())
      .WillRepeatedly(Return(ssrc));

  // TODO(mflodman) Add fake clock and remove the lowered bitrate below.
  SleepMs(1010);
  EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
      .Times(1);
  vie_remb_->Process();

  // Lower bitrate to send another REMB packet.
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate - 100);
  EXPECT_CALL(rtp, SetREMBData(bitrate_estimate - 100, 1, _))
        .Times(1);
  vie_remb_->Process();

  vie_remb_->RemoveReceiveChannel(&rtp);
  vie_remb_->RemoveRembSender(&rtp);
}

TEST_F(ViERembTest, LowerEstimateToSendRemb) {
  MockRtpRtcp rtp;
  vie_remb_->AddReceiveChannel(&rtp);
  vie_remb_->AddRembSender(&rtp);

  unsigned int bitrate_estimate = 456;
  unsigned int ssrc = 1234;

  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  EXPECT_CALL(rtp, RemoteSSRC())
      .WillRepeatedly(Return(ssrc));
  // Call process to get a first estimate.
  SleepMs(1010);
  EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
        .Times(1);
  vie_remb_->Process();

  // Lower the estimate with more than 3% to trigger a call to SetREMBData right
  // away.
  bitrate_estimate = bitrate_estimate - 100;
  EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
      .Times(1);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  vie_remb_->Process();
}

TEST_F(ViERembTest, VerifyIncreasingAndDecreasing) {
  MockRtpRtcp rtp_0;
  MockRtpRtcp rtp_1;
  vie_remb_->AddReceiveChannel(&rtp_0);
  vie_remb_->AddRembSender(&rtp_0);
  vie_remb_->AddReceiveChannel(&rtp_1);

  unsigned int bitrate_estimate[] = { 456, 789 };
  unsigned int ssrc[] = { 1234, 5678 };

  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate[0]);
  EXPECT_CALL(rtp_0, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[0]));
  EXPECT_CALL(rtp_1, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[1]));

  // Call process to get a first estimate.
  EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate[0], 2, _))
        .Times(1);
  SleepMs(1010);
  vie_remb_->Process();

  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate[1] + 100);
  EXPECT_CALL(rtp_0, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[0]));
  EXPECT_CALL(rtp_1, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[1]));

  // Lower the estimate to trigger a callback.
  EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate[1], 2, _))
      .Times(1);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate[1]);
  vie_remb_->Process();

  vie_remb_->RemoveReceiveChannel(&rtp_0);
  vie_remb_->RemoveRembSender(&rtp_0);
  vie_remb_->RemoveReceiveChannel(&rtp_1);
}

TEST_F(ViERembTest, NoRembForIncreasedBitrate) {
  MockRtpRtcp rtp_0;
  MockRtpRtcp rtp_1;
  vie_remb_->AddReceiveChannel(&rtp_0);
  vie_remb_->AddRembSender(&rtp_0);
  vie_remb_->AddReceiveChannel(&rtp_1);

  unsigned int bitrate_estimate = 456;
  unsigned int ssrc[] = { 1234, 5678 };

  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  EXPECT_CALL(rtp_0, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[0]));
  EXPECT_CALL(rtp_1, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[1]));

  // Trigger a first call to have a running state.
  // TODO(mflodman) Add fake clock.
  SleepMs(1010);
  EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _))
      .Times(1);
  vie_remb_->Process();

  // Increased estimate shouldn't trigger a callback right away.
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate + 1);
  EXPECT_CALL(rtp_0, SetREMBData(_, _, _))
      .Times(0);

  // Decreasing the estimate less than 3% shouldn't trigger a new callback.
  int lower_estimate = bitrate_estimate * 98 / 100;
  vie_remb_->OnReceiveBitrateChanged(lower_estimate);
  EXPECT_CALL(rtp_0, SetREMBData(_, _, _))
      .Times(0);

  vie_remb_->Process();
  vie_remb_->RemoveReceiveChannel(&rtp_1);
  vie_remb_->RemoveReceiveChannel(&rtp_0);
  vie_remb_->RemoveRembSender(&rtp_0);
}

TEST_F(ViERembTest, ChangeSendRtpModule) {
  MockRtpRtcp rtp_0;
  MockRtpRtcp rtp_1;
  vie_remb_->AddReceiveChannel(&rtp_0);
  vie_remb_->AddRembSender(&rtp_0);
  vie_remb_->AddReceiveChannel(&rtp_1);

  unsigned int bitrate_estimate = 456;
  unsigned int ssrc[] = { 1234, 5678 };

  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  EXPECT_CALL(rtp_0, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[0]));
  EXPECT_CALL(rtp_1, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[1]));

  // Call process to get a first estimate.
  SleepMs(1010);
  EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _))
      .Times(1);
  vie_remb_->Process();

  // Decrease estimate to trigger a REMB.
  bitrate_estimate = bitrate_estimate - 100;
  EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _))
      .Times(1);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  vie_remb_->Process();

  // Remove the sending module, add it again -> should get remb on the second
  // module.
  vie_remb_->RemoveRembSender(&rtp_0);
  vie_remb_->AddRembSender(&rtp_1);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);

  bitrate_estimate = bitrate_estimate - 100;
  EXPECT_CALL(rtp_1, SetREMBData(bitrate_estimate, 2, _))
        .Times(1);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  vie_remb_->Process();

  vie_remb_->RemoveReceiveChannel(&rtp_0);
  vie_remb_->RemoveReceiveChannel(&rtp_1);
}

TEST_F(ViERembTest, OnlyOneRembForDoubleProcess) {
  MockRtpRtcp rtp;
  unsigned int bitrate_estimate = 456;
  unsigned int ssrc = 1234;

  vie_remb_->AddReceiveChannel(&rtp);
  vie_remb_->AddRembSender(&rtp);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  EXPECT_CALL(rtp, RemoteSSRC())
      .WillRepeatedly(Return(ssrc));

  // Call process to get a first estimate.
  SleepMs(1010);
  EXPECT_CALL(rtp, SetREMBData(_, _, _))
        .Times(1);
  vie_remb_->Process();

  // Lower the estimate, should trigger a call to SetREMBData right away.
  bitrate_estimate = bitrate_estimate - 100;
  EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
      .Times(1);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  vie_remb_->Process();

  // Call Process again, this should not trigger a new callback.
  EXPECT_CALL(rtp, SetREMBData(_, _, _))
      .Times(0);
  vie_remb_->Process();
  vie_remb_->RemoveReceiveChannel(&rtp);
  vie_remb_->RemoveRembSender(&rtp);
}

TEST_F(ViERembTest, NoOnReceivedBitrateChangedCall) {
  MockRtpRtcp rtp;
  EXPECT_CALL(rtp, RemoteSSRC())
        .WillRepeatedly(Return(1234));

  vie_remb_->AddReceiveChannel(&rtp);
  vie_remb_->AddRembSender(&rtp);
  // TODO(mflodman) Add fake clock.
  SleepMs(1010);
  // No bitrate estimate given, no callback expected.
  EXPECT_CALL(rtp, SetREMBData(_, _, _))
      .Times(0);
  vie_remb_->Process();

  vie_remb_->RemoveReceiveChannel(&rtp);
  vie_remb_->RemoveRembSender(&rtp);
}

// Only register receiving modules and make sure we fallback to trigger a REMB
// packet on this one.
TEST_F(ViERembTest, NoSendingRtpModule) {
  MockRtpRtcp rtp;
  vie_remb_->AddReceiveChannel(&rtp);

  unsigned int bitrate_estimate = 456;
  unsigned int ssrc = 1234;

  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  EXPECT_CALL(rtp, RemoteSSRC())
      .WillRepeatedly(Return(ssrc));

  // Call process to get a first estimate.
  SleepMs(1010);
  EXPECT_CALL(rtp, SetREMBData(_, _, _))
      .Times(1);
  vie_remb_->Process();

  // Lower the estimate to trigger a new packet REMB packet.
  bitrate_estimate = bitrate_estimate - 100;
  EXPECT_CALL(rtp, SetREMBData(_, _, _))
      .Times(1);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  vie_remb_->Process();
}

}  // namespace webrtc
<commit_msg>Replaced remb unittest sleep with fake clock.<commit_after>/*
 *  Copyright (c) 2012 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.
 */

// This file includes unit tests for ViERemb.

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
#include "webrtc/modules/utility/interface/process_thread.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/system_wrappers/interface/tick_util.h"
#include "webrtc/video_engine/vie_remb.h"

using ::testing::_;
using ::testing::AnyNumber;
using ::testing::Return;

namespace webrtc {

class TestProcessThread : public ProcessThread {
 public:
  explicit TestProcessThread() {}
  ~TestProcessThread() {}
  virtual WebRtc_Word32 Start() { return 0; }
  virtual WebRtc_Word32 Stop() { return 0; }
  virtual WebRtc_Word32 RegisterModule(const Module* module) { return 0; }
  virtual WebRtc_Word32 DeRegisterModule(const Module* module) { return 0; }
};

class ViERembTest : public ::testing::Test {
 protected:
  virtual void SetUp() {
    TickTime::UseFakeClock(12345);
    process_thread_.reset(new TestProcessThread);
    vie_remb_.reset(new VieRemb(process_thread_.get()));
  }
  scoped_ptr<TestProcessThread> process_thread_;
  scoped_ptr<VieRemb> vie_remb_;
};

TEST_F(ViERembTest, OneModuleTestForSendingRemb) {
  MockRtpRtcp rtp;
  vie_remb_->AddReceiveChannel(&rtp);
  vie_remb_->AddRembSender(&rtp);

  const unsigned int bitrate_estimate = 456;
  unsigned int ssrc = 1234;

  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  EXPECT_CALL(rtp, RemoteSSRC())
      .WillRepeatedly(Return(ssrc));

  TickTime::AdvanceFakeClock(1000);
  EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
      .Times(1);
  vie_remb_->Process();

  // Lower bitrate to send another REMB packet.
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate - 100);
  EXPECT_CALL(rtp, SetREMBData(bitrate_estimate - 100, 1, _))
        .Times(1);
  vie_remb_->Process();

  vie_remb_->RemoveReceiveChannel(&rtp);
  vie_remb_->RemoveRembSender(&rtp);
}

TEST_F(ViERembTest, LowerEstimateToSendRemb) {
  MockRtpRtcp rtp;
  vie_remb_->AddReceiveChannel(&rtp);
  vie_remb_->AddRembSender(&rtp);

  unsigned int bitrate_estimate = 456;
  unsigned int ssrc = 1234;

  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  EXPECT_CALL(rtp, RemoteSSRC())
      .WillRepeatedly(Return(ssrc));
  // Call process to get a first estimate.
  TickTime::AdvanceFakeClock(1000);
  EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
        .Times(1);
  vie_remb_->Process();

  // Lower the estimate with more than 3% to trigger a call to SetREMBData right
  // away.
  bitrate_estimate = bitrate_estimate - 100;
  EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
      .Times(1);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  vie_remb_->Process();
}

TEST_F(ViERembTest, VerifyIncreasingAndDecreasing) {
  MockRtpRtcp rtp_0;
  MockRtpRtcp rtp_1;
  vie_remb_->AddReceiveChannel(&rtp_0);
  vie_remb_->AddRembSender(&rtp_0);
  vie_remb_->AddReceiveChannel(&rtp_1);

  unsigned int bitrate_estimate[] = { 456, 789 };
  unsigned int ssrc[] = { 1234, 5678 };

  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate[0]);
  EXPECT_CALL(rtp_0, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[0]));
  EXPECT_CALL(rtp_1, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[1]));

  // Call process to get a first estimate.
  EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate[0], 2, _))
        .Times(1);
  TickTime::AdvanceFakeClock(1000);
  vie_remb_->Process();

  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate[1] + 100);
  EXPECT_CALL(rtp_0, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[0]));
  EXPECT_CALL(rtp_1, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[1]));

  // Lower the estimate to trigger a callback.
  EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate[1], 2, _))
      .Times(1);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate[1]);
  vie_remb_->Process();

  vie_remb_->RemoveReceiveChannel(&rtp_0);
  vie_remb_->RemoveRembSender(&rtp_0);
  vie_remb_->RemoveReceiveChannel(&rtp_1);
}

TEST_F(ViERembTest, NoRembForIncreasedBitrate) {
  MockRtpRtcp rtp_0;
  MockRtpRtcp rtp_1;
  vie_remb_->AddReceiveChannel(&rtp_0);
  vie_remb_->AddRembSender(&rtp_0);
  vie_remb_->AddReceiveChannel(&rtp_1);

  unsigned int bitrate_estimate = 456;
  unsigned int ssrc[] = { 1234, 5678 };

  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  EXPECT_CALL(rtp_0, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[0]));
  EXPECT_CALL(rtp_1, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[1]));

  // Trigger a first call to have a running state.
  TickTime::AdvanceFakeClock(1000);
  EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _))
      .Times(1);
  vie_remb_->Process();

  // Increased estimate shouldn't trigger a callback right away.
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate + 1);
  EXPECT_CALL(rtp_0, SetREMBData(_, _, _))
      .Times(0);

  // Decreasing the estimate less than 3% shouldn't trigger a new callback.
  int lower_estimate = bitrate_estimate * 98 / 100;
  vie_remb_->OnReceiveBitrateChanged(lower_estimate);
  EXPECT_CALL(rtp_0, SetREMBData(_, _, _))
      .Times(0);

  vie_remb_->Process();
  vie_remb_->RemoveReceiveChannel(&rtp_1);
  vie_remb_->RemoveReceiveChannel(&rtp_0);
  vie_remb_->RemoveRembSender(&rtp_0);
}

TEST_F(ViERembTest, ChangeSendRtpModule) {
  MockRtpRtcp rtp_0;
  MockRtpRtcp rtp_1;
  vie_remb_->AddReceiveChannel(&rtp_0);
  vie_remb_->AddRembSender(&rtp_0);
  vie_remb_->AddReceiveChannel(&rtp_1);

  unsigned int bitrate_estimate = 456;
  unsigned int ssrc[] = { 1234, 5678 };

  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  EXPECT_CALL(rtp_0, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[0]));
  EXPECT_CALL(rtp_1, RemoteSSRC())
      .Times(AnyNumber())
      .WillRepeatedly(Return(ssrc[1]));

  // Call process to get a first estimate.
  TickTime::AdvanceFakeClock(1000);
  EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _))
      .Times(1);
  vie_remb_->Process();

  // Decrease estimate to trigger a REMB.
  bitrate_estimate = bitrate_estimate - 100;
  EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate, 2, _))
      .Times(1);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  vie_remb_->Process();

  // Remove the sending module, add it again -> should get remb on the second
  // module.
  vie_remb_->RemoveRembSender(&rtp_0);
  vie_remb_->AddRembSender(&rtp_1);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);

  bitrate_estimate = bitrate_estimate - 100;
  EXPECT_CALL(rtp_1, SetREMBData(bitrate_estimate, 2, _))
        .Times(1);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  vie_remb_->Process();

  vie_remb_->RemoveReceiveChannel(&rtp_0);
  vie_remb_->RemoveReceiveChannel(&rtp_1);
}

TEST_F(ViERembTest, OnlyOneRembForDoubleProcess) {
  MockRtpRtcp rtp;
  unsigned int bitrate_estimate = 456;
  unsigned int ssrc = 1234;

  vie_remb_->AddReceiveChannel(&rtp);
  vie_remb_->AddRembSender(&rtp);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  EXPECT_CALL(rtp, RemoteSSRC())
      .WillRepeatedly(Return(ssrc));

  // Call process to get a first estimate.
  TickTime::AdvanceFakeClock(1000);
  EXPECT_CALL(rtp, SetREMBData(_, _, _))
        .Times(1);
  vie_remb_->Process();

  // Lower the estimate, should trigger a call to SetREMBData right away.
  bitrate_estimate = bitrate_estimate - 100;
  EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
      .Times(1);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  vie_remb_->Process();

  // Call Process again, this should not trigger a new callback.
  EXPECT_CALL(rtp, SetREMBData(_, _, _))
      .Times(0);
  vie_remb_->Process();
  vie_remb_->RemoveReceiveChannel(&rtp);
  vie_remb_->RemoveRembSender(&rtp);
}

TEST_F(ViERembTest, NoOnReceivedBitrateChangedCall) {
  MockRtpRtcp rtp;
  EXPECT_CALL(rtp, RemoteSSRC())
        .WillRepeatedly(Return(1234));

  vie_remb_->AddReceiveChannel(&rtp);
  vie_remb_->AddRembSender(&rtp);
  // TODO(mflodman) Add fake clock.
  TickTime::AdvanceFakeClock(1000);
  // No bitrate estimate given, no callback expected.
  EXPECT_CALL(rtp, SetREMBData(_, _, _))
      .Times(0);
  vie_remb_->Process();

  vie_remb_->RemoveReceiveChannel(&rtp);
  vie_remb_->RemoveRembSender(&rtp);
}

// Only register receiving modules and make sure we fallback to trigger a REMB
// packet on this one.
TEST_F(ViERembTest, NoSendingRtpModule) {
  MockRtpRtcp rtp;
  vie_remb_->AddReceiveChannel(&rtp);

  unsigned int bitrate_estimate = 456;
  unsigned int ssrc = 1234;

  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  EXPECT_CALL(rtp, RemoteSSRC())
      .WillRepeatedly(Return(ssrc));

  // Call process to get a first estimate.
  TickTime::AdvanceFakeClock(1000);
  EXPECT_CALL(rtp, SetREMBData(_, _, _))
      .Times(1);
  vie_remb_->Process();

  // Lower the estimate to trigger a new packet REMB packet.
  bitrate_estimate = bitrate_estimate - 100;
  EXPECT_CALL(rtp, SetREMBData(_, _, _))
      .Times(1);
  vie_remb_->OnReceiveBitrateChanged(bitrate_estimate);
  vie_remb_->Process();
}

}  // namespace webrtc
<|endoftext|>


<commit_before>/* Rapicorn - Experimental UI Toolkit
 * Copyright (C) 2007 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#include <rapicorn.hh>

namespace {
using namespace Rapicorn;

static void
help_usage (bool usage_error)
{
  const char *usage = "Usage: rapidrun [OPTIONS] <GuiFile.xml>";
  if (usage_error)
    {
      printerr ("%s\n", usage);
      printerr ("Try 'rapidrun --help' for more information.\n");
      exit (1);
    }
  printout ("%s\n", usage);
  /*         12345678901234567890123456789012345678901234567890123456789012345678901234567890 */
  printout ("Show Rapicorn dialogs defined in GuiFile.xml.\n");
  printout ("This tool will read the GUI description file listed on the command\n");
  printout ("line, look for a dialog named 'test-dialog' and show it.\n");
  printout ("\n");
  printout ("Options:\n");
  printout ("  --parse-test                  Parse GuiFile.xml and exit.\n");
  printout ("  -h, --help                    Display this help and exit.\n");
  printout ("  -v, --version                 Display version and exit.\n");
}

static bool parse_test = false;

static void
parse_args (int    *argc_p,
            char ***argv_p)
{
  char **argv = *argv_p;
  uint argc = *argc_p;

  for (uint i = 1; i < argc; i++)
    {
      if (strcmp (argv[i], "--parse-test") == 0)
        {
          parse_test = true;
          argv[i] = NULL;
        }
      else if (strcmp (argv[i], "--help") == 0 || strcmp (argv[i], "-h") == 0)
        {
          help_usage (false);
          exit (0);
        }
      else if (strcmp (argv[i], "--version") == 0 || strcmp (argv[i], "-v") == 0)
        {
          printout ("rapidrun (Rapicorn utilities) %s\n", RAPICORN_VERSION);
          printout ("Copyright (C) 2007 Tim Janik.\n");
          printout ("This is free software and comes with ABSOLUTELY NO WARRANTY; see\n");
          printout ("the source for copying conditions. Sources, examples and contact\n");
          printout ("information are available at http://rapicorn.org/.\n");
          exit (0);
        }
    }

  uint e = 1;
  for (uint i = 1; i < argc; i++)
    if (argv[i])
      {
        argv[e++] = argv[i];
        if (i >= e)
          argv[i] = NULL;
      }
  *argc_p = e;
}

extern "C" int
main (int   argc,
      char *argv[])
{
  /* initialize Rapicorn and its X11 (Gtk+) backend */
  Application::init_with_x11 (&argc, &argv, "Rapidrun"); // acquires Rapicorn mutex
  parse_args (&argc, &argv);
  if (argc != 2)
    help_usage (true);

  /* load GUI definition file, relative to argv[0] */
  Application::auto_load ("RapicornTest", argv[1], argv[0]);

  /* create root item */
  Window window = Application::create_window ("test-dialog");

  /* show window and process events */
  window.show();
  Application::execute_loops();

  return 0;
}

} // anon
<commit_msg>rapidrun.cc: load GUI definition files CWD relative.<commit_after>/* Rapicorn - Experimental UI Toolkit
 * Copyright (C) 2007 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#include <rapicorn.hh>

namespace {
using namespace Rapicorn;

static void
help_usage (bool usage_error)
{
  const char *usage = "Usage: rapidrun [OPTIONS] <GuiFile.xml>";
  if (usage_error)
    {
      printerr ("%s\n", usage);
      printerr ("Try 'rapidrun --help' for more information.\n");
      exit (1);
    }
  printout ("%s\n", usage);
  /*         12345678901234567890123456789012345678901234567890123456789012345678901234567890 */
  printout ("Show Rapicorn dialogs defined in GuiFile.xml.\n");
  printout ("This tool will read the GUI description file listed on the command\n");
  printout ("line, look for a dialog named 'test-dialog' and show it.\n");
  printout ("\n");
  printout ("Options:\n");
  printout ("  --parse-test                  Parse GuiFile.xml and exit.\n");
  printout ("  -h, --help                    Display this help and exit.\n");
  printout ("  -v, --version                 Display version and exit.\n");
}

static bool parse_test = false;

static void
parse_args (int    *argc_p,
            char ***argv_p)
{
  char **argv = *argv_p;
  uint argc = *argc_p;

  for (uint i = 1; i < argc; i++)
    {
      if (strcmp (argv[i], "--parse-test") == 0)
        {
          parse_test = true;
          argv[i] = NULL;
        }
      else if (strcmp (argv[i], "--help") == 0 || strcmp (argv[i], "-h") == 0)
        {
          help_usage (false);
          exit (0);
        }
      else if (strcmp (argv[i], "--version") == 0 || strcmp (argv[i], "-v") == 0)
        {
          printout ("rapidrun (Rapicorn utilities) %s\n", RAPICORN_VERSION);
          printout ("Copyright (C) 2007 Tim Janik.\n");
          printout ("This is free software and comes with ABSOLUTELY NO WARRANTY; see\n");
          printout ("the source for copying conditions. Sources, examples and contact\n");
          printout ("information are available at http://rapicorn.org/.\n");
          exit (0);
        }
    }

  uint e = 1;
  for (uint i = 1; i < argc; i++)
    if (argv[i])
      {
        argv[e++] = argv[i];
        if (i >= e)
          argv[i] = NULL;
      }
  *argc_p = e;
}

extern "C" int
main (int   argc,
      char *argv[])
{
  /* initialize Rapicorn and its X11 (Gtk+) backend */
  Application::init_with_x11 (&argc, &argv, "Rapidrun"); // acquires Rapicorn mutex
  parse_args (&argc, &argv);
  if (argc != 2)
    help_usage (true);

  /* load GUI definition file, relative to CWD */
  Application::auto_load ("RapicornTest", argv[1], ".");

  /* create root item */
  Window window = Application::create_window ("test-dialog");

  /* show window and process events */
  window.show();
  Application::execute_loops();

  return 0;
}

} // anon
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <assert.h>
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <numeric>
#include <algorithm>
#include <map>
#include <set>

#include <absl/strings/str_cat.h>
#include <gflags/gflags.h>
#include <prjxray/database.h>

DEFINE_int32(c, 4, "threshold under which candidates are output. set to -1 to output all.");
DEFINE_bool(i, false, "add inverted tags");
DEFINE_int32(m, 0, "min number of set/cleared samples each");
DEFINE_int32(M, 0, "min number of set/cleared samples total");
DEFINE_string(o, "", "set output file");
DEFINE_string(k, "", "set output mask file");
DEFINE_string(database_path, "", "path to root directory of a database");
DEFINE_bool(exclude_known, false, "exclude tags and bits recorded in the "
				  "database specified by --database");

using std::map;
using std::tuple;
using std::vector;
using std::string;

int num_bits = 0, num_tags = 0;
map<string, int> bit_ids, tag_ids;
vector<string> bit_ids_r, tag_ids_r;

#if 0
struct bool_vec
{
	vector<bool> data;

	bool_vec(int n = 0, bool initval = false) : data(n, initval)
	{
	}

	void set(int n)
	{
		if (int(data.size()) <= n)
			data.resize(n+1);
		data[n] = true;
	}

	bool get(int n)
	{
		return data.at(n);
	}

	void resize(int n)
	{
		data.resize(n);
	}

	int count()
	{
		return std::accumulate(data.begin(), data.end(), 0);
	}

	void apply_and(const bool_vec &other)
	{
		assert(data.size() == other.data.size());
		for (int i = 0; i < int(data.size()); i++)
			data[i] = data[i] && other.data[i];
	}

	void apply_andc(const bool_vec &other)
	{
		assert(data.size() == other.data.size());
		for (int i = 0; i < int(data.size()); i++)
			data[i] = data[i] && !other.data[i];
	}
};
#else
struct bool_vec
{
	vector<uint64_t> data;

	bool_vec(int n = 0, bool initval = false) :
		data((n+63)/64, initval ? ~uint64_t(0) : uint64_t(0))
	{
		for (int i = data.size()*64-1; i >= n; i--)
			data[n / 64] &= ~(uint64_t(1) << (n % 64));
	}

	void set(int n)
	{
		if (int(data.size()*64) <= n)
			data.resize((n+64) / 64);
		data[n / 64] |= uint64_t(1) << (n % 64);
	}

	bool get(int n)
	{
		return (data[n / 64] >> (n % 64)) & 1;
	}

	void resize(int n)
	{
		data.resize((n+63) / 64);
	}

	int count()
	{
		int sum = 0;
		for (int i = 0; i < 64*int(data.size()); i++)
			if (get(i)) sum++;
		return sum;
	}

	void apply_and(const bool_vec &other)
	{
		assert(data.size() == other.data.size());
		for (int i = 0; i < int(data.size()); i++)
			data[i] &= other.data[i];
	}

	void apply_andc(const bool_vec &other)
	{
		assert(data.size() == other.data.size());
		for (int i = 0; i < int(data.size()); i++)
			data[i] &= ~other.data[i];
	}
};
#endif

// segname -> bits, tags_on, tags_off
typedef tuple<bool_vec, bool_vec, bool_vec> segdata_t;
map<string, segdata_t> segdata;

map<string, int> segnamecnt;

static inline bool_vec &segdata_bits(segdata_t &sd) { return std::get<0>(sd); }
static inline bool_vec &segdata_tags1(segdata_t &sd) { return std::get<1>(sd); }
static inline bool_vec &segdata_tags0(segdata_t &sd) { return std::get<2>(sd); }

std::set<std::string> exclude_tags;
std::set<std::string> exclude_bits;

void read_input(std::istream &f, std::string filename)
{
	string token;
	segdata_t *segptr = nullptr;

	while (f >> token)
	{
		if (token == "seg")
		{
			f >> token;
			token = filename + ":" + token;
			while (segdata.count(token)) {
				int idx = 1;
				if (segnamecnt.count(token))
					idx = segnamecnt.at(token);
				segnamecnt[token] = idx + 1;
				char buffer[64];
				snprintf(buffer, 64, "-%d", idx);
				token += buffer;
			}
			segptr = &segdata[token];
			continue;
		}

		if (token == "bit")
		{
			assert(segptr != nullptr);

			f >> token;

			if (exclude_bits.find(token) != exclude_bits.end())
				continue;

			if (bit_ids.count(token) == 0) {
				bit_ids[token] = num_bits++;
				bit_ids_r.push_back(token);
			}

			int bit_idx = bit_ids.at(token);
			auto &bits = segdata_bits(*segptr);

			bits.set(bit_idx);
			continue;
		}

		if (token == "tag")
		{
			assert(segptr != nullptr);

			f >> token;

			if (exclude_tags.find(token) != exclude_tags.end()) {
				// Consume the rest of the line.
				f >> token;
				continue;
			}

			if (tag_ids.count(token) == 0) {
				tag_ids[token] = num_tags++;
				tag_ids_r.push_back(token);
			}

			int tag_idx = tag_ids.at(token);

			f >> token;
			assert(token == "0" || token == "1");

			auto &tags = token == "1" ? segdata_tags1(*segptr) : segdata_tags0(*segptr);

			tags.set(tag_idx);

			if (FLAGS_i)
			{
				auto &inv_tags = token == "1" ? segdata_tags0(*segptr) : segdata_tags1(*segptr);

				token = tag_ids_r.at(tag_idx) + "__INV";

				if (tag_ids.count(token) == 0) {
					tag_ids[token] = num_tags++;
					tag_ids_r.push_back(token);
				}

				int inv_tag_idx = tag_ids.at(token);
				inv_tags.set(inv_tag_idx);
			}

			continue;
		}

		abort();
	}

	// printf("Number of segments: %d\n", int(segdata.size()));
	// printf("Number of bits: %d\n", num_bits);
	// printf("Number of tags: %d\n", num_tags);

	for (auto &segdat : segdata) {
		segdata_bits(segdat.second).resize(num_bits);
		segdata_tags1(segdat.second).resize(num_tags);
		segdata_tags0(segdat.second).resize(num_tags);
	}
}

int main(int argc, char **argv)
{
	gflags::SetUsageMessage(
			absl::StrCat("Usage: ", argv[0], " [options] file.."));
	gflags::ParseCommandLineFlags(&argc, &argv, true);

	if (!FLAGS_database_path.empty()) {
		prjxray::Database database(FLAGS_database_path);

		if (FLAGS_exclude_known) {
			for (auto& segbits : database.segbits()) {
				for (auto tag_bit : *segbits) {
					exclude_tags.emplace(tag_bit.tag());
					exclude_bits.emplace(tag_bit.bit());
				}
			}
		}
	}

	if (argc > 1) {
		for (int optind = 1; optind < argc; optind++) {
			printf("Reading %s.\n", argv[optind]);
			std::ifstream f;
			f.open(argv[optind]);
			assert(!f.fail());
			read_input(f, argv[optind]);
		}
	} else {
		printf("Reading from stding.\n");
		read_input(std::cin, "stdin");
	}

	printf("#of segments: %d\n", int(segdata.size()));
	printf("#of bits: %d\n", num_bits);
	printf("#of tags: %d\n", num_tags);

	FILE *f = stdout;

	if (!FLAGS_o.empty()) {
		f = fopen(FLAGS_o.c_str(), "w");
		assert(f != nullptr);
	}

	int cnt_const0 = 0;
	int cnt_const1 = 0;
	int cnt_candidates = 0;
	int min_candidates = num_bits;
	int max_candidates = 0;
	float avg_candidates = 0;

	std::vector<std::string> out_lines;

	for (int tag_idx = 0; tag_idx < num_tags; tag_idx++)
	{
		bool_vec mask(num_bits, true);
		int count1 = 0, count0 = 0;

		for (auto &segdat : segdata)
		{
			auto &sd = segdat.second;
			bool tag1 = segdata_tags1(sd).get(tag_idx);
			bool tag0 = segdata_tags0(sd).get(tag_idx);

			assert(!tag1 || !tag0);

			if (tag1) {
				count1++;
				mask.apply_and(segdata_bits(sd));
				continue;
			}

			if (tag0) {
				count0++;
				mask.apply_andc(segdata_bits(sd));
				continue;
			}
		}

		assert(count1 || count0);

		std::string out_line = tag_ids_r.at(tag_idx);

		if (count1 < FLAGS_m) {
			char buffer[64];
			snprintf(buffer, 64, " <m1 %d>", count1);
			out_line += buffer;
		}

		if (count0 < FLAGS_m) {
			char buffer[64];
			snprintf(buffer, 64, " <m0 %d>", count0);
			out_line += buffer;
		}

		if (count1 + count0 < FLAGS_M) {
			char buffer[64];
			snprintf(buffer, 64, " <M %d %d>", count1, count0);
			out_line += buffer;
		}

		if (!count1) {
			out_lines.push_back(out_line + " <const0>");
			cnt_const0 += 1;
			continue;
		}

		if (!count0) {
			out_line += " <const1>";
			cnt_const1 += 1;
		}

		int num_candidates = mask.count();

		if (count0) {
			min_candidates = std::min(min_candidates, num_candidates);
			max_candidates = std::max(max_candidates, num_candidates);
			avg_candidates += num_candidates;
			cnt_candidates += 1;
		}

		if (FLAGS_c < 0 ||
		    (0 < num_candidates &&
		     num_candidates <= FLAGS_c)) {
			std::vector<std::string> out_tags;
			for (int bit_idx = 0; bit_idx < num_bits; bit_idx++)
				if (mask.get(bit_idx))
					out_tags.push_back(bit_ids_r.at(bit_idx));
			std::sort(out_tags.begin(), out_tags.end());
			for (auto &tag : out_tags)
				out_line += " " + tag;
		} else {
			char buffer[64];
			snprintf(buffer, 64, " <%d candidates>", num_candidates);
			out_line += buffer;
		}

		out_lines.push_back(out_line);
	}

	std::sort(out_lines.begin(), out_lines.end());

	for (auto &line : out_lines)
		fprintf(f, "%s\n", line.c_str());

	if (cnt_candidates)
		avg_candidates /= cnt_candidates;

	printf("#of const0 tags: %d\n", cnt_const0);
	printf("#of const1 tags: %d\n", cnt_const1);

	if (cnt_candidates) {
		printf("min #of candidates: %d\n", min_candidates);
		printf("max #of candidates: %d\n", max_candidates);
		printf("avg #of candidates: %.3f\n", avg_candidates);
	}

	if (!FLAGS_k.empty()) {
		f = fopen(FLAGS_k.c_str(), "w");
		assert(f != nullptr);
		std::sort(bit_ids_r.begin(), bit_ids_r.end());
		for (auto bit : bit_ids_r)
			fprintf(f, "bit %s\n", bit.c_str());
	}

	return 0;
}

<commit_msg>Revert "segmath: fixup inverted logic for --exclude_known"<commit_after>#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <assert.h>
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <numeric>
#include <algorithm>
#include <map>
#include <set>

#include <absl/strings/str_cat.h>
#include <gflags/gflags.h>
#include <prjxray/database.h>

DEFINE_int32(c, 4, "threshold under which candidates are output. set to -1 to output all.");
DEFINE_bool(i, false, "add inverted tags");
DEFINE_int32(m, 0, "min number of set/cleared samples each");
DEFINE_int32(M, 0, "min number of set/cleared samples total");
DEFINE_string(o, "", "set output file");
DEFINE_string(k, "", "set output mask file");
DEFINE_string(database_path, "", "path to root directory of a database");
DEFINE_bool(exclude_known, false, "exclude tags and bits recorded in the "
				  "database specified by --database");

using std::map;
using std::tuple;
using std::vector;
using std::string;

int num_bits = 0, num_tags = 0;
map<string, int> bit_ids, tag_ids;
vector<string> bit_ids_r, tag_ids_r;

#if 0
struct bool_vec
{
	vector<bool> data;

	bool_vec(int n = 0, bool initval = false) : data(n, initval)
	{
	}

	void set(int n)
	{
		if (int(data.size()) <= n)
			data.resize(n+1);
		data[n] = true;
	}

	bool get(int n)
	{
		return data.at(n);
	}

	void resize(int n)
	{
		data.resize(n);
	}

	int count()
	{
		return std::accumulate(data.begin(), data.end(), 0);
	}

	void apply_and(const bool_vec &other)
	{
		assert(data.size() == other.data.size());
		for (int i = 0; i < int(data.size()); i++)
			data[i] = data[i] && other.data[i];
	}

	void apply_andc(const bool_vec &other)
	{
		assert(data.size() == other.data.size());
		for (int i = 0; i < int(data.size()); i++)
			data[i] = data[i] && !other.data[i];
	}
};
#else
struct bool_vec
{
	vector<uint64_t> data;

	bool_vec(int n = 0, bool initval = false) :
		data((n+63)/64, initval ? ~uint64_t(0) : uint64_t(0))
	{
		for (int i = data.size()*64-1; i >= n; i--)
			data[n / 64] &= ~(uint64_t(1) << (n % 64));
	}

	void set(int n)
	{
		if (int(data.size()*64) <= n)
			data.resize((n+64) / 64);
		data[n / 64] |= uint64_t(1) << (n % 64);
	}

	bool get(int n)
	{
		return (data[n / 64] >> (n % 64)) & 1;
	}

	void resize(int n)
	{
		data.resize((n+63) / 64);
	}

	int count()
	{
		int sum = 0;
		for (int i = 0; i < 64*int(data.size()); i++)
			if (get(i)) sum++;
		return sum;
	}

	void apply_and(const bool_vec &other)
	{
		assert(data.size() == other.data.size());
		for (int i = 0; i < int(data.size()); i++)
			data[i] &= other.data[i];
	}

	void apply_andc(const bool_vec &other)
	{
		assert(data.size() == other.data.size());
		for (int i = 0; i < int(data.size()); i++)
			data[i] &= ~other.data[i];
	}
};
#endif

// segname -> bits, tags_on, tags_off
typedef tuple<bool_vec, bool_vec, bool_vec> segdata_t;
map<string, segdata_t> segdata;

map<string, int> segnamecnt;

static inline bool_vec &segdata_bits(segdata_t &sd) { return std::get<0>(sd); }
static inline bool_vec &segdata_tags1(segdata_t &sd) { return std::get<1>(sd); }
static inline bool_vec &segdata_tags0(segdata_t &sd) { return std::get<2>(sd); }

std::set<std::string> exclude_tags;
std::set<std::string> exclude_bits;

void read_input(std::istream &f, std::string filename)
{
	string token;
	segdata_t *segptr = nullptr;

	while (f >> token)
	{
		if (token == "seg")
		{
			f >> token;
			token = filename + ":" + token;
			while (segdata.count(token)) {
				int idx = 1;
				if (segnamecnt.count(token))
					idx = segnamecnt.at(token);
				segnamecnt[token] = idx + 1;
				char buffer[64];
				snprintf(buffer, 64, "-%d", idx);
				token += buffer;
			}
			segptr = &segdata[token];
			continue;
		}

		if (token == "bit")
		{
			assert(segptr != nullptr);

			f >> token;

			if (exclude_bits.find(token) == exclude_bits.end())
				continue;

			if (bit_ids.count(token) == 0) {
				bit_ids[token] = num_bits++;
				bit_ids_r.push_back(token);
			}

			int bit_idx = bit_ids.at(token);
			auto &bits = segdata_bits(*segptr);

			bits.set(bit_idx);
			continue;
		}

		if (token == "tag")
		{
			assert(segptr != nullptr);

			f >> token;

			if (exclude_tags.find(token) == exclude_tags.end()) {
				// Consume the rest of the line.
				f >> token;
				continue;
			}

			if (tag_ids.count(token) == 0) {
				tag_ids[token] = num_tags++;
				tag_ids_r.push_back(token);
			}

			int tag_idx = tag_ids.at(token);

			f >> token;
			assert(token == "0" || token == "1");

			auto &tags = token == "1" ? segdata_tags1(*segptr) : segdata_tags0(*segptr);

			tags.set(tag_idx);

			if (FLAGS_i)
			{
				auto &inv_tags = token == "1" ? segdata_tags0(*segptr) : segdata_tags1(*segptr);

				token = tag_ids_r.at(tag_idx) + "__INV";

				if (tag_ids.count(token) == 0) {
					tag_ids[token] = num_tags++;
					tag_ids_r.push_back(token);
				}

				int inv_tag_idx = tag_ids.at(token);
				inv_tags.set(inv_tag_idx);
			}

			continue;
		}

		abort();
	}

	// printf("Number of segments: %d\n", int(segdata.size()));
	// printf("Number of bits: %d\n", num_bits);
	// printf("Number of tags: %d\n", num_tags);

	for (auto &segdat : segdata) {
		segdata_bits(segdat.second).resize(num_bits);
		segdata_tags1(segdat.second).resize(num_tags);
		segdata_tags0(segdat.second).resize(num_tags);
	}
}

int main(int argc, char **argv)
{
	gflags::SetUsageMessage(
			absl::StrCat("Usage: ", argv[0], " [options] file.."));
	gflags::ParseCommandLineFlags(&argc, &argv, true);

	if (!FLAGS_database_path.empty()) {
		prjxray::Database database(FLAGS_database_path);

		if (FLAGS_exclude_known) {
			for (auto& segbits : database.segbits()) {
				for (auto tag_bit : *segbits) {
					exclude_tags.emplace(tag_bit.tag());
					exclude_bits.emplace(tag_bit.bit());
				}
			}
		}
	}

	if (argc > 1) {
		for (int optind = 1; optind < argc; optind++) {
			printf("Reading %s.\n", argv[optind]);
			std::ifstream f;
			f.open(argv[optind]);
			assert(!f.fail());
			read_input(f, argv[optind]);
		}
	} else {
		printf("Reading from stding.\n");
		read_input(std::cin, "stdin");
	}

	printf("#of segments: %d\n", int(segdata.size()));
	printf("#of bits: %d\n", num_bits);
	printf("#of tags: %d\n", num_tags);

	FILE *f = stdout;

	if (!FLAGS_o.empty()) {
		f = fopen(FLAGS_o.c_str(), "w");
		assert(f != nullptr);
	}

	int cnt_const0 = 0;
	int cnt_const1 = 0;
	int cnt_candidates = 0;
	int min_candidates = num_bits;
	int max_candidates = 0;
	float avg_candidates = 0;

	std::vector<std::string> out_lines;

	for (int tag_idx = 0; tag_idx < num_tags; tag_idx++)
	{
		bool_vec mask(num_bits, true);
		int count1 = 0, count0 = 0;

		for (auto &segdat : segdata)
		{
			auto &sd = segdat.second;
			bool tag1 = segdata_tags1(sd).get(tag_idx);
			bool tag0 = segdata_tags0(sd).get(tag_idx);

			assert(!tag1 || !tag0);

			if (tag1) {
				count1++;
				mask.apply_and(segdata_bits(sd));
				continue;
			}

			if (tag0) {
				count0++;
				mask.apply_andc(segdata_bits(sd));
				continue;
			}
		}

		assert(count1 || count0);

		std::string out_line = tag_ids_r.at(tag_idx);

		if (count1 < FLAGS_m) {
			char buffer[64];
			snprintf(buffer, 64, " <m1 %d>", count1);
			out_line += buffer;
		}

		if (count0 < FLAGS_m) {
			char buffer[64];
			snprintf(buffer, 64, " <m0 %d>", count0);
			out_line += buffer;
		}

		if (count1 + count0 < FLAGS_M) {
			char buffer[64];
			snprintf(buffer, 64, " <M %d %d>", count1, count0);
			out_line += buffer;
		}

		if (!count1) {
			out_lines.push_back(out_line + " <const0>");
			cnt_const0 += 1;
			continue;
		}

		if (!count0) {
			out_line += " <const1>";
			cnt_const1 += 1;
		}

		int num_candidates = mask.count();

		if (count0) {
			min_candidates = std::min(min_candidates, num_candidates);
			max_candidates = std::max(max_candidates, num_candidates);
			avg_candidates += num_candidates;
			cnt_candidates += 1;
		}

		if (FLAGS_c < 0 ||
		    (0 < num_candidates &&
		     num_candidates <= FLAGS_c)) {
			std::vector<std::string> out_tags;
			for (int bit_idx = 0; bit_idx < num_bits; bit_idx++)
				if (mask.get(bit_idx))
					out_tags.push_back(bit_ids_r.at(bit_idx));
			std::sort(out_tags.begin(), out_tags.end());
			for (auto &tag : out_tags)
				out_line += " " + tag;
		} else {
			char buffer[64];
			snprintf(buffer, 64, " <%d candidates>", num_candidates);
			out_line += buffer;
		}

		out_lines.push_back(out_line);
	}

	std::sort(out_lines.begin(), out_lines.end());

	for (auto &line : out_lines)
		fprintf(f, "%s\n", line.c_str());

	if (cnt_candidates)
		avg_candidates /= cnt_candidates;

	printf("#of const0 tags: %d\n", cnt_const0);
	printf("#of const1 tags: %d\n", cnt_const1);

	if (cnt_candidates) {
		printf("min #of candidates: %d\n", min_candidates);
		printf("max #of candidates: %d\n", max_candidates);
		printf("avg #of candidates: %.3f\n", avg_candidates);
	}

	if (!FLAGS_k.empty()) {
		f = fopen(FLAGS_k.c_str(), "w");
		assert(f != nullptr);
		std::sort(bit_ids_r.begin(), bit_ids_r.end());
		for (auto bit : bit_ids_r)
			fprintf(f, "bit %s\n", bit.c_str());
	}

	return 0;
}

<|endoftext|>


<commit_before>#include <utility>
#include <vector>
#include <gtest/gtest.h>
#include <entt/signal/sigh.hpp>

struct sigh_listener {
    static void f(int &v) { v = 42; }

    bool g(int) { k = !k; return true; }
    bool h(const int &) { return k; }

    void i() {}
    // useless definition just because msvc does weird things if both are empty
    void l() { k = k ? true : false; }

    bool k{false};
};

template<typename Ret>
struct test_collect_all {
    std::vector<Ret> vec{};
    static int f() { return 42; }
    static int g() { return 3; }
    bool operator()(Ret r) noexcept {
        vec.push_back(r);
        return true;
    }
};

template<>
struct test_collect_all<void> {
    std::vector<int> vec{};
    static void h(const void *) {}
    bool operator()() noexcept {
        return true;
    }
};

template<typename Ret>
struct test_collect_first {
    std::vector<Ret> vec{};
    static int f(const void *) { return 42; }
    bool operator()(Ret r) noexcept {
        vec.push_back(r);
        return false;
    }
};

struct const_nonconst_noexcept {
    void f() { ++cnt; }
    void g() noexcept { ++cnt; }
    void h() const { ++cnt; }
    void i() const noexcept { ++cnt; }
    mutable int cnt{0};
};

TEST(SigH, Lifetime) {
    using signal = entt::sigh<void(void)>;

    ASSERT_NO_THROW(signal{});

    signal src{}, other{};

    ASSERT_NO_THROW(signal{src});
    ASSERT_NO_THROW(signal{std::move(other)});
    ASSERT_NO_THROW(src = other);
    ASSERT_NO_THROW(src = std::move(other));

    ASSERT_NO_THROW(delete new signal{});
}

TEST(SigH, Clear) {
    entt::sigh<void(int &)> sigh;
    sigh.sink().connect<&sigh_listener::f>();

    ASSERT_FALSE(sigh.empty());

    sigh.sink().disconnect();

    ASSERT_TRUE(sigh.empty());
}

TEST(SigH, Swap) {
    entt::sigh<void(int &)> sigh1;
    entt::sigh<void(int &)> sigh2;

    sigh1.sink().connect<&sigh_listener::f>();

    ASSERT_FALSE(sigh1.empty());
    ASSERT_TRUE(sigh2.empty());

    std::swap(sigh1, sigh2);

    ASSERT_TRUE(sigh1.empty());
    ASSERT_FALSE(sigh2.empty());
}

TEST(SigH, Functions) {
    entt::sigh<void(int &)> sigh;
    int v = 0;

    sigh.sink().connect<&sigh_listener::f>();
    sigh.publish(v);

    ASSERT_FALSE(sigh.empty());
    ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(1), sigh.size());
    ASSERT_EQ(42, v);

    v = 0;
    sigh.sink().disconnect<&sigh_listener::f>();
    sigh.publish(v);

    ASSERT_TRUE(sigh.empty());
    ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(0), sigh.size());
    ASSERT_EQ(v, 0);

    sigh.sink().connect<&sigh_listener::f>();
}

TEST(SigH, Members) {
    sigh_listener s;
    sigh_listener *ptr = &s;
    entt::sigh<bool(int)> sigh;

    sigh.sink().connect<&sigh_listener::g>(ptr);
    sigh.publish(42);

    ASSERT_TRUE(s.k);
    ASSERT_FALSE(sigh.empty());
    ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(1), sigh.size());

    sigh.sink().disconnect<&sigh_listener::g>(ptr);
    sigh.publish(42);

    ASSERT_TRUE(s.k);
    ASSERT_TRUE(sigh.empty());
    ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(0), sigh.size());

    sigh.sink().connect<&sigh_listener::g>(ptr);
    sigh.sink().connect<&sigh_listener::h>(ptr);

    ASSERT_FALSE(sigh.empty());
    ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(2), sigh.size());

    sigh.sink().disconnect<&sigh_listener::g>(ptr);
    sigh.sink().disconnect<&sigh_listener::h>(ptr);

    ASSERT_TRUE(sigh.empty());
    ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(0), sigh.size());
}

TEST(SigH, Collector) {
    entt::sigh<void(), test_collect_all<void>> sigh_void;
    const void *fake_instance = nullptr;

    sigh_void.sink().connect<&test_collect_all<void>::h>(fake_instance);
    auto collector_void = sigh_void.collect();

    ASSERT_FALSE(sigh_void.empty());
    ASSERT_TRUE(collector_void.vec.empty());

    entt::sigh<int(), test_collect_all<int>> sigh_all;

    sigh_all.sink().connect<&test_collect_all<int>::f>();
    sigh_all.sink().connect<&test_collect_all<int>::f>();
    sigh_all.sink().connect<&test_collect_all<int>::g>();
    auto collector_all = sigh_all.collect();

    ASSERT_FALSE(sigh_all.empty());
    ASSERT_FALSE(collector_all.vec.empty());
    ASSERT_EQ(static_cast<std::vector<int>::size_type>(2), collector_all.vec.size());
    ASSERT_EQ(42, collector_all.vec[0]);
    ASSERT_EQ(3, collector_all.vec[1]);

    entt::sigh<int(), test_collect_first<int>> sigh_first;

    sigh_first.sink().connect<&test_collect_first<int>::f>(fake_instance);
    sigh_first.sink().connect<&test_collect_first<int>::f>(fake_instance);
    auto collector_first = sigh_first.collect();

    ASSERT_FALSE(sigh_first.empty());
    ASSERT_FALSE(collector_first.vec.empty());
    ASSERT_EQ(static_cast<std::vector<int>::size_type>(1), collector_first.vec.size());
    ASSERT_EQ(42, collector_first.vec[0]);
}

TEST(SigH, ConstNonConstNoExcept) {
    entt::sigh<void()> sigh;
    const_nonconst_noexcept functor;
    const const_nonconst_noexcept cfunctor;

    sigh.sink().connect<&const_nonconst_noexcept::f>(&functor);
    sigh.sink().connect<&const_nonconst_noexcept::g>(&functor);
    sigh.sink().connect<&const_nonconst_noexcept::h>(&cfunctor);
    sigh.sink().connect<&const_nonconst_noexcept::i>(&cfunctor);
    sigh.publish();

    ASSERT_EQ(functor.cnt, 2);
    ASSERT_EQ(cfunctor.cnt, 2);

    sigh.sink().disconnect<&const_nonconst_noexcept::f>(&functor);
    sigh.sink().disconnect<&const_nonconst_noexcept::g>(&functor);
    sigh.sink().disconnect<&const_nonconst_noexcept::h>(&cfunctor);
    sigh.sink().disconnect<&const_nonconst_noexcept::i>(&cfunctor);
    sigh.publish();

    ASSERT_EQ(functor.cnt, 2);
    ASSERT_EQ(cfunctor.cnt, 2);
}
<commit_msg>sigh: more tests<commit_after>#include <utility>
#include <vector>
#include <gtest/gtest.h>
#include <entt/signal/sigh.hpp>

struct sigh_listener {
    static void f(int &v) { v = 42; }

    bool g(int) { k = !k; return true; }
    bool h(const int &) { return k; }

    void i() {}
    // useless definition just because msvc does weird things if both are empty
    void l() { k = k ? true : false; }

    bool k{false};
};

template<typename Ret>
struct test_collect_all {
    std::vector<Ret> vec{};
    static int f() { return 42; }
    static int g() { return 3; }
    bool operator()(Ret r) noexcept {
        vec.push_back(r);
        return true;
    }
};

template<>
struct test_collect_all<void> {
    std::vector<int> vec{};
    static void h(const void *) {}
    bool operator()() noexcept {
        return true;
    }
};

template<typename Ret>
struct test_collect_first {
    std::vector<Ret> vec{};
    static int f(const void *) { return 42; }
    bool operator()(Ret r) noexcept {
        vec.push_back(r);
        return false;
    }
};

struct const_nonconst_noexcept {
    void f() { ++cnt; }
    void g() noexcept { ++cnt; }
    void h() const { ++cnt; }
    void i() const noexcept { ++cnt; }
    mutable int cnt{0};
};

TEST(SigH, Lifetime) {
    using signal = entt::sigh<void(void)>;

    ASSERT_NO_THROW(signal{});

    signal src{}, other{};

    ASSERT_NO_THROW(signal{src});
    ASSERT_NO_THROW(signal{std::move(other)});
    ASSERT_NO_THROW(src = other);
    ASSERT_NO_THROW(src = std::move(other));

    ASSERT_NO_THROW(delete new signal{});
}

TEST(SigH, Clear) {
    entt::sigh<void(int &)> sigh;
    sigh.sink().connect<&sigh_listener::f>();

    ASSERT_FALSE(sigh.sink().empty());
    ASSERT_FALSE(sigh.empty());

    sigh.sink().disconnect();

    ASSERT_TRUE(sigh.sink().empty());
    ASSERT_TRUE(sigh.empty());
}

TEST(SigH, Swap) {
    entt::sigh<void(int &)> sigh1;
    entt::sigh<void(int &)> sigh2;

    sigh1.sink().connect<&sigh_listener::f>();

    ASSERT_FALSE(sigh1.sink().empty());
    ASSERT_TRUE(sigh2.sink().empty());

    ASSERT_FALSE(sigh1.empty());
    ASSERT_TRUE(sigh2.empty());

    std::swap(sigh1, sigh2);

    ASSERT_TRUE(sigh1.sink().empty());
    ASSERT_FALSE(sigh2.sink().empty());

    ASSERT_TRUE(sigh1.empty());
    ASSERT_FALSE(sigh2.empty());
}

TEST(SigH, Functions) {
    entt::sigh<void(int &)> sigh;
    int v = 0;

    sigh.sink().connect<&sigh_listener::f>();
    sigh.publish(v);

    ASSERT_FALSE(sigh.empty());
    ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(1), sigh.size());
    ASSERT_EQ(42, v);

    v = 0;
    sigh.sink().disconnect<&sigh_listener::f>();
    sigh.publish(v);

    ASSERT_TRUE(sigh.empty());
    ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(0), sigh.size());
    ASSERT_EQ(v, 0);

    sigh.sink().connect<&sigh_listener::f>();
}

TEST(SigH, Members) {
    sigh_listener s;
    sigh_listener *ptr = &s;
    entt::sigh<bool(int)> sigh;

    sigh.sink().connect<&sigh_listener::g>(ptr);
    sigh.publish(42);

    ASSERT_TRUE(s.k);
    ASSERT_FALSE(sigh.empty());
    ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(1), sigh.size());

    sigh.sink().disconnect<&sigh_listener::g>(ptr);
    sigh.publish(42);

    ASSERT_TRUE(s.k);
    ASSERT_TRUE(sigh.empty());
    ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(0), sigh.size());

    sigh.sink().connect<&sigh_listener::g>(ptr);
    sigh.sink().connect<&sigh_listener::h>(ptr);

    ASSERT_FALSE(sigh.empty());
    ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(2), sigh.size());

    sigh.sink().disconnect<&sigh_listener::g>(ptr);
    sigh.sink().disconnect<&sigh_listener::h>(ptr);

    ASSERT_TRUE(sigh.empty());
    ASSERT_EQ(static_cast<entt::sigh<bool(int)>::size_type>(0), sigh.size());
}

TEST(SigH, Collector) {
    entt::sigh<void(), test_collect_all<void>> sigh_void;
    const void *fake_instance = nullptr;

    sigh_void.sink().connect<&test_collect_all<void>::h>(fake_instance);
    auto collector_void = sigh_void.collect();

    ASSERT_FALSE(sigh_void.empty());
    ASSERT_TRUE(collector_void.vec.empty());

    entt::sigh<int(), test_collect_all<int>> sigh_all;

    sigh_all.sink().connect<&test_collect_all<int>::f>();
    sigh_all.sink().connect<&test_collect_all<int>::f>();
    sigh_all.sink().connect<&test_collect_all<int>::g>();
    auto collector_all = sigh_all.collect();

    ASSERT_FALSE(sigh_all.empty());
    ASSERT_FALSE(collector_all.vec.empty());
    ASSERT_EQ(static_cast<std::vector<int>::size_type>(2), collector_all.vec.size());
    ASSERT_EQ(42, collector_all.vec[0]);
    ASSERT_EQ(3, collector_all.vec[1]);

    entt::sigh<int(), test_collect_first<int>> sigh_first;

    sigh_first.sink().connect<&test_collect_first<int>::f>(fake_instance);
    sigh_first.sink().connect<&test_collect_first<int>::f>(fake_instance);
    auto collector_first = sigh_first.collect();

    ASSERT_FALSE(sigh_first.empty());
    ASSERT_FALSE(collector_first.vec.empty());
    ASSERT_EQ(static_cast<std::vector<int>::size_type>(1), collector_first.vec.size());
    ASSERT_EQ(42, collector_first.vec[0]);
}

TEST(SigH, ConstNonConstNoExcept) {
    entt::sigh<void()> sigh;
    const_nonconst_noexcept functor;
    const const_nonconst_noexcept cfunctor;

    sigh.sink().connect<&const_nonconst_noexcept::f>(&functor);
    sigh.sink().connect<&const_nonconst_noexcept::g>(&functor);
    sigh.sink().connect<&const_nonconst_noexcept::h>(&cfunctor);
    sigh.sink().connect<&const_nonconst_noexcept::i>(&cfunctor);
    sigh.publish();

    ASSERT_EQ(functor.cnt, 2);
    ASSERT_EQ(cfunctor.cnt, 2);

    sigh.sink().disconnect<&const_nonconst_noexcept::f>(&functor);
    sigh.sink().disconnect<&const_nonconst_noexcept::g>(&functor);
    sigh.sink().disconnect<&const_nonconst_noexcept::h>(&cfunctor);
    sigh.sink().disconnect<&const_nonconst_noexcept::i>(&cfunctor);
    sigh.publish();

    ASSERT_EQ(functor.cnt, 2);
    ASSERT_EQ(cfunctor.cnt, 2);
}
<|endoftext|>


<commit_before>// Copyright © 2010-2015 The CefSharp 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 "Stdafx.h"
#include "CefRequestWrapper.h"
#include "CefPostDataWrapper.h"

using namespace System::Text;

namespace CefSharp
{
    namespace Internals
    {
        String^ CefRequestWrapper::Url::get()
        {
            return StringUtils::ToClr(_wrappedRequest->GetURL());
        }

        void CefRequestWrapper::Url::set(String^ url)
        {
            if (url == nullptr)
            {
                throw gcnew System::ArgumentException("cannot be null", "url");
            }

            CefString str = StringUtils::ToNative(url);
            _wrappedRequest->SetURL(str);
        }

        String^ CefRequestWrapper::Method::get()
        {
            return StringUtils::ToClr(_wrappedRequest->GetMethod());
        }

        NameValueCollection^ CefRequestWrapper::Headers::get()
        {
            CefRequest::HeaderMap hm;
            _wrappedRequest->GetHeaderMap(hm);

            NameValueCollection^ headers = gcnew NameValueCollection();

            for (CefRequest::HeaderMap::iterator it = hm.begin(); it != hm.end(); ++it)
            {
                String^ name = StringUtils::ToClr(it->first);
                String^ value = StringUtils::ToClr(it->second);
                headers->Add(name, value);
            }

            return headers;
        }

        void CefRequestWrapper::Headers::set(NameValueCollection^ headers)
        {
            CefRequest::HeaderMap hm;

            for each(String^ key in headers)
            {
                CefString name = StringUtils::ToNative(key);
                for each(String^ element in headers->GetValues(key))
                {
                    CefString value = StringUtils::ToNative(element);
                    hm.insert(std::make_pair(name, value));
                }
            }

            _wrappedRequest->SetHeaderMap(hm);
        }

        TransitionType CefRequestWrapper::TransitionType::get()
        {
            return (CefSharp::TransitionType) _wrappedRequest->GetTransitionType();
        }

        IPostData^ CefRequestWrapper::PostData::get()
        {
            if (_postData == nullptr)
            {
                _postData = gcnew CefPostDataWrapper(_wrappedRequest->GetPostData());
            }
            return _postData;
        }
    }
}
<commit_msg>Change CefRequestWrapper to return null when PostData is null;<commit_after>// Copyright © 2010-2015 The CefSharp 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 "Stdafx.h"
#include "CefRequestWrapper.h"
#include "CefPostDataWrapper.h"

using namespace System::Text;

namespace CefSharp
{
    namespace Internals
    {
        String^ CefRequestWrapper::Url::get()
        {
            return StringUtils::ToClr(_wrappedRequest->GetURL());
        }

        void CefRequestWrapper::Url::set(String^ url)
        {
            if (url == nullptr)
            {
                throw gcnew System::ArgumentException("cannot be null", "url");
            }

            CefString str = StringUtils::ToNative(url);
            _wrappedRequest->SetURL(str);
        }

        String^ CefRequestWrapper::Method::get()
        {
            return StringUtils::ToClr(_wrappedRequest->GetMethod());
        }

        NameValueCollection^ CefRequestWrapper::Headers::get()
        {
            CefRequest::HeaderMap hm;
            _wrappedRequest->GetHeaderMap(hm);

            NameValueCollection^ headers = gcnew NameValueCollection();

            for (CefRequest::HeaderMap::iterator it = hm.begin(); it != hm.end(); ++it)
            {
                String^ name = StringUtils::ToClr(it->first);
                String^ value = StringUtils::ToClr(it->second);
                headers->Add(name, value);
            }

            return headers;
        }

        void CefRequestWrapper::Headers::set(NameValueCollection^ headers)
        {
            CefRequest::HeaderMap hm;

            for each(String^ key in headers)
            {
                CefString name = StringUtils::ToNative(key);
                for each(String^ element in headers->GetValues(key))
                {
                    CefString value = StringUtils::ToNative(element);
                    hm.insert(std::make_pair(name, value));
                }
            }

            _wrappedRequest->SetHeaderMap(hm);
        }

        TransitionType CefRequestWrapper::TransitionType::get()
        {
            return (CefSharp::TransitionType) _wrappedRequest->GetTransitionType();
        }

        IPostData^ CefRequestWrapper::PostData::get()
        {
            if (_postData == nullptr)
            {
                auto postData = _wrappedRequest->GetPostData();
                if (postData.get())
                {
                    _postData = gcnew CefPostDataWrapper(postData);
                }
            }
            return _postData;
        }
    }
}
<|endoftext|>


<commit_before>#ifndef DATA_STRUCTURE_RED_BLACK_TREE_HPP
#define DATA_STRUCTURE_RED_BLACK_TREE_HPP 1

#include <algorithm>
#include <cassert>

#define RED     0
#define BLACK   1

struct RedBlackTreeNode {
    /* 节点颜色 */
    int color;
    /* 节点值 */
    int index;

    RedBlackTreeNode *left;
    RedBlackTreeNode *right;
    RedBlackTreeNode *father;
};

struct RedBlackTree {
    RedBlackTreeNode *root;
};

int Color(const RedBlackTreeNode *e);
int & Color(RedBlackTreeNode *e);
RedBlackTreeNode* & Previous(RedBlackTreeNode *e);
RedBlackTreeNode* Previous(const RedBlackTreeNode *e);
RedBlackTreeNode* & Next(RedBlackTreeNode *e);
RedBlackTreeNode* Next(const RedBlackTreeNode *e);
RedBlackTreeNode* & Father(RedBlackTreeNode *e);
RedBlackTreeNode* Father(const RedBlackTreeNode *e);
RedBlackTreeNode* & Uncle(RedBlackTreeNode *e);
RedBlackTreeNode* Uncle(const RedBlackTreeNode *e);
RedBlackTreeNode* & GrandFather(RedBlackTreeNode *e);
RedBlackTreeNode* GrandFather(const RedBlackTreeNode *e);
RedBlackTreeNode* & Brother(RedBlackTreeNode *e);
RedBlackTreeNode* Brother(const RedBlackTreeNode *e);
RedBlackTreeNode* & LeftChild(RedBlackTreeNode *e);
RedBlackTreeNode* LeftChild(const RedBlackTreeNode *e);
RedBlackTreeNode* & RightChild(RedBlackTreeNode *e);
RedBlackTreeNode* RightChild(const RedBlackTreeNode *e);
bool IsLeftChild(RedBlackTreeNode *e);
bool IsRightChild(RedBlackTreeNode *e);
int ChildNumber(RedBlackTreeNode *e);

void SwapNode(RedBlackTreeNode *a, RedBlackTreeNode *b);
void SwapColor(RedBlackTreeNode *a, RedBlackTreeNode *b);

void NodeFree(RedBlackTreeNode *e);
RedBlackTreeNode* NodeFind(RedBlackTree *t, int index, RedBlackTreeNode **father);
void InsertCase1(RedBlackTree *t, RedBlackTreeNode *e);
void InsertCase2(RedBlackTree *t, RedBlackTreeNode *e);
void InsertCase3(RedBlackTree *t, RedBlackTreeNode *e);
void InsertCase4(RedBlackTree *t, RedBlackTreeNode *e);
void InsertCase5(RedBlackTree *t, RedBlackTreeNode *e);

void EraseCase0(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase0_A(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase0_B(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase0_C(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase1(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase2(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase3(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase4(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase5(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase6(RedBlackTree *t, RedBlackTreeNode *e);

void RotateLeft(RedBlackTree *t, RedBlackTreeNode *e);
void RotateRight(RedBlackTree *t, RedBlackTreeNode *e);

RedBlackTree* RedBlackTreeNew()
{
    RedBlackTree *t = new RedBlackTree();
    if (!t)
        return NULL;
    t->root = NULL;
    return t;
}

void RedBlackTreeFree(RedBlackTree *t)
{
    NodeFree(t->root);
}

void RedBlackTreeInsert(RedBlackTree *t, int index)
{
    RedBlackTreeNode *e = new RedBlackTreeNode();
    RedBlackTreeNode *father;
    RedBlackTreeNode *tmp;
    tmp = NodeFind(t, index, &father);
    assert(tmp == NULL);
    e->color = RED;
    e->index = index;
    e->left = NULL;
    e->right = NULL;
    e->father = father;
    if (father) {
        if (index < father->index)
            father->left = e;
        else
            father->right = e;
    }
    // fix rbtree from e
    InsertCase1(t, e);
}

int RedBlackTreeFind(RedBlackTree *t, int index)
{
    return (NodeFind(t, index, NULL) == NULL)? 0 : 1;
}

void RedBlackTreeErase(RedBlackTree *t, int index)
{
    RedBlackTreeNode *e = NodeFind(t, index, NULL);
    assert(e);

    EraseCase0(t, e);
}

void NodeFree(RedBlackTreeNode *e)
{
    if (!e)
        return;
    NodeFree(e->left);
    NodeFree(e->right);
    delete e;
}

void RotateLeft(RedBlackTree *t, RedBlackTreeNode *e)
{
    RedBlackTreeNode *p = e;
    RedBlackTreeNode *q = e->right;
    RedBlackTreeNode *father = e->father;

    if (father == NULL) {
        t->root = q;
    } else {
        if (father->left == p)
            father->left = q;
        else
            father->right = q;
    }

    q->father = father;
    p->father = q;

    p->right = q->left;
    if (q->left)
        q->left->father = p;
    q->left = p;
}

void RotateRight(RedBlackTree *t, RedBlackTreeNode *e)
{
    RedBlackTreeNode *p = e;
    RedBlackTreeNode *q = e->left; /* can't be NULL */
    RedBlackTreeNode *father = p->father;

    if (p->father == NULL) {
        t->root = q;
    }
    else {
        if (father->left == p)
            father->left = q;
        else
            father->right = q;
    }
    q->father = father;
    p->father = q;

    p->left = q->right;
    if (p->left)
        p->left->father = p;
    q->right = p;
}

RedBlackTreeNode* NodeFind(RedBlackTree *t, int index, RedBlackTreeNode **father)
{
    RedBlackTreeNode *cur = t->root;
    while (cur) {
        if (cur->index == index)
            return cur;
        else {
            if (father != NULL)
                *father = cur;
            if (index < cur->index)
                cur = cur->left;
            else
                cur = cur->right;
        }
    }
    return NULL;
}

void InsertCase1(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (t->root == NULL || e->father == NULL) {
        assert(t->root == NULL);
        assert(e->father == NULL);
        e->color = BLACK;
        t->root = e;
    } else {
        InsertCase2(t, e);
    }
}

void InsertCase2(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (e->father->color != BLACK) {
        InsertCase3(t, e);
    }
}

void InsertCase3(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (Color(Father(e)) == RED
        && Color(Uncle(e)) == RED) {
        Color(Father(e)) = BLACK;
        Color(Uncle(e)) = BLACK;
        Color(GrandFather(e)) = RED;
        InsertCase1(t, GrandFather(e));
    } else {
        InsertCase4(t, e);
    }
}

void InsertCase4(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (Color(Father(e)) == RED
        && Color(Uncle(e)) == BLACK
        && IsRightChild(e)
        && IsLeftChild(Father(e))) {
        RotateLeft(t, e);
        InsertCase5(t, Father(e));
    }
}

void InsertCase5(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (Color(Father(e)) == RED
        && Color(Uncle(e)) == BLACK
        && IsLeftChild(e)
        && IsLeftChild(Father(e))) {
        RotateRight(t, GrandFather(e));
        //swap color of Father and GrandFather
        int tmp_color = Color(Father(e));
        Color(Father(e)) = Color(GrandFather(e));
        Color(GrandFather(e)) = tmp_color;
    }
}

void EraseCase0(RedBlackTree *t, RedBlackTreeNode *e)
{
    int child_number = ChildNumber(e);
    if (child_number == 0) {
        // 删除操作 0-a
        EraseCase0_A(t, e);
    } else if (child_number == 1) {
        // 删除操作 0-b
        EraseCase0_B(t, e);
    } else if (child_number == 2) {
        // 删除操作 0-c
        EraseCase0_C(t, e);
    }
}

void EraseCase0_A(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (Father(e)->left == e)
        Father(e)->left = NULL;
    else if (Father(e)->right == e)
        Father(e)->right = NULL;
    delete e;
}

void EraseCase0_B(RedBlackTree *t, RedBlackTreeNode *e)
{
    RedBlackTreeNode *child = e->left ? e->left : e->right;
    SwapNode(child, e);

    // now "child" is father of "e", while "e" is child of "child"
    child->left = child->right = NULL;
    delete e;
    EraseCase1(t, child);
}

void EraseCase0_C(RedBlackTree *t, RedBlackTreeNode *e)
{
    RedBlackTreeNode *next = Next(e);
    e->index = next->index;
    EraseCase0(t, next);
}

void EraseCase1(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (t->root != e || e->father != NULL) {
        assert(t->root != e);
        assert(e->father != NULL);
        EraseCase2(t, e);
    }
}

void EraseCase2(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (Color(Brother(e)) == RED) {
        if (IsLeftChild(e)) {
            RotateLeft(t, e);
        } else if (IsRightChild(e)) {
            RotateRight(t, e);
        }
        SwapColor(Father(e), Brother(e));
    } else {
        EraseCase3(t, e);
    }
}

void EraseCase3(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (Color(Father(e)) == BLACK
        && Color(Brother(e)) == BLACK
        && Color(LeftChild(Brother(e))) == BLACK
        && Color(RightChild(Brother(e))) == BLACK) {
        Color(Brother(e)) = RED;
        EraseCase1(t, Father(e));
    } else {
        EraseCase4(t, e);
    }
}

void EraseCase4(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (Color(e) == BLACK
        && Color(Brother(e)) == BLACK
        && Color(LeftChild(Brother(e))) == BLACK
        && Color(RightChild(Brother(e))) == BLACK
        && Color(Father(e)) == RED) {
        SwapColor(Father(e), Brother(e));
    } else {
        EraseCase5(t, e);
    }
}

void EraseCase5(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (IsLeftChild(e)
        && Color(Brother(e)) == BLACK
        && Color(LeftChild(Brother(e))) == RED
        && Color(RightChild(Brother(e))) == BLACK) {
        RotateRight(t, Brother(e));
        SwapColor(Brother(e), Father(e));
        EraseCase6(t, e);
    }
}

void EraseCase6(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (IsLeftChild(e)
        && Color(Brother(e)) == BLACK
        && Color(RightChild(Brother(e))) == RED) {
        RotateLeft(t, Father(e));
        SwapColor(Father(e), Father(Father(e)));
        Color(Brother(e)) = BLACK;
    }
}

void SwapNode(RedBlackTreeNode *a, RedBlackTreeNode *b)
{
    RedBlackTreeNode tmp_a = *a;
    RedBlackTreeNode tmp_b = *b;

    /*
        a_father
            |
            a
           / \
     a_left   a_right
        b_father
            |
            b
           / \
     b_left   b_right
    */

    if (LeftChild(Father(a)) == a)
        LeftChild(Father(a)) = b;
    else if (RightChild(Father(a)) == a)
        RightChild(Father(a)) = b;
    Father(a) = Father(b);
    LeftChild(a) = LeftChild(b);
    Father(LeftChild(a)) = a;
    RightChild(a) = RightChild(b);
    Father(RightChild(a)) = a;

    if (LeftChild(Father(&tmp_b)) == b)
        LeftChild(Father(&tmp_b)) = a;
    if (RightChild(Father(&tmp_b)) == b)
        RightChild(Father(&tmp_b)) = a;
    Father(b) = Father(&tmp_a);
    LeftChild(b) = LeftChild(&tmp_b);
    Father(LeftChild(b)) = b;
    RightChild(b) = RightChild(&tmp_b);
    Father(RightChild(b)) = b;
}

void SwapColor(RedBlackTreeNode *a, RedBlackTreeNode *b)
{
    int c = a->color;
    a->color = b->color;
    b->color = c;
}

int Color(const RedBlackTreeNode *e)
{
    return (e == NULL) ? BLACK : e->color;
}

int & Color(RedBlackTreeNode *e)
{
    return e->color;
}

RedBlackTreeNode* Previous(const RedBlackTreeNode *e)
{
}

RedBlackTreeNode* & Previous(RedBlackTreeNode *e)
{
}

RedBlackTreeNode* & Next(RedBlackTreeNode *e);
RedBlackTreeNode* & Father(RedBlackTreeNode *e);
RedBlackTreeNode* & Uncle(RedBlackTreeNode *e);
RedBlackTreeNode* & GrandFather(RedBlackTreeNode *e);
RedBlackTreeNode* & Brother(RedBlackTreeNode *e);
RedBlackTreeNode* & LeftChild(RedBlackTreeNode *e);
RedBlackTreeNode* & RightChild(RedBlackTreeNode *e);
bool IsLeftChild(RedBlackTreeNode *e);
bool IsRightChild(RedBlackTreeNode *e);
int ChildNumber(RedBlackTreeNode *e);

#endif<commit_msg>finish code<commit_after>#ifndef DATA_STRUCTURE_RED_BLACK_TREE_HPP
#define DATA_STRUCTURE_RED_BLACK_TREE_HPP 1

#include <algorithm>
#include <cassert>

#define RED     0
#define BLACK   1

struct RedBlackTreeNode {
    /* 节点颜色 */
    int color;
    /* 节点值 */
    int index;

    RedBlackTreeNode *left;
    RedBlackTreeNode *right;
    RedBlackTreeNode *father;
};

struct RedBlackTree {
    RedBlackTreeNode *root;
};

int & Index(RedBlackTreeNode *e);
int Index(const RedBlackTreeNode *e);
int Color(const RedBlackTreeNode *e);
int & Color(RedBlackTreeNode *e);
RedBlackTreeNode* & Previous(RedBlackTreeNode *e);
RedBlackTreeNode* Previous(const RedBlackTreeNode *e);
RedBlackTreeNode* & Next(RedBlackTreeNode *e);
RedBlackTreeNode* Next(const RedBlackTreeNode *e);
RedBlackTreeNode* & Father(RedBlackTreeNode *e);
RedBlackTreeNode* Father(const RedBlackTreeNode *e);
RedBlackTreeNode* & Uncle(RedBlackTreeNode *e);
RedBlackTreeNode* Uncle(const RedBlackTreeNode *e);
RedBlackTreeNode* & GrandFather(RedBlackTreeNode *e);
RedBlackTreeNode* GrandFather(const RedBlackTreeNode *e);
RedBlackTreeNode* & Brother(RedBlackTreeNode *e);
RedBlackTreeNode* Brother(const RedBlackTreeNode *e);
RedBlackTreeNode* & LeftChild(RedBlackTreeNode *e);
RedBlackTreeNode* LeftChild(const RedBlackTreeNode *e);
RedBlackTreeNode* & RightChild(RedBlackTreeNode *e);
RedBlackTreeNode* RightChild(const RedBlackTreeNode *e);
bool IsLeftChild(RedBlackTreeNode *e);
bool IsRightChild(RedBlackTreeNode *e);
int ChildNumber(RedBlackTreeNode *e);
void SwapNode(RedBlackTreeNode *a, RedBlackTreeNode *b);
void SwapColor(RedBlackTreeNode *a, RedBlackTreeNode *b);

void NodeFree(RedBlackTreeNode *e);
RedBlackTreeNode* NodeFind(RedBlackTree *t, int index, RedBlackTreeNode **father);
void InsertCase1(RedBlackTree *t, RedBlackTreeNode *e);
void InsertCase2(RedBlackTree *t, RedBlackTreeNode *e);
void InsertCase3(RedBlackTree *t, RedBlackTreeNode *e);
void InsertCase4(RedBlackTree *t, RedBlackTreeNode *e);
void InsertCase5(RedBlackTree *t, RedBlackTreeNode *e);

void EraseCase0(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase0_A(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase0_B(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase0_C(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase1(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase2(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase3(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase4(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase5(RedBlackTree *t, RedBlackTreeNode *e);
void EraseCase6(RedBlackTree *t, RedBlackTreeNode *e);

void RotateLeft(RedBlackTree *t, RedBlackTreeNode *e);
void RotateRight(RedBlackTree *t, RedBlackTreeNode *e);

RedBlackTree* RedBlackTreeNew()
{
    RedBlackTree *t = new RedBlackTree();
    if (!t)
        return NULL;
    t->root = NULL;
    return t;
}

void RedBlackTreeFree(RedBlackTree *t)
{
    NodeFree(t->root);
}

void RedBlackTreeInsert(RedBlackTree *t, int index)
{
    RedBlackTreeNode *e = new RedBlackTreeNode();
    RedBlackTreeNode *father;
    RedBlackTreeNode *tmp;
    tmp = NodeFind(t, index, &father);
    assert(tmp == NULL);
    Color(e) = RED;
    Index(e) = index;
    LeftChild(e) = NULL;
    RightChild(e) = NULL;
    Father(e) = father;
    if (father) {
        if (index < Index(father))
            LeftChild(father) = e;
        else
            RightChild(father) = e;
    }
    // fix rbtree from e
    InsertCase1(t, e);
}

int RedBlackTreeFind(RedBlackTree *t, int index)
{
    return (NodeFind(t, index, NULL) == NULL)? 0 : 1;
}

void RedBlackTreeErase(RedBlackTree *t, int index)
{
    RedBlackTreeNode *e = NodeFind(t, index, NULL);
    assert(e);

    EraseCase0(t, e);
}

void NodeFree(RedBlackTreeNode *e)
{
    if (!e)
        return;
    NodeFree(e->left);
    NodeFree(e->right);
    delete e;
}

void RotateLeft(RedBlackTree *t, RedBlackTreeNode *e)
{
    RedBlackTreeNode *p = e;
    RedBlackTreeNode *q = RightChild(e);
    RedBlackTreeNode *father = Father(e);

    if (father == NULL) {
        t->root = q;
    } else {
        if (LeftChild(father) == p)
            LeftChild(father) = q;
        else
            RightChild(father) = q;
    }

    Father(q) = father;
    Father(p) = q;

    RightChild(p) = LeftChild(q);
    if (LeftChild(q))
        Father(LeftChild(q)) = p;
    LeftChild(q) = p;
}

void RotateRight(RedBlackTree *t, RedBlackTreeNode *e)
{
    RedBlackTreeNode *p = e;
    RedBlackTreeNode *q = LeftChild(e); /* can't be NULL */
    RedBlackTreeNode *father = Father(p);

    if (father == NULL) {
        t->root = q;
    }
    else {
        if (LeftChild(father) == p)
            LeftChild(father) = q;
        else
            RightChild(father) = q;
    }
    Father(q) = father;
    Father(p) = q;

    LeftChild(p) = RightChild(q);
    if (LeftChild(p))
        Father(LeftChild(p)) = p;
    RightChild(q) = p;
}

RedBlackTreeNode* NodeFind(RedBlackTree *t, int index, RedBlackTreeNode **father)
{
    RedBlackTreeNode *cur = t->root;
    while (cur) {
        if (Index(cur) == index)
            return cur;
        else {
            if (father != NULL)
                *father = cur;
            if (index < Index(cur))
                cur = LeftChild(cur);
            else
                cur = RightChild(cur);
        }
    }
    return NULL;
}

void InsertCase1(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (t->root == NULL || Father(e) == NULL) {
        assert(t->root == NULL);
        assert(Father(e) == NULL);
        Color(e) = BLACK;
        t->root = e;
    } else {
        InsertCase2(t, e);
    }
}

void InsertCase2(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (Color(Father(e)) != BLACK) {
        InsertCase3(t, e);
    }
}

void InsertCase3(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (Color(Father(e)) == RED
        && Color(Uncle(e)) == RED) {
        Color(Father(e)) = BLACK;
        Color(Uncle(e)) = BLACK;
        Color(GrandFather(e)) = RED;
        InsertCase1(t, GrandFather(e));
    } else {
        InsertCase4(t, e);
    }
}

void InsertCase4(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (Color(Father(e)) == RED
        && Color(Uncle(e)) == BLACK
        && IsRightChild(e)
        && IsLeftChild(Father(e))) {
        RotateLeft(t, e);
        InsertCase5(t, Father(e));
    }
}

void InsertCase5(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (Color(Father(e)) == RED
        && Color(Uncle(e)) == BLACK
        && IsLeftChild(e)
        && IsLeftChild(Father(e))) {
        RotateRight(t, GrandFather(e));
        //swap color of Father and GrandFather
        SwapColor(Father(e), GrandFather(e));
    }
}

void EraseCase0(RedBlackTree *t, RedBlackTreeNode *e)
{
    int child_number = ChildNumber(e);
    if (child_number == 0) {
        // 删除操作 0-a
        EraseCase0_A(t, e);
    } else if (child_number == 1) {
        // 删除操作 0-b
        EraseCase0_B(t, e);
    } else if (child_number == 2) {
        // 删除操作 0-c
        EraseCase0_C(t, e);
    }
}

void EraseCase0_A(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (LeftChild(Father(e)) == e)
        LeftChild(Father(e)) = NULL;
    else if (RightChild(Father(e)) == e)
        RightChild(Father(e)) = NULL;
    delete e;
}

void EraseCase0_B(RedBlackTree *t, RedBlackTreeNode *e)
{
    RedBlackTreeNode *child = LeftChild(e) ? LeftChild(e) : RightChild(e);
    SwapNode(child, e);

    // now "child" is father of "e", while "e" is child of "child"
    LeftChild(child) = RightChild(child) = NULL;
    delete e;
    EraseCase1(t, child);
}

void EraseCase0_C(RedBlackTree *t, RedBlackTreeNode *e)
{
    RedBlackTreeNode *next = Next(e);
    Index(e) = Index(next);
    EraseCase0(t, next);
}

void EraseCase1(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (t->root != e || Father(e) != NULL) {
        assert(t->root != e);
        assert(Father(e) != NULL);
        EraseCase2(t, e);
    }
}

void EraseCase2(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (Color(Brother(e)) == RED) {
        if (IsLeftChild(e)) {
            RotateLeft(t, e);
        } else if (IsRightChild(e)) {
            RotateRight(t, e);
        }
        SwapColor(Father(e), Brother(e));
    } else {
        EraseCase3(t, e);
    }
}

void EraseCase3(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (Color(Father(e)) == BLACK
        && Color(Brother(e)) == BLACK
        && Color(LeftChild(Brother(e))) == BLACK
        && Color(RightChild(Brother(e))) == BLACK) {
        Color(Brother(e)) = RED;
        EraseCase1(t, Father(e));
    } else {
        EraseCase4(t, e);
    }
}

void EraseCase4(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (Color(e) == BLACK
        && Color(Brother(e)) == BLACK
        && Color(LeftChild(Brother(e))) == BLACK
        && Color(RightChild(Brother(e))) == BLACK
        && Color(Father(e)) == RED) {
        SwapColor(Father(e), Brother(e));
    } else {
        EraseCase5(t, e);
    }
}

void EraseCase5(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (IsLeftChild(e)
        && Color(Brother(e)) == BLACK
        && Color(LeftChild(Brother(e))) == RED
        && Color(RightChild(Brother(e))) == BLACK) {
        RotateRight(t, Brother(e));
        SwapColor(Brother(e), Father(e));
        EraseCase6(t, e);
    }
}

void EraseCase6(RedBlackTree *t, RedBlackTreeNode *e)
{
    if (IsLeftChild(e)
        && Color(Brother(e)) == BLACK
        && Color(RightChild(Brother(e))) == RED) {
        RotateLeft(t, Father(e));
        SwapColor(Father(e), Father(Father(e)));
        Color(Brother(e)) = BLACK;
    }
}

void SwapNode(RedBlackTreeNode *a, RedBlackTreeNode *b)
{
    RedBlackTreeNode tmp_a = *a;
    RedBlackTreeNode tmp_b = *b;

    /*
        a_father
            |
            a
           / \
     a_left   a_right
        b_father
            |
            b
           / \
     b_left   b_right
    */

    if (LeftChild(Father(a)) == a)
        LeftChild(Father(a)) = b;
    else if (RightChild(Father(a)) == a)
        RightChild(Father(a)) = b;
    Father(a) = Father(b);
    LeftChild(a) = LeftChild(b);
    Father(LeftChild(a)) = a;
    RightChild(a) = RightChild(b);
    Father(RightChild(a)) = a;

    if (LeftChild(Father(&tmp_b)) == b)
        LeftChild(Father(&tmp_b)) = a;
    if (RightChild(Father(&tmp_b)) == b)
        RightChild(Father(&tmp_b)) = a;
    Father(b) = Father(&tmp_a);
    LeftChild(b) = LeftChild(&tmp_b);
    Father(LeftChild(b)) = b;
    RightChild(b) = RightChild(&tmp_b);
    Father(RightChild(b)) = b;
}

void SwapColor(RedBlackTreeNode *a, RedBlackTreeNode *b)
{
    int c = Color(a);
    Color(a) = Color(b);
    Color(b) = c;
}

int Color(const RedBlackTreeNode *e)
{
    return (e == NULL) ? BLACK : e->color;
}
int & Color(RedBlackTreeNode *e)
{
    return e->color;
}
RedBlackTreeNode* Previous(const RedBlackTreeNode *e)
{
    if (!e)
        return NULL;
    while (e->left)
        e = e->left;
    return (RedBlackTreeNode*)e;
}
RedBlackTreeNode* & Previous(RedBlackTreeNode *e)
{
    while (e->left)
        e = e->left;
    return e;
}
RedBlackTreeNode* Next(const RedBlackTreeNode *e)
{
    if (!e)
        return NULL;
    while (e->right)
        e = e->right;
    return (RedBlackTreeNode*)e;
}
RedBlackTreeNode* & Next(RedBlackTreeNode *e)
{
    while (e->right)
        e = e->right;
    return e;
}
RedBlackTreeNode* & Father(RedBlackTreeNode *e)
{
    return e->father;
}
RedBlackTreeNode* Father(const RedBlackTreeNode *e)
{
    return e ? e->father : NULL;
}
RedBlackTreeNode* Uncle(const RedBlackTreeNode *e)
{
    if (GrandFather(e) == NULL)
        return NULL;
    return (LeftChild(GrandFather(e)) == e) ? RightChild(GrandFather(e)) : LeftChild(GrandFather(e));
}
RedBlackTreeNode* & Uncle(RedBlackTreeNode *e)
{
    return (LeftChild(GrandFather(e)) == e) ? RightChild(GrandFather(e)) : LeftChild(GrandFather(e));
}
RedBlackTreeNode* & GrandFather(RedBlackTreeNode *e)
{
    return Father(Father(e));
}
RedBlackTreeNode* GrandFather(const RedBlackTreeNode *e)
{
    return Father(Father(e));
}
RedBlackTreeNode* & Brother(RedBlackTreeNode *e)
{
    if (LeftChild(Father(e)) == e)
        return RightChild(Father(e));
    else
        return LeftChild(Father(e));
}
RedBlackTreeNode* Brother(const RedBlackTreeNode *e)
{
    if (Father(e) == NULL)
        return NULL;
    if (LeftChild(Father(e)) == e)
        return RightChild(Father(e));
    else
        return LeftChild(Father(e));
}
RedBlackTreeNode* & LeftChild(RedBlackTreeNode *e)
{
    return e->left;
}
RedBlackTreeNode* LeftChild(const RedBlackTreeNode *e)
{
    return e ? e->left : NULL;
}
RedBlackTreeNode* & RightChild(RedBlackTreeNode *e)
{
    return e->right;
}
RedBlackTreeNode* RightChild(const RedBlackTreeNode *e)
{
    return e ? e->right : NULL;
}
bool IsLeftChild(RedBlackTreeNode *e)
{
    return e? (LeftChild(Father(e)) == e) : false;
}
bool IsRightChild(RedBlackTreeNode *e)
{
    return e? (RightChild(Father(e)) == e) : false;
}
int ChildNumber(RedBlackTreeNode *e)
{
    return e ? ((LeftChild(e) ? 1 : 0) + (RightChild(e) ? 1 : 0)) : 0;
}
int Index(const RedBlackTreeNode *e)
{
    return e ? e->index : -1;
}
int & Index(RedBlackTreeNode *e)
{
    return e->index;
}

#endif<|endoftext|>


<commit_before>#include "Sqlite3Statement.h"
#include <cstddef>
#include "../DatabaseException.h"

#include "../../Finally.h"

namespace EasyCpp
{
	namespace Database
	{
		namespace Sqlite3
		{
			Sqlite3Statement::Sqlite3Statement(Sqlite3SharedDataPtr shared, std::string sql)
				:_shared(shared)
			{
				auto db = _shared->getDatabase();
				int rc = sqlite3_prepare_v2(db.get(), sql.c_str(), sql.length(), &_stmt, nullptr);
				if (rc != SQLITE_OK)
					throw DatabaseException("(" + std::to_string(rc) + ") " + sqlite3_errmsg(db.get()), Bundle({ { "sql", sql } }));
			}

			Sqlite3Statement::~Sqlite3Statement()
			{
				sqlite3_finalize(_stmt);
			}

			uint64_t Sqlite3Statement::execute()
			{
				auto db = _shared->getDatabase();
				Finally finally([this, db]() {
					sqlite3_reset(_stmt);
				});
				int rc = sqlite3_reset(_stmt);
				// Do we need to check the return code ?
				rc = sqlite3_step(_stmt);
				if (rc == SQLITE_ROW)
					throw DatabaseException("Statement returned rows", {});
				if (rc != SQLITE_DONE)
					throw DatabaseException("Failed to execute statement", {});
				int res = sqlite3_changes(db.get());
				return res;
			}

			AnyValue Sqlite3Statement::executeScalar()
			{
				auto db = _shared->getDatabase();
				Finally finally([this, db]() {
					sqlite3_reset(_stmt);
				});
				int rc = sqlite3_reset(_stmt);
				// Do we need to check the return code ?
				rc = sqlite3_step(_stmt);
				if (rc != SQLITE_OK&&rc != SQLITE_ROW)
					throw DatabaseException("Failed to execute statement", {});
				return getColumn(0);
			}

			Bundle Sqlite3Statement::executeQueryRow()
			{
				auto db = _shared->getDatabase();
				Finally finally([this, db]() {
					sqlite3_reset(_stmt);
				});
				int rc = sqlite3_reset(_stmt);
				// Do we need to check the return code ?
				rc = sqlite3_step(_stmt);
				if (rc != SQLITE_OK&&rc != SQLITE_ROW)
					throw DatabaseException("Failed to execute statement", {});

				int colcount = sqlite3_column_count(_stmt);
				if (rc == SQLITE_DONE) // No result rows
					throw DatabaseException("Query did not return a result", {});
				Bundle row;
				for (int i = 0; i < colcount; i++)
					row.set(sqlite3_column_name(_stmt, i), getColumn(i));
				return row;
			}

			ResultSet Sqlite3Statement::executeQuery()
			{
				auto db = _shared->getDatabase();
				Finally finally([this, db]() {
					sqlite3_reset(_stmt);
				});
				int rc = sqlite3_reset(_stmt);
				// Do we need to check the return code ?
				rc = sqlite3_step(_stmt);
				if (rc != SQLITE_OK&&rc != SQLITE_ROW)
					throw DatabaseException("Failed to execute statement", {});

				int colcount = sqlite3_column_count(_stmt);
				std::vector<std::string> names;
				for (int i = 0; i < colcount; i++)
					names.push_back(sqlite3_column_name(_stmt, i));
				ResultSet res(std::unordered_set<std::string>(names.begin(), names.end()));

				if (rc == SQLITE_DONE) // No result rows
					return res;
				do {
					Bundle row;
					for (int i = 0; i < colcount; i++)
						row.set(names[i], getColumn(i));
					res.appendRow(row);

					// Read next row
					rc = sqlite3_step(_stmt);
					if (rc != SQLITE_DONE&&rc != SQLITE_ROW)
						throw DatabaseException("Failed to execute statement", {});
				} while (rc != SQLITE_DONE);
				return res;
			}

			void Sqlite3Statement::bind(uint64_t id, AnyValue value)
			{
				auto db = _shared->getDatabase();
				if (value.isType<std::vector<uint8_t>>()) {
					auto v = value.as<std::vector<uint8_t>>();
					int rc = sqlite3_bind_blob64(_stmt, (int)(id + 1), v.data(), v.size(), SQLITE_TRANSIENT);
					if (rc != SQLITE_OK)
						throw DatabaseException(sqlite3_errmsg(db.get()), {});
				}
				else if (value.type_info().isIntegral()) {
					auto v = value.as<int64_t>();
					int rc = sqlite3_bind_int64(_stmt, (int)(id + 1), v);
					if (rc != SQLITE_OK)
						throw DatabaseException(sqlite3_errmsg(db.get()), {});
				}
				else if (value.type_info().isFloatingPoint()) {
					auto v = value.as<double>();
					int rc = sqlite3_bind_double(_stmt, (int)(id + 1), v);
					if (rc != SQLITE_OK)
						throw DatabaseException(sqlite3_errmsg(db.get()), {});
				}
				else if (value.isType<nullptr_t>()) {
					int rc = sqlite3_bind_null(_stmt, (int)(id + 1));
					if (rc != SQLITE_OK)
						throw DatabaseException(sqlite3_errmsg(db.get()), {});
				}
				else {
					auto v = value.as<std::string>();
					int rc = sqlite3_bind_text64(_stmt, (int)(id + 1), v.data(), v.length(), SQLITE_TRANSIENT, SQLITE_UTF8);
					if (rc != SQLITE_OK)
						throw DatabaseException(sqlite3_errmsg(db.get()), {});
				}
			}

			void Sqlite3Statement::bind(const std::string & id, AnyValue value)
			{
				this->bind(this->getParameterIndex(id), value);
			}

			AnyValue Sqlite3Statement::getColumn(int i)
			{
				int dtype = sqlite3_column_type(_stmt, i);
				if (dtype == SQLITE_INTEGER)
				{
					return AnyValue((int64_t)sqlite3_column_int64(_stmt, i));
				}
				else if (dtype == SQLITE_FLOAT)
				{
					return AnyValue(sqlite3_column_double(_stmt, i));
				}
				else if (dtype == SQLITE_BLOB)
				{
					const uint8_t* ptr = (const uint8_t*)sqlite3_column_blob(_stmt, i);
					int length = sqlite3_column_bytes(_stmt, i);
					return AnyValue(std::vector<uint8_t>(ptr, ptr + length));
				}
				else if (dtype == SQLITE3_TEXT)
				{
					return AnyValue(std::string((const char*)sqlite3_column_text(_stmt, i)));
				}
				else if (dtype == SQLITE_NULL)
				{
					return AnyValue();
				}
				throw DatabaseException("Invalid result type", {});
			}
			int Sqlite3Statement::getParameterIndex(const std::string & name)
			{
				int rc = sqlite3_bind_parameter_index(_stmt, name.c_str());
				if (rc == 0)
					throw DatabaseException("Parameter not found", {});
				return rc - 1;
			}
		}
	}
}
<commit_msg>Fix for strings containing null characters<commit_after>#include "Sqlite3Statement.h"
#include <cstddef>
#include "../DatabaseException.h"

#include "../../Finally.h"

namespace EasyCpp
{
	namespace Database
	{
		namespace Sqlite3
		{
			Sqlite3Statement::Sqlite3Statement(Sqlite3SharedDataPtr shared, std::string sql)
				:_shared(shared)
			{
				auto db = _shared->getDatabase();
				int rc = sqlite3_prepare_v2(db.get(), sql.c_str(), sql.length(), &_stmt, nullptr);
				if (rc != SQLITE_OK)
					throw DatabaseException("(" + std::to_string(rc) + ") " + sqlite3_errmsg(db.get()), Bundle({ { "sql", sql } }));
			}

			Sqlite3Statement::~Sqlite3Statement()
			{
				sqlite3_finalize(_stmt);
			}

			uint64_t Sqlite3Statement::execute()
			{
				auto db = _shared->getDatabase();
				Finally finally([this, db]() {
					sqlite3_reset(_stmt);
				});
				int rc = sqlite3_reset(_stmt);
				// Do we need to check the return code ?
				rc = sqlite3_step(_stmt);
				if (rc == SQLITE_ROW)
					throw DatabaseException("Statement returned rows", {});
				if (rc != SQLITE_DONE)
					throw DatabaseException("Failed to execute statement", {});
				int res = sqlite3_changes(db.get());
				return res;
			}

			AnyValue Sqlite3Statement::executeScalar()
			{
				auto db = _shared->getDatabase();
				Finally finally([this, db]() {
					sqlite3_reset(_stmt);
				});
				int rc = sqlite3_reset(_stmt);
				// Do we need to check the return code ?
				rc = sqlite3_step(_stmt);
				if (rc != SQLITE_OK&&rc != SQLITE_ROW)
					throw DatabaseException("Failed to execute statement", {});
				return getColumn(0);
			}

			Bundle Sqlite3Statement::executeQueryRow()
			{
				auto db = _shared->getDatabase();
				Finally finally([this, db]() {
					sqlite3_reset(_stmt);
				});
				int rc = sqlite3_reset(_stmt);
				// Do we need to check the return code ?
				rc = sqlite3_step(_stmt);
				if (rc != SQLITE_OK&&rc != SQLITE_ROW)
					throw DatabaseException("Failed to execute statement", {});

				int colcount = sqlite3_column_count(_stmt);
				if (rc == SQLITE_DONE) // No result rows
					throw DatabaseException("Query did not return a result", {});
				Bundle row;
				for (int i = 0; i < colcount; i++)
					row.set(sqlite3_column_name(_stmt, i), getColumn(i));
				return row;
			}

			ResultSet Sqlite3Statement::executeQuery()
			{
				auto db = _shared->getDatabase();
				Finally finally([this, db]() {
					sqlite3_reset(_stmt);
				});
				int rc = sqlite3_reset(_stmt);
				// Do we need to check the return code ?
				rc = sqlite3_step(_stmt);
				if (rc != SQLITE_OK&&rc != SQLITE_ROW)
					throw DatabaseException("Failed to execute statement", {});

				int colcount = sqlite3_column_count(_stmt);
				std::vector<std::string> names;
				for (int i = 0; i < colcount; i++)
					names.push_back(sqlite3_column_name(_stmt, i));
				ResultSet res(std::unordered_set<std::string>(names.begin(), names.end()));

				if (rc == SQLITE_DONE) // No result rows
					return res;
				do {
					Bundle row;
					for (int i = 0; i < colcount; i++)
						row.set(names[i], getColumn(i));
					res.appendRow(row);

					// Read next row
					rc = sqlite3_step(_stmt);
					if (rc != SQLITE_DONE&&rc != SQLITE_ROW)
						throw DatabaseException("Failed to execute statement", {});
				} while (rc != SQLITE_DONE);
				return res;
			}

			void Sqlite3Statement::bind(uint64_t id, AnyValue value)
			{
				auto db = _shared->getDatabase();
				if (value.isType<std::vector<uint8_t>>()) {
					auto v = value.as<std::vector<uint8_t>>();
					int rc = sqlite3_bind_blob64(_stmt, (int)(id + 1), v.data(), v.size(), SQLITE_TRANSIENT);
					if (rc != SQLITE_OK)
						throw DatabaseException(sqlite3_errmsg(db.get()), {});
				}
				else if (value.type_info().isIntegral()) {
					auto v = value.as<int64_t>();
					int rc = sqlite3_bind_int64(_stmt, (int)(id + 1), v);
					if (rc != SQLITE_OK)
						throw DatabaseException(sqlite3_errmsg(db.get()), {});
				}
				else if (value.type_info().isFloatingPoint()) {
					auto v = value.as<double>();
					int rc = sqlite3_bind_double(_stmt, (int)(id + 1), v);
					if (rc != SQLITE_OK)
						throw DatabaseException(sqlite3_errmsg(db.get()), {});
				}
				else if (value.isType<nullptr_t>()) {
					int rc = sqlite3_bind_null(_stmt, (int)(id + 1));
					if (rc != SQLITE_OK)
						throw DatabaseException(sqlite3_errmsg(db.get()), {});
				}
				else {
					auto v = value.as<std::string>();
					int rc = sqlite3_bind_text64(_stmt, (int)(id + 1), v.data(), v.length(), SQLITE_TRANSIENT, SQLITE_UTF8);
					if (rc != SQLITE_OK)
						throw DatabaseException(sqlite3_errmsg(db.get()), {});
				}
			}

			void Sqlite3Statement::bind(const std::string & id, AnyValue value)
			{
				this->bind(this->getParameterIndex(id), value);
			}

			AnyValue Sqlite3Statement::getColumn(int i)
			{
				int dtype = sqlite3_column_type(_stmt, i);
				if (dtype == SQLITE_INTEGER)
				{
					return AnyValue((int64_t)sqlite3_column_int64(_stmt, i));
				}
				else if (dtype == SQLITE_FLOAT)
				{
					return AnyValue(sqlite3_column_double(_stmt, i));
				}
				else if (dtype == SQLITE_BLOB)
				{
					const uint8_t* ptr = (const uint8_t*)sqlite3_column_blob(_stmt, i);
					int length = sqlite3_column_bytes(_stmt, i);
					return AnyValue(std::vector<uint8_t>(ptr, ptr + length));
				}
				else if (dtype == SQLITE3_TEXT)
				{
					int length = sqlite3_column_bytes(_stmt, i);
					auto ptr = (const char*)sqlite3_column_text(_stmt, i);
					return AnyValue(std::string(ptr, ptr + length));
				}
				else if (dtype == SQLITE_NULL)
				{
					return AnyValue();
				}
				throw DatabaseException("Invalid result type", {});
			}
			int Sqlite3Statement::getParameterIndex(const std::string & name)
			{
				int rc = sqlite3_bind_parameter_index(_stmt, name.c_str());
				if (rc == 0)
					throw DatabaseException("Parameter not found", {});
				return rc - 1;
			}
		}
	}
}
<|endoftext|>