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

#include "webrtc/modules/video_coding/packet_buffer.h"

#include <algorithm>
#include <limits>
#include <utility>

#include "webrtc/base/atomicops.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/modules/video_coding/frame_object.h"
#include "webrtc/system_wrappers/include/clock.h"

namespace webrtc {
namespace video_coding {

rtc::scoped_refptr<PacketBuffer> PacketBuffer::Create(
    Clock* clock,
    size_t start_buffer_size,
    size_t max_buffer_size,
    OnReceivedFrameCallback* received_frame_callback) {
  return rtc::scoped_refptr<PacketBuffer>(new PacketBuffer(
      clock, start_buffer_size, max_buffer_size, received_frame_callback));
}

PacketBuffer::PacketBuffer(Clock* clock,
                           size_t start_buffer_size,
                           size_t max_buffer_size,
                           OnReceivedFrameCallback* received_frame_callback)
    : clock_(clock),
      size_(start_buffer_size),
      max_size_(max_buffer_size),
      first_seq_num_(0),
      first_packet_received_(false),
      is_cleared_to_first_seq_num_(false),
      data_buffer_(start_buffer_size),
      sequence_buffer_(start_buffer_size),
      received_frame_callback_(received_frame_callback) {
  RTC_DCHECK_LE(start_buffer_size, max_buffer_size);
  // Buffer size must always be a power of 2.
  RTC_DCHECK((start_buffer_size & (start_buffer_size - 1)) == 0);
  RTC_DCHECK((max_buffer_size & (max_buffer_size - 1)) == 0);
}

PacketBuffer::~PacketBuffer() {
  Clear();
}

bool PacketBuffer::InsertPacket(VCMPacket* packet) {
  std::vector<std::unique_ptr<RtpFrameObject>> found_frames;
  {
    rtc::CritScope lock(&crit_);
    uint16_t seq_num = packet->seqNum;
    size_t index = seq_num % size_;

    if (!first_packet_received_) {
      first_seq_num_ = seq_num;
      first_packet_received_ = true;
    } else if (AheadOf(first_seq_num_, seq_num)) {
      // If we have explicitly cleared past this packet then it's old,
      // don't insert it.
      if (is_cleared_to_first_seq_num_) {
        delete[] packet->dataPtr;
        packet->dataPtr = nullptr;
        return false;
      }

      first_seq_num_ = seq_num;
    }

    if (sequence_buffer_[index].used) {
      // Duplicate packet, just delete the payload.
      if (data_buffer_[index].seqNum == packet->seqNum) {
        delete[] packet->dataPtr;
        packet->dataPtr = nullptr;
        return true;
      }

      // The packet buffer is full, try to expand the buffer.
      while (ExpandBufferSize() && sequence_buffer_[seq_num % size_].used) {
      }
      index = seq_num % size_;

      // Packet buffer is still full.
      if (sequence_buffer_[index].used) {
        delete[] packet->dataPtr;
        packet->dataPtr = nullptr;
        return false;
      }
    }

    sequence_buffer_[index].frame_begin = packet->is_first_packet_in_frame;
    sequence_buffer_[index].frame_end = packet->markerBit;
    sequence_buffer_[index].seq_num = packet->seqNum;
    sequence_buffer_[index].continuous = false;
    sequence_buffer_[index].frame_created = false;
    sequence_buffer_[index].used = true;
    data_buffer_[index] = *packet;
    packet->dataPtr = nullptr;

    found_frames = FindFrames(seq_num);
  }

  for (std::unique_ptr<RtpFrameObject>& frame : found_frames)
    received_frame_callback_->OnReceivedFrame(std::move(frame));

  return true;
}

void PacketBuffer::ClearTo(uint16_t seq_num) {
  rtc::CritScope lock(&crit_);

  // If the packet buffer was cleared between a frame was created and returned.
  if (!first_packet_received_)
    return;

  is_cleared_to_first_seq_num_ = true;
  while (AheadOrAt<uint16_t>(seq_num, first_seq_num_)) {
    size_t index = first_seq_num_ % size_;
    delete[] data_buffer_[index].dataPtr;
    data_buffer_[index].dataPtr = nullptr;
    sequence_buffer_[index].used = false;
    ++first_seq_num_;
  }
}

void PacketBuffer::Clear() {
  rtc::CritScope lock(&crit_);
  for (size_t i = 0; i < size_; ++i) {
    delete[] data_buffer_[i].dataPtr;
    data_buffer_[i].dataPtr = nullptr;
    sequence_buffer_[i].used = false;
  }

  first_packet_received_ = false;
  is_cleared_to_first_seq_num_ = false;
}

bool PacketBuffer::ExpandBufferSize() {
  if (size_ == max_size_) {
    LOG(LS_WARNING) << "PacketBuffer is already at max size (" << max_size_
                    << "), failed to increase size.";
    return false;
  }

  size_t new_size = std::min(max_size_, 2 * size_);
  std::vector<VCMPacket> new_data_buffer(new_size);
  std::vector<ContinuityInfo> new_sequence_buffer(new_size);
  for (size_t i = 0; i < size_; ++i) {
    if (sequence_buffer_[i].used) {
      size_t index = sequence_buffer_[i].seq_num % new_size;
      new_sequence_buffer[index] = sequence_buffer_[i];
      new_data_buffer[index] = data_buffer_[i];
    }
  }
  size_ = new_size;
  sequence_buffer_ = std::move(new_sequence_buffer);
  data_buffer_ = std::move(new_data_buffer);
  LOG(LS_INFO) << "PacketBuffer size expanded to " << new_size;
  return true;
}

bool PacketBuffer::PotentialNewFrame(uint16_t seq_num) const {
  size_t index = seq_num % size_;
  int prev_index = index > 0 ? index - 1 : size_ - 1;

  if (!sequence_buffer_[index].used)
    return false;
  if (sequence_buffer_[index].frame_created)
    return false;
  if (sequence_buffer_[index].frame_begin)
    return true;
  if (!sequence_buffer_[prev_index].used)
    return false;
  if (sequence_buffer_[prev_index].frame_created)
    return false;
  if (sequence_buffer_[prev_index].seq_num !=
      static_cast<uint16_t>(sequence_buffer_[index].seq_num - 1)) {
    return false;
  }
  if (sequence_buffer_[prev_index].continuous)
    return true;

  return false;
}

std::vector<std::unique_ptr<RtpFrameObject>> PacketBuffer::FindFrames(
    uint16_t seq_num) {
  std::vector<std::unique_ptr<RtpFrameObject>> found_frames;
  size_t packets_tested = 0;
  while (packets_tested < size_ && PotentialNewFrame(seq_num)) {
    size_t index = seq_num % size_;
    sequence_buffer_[index].continuous = true;

    // If all packets of the frame is continuous, find the first packet of the
    // frame and create an RtpFrameObject.
    if (sequence_buffer_[index].frame_end) {
      size_t frame_size = 0;
      int max_nack_count = -1;
      uint16_t start_seq_num = seq_num;

      // Find the start index by searching backward until the packet with
      // the |frame_begin| flag is set.
      int start_index = index;
      while (true) {
        frame_size += data_buffer_[start_index].sizeBytes;
        max_nack_count =
            std::max(max_nack_count, data_buffer_[start_index].timesNacked);
        sequence_buffer_[start_index].frame_created = true;

        if (sequence_buffer_[start_index].frame_begin)
          break;

        start_index = start_index > 0 ? start_index - 1 : size_ - 1;
        start_seq_num--;
      }

      found_frames.emplace_back(
          new RtpFrameObject(this, start_seq_num, seq_num, frame_size,
                             max_nack_count, clock_->TimeInMilliseconds()));
    }
    ++seq_num;
    ++packets_tested;
  }
  return found_frames;
}

void PacketBuffer::ReturnFrame(RtpFrameObject* frame) {
  rtc::CritScope lock(&crit_);
  size_t index = frame->first_seq_num() % size_;
  size_t end = (frame->last_seq_num() + 1) % size_;
  uint16_t seq_num = frame->first_seq_num();
  while (index != end) {
    if (sequence_buffer_[index].seq_num == seq_num) {
      delete[] data_buffer_[index].dataPtr;
      data_buffer_[index].dataPtr = nullptr;
      sequence_buffer_[index].used = false;
    }

    index = (index + 1) % size_;
    ++seq_num;
  }
}

bool PacketBuffer::GetBitstream(const RtpFrameObject& frame,
                                uint8_t* destination) {
  rtc::CritScope lock(&crit_);

  size_t index = frame.first_seq_num() % size_;
  size_t end = (frame.last_seq_num() + 1) % size_;
  uint16_t seq_num = frame.first_seq_num();
  while (index != end) {
    if (!sequence_buffer_[index].used ||
        sequence_buffer_[index].seq_num != seq_num) {
      return false;
    }

    const uint8_t* source = data_buffer_[index].dataPtr;
    size_t length = data_buffer_[index].sizeBytes;
    memcpy(destination, source, length);
    destination += length;
    index = (index + 1) % size_;
    ++seq_num;
  }
  return true;
}

VCMPacket* PacketBuffer::GetPacket(uint16_t seq_num) {
  size_t index = seq_num % size_;
  if (!sequence_buffer_[index].used ||
      seq_num != sequence_buffer_[index].seq_num) {
    return nullptr;
  }
  return &data_buffer_[index];
}

int PacketBuffer::AddRef() const {
  return rtc::AtomicOps::Increment(&ref_count_);
}

int PacketBuffer::Release() const {
  int count = rtc::AtomicOps::Decrement(&ref_count_);
  if (!count) {
    delete this;
  }
  return count;
}

}  // namespace video_coding
}  // namespace webrtc
<commit_msg>video_coding::PacketBuffer now group all H264 packets with the same timestamp into the same frame.<commit_after>/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/video_coding/packet_buffer.h"

#include <algorithm>
#include <limits>
#include <utility>

#include "webrtc/base/atomicops.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/modules/video_coding/frame_object.h"
#include "webrtc/system_wrappers/include/clock.h"

namespace webrtc {
namespace video_coding {

rtc::scoped_refptr<PacketBuffer> PacketBuffer::Create(
    Clock* clock,
    size_t start_buffer_size,
    size_t max_buffer_size,
    OnReceivedFrameCallback* received_frame_callback) {
  return rtc::scoped_refptr<PacketBuffer>(new PacketBuffer(
      clock, start_buffer_size, max_buffer_size, received_frame_callback));
}

PacketBuffer::PacketBuffer(Clock* clock,
                           size_t start_buffer_size,
                           size_t max_buffer_size,
                           OnReceivedFrameCallback* received_frame_callback)
    : clock_(clock),
      size_(start_buffer_size),
      max_size_(max_buffer_size),
      first_seq_num_(0),
      first_packet_received_(false),
      is_cleared_to_first_seq_num_(false),
      data_buffer_(start_buffer_size),
      sequence_buffer_(start_buffer_size),
      received_frame_callback_(received_frame_callback) {
  RTC_DCHECK_LE(start_buffer_size, max_buffer_size);
  // Buffer size must always be a power of 2.
  RTC_DCHECK((start_buffer_size & (start_buffer_size - 1)) == 0);
  RTC_DCHECK((max_buffer_size & (max_buffer_size - 1)) == 0);
}

PacketBuffer::~PacketBuffer() {
  Clear();
}

bool PacketBuffer::InsertPacket(VCMPacket* packet) {
  std::vector<std::unique_ptr<RtpFrameObject>> found_frames;
  {
    rtc::CritScope lock(&crit_);
    uint16_t seq_num = packet->seqNum;
    size_t index = seq_num % size_;

    if (!first_packet_received_) {
      first_seq_num_ = seq_num;
      first_packet_received_ = true;
    } else if (AheadOf(first_seq_num_, seq_num)) {
      // If we have explicitly cleared past this packet then it's old,
      // don't insert it.
      if (is_cleared_to_first_seq_num_) {
        delete[] packet->dataPtr;
        packet->dataPtr = nullptr;
        return false;
      }

      first_seq_num_ = seq_num;
    }

    if (sequence_buffer_[index].used) {
      // Duplicate packet, just delete the payload.
      if (data_buffer_[index].seqNum == packet->seqNum) {
        delete[] packet->dataPtr;
        packet->dataPtr = nullptr;
        return true;
      }

      // The packet buffer is full, try to expand the buffer.
      while (ExpandBufferSize() && sequence_buffer_[seq_num % size_].used) {
      }
      index = seq_num % size_;

      // Packet buffer is still full.
      if (sequence_buffer_[index].used) {
        delete[] packet->dataPtr;
        packet->dataPtr = nullptr;
        return false;
      }
    }

    sequence_buffer_[index].frame_begin = packet->is_first_packet_in_frame;
    sequence_buffer_[index].frame_end = packet->markerBit;
    sequence_buffer_[index].seq_num = packet->seqNum;
    sequence_buffer_[index].continuous = false;
    sequence_buffer_[index].frame_created = false;
    sequence_buffer_[index].used = true;
    data_buffer_[index] = *packet;
    packet->dataPtr = nullptr;

    found_frames = FindFrames(seq_num);
  }

  for (std::unique_ptr<RtpFrameObject>& frame : found_frames)
    received_frame_callback_->OnReceivedFrame(std::move(frame));

  return true;
}

void PacketBuffer::ClearTo(uint16_t seq_num) {
  rtc::CritScope lock(&crit_);

  // If the packet buffer was cleared between a frame was created and returned.
  if (!first_packet_received_)
    return;

  is_cleared_to_first_seq_num_ = true;
  while (AheadOrAt<uint16_t>(seq_num, first_seq_num_)) {
    size_t index = first_seq_num_ % size_;
    delete[] data_buffer_[index].dataPtr;
    data_buffer_[index].dataPtr = nullptr;
    sequence_buffer_[index].used = false;
    ++first_seq_num_;
  }
}

void PacketBuffer::Clear() {
  rtc::CritScope lock(&crit_);
  for (size_t i = 0; i < size_; ++i) {
    delete[] data_buffer_[i].dataPtr;
    data_buffer_[i].dataPtr = nullptr;
    sequence_buffer_[i].used = false;
  }

  first_packet_received_ = false;
  is_cleared_to_first_seq_num_ = false;
}

bool PacketBuffer::ExpandBufferSize() {
  if (size_ == max_size_) {
    LOG(LS_WARNING) << "PacketBuffer is already at max size (" << max_size_
                    << "), failed to increase size.";
    return false;
  }

  size_t new_size = std::min(max_size_, 2 * size_);
  std::vector<VCMPacket> new_data_buffer(new_size);
  std::vector<ContinuityInfo> new_sequence_buffer(new_size);
  for (size_t i = 0; i < size_; ++i) {
    if (sequence_buffer_[i].used) {
      size_t index = sequence_buffer_[i].seq_num % new_size;
      new_sequence_buffer[index] = sequence_buffer_[i];
      new_data_buffer[index] = data_buffer_[i];
    }
  }
  size_ = new_size;
  sequence_buffer_ = std::move(new_sequence_buffer);
  data_buffer_ = std::move(new_data_buffer);
  LOG(LS_INFO) << "PacketBuffer size expanded to " << new_size;
  return true;
}

bool PacketBuffer::PotentialNewFrame(uint16_t seq_num) const {
  size_t index = seq_num % size_;
  int prev_index = index > 0 ? index - 1 : size_ - 1;

  if (!sequence_buffer_[index].used)
    return false;
  if (sequence_buffer_[index].frame_created)
    return false;
  if (sequence_buffer_[index].frame_begin)
    return true;
  if (!sequence_buffer_[prev_index].used)
    return false;
  if (sequence_buffer_[prev_index].frame_created)
    return false;
  if (sequence_buffer_[prev_index].seq_num !=
      static_cast<uint16_t>(sequence_buffer_[index].seq_num - 1)) {
    return false;
  }
  if (sequence_buffer_[prev_index].continuous)
    return true;

  return false;
}

std::vector<std::unique_ptr<RtpFrameObject>> PacketBuffer::FindFrames(
    uint16_t seq_num) {
  std::vector<std::unique_ptr<RtpFrameObject>> found_frames;
  size_t packets_tested = 0;
  while (packets_tested < size_ && PotentialNewFrame(seq_num)) {
    size_t index = seq_num % size_;
    sequence_buffer_[index].continuous = true;

    // If all packets of the frame is continuous, find the first packet of the
    // frame and create an RtpFrameObject.
    if (sequence_buffer_[index].frame_end) {
      size_t frame_size = 0;
      int max_nack_count = -1;
      uint16_t start_seq_num = seq_num;

      // Find the start index by searching backward until the packet with
      // the |frame_begin| flag is set.
      int start_index = index;

      bool is_h264 = data_buffer_[start_index].codec == kVideoCodecH264;
      int64_t frame_timestamp = data_buffer_[start_index].timestamp;
      while (true) {
        frame_size += data_buffer_[start_index].sizeBytes;
        max_nack_count =
            std::max(max_nack_count, data_buffer_[start_index].timesNacked);
        sequence_buffer_[start_index].frame_created = true;

        if (!is_h264 && sequence_buffer_[start_index].frame_begin)
          break;

        start_index = start_index > 0 ? start_index - 1 : size_ - 1;

        // In the case of H264 we don't have a frame_begin bit (yes,
        // |frame_begin| might be set to true but that is a lie). So instead
        // we traverese backwards as long as we have a previous packet and
        // the timestamp of that packet is the same as this one. This may cause
        // the PacketBuffer to hand out incomplete frames.
        // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=7106
        //
        // Since we ignore the |frame_begin| flag of the inserted packets
        // we check that |start_index != static_cast<int>(index)| to make sure
        // that we don't get stuck in a loop if the packet buffer is filled
        // with packets of the same timestamp.
        if (is_h264 && start_index != static_cast<int>(index) &&
            (!sequence_buffer_[start_index].used ||
             data_buffer_[start_index].timestamp != frame_timestamp)) {
          break;
        }

        --start_seq_num;
      }

      found_frames.emplace_back(
          new RtpFrameObject(this, start_seq_num, seq_num, frame_size,
                             max_nack_count, clock_->TimeInMilliseconds()));
    }
    ++seq_num;
    ++packets_tested;
  }
  return found_frames;
}

void PacketBuffer::ReturnFrame(RtpFrameObject* frame) {
  rtc::CritScope lock(&crit_);
  size_t index = frame->first_seq_num() % size_;
  size_t end = (frame->last_seq_num() + 1) % size_;
  uint16_t seq_num = frame->first_seq_num();
  while (index != end) {
    if (sequence_buffer_[index].seq_num == seq_num) {
      delete[] data_buffer_[index].dataPtr;
      data_buffer_[index].dataPtr = nullptr;
      sequence_buffer_[index].used = false;
    }

    index = (index + 1) % size_;
    ++seq_num;
  }
}

bool PacketBuffer::GetBitstream(const RtpFrameObject& frame,
                                uint8_t* destination) {
  rtc::CritScope lock(&crit_);

  size_t index = frame.first_seq_num() % size_;
  size_t end = (frame.last_seq_num() + 1) % size_;
  uint16_t seq_num = frame.first_seq_num();
  while (index != end) {
    if (!sequence_buffer_[index].used ||
        sequence_buffer_[index].seq_num != seq_num) {
      return false;
    }

    const uint8_t* source = data_buffer_[index].dataPtr;
    size_t length = data_buffer_[index].sizeBytes;
    memcpy(destination, source, length);
    destination += length;
    index = (index + 1) % size_;
    ++seq_num;
  }
  return true;
}

VCMPacket* PacketBuffer::GetPacket(uint16_t seq_num) {
  size_t index = seq_num % size_;
  if (!sequence_buffer_[index].used ||
      seq_num != sequence_buffer_[index].seq_num) {
    return nullptr;
  }
  return &data_buffer_[index];
}

int PacketBuffer::AddRef() const {
  return rtc::AtomicOps::Increment(&ref_count_);
}

int PacketBuffer::Release() const {
  int count = rtc::AtomicOps::Decrement(&ref_count_);
  if (!count) {
    delete this;
  }
  return count;
}

}  // namespace video_coding
}  // namespace webrtc
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-2003, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

////////////////////////////////////////////////////////////
//This class contains the methods to create raw data                //
//for CTP (trigger). The CTP data format is taken as                //
//described in the Trigger TDR - pages 134  and 135.                //
//The updated version of raw data is in:                            //
//http://epweb2.ph.bham.ac.uk/user/krivda/alice/ctp/ctp_readout1.pdf//
//////////////////////////////////////////////////////////

#include <TObject.h>
#include <TString.h>
#include <Riostream.h>
#include "AliCTPRawData.h"
#include "AliRunLoader.h"
#include "AliCentralTrigger.h"
#include "AliRawDataHeaderSim.h"
#include "AliLog.h"
#include "AliDAQ.h"
#include "AliFstream.h"

ClassImp(AliCTPRawData)
////////////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
AliCTPRawData::AliCTPRawData()
{
  // Default constructor
}

//______________________________________________________________________________
AliCTPRawData::AliCTPRawData(const AliCTPRawData &source):
  TObject(source)
{
  // Copy Constructor
}

//______________________________________________________________________________
AliCTPRawData& AliCTPRawData::operator=(const AliCTPRawData &source)
{
  // Assigment operator
  if(this==&source) return *this;
  ((TObject *)this)->operator=(source);

 return *this;
}

//______________________________________________________________________________
void AliCTPRawData::RawData()
{
  // This method writes the CTP (trigger)
  // raw data in a DDL file
  ULong64_t l2class = 0;
  UChar_t l2cluster = 0;
  UInt_t l0input = 0;
  UInt_t l1input = 0;
  UShort_t l2input=0;
  AliInfo("Storing the CTP DDL raw data...");
  AliRunLoader *runloader = AliRunLoader::Instance();
  if (runloader) {
    if (!runloader->LoadTrigger()) {
      AliCentralTrigger *aCTP = runloader->GetTrigger();
      if (AliDebugLevel() > 0)
	aCTP->Dump();
      // First get the trigger mask
      l2class = aCTP->GetClassMask();
      // Then get the detector cluster to be read out
      l2cluster = aCTP->GetClusterMask();
      // Then get the input cluster mask
      l0input = aCTP->GetL0TriggerInputs();
      l1input = aCTP->GetL1TriggerInputs();
      l2input = aCTP->GetL2TriggerInputs();
    }
    else
      AliWarning("No trigger can be loaded! Putting empty trigger class into the CTP raw data !");
  }
  else
    AliError("No run loader is available! Putting empty trigger class into the CTP raw data !");

  AliDebug(1,Form("CTP trigger mask = 0x%llx",l2class));
  AliDebug(1,Form("CTP detector cluster = 0x%x",l2cluster));

  char  fileName[15];
  strcpy(fileName,AliDAQ::DdlFileName("TRG",0));
  AliInfo(Form("Storing CTP raw data in %s",fileName));
  AliFstream* outfile;         // logical name of the output file
  outfile = new AliFstream(fileName);

  // Writing CTP raw data here
  // The format is taken as in
  // dhttp://epweb2.ph.bham.ac.uk/user/krivda/alice/ctp/ctp_readout1.pdf

  // If not 0, from where??
  UInt_t bunchCross = 0;
  UInt_t orbitId = 0;
  Bool_t esr = 0; // Enable Segmented Readout flag

  // First 3 words here - Bunch-crossing and orbit numbers
  UInt_t word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= bunchCross & 0xFFF;
  AliDebug(1,Form("CTP word1 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));

  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (orbitId >> 12) & 0xFFF;
  AliDebug(1,Form("CTP word2 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= orbitId & 0xFFF;
  AliDebug(1,Form("CTP word3 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));

  // Now the 4th word
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= ((UInt_t)esr) << 10;
  word |= 0 << 8; // L2SwC - physics trigger
  word |= (l2cluster & 0x3F) << 2; // L2Cluster
  word |= (UInt_t)((l2class >> 48) & 0x3);
  AliDebug(1,Form("CTP word4 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));

  // Then the  4 words with the trigger classes
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l2class >> 36) & 0xFFF);
  AliDebug(1,Form("CTP word5 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l2class >> 24) & 0xFFF);
  AliDebug(1,Form("CTP word6 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l2class >> 12) & 0xFFF);
  AliDebug(1,Form("CTP word7 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)(l2class & 0xFFF);
  AliDebug(1,Form("CTP word8 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));

  // The last 5 words with trigger inputs
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l0input >> 12) & 0xFFF);
  AliDebug(1,Form("CTP word9 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l0input >> 0) & 0xFFF);
  AliDebug(1,Form("CTP word10 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l1input >> 12) & 0xFFF);
  AliDebug(1,Form("CTP word11 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l1input >> 0) & 0xFFF);
  AliDebug(1,Form("CTP word12 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l2input >> 0) & 0xFFF);
  AliDebug(1,Form("CTP word13 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));

  delete outfile;

  return;
}
<commit_msg>Coverity defect fixed.<commit_after>/**************************************************************************
 * Copyright(c) 1998-2003, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

////////////////////////////////////////////////////////////
//This class contains the methods to create raw data                //
//for CTP (trigger). The CTP data format is taken as                //
//described in the Trigger TDR - pages 134  and 135.                //
//The updated version of raw data is in:                            //
//http://epweb2.ph.bham.ac.uk/user/krivda/alice/ctp/ctp_readout1.pdf//
//////////////////////////////////////////////////////////

#include <TObject.h>
#include <TString.h>
#include <Riostream.h>
#include "AliCTPRawData.h"
#include "AliRunLoader.h"
#include "AliCentralTrigger.h"
#include "AliRawDataHeaderSim.h"
#include "AliLog.h"
#include "AliDAQ.h"
#include "AliFstream.h"

ClassImp(AliCTPRawData)
////////////////////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
AliCTPRawData::AliCTPRawData()
{
  // Default constructor
}

//______________________________________________________________________________
AliCTPRawData::AliCTPRawData(const AliCTPRawData &source):
  TObject(source)
{
  // Copy Constructor
}

//______________________________________________________________________________
AliCTPRawData& AliCTPRawData::operator=(const AliCTPRawData &source)
{
  // Assigment operator
  if(this==&source) return *this;
  ((TObject *)this)->operator=(source);

 return *this;
}

//______________________________________________________________________________
void AliCTPRawData::RawData()
{
  // This method writes the CTP (trigger)
  // raw data in a DDL file
  ULong64_t l2class = 0;
  UChar_t l2cluster = 0;
  UInt_t l0input = 0;
  UInt_t l1input = 0;
  UShort_t l2input=0;
  AliInfo("Storing the CTP DDL raw data...");
  AliRunLoader *runloader = AliRunLoader::Instance();
  if (runloader) {
    if (!runloader->LoadTrigger()) {
      AliCentralTrigger *aCTP = runloader->GetTrigger();
      if (AliDebugLevel() > 0)
	aCTP->Dump();
      // First get the trigger mask
      l2class = aCTP->GetClassMask();
      // Then get the detector cluster to be read out
      l2cluster = aCTP->GetClusterMask();
      // Then get the input cluster mask
      l0input = aCTP->GetL0TriggerInputs();
      l1input = aCTP->GetL1TriggerInputs();
      l2input = aCTP->GetL2TriggerInputs();
    }
    else
      AliWarning("No trigger can be loaded! Putting empty trigger class into the CTP raw data !");
  }
  else
    AliError("No run loader is available! Putting empty trigger class into the CTP raw data !");

  AliDebug(1,Form("CTP trigger mask = 0x%llx",l2class));
  AliDebug(1,Form("CTP detector cluster = 0x%x",l2cluster));

  TString fileName = AliDAQ::DdlFileName("TRG",0);
  AliInfo(Form("Storing CTP raw data in %s",fileName.Data()));
  AliFstream* outfile;         // logical name of the output file
  outfile = new AliFstream(fileName.Data());

  // Writing CTP raw data here
  // The format is taken as in
  // dhttp://epweb2.ph.bham.ac.uk/user/krivda/alice/ctp/ctp_readout1.pdf

  // If not 0, from where??
  UInt_t bunchCross = 0;
  UInt_t orbitId = 0;
  Bool_t esr = 0; // Enable Segmented Readout flag

  // First 3 words here - Bunch-crossing and orbit numbers
  UInt_t word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= bunchCross & 0xFFF;
  AliDebug(1,Form("CTP word1 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));

  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (orbitId >> 12) & 0xFFF;
  AliDebug(1,Form("CTP word2 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= orbitId & 0xFFF;
  AliDebug(1,Form("CTP word3 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));

  // Now the 4th word
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= ((UInt_t)esr) << 10;
  word |= 0 << 8; // L2SwC - physics trigger
  word |= (l2cluster & 0x3F) << 2; // L2Cluster
  word |= (UInt_t)((l2class >> 48) & 0x3);
  AliDebug(1,Form("CTP word4 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));

  // Then the  4 words with the trigger classes
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l2class >> 36) & 0xFFF);
  AliDebug(1,Form("CTP word5 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l2class >> 24) & 0xFFF);
  AliDebug(1,Form("CTP word6 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l2class >> 12) & 0xFFF);
  AliDebug(1,Form("CTP word7 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)(l2class & 0xFFF);
  AliDebug(1,Form("CTP word8 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));

  // The last 5 words with trigger inputs
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l0input >> 12) & 0xFFF);
  AliDebug(1,Form("CTP word9 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l0input >> 0) & 0xFFF);
  AliDebug(1,Form("CTP word10 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l1input >> 12) & 0xFFF);
  AliDebug(1,Form("CTP word11 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l1input >> 0) & 0xFFF);
  AliDebug(1,Form("CTP word12 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));
  word = 0;
  word |= 0 << 15; // BlockID = 0 in case of CTP readout
  word |= (UInt_t)((l2input >> 0) & 0xFFF);
  AliDebug(1,Form("CTP word13 = 0x%x",word));
  outfile->WriteBuffer((char*)(&word),sizeof(UInt_t));

  delete outfile;

  return;
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Lewis Baker
// Licenced under MIT license. See LICENSE.txt for details.
///////////////////////////////////////////////////////////////////////////////

#include <cppcoro/when_all.hpp>

#include <cppcoro/config.hpp>
#include <cppcoro/async_manual_reset_event.hpp>
#include <cppcoro/async_mutex.hpp>
#include <cppcoro/fmap.hpp>
#include <cppcoro/shared_task.hpp>
#include <cppcoro/sync_wait.hpp>
#include <cppcoro/task.hpp>

#include "counted.hpp"

#include <functional>
#include <string>
#include <vector>

#include <ostream>
#include "doctest/doctest.h"

TEST_SUITE_BEGIN("when_all");

namespace
{
	template<template<typename T> class TASK, typename T>
	TASK<T> when_event_set_return(cppcoro::async_manual_reset_event& event, T value)
	{
		co_await event;
		co_return std::move(value);
	}
}

TEST_CASE("when_all() with no args completes immediately")
{
	[[maybe_unused]] std::tuple<> result = cppcoro::sync_wait(cppcoro::when_all());
}

TEST_CASE("when_all() with one arg")
{
	bool started = false;
	bool finished = false;
	auto f = [&](cppcoro::async_manual_reset_event& event) -> cppcoro::task<std::string>
	{
		started = true;
		co_await event;
		finished = true;
		co_return "foo";
	};

	cppcoro::async_manual_reset_event event;

	auto whenAllTask = cppcoro::when_all(f(event));
	CHECK(!started);

	cppcoro::sync_wait(cppcoro::when_all_ready(
		[&]() -> cppcoro::task<>
	{
		auto[s] = co_await whenAllTask;
		CHECK(s == "foo");
	}(),
		[&]() -> cppcoro::task<>
	{
		CHECK(started);
		CHECK(!finished);
		event.set();
		CHECK(finished);
		co_return;
	}()));
}

TEST_CASE("when_all() with awaitables")
{
	cppcoro::sync_wait([]() -> cppcoro::task<>
	{
		auto makeTask = [](int x) -> cppcoro::task<int>
		{
			co_return x;
		};

		cppcoro::async_manual_reset_event event;
		event.set();

		cppcoro::async_mutex mutex;

		auto[eventResult, mutexLock, number] = co_await cppcoro::when_all(
			std::ref(event),
			mutex.scoped_lock_async(),
			makeTask(123) | cppcoro::fmap([](int x) { return x + 1; }));

		(void)eventResult;
		(void)mutexLock;
		CHECK(number == 124);
		CHECK(!mutex.try_lock());
	}());
}

TEST_CASE("when_all() with all task types")
{
	counted::reset_counts();

	auto run = [](cppcoro::async_manual_reset_event& event) -> cppcoro::task<>
	{
		using namespace std::string_literals;

		auto[a, b] = co_await cppcoro::when_all(
			when_event_set_return<cppcoro::task>(event, "foo"s),
			when_event_set_return<cppcoro::shared_task>(event, counted{}));

		CHECK(a == "foo");
		CHECK(b.id == 0);
		CHECK(counted::active_count() == 1);
	};

	cppcoro::async_manual_reset_event event;

	cppcoro::sync_wait(cppcoro::when_all_ready(
		run(event),
		[&]() -> cppcoro::task<>
	{
		event.set();
		co_return;
	}()));
}

TEST_CASE("when_all() throws if any task throws")
{
	struct X {};
	struct Y {};

	int startedCount = 0;
	auto makeTask = [&](int value) -> cppcoro::task<int>
	{
		++startedCount;
		if (value == 0) throw X{};
		else if (value == 1) throw Y{};
		else co_return value;
	};

	cppcoro::sync_wait([&]() -> cppcoro::task<>
	{
		try
		{
			// This could either throw X or Y exception.
			// The exact exception that is thrown is not defined if multiple tasks throw an exception.
			// TODO: Consider throwing some kind of aggregate_exception that collects all of the exceptions together.
			(void)co_await cppcoro::when_all(makeTask(0), makeTask(1), makeTask(2));
		}
		catch (const X&)
		{
		}
		catch (const Y&)
		{
		}
	}());
}

TEST_CASE("when_all() with task<void>")
{
	int voidTaskCount = 0;
	auto makeVoidTask = [&]() -> cppcoro::task<>
	{
		++voidTaskCount;
		co_return;
	};

	auto makeIntTask = [](int x) -> cppcoro::task<int>
	{
		co_return x;
	};

	// Single void task in when_all()
	auto[x] = cppcoro::sync_wait(cppcoro::when_all(makeVoidTask()));
	(void)x;
	CHECK(voidTaskCount == 1);

	// Multiple void tasks in when_all()
	auto[a, b] = cppcoro::sync_wait(cppcoro::when_all(
		makeVoidTask(),
		makeVoidTask()));
	(void)a;
	(void)b;
	CHECK(voidTaskCount == 3);

	// Mixing void and non-void tasks in when_all()
	auto[v1, i, v2] = cppcoro::sync_wait(cppcoro::when_all(
		makeVoidTask(),
		makeIntTask(123),
		makeVoidTask()));
	(void)v1;
	(void)v2;
	CHECK(voidTaskCount == 5);

	CHECK(i == 123);
}

TEST_CASE("when_all() with vector<task<>>")
{
	int startedCount = 0;
	auto makeTask = [&](cppcoro::async_manual_reset_event& event) -> cppcoro::task<>
	{
		++startedCount;
		co_await event;
	};

	cppcoro::async_manual_reset_event event1;
	cppcoro::async_manual_reset_event event2;

	bool finished = false;

	auto run = [&]() -> cppcoro::task<>
	{
		std::vector<cppcoro::task<>> tasks;
		tasks.push_back(makeTask(event1));
		tasks.push_back(makeTask(event2));
		tasks.push_back(makeTask(event1));

		auto allTask = cppcoro::when_all(std::move(tasks));

		CHECK(startedCount == 0);

		co_await allTask;

		finished = true;
	};

	cppcoro::sync_wait(cppcoro::when_all_ready(
		run(),
		[&]() -> cppcoro::task<>
	{
		CHECK(startedCount == 3);
		CHECK(!finished);

		event1.set();

		CHECK(!finished);

		event2.set();

		CHECK(finished);
		co_return;
	}()));
}

TEST_CASE("when_all() with vector<shared_task<>>")
{
	int startedCount = 0;
	auto makeTask = [&](cppcoro::async_manual_reset_event& event) -> cppcoro::shared_task<>
	{
		++startedCount;
		co_await event;
	};

	cppcoro::async_manual_reset_event event1;
	cppcoro::async_manual_reset_event event2;

	bool finished = false;

	auto run = [&]() -> cppcoro::task<>
	{
		std::vector<cppcoro::shared_task<>> tasks;
		tasks.push_back(makeTask(event1));
		tasks.push_back(makeTask(event2));
		tasks.push_back(makeTask(event1));

		auto allTask = cppcoro::when_all(std::move(tasks));

		CHECK(startedCount == 0);

		co_await allTask;

		finished = true;
	};

	cppcoro::sync_wait(cppcoro::when_all_ready(
		run(),
		[&]() -> cppcoro::task<>
	{
		CHECK(startedCount == 3);
		CHECK(!finished);

		event1.set();

		CHECK(!finished);

		event2.set();

		CHECK(finished);

		co_return;
	}()));
}

namespace
{
	template<template<typename T> class TASK>
	void check_when_all_vector_of_task_value()
	{
		cppcoro::async_manual_reset_event event1;
		cppcoro::async_manual_reset_event event2;

		bool whenAllCompleted = false;

		cppcoro::sync_wait(cppcoro::when_all_ready(
			[&]() -> cppcoro::task<>
		{
			std::vector<TASK<int>> tasks;

			tasks.emplace_back(when_event_set_return<TASK>(event1, 1));
			tasks.emplace_back(when_event_set_return<TASK>(event2, 2));

			auto whenAllTask = cppcoro::when_all(std::move(tasks));

			auto values = co_await whenAllTask;
			REQUIRE(values.size() == 2);
			CHECK(values[0] == 1);
			CHECK(values[1] == 2);

			whenAllCompleted = true;
		}(),
			[&]() -> cppcoro::task<>
		{
			CHECK(!whenAllCompleted);
			event2.set();
			CHECK(!whenAllCompleted);
			event1.set();
			CHECK(whenAllCompleted);
			co_return;
		}()));
	}
}

TEST_CASE("when_all() with vector<task<T>>")
{
	check_when_all_vector_of_task_value<cppcoro::task>();
}

#if defined(CPPCORO_RELEASE_OPTIMISED)
constexpr bool isOptimised = true;
#else
constexpr bool isOptimised = false;
#endif

// Disable test on MSVC x64 optimised due to bad codegen bug in
// 'co_await whenAllTask' expression.
// Issue reported to MS on 19/11/2017.
TEST_CASE("when_all() with vector<shared_task<T>>"
* doctest::skip(CPPCORO_COMPILER_MSVC && CPPCORO_COMPILER_MSVC <= 191225805 &&
	            isOptimised && CPPCORO_CPU_X64))
{
	check_when_all_vector_of_task_value<cppcoro::shared_task>();
}

namespace
{
	template<template<typename T> class TASK>
	void check_when_all_vector_of_task_reference()
	{
		cppcoro::async_manual_reset_event event1;
		cppcoro::async_manual_reset_event event2;

		int value1 = 1;
		int value2 = 2;

		auto makeTask = [](cppcoro::async_manual_reset_event& event, int& value) -> TASK<int&>
		{
			co_await event;
			co_return value;
		};

		bool whenAllComplete = false;

		cppcoro::sync_wait(cppcoro::when_all_ready(
			[&]() -> cppcoro::task<>
		{
			std::vector<TASK<int&>> tasks;
			tasks.emplace_back(makeTask(event1, value1));
			tasks.emplace_back(makeTask(event2, value2));

			auto whenAllTask = cppcoro::when_all(std::move(tasks));

			std::vector<std::reference_wrapper<int>> values = co_await whenAllTask;
			REQUIRE(values.size() == 2);
			CHECK(&values[0].get() == &value1);
			CHECK(&values[1].get() == &value2);

			whenAllComplete = true;
		}(),
			[&]() -> cppcoro::task<>
		{
			CHECK(!whenAllComplete);
			event2.set();
			CHECK(!whenAllComplete);
			event1.set();
			CHECK(whenAllComplete);
			co_return;
		}()));
	}
}

// Disable test on MSVC x64 optimised due to bad codegen bug in
// 'co_await whenAllTask' expression.
// Issue reported to MS on 19/11/2017.
TEST_CASE("when_all() with vector<task<T&>>"
	* doctest::skip(CPPCORO_COMPILER_MSVC && CPPCORO_COMPILER_MSVC <= 191225805 &&
		isOptimised && CPPCORO_CPU_X64))
{
	check_when_all_vector_of_task_reference<cppcoro::task>();
}

// Disable test on MSVC x64 optimised due to bad codegen bug in
// 'co_await whenAllTask' expression.
// Issue reported to MS on 19/11/2017.
TEST_CASE("when_all() with vector<shared_task<T&>>"
	* doctest::skip(CPPCORO_COMPILER_MSVC && CPPCORO_COMPILER_MSVC <= 191225805 &&
		isOptimised && CPPCORO_CPU_X64))
{
	check_when_all_vector_of_task_reference<cppcoro::shared_task>();
}

TEST_SUITE_END();
<commit_msg>Skip failing when_all() test on msvc x86 optimised.<commit_after>///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Lewis Baker
// Licenced under MIT license. See LICENSE.txt for details.
///////////////////////////////////////////////////////////////////////////////

#include <cppcoro/when_all.hpp>

#include <cppcoro/config.hpp>
#include <cppcoro/async_manual_reset_event.hpp>
#include <cppcoro/async_mutex.hpp>
#include <cppcoro/fmap.hpp>
#include <cppcoro/shared_task.hpp>
#include <cppcoro/sync_wait.hpp>
#include <cppcoro/task.hpp>

#include "counted.hpp"

#include <functional>
#include <string>
#include <vector>

#include <ostream>
#include "doctest/doctest.h"

TEST_SUITE_BEGIN("when_all");

namespace
{
	template<template<typename T> class TASK, typename T>
	TASK<T> when_event_set_return(cppcoro::async_manual_reset_event& event, T value)
	{
		co_await event;
		co_return std::move(value);
	}
}

TEST_CASE("when_all() with no args completes immediately")
{
	[[maybe_unused]] std::tuple<> result = cppcoro::sync_wait(cppcoro::when_all());
}

TEST_CASE("when_all() with one arg")
{
	bool started = false;
	bool finished = false;
	auto f = [&](cppcoro::async_manual_reset_event& event) -> cppcoro::task<std::string>
	{
		started = true;
		co_await event;
		finished = true;
		co_return "foo";
	};

	cppcoro::async_manual_reset_event event;

	auto whenAllTask = cppcoro::when_all(f(event));
	CHECK(!started);

	cppcoro::sync_wait(cppcoro::when_all_ready(
		[&]() -> cppcoro::task<>
	{
		auto[s] = co_await whenAllTask;
		CHECK(s == "foo");
	}(),
		[&]() -> cppcoro::task<>
	{
		CHECK(started);
		CHECK(!finished);
		event.set();
		CHECK(finished);
		co_return;
	}()));
}

TEST_CASE("when_all() with awaitables")
{
	cppcoro::sync_wait([]() -> cppcoro::task<>
	{
		auto makeTask = [](int x) -> cppcoro::task<int>
		{
			co_return x;
		};

		cppcoro::async_manual_reset_event event;
		event.set();

		cppcoro::async_mutex mutex;

		auto[eventResult, mutexLock, number] = co_await cppcoro::when_all(
			std::ref(event),
			mutex.scoped_lock_async(),
			makeTask(123) | cppcoro::fmap([](int x) { return x + 1; }));

		(void)eventResult;
		(void)mutexLock;
		CHECK(number == 124);
		CHECK(!mutex.try_lock());
	}());
}

TEST_CASE("when_all() with all task types")
{
	counted::reset_counts();

	auto run = [](cppcoro::async_manual_reset_event& event) -> cppcoro::task<>
	{
		using namespace std::string_literals;

		auto[a, b] = co_await cppcoro::when_all(
			when_event_set_return<cppcoro::task>(event, "foo"s),
			when_event_set_return<cppcoro::shared_task>(event, counted{}));

		CHECK(a == "foo");
		CHECK(b.id == 0);
		CHECK(counted::active_count() == 1);
	};

	cppcoro::async_manual_reset_event event;

	cppcoro::sync_wait(cppcoro::when_all_ready(
		run(event),
		[&]() -> cppcoro::task<>
	{
		event.set();
		co_return;
	}()));
}

TEST_CASE("when_all() throws if any task throws")
{
	struct X {};
	struct Y {};

	int startedCount = 0;
	auto makeTask = [&](int value) -> cppcoro::task<int>
	{
		++startedCount;
		if (value == 0) throw X{};
		else if (value == 1) throw Y{};
		else co_return value;
	};

	cppcoro::sync_wait([&]() -> cppcoro::task<>
	{
		try
		{
			// This could either throw X or Y exception.
			// The exact exception that is thrown is not defined if multiple tasks throw an exception.
			// TODO: Consider throwing some kind of aggregate_exception that collects all of the exceptions together.
			(void)co_await cppcoro::when_all(makeTask(0), makeTask(1), makeTask(2));
		}
		catch (const X&)
		{
		}
		catch (const Y&)
		{
		}
	}());
}

TEST_CASE("when_all() with task<void>")
{
	int voidTaskCount = 0;
	auto makeVoidTask = [&]() -> cppcoro::task<>
	{
		++voidTaskCount;
		co_return;
	};

	auto makeIntTask = [](int x) -> cppcoro::task<int>
	{
		co_return x;
	};

	// Single void task in when_all()
	auto[x] = cppcoro::sync_wait(cppcoro::when_all(makeVoidTask()));
	(void)x;
	CHECK(voidTaskCount == 1);

	// Multiple void tasks in when_all()
	auto[a, b] = cppcoro::sync_wait(cppcoro::when_all(
		makeVoidTask(),
		makeVoidTask()));
	(void)a;
	(void)b;
	CHECK(voidTaskCount == 3);

	// Mixing void and non-void tasks in when_all()
	auto[v1, i, v2] = cppcoro::sync_wait(cppcoro::when_all(
		makeVoidTask(),
		makeIntTask(123),
		makeVoidTask()));
	(void)v1;
	(void)v2;
	CHECK(voidTaskCount == 5);

	CHECK(i == 123);
}

TEST_CASE("when_all() with vector<task<>>")
{
	int startedCount = 0;
	auto makeTask = [&](cppcoro::async_manual_reset_event& event) -> cppcoro::task<>
	{
		++startedCount;
		co_await event;
	};

	cppcoro::async_manual_reset_event event1;
	cppcoro::async_manual_reset_event event2;

	bool finished = false;

	auto run = [&]() -> cppcoro::task<>
	{
		std::vector<cppcoro::task<>> tasks;
		tasks.push_back(makeTask(event1));
		tasks.push_back(makeTask(event2));
		tasks.push_back(makeTask(event1));

		auto allTask = cppcoro::when_all(std::move(tasks));

		CHECK(startedCount == 0);

		co_await allTask;

		finished = true;
	};

	cppcoro::sync_wait(cppcoro::when_all_ready(
		run(),
		[&]() -> cppcoro::task<>
	{
		CHECK(startedCount == 3);
		CHECK(!finished);

		event1.set();

		CHECK(!finished);

		event2.set();

		CHECK(finished);
		co_return;
	}()));
}

TEST_CASE("when_all() with vector<shared_task<>>")
{
	int startedCount = 0;
	auto makeTask = [&](cppcoro::async_manual_reset_event& event) -> cppcoro::shared_task<>
	{
		++startedCount;
		co_await event;
	};

	cppcoro::async_manual_reset_event event1;
	cppcoro::async_manual_reset_event event2;

	bool finished = false;

	auto run = [&]() -> cppcoro::task<>
	{
		std::vector<cppcoro::shared_task<>> tasks;
		tasks.push_back(makeTask(event1));
		tasks.push_back(makeTask(event2));
		tasks.push_back(makeTask(event1));

		auto allTask = cppcoro::when_all(std::move(tasks));

		CHECK(startedCount == 0);

		co_await allTask;

		finished = true;
	};

	cppcoro::sync_wait(cppcoro::when_all_ready(
		run(),
		[&]() -> cppcoro::task<>
	{
		CHECK(startedCount == 3);
		CHECK(!finished);

		event1.set();

		CHECK(!finished);

		event2.set();

		CHECK(finished);

		co_return;
	}()));
}

namespace
{
	template<template<typename T> class TASK>
	void check_when_all_vector_of_task_value()
	{
		cppcoro::async_manual_reset_event event1;
		cppcoro::async_manual_reset_event event2;

		bool whenAllCompleted = false;

		cppcoro::sync_wait(cppcoro::when_all_ready(
			[&]() -> cppcoro::task<>
		{
			std::vector<TASK<int>> tasks;

			tasks.emplace_back(when_event_set_return<TASK>(event1, 1));
			tasks.emplace_back(when_event_set_return<TASK>(event2, 2));

			auto whenAllTask = cppcoro::when_all(std::move(tasks));

			auto values = co_await whenAllTask;
			REQUIRE(values.size() == 2);
			CHECK(values[0] == 1);
			CHECK(values[1] == 2);

			whenAllCompleted = true;
		}(),
			[&]() -> cppcoro::task<>
		{
			CHECK(!whenAllCompleted);
			event2.set();
			CHECK(!whenAllCompleted);
			event1.set();
			CHECK(whenAllCompleted);
			co_return;
		}()));
	}
}

#if defined(CPPCORO_RELEASE_OPTIMISED)
constexpr bool isOptimised = true;
#else
constexpr bool isOptimised = false;
#endif

// Disable test on MSVC x86 optimised due to bad codegen bug in
// `co_await whenAllTask` expression under MSVC 15.7 (Preview 2) and earlier.
TEST_CASE("when_all() with vector<task<T>>"
* doctest::skip(CPPCORO_COMPILER_MSVC && CPPCORO_COMPILER_MSVC <= 191426316 && CPPCORO_CPU_X86 && isOptimised))
{
	check_when_all_vector_of_task_value<cppcoro::task>();
}

// Disable test on MSVC x64 optimised due to bad codegen bug in
// 'co_await whenAllTask' expression.
// Issue reported to MS on 19/11/2017.
TEST_CASE("when_all() with vector<shared_task<T>>"
* doctest::skip(CPPCORO_COMPILER_MSVC && CPPCORO_COMPILER_MSVC <= 191225805 &&
	            isOptimised && CPPCORO_CPU_X64))
{
	check_when_all_vector_of_task_value<cppcoro::shared_task>();
}

namespace
{
	template<template<typename T> class TASK>
	void check_when_all_vector_of_task_reference()
	{
		cppcoro::async_manual_reset_event event1;
		cppcoro::async_manual_reset_event event2;

		int value1 = 1;
		int value2 = 2;

		auto makeTask = [](cppcoro::async_manual_reset_event& event, int& value) -> TASK<int&>
		{
			co_await event;
			co_return value;
		};

		bool whenAllComplete = false;

		cppcoro::sync_wait(cppcoro::when_all_ready(
			[&]() -> cppcoro::task<>
		{
			std::vector<TASK<int&>> tasks;
			tasks.emplace_back(makeTask(event1, value1));
			tasks.emplace_back(makeTask(event2, value2));

			auto whenAllTask = cppcoro::when_all(std::move(tasks));

			std::vector<std::reference_wrapper<int>> values = co_await whenAllTask;
			REQUIRE(values.size() == 2);
			CHECK(&values[0].get() == &value1);
			CHECK(&values[1].get() == &value2);

			whenAllComplete = true;
		}(),
			[&]() -> cppcoro::task<>
		{
			CHECK(!whenAllComplete);
			event2.set();
			CHECK(!whenAllComplete);
			event1.set();
			CHECK(whenAllComplete);
			co_return;
		}()));
	}
}

// Disable test on MSVC x64 optimised due to bad codegen bug in
// 'co_await whenAllTask' expression.
// Issue reported to MS on 19/11/2017.
TEST_CASE("when_all() with vector<task<T&>>"
	* doctest::skip(CPPCORO_COMPILER_MSVC && CPPCORO_COMPILER_MSVC <= 191225805 &&
		isOptimised && CPPCORO_CPU_X64))
{
	check_when_all_vector_of_task_reference<cppcoro::task>();
}

// Disable test on MSVC x64 optimised due to bad codegen bug in
// 'co_await whenAllTask' expression.
// Issue reported to MS on 19/11/2017.
TEST_CASE("when_all() with vector<shared_task<T&>>"
	* doctest::skip(CPPCORO_COMPILER_MSVC && CPPCORO_COMPILER_MSVC <= 191225805 &&
		isOptimised && CPPCORO_CPU_X64))
{
	check_when_all_vector_of_task_reference<cppcoro::shared_task>();
}

TEST_SUITE_END();
<|endoftext|>


<commit_before>// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2013 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin D4Opaqueeet, Fifth Floor, Boston, MA  02110-1301  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

#define DODS_DEBUG

#include "config.h"

#include <sstream>
#include <iterator>

#include "D4Opaque.h"

#include "DMR.h"
#include "D4StreamMarshaller.h"
#include "D4StreamUnMarshaller.h"

#include "util.h"
#include "crc.h"

#include "debug.h"

#undef CLEAR_LOCAL_DATA

using namespace std;

namespace libdap {

D4Opaque &
D4Opaque::operator=(const D4Opaque &rhs)
{
    if (this == &rhs)
        return *this;

    // Call BaseType::operator=
    dynamic_cast<BaseType &>(*this) = rhs;

    d_buf = rhs.d_buf;

    return *this;
}

void
D4Opaque::clear_local_data()
{
    if (!d_buf.empty()) {
        d_buf.erase(d_buf.begin(), d_buf.end());
        d_buf.resize(0);
    }

    set_read_p(false);
}

void
D4Opaque::compute_checksum(Crc32 &checksum)
{
	checksum.AddData(&d_buf[0], d_buf.size());
}

void
D4Opaque::serialize(D4StreamMarshaller &m, DMR &, bool)
{
    if (!read_p())
        read();          // read() throws Error

    m.put_opaque_dap4( reinterpret_cast<char*>(&d_buf[0]), d_buf.size() ) ;

#ifdef CLEAR_LOCAL_DATA
    clear_local_data();
#endif

}

void
D4Opaque::deserialize(D4StreamUnMarshaller &um, DMR &)
{
    um.get_opaque_dap4( d_buf ) ;
}

unsigned int
D4Opaque::buf2val(void **val)
{
	assert(val);

    // If *val is null, then the caller has not allocated storage for the
    // value; we must. If there is storage there, assume it is a vector<uint8_t>
	// (i.e., dods_opaque) and assign d_buf's value to that storage.
    if (!*val)
        *val = new vector<uint8_t>;
    else
        *static_cast<vector<uint8_t>*>(*val) = d_buf;

    return sizeof(vector<uint8_t>*);
}

unsigned int
D4Opaque::val2buf(void *val, bool)
{
    assert(val);

    d_buf = *static_cast<dods_opaque*>(val);

    return sizeof(dods_opaque*);
}

/** Set the value of this instance.
    @param value The value
    @return Always returns true; the return type of bool is for compatibility
    with the Passive* subclasses written by HAO. */
bool
D4Opaque::set_value(const dods_opaque &value)
{
    d_buf = value;
    set_read_p(true);

    return true;
}

/** Get the value of this instance.
    @return The value. */
D4Opaque::dods_opaque
D4Opaque::value() const
{
    return d_buf;
}

std::vector<BaseType *> *
D4Opaque::transform_to_dap2(AttrTable *){
    DBG(cerr << __func__ << "() - Transform not implemented DAP4 Opaque type." << endl;);
    return NULL;
}

void
D4Opaque::print_val(ostream &out, string space, bool print_decl_p)
{
	if (print_decl_p) print_decl(out, space, false);

	if (d_buf.size()) {
		// end() - 1 is only OK if size() is > 0
		std::ostream_iterator<unsigned int> out_it(out, ",");
		std::copy(d_buf.begin(), d_buf.end() - 1, out_it);
		out << (unsigned int) d_buf.back(); // can also use: *(d_buf.end()-1);
	}

	if (print_decl_p) out << ";" << endl;
}

void
D4Opaque::dump(ostream &strm) const
{
    strm << DapIndent::LMarg << "D4Opaque::dump - ("
    << (void *)this << ")" << endl ;
    DapIndent::Indent() ;
    BaseType::dump(strm) ;
    //strm << DapIndent::LMarg << "value: " << d_buf << endl ;
    ostream_iterator<uint8_t> out_it (strm," ");
    std::copy ( d_buf.begin(), d_buf.end(), out_it );

    DapIndent::UnIndent() ;
}

} // namespace libdap

<commit_msg>Silencing more debug chatter.<commit_after>// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2013 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin D4Opaqueeet, Fifth Floor, Boston, MA  02110-1301  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

//#define DODS_DEBUG

#include "config.h"

#include <sstream>
#include <iterator>

#include "D4Opaque.h"

#include "DMR.h"
#include "D4StreamMarshaller.h"
#include "D4StreamUnMarshaller.h"

#include "util.h"
#include "crc.h"

#include "debug.h"

#undef CLEAR_LOCAL_DATA

using namespace std;

namespace libdap {

D4Opaque &
D4Opaque::operator=(const D4Opaque &rhs)
{
    if (this == &rhs)
        return *this;

    // Call BaseType::operator=
    dynamic_cast<BaseType &>(*this) = rhs;

    d_buf = rhs.d_buf;

    return *this;
}

void
D4Opaque::clear_local_data()
{
    if (!d_buf.empty()) {
        d_buf.erase(d_buf.begin(), d_buf.end());
        d_buf.resize(0);
    }

    set_read_p(false);
}

void
D4Opaque::compute_checksum(Crc32 &checksum)
{
	checksum.AddData(&d_buf[0], d_buf.size());
}

void
D4Opaque::serialize(D4StreamMarshaller &m, DMR &, bool)
{
    if (!read_p())
        read();          // read() throws Error

    m.put_opaque_dap4( reinterpret_cast<char*>(&d_buf[0]), d_buf.size() ) ;

#ifdef CLEAR_LOCAL_DATA
    clear_local_data();
#endif

}

void
D4Opaque::deserialize(D4StreamUnMarshaller &um, DMR &)
{
    um.get_opaque_dap4( d_buf ) ;
}

unsigned int
D4Opaque::buf2val(void **val)
{
	assert(val);

    // If *val is null, then the caller has not allocated storage for the
    // value; we must. If there is storage there, assume it is a vector<uint8_t>
	// (i.e., dods_opaque) and assign d_buf's value to that storage.
    if (!*val)
        *val = new vector<uint8_t>;
    else
        *static_cast<vector<uint8_t>*>(*val) = d_buf;

    return sizeof(vector<uint8_t>*);
}

unsigned int
D4Opaque::val2buf(void *val, bool)
{
    assert(val);

    d_buf = *static_cast<dods_opaque*>(val);

    return sizeof(dods_opaque*);
}

/** Set the value of this instance.
    @param value The value
    @return Always returns true; the return type of bool is for compatibility
    with the Passive* subclasses written by HAO. */
bool
D4Opaque::set_value(const dods_opaque &value)
{
    d_buf = value;
    set_read_p(true);

    return true;
}

/** Get the value of this instance.
    @return The value. */
D4Opaque::dods_opaque
D4Opaque::value() const
{
    return d_buf;
}

std::vector<BaseType *> *
D4Opaque::transform_to_dap2(AttrTable *){
    DBG(cerr << __func__ << "() - Transform not implemented DAP4 Opaque type." << endl;);
    return NULL;
}

void
D4Opaque::print_val(ostream &out, string space, bool print_decl_p)
{
	if (print_decl_p) print_decl(out, space, false);

	if (d_buf.size()) {
		// end() - 1 is only OK if size() is > 0
		std::ostream_iterator<unsigned int> out_it(out, ",");
		std::copy(d_buf.begin(), d_buf.end() - 1, out_it);
		out << (unsigned int) d_buf.back(); // can also use: *(d_buf.end()-1);
	}

	if (print_decl_p) out << ";" << endl;
}

void
D4Opaque::dump(ostream &strm) const
{
    strm << DapIndent::LMarg << "D4Opaque::dump - ("
    << (void *)this << ")" << endl ;
    DapIndent::Indent() ;
    BaseType::dump(strm) ;
    //strm << DapIndent::LMarg << "value: " << d_buf << endl ;
    ostream_iterator<uint8_t> out_it (strm," ");
    std::copy ( d_buf.begin(), d_buf.end(), out_it );

    DapIndent::UnIndent() ;
}

} // namespace libdap

<|endoftext|>


<commit_before>/* crosstest.py --test=test_global.cpp \
   --driver=test_global_main.cpp --prefix=Subzero_ --output=test_global */

#include <stdint.h>
#include <cstdlib>
#include <iostream>

#include "test_global.h"
namespace Subzero_ {
#include "test_global.h"
}

int main(int argc, char **argv) {
  size_t TotalTests = 0;
  size_t Passes = 0;
  size_t Failures = 0;

  const uint8_t *SzArray, *LlcArray;
  size_t SzArrayLen, LlcArrayLen;

  size_t NumArrays = getNumArrays();
  for (size_t i = 0; i < NumArrays; ++i) {
    LlcArrayLen = -1;
    SzArrayLen = -2;
    LlcArray = getArray(i, LlcArrayLen);
    SzArray = Subzero_::getArray(i, SzArrayLen);
    if (LlcArrayLen == SzArrayLen) {
      ++Passes;
    } else {
      std::cout << i << ":LlcArrayLen=" << LlcArrayLen
                << ", SzArrayLen=" << SzArrayLen << std::endl;
      ++Failures;
    }

    for (size_t i = 0; i < LlcArrayLen; ++i) {
      if (LlcArray[i] == SzArray[i]) {
        ++Passes;
      } else {
        ++Failures;
        std::cout << i << ":LlcArray[" << i << "] = " << (int)LlcArray[i]
                  << ", SzArray[" << i << "] = " << (int)SzArray[i]
                  << std::endl;
      }
    }
  }

  std::cout << "TotalTests=" << TotalTests << " Passes=" << Passes
            << " Failures=" << Failures << "\n";
  return Failures;
}
<commit_msg>Fix a counter in the test_global crosstest.<commit_after>/* crosstest.py --test=test_global.cpp \
   --driver=test_global_main.cpp --prefix=Subzero_ --output=test_global */

#include <stdint.h>
#include <cstdlib>
#include <iostream>

#include "test_global.h"
namespace Subzero_ {
#include "test_global.h"
}

int main(int argc, char **argv) {
  size_t TotalTests = 0;
  size_t Passes = 0;
  size_t Failures = 0;

  const uint8_t *SzArray, *LlcArray;
  size_t SzArrayLen, LlcArrayLen;

  size_t NumArrays = getNumArrays();
  for (size_t i = 0; i < NumArrays; ++i) {
    LlcArrayLen = -1;
    SzArrayLen = -2;
    LlcArray = getArray(i, LlcArrayLen);
    SzArray = Subzero_::getArray(i, SzArrayLen);
    ++TotalTests;
    if (LlcArrayLen == SzArrayLen) {
      ++Passes;
    } else {
      std::cout << i << ":LlcArrayLen=" << LlcArrayLen
                << ", SzArrayLen=" << SzArrayLen << std::endl;
      ++Failures;
    }

    for (size_t i = 0; i < LlcArrayLen; ++i) {
      ++TotalTests;
      if (LlcArray[i] == SzArray[i]) {
        ++Passes;
      } else {
        ++Failures;
        std::cout << i << ":LlcArray[" << i << "] = " << (int)LlcArray[i]
                  << ", SzArray[" << i << "] = " << (int)SzArray[i]
                  << std::endl;
      }
    }
  }

  std::cout << "TotalTests=" << TotalTests << " Passes=" << Passes
            << " Failures=" << Failures << "\n";
  return Failures;
}
<|endoftext|>


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

#include "views/examples/radio_button_example.h"

#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "views/controls/button/text_button.h"
#include "views/layout/grid_layout.h"
#include "views/view.h"

namespace examples {

RadioButtonExample::RadioButtonExample(ExamplesMain* main)
    : ExampleBase(main, "Radio Button"), count_(0) {
}

RadioButtonExample::~RadioButtonExample() {
}

void RadioButtonExample::CreateExampleView(views::View* container) {
  select_ = new views::TextButton(this, L"Select");
  status_ = new views::TextButton(this, L"Show Status");

  int group = 1;
  for (size_t i = 0; i < arraysize(radio_buttons_); ++i) {
    radio_buttons_[i] = new views::RadioButton(
        UTF8ToUTF16(base::StringPrintf("Radio %d in group %d", i + 1, group)),
        group);
    radio_buttons_[i]->set_listener(this);
  }

  views::GridLayout* layout = new views::GridLayout(container);
  container->SetLayoutManager(layout);

  views::ColumnSet* column_set = layout->AddColumnSet(0);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
                        1.0f, views::GridLayout::USE_PREF, 0, 0);
  for (size_t i = 0; i < arraysize(radio_buttons_); ++i) {
    layout->StartRow(0, 0);
    layout->AddView(radio_buttons_[i]);
  }
  layout->StartRow(0, 0);
  layout->AddView(select_);
  layout->StartRow(0, 0);
  layout->AddView(status_);
}

void RadioButtonExample::ButtonPressed(views::Button* sender,
                                       const views::Event& event) {
  if (sender == select_) {
    radio_buttons_[2]->SetChecked(true);
  } else if (sender == status_) {
    // Show the state of radio buttons.
    PrintStatus("Group: 1:%s, 2:%s, 3:%s",
                BoolToOnOff(radio_buttons_[0]->checked()),
                BoolToOnOff(radio_buttons_[1]->checked()),
                BoolToOnOff(radio_buttons_[2]->checked()));
  } else {
    PrintStatus("Pressed! count:%d", ++count_);
  }
}

}  // namespace examples
<commit_msg>views/examples: Fix the format string of size_t var in RadioButton example.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "views/examples/radio_button_example.h"

#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "views/controls/button/text_button.h"
#include "views/layout/grid_layout.h"
#include "views/view.h"

namespace examples {

RadioButtonExample::RadioButtonExample(ExamplesMain* main)
    : ExampleBase(main, "Radio Button"), count_(0) {
}

RadioButtonExample::~RadioButtonExample() {
}

void RadioButtonExample::CreateExampleView(views::View* container) {
  select_ = new views::TextButton(this, L"Select");
  status_ = new views::TextButton(this, L"Show Status");

  int group = 1;
  for (size_t i = 0; i < arraysize(radio_buttons_); ++i) {
    radio_buttons_[i] = new views::RadioButton(
        UTF8ToUTF16(base::StringPrintf(
            "Radio %d in group %d", static_cast<int>(i) + 1, group)),
        group);
    radio_buttons_[i]->set_listener(this);
  }

  views::GridLayout* layout = new views::GridLayout(container);
  container->SetLayoutManager(layout);

  views::ColumnSet* column_set = layout->AddColumnSet(0);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
                        1.0f, views::GridLayout::USE_PREF, 0, 0);
  for (size_t i = 0; i < arraysize(radio_buttons_); ++i) {
    layout->StartRow(0, 0);
    layout->AddView(radio_buttons_[i]);
  }
  layout->StartRow(0, 0);
  layout->AddView(select_);
  layout->StartRow(0, 0);
  layout->AddView(status_);
}

void RadioButtonExample::ButtonPressed(views::Button* sender,
                                       const views::Event& event) {
  if (sender == select_) {
    radio_buttons_[2]->SetChecked(true);
  } else if (sender == status_) {
    // Show the state of radio buttons.
    PrintStatus("Group: 1:%s, 2:%s, 3:%s",
                BoolToOnOff(radio_buttons_[0]->checked()),
                BoolToOnOff(radio_buttons_[1]->checked()),
                BoolToOnOff(radio_buttons_[2]->checked()));
  } else {
    PrintStatus("Pressed! count:%d", ++count_);
  }
}

}  // namespace examples
<|endoftext|>


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

#include "omxData.h"
#include <Eigen/Core>
// #include <Eigen/Dense>
#include "EnableWarnings.h"

struct omxWLSFitFunction : omxFitFunction {

	omxMatrix* observedCov;
	omxMatrix* observedMeans;
	omxMatrix* expectedCov;
	omxMatrix* expectedMeans;
	omxMatrix* observedFlattened;
	omxMatrix* expectedFlattened;
	omxMatrix* weights;
	omxMatrix* P;
	omxMatrix* B;
	int n;
	int fullWls;
	int numOrdinal;

	omxWLSFitFunction() :standardMeans(0), standardThresholds(0) {};
	virtual ~omxWLSFitFunction();
	virtual void init();
	virtual void compute(int ffcompute, FitContext *fc);
	virtual void populateAttr(SEXP algebra);

	// 'standard' prefix variables are temp space used by flattenDataToVector
	omxMatrix* standardCov;
	omxMatrix* standardMeans;
	omxMatrix* standardThresholds;
	void flattenDataToVector(omxMatrix* cov, omxMatrix* means, omxMatrix *thresholdMat,
				 std::vector< omxThresholdColumn > &thresholds, omxMatrix* vector);
};

void omxWLSFitFunction::flattenDataToVector(omxMatrix* cov, omxMatrix* means, omxMatrix *thresholdMat,
			 std::vector< omxThresholdColumn > &thresholds, omxMatrix* vector)
{
	EigenVectorAdaptor vec1(vector);
	normalToStdVector(cov, means, thresholdMat, numOrdinal, thresholds, vec1);
}

omxWLSFitFunction::~omxWLSFitFunction()
{
	if(OMX_DEBUG) {mxLog("Freeing WLS FitFunction.");}

	omxWLSFitFunction* owo = this;
	omxFreeMatrix(owo->observedFlattened);
	omxFreeMatrix(owo->expectedFlattened);
	omxFreeMatrix(owo->B);
	omxFreeMatrix(owo->P);
	omxFreeMatrix(owo->standardCov);
	omxFreeMatrix(owo->standardMeans);
	omxFreeMatrix(owo->standardThresholds);
}

void omxWLSFitFunction::compute(int want, FitContext *fc)
{
	auto *oo = this;
	auto *owo = this;
	if (want & (FF_COMPUTE_INITIAL_FIT | FF_COMPUTE_PREOPTIMIZE)) return;

	if(OMX_DEBUG) { mxLog("Beginning WLS Evaluation.");}
	// Requires: Data, means, covariances.

	double sum = 0.0;

	omxMatrix *eCov, *eMeans, *oFlat, *eFlat;

	/* Locals for readability.  Compiler should cut through this. */
	eCov		= owo->expectedCov;
	eMeans 		= owo->expectedMeans;
	auto &eThresh   = oo->expectation->getThresholdInfo();
	oFlat		= owo->observedFlattened;
	eFlat		= owo->expectedFlattened;
	int onei	= 1;

	/* Recompute and recopy */
	if(OMX_DEBUG) { mxLog("WLSFitFunction Computing expectation"); }
	omxExpectationCompute(fc, expectation, NULL);

	omxMatrix *expThresholdsMat = expectation->thresholdsMat;

	flattenDataToVector(eCov, eMeans, expThresholdsMat, eThresh, eFlat);

	omxCopyMatrix(B, oFlat);

	//if(OMX_DEBUG) {omxPrintMatrix(B, "....WLS Observed Vector: "); }
	if(OMX_DEBUG) {omxPrintMatrix(eFlat, "....WLS Expected Vector: "); }
	omxDAXPY(-1.0, eFlat, B);
	//if(OMX_DEBUG) {omxPrintMatrix(B, "....WLS Observed - Expected Vector: "); }

	if(weights != NULL) {
		//if(OMX_DEBUG_ALGEBRA) {omxPrintMatrix(weights, "....WLS Weight Matrix: "); }
		omxDGEMV(TRUE, 1.0, weights, B, 0.0, P);
	} else {
		// ULS Case: Memcpy faster than dgemv.
		omxCopyMatrix(P, B);
	}

	sum = F77_CALL(ddot)(&(P->cols), P->data, &onei, B->data, &onei);

	oo->matrix->data[0] = sum;

	if(OMX_DEBUG) { mxLog("WLSFitFunction value comes to: %f.", oo->matrix->data[0]); }

}

void omxWLSFitFunction::populateAttr(SEXP algebra)
{
	if(OMX_DEBUG) { mxLog("Populating WLS Attributes."); }

	omxWLSFitFunction *argStruct = this;
	omxMatrix *expCovInt = argStruct->expectedCov;	    		// Expected covariance
	omxMatrix *expMeanInt = argStruct->expectedMeans;			// Expected means
	omxMatrix *weightInt = argStruct->weights;			// Expected means

	SEXP expCovExt, expMeanExt, gradients;
	Rf_protect(expCovExt = Rf_allocMatrix(REALSXP, expCovInt->rows, expCovInt->cols));
	for(int row = 0; row < expCovInt->rows; row++)
		for(int col = 0; col < expCovInt->cols; col++)
			REAL(expCovExt)[col * expCovInt->rows + row] =
				omxMatrixElement(expCovInt, row, col);

	if (expMeanInt != NULL) {
		Rf_protect(expMeanExt = Rf_allocMatrix(REALSXP, expMeanInt->rows, expMeanInt->cols));
		for(int row = 0; row < expMeanInt->rows; row++)
			for(int col = 0; col < expMeanInt->cols; col++)
				REAL(expMeanExt)[col * expMeanInt->rows + row] =
					omxMatrixElement(expMeanInt, row, col);
	} else {
		Rf_protect(expMeanExt = Rf_allocMatrix(REALSXP, 0, 0));
	}

	if(OMX_DEBUG_ALGEBRA) {omxPrintMatrix(weightInt, "...WLS Weight Matrix: W"); }
	SEXP weightExt = NULL;
	if (weightInt) {
		Rf_protect(weightExt = Rf_allocMatrix(REALSXP, weightInt->rows, weightInt->cols));
		for(int row = 0; row < weightInt->rows; row++)
			for(int col = 0; col < weightInt->cols; col++)
				REAL(weightExt)[col * weightInt->rows + row] = weightInt->data[col * weightInt->rows + row];
	}

	if(0) {  /* TODO fix for new internal API
		int nLocs = Global->numFreeParams;
		double gradient[Global->numFreeParams];
		for(int loc = 0; loc < nLocs; loc++) {
			gradient[loc] = NA_REAL;
		}
		//oo->gradientFun(oo, gradient);
		Rf_protect(gradients = Rf_allocMatrix(REALSXP, 1, nLocs));

		for(int loc = 0; loc < nLocs; loc++)
			REAL(gradients)[loc] = gradient[loc];
		 */
	} else {
		Rf_protect(gradients = Rf_allocMatrix(REALSXP, 0, 0));
	}

	if(OMX_DEBUG) { mxLog("Installing populated WLS Attributes."); }
	Rf_setAttrib(algebra, Rf_install("expCov"), expCovExt);
	Rf_setAttrib(algebra, Rf_install("expMean"), expMeanExt);
	if (weightExt) Rf_setAttrib(algebra, Rf_install("weights"), weightExt);
	Rf_setAttrib(algebra, Rf_install("gradients"), gradients);

	ProtectedSEXP Rsat(Rf_ScalarReal(0));
	Rf_setAttrib(algebra, Rf_install("SaturatedLikelihood"), Rsat);
	//Rf_setAttrib(algebra, Rf_install("IndependenceLikelihood"), Rf_ScalarReal(0));
	ProtectedSEXP Rmisfit(Rf_ScalarReal(omxMatrixElement(matrix, 0, 0)));
	Rf_setAttrib(algebra, Rf_install("ADFMisfit"), Rmisfit);
}

omxFitFunction *omxInitWLSFitFunction()
{ return new omxWLSFitFunction; }

void omxWLSFitFunction::init()
{
	auto *oo = this;
	auto *newObj = this;

	omxState *currentState = oo->matrix->currentState;
	omxMatrix *cov, *means;

	if(OMX_DEBUG) { mxLog("Initializing WLS FitFunction function."); }

	if(OMX_DEBUG) { mxLog("Retrieving expectation.\n"); }
	if (!oo->expectation) { Rf_error("%s requires an expectation", oo->fitType); }

	if(OMX_DEBUG) { mxLog("Retrieving data.\n"); }
	omxData* dataMat = oo->expectation->data;
	if (dataMat->hasDefinitionVariables()) Rf_error("%s: def vars not implemented", oo->name());

	if(!strEQ(omxDataType(dataMat), "acov") && !strEQ(omxDataType(dataMat), "cov")) {
		char *errstr = (char*) calloc(250, sizeof(char));
		sprintf(errstr, "WLS FitFunction unable to handle data type %s.  Data must be of type 'acov'.\n", omxDataType(dataMat));
		omxRaiseError(errstr);
		free(errstr);
		if(OMX_DEBUG) { mxLog("WLS FitFunction unable to handle data type %s.  Aborting.", omxDataType(dataMat)); }
		return;
	}

	fullWls = strEQ("WLS", CHAR(Rf_asChar(R_do_slot(rObj, Rf_install("weights")))));

	oo->units = fullWls? FIT_UNITS_SQUARED_RESIDUAL_CHISQ : FIT_UNITS_SQUARED_RESIDUAL;

	/* Get Expectation Elements */
	newObj->expectedCov = omxGetExpectationComponent(oo->expectation, "cov");
	newObj->expectedMeans = omxGetExpectationComponent(oo->expectation, "means");

	/* Read and set expected means, variances, and weights */
	dataMat->permute(oo->expectation->getDataColumns());

	cov = omxDataCovariance(dataMat);
	means = omxDataMeans(dataMat);
	weights = omxDataAcov(dataMat);

	std::vector< omxThresholdColumn > &oThresh = omxDataThresholds(oo->expectation->data);

	newObj->observedCov = cov;
	newObj->observedMeans = means;
	newObj->n = omxDataNumObs(dataMat);

	numOrdinal = oo->expectation->numOrdinal;
	auto &eThresh = oo->expectation->getThresholdInfo();

	if (eThresh.size() && !means) {
		omxRaiseError("Means are required when the data include ordinal measurements");
		return;
	}

	// Error Checking: Observed/Expected means must agree.
	// ^ is XOR: true when one is false and the other is not.
	if((newObj->expectedMeans == NULL) ^ (newObj->observedMeans == NULL)) {
		if(newObj->expectedMeans != NULL) {
			omxRaiseError("Observed means not detected, but an expected means matrix was specified.\n  If you  wish to model the means, you must provide observed means.\n");
			return;
		} else {
			omxRaiseError("Observed means were provided, but an expected means matrix was not specified.\n  If you provide observed means, you must specify a model for the means.\n");
			return;
		}
	}

	if((eThresh.size()==0) ^ (oThresh.size()==0)) {
		if (eThresh.size()) {
			omxRaiseError("Observed thresholds not detected, but an expected thresholds matrix was specified.\n   If you wish to model the thresholds, you must provide observed thresholds.\n ");
			return;
		} else {
			omxRaiseError("Observed thresholds were provided, but an expected thresholds matrix was not specified.\nIf you provide observed thresholds, you must specify a model for the thresholds.\n");
			return;
		}
	}

	for(int i = 0, ei=0; i < int(oThresh.size()); i++) {
		while (ei < int(eThresh.size()) && eThresh[ei].dColumn != oThresh[i].dColumn) ++ei;
		eThresh[ei].numThresholds = oThresh[i].numThresholds;
	}

	if (OMX_DEBUG) {
		mxLog("expected thresholds:");
		for (auto &th : eThresh) { th.log(); }
		mxLog("observed thresholds:");
		for (auto &th : oThresh) { th.log(); }
	}

	/* Error check weight matrix size */
	int ncol = newObj->observedCov->cols;
	int vectorSize = expectation->numSummaryStats();
	if(OMX_DEBUG) { mxLog("Intial WLSFitFunction vectorSize comes to: %d.", vectorSize); }

	if(weights != NULL && (weights->rows != weights->cols || weights->cols != vectorSize)) {
		omxRaiseError("Developer Error in WLS-based FitFunction object: WLS-based expectation specified an incorrectly-sized weight matrix.\nIf you are not developing a new expectation type, you should probably post this to the OpenMx forums.");
		return;
	}

	// FIXME: More Rf_error checking for incoming Fit Functions

	/* Temporary storage for calculation */
	newObj->observedFlattened = omxInitMatrix(vectorSize, 1, TRUE, currentState);
	newObj->expectedFlattened = omxInitMatrix(vectorSize, 1, TRUE, currentState);
	newObj->P = omxInitMatrix(1, vectorSize, TRUE, currentState);
	newObj->B = omxInitMatrix(vectorSize, 1, TRUE, currentState);
	newObj->standardCov = omxInitMatrix(ncol, ncol, TRUE, currentState);
	if (oo->expectation->thresholdsMat) {
		newObj->standardThresholds = omxInitMatrix(oo->expectation->thresholdsMat->rows, oo->expectation->thresholdsMat->cols, TRUE, currentState);
	}
	if(means){
		newObj->standardMeans = omxInitMatrix(1, ncol, TRUE, currentState);
	}
	omxMatrix *obsThresholdsMat = oo->expectation->data->obsThresholdsMat;
	if (obsThresholdsMat && oo->expectation->thresholdsMat) {
		if (obsThresholdsMat->rows != oo->expectation->thresholdsMat->rows ||
		    obsThresholdsMat->cols != oo->expectation->thresholdsMat->cols) {
			omxRaiseError("Observed and expected threshold matrices must have the same number of rows and columns");
		}
	}

	flattenDataToVector(newObj->observedCov, newObj->observedMeans, obsThresholdsMat, oThresh, newObj->observedFlattened);
	flattenDataToVector(newObj->expectedCov, newObj->expectedMeans, oo->expectation->thresholdsMat,
				eThresh, newObj->expectedFlattened);
}
<commit_msg>Remove deadcode<commit_after> /*
 *  Copyright 2007-2018 by the individuals mentioned in the source code history
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include "omxData.h"
#include <Eigen/Core>
// #include <Eigen/Dense>
#include "EnableWarnings.h"

struct omxWLSFitFunction : omxFitFunction {

	omxMatrix* expectedCov;
	omxMatrix* expectedMeans;
	omxMatrix* observedFlattened;
	omxMatrix* expectedFlattened;
	omxMatrix* weights;
	omxMatrix* P;
	omxMatrix* B;
	int n;
	int fullWls;
	int numOrdinal;

	omxWLSFitFunction() :standardMeans(0), standardThresholds(0) {};
	virtual ~omxWLSFitFunction();
	virtual void init();
	virtual void compute(int ffcompute, FitContext *fc);
	virtual void populateAttr(SEXP algebra);

	// 'standard' prefix variables are temp space used by flattenDataToVector
	omxMatrix* standardCov;
	omxMatrix* standardMeans;
	omxMatrix* standardThresholds;
	void flattenDataToVector(omxMatrix* cov, omxMatrix* means, omxMatrix *thresholdMat,
				 std::vector< omxThresholdColumn > &thresholds, omxMatrix* vector);
};

void omxWLSFitFunction::flattenDataToVector(omxMatrix* cov, omxMatrix* means, omxMatrix *thresholdMat,
			 std::vector< omxThresholdColumn > &thresholds, omxMatrix* vector)
{
	EigenVectorAdaptor vec1(vector);
	normalToStdVector(cov, means, thresholdMat, numOrdinal, thresholds, vec1);
}

omxWLSFitFunction::~omxWLSFitFunction()
{
	if(OMX_DEBUG) {mxLog("Freeing WLS FitFunction.");}

	omxWLSFitFunction* owo = this;
	omxFreeMatrix(owo->observedFlattened);
	omxFreeMatrix(owo->expectedFlattened);
	omxFreeMatrix(owo->B);
	omxFreeMatrix(owo->P);
	omxFreeMatrix(owo->standardCov);
	omxFreeMatrix(owo->standardMeans);
	omxFreeMatrix(owo->standardThresholds);
}

void omxWLSFitFunction::compute(int want, FitContext *fc)
{
	auto *oo = this;
	auto *owo = this;
	if (want & (FF_COMPUTE_INITIAL_FIT | FF_COMPUTE_PREOPTIMIZE)) return;

	if(OMX_DEBUG) { mxLog("Beginning WLS Evaluation.");}
	// Requires: Data, means, covariances.

	double sum = 0.0;

	omxMatrix *eCov, *eMeans, *oFlat, *eFlat;

	/* Locals for readability.  Compiler should cut through this. */
	eCov		= owo->expectedCov;
	eMeans 		= owo->expectedMeans;
	auto &eThresh   = oo->expectation->getThresholdInfo();
	oFlat		= owo->observedFlattened;
	eFlat		= owo->expectedFlattened;
	int onei	= 1;

	/* Recompute and recopy */
	if(OMX_DEBUG) { mxLog("WLSFitFunction Computing expectation"); }
	omxExpectationCompute(fc, expectation, NULL);

	omxMatrix *expThresholdsMat = expectation->thresholdsMat;

	flattenDataToVector(eCov, eMeans, expThresholdsMat, eThresh, eFlat);

	omxCopyMatrix(B, oFlat);

	//if(OMX_DEBUG) {omxPrintMatrix(B, "....WLS Observed Vector: "); }
	if(OMX_DEBUG) {omxPrintMatrix(eFlat, "....WLS Expected Vector: "); }
	omxDAXPY(-1.0, eFlat, B);
	//if(OMX_DEBUG) {omxPrintMatrix(B, "....WLS Observed - Expected Vector: "); }

	if(weights != NULL) {
		//if(OMX_DEBUG_ALGEBRA) {omxPrintMatrix(weights, "....WLS Weight Matrix: "); }
		omxDGEMV(TRUE, 1.0, weights, B, 0.0, P);
	} else {
		// ULS Case: Memcpy faster than dgemv.
		omxCopyMatrix(P, B);
	}

	sum = F77_CALL(ddot)(&(P->cols), P->data, &onei, B->data, &onei);

	oo->matrix->data[0] = sum;

	if(OMX_DEBUG) { mxLog("WLSFitFunction value comes to: %f.", oo->matrix->data[0]); }

}

void omxWLSFitFunction::populateAttr(SEXP algebra)
{
	if(OMX_DEBUG) { mxLog("Populating WLS Attributes."); }

	omxWLSFitFunction *argStruct = this;
	omxMatrix *expCovInt = argStruct->expectedCov;	    		// Expected covariance
	omxMatrix *expMeanInt = argStruct->expectedMeans;			// Expected means
	omxMatrix *weightInt = argStruct->weights;			// Expected means

	SEXP expCovExt, expMeanExt, gradients;
	Rf_protect(expCovExt = Rf_allocMatrix(REALSXP, expCovInt->rows, expCovInt->cols));
	for(int row = 0; row < expCovInt->rows; row++)
		for(int col = 0; col < expCovInt->cols; col++)
			REAL(expCovExt)[col * expCovInt->rows + row] =
				omxMatrixElement(expCovInt, row, col);

	if (expMeanInt != NULL) {
		Rf_protect(expMeanExt = Rf_allocMatrix(REALSXP, expMeanInt->rows, expMeanInt->cols));
		for(int row = 0; row < expMeanInt->rows; row++)
			for(int col = 0; col < expMeanInt->cols; col++)
				REAL(expMeanExt)[col * expMeanInt->rows + row] =
					omxMatrixElement(expMeanInt, row, col);
	} else {
		Rf_protect(expMeanExt = Rf_allocMatrix(REALSXP, 0, 0));
	}

	if(OMX_DEBUG_ALGEBRA) {omxPrintMatrix(weightInt, "...WLS Weight Matrix: W"); }
	SEXP weightExt = NULL;
	if (weightInt) {
		Rf_protect(weightExt = Rf_allocMatrix(REALSXP, weightInt->rows, weightInt->cols));
		for(int row = 0; row < weightInt->rows; row++)
			for(int col = 0; col < weightInt->cols; col++)
				REAL(weightExt)[col * weightInt->rows + row] = weightInt->data[col * weightInt->rows + row];
	}

	if(0) {  /* TODO fix for new internal API
		int nLocs = Global->numFreeParams;
		double gradient[Global->numFreeParams];
		for(int loc = 0; loc < nLocs; loc++) {
			gradient[loc] = NA_REAL;
		}
		//oo->gradientFun(oo, gradient);
		Rf_protect(gradients = Rf_allocMatrix(REALSXP, 1, nLocs));

		for(int loc = 0; loc < nLocs; loc++)
			REAL(gradients)[loc] = gradient[loc];
		 */
	} else {
		Rf_protect(gradients = Rf_allocMatrix(REALSXP, 0, 0));
	}

	if(OMX_DEBUG) { mxLog("Installing populated WLS Attributes."); }
	Rf_setAttrib(algebra, Rf_install("expCov"), expCovExt);
	Rf_setAttrib(algebra, Rf_install("expMean"), expMeanExt);
	if (weightExt) Rf_setAttrib(algebra, Rf_install("weights"), weightExt);
	Rf_setAttrib(algebra, Rf_install("gradients"), gradients);

	ProtectedSEXP Rsat(Rf_ScalarReal(0));
	Rf_setAttrib(algebra, Rf_install("SaturatedLikelihood"), Rsat);
	//Rf_setAttrib(algebra, Rf_install("IndependenceLikelihood"), Rf_ScalarReal(0));
	ProtectedSEXP Rmisfit(Rf_ScalarReal(omxMatrixElement(matrix, 0, 0)));
	Rf_setAttrib(algebra, Rf_install("ADFMisfit"), Rmisfit);
}

omxFitFunction *omxInitWLSFitFunction()
{ return new omxWLSFitFunction; }

void omxWLSFitFunction::init()
{
	auto *oo = this;
	auto *newObj = this;

	omxState *currentState = oo->matrix->currentState;
	omxMatrix *cov, *means;

	if(OMX_DEBUG) { mxLog("Initializing WLS FitFunction function."); }

	if(OMX_DEBUG) { mxLog("Retrieving expectation.\n"); }
	if (!oo->expectation) { Rf_error("%s requires an expectation", oo->fitType); }

	if(OMX_DEBUG) { mxLog("Retrieving data.\n"); }
	omxData* dataMat = oo->expectation->data;
	if (dataMat->hasDefinitionVariables()) Rf_error("%s: def vars not implemented", oo->name());

	if(!strEQ(omxDataType(dataMat), "acov") && !strEQ(omxDataType(dataMat), "cov")) {
		char *errstr = (char*) calloc(250, sizeof(char));
		sprintf(errstr, "WLS FitFunction unable to handle data type %s.  Data must be of type 'acov'.\n", omxDataType(dataMat));
		omxRaiseError(errstr);
		free(errstr);
		if(OMX_DEBUG) { mxLog("WLS FitFunction unable to handle data type %s.  Aborting.", omxDataType(dataMat)); }
		return;
	}

	fullWls = strEQ("WLS", CHAR(Rf_asChar(R_do_slot(rObj, Rf_install("weights")))));

	oo->units = fullWls? FIT_UNITS_SQUARED_RESIDUAL_CHISQ : FIT_UNITS_SQUARED_RESIDUAL;

	/* Get Expectation Elements */
	newObj->expectedCov = omxGetExpectationComponent(oo->expectation, "cov");
	newObj->expectedMeans = omxGetExpectationComponent(oo->expectation, "means");

	/* Read and set expected means, variances, and weights */
	dataMat->permute(oo->expectation->getDataColumns());

	cov = omxDataCovariance(dataMat);
	means = omxDataMeans(dataMat);
	weights = omxDataAcov(dataMat);

	std::vector< omxThresholdColumn > &oThresh = omxDataThresholds(oo->expectation->data);

	newObj->n = omxDataNumObs(dataMat);

	numOrdinal = oo->expectation->numOrdinal;
	auto &eThresh = oo->expectation->getThresholdInfo();

	if (eThresh.size() && !means) {
		omxRaiseError("Means are required when the data include ordinal measurements");
		return;
	}

	// Error Checking: Observed/Expected means must agree.
	// ^ is XOR: true when one is false and the other is not.
	if((newObj->expectedMeans == NULL) ^ (means == NULL)) {
		if(newObj->expectedMeans != NULL) {
			omxRaiseError("Observed means not detected, but an expected means matrix was specified.\n  If you  wish to model the means, you must provide observed means.\n");
			return;
		} else {
			omxRaiseError("Observed means were provided, but an expected means matrix was not specified.\n  If you provide observed means, you must specify a model for the means.\n");
			return;
		}
	}

	if((eThresh.size()==0) ^ (oThresh.size()==0)) {
		if (eThresh.size()) {
			omxRaiseError("Observed thresholds not detected, but an expected thresholds matrix was specified.\n   If you wish to model the thresholds, you must provide observed thresholds.\n ");
			return;
		} else {
			omxRaiseError("Observed thresholds were provided, but an expected thresholds matrix was not specified.\nIf you provide observed thresholds, you must specify a model for the thresholds.\n");
			return;
		}
	}

	for(int i = 0, ei=0; i < int(oThresh.size()); i++) {
		while (ei < int(eThresh.size()) && eThresh[ei].dColumn != oThresh[i].dColumn) ++ei;
		eThresh[ei].numThresholds = oThresh[i].numThresholds;
	}

	if (OMX_DEBUG) {
		mxLog("expected thresholds:");
		for (auto &th : eThresh) { th.log(); }
		mxLog("observed thresholds:");
		for (auto &th : oThresh) { th.log(); }
	}

	/* Error check weight matrix size */
	int ncol = cov->cols;
	int vectorSize = expectation->numSummaryStats();
	if(OMX_DEBUG) { mxLog("Intial WLSFitFunction vectorSize comes to: %d.", vectorSize); }

	if(weights != NULL && (weights->rows != weights->cols || weights->cols != vectorSize)) {
		omxRaiseError("Developer Error in WLS-based FitFunction object: WLS-based expectation specified an incorrectly-sized weight matrix.\nIf you are not developing a new expectation type, you should probably post this to the OpenMx forums.");
		return;
	}

	// FIXME: More Rf_error checking for incoming Fit Functions

	/* Temporary storage for calculation */
	newObj->observedFlattened = omxInitMatrix(vectorSize, 1, TRUE, currentState);
	newObj->expectedFlattened = omxInitMatrix(vectorSize, 1, TRUE, currentState);
	newObj->P = omxInitMatrix(1, vectorSize, TRUE, currentState);
	newObj->B = omxInitMatrix(vectorSize, 1, TRUE, currentState);
	newObj->standardCov = omxInitMatrix(ncol, ncol, TRUE, currentState);
	if (oo->expectation->thresholdsMat) {
		newObj->standardThresholds = omxInitMatrix(oo->expectation->thresholdsMat->rows, oo->expectation->thresholdsMat->cols, TRUE, currentState);
	}
	if(means){
		newObj->standardMeans = omxInitMatrix(1, ncol, TRUE, currentState);
	}
	omxMatrix *obsThresholdsMat = oo->expectation->data->obsThresholdsMat;
	if (obsThresholdsMat && oo->expectation->thresholdsMat) {
		if (obsThresholdsMat->rows != oo->expectation->thresholdsMat->rows ||
		    obsThresholdsMat->cols != oo->expectation->thresholdsMat->cols) {
			omxRaiseError("Observed and expected threshold matrices must have the same number of rows and columns");
		}
	}

	flattenDataToVector(cov, means, obsThresholdsMat, oThresh, newObj->observedFlattened);
	flattenDataToVector(newObj->expectedCov, newObj->expectedMeans, oo->expectation->thresholdsMat,
				eThresh, newObj->expectedFlattened);
}
<|endoftext|>