<commit_before>#define MS_CLASS "RTC::RtpStreamRecv"
// #define MS_LOG_DEV

#include "RTC/RtpStreamRecv.hpp"
#include "DepLibUV.hpp"
#include "Logger.hpp"
#include "RTC/Codecs/Codecs.hpp"

namespace RTC
{
	/* Instance methods. */

	RtpStreamRecv::RtpStreamRecv(Listener* listener, RTC::RtpStream::Params& params)
	  : RtpStream::RtpStream(params), listener(listener)
	{
		MS_TRACE();

		if (this->params.useNack)
			this->nackGenerator.reset(new RTC::NackGenerator(this));
	}

	RtpStreamRecv::~RtpStreamRecv()
	{
		MS_TRACE();
	}

	Json::Value RtpStreamRecv::GetStats()
	{
		static const std::string Type = "inbound-rtp";
		static const Json::StaticString JsonStringType{ "type" };
		static const Json::StaticString JsonStringJitter{ "jitter" };

		Json::Value json = RtpStream::GetStats();

		json[JsonStringType]   = Type;
		json[JsonStringJitter] = Json::UInt{ this->jitter };

		return json;
	}

	bool RtpStreamRecv::ReceivePacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		// Call the parent method.
		if (!RtpStream::ReceivePacket(packet))
		{
			MS_WARN_TAG(rtp, "packet discarded");

			return false;
		}

		// Calculate Jitter.
		CalculateJitter(packet->GetTimestamp());

		// Process the packet at codec level.
		if (packet->GetPayloadType() == GetPayloadType())
			Codecs::ProcessRtpPacket(packet, GetMimeType());

		// Pass the packet to the NackGenerator.
		if (this->params.useNack)
			this->nackGenerator->ReceivePacket(packet);

		return true;
	}

	bool RtpStreamRecv::ReceiveRtxPacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		MS_ASSERT(packet->GetSsrc() == this->rtxSsrc, "invalid ssrc on RTX packet");

		// Check that the payload type corresponds to the one negotiated.
		if (packet->GetPayloadType() != this->rtxPayloadType)
		{
			MS_WARN_TAG(
			  rtx,
			  "ignoring RTX packet with invalid payload type [ssrc:%" PRIu32 ", seq:%" PRIu16
			  ", pt:%" PRIu8 "]",
			  packet->GetSsrc(),
			  packet->GetSequenceNumber(),
			  packet->GetPayloadType());

			return false;
		}

		// Get the RTX packet sequence number for logging purposes.
		auto rtxSeq = packet->GetSequenceNumber();

		// Get the original RTP packet.
		if (!packet->RtxDecode(this->params.payloadType, this->params.ssrc))
		{
			MS_DEBUG_TAG(
			  rtx,
			  "ignoring empty RTX packet [ssrc:%" PRIu32 ", seq:%" PRIu16 ", pt:%" PRIu8 "]",
			  packet->GetSsrc(),
			  packet->GetSequenceNumber(),
			  packet->GetPayloadType());

			return false;
		}

		MS_DEBUG_TAG(
		  rtx,
		  "received RTX packet [ssrc:%" PRIu32 ", seq:%" PRIu16 "] recovering original [ssrc:%" PRIu32
		  ", seq:%" PRIu16 "]",
		  this->rtxSsrc,
		  rtxSeq,
		  packet->GetSsrc(),
		  packet->GetSequenceNumber());

		// If not a valid packet ignore it.
		if (!UpdateSeq(packet))
		{
			MS_WARN_TAG(
			  rtx,
			  "invalid RTX packet [ssrc:%" PRIu32 ", seq:%" PRIu16 "]",
			  packet->GetSsrc(),
			  packet->GetSequenceNumber());

			return false;
		}

		// Process the packet at codec level.
		if (packet->GetPayloadType() == GetPayloadType())
			Codecs::ProcessRtpPacket(packet, GetMimeType());

		// Pass the packet to the NackGenerator and return true just if this was a
		// NACKed packet.
		if (this->params.useNack)
			return this->nackGenerator->ReceivePacket(packet);

		return false;
	}

	RTC::RTCP::ReceiverReport* RtpStreamRecv::GetRtcpReceiverReport()
	{
		MS_TRACE();

		auto report = new RTC::RTCP::ReceiverReport();

		// Calculate Packets Expected and Lost.
		uint32_t expected = (this->cycles + this->maxSeq) - this->baseSeq + 1;
		this->packetsLost = expected - this->transmissionCounter.GetPacketCount();

		report->SetTotalLost(this->packetsLost);

		// Calculate Fraction Lost.
		uint32_t expectedInterval = expected - this->expectedPrior;

		this->expectedPrior = expected;

		uint32_t receivedInterval = this->transmissionCounter.GetPacketCount() - this->receivedPrior;

		this->receivedPrior = transmissionCounter.GetPacketCount();

		int32_t lostInterval = expectedInterval - receivedInterval;

		if (expectedInterval == 0 || lostInterval <= 0)
			this->fractionLost = 0;
		else
			this->fractionLost = (lostInterval << 8) / expectedInterval;

		report->SetFractionLost(this->fractionLost);

		// Fill the rest of the report.
		report->SetLastSeq(static_cast<uint32_t>(this->maxSeq) + this->cycles);
		report->SetJitter(this->jitter);

		if (this->lastSrReceived != 0u)
		{
			// Get delay in milliseconds.
			auto delayMs = static_cast<uint32_t>(DepLibUV::GetTime() - this->lastSrReceived);
			// Express delay in units of 1/65536 seconds.
			uint32_t dlsr = (delayMs / 1000) << 16;

			dlsr |= uint32_t{ (delayMs % 1000) * 65536 / 1000 };
			report->SetDelaySinceLastSenderReport(dlsr);
			report->SetLastSenderReport(this->lastSrTimestamp);
		}
		else
		{
			report->SetDelaySinceLastSenderReport(0);
			report->SetLastSenderReport(0);
		}

		return report;
	}

	void RtpStreamRecv::ReceiveRtcpSenderReport(RTC::RTCP::SenderReport* report)
	{
		MS_TRACE();

		this->lastSrReceived  = DepLibUV::GetTime();
		this->lastSrTimestamp = report->GetNtpSec() << 16;
		this->lastSrTimestamp += report->GetNtpFrac() >> 16;
	}

	void RtpStreamRecv::RequestKeyFrame()
	{
		MS_TRACE();

		if (this->params.usePli)
		{
			// Reset NackGenerator.
			if (this->params.useNack)
				this->nackGenerator.reset(new RTC::NackGenerator(this));

			this->listener->OnRtpStreamRecvPliRequired(this);
		}
	}

	void RtpStreamRecv::CalculateJitter(uint32_t rtpTimestamp)
	{
		MS_TRACE();

		if (this->params.clockRate == 0u)
			return;

		auto transit =
		  static_cast<int>(DepLibUV::GetTime() - (rtpTimestamp * 1000 / this->params.clockRate));
		int d = transit - this->transit;

		this->transit = transit;
		if (d < 0)
			d = -d;
		this->jitter += (1. / 16.) * (static_cast<double>(d) - this->jitter);
	}

	void RtpStreamRecv::CheckHealth()
	{
		auto now = DepLibUV::GetTime();

		if (this->transmissionCounter.GetRate(now) == 0 && IsHealthy())
			this->listener->OnRtpStreamInactivity(this);
	}

	void RtpStreamRecv::OnNackGeneratorNackRequired(const std::vector<uint16_t>& seqNumbers)
	{
		MS_TRACE();

		MS_ASSERT(this->params.useNack, "NACK required but not supported");

		MS_DEBUG_TAG(
		  rtx,
		  "triggering NACK [ssrc:%" PRIu32 ", first seq:%" PRIu16 ", num packets:%zu]",
		  this->params.ssrc,
		  seqNumbers[0],
		  seqNumbers.size());

		this->listener->OnRtpStreamRecvNackRequired(this, seqNumbers);
	}

	void RtpStreamRecv::OnNackGeneratorKeyFrameRequired()
	{
		MS_TRACE();

		MS_DEBUG_TAG(rtx, "requesting key frame [ssrc:%" PRIu32 "]", this->params.ssrc);

		RequestKeyFrame();
	}

	void RtpStreamRecv::SetRtx(uint8_t payloadType, uint32_t ssrc)
	{
		MS_TRACE();

		this->hasRtx         = true;
		this->rtxPayloadType = payloadType;
		this->rtxSsrc        = ssrc;
	}
} // namespace RTC
<commit_msg>RtpStreamSend: correctly call OnRtpStreamInactivity and OnRtpStreamHealthy<commit_after>#define MS_CLASS "RTC::RtpStreamRecv"
// #define MS_LOG_DEV

#include "RTC/RtpStreamRecv.hpp"
#include "DepLibUV.hpp"
#include "Logger.hpp"
#include "RTC/Codecs/Codecs.hpp"

namespace RTC
{
	/* Instance methods. */

	RtpStreamRecv::RtpStreamRecv(Listener* listener, RTC::RtpStream::Params& params)
	  : RtpStream::RtpStream(params), listener(listener)
	{
		MS_TRACE();

		if (this->params.useNack)
			this->nackGenerator.reset(new RTC::NackGenerator(this));
	}

	RtpStreamRecv::~RtpStreamRecv()
	{
		MS_TRACE();
	}

	Json::Value RtpStreamRecv::GetStats()
	{
		static const std::string Type = "inbound-rtp";
		static const Json::StaticString JsonStringType{ "type" };
		static const Json::StaticString JsonStringJitter{ "jitter" };

		Json::Value json = RtpStream::GetStats();

		json[JsonStringType]   = Type;
		json[JsonStringJitter] = Json::UInt{ this->jitter };

		return json;
	}

	bool RtpStreamRecv::ReceivePacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		// Call the parent method.
		if (!RtpStream::ReceivePacket(packet))
		{
			MS_WARN_TAG(rtp, "packet discarded");

			return false;
		}

		// Calculate Jitter.
		CalculateJitter(packet->GetTimestamp());

		// Process the packet at codec level.
		if (packet->GetPayloadType() == GetPayloadType())
			Codecs::ProcessRtpPacket(packet, GetMimeType());

		// Pass the packet to the NackGenerator.
		if (this->params.useNack)
			this->nackGenerator->ReceivePacket(packet);

		return true;
	}

	bool RtpStreamRecv::ReceiveRtxPacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		MS_ASSERT(packet->GetSsrc() == this->rtxSsrc, "invalid ssrc on RTX packet");

		// Check that the payload type corresponds to the one negotiated.
		if (packet->GetPayloadType() != this->rtxPayloadType)
		{
			MS_WARN_TAG(
			  rtx,
			  "ignoring RTX packet with invalid payload type [ssrc:%" PRIu32 ", seq:%" PRIu16
			  ", pt:%" PRIu8 "]",
			  packet->GetSsrc(),
			  packet->GetSequenceNumber(),
			  packet->GetPayloadType());

			return false;
		}

		// Get the RTX packet sequence number for logging purposes.
		auto rtxSeq = packet->GetSequenceNumber();

		// Get the original RTP packet.
		if (!packet->RtxDecode(this->params.payloadType, this->params.ssrc))
		{
			MS_DEBUG_TAG(
			  rtx,
			  "ignoring empty RTX packet [ssrc:%" PRIu32 ", seq:%" PRIu16 ", pt:%" PRIu8 "]",
			  packet->GetSsrc(),
			  packet->GetSequenceNumber(),
			  packet->GetPayloadType());

			return false;
		}

		MS_DEBUG_TAG(
		  rtx,
		  "received RTX packet [ssrc:%" PRIu32 ", seq:%" PRIu16 "] recovering original [ssrc:%" PRIu32
		  ", seq:%" PRIu16 "]",
		  this->rtxSsrc,
		  rtxSeq,
		  packet->GetSsrc(),
		  packet->GetSequenceNumber());

		// If not a valid packet ignore it.
		if (!UpdateSeq(packet))
		{
			MS_WARN_TAG(
			  rtx,
			  "invalid RTX packet [ssrc:%" PRIu32 ", seq:%" PRIu16 "]",
			  packet->GetSsrc(),
			  packet->GetSequenceNumber());

			return false;
		}

		// Process the packet at codec level.
		if (packet->GetPayloadType() == GetPayloadType())
			Codecs::ProcessRtpPacket(packet, GetMimeType());

		// Pass the packet to the NackGenerator and return true just if this was a
		// NACKed packet.
		if (this->params.useNack)
			return this->nackGenerator->ReceivePacket(packet);

		return false;
	}

	RTC::RTCP::ReceiverReport* RtpStreamRecv::GetRtcpReceiverReport()
	{
		MS_TRACE();

		auto report = new RTC::RTCP::ReceiverReport();

		// Calculate Packets Expected and Lost.
		uint32_t expected = (this->cycles + this->maxSeq) - this->baseSeq + 1;
		this->packetsLost = expected - this->transmissionCounter.GetPacketCount();

		report->SetTotalLost(this->packetsLost);

		// Calculate Fraction Lost.
		uint32_t expectedInterval = expected - this->expectedPrior;

		this->expectedPrior = expected;

		uint32_t receivedInterval = this->transmissionCounter.GetPacketCount() - this->receivedPrior;

		this->receivedPrior = transmissionCounter.GetPacketCount();

		int32_t lostInterval = expectedInterval - receivedInterval;

		if (expectedInterval == 0 || lostInterval <= 0)
			this->fractionLost = 0;
		else
			this->fractionLost = (lostInterval << 8) / expectedInterval;

		report->SetFractionLost(this->fractionLost);

		// Fill the rest of the report.
		report->SetLastSeq(static_cast<uint32_t>(this->maxSeq) + this->cycles);
		report->SetJitter(this->jitter);

		if (this->lastSrReceived != 0u)
		{
			// Get delay in milliseconds.
			auto delayMs = static_cast<uint32_t>(DepLibUV::GetTime() - this->lastSrReceived);
			// Express delay in units of 1/65536 seconds.
			uint32_t dlsr = (delayMs / 1000) << 16;

			dlsr |= uint32_t{ (delayMs % 1000) * 65536 / 1000 };
			report->SetDelaySinceLastSenderReport(dlsr);
			report->SetLastSenderReport(this->lastSrTimestamp);
		}
		else
		{
			report->SetDelaySinceLastSenderReport(0);
			report->SetLastSenderReport(0);
		}

		return report;
	}

	void RtpStreamRecv::ReceiveRtcpSenderReport(RTC::RTCP::SenderReport* report)
	{
		MS_TRACE();

		this->lastSrReceived  = DepLibUV::GetTime();
		this->lastSrTimestamp = report->GetNtpSec() << 16;
		this->lastSrTimestamp += report->GetNtpFrac() >> 16;
	}

	void RtpStreamRecv::RequestKeyFrame()
	{
		MS_TRACE();

		if (this->params.usePli)
		{
			// Reset NackGenerator.
			if (this->params.useNack)
				this->nackGenerator.reset(new RTC::NackGenerator(this));

			this->listener->OnRtpStreamRecvPliRequired(this);
		}
	}

	void RtpStreamRecv::CalculateJitter(uint32_t rtpTimestamp)
	{
		MS_TRACE();

		if (this->params.clockRate == 0u)
			return;

		auto transit =
		  static_cast<int>(DepLibUV::GetTime() - (rtpTimestamp * 1000 / this->params.clockRate));
		int d = transit - this->transit;

		this->transit = transit;
		if (d < 0)
			d = -d;
		this->jitter += (1. / 16.) * (static_cast<double>(d) - this->jitter);
	}

	void RtpStreamRecv::CheckHealth()
	{
		MS_TRACE();

		auto now = DepLibUV::GetTime();

		if (this->transmissionCounter.GetRate(now) == 0 && this->healthy)
		{
			this->listener->OnRtpStreamInactivity(this);
		}
		else if (!this->healthy)
		{
			this->healthy = true;
			this->listener->OnRtpStreamHealthy(this);
		}
	}

	void RtpStreamRecv::OnNackGeneratorNackRequired(const std::vector<uint16_t>& seqNumbers)
	{
		MS_TRACE();

		MS_ASSERT(this->params.useNack, "NACK required but not supported");

		MS_DEBUG_TAG(
		  rtx,
		  "triggering NACK [ssrc:%" PRIu32 ", first seq:%" PRIu16 ", num packets:%zu]",
		  this->params.ssrc,
		  seqNumbers[0],
		  seqNumbers.size());

		this->listener->OnRtpStreamRecvNackRequired(this, seqNumbers);
	}

	void RtpStreamRecv::OnNackGeneratorKeyFrameRequired()
	{
		MS_TRACE();

		MS_DEBUG_TAG(rtx, "requesting key frame [ssrc:%" PRIu32 "]", this->params.ssrc);

		RequestKeyFrame();
	}

	void RtpStreamRecv::SetRtx(uint8_t payloadType, uint32_t ssrc)
	{
		MS_TRACE();

		this->hasRtx         = true;
		this->rtxPayloadType = payloadType;
		this->rtxSsrc        = ssrc;
	}
} // namespace RTC
<|endoftext|>


<commit_before>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <zbase/core/Partition.h>
#include <stx/io/fileutil.h>
#include <stx/uri.h>
#include <stx/logging.h>
#include <stx/util/binarymessagewriter.h>
#include <stx/wallclock.h>
#include <stx/protobuf/MessageEncoder.h>
#include <stx/protobuf/MessageDecoder.h>
#include <stx/protobuf/msg.h>
#include <sstable/sstablereader.h>
#include <zbase/core/LogPartitionReader.h>
#include <zbase/core/LogPartitionWriter.h>
#include <zbase/core/LogPartitionReplication.h>
#include <zbase/core/LSMPartitionReader.h>
#include <zbase/core/LSMPartitionWriter.h>
#include <zbase/core/LSMPartitionReplication.h>
#include <zbase/core/StaticPartitionReader.h>
#include <zbase/core/StaticPartitionWriter.h>
#include <zbase/core/StaticPartitionReplication.h>
#include <zbase/z1stats.h>

using namespace stx;

namespace zbase {

RefPtr<Partition> Partition::create(
    const String& tsdb_namespace,
    RefPtr<Table> table,
    const SHA1Hash& partition_key,
    const String& db_path) {
  stx::logDebug(
      "tsdb",
      "Creating new partition; stream='$0' partition='$1'",
      table->name(),
      partition_key.toString());

  auto pdir = FileUtil::joinPaths(
      db_path,
      StringUtil::format(
          "$0/$1/$2",
          tsdb_namespace,
          SHA1::compute(table->name()).toString(),
          partition_key.toString()));

  FileUtil::mkdir_p(pdir);

  auto uuid = Random::singleton()->sha1();

  PartitionState state;
  state.set_tsdb_namespace(tsdb_namespace);
  state.set_partition_key(partition_key.data(), partition_key.size());
  state.set_table_key(table->name());
  state.set_uuid(uuid.data(), uuid.size());

  auto snap = mkRef(new PartitionSnapshot(state, pdir, 0));
  snap->writeToDisk();
  return new Partition(snap, table);
}

RefPtr<Partition> Partition::reopen(
    const String& tsdb_namespace,
    RefPtr<Table> table,
    const SHA1Hash& partition_key,
    const String& db_path) {
  auto pdir = FileUtil::joinPaths(
      db_path,
      StringUtil::format(
          "$0/$1/$2",
          tsdb_namespace,
          SHA1::compute(table->name()).toString(),
          partition_key.toString()));

  auto state = msg::decode<PartitionState>(
      FileUtil::read(FileUtil::joinPaths(pdir, "_snapshot")));

  auto nrecs = 0;
  const auto& files = state.sstable_files();
  for (const auto& f : files) {
    auto is = FileInputStream::openFile(FileUtil::joinPaths(pdir, f));
    auto header = sstable::FileHeaderReader::readMetaPage(is.get());
    nrecs += header.rowCount();
  }

  stx::logTrace(
      "tsdb",
      "Loading partition $0/$1/$2 ($3 records)",
      tsdb_namespace,
      table->name(),
      partition_key.toString(),
      nrecs);

  auto snap = mkRef(new PartitionSnapshot(state, pdir, nrecs));
  return new Partition(snap, table);
}

Partition::Partition(
    RefPtr<PartitionSnapshot> head,
    RefPtr<Table> table) :
    head_(head),
    table_(table) {
  z1stats()->num_partitions_loaded.incr(1);
}

Partition::~Partition() {
  z1stats()->num_partitions_loaded.decr(1);
}

SHA1Hash Partition::uuid() const {
  auto snap = head_.getSnapshot();
  return snap->uuid();
}

RefPtr<PartitionWriter> Partition::getWriter() {
  std::unique_lock<std::mutex> lk(writer_lock_);
  if (writer_.get() == nullptr) {
    switch (table_->storage()) {

      case zbase::TBL_STORAGE_LOG:
        if (upgradeToLSMv2()) {
          writer_ = mkRef<PartitionWriter>(new LSMPartitionWriter(this, &head_));
        } else {
          writer_ = mkRef<PartitionWriter>(new LogPartitionWriter(this, &head_));
        }
        break;

      case zbase::TBL_STORAGE_STATIC:
        writer_ = mkRef<PartitionWriter>(new StaticPartitionWriter(&head_));
        break;

      default:
        RAISE(kRuntimeError, "invalid storage class");

    }
  }

  auto writer = writer_;
  return writer;
}

RefPtr<PartitionReader> Partition::getReader() {
  switch (table_->storage()) {

    case zbase::TBL_STORAGE_LOG:
      if (upgradeToLSMv2()) {
        return new LSMPartitionReader(table_, head_.getSnapshot());
      } else {
        return new LogPartitionReader(table_, head_.getSnapshot());
      }

    case zbase::TBL_STORAGE_STATIC:
      return new StaticPartitionReader(table_, head_.getSnapshot());

    default:
      RAISE(kRuntimeError, "invalid storage class");

  }
}

RefPtr<PartitionSnapshot> Partition::getSnapshot() {
  return head_.getSnapshot();
}

RefPtr<Table> Partition::getTable() {
  return table_;
}

PartitionInfo Partition::getInfo() const {
  auto snap = head_.getSnapshot();

  auto checksum = SHA1::compute(
      StringUtil::format("$0~$1", snap->key.toString(), snap->nrecs));

  PartitionInfo pi;
  pi.set_partition_key(snap->key.toString());
  pi.set_table_name(table_->name());
  pi.set_checksum(checksum.toString());
  pi.set_cstable_version(snap->state.cstable_version());
  pi.set_exists(true);
  return pi;
}

RefPtr<PartitionReplication> Partition::getReplicationStrategy(
    RefPtr<ReplicationScheme> repl_scheme,
    http::HTTPConnectionPool* http) {
  switch (table_->storage()) {

    case zbase::TBL_STORAGE_LOG:
      if (upgradeToLSMv2()) {
        return new LSMPartitionReplication(
            this,
            repl_scheme,
            http);
      } else {
        return new LogPartitionReplication(
            this,
            repl_scheme,
            http);
      }

    case zbase::TBL_STORAGE_STATIC:
      return new StaticPartitionReplication(
          this,
          repl_scheme,
          http);

    default:
      RAISE(kRuntimeError, "invalid storage class");

  }
}

bool Partition::upgradeToLSMv2() const {
  return true;
}

}
<commit_msg>set upgradeToLSMv2 to false by default<commit_after>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <zbase/core/Partition.h>
#include <stx/io/fileutil.h>
#include <stx/uri.h>
#include <stx/logging.h>
#include <stx/util/binarymessagewriter.h>
#include <stx/wallclock.h>
#include <stx/protobuf/MessageEncoder.h>
#include <stx/protobuf/MessageDecoder.h>
#include <stx/protobuf/msg.h>
#include <sstable/sstablereader.h>
#include <zbase/core/LogPartitionReader.h>
#include <zbase/core/LogPartitionWriter.h>
#include <zbase/core/LogPartitionReplication.h>
#include <zbase/core/LSMPartitionReader.h>
#include <zbase/core/LSMPartitionWriter.h>
#include <zbase/core/LSMPartitionReplication.h>
#include <zbase/core/StaticPartitionReader.h>
#include <zbase/core/StaticPartitionWriter.h>
#include <zbase/core/StaticPartitionReplication.h>
#include <zbase/z1stats.h>

using namespace stx;

namespace zbase {

RefPtr<Partition> Partition::create(
    const String& tsdb_namespace,
    RefPtr<Table> table,
    const SHA1Hash& partition_key,
    const String& db_path) {
  stx::logDebug(
      "tsdb",
      "Creating new partition; stream='$0' partition='$1'",
      table->name(),
      partition_key.toString());

  auto pdir = FileUtil::joinPaths(
      db_path,
      StringUtil::format(
          "$0/$1/$2",
          tsdb_namespace,
          SHA1::compute(table->name()).toString(),
          partition_key.toString()));

  FileUtil::mkdir_p(pdir);

  auto uuid = Random::singleton()->sha1();

  PartitionState state;
  state.set_tsdb_namespace(tsdb_namespace);
  state.set_partition_key(partition_key.data(), partition_key.size());
  state.set_table_key(table->name());
  state.set_uuid(uuid.data(), uuid.size());

  auto snap = mkRef(new PartitionSnapshot(state, pdir, 0));
  snap->writeToDisk();
  return new Partition(snap, table);
}

RefPtr<Partition> Partition::reopen(
    const String& tsdb_namespace,
    RefPtr<Table> table,
    const SHA1Hash& partition_key,
    const String& db_path) {
  auto pdir = FileUtil::joinPaths(
      db_path,
      StringUtil::format(
          "$0/$1/$2",
          tsdb_namespace,
          SHA1::compute(table->name()).toString(),
          partition_key.toString()));

  auto state = msg::decode<PartitionState>(
      FileUtil::read(FileUtil::joinPaths(pdir, "_snapshot")));

  auto nrecs = 0;
  const auto& files = state.sstable_files();
  for (const auto& f : files) {
    auto is = FileInputStream::openFile(FileUtil::joinPaths(pdir, f));
    auto header = sstable::FileHeaderReader::readMetaPage(is.get());
    nrecs += header.rowCount();
  }

  stx::logTrace(
      "tsdb",
      "Loading partition $0/$1/$2 ($3 records)",
      tsdb_namespace,
      table->name(),
      partition_key.toString(),
      nrecs);

  auto snap = mkRef(new PartitionSnapshot(state, pdir, nrecs));
  return new Partition(snap, table);
}

Partition::Partition(
    RefPtr<PartitionSnapshot> head,
    RefPtr<Table> table) :
    head_(head),
    table_(table) {
  z1stats()->num_partitions_loaded.incr(1);
}

Partition::~Partition() {
  z1stats()->num_partitions_loaded.decr(1);
}

SHA1Hash Partition::uuid() const {
  auto snap = head_.getSnapshot();
  return snap->uuid();
}

RefPtr<PartitionWriter> Partition::getWriter() {
  std::unique_lock<std::mutex> lk(writer_lock_);
  if (writer_.get() == nullptr) {
    switch (table_->storage()) {

      case zbase::TBL_STORAGE_LOG:
        if (upgradeToLSMv2()) {
          writer_ = mkRef<PartitionWriter>(new LSMPartitionWriter(this, &head_));
        } else {
          writer_ = mkRef<PartitionWriter>(new LogPartitionWriter(this, &head_));
        }
        break;

      case zbase::TBL_STORAGE_STATIC:
        writer_ = mkRef<PartitionWriter>(new StaticPartitionWriter(&head_));
        break;

      default:
        RAISE(kRuntimeError, "invalid storage class");

    }
  }

  auto writer = writer_;
  return writer;
}

RefPtr<PartitionReader> Partition::getReader() {
  switch (table_->storage()) {

    case zbase::TBL_STORAGE_LOG:
      if (upgradeToLSMv2()) {
        return new LSMPartitionReader(table_, head_.getSnapshot());
      } else {
        return new LogPartitionReader(table_, head_.getSnapshot());
      }

    case zbase::TBL_STORAGE_STATIC:
      return new StaticPartitionReader(table_, head_.getSnapshot());

    default:
      RAISE(kRuntimeError, "invalid storage class");

  }
}

RefPtr<PartitionSnapshot> Partition::getSnapshot() {
  return head_.getSnapshot();
}

RefPtr<Table> Partition::getTable() {
  return table_;
}

PartitionInfo Partition::getInfo() const {
  auto snap = head_.getSnapshot();

  auto checksum = SHA1::compute(
      StringUtil::format("$0~$1", snap->key.toString(), snap->nrecs));

  PartitionInfo pi;
  pi.set_partition_key(snap->key.toString());
  pi.set_table_name(table_->name());
  pi.set_checksum(checksum.toString());
  pi.set_cstable_version(snap->state.cstable_version());
  pi.set_exists(true);
  return pi;
}

RefPtr<PartitionReplication> Partition::getReplicationStrategy(
    RefPtr<ReplicationScheme> repl_scheme,
    http::HTTPConnectionPool* http) {
  switch (table_->storage()) {

    case zbase::TBL_STORAGE_LOG:
      if (upgradeToLSMv2()) {
        return new LSMPartitionReplication(
            this,
            repl_scheme,
            http);
      } else {
        return new LogPartitionReplication(
            this,
            repl_scheme,
            http);
      }

    case zbase::TBL_STORAGE_STATIC:
      return new StaticPartitionReplication(
          this,
          repl_scheme,
          http);

    default:
      RAISE(kRuntimeError, "invalid storage class");

  }
}

bool Partition::upgradeToLSMv2() const {
  return false;
}

}
<|endoftext|>


<commit_before>/*
* Copyright 2016 Nu-book Inc.
*/
// SPDX-License-Identifier: Apache-2.0

#if (_MSC_VER >= 1915)
#define no_init_all deprecated
#pragma warning(disable : 4996)
#endif

#include "BarcodeReader.h"

#define ZX_USE_UTF8 1 // silence deprecation warning in Result.h

#include "BarcodeFormat.h"
#include "DecodeHints.h"
#include "ReadBarcode.h"
#include "ReadResult.h"
#include "TextUtfEncoding.h"

#include <algorithm>
#include <MemoryBuffer.h>
#include <stdexcept>
#include <wrl.h>

using namespace Microsoft::WRL;
using namespace Windows::Foundation;
using namespace Windows::Graphics::Imaging;

namespace ZXing {

BarcodeReader::BarcodeReader(bool tryHarder, bool tryRotate, const Platform::Array<BarcodeType>^ types)
{
	init(tryHarder, tryRotate, types);
}

BarcodeReader::BarcodeReader(bool tryHarder, bool tryRotate)
{
	init(tryHarder, tryRotate, nullptr);
}

BarcodeReader::BarcodeReader(bool tryHarder)
{
	init(tryHarder, tryHarder, nullptr);
}

void
BarcodeReader::init(bool tryHarder, bool tryRotate, const Platform::Array<BarcodeType>^ types)
{
	m_hints.reset(new DecodeHints());
	m_hints->setTryHarder(tryHarder);
	m_hints->setTryRotate(tryRotate);

	if (types != nullptr && types->Length > 0) {
		BarcodeFormats barcodeFormats;
		for (BarcodeType type : types) {
			barcodeFormats |= BarcodeReader::ConvertRuntimeToNative(type);
		}
		m_hints->setFormats(barcodeFormats);
	}
}

BarcodeReader::~BarcodeReader()
{
}

BarcodeFormat BarcodeReader::ConvertRuntimeToNative(BarcodeType type)
{
	switch (type) {
	case BarcodeType::AZTEC:
		return BarcodeFormat::AZTEC;
	case BarcodeType::CODABAR:
		return BarcodeFormat::CODABAR;
	case BarcodeType::CODE_128:
		return BarcodeFormat::CODE_128;
	case BarcodeType::CODE_39:
		return BarcodeFormat::CODE_39;
	case BarcodeType::CODE_93:
		return BarcodeFormat::CODE_93;
	case BarcodeType::DATA_MATRIX:
		return BarcodeFormat::DATA_MATRIX;
	case BarcodeType::EAN_13:
		return BarcodeFormat::EAN_13;
	case BarcodeType::EAN_8:
		return BarcodeFormat::EAN_8;
	case BarcodeType::ITF:
		return BarcodeFormat::ITF;
	case BarcodeType::MAXICODE:
		return BarcodeFormat::MAXICODE;
	case BarcodeType::PDF_417:
		return BarcodeFormat::PDF_417;
	case BarcodeType::QR_CODE:
		return BarcodeFormat::QR_CODE;
	case BarcodeType::MICRO_QR_CODE:
		return BarcodeFormat::MicroQRCode;
	case BarcodeType::RSS_14:
		return BarcodeFormat::RSS_14;
	case BarcodeType::RSS_EXPANDED:
		return BarcodeFormat::RSS_EXPANDED;
	case BarcodeType::UPC_A:
		return BarcodeFormat::UPC_A;
	case BarcodeType::UPC_E:
		return BarcodeFormat::UPC_E;
	default:
		std::wstring typeAsString = type.ToString()->Begin();
		throw std::invalid_argument("Unknown Barcode Type: " + TextUtfEncoding::ToUtf8(typeAsString));
	}
}

BarcodeType BarcodeReader::ConvertNativeToRuntime(BarcodeFormat format)
{
	switch (format) {
	case BarcodeFormat::AZTEC:
		return BarcodeType::AZTEC;
	case BarcodeFormat::CODABAR:
		return BarcodeType::CODABAR;
	case BarcodeFormat::CODE_128:
		return BarcodeType::CODE_128;
	case BarcodeFormat::CODE_39:
		return BarcodeType::CODE_39;
	case BarcodeFormat::CODE_93:
		return BarcodeType::CODE_93;
	case BarcodeFormat::DATA_MATRIX:
		return BarcodeType::DATA_MATRIX;
	case BarcodeFormat::EAN_13:
		return BarcodeType::EAN_13;
	case BarcodeFormat::EAN_8:
		return BarcodeType::EAN_8;
	case BarcodeFormat::ITF:
		return BarcodeType::ITF;
	case BarcodeFormat::MAXICODE:
		return BarcodeType::MAXICODE;
	case BarcodeFormat::PDF_417:
		return BarcodeType::PDF_417;
	case BarcodeFormat::QR_CODE:
		return BarcodeType::QR_CODE;
	case BarcodeFormat::MicroQRCode:
		return BarcodeType::MICRO_QR_CODE;
	case BarcodeFormat::RSS_14:
		return BarcodeType::RSS_14;
	case BarcodeFormat::RSS_EXPANDED:
		return BarcodeType::RSS_EXPANDED;
	case BarcodeFormat::UPC_A:
		return BarcodeType::UPC_A;
	case BarcodeFormat::UPC_E:
		return BarcodeType::UPC_E;
	default:
		throw std::invalid_argument("Unknown Barcode Format ");
	}
}

static Platform::String^ ToPlatformString(const std::string& str)
{
	std::wstring wstr = TextUtfEncoding::FromUtf8(str);
	return ref new Platform::String(wstr.c_str(), (unsigned)wstr.length());
}

ReadResult^
BarcodeReader::Read(SoftwareBitmap^ bitmap, int cropWidth, int cropHeight)
{
	try {
		cropWidth = cropWidth <= 0 ? bitmap->PixelWidth : std::min(bitmap->PixelWidth, cropWidth);
		cropHeight = cropHeight <= 0 ? bitmap->PixelHeight : std::min(bitmap->PixelHeight, cropHeight);
		int cropLeft = (bitmap->PixelWidth - cropWidth) / 2;
		int cropTop = (bitmap->PixelHeight - cropHeight) / 2;

		auto inBuffer = bitmap->LockBuffer(BitmapBufferAccessMode::Read);
		auto inMemRef = inBuffer->CreateReference();
		ComPtr<IMemoryBufferByteAccess> inBufferAccess;

		if (SUCCEEDED(ComPtr<IUnknown>(reinterpret_cast<IUnknown*>(inMemRef)).As(&inBufferAccess))) {
			BYTE* inBytes = nullptr;
			UINT32 inCapacity = 0;
			inBufferAccess->GetBuffer(&inBytes, &inCapacity);

			ImageFormat fmt = ImageFormat::None;
			switch (bitmap->BitmapPixelFormat)
			{
			case BitmapPixelFormat::Gray8: fmt = ImageFormat::Lum; break;
			case BitmapPixelFormat::Bgra8: fmt = ImageFormat::BGRX; break;
			case BitmapPixelFormat::Rgba8: fmt = ImageFormat::RGBX; break;
			default:
				throw std::runtime_error("Unsupported BitmapPixelFormat");
			}

			auto img = ImageView(inBytes, bitmap->PixelWidth, bitmap->PixelHeight, fmt, inBuffer->GetPlaneDescription(0).Stride)
						   .cropped(cropLeft, cropTop, cropWidth, cropHeight);

			auto result = ReadBarcode(img, *m_hints);
			if (result.isValid()) {
				return ref new ReadResult(ToPlatformString(ZXing::ToString(result.format())), ToPlatformString(result.text()), ConvertNativeToRuntime(result.format()));
			}
		} else {
			throw std::runtime_error("Failed to read bitmap's data");
		}
	}
	catch (const std::exception& e) {
		OutputDebugStringA(e.what());
	}
	catch (...) {
	}
	return nullptr;
}

} // ZXing
<commit_msg>WINRT: replace usage of deprecated BarcodeFormat enum names<commit_after>/*
* Copyright 2016 Nu-book Inc.
*/
// SPDX-License-Identifier: Apache-2.0

#if (_MSC_VER >= 1915)
#define no_init_all deprecated
#pragma warning(disable : 4996)
#endif

#include "BarcodeReader.h"

#define ZX_USE_UTF8 1 // silence deprecation warning in Result.h

#include "BarcodeFormat.h"
#include "DecodeHints.h"
#include "ReadBarcode.h"
#include "ReadResult.h"
#include "TextUtfEncoding.h"

#include <algorithm>
#include <MemoryBuffer.h>
#include <stdexcept>
#include <wrl.h>

using namespace Microsoft::WRL;
using namespace Windows::Foundation;
using namespace Windows::Graphics::Imaging;

namespace ZXing {

BarcodeReader::BarcodeReader(bool tryHarder, bool tryRotate, const Platform::Array<BarcodeType>^ types)
{
	init(tryHarder, tryRotate, types);
}

BarcodeReader::BarcodeReader(bool tryHarder, bool tryRotate)
{
	init(tryHarder, tryRotate, nullptr);
}

BarcodeReader::BarcodeReader(bool tryHarder)
{
	init(tryHarder, tryHarder, nullptr);
}

void
BarcodeReader::init(bool tryHarder, bool tryRotate, const Platform::Array<BarcodeType>^ types)
{
	m_hints.reset(new DecodeHints());
	m_hints->setTryHarder(tryHarder);
	m_hints->setTryRotate(tryRotate);

	if (types != nullptr && types->Length > 0) {
		BarcodeFormats barcodeFormats;
		for (BarcodeType type : types) {
			barcodeFormats |= BarcodeReader::ConvertRuntimeToNative(type);
		}
		m_hints->setFormats(barcodeFormats);
	}
}

BarcodeReader::~BarcodeReader()
{
}

BarcodeFormat BarcodeReader::ConvertRuntimeToNative(BarcodeType type)
{
	switch (type) {
	case BarcodeType::AZTEC:
		return BarcodeFormat::Aztec;
	case BarcodeType::CODABAR:
		return BarcodeFormat::Codabar;
	case BarcodeType::CODE_128:
		return BarcodeFormat::Code128;
	case BarcodeType::CODE_39:
		return BarcodeFormat::Code39;
	case BarcodeType::CODE_93:
		return BarcodeFormat::Code93;
	case BarcodeType::DATA_MATRIX:
		return BarcodeFormat::DataMatrix;
	case BarcodeType::EAN_13:
		return BarcodeFormat::EAN13;
	case BarcodeType::EAN_8:
		return BarcodeFormat::EAN8;
	case BarcodeType::ITF:
		return BarcodeFormat::ITF;
	case BarcodeType::MAXICODE:
		return BarcodeFormat::MaxiCode;
	case BarcodeType::PDF_417:
		return BarcodeFormat::PDF417;
	case BarcodeType::QR_CODE:
		return BarcodeFormat::QRCode;
	case BarcodeType::MICRO_QR_CODE:
		return BarcodeFormat::MicroQRCode;
	case BarcodeType::RSS_14:
		return BarcodeFormat::DataBar;
	case BarcodeType::RSS_EXPANDED:
		return BarcodeFormat::DataBarExpanded;
	case BarcodeType::UPC_A:
		return BarcodeFormat::UPCA;
	case BarcodeType::UPC_E:
		return BarcodeFormat::UPCE;
	default:
		std::wstring typeAsString = type.ToString()->Begin();
		throw std::invalid_argument("Unknown Barcode Type: " + TextUtfEncoding::ToUtf8(typeAsString));
	}
}

BarcodeType BarcodeReader::ConvertNativeToRuntime(BarcodeFormat format)
{
	switch (format) {
	case BarcodeFormat::Aztec:
		return BarcodeType::AZTEC;
	case BarcodeFormat::Codabar:
		return BarcodeType::CODABAR;
	case BarcodeFormat::Code128:
		return BarcodeType::CODE_128;
	case BarcodeFormat::Code39:
		return BarcodeType::CODE_39;
	case BarcodeFormat::Code93:
		return BarcodeType::CODE_93;
	case BarcodeFormat::DataMatrix:
		return BarcodeType::DATA_MATRIX;
	case BarcodeFormat::EAN13:
		return BarcodeType::EAN_13;
	case BarcodeFormat::EAN8:
		return BarcodeType::EAN_8;
	case BarcodeFormat::ITF:
		return BarcodeType::ITF;
	case BarcodeFormat::MaxiCode:
		return BarcodeType::MAXICODE;
	case BarcodeFormat::PDF417:
		return BarcodeType::PDF_417;
	case BarcodeFormat::QRCode:
		return BarcodeType::QR_CODE;
	case BarcodeFormat::MicroQRCode:
		return BarcodeType::MICRO_QR_CODE;
	case BarcodeFormat::DataBar:
		return BarcodeType::RSS_14;
	case BarcodeFormat::DataBarExpanded:
		return BarcodeType::RSS_EXPANDED;
	case BarcodeFormat::UPCA:
		return BarcodeType::UPC_A;
	case BarcodeFormat::UPCE:
		return BarcodeType::UPC_E;
	default:
		throw std::invalid_argument("Unknown Barcode Format ");
	}
}

static Platform::String^ ToPlatformString(const std::string& str)
{
	std::wstring wstr = TextUtfEncoding::FromUtf8(str);
	return ref new Platform::String(wstr.c_str(), (unsigned)wstr.length());
}

ReadResult^
BarcodeReader::Read(SoftwareBitmap^ bitmap, int cropWidth, int cropHeight)
{
	try {
		cropWidth = cropWidth <= 0 ? bitmap->PixelWidth : std::min(bitmap->PixelWidth, cropWidth);
		cropHeight = cropHeight <= 0 ? bitmap->PixelHeight : std::min(bitmap->PixelHeight, cropHeight);
		int cropLeft = (bitmap->PixelWidth - cropWidth) / 2;
		int cropTop = (bitmap->PixelHeight - cropHeight) / 2;

		auto inBuffer = bitmap->LockBuffer(BitmapBufferAccessMode::Read);
		auto inMemRef = inBuffer->CreateReference();
		ComPtr<IMemoryBufferByteAccess> inBufferAccess;

		if (SUCCEEDED(ComPtr<IUnknown>(reinterpret_cast<IUnknown*>(inMemRef)).As(&inBufferAccess))) {
			BYTE* inBytes = nullptr;
			UINT32 inCapacity = 0;
			inBufferAccess->GetBuffer(&inBytes, &inCapacity);

			ImageFormat fmt = ImageFormat::None;
			switch (bitmap->BitmapPixelFormat)
			{
			case BitmapPixelFormat::Gray8: fmt = ImageFormat::Lum; break;
			case BitmapPixelFormat::Bgra8: fmt = ImageFormat::BGRX; break;
			case BitmapPixelFormat::Rgba8: fmt = ImageFormat::RGBX; break;
			default:
				throw std::runtime_error("Unsupported BitmapPixelFormat");
			}

			auto img = ImageView(inBytes, bitmap->PixelWidth, bitmap->PixelHeight, fmt, inBuffer->GetPlaneDescription(0).Stride)
						   .cropped(cropLeft, cropTop, cropWidth, cropHeight);

			auto result = ReadBarcode(img, *m_hints);
			if (result.isValid()) {
				return ref new ReadResult(ToPlatformString(ZXing::ToString(result.format())), ToPlatformString(result.text()), ConvertNativeToRuntime(result.format()));
			}
		} else {
			throw std::runtime_error("Failed to read bitmap's data");
		}
	}
	catch (const std::exception& e) {
		OutputDebugStringA(e.what());
	}
	catch (...) {
	}
	return nullptr;
}

} // ZXing
<|endoftext|>


<commit_before>/*
Copyright (C) 2007 <SWGEmu>

This File is part of Core3.

This program is free software; you can redistribute
it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software
Foundation; either version 2 of the License,
or (at your option) any later version.

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

You should have received a copy of the GNU Lesser General
Public License along with this program; if not, write to
the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

Linking Engine3 statically or dynamically with other modules
is making a combined work based on Engine3.
Thus, the terms and conditions of the GNU Lesser General Public License
cover the whole combination.

In addition, as a special exception, the copyright holders of Engine3
give you permission to combine Engine3 program with free software
programs or libraries that are released under the GNU LGPL and with
code included in the standard release of Core3 under the GNU LGPL
license (or modified versions of such code, with unchanged license).
You may copy and distribute such a system following the terms of the
GNU LGPL for Engine3 and the licenses of the other code concerned,
provided that you include the source code of that other code when
and as the GNU LGPL requires distribution of source code.

Note that people who make modified versions of Engine3 are not obligated
to grant this special exception for their modified versions;
it is their choice whether to do so. The GNU Lesser General Public License
gives permission to release a modified version without this exception;
this exception also makes it possible to release a modified version
which carries forward this exception.
*/

#include "GroupManager.h"

#include "../../ZoneServer.h"
#include "../../Zone.h"

#include "../../../chat/room/ChatRoom.h"

#include "../../objects/creature/CreatureObject.h"
#include "../../objects/creature/CreatureObject.h"

#include "../../objects/group/GroupObject.h"
#include "server/chat/StringIdChatParameter.h"
#include "../../managers/object/ObjectManager.h"

GroupManager::GroupManager() {
}

void GroupManager::inviteToGroup(CreatureObject* leader, CreatureObject* player) {
	// Pre: leader locked
	// Post: player invited to leader's group, leader locked

	Locker clocker(player, leader);

	if (player == leader) {
		leader->sendSystemMessage("@group:invite_no_target_self");
		return;
	}

	if (leader->isGrouped()) {
		ManagedReference<GroupObject*> group = leader->getGroup();

		if (group->getLeader() != leader) {
			leader->sendSystemMessage("@group:must_be_leader");
			return;
		}
	}

	if (player->isGrouped()) {
		StringIdChatParameter stringId;
		stringId.setStringId("group", "already_grouped");
		stringId.setTT(player);
		leader->sendSystemMessage(stringId);
		//leader->sendSystemMessage("group", "already_grouped", player->getObjectID());

		return;
	}

	if (player->getGroupInviterID() == leader->getObjectID()) {
		StringIdChatParameter stringId;
		stringId.setStringId("group", "considering_your_group");
		stringId.setTT(player);
		leader->sendSystemMessage(stringId);
		//leader->sendSystemMessage("group", "considering_your_group", player->getObjectID());

		return;
	} else if (player->getGroupInviterID() != 0) {
		StringBuffer msg;
		msg << player->getCreatureName().toString() << " is considering joining another group.";
		leader->sendSystemMessage(msg.toString());

		return;
	}

	player->updateGroupInviterID(leader->getObjectID());

	StringIdChatParameter stringId;
	stringId.setStringId("group", "invite_target");
	stringId.setTT(leader->getDisplayedName());
	player->sendSystemMessage(stringId);

	stringId.setStringId("group", "invite_leader");
	stringId.setTT(player->getDisplayedName());
	leader->sendSystemMessage(stringId);
}

void GroupManager::joinGroup(CreatureObject* player) {
	//Pre: player locked
	//Post: player locked
	uint64 inviterID = player->getGroupInviterID();

	Zone* zone = player->getZone();

	if (zone == NULL)
		return;

	ManagedReference<ZoneServer*> server = zone->getZoneServer();
	ManagedReference<SceneObject*> object = server->getObject(inviterID);

	if (object == NULL || !object->isPlayerCreature() || object == player)
		return;

	CreatureObject* inviter = cast<CreatureObject*>( object.get());
	GroupObject* group = NULL;

	Locker clocker(inviter, player);

	group = inviter->getGroup();

	if (group == NULL) {
		group = createGroup(inviter);

		if (group == NULL)
			return;
	}

	Locker clocker2(group, player);

	if (group->getGroupSize() == 20) {
		clocker.release();

		player->updateGroupInviterID(0);

		player->sendSystemMessage("@group:full");
		return;
	}

	player->info("joining group");

	group->addMember(player);
	player->updateGroup(group);
	player->sendSystemMessage("@group:joined_self");

	ManagedReference<ChatRoom*> groupChannel = group->getGroupChannel();

	if (groupChannel != NULL && player->isPlayerCreature()) {
		groupChannel->sendTo(cast<CreatureObject*>(player));
		groupChannel->addPlayer(cast<CreatureObject*>(player), false);
	}

	player->updateGroupInviterID(0);
}

GroupObject* GroupManager::createGroup(CreatureObject* leader) {
	// Pre: leader locked
	// Post: GroupObject is a new group with leader, leader locked.
	Zone* zone = leader->getZone();

	if (zone == NULL)
		return NULL;

	ManagedReference<ZoneServer*> server = leader->getZone()->getZoneServer();

	ManagedReference<GroupObject*> group = cast<GroupObject*>( ObjectManager::instance()->createObject(0x13dcb432, 0, ""));
	group->initializeLeader(leader);
	group->startChatRoom();
	group->setZone(leader->getZone());

	group->sendTo(leader, true);

	leader->updateGroup(group);
	leader->sendSystemMessage("@group:formed_self");

	if (leader->getGroupInviterID() != 0)
		leader->updateGroupInviterID(0);

	return group;
}

void GroupManager::leaveGroup(ManagedReference<GroupObject*> group, CreatureObject* player) {
	// Pre: player locked
	// Post: player locked
	if (group == NULL)
		return;

	try {
		Locker clocker(group, player);

		ChatRoom* groupChannel = group->getGroupChannel();
		if (groupChannel != NULL && player->isPlayerCreature()) {
			CreatureObject* playerCreature = cast<CreatureObject*>( player);
			groupChannel->removePlayer(playerCreature, false);
			groupChannel->sendDestroyTo(playerCreature);

			ChatRoom* room = groupChannel->getParent();
			room->sendDestroyTo(playerCreature);
		}

		player->updateGroup(NULL);

		//if (player != NULL && player->isOnline() && !player->isLoggingOut())
		player->sendSystemMessage("@group:removed");

		player->unlock();

		group->removeMember(player);

		group->sendDestroyTo(player);

		player->info("leaving group");

		if (group->getGroupSize() < 2) {
			group->disband();
		}

	} catch (Exception& e) {
		System::out << e.getMessage();
		e.printStackTrace();

	} catch (...) {
		player->wlock();

		throw;
	}

	player->wlock();
}

void GroupManager::disbandGroup(ManagedReference<GroupObject*> group, CreatureObject* player) {
	//Pre: player locked
	//Post: player locked
	player->unlock();

	try {
		group->wlock();
		//The following should never happen, as a check is made in
		//ObjectControlMessage.cpp and removes the player from the group
		//if he's not the leader. Remove?
		//After Fix 13 feb 2009 - Bankler
		if (group->getLeader() != player) {
			player->sendSystemMessage("@group:must_be_leader");
			group->unlock();
			player->wlock();
			return;
		}

		for (int i = 0; i < group->getGroupSize(); i++) {
			CreatureObject* play = cast<CreatureObject*>( group->getGroupMember(i));

			play->sendSystemMessage("@group:disbanded");
		}

		group->disband();

		group->unlock();
	} catch (...) {
		group->unlock();

		player->wlock();

		throw;
	}

	player->wlock();
}

void GroupManager::kickFromGroup(ManagedReference<GroupObject*> group, CreatureObject* player, CreatureObject* playerToKick) {
	// Pre: player is locked, group != NULL
	// Post: playerToKick kicked from group

	player->unlock();

	bool disbanded = false;

	try {
		group->wlock();

		if (!group->hasMember(playerToKick)) {
			group->unlock();
			player->wlock();
			return;
		}

		CreatureObject* leader = cast<CreatureObject*>( group->getLeader());

		if (player != leader) {
			player->sendSystemMessage("@group:must_be_leader");

			group->unlock();

			player->wlock();
			return;
		}

		if (group->getGroupSize() - 1 < 2) {
			for (int i = 0; i < group->getGroupSize(); i++) {
				CreatureObject* play = cast<CreatureObject*>( group->getGroupMember(i));

				play->sendSystemMessage("@group:disbanded");
			}
			group->disband();
			disbanded = true;
		} else {
			group->removeMember(playerToKick);

			playerToKick->sendSystemMessage("@group:removed");

			playerToKick->info("kicking from group");
		}

		group->unlock();

	} catch (...) {
		group->unlock();

		player->wlock();

		throw;
	}

	if (!disbanded) {
		try {
			playerToKick->wlock();

			if (playerToKick->isPlayerCreature()) {
				CreatureObject* pl = cast<CreatureObject*>( playerToKick);
				ManagedReference<ChatRoom*> groupChannel = group->getGroupChannel();
				groupChannel->removePlayer(pl, false);
				groupChannel->sendDestroyTo(pl);

				ManagedReference<ChatRoom*> room = groupChannel->getParent();
				room->sendDestroyTo(pl);
			}

			playerToKick->updateGroup(NULL);

			group->sendDestroyTo(playerToKick);

			playerToKick->unlock();
		} catch (...) {
			playerToKick->unlock();

			player->wlock();

			throw;
		}
	}

	player->wlock();
}

void GroupManager::makeLeader(GroupObject* group, CreatureObject* player, CreatureObject* newLeader) {
	// Pre: player locked
	// Post: player locked
	player->unlock();

	try {
		group->wlock();

		if (group->getLeader() != player) {
			player->sendSystemMessage("@group:must_be_leader");
			group->unlock();
			player->wlock();
			return;
		}

		if (!group->hasMember(newLeader)) {
			group->unlock();
			player->wlock();
			return;
		}

		group->makeLeader(newLeader);

		String firstNameLeader;
		firstNameLeader = "[Offline player]";

		if (newLeader->isPlayerCreature()) {
			CreatureObject* playerLeader = cast<CreatureObject*>( newLeader);

			if (playerLeader->isOnline())
				firstNameLeader= playerLeader->getFirstName();
		}

		StringBuffer message;
		message << firstNameLeader << " is now the group leader.\n";

		for (int i = 0; i < group->getGroupSize(); i++) {
			CreatureObject* play = cast<CreatureObject*>( group->getGroupMember(i));

			play->sendSystemMessage(message.toString());
		}

		group->unlock();
	} catch (...) {
		group->unlock();

		player->wlock();

		throw;
	}

	player->wlock();
}
<commit_msg>(unstable) [fixed] Group invite issue - Mantis 3218<commit_after>/*
Copyright (C) 2007 <SWGEmu>

This File is part of Core3.

This program is free software; you can redistribute
it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software
Foundation; either version 2 of the License,
or (at your option) any later version.

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

You should have received a copy of the GNU Lesser General
Public License along with this program; if not, write to
the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

Linking Engine3 statically or dynamically with other modules
is making a combined work based on Engine3.
Thus, the terms and conditions of the GNU Lesser General Public License
cover the whole combination.

In addition, as a special exception, the copyright holders of Engine3
give you permission to combine Engine3 program with free software
programs or libraries that are released under the GNU LGPL and with
code included in the standard release of Core3 under the GNU LGPL
license (or modified versions of such code, with unchanged license).
You may copy and distribute such a system following the terms of the
GNU LGPL for Engine3 and the licenses of the other code concerned,
provided that you include the source code of that other code when
and as the GNU LGPL requires distribution of source code.

Note that people who make modified versions of Engine3 are not obligated
to grant this special exception for their modified versions;
it is their choice whether to do so. The GNU Lesser General Public License
gives permission to release a modified version without this exception;
this exception also makes it possible to release a modified version
which carries forward this exception.
*/

#include "GroupManager.h"

#include "../../ZoneServer.h"
#include "../../Zone.h"

#include "../../../chat/room/ChatRoom.h"

#include "../../objects/creature/CreatureObject.h"
#include "../../objects/creature/CreatureObject.h"

#include "../../objects/group/GroupObject.h"
#include "server/chat/StringIdChatParameter.h"
#include "../../managers/object/ObjectManager.h"

GroupManager::GroupManager() {
}

void GroupManager::inviteToGroup(CreatureObject* leader, CreatureObject* player) {
	// Pre: leader locked
	// Post: player invited to leader's group, leader locked

	Locker clocker(player, leader);

	if (player == leader) {
		leader->sendSystemMessage("@group:invite_no_target_self");
		return;
	}

	if (leader->isGrouped()) {
		ManagedReference<GroupObject*> group = leader->getGroup();

		if (group->getLeader() != leader) {
			leader->sendSystemMessage("@group:must_be_leader");
			return;
		}
	}

	if (player->isGrouped()) {
		StringIdChatParameter stringId;
		stringId.setStringId("group", "already_grouped");
		stringId.setTT(player);
		leader->sendSystemMessage(stringId);
		//leader->sendSystemMessage("group", "already_grouped", player->getObjectID());

		return;
	}

	if (player->getGroupInviterID() == leader->getObjectID()) {
		StringIdChatParameter stringId;
		stringId.setStringId("group", "considering_your_group");
		stringId.setTT(player);
		leader->sendSystemMessage(stringId);
		//leader->sendSystemMessage("group", "considering_your_group", player->getObjectID());

		return;
	} else if (player->getGroupInviterID() != 0) {
		StringBuffer msg;
		msg << player->getCreatureName().toString() << " is considering joining another group.";
		leader->sendSystemMessage(msg.toString());

		return;
	}

	player->updateGroupInviterID(leader->getObjectID());

	StringIdChatParameter stringId;
	stringId.setStringId("group", "invite_target");
	stringId.setTT(leader->getDisplayedName());
	player->sendSystemMessage(stringId);

	stringId.setStringId("group", "invite_leader");
	stringId.setTT(player->getDisplayedName());
	leader->sendSystemMessage(stringId);
}

void GroupManager::joinGroup(CreatureObject* player) {
	//Pre: player locked
	//Post: player locked
	uint64 inviterID = player->getGroupInviterID();

	Zone* zone = player->getZone();

	if (zone == NULL)
		return;

	ManagedReference<ZoneServer*> server = zone->getZoneServer();
	ManagedReference<SceneObject*> object = server->getObject(inviterID);

	if (object == NULL || !object->isPlayerCreature() || object == player)
		return;

	CreatureObject* inviter = cast<CreatureObject*>( object.get());
	GroupObject* group = NULL;

	Locker clocker(inviter, player);

	group = inviter->getGroup();

	if (group == NULL) {
		group = createGroup(inviter);

		if (group == NULL)
			return;
	}

	Locker clocker2(group, player);

	if (group->getGroupSize() == 20) {
		clocker.release();

		player->updateGroupInviterID(0);

		player->sendSystemMessage("@group:full");
		return;
	}

	// if invite IS in the group but is not the leader
	if ( group->getLeader() != inviter ){
		player->updateGroupInviterID(0);
		StringIdChatParameter param("group", "prose_leader_changed"); // "%TU has abdicated group leadership to %TT."
		param.setTU( inviter->getDisplayedName() );
		param.setTT( group->getLeader()->getDisplayedName() ) ;
		player->sendSystemMessage(param);

		return;
    }

	player->info("joining group");

	group->addMember(player);
	player->updateGroup(group);
	player->sendSystemMessage("@group:joined_self");

	ManagedReference<ChatRoom*> groupChannel = group->getGroupChannel();

	if (groupChannel != NULL && player->isPlayerCreature()) {
		groupChannel->sendTo(cast<CreatureObject*>(player));
		groupChannel->addPlayer(cast<CreatureObject*>(player), false);
	}

	player->updateGroupInviterID(0);
}

GroupObject* GroupManager::createGroup(CreatureObject* leader) {
	// Pre: leader locked
	// Post: GroupObject is a new group with leader, leader locked.
	Zone* zone = leader->getZone();

	if (zone == NULL)
		return NULL;

	ManagedReference<ZoneServer*> server = leader->getZone()->getZoneServer();

	ManagedReference<GroupObject*> group = cast<GroupObject*>( ObjectManager::instance()->createObject(0x13dcb432, 0, ""));
	group->initializeLeader(leader);
	group->startChatRoom();
	group->setZone(leader->getZone());

	group->sendTo(leader, true);

	leader->updateGroup(group);
	leader->sendSystemMessage("@group:formed_self");

	if (leader->getGroupInviterID() != 0)
		leader->updateGroupInviterID(0);

	return group;
}

void GroupManager::leaveGroup(ManagedReference<GroupObject*> group, CreatureObject* player) {
	// Pre: player locked
	// Post: player locked
	if (group == NULL)
		return;

	try {
		Locker clocker(group, player);

		ChatRoom* groupChannel = group->getGroupChannel();
		if (groupChannel != NULL && player->isPlayerCreature()) {
			CreatureObject* playerCreature = cast<CreatureObject*>( player);
			groupChannel->removePlayer(playerCreature, false);
			groupChannel->sendDestroyTo(playerCreature);

			ChatRoom* room = groupChannel->getParent();
			room->sendDestroyTo(playerCreature);
		}

		player->updateGroup(NULL);

		//if (player != NULL && player->isOnline() && !player->isLoggingOut())
		player->sendSystemMessage("@group:removed");

		player->unlock();

		group->removeMember(player);

		group->sendDestroyTo(player);

		player->info("leaving group");

		if (group->getGroupSize() < 2) {
			group->disband();
		}

	} catch (Exception& e) {
		System::out << e.getMessage();
		e.printStackTrace();

	} catch (...) {
		player->wlock();

		throw;
	}

	player->wlock();
}

void GroupManager::disbandGroup(ManagedReference<GroupObject*> group, CreatureObject* player) {
	//Pre: player locked
	//Post: player locked
	player->unlock();

	try {
		group->wlock();
		//The following should never happen, as a check is made in
		//ObjectControlMessage.cpp and removes the player from the group
		//if he's not the leader. Remove?
		//After Fix 13 feb 2009 - Bankler
		if (group->getLeader() != player) {
			player->sendSystemMessage("@group:must_be_leader");
			group->unlock();
			player->wlock();
			return;
		}

		for (int i = 0; i < group->getGroupSize(); i++) {
			CreatureObject* play = cast<CreatureObject*>( group->getGroupMember(i));

			play->sendSystemMessage("@group:disbanded");
		}

		group->disband();

		group->unlock();
	} catch (...) {
		group->unlock();

		player->wlock();

		throw;
	}

	player->wlock();
}

void GroupManager::kickFromGroup(ManagedReference<GroupObject*> group, CreatureObject* player, CreatureObject* playerToKick) {
	// Pre: player is locked, group != NULL
	// Post: playerToKick kicked from group

	player->unlock();

	bool disbanded = false;

	try {
		group->wlock();

		if (!group->hasMember(playerToKick)) {
			group->unlock();
			player->wlock();
			return;
		}

		CreatureObject* leader = cast<CreatureObject*>( group->getLeader());

		if (player != leader) {
			player->sendSystemMessage("@group:must_be_leader");

			group->unlock();

			player->wlock();
			return;
		}

		if (group->getGroupSize() - 1 < 2) {
			for (int i = 0; i < group->getGroupSize(); i++) {
				CreatureObject* play = cast<CreatureObject*>( group->getGroupMember(i));

				play->sendSystemMessage("@group:disbanded");
			}
			group->disband();
			disbanded = true;
		} else {
			group->removeMember(playerToKick);

			playerToKick->sendSystemMessage("@group:removed");

			playerToKick->info("kicking from group");
		}

		group->unlock();

	} catch (...) {
		group->unlock();

		player->wlock();

		throw;
	}

	if (!disbanded) {
		try {
			playerToKick->wlock();

			if (playerToKick->isPlayerCreature()) {
				CreatureObject* pl = cast<CreatureObject*>( playerToKick);
				ManagedReference<ChatRoom*> groupChannel = group->getGroupChannel();
				groupChannel->removePlayer(pl, false);
				groupChannel->sendDestroyTo(pl);

				ManagedReference<ChatRoom*> room = groupChannel->getParent();
				room->sendDestroyTo(pl);
			}

			playerToKick->updateGroup(NULL);

			group->sendDestroyTo(playerToKick);

			playerToKick->unlock();
		} catch (...) {
			playerToKick->unlock();

			player->wlock();

			throw;
		}
	}

	player->wlock();
}

void GroupManager::makeLeader(GroupObject* group, CreatureObject* player, CreatureObject* newLeader) {
	// Pre: player locked
	// Post: player locked
	player->unlock();

	try {
		group->wlock();

		if (group->getLeader() != player) {
			player->sendSystemMessage("@group:must_be_leader");
			group->unlock();
			player->wlock();
			return;
		}

		if (!group->hasMember(newLeader)) {
			group->unlock();
			player->wlock();
			return;
		}

		group->makeLeader(newLeader);

		String firstNameLeader;
		firstNameLeader = "[Offline player]";

		if (newLeader->isPlayerCreature()) {
			CreatureObject* playerLeader = cast<CreatureObject*>( newLeader);

			if (playerLeader->isOnline())
				firstNameLeader= playerLeader->getFirstName();
		}

		StringBuffer message;
		message << firstNameLeader << " is now the group leader.\n";

		for (int i = 0; i < group->getGroupSize(); i++) {
			CreatureObject* play = cast<CreatureObject*>( group->getGroupMember(i));

			play->sendSystemMessage(message.toString());
		}

		group->unlock();
	} catch (...) {
		group->unlock();

		player->wlock();

		throw;
	}

	player->wlock();
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief legends for shaped JSON objects to make them self-contained
///
/// @file
/// Code for legends.
///
/// DISCLAIMER
///
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Copyright 2014-2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "ShapedJson/Legends.h"

using namespace std;
using namespace triagens;
using namespace triagens::basics;

////////////////////////////////////////////////////////////////////////////////
/// Data format of a legend in memory:
///
/// Rough overview description:
///
///   - attribute-ID table
///   - shape table
///   - attribute-ID string data
///   - padding to achieve 8-byte alignment
///   - shape data
///   - padding to achieve 8-byte alignment
///
/// Description of the attribute-ID table (actual binary types in
/// [square brackets]):
///
///   - number of entries [TRI_shape_size_t]
///   - each entry consists of:
///
///       - attribute ID (aid) [TRI_shape_aid_t]
///       - offset to string value, measured from the beginning of the legend
///         [TRI_shape_size_t]
///
/// The entries in the attribute-ID table are sorted by ascending order of
/// shape IDs to allow for binary search if needed.
///
/// Description of the shape table:
///
///   - number of entries [TRI_shape_size_t]
///   - each entry consists of:
///
///       - shape ID (sid) [TRI_shape_sid_t]
///       - offset to shape data, measured from the beginning of the legend
///         [TRI_shape_size_t]
///       - size in bytes of the shape data for this shape ID [TRI_shape_size_t]
///
/// The entries in the shape table are sorted by ascending order of
/// shape IDs to allow for binary search if needed.
///
/// The strings for the attribute IDs are stored one after another, each
/// including a terminating zero byte. At the end of the string data follow
/// zero bytes to pad to a total length that is divisible by 8.
///
/// The actual entries of the shape data is stored one after another. Alignment
/// for each entry is automatically given by the length of the shape data. At
/// the end there is padding to make the length of the total legend divisible
/// by 8.
///
/// Note that the builtin shapes are never dumped and that proper legends
/// contain all attribute IDs
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief clear all data to build a new legend, keep shaper
////////////////////////////////////////////////////////////////////////////////

void JsonLegend::clear () {
  _have_attribute.clear();
  _attribs.clear();
  _att_data.clear();
  _have_shape.clear();
  _shapes.clear();
  _shape_data.clear();
}

////////////////////////////////////////////////////////////////////////////////
/// @brief add an attribute ID to the legend
////////////////////////////////////////////////////////////////////////////////

int JsonLegend::addAttributeId (TRI_shape_aid_t aid) {
  unordered_set<TRI_shape_aid_t>::const_iterator it = _have_attribute.find(aid);
  if (it != _have_attribute.end()) {
    return TRI_ERROR_NO_ERROR;
  }

  char const* p = _shaper->lookupAttributeId(_shaper, aid);
  if (nullptr == p) {
    return TRI_ERROR_AID_NOT_FOUND;
  }

  _have_attribute.insert(it, aid);
  size_t len = strlen(p);
  _attribs.emplace_back(aid, _att_data.length());
  _att_data.appendText(p, len + 1);   // including the zero byte
  return TRI_ERROR_NO_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief add a shape to the legend
////////////////////////////////////////////////////////////////////////////////

int JsonLegend::addShape (TRI_shape_sid_t sid,
                          char const* data, uint32_t len) {
  // data can be 0, then no data is associated, note that if the shape
  // contains an inhomogeneous list as one of its subobjects, then the
  // shape legend could be incomplete, because the actual shapes of
  // the subobject(s) are held only in the data and not in the shaper.
  // In this case this method includes all shapes it can but then
  // returns TRI_ERROR_LEGEND_INCOMPLETE.

  int res = TRI_ERROR_NO_ERROR;

  TRI_shape_t const* shape = nullptr;

  // First the trivial cases:
  if (sid < TRI_FirstCustomShapeIdShaper()) {
    shape = TRI_LookupSidBasicShapeShaper(sid);
  }
  else {
    shape = _shaper->lookupShapeId(_shaper, sid);
    if (nullptr == shape) {
      return TRI_ERROR_LEGEND_INCOMPLETE;
    }

    unordered_set<TRI_shape_sid_t>::const_iterator it = _have_shape.find(sid);
    if (it == _have_shape.end()) {
      _have_shape.insert(it, sid);
      Shape sh(sid, _shape_data.length(), shape->_size);
      _shapes.push_back(sh);
      _shape_data.appendText( reinterpret_cast<char const*>(shape),
                              shape->_size );
    }
  }

  // Now we have to add all attribute IDs and all shapes used by this
  // one recursively, note that the data of this object is in a
  // consistent state, such that we can call ourselves recursively.

  if (shape->_type == TRI_SHAPE_HOMOGENEOUS_SIZED_LIST) {
    // Handle a homogeneous list with equal size entries:
    // Subobjects have fixed size, so in particular no subobject can
    // contain any inhomogeneous list as one of its subobjects,
    // therefore we do not have to hand down actual shaped JSON data.
    TRI_homogeneous_sized_list_shape_t const* shape_spec
      = reinterpret_cast<TRI_homogeneous_sized_list_shape_t const*>
                        (shape);
    res = addShape(shape_spec->_sidEntry, 0, 0);
  }
  else if (shape->_type == TRI_SHAPE_HOMOGENEOUS_LIST) {
    // Handle a homogeneous list:
    // Only one sid, but one of the subobjects could be an
    // inhomogeneous list. We first scan the shape without data, if this
    // goes well, there was no subshape containing an inhomogeneous
    // list! Otherwise, we have to scan all entries of the list.
    TRI_homogeneous_list_shape_t const* shape_spec
      = reinterpret_cast<TRI_homogeneous_list_shape_t const*>
                        (shape);
    res = addShape(shape_spec->_sidEntry, 0, 0);
    if (res == TRI_ERROR_LEGEND_INCOMPLETE) {
      // The subdocuments contain inhomogeneous lists, so we have to
      // scan them all:
      res = TRI_ERROR_NO_ERROR;  // just in case the length is 0
      TRI_shape_length_list_t const* len
        = reinterpret_cast<TRI_shape_length_list_t const*>(data);
      TRI_shape_size_t const* offsets
        = reinterpret_cast<TRI_shape_size_t const*>(len+1);
      TRI_shape_length_list_t i;
      for (i = 0;i < *len;i++) {
        res = addShape(shape_spec->_sidEntry, data + offsets[i],
                                              offsets[i+1]-offsets[i]);
        if (res != TRI_ERROR_NO_ERROR) {
          break;
        }
      }
    }
  }
  else if (shape->_type == TRI_SHAPE_LIST) {
    // Handle an inhomogeneous list:
    // We have to scan recursively all entries of the list since they
    // contain sids in the data area.
    TRI_shape_length_list_t const* len
      = reinterpret_cast<TRI_shape_length_list_t const*>(data);
    TRI_shape_sid_t const* sids
      = reinterpret_cast<TRI_shape_sid_t const*>(len+1);
    TRI_shape_size_t const* offsets
      = reinterpret_cast<TRI_shape_size_t const*>(sids + *len);
    TRI_shape_length_list_t i;
    for (i = 0;i < *len;i++) {
      res = addShape(sids[i], data + offsets[i], offsets[i+1]-offsets[i]);
      if (res != TRI_ERROR_NO_ERROR) {
        break;
      }
    }
  }
  else if (shape->_type == TRI_SHAPE_ARRAY) {
    // Handle an array:
    // Distinguish between fixed size subobjects and variable size
    // subobjects. The fixed ones cannot contain inhomogeneous lists.
    TRI_array_shape_t const* shape_spec
      = reinterpret_cast<TRI_array_shape_t const*> (shape);
    TRI_shape_sid_t const* sids
      = reinterpret_cast<TRI_shape_sid_t const*>(shape_spec+1);
    TRI_shape_aid_t const* aids
      = reinterpret_cast<TRI_shape_aid_t const*>
        (sids + (shape_spec->_fixedEntries + shape_spec->_variableEntries));
    TRI_shape_size_t const* offsets
      = reinterpret_cast<TRI_shape_size_t const*>
        (aids + (shape_spec->_fixedEntries + shape_spec->_variableEntries));
    uint64_t i;
    for (i = 0; res == TRI_ERROR_NO_ERROR &&
                i < shape_spec->_fixedEntries + shape_spec->_variableEntries;
         i++) {
      res = addAttributeId(aids[i]);
    }
    for (i = 0; res == TRI_ERROR_NO_ERROR && i < shape_spec->_fixedEntries;
         i++) {
      // Fixed size subdocs cannot have inhomogeneous lists as subdocs:
      res = addShape(sids[i], 0, 0);
    }
    for (i = 0; res == TRI_ERROR_NO_ERROR && i < shape_spec->_variableEntries;
         i++) {
      addShape(sids[i + shape_spec->_fixedEntries],
               data + offsets[i], offsets[i+1] - offsets[i]);
    }
  }

  return res;
}

static inline TRI_shape_size_t roundup8 (TRI_shape_size_t x) {
  return (x + 7) - ((x + 7) & 7);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief get the total size in bytes of the legend
////////////////////////////////////////////////////////////////////////////////

size_t JsonLegend::getSize () const {
  // Add string pool size and shape pool size and add space for header
  // and tables in bytes.
  return   sizeof(TRI_shape_size_t)                 // number of aids
         + sizeof(AttributeId) * _attribs.size()    // aid entries
         + sizeof(TRI_shape_size_t)                 // number of sids
         + sizeof(Shape) * _shapes.size()           // sid entries
         + roundup8(_att_data.length())             // string data, padded
         + roundup8(_shape_data.length());          // shape data, padded
}

JsonLegend::AttributeComparerClass JsonLegend::AttributeComparerObject;
JsonLegend::ShapeComparerClass JsonLegend::ShapeComparerObject;

////////////////////////////////////////////////////////////////////////////////
/// @brief dump the legend to the buffer pointed to by buf
////////////////////////////////////////////////////////////////////////////////

void JsonLegend::dump (void* buf) {
  // Dump the resulting legend to a given buffer.

  // First sort the aids in ascending order:
  sort(_attribs.begin(), _attribs.end(), AttributeComparerObject);

  // Then sort the sids in ascending order:
  sort(_shapes.begin(), _shapes.end(), ShapeComparerObject);

  // Total length of table data to add to offsets:
  TRI_shape_size_t socle =   sizeof(TRI_shape_size_t)
                           + sizeof(AttributeId) * _attribs.size()
                           + sizeof(TRI_shape_size_t)
                           + sizeof(Shape) * _shapes.size();

  // Attribute ID table:
  TRI_shape_size_t* p = reinterpret_cast<TRI_shape_size_t*>(buf);
  TRI_shape_size_t i;
  *p++ = _attribs.size();
  AttributeId* a = reinterpret_cast<AttributeId*>(p);
  for (i = 0; i < _attribs.size(); i++) {
    _attribs[i].offset += socle;
    *a++ = _attribs[i];
    _attribs[i].offset -= socle;
  }

  // Add the length of the string data to socle for second table:
  size_t const attDataLength = _att_data.length();
  socle += roundup8(attDataLength);

  // shape table:
  size_t const n = _shapes.size();
  p = reinterpret_cast<TRI_shape_size_t*>(a);
  *p++ = n;
  Shape* s = reinterpret_cast<Shape*>(p);
  for (i = 0; i < n; i++) {
    _shapes[i].offset += socle;
    *s++ = _shapes[i];
    _shapes[i].offset -= socle;
  }

  // Attribute ID string data:
  char* c = reinterpret_cast<char*>(s);
  memcpy(c, _att_data.c_str(), attDataLength);
  i = roundup8(attDataLength);
  if (i > attDataLength) {
    memset(c + attDataLength, 0, i - attDataLength);
  }
  c += i;

  // Shape data:
  size_t const shapeDataLength = _shape_data.length();
  memcpy(c, _shape_data.c_str(), shapeDataLength);
  i = roundup8(shapeDataLength);
  if (i > shapeDataLength) {
    memset(c + shapeDataLength, 0, i - shapeDataLength);
  }
}
<commit_msg>legend fix<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief legends for shaped JSON objects to make them self-contained
///
/// @file
/// Code for legends.
///
/// DISCLAIMER
///
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Copyright 2014-2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "ShapedJson/Legends.h"

using namespace std;
using namespace triagens;
using namespace triagens::basics;

////////////////////////////////////////////////////////////////////////////////
/// Data format of a legend in memory:
///
/// Rough overview description:
///
///   - attribute-ID table
///   - shape table
///   - attribute-ID string data
///   - padding to achieve 8-byte alignment
///   - shape data
///   - padding to achieve 8-byte alignment
///
/// Description of the attribute-ID table (actual binary types in
/// [square brackets]):
///
///   - number of entries [TRI_shape_size_t]
///   - each entry consists of:
///
///       - attribute ID (aid) [TRI_shape_aid_t]
///       - offset to string value, measured from the beginning of the legend
///         [TRI_shape_size_t]
///
/// The entries in the attribute-ID table are sorted by ascending order of
/// shape IDs to allow for binary search if needed.
///
/// Description of the shape table:
///
///   - number of entries [TRI_shape_size_t]
///   - each entry consists of:
///
///       - shape ID (sid) [TRI_shape_sid_t]
///       - offset to shape data, measured from the beginning of the legend
///         [TRI_shape_size_t]
///       - size in bytes of the shape data for this shape ID [TRI_shape_size_t]
///
/// The entries in the shape table are sorted by ascending order of
/// shape IDs to allow for binary search if needed.
///
/// The strings for the attribute IDs are stored one after another, each
/// including a terminating zero byte. At the end of the string data follow
/// zero bytes to pad to a total length that is divisible by 8.
///
/// The actual entries of the shape data is stored one after another. Alignment
/// for each entry is automatically given by the length of the shape data. At
/// the end there is padding to make the length of the total legend divisible
/// by 8.
///
/// Note that the builtin shapes are never dumped and that proper legends
/// contain all attribute IDs
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief clear all data to build a new legend, keep shaper
////////////////////////////////////////////////////////////////////////////////

void JsonLegend::clear () {
  _have_attribute.clear();
  _attribs.clear();
  _att_data.clear();
  _have_shape.clear();
  _shapes.clear();
  _shape_data.clear();
}

////////////////////////////////////////////////////////////////////////////////
/// @brief add an attribute ID to the legend
////////////////////////////////////////////////////////////////////////////////

int JsonLegend::addAttributeId (TRI_shape_aid_t aid) {
  unordered_set<TRI_shape_aid_t>::const_iterator it = _have_attribute.find(aid);
  if (it != _have_attribute.end()) {
    return TRI_ERROR_NO_ERROR;
  }

  char const* p = _shaper->lookupAttributeId(_shaper, aid);
  if (nullptr == p) {
    return TRI_ERROR_AID_NOT_FOUND;
  }

  _have_attribute.insert(it, aid);
  size_t len = strlen(p);
  _attribs.emplace_back(aid, _att_data.length());
  _att_data.appendText(p, len + 1);   // including the zero byte
  return TRI_ERROR_NO_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief add a shape to the legend
////////////////////////////////////////////////////////////////////////////////

int JsonLegend::addShape (TRI_shape_sid_t sid,
                          char const* data,
                          uint32_t len) {
  // data can be 0, then no data is associated, note that if the shape
  // contains an inhomogeneous list as one of its subobjects, then the
  // shape legend could be incomplete, because the actual shapes of
  // the subobject(s) are held only in the data and not in the shaper.
  // In this case this method includes all shapes it can but then
  // returns TRI_ERROR_LEGEND_INCOMPLETE.
  int res = TRI_ERROR_NO_ERROR;

  TRI_shape_t const* shape = nullptr;

  // First the trivial cases:
  if (sid < TRI_FirstCustomShapeIdShaper()) {
    shape = TRI_LookupSidBasicShapeShaper(sid);

    TRI_ASSERT(shape != nullptr);
  }
  else {
    shape = _shaper->lookupShapeId(_shaper, sid);

    if (nullptr == shape) {
      return TRI_ERROR_LEGEND_INCOMPLETE;
    }

    unordered_set<TRI_shape_sid_t>::const_iterator it = _have_shape.find(sid);

    if (it == _have_shape.end()) {
      _have_shape.insert(it, sid);
      Shape sh(sid, _shape_data.length(), shape->_size);
      _shapes.push_back(sh);
      _shape_data.appendText(reinterpret_cast<char const*>(shape), shape->_size);
    }
  }

  // Now we have to add all attribute IDs and all shapes used by this
  // one recursively, note that the data of this object is in a
  // consistent state, such that we can call ourselves recursively.

  if (shape->_type == TRI_SHAPE_HOMOGENEOUS_SIZED_LIST) {
    // Handle a homogeneous list with equal size entries:
    // Subobjects have fixed size, so in particular no subobject can
    // contain any inhomogeneous list as one of its subobjects,
    // therefore we do not have to hand down actual shaped JSON data.
    TRI_homogeneous_sized_list_shape_t const* shape_spec
      = reinterpret_cast<TRI_homogeneous_sized_list_shape_t const*>(shape);
    res = addShape(shape_spec->_sidEntry, nullptr, 0);
  }
  else if (shape->_type == TRI_SHAPE_HOMOGENEOUS_LIST) {
    // Handle a homogeneous list:
    // Only one sid, but one of the subobjects could be an
    // inhomogeneous list. We first scan the shape without data, if this
    // goes well, there was no subshape containing an inhomogeneous
    // list! Otherwise, we have to scan all entries of the list.
    TRI_homogeneous_list_shape_t const* shape_spec
      = reinterpret_cast<TRI_homogeneous_list_shape_t const*>
                        (shape);
    res = addShape(shape_spec->_sidEntry, nullptr, 0);

    if (res == TRI_ERROR_LEGEND_INCOMPLETE) {
      // The subdocuments contain inhomogeneous lists, so we have to
      // scan them all:
      TRI_ASSERT(data != nullptr);

      res = TRI_ERROR_NO_ERROR;  // just in case the length is 0
      TRI_shape_length_list_t const* len
        = reinterpret_cast<TRI_shape_length_list_t const*>(data);
      TRI_shape_size_t const* offsets
        = reinterpret_cast<TRI_shape_size_t const*>(len + 1);
      TRI_shape_length_list_t i;
      for (i = 0; i < *len; i++) {
        res = addShape(shape_spec->_sidEntry, data + offsets[i],
                                              offsets[i + 1] - offsets[i]);
        if (res != TRI_ERROR_NO_ERROR) {
          break;
        }
      }
    }
  }
  else if (shape->_type == TRI_SHAPE_LIST) {
    // Handle an inhomogeneous list:
    // We have to scan recursively all entries of the list since they
    // contain sids in the data area.
    TRI_ASSERT(data != nullptr);

    TRI_shape_length_list_t const* len = reinterpret_cast<TRI_shape_length_list_t const*>(data);
    TRI_shape_sid_t const* sids = reinterpret_cast<TRI_shape_sid_t const*>(len + 1);
    TRI_shape_size_t const* offsets = reinterpret_cast<TRI_shape_size_t const*>(sids + *len);
    TRI_shape_length_list_t i;

    for (i = 0; i < *len; i++) {
      res = addShape(sids[i], data + offsets[i], offsets[i + 1] - offsets[i]);

      if (res != TRI_ERROR_NO_ERROR) {
        break;
      }
    }
  }
  else if (shape->_type == TRI_SHAPE_ARRAY) {
    // Handle an array:
    // Distinguish between fixed size subobjects and variable size
    // subobjects. The fixed ones cannot contain inhomogeneous lists.
    TRI_array_shape_t const* shape_spec = reinterpret_cast<TRI_array_shape_t const*>(shape);
    TRI_shape_sid_t const* sids = reinterpret_cast<TRI_shape_sid_t const*>(shape_spec + 1);
    TRI_shape_aid_t const* aids = reinterpret_cast<TRI_shape_aid_t const*>(sids + (shape_spec->_fixedEntries + shape_spec->_variableEntries));
    TRI_shape_size_t const* offsets = reinterpret_cast<TRI_shape_size_t const*>(data);
    char const* base = reinterpret_cast<char const*>(offsets);
    uint64_t i;
    for (i = 0; res == TRI_ERROR_NO_ERROR &&
                i < shape_spec->_fixedEntries + shape_spec->_variableEntries;
         i++) {
      res = addAttributeId(aids[i]);
    }
    for (i = 0; res == TRI_ERROR_NO_ERROR && i < shape_spec->_fixedEntries;
         i++) {
      // Fixed size subdocs cannot have inhomogeneous lists as subdocs:
      res = addShape(sids[i], nullptr, 0);
    }
    for (i = 0; res == TRI_ERROR_NO_ERROR && i < shape_spec->_variableEntries;
         i++) {
      addShape(sids[i + shape_spec->_fixedEntries],
               base + offsets[i], offsets[i + 1] - offsets[i]);
    }
  }

  return res;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief round a value to the next multiple of 8
////////////////////////////////////////////////////////////////////////////////

static inline TRI_shape_size_t roundup8 (TRI_shape_size_t x) {
  return (x + 7) - ((x + 7) & 7);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief get the total size in bytes of the legend
////////////////////////////////////////////////////////////////////////////////

size_t JsonLegend::getSize () const {
  // Add string pool size and shape pool size and add space for header
  // and tables in bytes.
  return   sizeof(TRI_shape_size_t)                 // number of aids
         + sizeof(AttributeId) * _attribs.size()    // aid entries
         + sizeof(TRI_shape_size_t)                 // number of sids
         + sizeof(Shape) * _shapes.size()           // sid entries
         + roundup8(_att_data.length())             // string data, padded
         + roundup8(_shape_data.length());          // shape data, padded
}

JsonLegend::AttributeComparerClass JsonLegend::AttributeComparerObject;
JsonLegend::ShapeComparerClass JsonLegend::ShapeComparerObject;

////////////////////////////////////////////////////////////////////////////////
/// @brief dump the legend to the buffer pointed to by buf
////////////////////////////////////////////////////////////////////////////////

void JsonLegend::dump (void* buf) {
  // Dump the resulting legend to a given buffer.

  // First sort the aids in ascending order:
  sort(_attribs.begin(), _attribs.end(), AttributeComparerObject);

  // Then sort the sids in ascending order:
  sort(_shapes.begin(), _shapes.end(), ShapeComparerObject);

  // Total length of table data to add to offsets:
  TRI_shape_size_t socle =   sizeof(TRI_shape_size_t)
                           + sizeof(AttributeId) * _attribs.size()
                           + sizeof(TRI_shape_size_t)
                           + sizeof(Shape) * _shapes.size();

  // Attribute ID table:
  TRI_shape_size_t* p = reinterpret_cast<TRI_shape_size_t*>(buf);
  TRI_shape_size_t i;
  *p++ = _attribs.size();
  AttributeId* a = reinterpret_cast<AttributeId*>(p);
  for (i = 0; i < _attribs.size(); i++) {
    _attribs[i].offset += socle;
    *a++ = _attribs[i];
    _attribs[i].offset -= socle;
  }

  // Add the length of the string data to socle for second table:
  size_t const attDataLength = _att_data.length();
  socle += roundup8(attDataLength);

  // shape table:
  size_t const n = _shapes.size();
  p = reinterpret_cast<TRI_shape_size_t*>(a);
  *p++ = n;
  Shape* s = reinterpret_cast<Shape*>(p);
  for (i = 0; i < n; i++) {
    _shapes[i].offset += socle;
    *s++ = _shapes[i];
    _shapes[i].offset -= socle;
  }

  // Attribute ID string data:
  char* c = reinterpret_cast<char*>(s);
  memcpy(c, _att_data.c_str(), attDataLength);
  i = roundup8(attDataLength);
  if (i > attDataLength) {
    memset(c + attDataLength, 0, i - attDataLength);
  }
  c += i;

  // Shape data:
  size_t const shapeDataLength = _shape_data.length();
  memcpy(c, _shape_data.c_str(), shapeDataLength);
  i = roundup8(shapeDataLength);
  if (i > shapeDataLength) {
    memset(c + shapeDataLength, 0, i - shapeDataLength);
  }
}
<|endoftext|>


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

#include <type_traits>

#include "itkMetaProgrammingLibrary.h"
#include "itkStaticAssert.h"

int
itkMetaProgrammingLibraryTest(int, char *[])
{
  using namespace itk::mpl;

#if !defined(ITK_LEGACY_REMOVE)

  // Or between constants
  itkStaticAssert((OrC<true, true, true>::Value == true), "Unit test failed");
  itkStaticAssert((OrC<true, false, true>::Value == true), "Unit test failed");
  itkStaticAssert((OrC<true, true, false>::Value == true), "Unit test failed");
  itkStaticAssert((OrC<false, false, true>::Value == true), "Unit test failed");
  itkStaticAssert((OrC<true, false, false>::Value == true), "Unit test failed");
  itkStaticAssert((OrC<false, true, false>::Value == true), "Unit test failed");
  itkStaticAssert((OrC<false, false, false>::Value == false), "Unit test failed");

  itkStaticAssert((OrC<true, true>::Value == true), "Unit test failed");
  itkStaticAssert((OrC<true, false>::Value == true), "Unit test failed");
  itkStaticAssert((OrC<false, true>::Value == true), "Unit test failed");
  itkStaticAssert((OrC<false, false>::Value == false), "Unit test failed");

  // Or between types
  itkStaticAssert((std::is_same<Or<TrueType, TrueType, TrueType>::Type, TrueType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<Or<TrueType, FalseType, TrueType>::Type, TrueType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<Or<TrueType, TrueType, FalseType>::Type, TrueType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<Or<FalseType, FalseType, TrueType>::Type, TrueType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<Or<TrueType, FalseType, FalseType>::Type, TrueType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<Or<FalseType, TrueType, FalseType>::Type, TrueType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<Or<FalseType, FalseType, FalseType>::Type, FalseType>::value), "Unit test failed");

  itkStaticAssert((std::is_same<Or<TrueType, TrueType>::Type, TrueType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<Or<TrueType, FalseType>::Type, TrueType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<Or<FalseType, TrueType>::Type, TrueType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<Or<FalseType, FalseType>::Type, FalseType>::value), "Unit test failed");

  // And between constants
  itkStaticAssert((AndC<true, true>::Value == true), "Unit test failed");
  itkStaticAssert((AndC<true, false>::Value == false), "Unit test failed");
  itkStaticAssert((AndC<false, true>::Value == false), "Unit test failed");
  itkStaticAssert((AndC<false, false>::Value == false), "Unit test failed");

  // And between types
  itkStaticAssert((std::is_same<And<TrueType, TrueType>::Type, TrueType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<And<TrueType, FalseType>::Type, FalseType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<And<FalseType, TrueType>::Type, FalseType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<And<FalseType, FalseType>::Type, FalseType>::value), "Unit test failed");

  // Xor between constants
  itkStaticAssert((XorC<true, true>::Value == false), "Unit test failed");
  itkStaticAssert((XorC<true, false>::Value == true), "Unit test failed");
  itkStaticAssert((XorC<false, true>::Value == true), "Unit test failed");
  itkStaticAssert((XorC<false, false>::Value == false), "Unit test failed");

  // Xor between types
  itkStaticAssert((std::is_same<Xor<TrueType, TrueType>::Type, FalseType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<Xor<TrueType, FalseType>::Type, TrueType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<Xor<FalseType, TrueType>::Type, TrueType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<Xor<FalseType, FalseType>::Type, FalseType>::value), "Unit test failed");

  // Not between constants
  itkStaticAssert((NotC<true>::Value == false), "Unit test failed");
  itkStaticAssert((NotC<false>::Value == true), "Unit test failed");

  // Not between types
  itkStaticAssert((std::is_same<Not<TrueType>::Type, FalseType>::value), "Unit test failed");
  itkStaticAssert((std::is_same<Not<FalseType>::Type, TrueType>::value), "Unit test failed");

#endif

  return EXIT_SUCCESS;
}
<commit_msg>ENH: replace itkStaticAssert by STL's static_assert<commit_after>/*=========================================================================
 *
 *  Copyright NumFOCUS
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include <type_traits>

#include "itkMetaProgrammingLibrary.h"

int
itkMetaProgrammingLibraryTest(int, char *[])
{
  using namespace itk::mpl;

  // Or between constants
  static_assert((OrC<true, true, true>::Value == true), "Unit test failed");
  static_assert((OrC<true, false, true>::Value == true), "Unit test failed");
  static_assert((OrC<true, true, false>::Value == true), "Unit test failed");
  static_assert((OrC<false, false, true>::Value == true), "Unit test failed");
  static_assert((OrC<true, false, false>::Value == true), "Unit test failed");
  static_assert((OrC<false, true, false>::Value == true), "Unit test failed");
  static_assert((OrC<false, false, false>::Value == false), "Unit test failed");

  static_assert((OrC<true, true>::Value == true), "Unit test failed");
  static_assert((OrC<true, false>::Value == true), "Unit test failed");
  static_assert((OrC<false, true>::Value == true), "Unit test failed");
  static_assert((OrC<false, false>::Value == false), "Unit test failed");

  // Or between types
  static_assert((std::is_same<Or<TrueType, TrueType, TrueType>::Type, TrueType>::value), "Unit test failed");
  static_assert((std::is_same<Or<TrueType, FalseType, TrueType>::Type, TrueType>::value), "Unit test failed");
  static_assert((std::is_same<Or<TrueType, TrueType, FalseType>::Type, TrueType>::value), "Unit test failed");
  static_assert((std::is_same<Or<FalseType, FalseType, TrueType>::Type, TrueType>::value), "Unit test failed");
  static_assert((std::is_same<Or<TrueType, FalseType, FalseType>::Type, TrueType>::value), "Unit test failed");
  static_assert((std::is_same<Or<FalseType, TrueType, FalseType>::Type, TrueType>::value), "Unit test failed");
  static_assert((std::is_same<Or<FalseType, FalseType, FalseType>::Type, FalseType>::value), "Unit test failed");

  static_assert((std::is_same<Or<TrueType, TrueType>::Type, TrueType>::value), "Unit test failed");
  static_assert((std::is_same<Or<TrueType, FalseType>::Type, TrueType>::value), "Unit test failed");
  static_assert((std::is_same<Or<FalseType, TrueType>::Type, TrueType>::value), "Unit test failed");
  static_assert((std::is_same<Or<FalseType, FalseType>::Type, FalseType>::value), "Unit test failed");

  // And between constants
  static_assert((AndC<true, true>::Value == true), "Unit test failed");
  static_assert((AndC<true, false>::Value == false), "Unit test failed");
  static_assert((AndC<false, true>::Value == false), "Unit test failed");
  static_assert((AndC<false, false>::Value == false), "Unit test failed");

  // And between types
  static_assert((std::is_same<And<TrueType, TrueType>::Type, TrueType>::value), "Unit test failed");
  static_assert((std::is_same<And<TrueType, FalseType>::Type, FalseType>::value), "Unit test failed");
  static_assert((std::is_same<And<FalseType, TrueType>::Type, FalseType>::value), "Unit test failed");
  static_assert((std::is_same<And<FalseType, FalseType>::Type, FalseType>::value), "Unit test failed");

  // Xor between constants
  static_assert((XorC<true, true>::Value == false), "Unit test failed");
  static_assert((XorC<true, false>::Value == true), "Unit test failed");
  static_assert((XorC<false, true>::Value == true), "Unit test failed");
  static_assert((XorC<false, false>::Value == false), "Unit test failed");

  // Xor between types
  static_assert((std::is_same<Xor<TrueType, TrueType>::Type, FalseType>::value), "Unit test failed");
  static_assert((std::is_same<Xor<TrueType, FalseType>::Type, TrueType>::value), "Unit test failed");
  static_assert((std::is_same<Xor<FalseType, TrueType>::Type, TrueType>::value), "Unit test failed");
  static_assert((std::is_same<Xor<FalseType, FalseType>::Type, FalseType>::value), "Unit test failed");

  // Not between constants
  static_assert((NotC<true>::Value == false), "Unit test failed");
  static_assert((NotC<false>::Value == true), "Unit test failed");

  // Not between types
  static_assert((std::is_same<Not<TrueType>::Type, FalseType>::value), "Unit test failed");
  static_assert((std::is_same<Not<FalseType>::Type, TrueType>::value), "Unit test failed");

  return EXIT_SUCCESS;
}
<|endoftext|>