<commit_before>/**
 * @file	pci_device_base.cpp
 * @brief	PCI デバイス基底クラス実装。
 * @author	Masakazu Asama <m-asama@ginzado.co.jp>
 */

#include "pci_device_management.h"

#include "pci_device_base.h"

pci_device_base::pci_device_base()
	: m_bus(-1), m_slot(-1)
{
}

pci_device_base::~pci_device_base()
{
}

bool
pci_device_base::operator==(const pci_device_base &rhs)
{
	if ((m_bus == rhs.m_bus)
	 && (m_slot == rhs.m_slot)) {
		return true;
	}
	return false;
}

bool
pci_device_base::operator>(const pci_device_base &rhs)
{
	if ((m_bus > rhs.m_bus)
	 || ((m_bus == rhs.m_bus)
	  && (m_slot > rhs.m_slot))) {
		return true;
	}
	return false;
}

void
pci_device_base::bus(sint16_t bus)
{
	m_bus = bus;
}

sint16_t
pci_device_base::bus()
{
	return m_bus;
}

void
pci_device_base::slot(sint16_t slot)
{
	m_slot = slot;
}

sint16_t
pci_device_base::slot()
{
	return m_slot;
}

utf8str
pci_device_base::pci_dump()
{
	utf8str s;
	s += "Bus: ";
	s.append_hex64(m_bus, 2);
	s += " Slot: ";
	s.append_hex64(m_slot, 2);
	s += "\n";
	s += "    Vendor ID: ";
	s.append_hex64(pci_config_read_uint16(m_bus, m_slot, 0, 0x00), 4);
	s += " Device ID: ";
	s.append_hex64(pci_config_read_uint16(m_bus, m_slot, 0, 0x02), 4);
	s += "\n";
	s += "    Command: ";
	s.append_hex64(pci_config_read_uint16(m_bus, m_slot, 0, 0x04), 4);
	s += " Status: ";
	s.append_hex64(pci_config_read_uint16(m_bus, m_slot, 0, 0x06), 4);
	s += "\n";
	s += "    Revision ID: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x08), 2);
	s += " Class Code: ";
	s.append_hex64((pci_config_read_uint32(m_bus, m_slot, 0, 0x08) >> 8), 6);
	s += "\n";
	s += "    Cacheline Size: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x0c), 2);
	s += " Latency Timer: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x0d), 2);
	s += " Header Type: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x0e), 2);
	s += " BIST: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x0f), 2);
	s += "\n";
	s += "    Base Address Register 1: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x10), 8);
	s += "\n";
	s += "    Base Address Register 2: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x14), 8);
	s += "\n";
	s += "    Base Address Register 3: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x18), 8);
	s += "\n";
	s += "    Base Address Register 4: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x1c), 8);
	s += "\n";
	s += "    Base Address Register 5: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x20), 8);
	s += "\n";
	s += "    Base Address Register 6: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x24), 8);
	s += "\n";
	s += "    Cardbus CIS Pointer: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x28), 8);
	s += "\n";
	s += "    Subsystem Vendor ID: ";
	s.append_hex64(pci_config_read_uint16(m_bus, m_slot, 0, 0x2c), 4);
	s += " Subsystem ID: ";
	s.append_hex64(pci_config_read_uint16(m_bus, m_slot, 0, 0x2e), 4);
	s += "\n";
	s += "    Expansion ROM Base Address: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x30), 8);
	s += "\n";
	s += "    Capabilities Pointer: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x34), 2);
	s += " Reserved: ";
	s.append_hex64((pci_config_read_uint32(m_bus, m_slot, 0, 0x34) >> 8), 6);
	s += "\n";
	s += "    Reserved: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x38), 8);
	s += "\n";
	s += "    Interrupt Line: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x3c), 2);
	s += " Interrupt Pin: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x3d), 2);
	s += " Min_Gnt: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x3e), 2);
	s += " Max_Lat: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x3f), 2);
	s += "\n";

	s += "    Capabilities List:\n";
	uint8_t capp = pci_config_read_uint8(m_bus, m_slot, 0, 0x34);
	while (capp != 0x00) {
		uint8_t capid = pci_config_read_uint8(m_bus, m_slot, 0, capp);
		s += "        Capability ID: ";
		s.append_hex64(capid, 2);
		switch (capid) {
		case 0x01: s += " (PCI Power Management Interface)\n"; break;
		case 0x02: s += " (AGP)\n"; break;
		case 0x03: s += " (VPD)\n"; break;
		case 0x04: s += " (Slot Identification)\n"; break;
		case 0x05: s += " (Message Signaled Interrupts)\n"; break;
		case 0x06: s += " (CompactPCI Hot Swap)\n"; break;
		case 0x07: s += " (PCI-X)\n"; break;
		case 0x08: s += " (HyperTransport)\n"; break;
		case 0x09: s += " (Vendor Specific)\n"; break;
		case 0x0a: s += " (Debug port)\n"; break;
		case 0x0b: s += " (CompactPCI central resource control)\n"; break;
		case 0x0c: s += " (PCI Hot-Plug)\n"; break;
		case 0x0d: s += " (PCI Bridge Subsystem Vendor ID)\n"; break;
		case 0x0e: s += " (AGP 8x)\n"; break;
		case 0x0f: s += " (Secure Device)\n"; break;
		case 0x10: s += " (PCI Express)\n"; break;
		case 0x11: s += " (MSI-X)\n"; break;
		default:
			s += " (Unknown Capability)\n";
		}
		capp = pci_config_read_uint8(m_bus, m_slot, 0, capp + 1);
	}

	return s;
}

<commit_msg>PCI デバイスのデバッグダンプのケイパビリティに MSI-X の情報を追加。<commit_after>/**
 * @file	pci_device_base.cpp
 * @brief	PCI デバイス基底クラス実装。
 * @author	Masakazu Asama <m-asama@ginzado.co.jp>
 */

#include "pci_device_management.h"

#include "pci_device_base.h"

pci_device_base::pci_device_base()
	: m_bus(-1), m_slot(-1)
{
}

pci_device_base::~pci_device_base()
{
}

bool
pci_device_base::operator==(const pci_device_base &rhs)
{
	if ((m_bus == rhs.m_bus)
	 && (m_slot == rhs.m_slot)) {
		return true;
	}
	return false;
}

bool
pci_device_base::operator>(const pci_device_base &rhs)
{
	if ((m_bus > rhs.m_bus)
	 || ((m_bus == rhs.m_bus)
	  && (m_slot > rhs.m_slot))) {
		return true;
	}
	return false;
}

void
pci_device_base::bus(sint16_t bus)
{
	m_bus = bus;
}

sint16_t
pci_device_base::bus()
{
	return m_bus;
}

void
pci_device_base::slot(sint16_t slot)
{
	m_slot = slot;
}

sint16_t
pci_device_base::slot()
{
	return m_slot;
}

utf8str
pci_device_base::pci_dump()
{
	utf8str s;
	s += "Bus: ";
	s.append_hex64(m_bus, 2);
	s += " Slot: ";
	s.append_hex64(m_slot, 2);
	s += "\n";
	s += "    Vendor ID: ";
	s.append_hex64(pci_config_read_uint16(m_bus, m_slot, 0, 0x00), 4);
	s += " Device ID: ";
	s.append_hex64(pci_config_read_uint16(m_bus, m_slot, 0, 0x02), 4);
	s += "\n";
	s += "    Command: ";
	s.append_hex64(pci_config_read_uint16(m_bus, m_slot, 0, 0x04), 4);
	s += " Status: ";
	s.append_hex64(pci_config_read_uint16(m_bus, m_slot, 0, 0x06), 4);
	s += "\n";
	s += "    Revision ID: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x08), 2);
	s += " Class Code: ";
	s.append_hex64((pci_config_read_uint32(m_bus, m_slot, 0, 0x08) >> 8), 6);
	s += "\n";
	s += "    Cacheline Size: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x0c), 2);
	s += " Latency Timer: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x0d), 2);
	s += " Header Type: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x0e), 2);
	s += " BIST: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x0f), 2);
	s += "\n";
	if (pci_config_read_uint8(m_bus, m_slot, 0, 0x0e) != 0x00) {
		return s;
	}
	s += "    Base Address Register 1: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x10), 8);
	s += "\n";
	s += "    Base Address Register 2: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x14), 8);
	s += "\n";
	s += "    Base Address Register 3: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x18), 8);
	s += "\n";
	s += "    Base Address Register 4: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x1c), 8);
	s += "\n";
	s += "    Base Address Register 5: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x20), 8);
	s += "\n";
	s += "    Base Address Register 6: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x24), 8);
	s += "\n";
	s += "    Cardbus CIS Pointer: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x28), 8);
	s += "\n";
	s += "    Subsystem Vendor ID: ";
	s.append_hex64(pci_config_read_uint16(m_bus, m_slot, 0, 0x2c), 4);
	s += " Subsystem ID: ";
	s.append_hex64(pci_config_read_uint16(m_bus, m_slot, 0, 0x2e), 4);
	s += "\n";
	s += "    Expansion ROM Base Address: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x30), 8);
	s += "\n";
	s += "    Capabilities Pointer: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x34), 2);
	s += " Reserved: ";
	s.append_hex64((pci_config_read_uint32(m_bus, m_slot, 0, 0x34) >> 8), 6);
	s += "\n";
	s += "    Reserved: ";
	s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, 0x38), 8);
	s += "\n";
	s += "    Interrupt Line: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x3c), 2);
	s += " Interrupt Pin: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x3d), 2);
	s += " Min_Gnt: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x3e), 2);
	s += " Max_Lat: ";
	s.append_hex64(pci_config_read_uint8(m_bus, m_slot, 0, 0x3f), 2);
	s += "\n";

	s += "    Capabilities List:\n";
	uint8_t capp = pci_config_read_uint8(m_bus, m_slot, 0, 0x34) & 0xfc;
	while (capp != 0x00) {
		uint8_t capid = pci_config_read_uint8(m_bus, m_slot, 0, capp);
		s += "        Capability ID: ";
		s.append_hex64(capid, 2);
		switch (capid) {
		case 0x01: s += " (PCI Power Management Interface)\n"; break;
		case 0x02: s += " (AGP)\n"; break;
		case 0x03: s += " (VPD)\n"; break;
		case 0x04: s += " (Slot Identification)\n"; break;
		case 0x05: s += " (Message Signaled Interrupts)\n"; break;
		case 0x06: s += " (CompactPCI Hot Swap)\n"; break;
		case 0x07: s += " (PCI-X)\n"; break;
		case 0x08: s += " (HyperTransport)\n"; break;
		case 0x09: s += " (Vendor Specific)\n"; break;
		case 0x0a: s += " (Debug port)\n"; break;
		case 0x0b: s += " (CompactPCI central resource control)\n"; break;
		case 0x0c: s += " (PCI Hot-Plug)\n"; break;
		case 0x0d: s += " (PCI Bridge Subsystem Vendor ID)\n"; break;
		case 0x0e: s += " (AGP 8x)\n"; break;
		case 0x0f: s += " (Secure Device)\n"; break;
		case 0x10: s += " (PCI Express)\n"; break;
		case 0x11:
			s += " (MSI-X)\n";
			s += "            Message Control: ";
			s.append_hex64(pci_config_read_uint16(m_bus, m_slot, 0, capp + 2), 4);
			s += "\n            Table Offset: ";
			s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, capp + 4), 8);
			s += "\n            PBA Offset: ";
			s.append_hex64(pci_config_read_uint32(m_bus, m_slot, 0, capp + 8), 8);
			s += "\n";
			break;
		default:
			s += " (Unknown Capability)\n";
		}
		capp = pci_config_read_uint8(m_bus, m_slot, 0, capp + 1) & 0xfc;
	}

	return s;
}

<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
//
// "Copyright Centre National d'Etudes Spatiales"
// "Copyright Centre for Remote Imaging, Sensing and Processing"
//
// License:  LGPL
//
// See LICENSE.txt file in the top level directory for more details.
//
//----------------------------------------------------------------------------
// $Id$

#include <AlosPalsar/AlosPalsarData.h>
#include <AlosPalsar/AlosPalsarRecordHeader.h>

#include <AlosPalsar/AlosPalsarDataFileDescriptor.h>
#include <AlosPalsar/AlosPalsarSignalData.h>

#include <ossim/base/ossimTrace.h>
#include <ossim/base/ossimKeywordlist.h>
#include <ossim/base/ossimKeywordNames.h>

// Static trace for debugging
static ossimTrace traceDebug("ossimAlosPalsarData:debug");

namespace ossimplugins
{

const int AlosPalsarData::AlosPalsarDataFileDescriptorID = 1;
const int AlosPalsarData::AlosPalsarSignalDataID = 2;

AlosPalsarData::AlosPalsarData()
{

}

AlosPalsarData::~AlosPalsarData()
{
  ClearRecords();
}

std::ostream& operator<<(std::ostream& os, const AlosPalsarData& data)
{
  std::map<int, AlosPalsarRecord*>::const_iterator it = data._records.begin();
  while (it != data._records.end())
  {
    (*it).second->Write(os);
    ++it;
  }
  return os;

}

std::istream& operator>>(std::istream& is, AlosPalsarData& data)
{

  data.ClearRecords();

  AlosPalsarRecordHeader header;

  is >> header;

  AlosPalsarRecord* record = new AlosPalsarDataFileDescriptor;
  if (record != NULL)
  {
    record->Read(is);
    data._records[header.get_rec_seq()] = record;
  }
  else
  {
    char* buff = new char[header.get_length()-12];
    is.read(buff, header.get_length() - 12);
    delete buff;
  }

  std::streampos filePosition;

  filePosition = is.tellg();
  is >> header;

  record = new AlosPalsarSignalData;

  if (record != NULL)
  {
    record->Read(is);
    data._records[header.get_rec_seq()] = record;
//    std::cout << "Record sequence number = " << header.get_rec_seq() << std::endl;
  }
  is.seekg(filePosition); // Rewind file pointer to start of record
  // Then, advance pointer to next record
  is.seekg(static_cast<std::streamoff>(header.get_length()), std::ios::cur);

  return is;
}

AlosPalsarData::AlosPalsarData(const AlosPalsarData& rhs)
{
  std::map<int, AlosPalsarRecord*>::const_iterator it = rhs._records.begin();
  while (it != rhs._records.end())
  {
    _records[(*it).first] = (*it).second->Clone();
    ++it;
  }
}

AlosPalsarData& AlosPalsarData::operator=(const AlosPalsarData& rhs)
{
  ClearRecords();
  std::map<int, AlosPalsarRecord*>::const_iterator it = rhs._records.begin();
  while (it != rhs._records.end())
  {
    _records[(*it).first] = (*it).second->Clone();
    ++it;
  }

  return *this;
}

void AlosPalsarData::ClearRecords()
{
  std::map<int, AlosPalsarRecord*>::const_iterator it = _records.begin();
  while (it != _records.end())
  {
    delete(*it).second;
    ++it;
  }
  _records.clear();
}

bool AlosPalsarData::saveState(ossimKeywordlist& kwl,
                               const char* prefix) const
{

  static const char MODULE[] = "AlosPalsarData::saveState";

  if (traceDebug())
  {
    ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entered...\n";
  }

  bool result = true;

  /*
   * Adding metadata necessary to the sensor model in the keywordlist
   */
  const AlosPalsarDataFileDescriptor *datafiledesc = get_AlosPalsarDataFileDescriptor();
  if (datafiledesc != NULL)
  {
    kwl.add(prefix, "num_lines", datafiledesc->get_num_lines(), true);
    kwl.add(prefix, "num_pix_in_line", datafiledesc->get_num_pix_in_line(), true);
  }
  else
  {
    result = false;
  }

  const AlosPalsarSignalData *signalData = get_AlosPalsarSignalData();
  if (datafiledesc != NULL)
  {
    kwl.add(prefix, "pulse_repetition_frequency", signalData->get_pulse_repetition_frequency(), true);
    // slant range to 1st data sample in metres
    kwl.add(prefix, "slant_range_to_1st_data_sample", signalData->get_slant_range_to_1st_data_sample(), true);
  }
  else
  {
    result = false;
  }

  return result;
}

const AlosPalsarDataFileDescriptor * AlosPalsarData::get_AlosPalsarDataFileDescriptor() const
{
  return dynamic_cast<const AlosPalsarDataFileDescriptor*>(_records.find(AlosPalsarDataFileDescriptorID)->second);
}

const AlosPalsarSignalData * AlosPalsarData::get_AlosPalsarSignalData() const
{
  // TODO: Check if _records[AlosPalsarSignalDataID] works
  return dynamic_cast<const AlosPalsarSignalData*>(_records.find(AlosPalsarSignalDataID)->second);
}

}
<commit_msg>Fixed delete [] for array allocated pointer<commit_after>//----------------------------------------------------------------------------
//
// "Copyright Centre National d'Etudes Spatiales"
// "Copyright Centre for Remote Imaging, Sensing and Processing"
//
// License:  LGPL
//
// See LICENSE.txt file in the top level directory for more details.
//
//----------------------------------------------------------------------------
// $Id$

#include <AlosPalsar/AlosPalsarData.h>
#include <AlosPalsar/AlosPalsarRecordHeader.h>

#include <AlosPalsar/AlosPalsarDataFileDescriptor.h>
#include <AlosPalsar/AlosPalsarSignalData.h>

#include <ossim/base/ossimTrace.h>
#include <ossim/base/ossimKeywordlist.h>
#include <ossim/base/ossimKeywordNames.h>

// Static trace for debugging
static ossimTrace traceDebug("ossimAlosPalsarData:debug");

namespace ossimplugins
{

const int AlosPalsarData::AlosPalsarDataFileDescriptorID = 1;
const int AlosPalsarData::AlosPalsarSignalDataID = 2;

AlosPalsarData::AlosPalsarData()
{

}

AlosPalsarData::~AlosPalsarData()
{
  ClearRecords();
}

std::ostream& operator<<(std::ostream& os, const AlosPalsarData& data)
{
  std::map<int, AlosPalsarRecord*>::const_iterator it = data._records.begin();
  while (it != data._records.end())
  {
    (*it).second->Write(os);
    ++it;
  }
  return os;

}

std::istream& operator>>(std::istream& is, AlosPalsarData& data)
{

  data.ClearRecords();

  AlosPalsarRecordHeader header;

  is >> header;

  AlosPalsarRecord* record = new AlosPalsarDataFileDescriptor;
  if (record != NULL)
  {
    record->Read(is);
    data._records[header.get_rec_seq()] = record;
  }
  else
  {
    char* buff = new char[header.get_length()-12];
    is.read(buff, header.get_length() - 12);
    delete [] buff;
  }

  std::streampos filePosition;

  filePosition = is.tellg();
  is >> header;

  record = new AlosPalsarSignalData;

  if (record != NULL)
  {
    record->Read(is);
    data._records[header.get_rec_seq()] = record;
//    std::cout << "Record sequence number = " << header.get_rec_seq() << std::endl;
  }
  is.seekg(filePosition); // Rewind file pointer to start of record
  // Then, advance pointer to next record
  is.seekg(static_cast<std::streamoff>(header.get_length()), std::ios::cur);

  return is;
}

AlosPalsarData::AlosPalsarData(const AlosPalsarData& rhs)
{
  std::map<int, AlosPalsarRecord*>::const_iterator it = rhs._records.begin();
  while (it != rhs._records.end())
  {
    _records[(*it).first] = (*it).second->Clone();
    ++it;
  }
}

AlosPalsarData& AlosPalsarData::operator=(const AlosPalsarData& rhs)
{
  ClearRecords();
  std::map<int, AlosPalsarRecord*>::const_iterator it = rhs._records.begin();
  while (it != rhs._records.end())
  {
    _records[(*it).first] = (*it).second->Clone();
    ++it;
  }

  return *this;
}

void AlosPalsarData::ClearRecords()
{
  std::map<int, AlosPalsarRecord*>::const_iterator it = _records.begin();
  while (it != _records.end())
  {
    delete(*it).second;
    ++it;
  }
  _records.clear();
}

bool AlosPalsarData::saveState(ossimKeywordlist& kwl,
                               const char* prefix) const
{

  static const char MODULE[] = "AlosPalsarData::saveState";

  if (traceDebug())
  {
    ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entered...\n";
  }

  bool result = true;

  /*
   * Adding metadata necessary to the sensor model in the keywordlist
   */
  const AlosPalsarDataFileDescriptor *datafiledesc = get_AlosPalsarDataFileDescriptor();
  if (datafiledesc != NULL)
  {
    kwl.add(prefix, "num_lines", datafiledesc->get_num_lines(), true);
    kwl.add(prefix, "num_pix_in_line", datafiledesc->get_num_pix_in_line(), true);
  }
  else
  {
    result = false;
  }

  const AlosPalsarSignalData *signalData = get_AlosPalsarSignalData();
  if (datafiledesc != NULL)
  {
    kwl.add(prefix, "pulse_repetition_frequency", signalData->get_pulse_repetition_frequency(), true);
    // slant range to 1st data sample in metres
    kwl.add(prefix, "slant_range_to_1st_data_sample", signalData->get_slant_range_to_1st_data_sample(), true);
  }
  else
  {
    result = false;
  }

  return result;
}

const AlosPalsarDataFileDescriptor * AlosPalsarData::get_AlosPalsarDataFileDescriptor() const
{
  return dynamic_cast<const AlosPalsarDataFileDescriptor*>(_records.find(AlosPalsarDataFileDescriptorID)->second);
}

const AlosPalsarSignalData * AlosPalsarData::get_AlosPalsarSignalData() const
{
  // TODO: Check if _records[AlosPalsarSignalDataID] works
  return dynamic_cast<const AlosPalsarSignalData*>(_records.find(AlosPalsarSignalDataID)->second);
}

}
<|endoftext|>


<commit_before>/**
 *  kmacctcachedimap.cpp
 *
 *  Copyright (c) 2002-2004 Bo Thorsen <bo@klaralvdalens-datakonsult.se>
 *  Copyright (c) 2002-2003 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License
 *
 *  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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of this program with any edition of
 *  the Qt library by Trolltech AS, Norway (or with modified versions
 *  of Qt that use the same license as Qt), and distribute linked
 *  combinations including the two.  You must obey the GNU General
 *  Public License in all respects for all of the code used other than
 *  Qt.  If you modify this file, you may extend this exception to
 *  your version of the file, but you are not obligated to do so.  If
 *  you do not wish to do so, delete this exception statement from
 *  your version.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "kmacctcachedimap.h"
using KMail::SieveConfig;

#include "kmfoldertree.h"
#include "kmfoldermgr.h"
#include "kmfiltermgr.h"
#include "kmfoldercachedimap.h"
#include "kmmainwin.h"
#include "kmmainwidget.h"
#include "kmkernel.h"
#include "kmacctmgr.h"
#include "progressmanager.h"

#include <kio/passdlg.h>
#include <kio/scheduler.h>
#include <kio/slave.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <kstandarddirs.h>
#include <kapplication.h>
#include <kconfig.h>

KMAcctCachedImap::KMAcctCachedImap( KMAcctMgr* aOwner,
				    const QString& aAccountName, uint id )
  : KMail::ImapAccountBase( aOwner, aAccountName, id ), mFolder( 0 ),
    mProgressDialogEnabled( true )
{
  // Never EVER set this for the cached IMAP account
  mAutoExpunge = false;
}

//-----------------------------------------------------------------------------
KMAcctCachedImap::~KMAcctCachedImap()
{
  killAllJobs( true );
}

//-----------------------------------------------------------------------------
QString KMAcctCachedImap::type() const
{
  return "cachedimap";
}

void KMAcctCachedImap::init() {
  ImapAccountBase::init();

  setProgressDialogEnabled( true );
}

//-----------------------------------------------------------------------------
void KMAcctCachedImap::pseudoAssign( const KMAccount * a ) {
  killAllJobs( true );
  if (mFolder)
  {
    mFolder->setContentState(KMFolderCachedImap::imapNoInformation);
    mFolder->setSubfolderState(KMFolderCachedImap::imapNoInformation);
  }

  setProgressDialogEnabled(static_cast<const KMAcctCachedImap*>(a)->isProgressDialogEnabled());

  ImapAccountBase::pseudoAssign( a );
}

void KMAcctCachedImap::setPrefixHook() {
  if ( mFolder ) mFolder->setImapPath( prefix() );
}

//-----------------------------------------------------------------------------
void KMAcctCachedImap::setImapFolder(KMFolderCachedImap *aFolder)
{
  mFolder = aFolder;
  mFolder->setImapPath(mPrefix);
  mFolder->setAccount( this );
}

//-----------------------------------------------------------------------------
void KMAcctCachedImap::setAutoExpunge( bool /*aAutoExpunge*/ )
{
  // Never EVER set this for the cached IMAP account
  mAutoExpunge = false;
}

//-----------------------------------------------------------------------------
void KMAcctCachedImap::killAllJobs( bool disconnectSlave )
{
  //kdDebug(5006) << "killAllJobs: disconnectSlave=" << disconnectSlave << "  " << mapJobData.count() << " jobs in map." << endl;
  // Make list of folders to reset. This must be done last, since folderComplete
  // can trigger the next queued mail check already.
  QValueList<KMFolderCachedImap*> folderList;
  QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
  for (; it != mapJobData.end(); ++it) {
    if ((*it).parent)
      folderList << static_cast<KMFolderCachedImap*>((*it).parent->storage());
    // Kill the job - except if it's the one that already died and is calling us
    if ( !it.key()->error() && mSlave ) {
      it.key()->kill();
      mSlave = 0; // killing a job, kills the slave
    }
  }
  mapJobData.clear();

  // Clear the joblist. Make SURE to stop the job emitting "finished"
  for( QPtrListIterator<CachedImapJob> it( mJobList ); it.current(); ++it )
    it.current()->setPassiveDestructor( true );
  KMAccount::deleteFolderJobs();

  if ( disconnectSlave && slave() ) {
    KIO::Scheduler::disconnectSlave( slave() );
    mSlave = 0;
  }
  for( QValueList<KMFolderCachedImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
    KMFolderCachedImap *fld = *it;
    fld->resetSyncState();
    fld->setContentState(KMFolderCachedImap::imapNoInformation);
    fld->setSubfolderState(KMFolderCachedImap::imapNoInformation);
    fld->sendFolderComplete(FALSE);
  }
}

//-----------------------------------------------------------------------------
void KMAcctCachedImap::cancelMailCheck()
{
  // Make list of folders to reset, like in killAllJobs
  QValueList<KMFolderCachedImap*> folderList;
  QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
  for (; it != mapJobData.end(); ++it) {
    if ( (*it).cancellable && (*it).parent )
      folderList << static_cast<KMFolderCachedImap*>((*it).parent->storage());
  }
  // Kill jobs
  ImapAccountBase::cancelMailCheck();
  // Reset sync states and emit folderComplete, this is important for
  // KMAccount::checkingMail() to be reset, in case we restart checking mail later.
  for( QValueList<KMFolderCachedImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
    KMFolderCachedImap *fld = *it;
    fld->resetSyncState();
    fld->setContentState(KMFolderCachedImap::imapNoInformation);
    fld->setSubfolderState(KMFolderCachedImap::imapNoInformation);
    fld->sendFolderComplete(FALSE);
  }
}

//-----------------------------------------------------------------------------
void KMAcctCachedImap::killJobsForItem(KMFolderTreeItem * fti)
{
  QMap<KIO::Job *, jobData>::Iterator it = mapJobData.begin();
  while (it != mapJobData.end())
  {
    if (it.data().parent == fti->folder())
    {
      killAllJobs();
      break;
    }
    else ++it;
  }
}

// Reimplemented from ImapAccountBase because we only check one folder at a time
void KMAcctCachedImap::slotCheckQueuedFolders()
{
    mMailCheckFolders.clear();
    mMailCheckFolders.append( mFoldersQueuedForChecking.front() );
    mFoldersQueuedForChecking.pop_front();
    if ( mFoldersQueuedForChecking.isEmpty() )
      disconnect( this, SIGNAL( finishedCheck( bool, CheckStatus ) ),
                  this, SLOT( slotCheckQueuedFolders() ) );

    kmkernel->acctMgr()->singleCheckMail(this, true);
    mMailCheckFolders.clear();
}

void KMAcctCachedImap::processNewMail( bool interactive )
{
  if ( !mFolder ) { // happens if this is a pseudo-account (from configuredialog)
    checkDone( false, CheckIgnored );
    return;
  }
  if ( mMailCheckFolders.isEmpty() )
   processNewMail( mFolder, interactive, true );
  else {
    KMFolder* f = mMailCheckFolders.front();
    mMailCheckFolders.pop_front();
    processNewMail( static_cast<KMFolderCachedImap *>( f->storage() ), interactive, false );
  }
}

void KMAcctCachedImap::processNewMail( KMFolderCachedImap* folder,
				       bool interactive,
                                       bool recurse )
{
  // This should never be set for a cached IMAP account
  mAutoExpunge = false;
  mCountLastUnread = 0;
  mUnreadBeforeCheck.clear();

  if( interactive && isProgressDialogEnabled() ) {
    // Show progress dialog in all kmail-mainwidgets.
    QPtrList<KMMainWidget>* lst = KMMainWidget::mainWidgetList();
    if ( lst ) {
      for( QPtrListIterator<KMMainWidget> it( *lst ); *it; ++it ) {
        (*it)->setProgressDialogVisible( true );
      }
    }
  }

  Q_ASSERT( !mMailCheckProgressItem );
  mMailCheckProgressItem = KMail::ProgressManager::createProgressItem(
    "MailCheck" + QString::number( id() ),
    folder->label(), // will be changed immediately in serverSync anyway
    QString::null,
    true, // can be cancelled
    useSSL() || useTLS() );
  connect( mMailCheckProgressItem, SIGNAL( progressItemCanceled( ProgressItem* ) ),
           this, SLOT( slotProgressItemCanceled( ProgressItem* ) ) );

  folder->setAccount(this);
  connect(folder, SIGNAL(folderComplete(KMFolderCachedImap*, bool)),
	  this, SLOT(postProcessNewMail(KMFolderCachedImap*, bool)));
  folder->serverSync( recurse );
}

void KMAcctCachedImap::postProcessNewMail( KMFolderCachedImap* folder, bool )
{
  disconnect(folder, SIGNAL(folderComplete(KMFolderCachedImap*, bool)),
             this, SLOT(postProcessNewMail(KMFolderCachedImap*, bool)));
  mMailCheckProgressItem->setComplete();
  mMailCheckProgressItem = 0;

  // We remove everything from the deleted folders list after a sync, unconditionally.
  // Even if it fails (no permission), because on the next sync we want the folder to reappear,
  //  instead of the user being stuck with "can't delete" every time.
  // And we do it for _all_ deleted folders, even those that were deleted on the server in the first place (slotListResult).
  //  Otherwise this might have side effects much later (e.g. when regaining permissions to a folder we could see before)
  mDeletedFolders.clear();
  mPreviouslyDeletedFolders.clear();

  KMail::ImapAccountBase::postProcessNewMail();
}

void KMAcctCachedImap::addUnreadMsgCount( const KMFolderCachedImap *folder,
                                          int countUnread )
{
  if ( folder->imapPath() != "/INBOX/" ) {
    // new mail in INBOX is processed with KMAccount::processNewMsg() and
    // therefore doesn't need to be counted here
    const QString folderId = folder->folder()->idString();
    int newInFolder = countUnread;
    if ( mUnreadBeforeCheck.find( folderId ) != mUnreadBeforeCheck.end() )
      newInFolder -= mUnreadBeforeCheck[folderId];
    if ( newInFolder > 0 )
      addToNewInFolder( folderId, newInFolder );
  }
  mCountUnread += countUnread;
}

void KMAcctCachedImap::addLastUnreadMsgCount( const KMFolderCachedImap *folder,
                                              int countLastUnread )
{
  mUnreadBeforeCheck[folder->folder()->idString()] = countLastUnread;
  mCountLastUnread += countLastUnread;
}

//
//
// read/write config
//
//

void KMAcctCachedImap::readConfig( /*const*/ KConfig/*Base*/ & config ) {
  ImapAccountBase::readConfig( config );
  setProgressDialogEnabled( config.readBoolEntry( "progressdialog", true ) );
  // Apparently this method is only ever called once (from KMKernel::init) so this is ok
  mPreviouslyDeletedFolders = config.readListEntry( "deleted-folders" );
  mDeletedFolders.clear(); // but just in case...
}

void KMAcctCachedImap::writeConfig( KConfig/*Base*/ & config ) /*const*/ {
  ImapAccountBase::writeConfig( config );
  config.writeEntry( "progressdialog", isProgressDialogEnabled() );
  config.writeEntry( "deleted-folders", mDeletedFolders + mPreviouslyDeletedFolders );
}

void KMAcctCachedImap::invalidateIMAPFolders()
{
  invalidateIMAPFolders( mFolder );
}

void KMAcctCachedImap::invalidateIMAPFolders( KMFolderCachedImap* folder )
{
  if( !folder || !folder->folder() )
    return;

  folder->setAccount(this);

  QStringList strList;
  QValueList<QGuardedPtr<KMFolder> > folderList;
  kmkernel->dimapFolderMgr()->createFolderList( &strList, &folderList,
						folder->folder()->child(), QString::null,
						false );
  QValueList<QGuardedPtr<KMFolder> >::Iterator it;
  mCountLastUnread = 0;
  mUnreadBeforeCheck.clear();

  for( it = folderList.begin(); it != folderList.end(); ++it ) {
    KMFolder *f = *it;
    if( f && f->folderType() == KMFolderTypeCachedImap ) {
      KMFolderCachedImap *cfolder = static_cast<KMFolderCachedImap*>(f->storage());
      // This invalidates the folder completely
      cfolder->setUidValidity("INVALID");
      cfolder->writeUidCache();
      processNewMailSingleFolder( f );
    }
  }
  folder->setUidValidity("INVALID");
  folder->writeUidCache();

  processNewMailSingleFolder( folder->folder() );
}

//-----------------------------------------------------------------------------
void KMAcctCachedImap::addDeletedFolder( const QString& subFolderPath )
{
  mDeletedFolders.append( subFolderPath );
}

bool KMAcctCachedImap::isDeletedFolder( const QString& subFolderPath ) const
{
  return mDeletedFolders.find( subFolderPath ) != mDeletedFolders.end();
}

bool KMAcctCachedImap::isPreviouslyDeletedFolder( const QString& subFolderPath ) const
{
  return mPreviouslyDeletedFolders.find( subFolderPath ) != mPreviouslyDeletedFolders.end();
}

void KMAcctCachedImap::removeDeletedFolder( const QString& subFolderPath )
{
  mDeletedFolders.remove( subFolderPath );
  mPreviouslyDeletedFolders.remove( subFolderPath );
}

void KMAcctCachedImap::slotProgressItemCanceled( ProgressItem* )
{
  killAllJobs( false );
}

FolderStorage* KMAcctCachedImap::rootFolder()
{
  return mFolder;
}

#include "kmacctcachedimap.moc"
<commit_msg>Use mIdleTimer again, to send a noop every minute, so that we don't end up with a "connection broken" error message after not syncing mail for a long time. CCMAIL: hansen@kde.org<commit_after>/**
 *  kmacctcachedimap.cpp
 *
 *  Copyright (c) 2002-2004 Bo Thorsen <bo@klaralvdalens-datakonsult.se>
 *  Copyright (c) 2002-2003 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License
 *
 *  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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of this program with any edition of
 *  the Qt library by Trolltech AS, Norway (or with modified versions
 *  of Qt that use the same license as Qt), and distribute linked
 *  combinations including the two.  You must obey the GNU General
 *  Public License in all respects for all of the code used other than
 *  Qt.  If you modify this file, you may extend this exception to
 *  your version of the file, but you are not obligated to do so.  If
 *  you do not wish to do so, delete this exception statement from
 *  your version.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "kmacctcachedimap.h"
using KMail::SieveConfig;

#include "kmfoldertree.h"
#include "kmfoldermgr.h"
#include "kmfiltermgr.h"
#include "kmfoldercachedimap.h"
#include "kmmainwin.h"
#include "kmmainwidget.h"
#include "kmkernel.h"
#include "kmacctmgr.h"
#include "progressmanager.h"

#include <kio/passdlg.h>
#include <kio/scheduler.h>
#include <kio/slave.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <kstandarddirs.h>
#include <kapplication.h>
#include <kconfig.h>

KMAcctCachedImap::KMAcctCachedImap( KMAcctMgr* aOwner,
				    const QString& aAccountName, uint id )
  : KMail::ImapAccountBase( aOwner, aAccountName, id ), mFolder( 0 ),
    mProgressDialogEnabled( true )
{
  // Never EVER set this for the cached IMAP account
  mAutoExpunge = false;
}

//-----------------------------------------------------------------------------
KMAcctCachedImap::~KMAcctCachedImap()
{
  killAllJobs( true );
}

//-----------------------------------------------------------------------------
QString KMAcctCachedImap::type() const
{
  return "cachedimap";
}

void KMAcctCachedImap::init() {
  ImapAccountBase::init();

  setProgressDialogEnabled( true );
}

//-----------------------------------------------------------------------------
void KMAcctCachedImap::pseudoAssign( const KMAccount * a ) {
  killAllJobs( true );
  if (mFolder)
  {
    mFolder->setContentState(KMFolderCachedImap::imapNoInformation);
    mFolder->setSubfolderState(KMFolderCachedImap::imapNoInformation);
  }

  setProgressDialogEnabled(static_cast<const KMAcctCachedImap*>(a)->isProgressDialogEnabled());

  ImapAccountBase::pseudoAssign( a );
}

void KMAcctCachedImap::setPrefixHook() {
  if ( mFolder ) mFolder->setImapPath( prefix() );
}

//-----------------------------------------------------------------------------
void KMAcctCachedImap::setImapFolder(KMFolderCachedImap *aFolder)
{
  mFolder = aFolder;
  mFolder->setImapPath(mPrefix);
  mFolder->setAccount( this );
}

//-----------------------------------------------------------------------------
void KMAcctCachedImap::setAutoExpunge( bool /*aAutoExpunge*/ )
{
  // Never EVER set this for the cached IMAP account
  mAutoExpunge = false;
}

//-----------------------------------------------------------------------------
void KMAcctCachedImap::killAllJobs( bool disconnectSlave )
{
  //kdDebug(5006) << "killAllJobs: disconnectSlave=" << disconnectSlave << "  " << mapJobData.count() << " jobs in map." << endl;
  // Make list of folders to reset. This must be done last, since folderComplete
  // can trigger the next queued mail check already.
  QValueList<KMFolderCachedImap*> folderList;
  QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
  for (; it != mapJobData.end(); ++it) {
    if ((*it).parent)
      folderList << static_cast<KMFolderCachedImap*>((*it).parent->storage());
    // Kill the job - except if it's the one that already died and is calling us
    if ( !it.key()->error() && mSlave ) {
      it.key()->kill();
      mSlave = 0; // killing a job, kills the slave
    }
  }
  mapJobData.clear();

  // Clear the joblist. Make SURE to stop the job emitting "finished"
  for( QPtrListIterator<CachedImapJob> it( mJobList ); it.current(); ++it )
    it.current()->setPassiveDestructor( true );
  KMAccount::deleteFolderJobs();

  if ( disconnectSlave && slave() ) {
    KIO::Scheduler::disconnectSlave( slave() );
    mSlave = 0;
  }
  for( QValueList<KMFolderCachedImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
    KMFolderCachedImap *fld = *it;
    fld->resetSyncState();
    fld->setContentState(KMFolderCachedImap::imapNoInformation);
    fld->setSubfolderState(KMFolderCachedImap::imapNoInformation);
    fld->sendFolderComplete(FALSE);
  }
}

//-----------------------------------------------------------------------------
void KMAcctCachedImap::cancelMailCheck()
{
  // Make list of folders to reset, like in killAllJobs
  QValueList<KMFolderCachedImap*> folderList;
  QMap<KIO::Job*, jobData>::Iterator it = mapJobData.begin();
  for (; it != mapJobData.end(); ++it) {
    if ( (*it).cancellable && (*it).parent )
      folderList << static_cast<KMFolderCachedImap*>((*it).parent->storage());
  }
  // Kill jobs
  ImapAccountBase::cancelMailCheck();
  // Reset sync states and emit folderComplete, this is important for
  // KMAccount::checkingMail() to be reset, in case we restart checking mail later.
  for( QValueList<KMFolderCachedImap*>::Iterator it = folderList.begin(); it != folderList.end(); ++it ) {
    KMFolderCachedImap *fld = *it;
    fld->resetSyncState();
    fld->setContentState(KMFolderCachedImap::imapNoInformation);
    fld->setSubfolderState(KMFolderCachedImap::imapNoInformation);
    fld->sendFolderComplete(FALSE);
  }
}

//-----------------------------------------------------------------------------
void KMAcctCachedImap::killJobsForItem(KMFolderTreeItem * fti)
{
  QMap<KIO::Job *, jobData>::Iterator it = mapJobData.begin();
  while (it != mapJobData.end())
  {
    if (it.data().parent == fti->folder())
    {
      killAllJobs();
      break;
    }
    else ++it;
  }
}

// Reimplemented from ImapAccountBase because we only check one folder at a time
void KMAcctCachedImap::slotCheckQueuedFolders()
{
    mMailCheckFolders.clear();
    mMailCheckFolders.append( mFoldersQueuedForChecking.front() );
    mFoldersQueuedForChecking.pop_front();
    if ( mFoldersQueuedForChecking.isEmpty() )
      disconnect( this, SIGNAL( finishedCheck( bool, CheckStatus ) ),
                  this, SLOT( slotCheckQueuedFolders() ) );

    kmkernel->acctMgr()->singleCheckMail(this, true);
    mMailCheckFolders.clear();
}

void KMAcctCachedImap::processNewMail( bool interactive )
{
  if ( !mFolder ) { // happens if this is a pseudo-account (from configuredialog)
    checkDone( false, CheckIgnored );
    return;
  }
  if ( mMailCheckFolders.isEmpty() )
   processNewMail( mFolder, interactive, true );
  else {
    KMFolder* f = mMailCheckFolders.front();
    mMailCheckFolders.pop_front();
    processNewMail( static_cast<KMFolderCachedImap *>( f->storage() ), interactive, false );
  }
}

void KMAcctCachedImap::processNewMail( KMFolderCachedImap* folder,
				       bool interactive,
                                       bool recurse )
{
  // This should never be set for a cached IMAP account
  mAutoExpunge = false;
  mCountLastUnread = 0;
  mUnreadBeforeCheck.clear();
  mIdleTimer.stop();

  if( interactive && isProgressDialogEnabled() ) {
    // Show progress dialog in all kmail-mainwidgets.
    QPtrList<KMMainWidget>* lst = KMMainWidget::mainWidgetList();
    if ( lst ) {
      for( QPtrListIterator<KMMainWidget> it( *lst ); *it; ++it ) {
        (*it)->setProgressDialogVisible( true );
      }
    }
  }

  Q_ASSERT( !mMailCheckProgressItem );
  mMailCheckProgressItem = KMail::ProgressManager::createProgressItem(
    "MailCheck" + QString::number( id() ),
    folder->label(), // will be changed immediately in serverSync anyway
    QString::null,
    true, // can be cancelled
    useSSL() || useTLS() );
  connect( mMailCheckProgressItem, SIGNAL( progressItemCanceled( ProgressItem* ) ),
           this, SLOT( slotProgressItemCanceled( ProgressItem* ) ) );

  folder->setAccount(this);
  connect(folder, SIGNAL(folderComplete(KMFolderCachedImap*, bool)),
	  this, SLOT(postProcessNewMail(KMFolderCachedImap*, bool)));
  folder->serverSync( recurse );
}

void KMAcctCachedImap::postProcessNewMail( KMFolderCachedImap* folder, bool )
{
  mIdleTimer.start( 60000 ); // send a noop every minute to avoid "connection broken" errors
  mIdle = false; // noop, don't disconnect (to make interval-mail-check faster)
  disconnect(folder, SIGNAL(folderComplete(KMFolderCachedImap*, bool)),
             this, SLOT(postProcessNewMail(KMFolderCachedImap*, bool)));
  mMailCheckProgressItem->setComplete();
  mMailCheckProgressItem = 0;

  // We remove everything from the deleted folders list after a sync, unconditionally.
  // Even if it fails (no permission), because on the next sync we want the folder to reappear,
  //  instead of the user being stuck with "can't delete" every time.
  // And we do it for _all_ deleted folders, even those that were deleted on the server in the first place (slotListResult).
  //  Otherwise this might have side effects much later (e.g. when regaining permissions to a folder we could see before)
  mDeletedFolders.clear();
  mPreviouslyDeletedFolders.clear();

  KMail::ImapAccountBase::postProcessNewMail();
}

void KMAcctCachedImap::addUnreadMsgCount( const KMFolderCachedImap *folder,
                                          int countUnread )
{
  if ( folder->imapPath() != "/INBOX/" ) {
    // new mail in INBOX is processed with KMAccount::processNewMsg() and
    // therefore doesn't need to be counted here
    const QString folderId = folder->folder()->idString();
    int newInFolder = countUnread;
    if ( mUnreadBeforeCheck.find( folderId ) != mUnreadBeforeCheck.end() )
      newInFolder -= mUnreadBeforeCheck[folderId];
    if ( newInFolder > 0 )
      addToNewInFolder( folderId, newInFolder );
  }
  mCountUnread += countUnread;
}

void KMAcctCachedImap::addLastUnreadMsgCount( const KMFolderCachedImap *folder,
                                              int countLastUnread )
{
  mUnreadBeforeCheck[folder->folder()->idString()] = countLastUnread;
  mCountLastUnread += countLastUnread;
}

//
//
// read/write config
//
//

void KMAcctCachedImap::readConfig( /*const*/ KConfig/*Base*/ & config ) {
  ImapAccountBase::readConfig( config );
  setProgressDialogEnabled( config.readBoolEntry( "progressdialog", true ) );
  // Apparently this method is only ever called once (from KMKernel::init) so this is ok
  mPreviouslyDeletedFolders = config.readListEntry( "deleted-folders" );
  mDeletedFolders.clear(); // but just in case...
}

void KMAcctCachedImap::writeConfig( KConfig/*Base*/ & config ) /*const*/ {
  ImapAccountBase::writeConfig( config );
  config.writeEntry( "progressdialog", isProgressDialogEnabled() );
  config.writeEntry( "deleted-folders", mDeletedFolders + mPreviouslyDeletedFolders );
}

void KMAcctCachedImap::invalidateIMAPFolders()
{
  invalidateIMAPFolders( mFolder );
}

void KMAcctCachedImap::invalidateIMAPFolders( KMFolderCachedImap* folder )
{
  if( !folder || !folder->folder() )
    return;

  folder->setAccount(this);

  QStringList strList;
  QValueList<QGuardedPtr<KMFolder> > folderList;
  kmkernel->dimapFolderMgr()->createFolderList( &strList, &folderList,
						folder->folder()->child(), QString::null,
						false );
  QValueList<QGuardedPtr<KMFolder> >::Iterator it;
  mCountLastUnread = 0;
  mUnreadBeforeCheck.clear();

  for( it = folderList.begin(); it != folderList.end(); ++it ) {
    KMFolder *f = *it;
    if( f && f->folderType() == KMFolderTypeCachedImap ) {
      KMFolderCachedImap *cfolder = static_cast<KMFolderCachedImap*>(f->storage());
      // This invalidates the folder completely
      cfolder->setUidValidity("INVALID");
      cfolder->writeUidCache();
      processNewMailSingleFolder( f );
    }
  }
  folder->setUidValidity("INVALID");
  folder->writeUidCache();

  processNewMailSingleFolder( folder->folder() );
}

//-----------------------------------------------------------------------------
void KMAcctCachedImap::addDeletedFolder( const QString& subFolderPath )
{
  mDeletedFolders.append( subFolderPath );
}

bool KMAcctCachedImap::isDeletedFolder( const QString& subFolderPath ) const
{
  return mDeletedFolders.find( subFolderPath ) != mDeletedFolders.end();
}

bool KMAcctCachedImap::isPreviouslyDeletedFolder( const QString& subFolderPath ) const
{
  return mPreviouslyDeletedFolders.find( subFolderPath ) != mPreviouslyDeletedFolders.end();
}

void KMAcctCachedImap::removeDeletedFolder( const QString& subFolderPath )
{
  mDeletedFolders.remove( subFolderPath );
  mPreviouslyDeletedFolders.remove( subFolderPath );
}

void KMAcctCachedImap::slotProgressItemCanceled( ProgressItem* )
{
  killAllJobs( false );
}

FolderStorage* KMAcctCachedImap::rootFolder()
{
  return mFolder;
}

#include "kmacctcachedimap.moc"
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <cmath>
#include <random>
#include <map>
#include <algorithm>
#include <cassert>
using namespace std;

class Solution3 {
    public:
        double median(int A[], int m, int B[], int n, int k) {
            if (m > n) return median(B, n, A, m, k);
            int ka = min((k+1)/2, m), kb = k - ka;

            if (m == 0) return B[k-1];
            if (k == 1) return min(A[0], B[0]);

            int va = A[ka-1], vb = B[kb-1];
            if (A[ka-1] >= B[kb-1]) return median(A, m, B+kb, n-kb, k-kb);
            else return median(A+ka, m-ka, B, n, k-ka);
        }

        double findMedianSortedArrays(int A[], int m, int B[], int n) {
            auto mid = (m+n)/2;
            bool even = (m+n)%2 == 0;

            if (even)
                return (median(A, m, B, n, mid) + median(A, m, B, n, mid+1))/2.0;
            else
                return median(A, m, B, n, mid+1);
        }
};

class Solution2 {
    public:
        // find right most index whose value is equal or less than val, or -1
        int after(int* arr, int len, int val) {
            int l = 0, r = len-1, m = l;
            while (l <= r) {
                m = l + (r-l)/2;
                if (arr[m] == val) return m;
                else if (arr[m] > val) r = m-1;
                else l = m+1;
            }
            if (arr[m] > val) m--;
            return m;
        }

        double single(int* arr, int len, bool even, int mid) {
            double res = arr[mid];
            if (even) {
                res += arr[mid+1];
                res /= 2.0;
            }
            return res;
        }

        double findMedianSortedArrays(int A[], int m, int B[], int n) {
            auto mid = (m+n-1)/2;
            bool even = (m+n)%2 == 0;
            if (m == 0) return single(B, n, even, mid);
            else if (n == 0) return single(A, m, even, mid);

            int *pa = A, *pb = B;
            if (A[0] > B[0]) { pa = B, pb = A; std::swap(m, n); }

            double res = 0.0;

            // no intersection
            if (*(pa+m-1) <= *pb) {
                if (mid >= m) {
                    mid -= m;
                    res = single(pb, n, even, mid);
                } else {
                    res = pa[mid];
                    if (even) {
                        res += (mid == m-1) ? pb[0]: pa[mid+1];
                        res /= 2.0;
                    }
                }
                return res;
            }

            // treat pa as buckets, and pb are values split into buckets
            // first find which bucket mid reside in, then locate it in the bucket

            // find bucket
            int l = 0, r = m-1, gid = -1, k = l;
            while (l <= r) {
                k = l + (r-l)/2;
                gid = after(pb, n, pa[k]) + k + 1;
                if (mid == gid) {
                    res = pa[k];
                    if (even) {
                        int t = gid - k;
                        if (t >= 0 && pb[t] < pa[k+1])
                            res += pb[t];
                        else res += pa[k+1];
                        res /= 2.0;
                    }
                    return res;
                } else if (mid < gid) {
                    r = k-1;
                } else l = k+1;
            }

            mid -= k+1;
            res = pb[mid];
            if (even) {
                if (mid + 1 == n || (k+1 < m && pa[k+1] < pb[mid+1])) res += pa[k+1];
                else res += pb[mid+1];
                res /= 2.0;
            }

            return res;
        }
};

class Solution {
    public:
        double findMedianSortedArrays(int A[], int m, int B[], int n) {
            auto l = m + n, mid = (m+n)/2;
            double v = 0, w = 0;

            for (int i = 0, j = 0, k = 0; k <= l; ) {
                if (k == mid + 1) {
                    if (l % 2 == 0) {
                        return (w + v)/2.0;
                    } else
                        return v;
                }

                w = v;
                if (i >= m) v = B[j++];
                else if (j >= n) v = A[i++];
                else if (A[i] > B[j]) v = B[j++];
                else v = A[i++];
                k++;
            }

            return 0;
        }
};

void test(int A[], int m, int B[], int n)
{
    cout << Solution().findMedianSortedArrays(A, m, B, n) << endl;
    cout << Solution3().findMedianSortedArrays(A, m, B, n) << endl;
}

#define LEN(a) (sizeof (a) /sizeof(a[0]))

int main(int argc, char *argv[])
{
    int a[] = {};
    int b[] = {1};
    test(a, 0, b, 1);

    int a1[] = {3, 5};
    int b1[] = {2};
    test(a1, 2, b1, 1);

    int a2[] = {3, 5};
    int b2[] = {2, 7};
    test(a2, 2, b2, 2);

    int a3[] = {};
    int b3[] = {2, 3};
    test(a3, 0, b3, 2);

    {
        int a[] = {2,3,4,5,6,7};
        int b[] = {1};
        test(a, LEN(a), b, LEN(b));
    }
    {
        int a[] = {2};
        int b[] = {1,3,4};
        test(a, LEN(a), b, LEN(b));
    }

    {
        int a[] = {1,3,4,8,9};
        int b[] = {2,5,5,6,7,18};
        test(a, LEN(a), b, LEN(b));
    }

    {
        int a[] = {1,3,4,8,9,15};
        int b[] = {2,5,5,6,7,18};
        test(a, LEN(a), b, LEN(b));
    }

    {
        int a[] = {1,2,4,8,9,15};
        int b[] = {3,4,5,6,7,18};
        test(a, LEN(a), b, LEN(b));
    }
    {
        int a[] = {1, 12, 15, 26, 38};
        int b[] = {2, 13, 17, 30, 45, 50};
        test(a, LEN(a), b, LEN(b));
    }
    return 0;
}
<commit_msg>update<commit_after>#include <iostream>
#include <vector>
#include <cmath>
#include <random>
#include <map>
#include <algorithm>
#include <cassert>
using namespace std;

class Solution3 {
    public:
        double median(int A[], int m, int B[], int n, int k) {
            // cout << "m " << m << ", n " << n << ", k " << k << endl;
            if (m == 0) return B[k];
            else if (n == 0) return A[k];
            if (k == 0) return min(A[0], B[0]);

            int ka = min((k)/2, m-1), kb = k - ka - 1;
            // cout << "ka " << ka << ", kb " << kb << endl;
            if (kb < 0) return A[ka];
            else if (kb > n-1) { kb = n-1; ka = k - kb - 1; }

            int va = A[ka], vb = B[kb];
            if (A[ka] >= B[kb]) return median(A, m, B+kb+1, n-kb-1, k-kb-1);
            else return median(A+ka+1, m-ka-1, B, n, k-ka-1);
        }

        double findMedianSortedArrays(int A[], int m, int B[], int n) {
            auto mid = (m+n-1)/2;
            bool even = (m+n)%2 == 0;

            if (even)
                return (median(A, m, B, n, mid) + median(A, m, B, n, mid+1))/2.0;
            else
                return median(A, m, B, n, mid);
        }
};

class Solution2 {
    public:
        // find right most index whose value is equal or less than val, or -1
        int after(int* arr, int len, int val) {
            int l = 0, r = len-1, m = l;
            while (l <= r) {
                m = l + (r-l)/2;
                if (arr[m] == val) return m;
                else if (arr[m] > val) r = m-1;
                else l = m+1;
            }
            if (arr[m] > val) m--;
            return m;
        }

        double single(int* arr, int len, bool even, int mid) {
            double res = arr[mid];
            if (even) res = (res + arr[mid+1]) / 2.0;
            return res;
        }

        double findMedianSortedArrays(int A[], int m, int B[], int n) {
            auto mid = (m+n-1)/2;
            bool even = (m+n)%2 == 0;
            if (m == 0) return single(B, n, even, mid);
            else if (n == 0) return single(A, m, even, mid);

            int *pa = A, *pb = B;
            if (A[0] > B[0]) { pa = B, pb = A; std::swap(m, n); }

            double res = 0.0;

            // treat pa as buckets, and pb are values split into buckets
            // first find which bucket mid reside in, then locate it in the bucket

            // find bucket
            int l = 0, r = m-1, gid = -1, k = l;
            while (l <= r) {
                k = l + (r-l)/2;
                gid = after(pb, n, pa[k]) + k + 1;
                if (mid == gid) {
                    res = pa[k];
                    if (even) {
                        int t = gid - k;
                        if (t >= 0 && pb[t] < pa[k+1])
                            res += pb[t];
                        else res += pa[k+1];
                        res /= 2.0;
                    }
                    return res;
                } else if (mid < gid) {
                    r = k-1;
                } else l = k+1;
            }

            if (gid >= mid) k--;
            mid -= k+1;
            res = pb[mid];
            if (even) {
                if (mid + 1 == n || (k+1 < m && pa[k+1] < pb[mid+1])) res += pa[k+1];
                else res += pb[mid+1];
                res /= 2.0;
            }

            return res;
        }
};

//O(m+n)
class Solution {
    public:
        double findMedianSortedArrays(int A[], int m, int B[], int n) {
            auto l = m + n, mid = (m+n)/2;
            double v = 0, w = 0;

            for (int i = 0, j = 0, k = 0; k <= l; ) {
                if (k == mid + 1) {
                    if (l % 2 == 0) {
                        return (w + v)/2.0;
                    } else
                        return v;
                }

                w = v;
                if (i >= m) v = B[j++];
                else if (j >= n) v = A[i++];
                else if (A[i] > B[j]) v = B[j++];
                else v = A[i++];
                k++;
            }

            return 0;
        }
};

void test(int A[], int m, int B[], int n)
{
    cout << Solution().findMedianSortedArrays(A, m, B, n) << endl;
    cout << Solution2().findMedianSortedArrays(A, m, B, n) << endl;
    cout << Solution3().findMedianSortedArrays(A, m, B, n) << endl;
    cout << "--------------\n";
}

#define LEN(a) (sizeof (a) /sizeof(a[0]))

int main(int argc, char *argv[])
{
    int a[] = {};
    int b[] = {1};
    test(a, 0, b, 1);

    int a1[] = {3, 5};
    int b1[] = {2};
    test(a1, 2, b1, 1);

    int a2[] = {3, 5};
    int b2[] = {2, 7};
    test(a2, 2, b2, 2);

    int a3[] = {};
    int b3[] = {2, 3};
    test(a3, 0, b3, 2);

    {
        int a[] = {2,3,4,5,6,7};
        int b[] = {1};
        test(a, LEN(a), b, LEN(b));
    }
    {
        int a[] = {2};
        int b[] = {1,3,4};
        test(a, LEN(a), b, LEN(b));
    }

    {
        int a[] = {1,3,4,8,9};
        int b[] = {2,5,5,6,7,18};
        test(a, LEN(a), b, LEN(b));
    }

    {
        int a[] = {1,3,4,8,9,15};
        int b[] = {2,5,5,6,7,18};
        test(a, LEN(a), b, LEN(b));
    }

    {
        int a[] = {1,2,4,8,9,15};
        int b[] = {3,4,5,6,7,18};
        test(a, LEN(a), b, LEN(b));
    }
    {
        int a[] = {1, 12, 15, 26, 38};
        int b[] = {2, 13, 17, 30, 45, 50};
        test(a, LEN(a), b, LEN(b));
    }
    return 0;
}
<|endoftext|>


<commit_before>#pragma once

#include "PhysicallyBasedMaterial.h"
#include "SkyBoxMaterial.h"

#include "VectorIndexer.hpp"
#include <tuple>

namespace Rendering
{
	namespace Manager
	{
		template <class... Materials>
		class MaterialPools final
		{
		public:
			MaterialPools() = default;
			DISALLOW_ASSIGN_COPY(MaterialPools);

			template <typename MaterialType>
			void Add(const std::string& key, MaterialType& material)
			{
				std::get<MaterialPool<MaterialType>>(_materials).Add(key, material);
			}
			template <typename MaterialType>
			void Delete(const std::string& key)
			{
				std::get<MaterialPool<MaterialType>>(_materials).Delete(key);
			}
			template <typename MaterialType>
			auto Find(const std::string& key)
			{
				return std::get<MaterialPool<MaterialType>>(_materials).Find(key);
			}

			template <typename MaterialType>
			const std::vector<MaterialType>& GetMaterials() const
			{
				return std::get<MaterialPool<MaterialType>>(_materials).GetVector();
			}

		private:
			template <class MaterialType>
			class MaterialPool : public Core::VectorHashMap<std::string, MaterialType> {};

			std::tuple<MaterialPool<Materials>...>	_materials;
		};

		class MaterialManager final
		{
		public:
			MaterialManager() = default;
			DISALLOW_ASSIGN_COPY(MaterialManager);

			auto& Get()
			{
				return _materialSystem;
			}

		private:
			MaterialPools<PhysicallyBasedMaterial, SkyBoxMaterial> _materialSystem;
		};
	}
}<commit_msg>MaterialManager - 코드 정리<commit_after>#pragma once

#include "PhysicallyBasedMaterial.h"
#include "SkyBoxMaterial.h"

#include "VectorIndexer.hpp"
#include <tuple>

namespace Rendering
{
	namespace Manager
	{
		class MaterialManager final
		{
		public:
			MaterialManager() = default;
			DISALLOW_ASSIGN_COPY(MaterialManager);

			template <typename MaterialType>
			void Add(const std::string& key, MaterialType& material)
			{
				std::get<MaterialPool<MaterialType>>(_materials).Add(key, material);
			}
			template <typename MaterialType>
			void Delete(const std::string& key)
			{
				std::get<MaterialPool<MaterialType>>(_materials).Delete(key);
			}
			template <typename MaterialType>
			auto Find(const std::string& key)
			{
				return std::get<MaterialPool<MaterialType>>(_materials).Find(key);
			}

			template <typename MaterialType>
			const std::vector<MaterialType>& GetMaterials() const
			{
				return std::get<MaterialPool<MaterialType>>(_materials).GetVector();
			}

		private:
			template <class MaterialType>
			using MaterialPool = Core::VectorHashMap<std::string, MaterialType>;

			std::tuple<	MaterialPool<PhysicallyBasedMaterial>,
						MaterialPool<SkyBoxMaterial> >	_materials;
		};
	}
}<|endoftext|>


<commit_before><commit_msg>Fixe debug cout<commit_after><|endoftext|>


<commit_before>// Author: Enrico Guiraud, Danilo Piparo CERN  03/2017

/*************************************************************************
 * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TRESULTPROXY
#define ROOT_TRESULTPROXY

#include "ROOT/TypeTraits.hxx"
#include "ROOT/TDFNodes.hxx"
#include "TError.h" // Warning

#include <memory>
#include <functional>

namespace ROOT {

namespace Experimental {
namespace TDF {
// Fwd decl for MakeResultProxy
template <typename T>
class TResultProxy;
}
}

namespace Detail {
namespace TDF {
using ROOT::Experimental::TDF::TResultProxy;
// Fwd decl for TResultProxy
template <typename T>
TResultProxy<T> MakeResultProxy(const std::shared_ptr<T> &r, const std::shared_ptr<TLoopManager> &df,
                                TDFInternal::TActionBase *actionPtr);
template <typename T>
std::pair<TResultProxy<T>, std::shared_ptr<ROOT::Internal::TDF::TActionBase *>>
MakeResultProxy(const std::shared_ptr<T> &r, const std::shared_ptr<TLoopManager> &df);
} // ns TDF
} // ns Detail

namespace Experimental {
namespace TDF {
namespace TDFInternal = ROOT::Internal::TDF;
namespace TDFDetail = ROOT::Detail::TDF;
namespace TTraits = ROOT::TypeTraits;

/// Smart pointer for the return type of actions
/**
\class ROOT::Experimental::TDF::TResultProxy
\ingroup dataframe
\brief A wrapper around the result of TDataFrame actions able to trigger calculations lazily.
\tparam T Type of the action result

A smart pointer which allows to access the result of a TDataFrame action. The
methods of the encapsulated object can be accessed via the arrow operator.
Upon invocation of the arrow operator or dereferencing (`operator*`), the
loop on the events and calculations of all scheduled actions are executed
if needed.
It is possible to iterate on the result proxy if the proxied object is a collection.
~~~{.cpp}
for (auto& myItem : myResultProxy) { ... };
~~~
If iteration is not supported by the type of the proxied object, a compilation error is thrown.

*/
template <typename T>
class TResultProxy {
   /// \cond HIDDEN_SYMBOLS
   template <typename V, bool isCont = TTraits::IsContainer<V>::value>
   struct TIterationHelper {
      using Iterator_t = void;
      void GetBegin(const V &) { static_assert(sizeof(V) == 0, "It does not make sense to ask begin for this class."); }
      void GetEnd(const V &) { static_assert(sizeof(V) == 0, "It does not make sense to ask end for this class."); }
   };

   template <typename V>
   struct TIterationHelper<V, true> {
      using Iterator_t = decltype(std::begin(std::declval<V>()));
      static Iterator_t GetBegin(const V &v) { return std::begin(v); };
      static Iterator_t GetEnd(const V &v) { return std::end(v); };
   };
   /// \endcond
   using SPT_t = std::shared_ptr<T>;
   using SPTLM_t = std::shared_ptr<TDFDetail::TLoopManager>;
   using WPTLM_t = std::weak_ptr<TDFDetail::TLoopManager>;
   using ShrdPtrBool_t = std::shared_ptr<bool>;
   template <typename W>
   friend TResultProxy<W>
   TDFDetail::MakeResultProxy(const std::shared_ptr<W> &, const SPTLM_t &, TDFInternal::TActionBase *);
   template <typename W>
   friend std::pair<TResultProxy<W>, std::shared_ptr<TDFInternal::TActionBase *>>
   TDFDetail::MakeResultProxy(const std::shared_ptr<W> &, const SPTLM_t &);

   const ShrdPtrBool_t fReadiness =
      std::make_shared<bool>(false); ///< State registered also in the TLoopManager until the event loop is executed
   WPTLM_t fImplWeakPtr;             ///< Points to the TLoopManager at the root of the functional graph
   const SPT_t fObjPtr;              ///< Shared pointer encapsulating the wrapped result
   /// Shared_ptr to a _pointer_ to the TDF action that produces this result. It is set at construction time for
   /// non-jitted actions, and at jitting time for jitted actions (at the time of writing, this means right
   /// before the event-loop).
   // N.B. what's on the heap is the _pointer_ to TActionBase, we are _not_ taking shared ownership of a TAction.
   // This cannot be a unique_ptr because that would disallow copy-construction of TResultProxies.
   // It cannot be just a pointer to TActionBase because we need something to store in the callback callable that will
   // be passed to TLoopManager _before_ the pointer to TActionBase is set in the case of jitted actions.
   const std::shared_ptr<TDFInternal::TActionBase *> fActionPtrPtr;

   /// Triggers the event loop in the TLoopManager instance to which it's associated via the fImplWeakPtr
   void TriggerRun();

   /// Get the pointer to the encapsulated result.
   /// Ownership is not transferred to the caller.
   /// Triggers event loop and execution of all actions booked in the associated TLoopManager.
   T *Get()
   {
      if (!*fReadiness)
         TriggerRun();
      return fObjPtr.get();
   }

   TResultProxy(const SPT_t &objPtr, const ShrdPtrBool_t &readiness, const SPTLM_t &loopManager,
                TDFInternal::TActionBase *actionPtr = nullptr)
      : fReadiness(readiness), fImplWeakPtr(loopManager), fObjPtr(objPtr),
        fActionPtrPtr(new (TDFInternal::TActionBase *)(actionPtr))
   {
   }

   std::shared_ptr<TDFInternal::TActionBase *> GetActionPtrPtr() const { return fActionPtrPtr; }

   void RegisterCallback(ULong64_t everyNEvents, std::function<void(unsigned int)> &&c) {
      auto lm = fImplWeakPtr.lock();
      if (!lm)
         throw std::runtime_error("The main TDataFrame is not reachable: did it go out of scope?");
      lm->RegisterCallback(everyNEvents, std::move(c));
   }

public:
   using Value_t = T; ///< Convenience alias to simplify access to proxied type
   static constexpr ULong64_t kOnce = 0ull; ///< Convenience definition to express a callback must be executed once

   TResultProxy() = delete;
   TResultProxy(const TResultProxy &) = default;
   TResultProxy(TResultProxy &&) = default;

   /// Get a const reference to the encapsulated object.
   /// Triggers event loop and execution of all actions booked in the associated TLoopManager.
   const T &GetValue() { return *Get(); }

   /// Get a pointer to the encapsulated object.
   /// Triggers event loop and execution of all actions booked in the associated TLoopManager.
   T &operator*() { return *Get(); }

   /// Get a pointer to the encapsulated object.
   /// Ownership is not transferred to the caller.
   /// Triggers event loop and execution of all actions booked in the associated TLoopManager.
   T *operator->() { return Get(); }

   /// Return an iterator to the beginning of the contained object if this makes
   /// sense, throw a compilation error otherwise
   typename TIterationHelper<T>::Iterator_t begin()
   {
      if (!*fReadiness)
         TriggerRun();
      return TIterationHelper<T>::GetBegin(*fObjPtr);
   }

   /// Return an iterator to the end of the contained object if this makes
   /// sense, throw a compilation error otherwise
   typename TIterationHelper<T>::Iterator_t end()
   {
      if (!*fReadiness)
         TriggerRun();
      return TIterationHelper<T>::GetEnd(*fObjPtr);
   }

   /// Register a callback that TDataFrame will execute "everyNEvents" on a partial result.
   ///
   /// \param[in] everyNEvents Frequency at which the callback will be called, as a number of events processed
   /// \param[in] callback a callable with signature `void(Value_t&)` where Value_t is the type of the value contained in this TResultProxy
   ///
   /// The callback must be a callable (lambda, function, functor class...) that takes a reference to the result type as
   /// argument and returns nothing. TDataFrame will invoke registered callbacks passing partial action results as
   /// arguments to them (e.g. a histogram filled with a part of the selected events, a counter incremented only up to a
   /// certain point, a mean over a subset of the events and so forth).
   ///
   /// Callbacks can be used e.g. to inspect partial results of the analysis while the event loop is running. For
   /// example one can draw an up-to-date version of a result histogram every 100 entries like this:
   /// \code{.cpp}
   /// auto h = tdf.Histo1D("x");
   /// TCanvas c("c","x hist");
   /// h.OnPartialResult(100, [&c](TH1D &h_) { c.cd(); h_.Draw(); c.Update(); });
   /// h->Draw(); // event loop runs here, this `Draw` is executed after the event loop is finished
   /// \endcode
   ///
   /// A value of 0 for everyNEvents indicates the callback must be executed only once, before running the event loop.
   /// A conveniece definition `kOnce` is provided to make this fact more expressive in user code (see snippet below).
   /// Multiple callbacks can be registered with the same TResultProxy (i.e. results of TDataFrame actions) and will
   /// be executed sequentially. Callbacks are executed in the order they were registered.
   /// The type of the value contained in a TResultProxy is also available as TResultProxy<T>::Value_t, e.g.
   /// \code{.cpp}
   /// auto h = tdf.Histo1D("x");
   /// // h.kOnce is 0
   /// // decltype(h)::Value_t is TH1D
   /// \endcode
   ///
   /// When implicit multi-threading is enabled, the callback:
   /// - will never be executed by multiple threads concurrently: it needs not be thread-safe. For example the snippet
   ///   above that draws the partial histogram on a canvas works seamlessly in multi-thread event loops.
   /// - will always be executed "everyNEvents": partial results will "contain" that number of events more from
   ///   one call to the next
   /// - might be executed by a different worker thread at different times: the value of `std::this_thread::get_id()`
   ///   might change between calls
   /// To register a callback that is called by _each_ worker thread (concurrently) every N events one can use
   /// OnPartialResultSlot.
   void OnPartialResult(ULong64_t everyNEvents, std::function<void(T&)> callback)
   {
      auto actionPtrPtr = fActionPtrPtr.get();
      auto c = [actionPtrPtr, callback](unsigned int slot) {
         if (slot != 0)
            return;
         auto partialResult = static_cast<Value_t*>((*actionPtrPtr)->PartialUpdate(slot));
         callback(*partialResult);
      };
      RegisterCallback(everyNEvents, std::move(c));
   }

   /// Register a callback that TDataFrame will execute in each worker thread concurrently on that thread's partial result.
   ///
   /// \param[in] everyNEvents Frequency at which the callback will be called by each thread, as a number of events processed
   /// \param[in] a callable with signature `void(unsigned int, Value_t&)` where Value_t is the type of the value contained in this TResultProxy
   ///
   /// See `RegisterCallback` for a generic explanation of the callback mechanism.
   /// Compared to `RegisterCallback`, this method has two major differences:
   /// - all worker threads invoke the callback once every specified number of events. The event count is per-thread,
   ///   and callback invocation might happen concurrently (i.e. the callback must be thread-safe)
   /// - the callable must take an extra `unsigned int` parameter corresponding to a multi-thread "processing slot":
   ///   this is a "helper value" to simplify writing thread-safe callbacks: different worker threads might invoke the
   ///   callback concurrently but always with different `slot` numbers.
   /// - a value of 0 for everyNEvents indicates the callback must be executed once _per slot_.
   ///
   /// For example, the following snippet prints out a thread-safe progress bar of the events processed by TDataFrame
   /// \code
   /// auto c = tdf.Count(); // any action would do, but `Count` is the most lightweight
   /// std::string progress;
   /// std::mutex bar_mutex;
   /// c.OnPartialResultSlot(nEvents / 100, [&progress, &bar_mutex](unsigned int, ULong64_t &) {
   ///    std::lock_guard<std::mutex> lg(bar_mutex);
   ///    progress.push_back('#');
   ///    std::cout << "\r[" << std::left << std::setw(100) << progress << ']' << std::flush;
   /// });
   /// std::cout << "Analysis running..." << std::endl;
   /// *c; // trigger the event loop by accessing an action's result
   /// std::cout << "\nDone!" << std::endl;
   /// \endcode
   void OnPartialResultSlot(ULong64_t everyNEvents, std::function<void(unsigned int, T&)> callback)
   {
      auto actionPtrPtr = fActionPtrPtr.get();
      auto c = [actionPtrPtr, callback](unsigned int slot) {
         auto partialResult = static_cast<Value_t*>((*actionPtrPtr)->PartialUpdate(slot));
         callback(slot, *partialResult);
      };
      RegisterCallback(everyNEvents, std::move(c));
   }
};

template <typename T>
void TResultProxy<T>::TriggerRun()
{
   auto df = fImplWeakPtr.lock();
   if (!df) {
      throw std::runtime_error("The main TDataFrame is not reachable: did it go out of scope?");
   }
   df->Run();
}
} // end NS TDF
} // end NS Experimental

namespace Detail {
namespace TDF {
/// Create a TResultProxy and set its pointer to the corresponding TAction
/// This overload is invoked by non-jitted actions, as they have access to TAction before constructing TResultProxy.
template <typename T>
TResultProxy<T> MakeResultProxy(const std::shared_ptr<T> &r, const std::shared_ptr<TLoopManager> &df,
                                TDFInternal::TActionBase *actionPtr)
{
   auto readiness = std::make_shared<bool>(false);
   auto resPtr = TResultProxy<T>(r, readiness, df, actionPtr);
   df->Book(readiness);
   return resPtr;
}

/// Create a TResultProxy and return it together with its pointer to TAction
/// This overload is invoked by jitted actions; the pointer to TAction will be set right before the loop by jitted code
template <typename T>
std::pair<TResultProxy<T>, std::shared_ptr<TDFInternal::TActionBase *>>
MakeResultProxy(const std::shared_ptr<T> &r, const std::shared_ptr<TLoopManager> &df)
{
   auto readiness = std::make_shared<bool>(false);
   auto resPtr = TResultProxy<T>(r, readiness, df);
   df->Book(readiness);
   return std::make_pair(resPtr, resPtr.GetActionPtrPtr());
}
} // end NS TDF
} // end NS Detail
} // end NS ROOT

#endif // ROOT_TRESULTPROXY
<commit_msg>[TDF] Reorder alias and friend declarations in TResultProxy<commit_after>// Author: Enrico Guiraud, Danilo Piparo CERN  03/2017

/*************************************************************************
 * Copyright (C) 1995-2016, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TRESULTPROXY
#define ROOT_TRESULTPROXY

#include "ROOT/TypeTraits.hxx"
#include "ROOT/TDFNodes.hxx"
#include "TError.h" // Warning

#include <memory>
#include <functional>

namespace ROOT {

namespace Experimental {
namespace TDF {
// Fwd decl for MakeResultProxy
template <typename T>
class TResultProxy;
}
}

namespace Detail {
namespace TDF {
using ROOT::Experimental::TDF::TResultProxy;
// Fwd decl for TResultProxy
template <typename T>
TResultProxy<T> MakeResultProxy(const std::shared_ptr<T> &r, const std::shared_ptr<TLoopManager> &df,
                                TDFInternal::TActionBase *actionPtr);
template <typename T>
std::pair<TResultProxy<T>, std::shared_ptr<ROOT::Internal::TDF::TActionBase *>>
MakeResultProxy(const std::shared_ptr<T> &r, const std::shared_ptr<TLoopManager> &df);
} // ns TDF
} // ns Detail

namespace Experimental {
namespace TDF {
namespace TDFInternal = ROOT::Internal::TDF;
namespace TDFDetail = ROOT::Detail::TDF;
namespace TTraits = ROOT::TypeTraits;

/// Smart pointer for the return type of actions
/**
\class ROOT::Experimental::TDF::TResultProxy
\ingroup dataframe
\brief A wrapper around the result of TDataFrame actions able to trigger calculations lazily.
\tparam T Type of the action result

A smart pointer which allows to access the result of a TDataFrame action. The
methods of the encapsulated object can be accessed via the arrow operator.
Upon invocation of the arrow operator or dereferencing (`operator*`), the
loop on the events and calculations of all scheduled actions are executed
if needed.
It is possible to iterate on the result proxy if the proxied object is a collection.
~~~{.cpp}
for (auto& myItem : myResultProxy) { ... };
~~~
If iteration is not supported by the type of the proxied object, a compilation error is thrown.

*/
template <typename T>
class TResultProxy {
   // private using declarations
   using SPT_t = std::shared_ptr<T>;
   using SPTLM_t = std::shared_ptr<TDFDetail::TLoopManager>;
   using WPTLM_t = std::weak_ptr<TDFDetail::TLoopManager>;
   using ShrdPtrBool_t = std::shared_ptr<bool>;

   // friend declarations
   template <typename W>
   friend TResultProxy<W>
   TDFDetail::MakeResultProxy(const std::shared_ptr<W> &, const SPTLM_t &, TDFInternal::TActionBase *);
   template <typename W>
   friend std::pair<TResultProxy<W>, std::shared_ptr<TDFInternal::TActionBase *>>
   TDFDetail::MakeResultProxy(const std::shared_ptr<W> &, const SPTLM_t &);

   /// \cond HIDDEN_SYMBOLS
   template <typename V, bool isCont = TTraits::IsContainer<V>::value>
   struct TIterationHelper {
      using Iterator_t = void;
      void GetBegin(const V &) { static_assert(sizeof(V) == 0, "It does not make sense to ask begin for this class."); }
      void GetEnd(const V &) { static_assert(sizeof(V) == 0, "It does not make sense to ask end for this class."); }
   };

   template <typename V>
   struct TIterationHelper<V, true> {
      using Iterator_t = decltype(std::begin(std::declval<V>()));
      static Iterator_t GetBegin(const V &v) { return std::begin(v); };
      static Iterator_t GetEnd(const V &v) { return std::end(v); };
   };
   /// \endcond

   /// State registered also in the TLoopManager until the event loop is executed
   const ShrdPtrBool_t fReadiness = std::make_shared<bool>(false);
   WPTLM_t fImplWeakPtr; ///< Points to the TLoopManager at the root of the functional graph
   const SPT_t fObjPtr;  ///< Shared pointer encapsulating the wrapped result
   /// Shared_ptr to a _pointer_ to the TDF action that produces this result. It is set at construction time for
   /// non-jitted actions, and at jitting time for jitted actions (at the time of writing, this means right
   /// before the event-loop).
   // N.B. what's on the heap is the _pointer_ to TActionBase, we are _not_ taking shared ownership of a TAction.
   // This cannot be a unique_ptr because that would disallow copy-construction of TResultProxies.
   // It cannot be just a pointer to TActionBase because we need something to store in the callback callable that will
   // be passed to TLoopManager _before_ the pointer to TActionBase is set in the case of jitted actions.
   const std::shared_ptr<TDFInternal::TActionBase *> fActionPtrPtr;

   /// Triggers the event loop in the TLoopManager instance to which it's associated via the fImplWeakPtr
   void TriggerRun();

   /// Get the pointer to the encapsulated result.
   /// Ownership is not transferred to the caller.
   /// Triggers event loop and execution of all actions booked in the associated TLoopManager.
   T *Get()
   {
      if (!*fReadiness)
         TriggerRun();
      return fObjPtr.get();
   }

   TResultProxy(const SPT_t &objPtr, const ShrdPtrBool_t &readiness, const SPTLM_t &loopManager,
                TDFInternal::TActionBase *actionPtr = nullptr)
      : fReadiness(readiness), fImplWeakPtr(loopManager), fObjPtr(objPtr),
        fActionPtrPtr(new (TDFInternal::TActionBase *)(actionPtr))
   {
   }

   std::shared_ptr<TDFInternal::TActionBase *> GetActionPtrPtr() const { return fActionPtrPtr; }

   void RegisterCallback(ULong64_t everyNEvents, std::function<void(unsigned int)> &&c) {
      auto lm = fImplWeakPtr.lock();
      if (!lm)
         throw std::runtime_error("The main TDataFrame is not reachable: did it go out of scope?");
      lm->RegisterCallback(everyNEvents, std::move(c));
   }

public:
   using Value_t = T; ///< Convenience alias to simplify access to proxied type
   static constexpr ULong64_t kOnce = 0ull; ///< Convenience definition to express a callback must be executed once

   TResultProxy() = delete;
   TResultProxy(const TResultProxy &) = default;
   TResultProxy(TResultProxy &&) = default;

   /// Get a const reference to the encapsulated object.
   /// Triggers event loop and execution of all actions booked in the associated TLoopManager.
   const T &GetValue() { return *Get(); }

   /// Get a pointer to the encapsulated object.
   /// Triggers event loop and execution of all actions booked in the associated TLoopManager.
   T &operator*() { return *Get(); }

   /// Get a pointer to the encapsulated object.
   /// Ownership is not transferred to the caller.
   /// Triggers event loop and execution of all actions booked in the associated TLoopManager.
   T *operator->() { return Get(); }

   /// Return an iterator to the beginning of the contained object if this makes
   /// sense, throw a compilation error otherwise
   typename TIterationHelper<T>::Iterator_t begin()
   {
      if (!*fReadiness)
         TriggerRun();
      return TIterationHelper<T>::GetBegin(*fObjPtr);
   }

   /// Return an iterator to the end of the contained object if this makes
   /// sense, throw a compilation error otherwise
   typename TIterationHelper<T>::Iterator_t end()
   {
      if (!*fReadiness)
         TriggerRun();
      return TIterationHelper<T>::GetEnd(*fObjPtr);
   }

   /// Register a callback that TDataFrame will execute "everyNEvents" on a partial result.
   ///
   /// \param[in] everyNEvents Frequency at which the callback will be called, as a number of events processed
   /// \param[in] callback a callable with signature `void(Value_t&)` where Value_t is the type of the value contained in this TResultProxy
   ///
   /// The callback must be a callable (lambda, function, functor class...) that takes a reference to the result type as
   /// argument and returns nothing. TDataFrame will invoke registered callbacks passing partial action results as
   /// arguments to them (e.g. a histogram filled with a part of the selected events, a counter incremented only up to a
   /// certain point, a mean over a subset of the events and so forth).
   ///
   /// Callbacks can be used e.g. to inspect partial results of the analysis while the event loop is running. For
   /// example one can draw an up-to-date version of a result histogram every 100 entries like this:
   /// \code{.cpp}
   /// auto h = tdf.Histo1D("x");
   /// TCanvas c("c","x hist");
   /// h.OnPartialResult(100, [&c](TH1D &h_) { c.cd(); h_.Draw(); c.Update(); });
   /// h->Draw(); // event loop runs here, this `Draw` is executed after the event loop is finished
   /// \endcode
   ///
   /// A value of 0 for everyNEvents indicates the callback must be executed only once, before running the event loop.
   /// A conveniece definition `kOnce` is provided to make this fact more expressive in user code (see snippet below).
   /// Multiple callbacks can be registered with the same TResultProxy (i.e. results of TDataFrame actions) and will
   /// be executed sequentially. Callbacks are executed in the order they were registered.
   /// The type of the value contained in a TResultProxy is also available as TResultProxy<T>::Value_t, e.g.
   /// \code{.cpp}
   /// auto h = tdf.Histo1D("x");
   /// // h.kOnce is 0
   /// // decltype(h)::Value_t is TH1D
   /// \endcode
   ///
   /// When implicit multi-threading is enabled, the callback:
   /// - will never be executed by multiple threads concurrently: it needs not be thread-safe. For example the snippet
   ///   above that draws the partial histogram on a canvas works seamlessly in multi-thread event loops.
   /// - will always be executed "everyNEvents": partial results will "contain" that number of events more from
   ///   one call to the next
   /// - might be executed by a different worker thread at different times: the value of `std::this_thread::get_id()`
   ///   might change between calls
   /// To register a callback that is called by _each_ worker thread (concurrently) every N events one can use
   /// OnPartialResultSlot.
   void OnPartialResult(ULong64_t everyNEvents, std::function<void(T&)> callback)
   {
      auto actionPtrPtr = fActionPtrPtr.get();
      auto c = [actionPtrPtr, callback](unsigned int slot) {
         if (slot != 0)
            return;
         auto partialResult = static_cast<Value_t*>((*actionPtrPtr)->PartialUpdate(slot));
         callback(*partialResult);
      };
      RegisterCallback(everyNEvents, std::move(c));
   }

   /// Register a callback that TDataFrame will execute in each worker thread concurrently on that thread's partial result.
   ///
   /// \param[in] everyNEvents Frequency at which the callback will be called by each thread, as a number of events processed
   /// \param[in] a callable with signature `void(unsigned int, Value_t&)` where Value_t is the type of the value contained in this TResultProxy
   ///
   /// See `RegisterCallback` for a generic explanation of the callback mechanism.
   /// Compared to `RegisterCallback`, this method has two major differences:
   /// - all worker threads invoke the callback once every specified number of events. The event count is per-thread,
   ///   and callback invocation might happen concurrently (i.e. the callback must be thread-safe)
   /// - the callable must take an extra `unsigned int` parameter corresponding to a multi-thread "processing slot":
   ///   this is a "helper value" to simplify writing thread-safe callbacks: different worker threads might invoke the
   ///   callback concurrently but always with different `slot` numbers.
   /// - a value of 0 for everyNEvents indicates the callback must be executed once _per slot_.
   ///
   /// For example, the following snippet prints out a thread-safe progress bar of the events processed by TDataFrame
   /// \code
   /// auto c = tdf.Count(); // any action would do, but `Count` is the most lightweight
   /// std::string progress;
   /// std::mutex bar_mutex;
   /// c.OnPartialResultSlot(nEvents / 100, [&progress, &bar_mutex](unsigned int, ULong64_t &) {
   ///    std::lock_guard<std::mutex> lg(bar_mutex);
   ///    progress.push_back('#');
   ///    std::cout << "\r[" << std::left << std::setw(100) << progress << ']' << std::flush;
   /// });
   /// std::cout << "Analysis running..." << std::endl;
   /// *c; // trigger the event loop by accessing an action's result
   /// std::cout << "\nDone!" << std::endl;
   /// \endcode
   void OnPartialResultSlot(ULong64_t everyNEvents, std::function<void(unsigned int, T&)> callback)
   {
      auto actionPtrPtr = fActionPtrPtr.get();
      auto c = [actionPtrPtr, callback](unsigned int slot) {
         auto partialResult = static_cast<Value_t*>((*actionPtrPtr)->PartialUpdate(slot));
         callback(slot, *partialResult);
      };
      RegisterCallback(everyNEvents, std::move(c));
   }
};

template <typename T>
void TResultProxy<T>::TriggerRun()
{
   auto df = fImplWeakPtr.lock();
   if (!df) {
      throw std::runtime_error("The main TDataFrame is not reachable: did it go out of scope?");
   }
   df->Run();
}
} // end NS TDF
} // end NS Experimental

namespace Detail {
namespace TDF {
/// Create a TResultProxy and set its pointer to the corresponding TAction
/// This overload is invoked by non-jitted actions, as they have access to TAction before constructing TResultProxy.
template <typename T>
TResultProxy<T> MakeResultProxy(const std::shared_ptr<T> &r, const std::shared_ptr<TLoopManager> &df,
                                TDFInternal::TActionBase *actionPtr)
{
   auto readiness = std::make_shared<bool>(false);
   auto resPtr = TResultProxy<T>(r, readiness, df, actionPtr);
   df->Book(readiness);
   return resPtr;
}

/// Create a TResultProxy and return it together with its pointer to TAction
/// This overload is invoked by jitted actions; the pointer to TAction will be set right before the loop by jitted code
template <typename T>
std::pair<TResultProxy<T>, std::shared_ptr<TDFInternal::TActionBase *>>
MakeResultProxy(const std::shared_ptr<T> &r, const std::shared_ptr<TLoopManager> &df)
{
   auto readiness = std::make_shared<bool>(false);
   auto resPtr = TResultProxy<T>(r, readiness, df);
   df->Book(readiness);
   return std::make_pair(resPtr, resPtr.GetActionPtrPtr());
}
} // end NS TDF
} // end NS Detail
} // end NS ROOT

#endif // ROOT_TRESULTPROXY
<|endoftext|>


<commit_before>// @(#)root/ldap:$Id$
// Author: Evgenia Smirnova   21/09/2001

/*************************************************************************
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TLDAPAttribute.h"
#include "TObjString.h"
#include "Riostream.h"

ClassImp(TLDAPAttribute)

//______________________________________________________________________________
TLDAPAttribute::TLDAPAttribute(const char *name) : fNCount(0)
{
   //constructor
   SetName(name);
   fValues = new TList;
   fValues->SetOwner();
}

//______________________________________________________________________________
TLDAPAttribute::TLDAPAttribute(const char *name, const char *value)
   : fNCount(0)
{
   // Creates an Attribute with name and value.

   SetName(name);
   fValues = new TList;
   fValues->SetOwner();
   AddValue(value);
}

//______________________________________________________________________________
TLDAPAttribute::TLDAPAttribute(const TLDAPAttribute &attr)
   : TNamed(attr), fNCount(attr.fNCount)
{
   // LDAP attribute copy ctor.

   fValues = new TList;
   fValues->SetOwner();

   TIter next(attr.fValues);
   while (TObjString *str = (TObjString*) next()) {
      fValues->AddLast(new TObjString(str->GetName()));
   }
}

//______________________________________________________________________________
TLDAPAttribute& TLDAPAttribute::operator=(const TLDAPAttribute &attr)
{
   // Equal operator
   if(this!=&attr) {
      TNamed::operator=(attr);
      fValues=attr.fValues;
      fNCount=attr.fNCount;
   } return *this;
}

//______________________________________________________________________________
TLDAPAttribute::~TLDAPAttribute()
{
   //destructor
   delete fValues;
}

//______________________________________________________________________________
void TLDAPAttribute::AddValue(const char *value)
{
   // Add a value to the attribute.

   fValues->AddLast(new TObjString(value));
}

//______________________________________________________________________________
void TLDAPAttribute::DeleteValue(const char *value)
{
   // Delete value by name.

   Int_t n = GetCount();
   for (Int_t i = 0; i < n; i++) {
      TObjString *v = (TObjString*) fValues->At(i);
      if (v->String().CompareTo(value) == 0) {
         delete fValues->Remove(v);
         if (fNCount > i) fNCount--;
         return;
      }
   }
}

//______________________________________________________________________________
const char *TLDAPAttribute::GetValue() const
{
   // Get next value of the attribute. Returns zero after the last value,
   // then returns the first value again.

   Int_t n = GetCount();
   if (n > fNCount) {
      return ((TObjString*)fValues->At(fNCount++))->GetName();
   } else {
      fNCount = 0;
      return 0;
   }
}

//_______________________________________________________________________________
void TLDAPAttribute::Print(Option_t *) const
{
   // Print an attribute.

   Int_t counter = GetCount();
   if (counter == 0) {
      cout << GetName() << ": " << endl;
   } else if (counter != 0) {
      for (Int_t i = 0; i < counter; i++) {
         cout << GetName() << ": " << GetValue() << endl;
      }
   }
}

//_______________________________________________________________________________
LDAPMod *TLDAPAttribute::GetMod(Int_t op)
{
   // Get "LDAPMod" structure for attribute. Returned LDAPMod must be
   // deleted by the user.

   LDAPMod *tmpMod = new LDAPMod;
   Int_t iCount = GetCount();
   char **values = new char* [iCount + 1];
   char *type = new char [strlen(GetName())+1];
   for (int i = 0; i < iCount; i++) {
      values[i] = new char [strlen(((TObjString*)fValues->At(i))->GetName()) + 1];
      strcpy(values[i], ((TObjString*)fValues->At(i))->GetName());
   }

   values[iCount] = 0;
   strcpy(type, GetName());
   tmpMod->mod_values = values;
   tmpMod->mod_type = type;
   tmpMod->mod_op = op;

   return tmpMod;
}
<commit_msg>Fix secure coding. coverity CID 14007<commit_after>// @(#)root/ldap:$Id$
// Author: Evgenia Smirnova   21/09/2001

/*************************************************************************
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TLDAPAttribute.h"
#include "TObjString.h"
#include "Riostream.h"

ClassImp(TLDAPAttribute)

//______________________________________________________________________________
TLDAPAttribute::TLDAPAttribute(const char *name) : fNCount(0)
{
   //constructor
   SetName(name);
   fValues = new TList;
   fValues->SetOwner();
}

//______________________________________________________________________________
TLDAPAttribute::TLDAPAttribute(const char *name, const char *value)
   : fNCount(0)
{
   // Creates an Attribute with name and value.

   SetName(name);
   fValues = new TList;
   fValues->SetOwner();
   AddValue(value);
}

//______________________________________________________________________________
TLDAPAttribute::TLDAPAttribute(const TLDAPAttribute &attr)
   : TNamed(attr), fNCount(attr.fNCount)
{
   // LDAP attribute copy ctor.

   fValues = new TList;
   fValues->SetOwner();

   TIter next(attr.fValues);
   while (TObjString *str = (TObjString*) next()) {
      fValues->AddLast(new TObjString(str->GetName()));
   }
}

//______________________________________________________________________________
TLDAPAttribute& TLDAPAttribute::operator=(const TLDAPAttribute &attr)
{
   // Equal operator
   if(this!=&attr) {
      TNamed::operator=(attr);
      fValues=attr.fValues;
      fNCount=attr.fNCount;
   } return *this;
}

//______________________________________________________________________________
TLDAPAttribute::~TLDAPAttribute()
{
   //destructor
   delete fValues;
}

//______________________________________________________________________________
void TLDAPAttribute::AddValue(const char *value)
{
   // Add a value to the attribute.

   fValues->AddLast(new TObjString(value));
}

//______________________________________________________________________________
void TLDAPAttribute::DeleteValue(const char *value)
{
   // Delete value by name.

   Int_t n = GetCount();
   for (Int_t i = 0; i < n; i++) {
      TObjString *v = (TObjString*) fValues->At(i);
      if (v->String().CompareTo(value) == 0) {
         delete fValues->Remove(v);
         if (fNCount > i) fNCount--;
         return;
      }
   }
}

//______________________________________________________________________________
const char *TLDAPAttribute::GetValue() const
{
   // Get next value of the attribute. Returns zero after the last value,
   // then returns the first value again.

   Int_t n = GetCount();
   if (n > fNCount) {
      return ((TObjString*)fValues->At(fNCount++))->GetName();
   } else {
      fNCount = 0;
      return 0;
   }
}

//_______________________________________________________________________________
void TLDAPAttribute::Print(Option_t *) const
{
   // Print an attribute.

   Int_t counter = GetCount();
   if (counter == 0) {
      cout << GetName() << ": " << endl;
   } else if (counter != 0) {
      for (Int_t i = 0; i < counter; i++) {
         cout << GetName() << ": " << GetValue() << endl;
      }
   }
}

//_______________________________________________________________________________
LDAPMod *TLDAPAttribute::GetMod(Int_t op)
{
   // Get "LDAPMod" structure for attribute. Returned LDAPMod must be
   // deleted by the user.

   LDAPMod *tmpMod = new LDAPMod;
   Int_t iCount = GetCount();
   char **values = new char* [iCount + 1];
   char *type = new char [strlen(GetName())+1];
   for (int i = 0; i < iCount; i++) {
      int nch = strlen(((TObjString*)fValues->At(i))->GetName()) + 1;
      values[i] = new char [nch];
      strlcpy(values[i], ((TObjString*)fValues->At(i))->GetName(),nch);
   }

   values[iCount] = 0;
   strcpy(type, GetName());
   tmpMod->mod_values = values;
   tmpMod->mod_type = type;
   tmpMod->mod_op = op;

   return tmpMod;
}
<|endoftext|>


<commit_before><commit_msg>vcl: remove dead code from brdwin.cxx<commit_after><|endoftext|>


<commit_before><commit_msg>vcl: Sidebar corner case.<commit_after><|endoftext|>


<commit_before><commit_msg>Once ~SystemWindow calls ~Window, this is no longer a SystemWindow<commit_after><|endoftext|>


<commit_before><commit_msg>coverity#441048 silence Dereference after null check<commit_after><|endoftext|>