<commit_before>#pragma ident "$Id: //depot/sgl/gpstk/dev/apps/receiver/AshtechMessage.cpp#1 $"

/**
 * @file AshtechMessage.cpp
 * Containers for Ashtech data, conversions to RINEX - definitions.
 */

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk 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
//  any later version.
//
//  The GPSTk 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 GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

//============================================================================
//
//This software developed by Applied Research Laboratories at the University of
//Texas at Austin, under contract to an agency or agencies within the U.S.
//Department of Defense. The U.S. Government retains all rights to use,
//duplicate, distribute, disclose, or release this software.
//
//Pursuant to DoD Directive 523024
//
// DISTRIBUTION STATEMENT A: This software has been approved for public
//                           release, distribution is unlimited.
//
//=============================================================================

#include <string>
#include <iostream>
#include <iomanip>
#include <string.h>

#include "BinUtils.hpp"
#include "StringUtils.hpp"
#include "DayTime.hpp"
#include "EngEphemeris.hpp"
#include "RinexObsHeader.hpp"
#include "icd_200_constants.hpp"
#include "AshtechMessage.hpp"

static bool debug=false;

namespace gpstk
{

   static const double CFF=C_GPS_M/OSC_FREQ;
   static const double wl1=CFF/L1_MULT;
   static const double wl2=CFF/L2_MULT;

   AshtechMessage::AshtechMessage(const std::string& ibuff, ObsSource src,
                                  ObsFormat fmt)
         : msgSource(src), msgFormat(fmt), buffer(ibuff)
   {
      using namespace std;

      // Determine the type of observation
      string label=buffer.substr(0,3);
      if (label=="MCA") msgType = MCA;
      if (label=="MCL") msgType = MCL;
      if (label=="MP1") msgType = MP1;
      if (label=="MP2") msgType = MP2;
      if (label=="MPC") msgType = MPC;
      if (label=="PBN") msgType = PBEN;
      if (label=="SNV") msgType = SNAV;
      if (label=="EPB") msgType = EPB;
      if (label=="SAL") msgType = SALM;
      if (label=="ALB") msgType = ALB;
      if (label=="ION") msgType = ION;
   }

   bool AshtechMessage::isObs(void) const
   {
     return ( (msgType==MCA) || (msgType==MCL) || (msgType==MP1) ||
              (msgType==MP2) || (msgType==MPC) );
   }

   int AshtechMessage::getSequence(void) const
   {
      int result=-1;

      if ((msgType == MPC) && (msgFormat == ASCII))
      {
         result=
            StringUtils::asInt(StringUtils::word(buffer,1,','));
      }

      return result;
   }

   int AshtechMessage::getPRN(void) const
   {
      int result=-1;

      if   ((msgType == MPC) && (msgFormat == ASCII))
      {
         result=
            StringUtils::asInt(StringUtils::word(buffer,3,','));
      }

      if   (msgType==EPB)
      {
         result=StringUtils::asInt(buffer.substr(4,5));
      }

      return result;
   }

   int AshtechMessage::getTracker(void) const
   {
      int result=-1;

      if ((msgType == MPC) && (msgFormat == ASCII))
      {
         result=
            StringUtils::asInt(StringUtils::word(buffer,6,','));
      }

      return result;
   }

   DayTime AshtechMessage::getEpoch(const DayTime& prevTime) const
   {
      short oldweek = prevTime.GPSfullweek();
      short newweek = oldweek;

      double oldsow = prevTime.GPSsecond();
      double newsow;

      DayTime thisTime(prevTime);

      if ((msgType == PBEN)&&(msgFormat == ASCII))
      {
         newsow =
            StringUtils::asDouble(StringUtils::word(buffer,1,','));

            // A test for week rollover
         if ((newsow+6*DayTime::SEC_DAY)<oldsow)
            newweek++;

         thisTime = DayTime(newweek, newsow);
      }

      if ((msgType == MPC)&&(msgFormat == ASCII))
      {
         int seqDiff = getSequence() - calculateSequenceNumber(prevTime);
         // Nominally seqDiff should be small. Check if there is a rollover
         // between the two inputs sequences numbers.
         while (seqDiff > (1800*50/2))
		seqDiff -= 1800*50;

         thisTime.addMilliSeconds(50 * seqDiff);
      }

      return thisTime;
   }

   float AshtechMessage::engSNR(short value, float equivalentNoiseBW)
   {
      const int   n = 20000; // number of samples in 1 ms
      const float m = 4.14;  // magnitude of the carrier estimate;

      const float d = gpstk::PI/(n*n*m*m*4.0);
      float snr;

      if (value)
      {
         snr = exp(((float)value)/25.0);
         snr = snr*snr*equivalentNoiseBW*d;
         snr = 10 * log10(snr);
      }
      else
         snr = 0;

      return snr;
   }

   RinexObsData
      AshtechMessage::convertToRinexObsData(
            const std::list<AshtechMessage> obsMsgs,
            const DayTime& recentEpoch)
   throw(gpstk::Exception)
   {
      RinexObsData rod;
         // TODO: Should check to make sure this is really a PBEN
      DayTime epoch;
      std::list<AshtechMessage>::const_iterator first = obsMsgs.begin();
      epoch = (*first).getEpoch(recentEpoch);

      rod.time = epoch;
      rod.numSvs = 0;
      rod.epochFlag = 1;

      std::list<AshtechMessage>::const_iterator i;
      for (i=obsMsgs.begin(); i!=obsMsgs.end(); i++)
      {
         if ((i->msgType == MPC)&&(i->msgFormat == ASCII))
         {

            int prn      = StringUtils::asInt(    StringUtils::word(i->buffer,3,','));
            double C1    = StringUtils::asDouble( StringUtils::word(i->buffer,13,',')) * C_GPS_M / 1000.0;
            double P1    = StringUtils::asDouble( StringUtils::word(i->buffer,23,',')) * C_GPS_M / 1000.0;
            double P2    = StringUtils::asDouble( StringUtils::word(i->buffer,33,',')) * C_GPS_M / 1000.0;
            double L1    = StringUtils::asDouble( StringUtils::word(i->buffer,22,','));
            double L2    = StringUtils::asDouble( StringUtils::word(i->buffer,32,','));
            double D1    = StringUtils::asDouble( StringUtils::word(i->buffer,24,','));
            double D2    = StringUtils::asDouble( StringUtils::word(i->buffer,34,','));
            int snrL1    = StringUtils::asInt(    StringUtils::word(i->buffer,20,','));
            int snrL2    = StringUtils::asInt(    StringUtils::word(i->buffer,30,','));

            int warning  = StringUtils::asInt(    StringUtils::word(i->buffer,27,','));

            double S1    = engSNR(snrL1, 9.21e6);
            double S2    = engSNR(snrL2, 9.21e6);

               // Debug check
               // std::cout << prn << " " << D1 << " " << D2 << " " << L1 << " " << L2 << std::endl;
               // exit(0);

            RinexPrn thisSat(prn, systemGPS);
            RinexObsData::RinexObsTypeMap datamap;

            datamap[RinexObsHeader::C1].data = C1;
            datamap[RinexObsHeader::P1].data = P1;
            datamap[RinexObsHeader::P2].data = P2;
            datamap[RinexObsHeader::L1].data = L1;
            datamap[RinexObsHeader::L2].data = L2;
            datamap[RinexObsHeader::D1].data = -D1; // Note sign convention for Doppler is opposite that of RINEX.
            datamap[RinexObsHeader::D2].data = -D2;
            datamap[RinexObsHeader::S1].data = S1;
            datamap[RinexObsHeader::S2].data = S2;

            datamap[RinexObsHeader::L1].lli = 0;
            datamap[RinexObsHeader::L2].lli = 0;
            if (warning & 128)
            {
               datamap[RinexObsHeader::L1].lli = 1;
               datamap[RinexObsHeader::L2].lli = 1;
            }

            datamap[RinexObsHeader::L1].ssi = mapSNRtoSSI(snrL1);
            datamap[RinexObsHeader::L2].ssi = mapSNRtoSSI(snrL2);

            rod.obs[thisSat]=datamap;
            rod.numSvs++;
         }

      }

      return rod;
   }

   int AshtechMessage::calculateSequenceNumber(const DayTime& t)
   {
         // TODO: Throw if not a MBEN
      double secondsOfHour = t.minute()*60+t.second();
      double secondsOfSequence = secondsOfHour;
      while (secondsOfSequence >= 1800.)
         secondsOfSequence -= 1800.;
      double milliSecondsOfSequence = secondsOfSequence*1000.;
      // There is sequence tick every 50 milliseconds
      return (int)(milliSecondsOfSequence / 50.);
   }

   short AshtechMessage::mapSNRtoSSI(float snr)
   {
      if (snr>34) return 9;
      if (snr>29) return 8;
      if (snr>20) return 5;
      if (snr>10) return 1;
      return 0;
   }

   RinexNavData AshtechMessage::convertToRinexNavData(const AshtechMessage& msg, const DayTime& epoch)
   {
         // TODO: throw if not an EPB type
      using namespace BinUtils;

      int offset=5;
      const char *dptr = msg.buffer.data();

      EngEphemeris eph;
      short PRN = StringUtils::asInt(msg.buffer.substr(4,2));

      long subframe[30];

         //using namespace std;

      for (int i=0;i<30;i++)
      {
         subframe[i]=*((long *)(dptr+7+i*4));
#if BYTE_ORDER == LITTLE_ENDIAN
         BinUtils::twiddle(subframe[i]);
#endif
            //    cout << "Word " << dec << i << ": 0x" << hex << subframe[i] << endl << flush << dec;
      }

// TODO: throw an exception if these calls fail
      eph.addSubframe(subframe, epoch.GPSfullweek(), PRN, 0);
         //    cout << "sf1" << endl << flush;

      eph.addSubframe(subframe+10, epoch.GPSfullweek(), PRN, 0);
         //     cout << "sf2" << endl << flush;

      eph.addSubframe(subframe+20, epoch.GPSfullweek(), PRN, 0);
         // cout << "sf3" << endl << flush;

         // eph.dump(std::cout);

         // exit(0);

      return eph;
         //return RinexNavData();
   }

   void AshtechMessage::updateNavHeader(const AshtechMessage& ionMsg, RinexNavHeader& hdr)
   {
         // TODO: the ION message interpreter is broken. Make it work. Then have the main programm
         // regularly request an ION msg.

         // TODO: Throw if not an ION type... hmm, need an ASSERT macro for types
      using namespace BinUtils;
      using namespace std;

      // Offset between location in the buffer and the location defined in the
      // Ashtech document ZFamily.pdf -- ZFamily GPS Receivers, Technical Ref. Manual, dated 2002
      int offset=5;
      const char *dptr = ionMsg.buffer.data();

      // Alpha parameters of Klobuchar model-------------------------------------------------
      float alpha0, alpha1, alpha2, alpha3;

      memmove(&alpha0, dptr+offset+0,  4);
      memmove(&alpha1, dptr+offset+4,  4);
      memmove(&alpha2, dptr+offset+8,  4);
      memmove(&alpha3, dptr+offset+12, 4);

#if BYTE_ORDER == LITTLE_ENDIAN
      twiddle(alpha0);
      twiddle(alpha1);
      twiddle(alpha2);
      twiddle(alpha3);
#endif

      hdr.ionAlpha[0] = alpha0;
      hdr.ionAlpha[1] = alpha1;
      hdr.ionAlpha[2] = alpha2;
      hdr.ionAlpha[3] = alpha3;

      hdr.valid |= RinexNavHeader::ionAlphaValid;

      // Beta parameters of Klobuchar model-------------------------------------------------
      float beta0, beta1, beta2, beta3;

      memmove(&beta0, dptr+offset+16, 4);
      memmove(&beta1, dptr+offset+20, 4);
      memmove(&beta2, dptr+offset+24, 4);
      memmove(&beta3, dptr+offset+28, 4);

#if BYTE_ORDER == LITTLE_ENDIAN
      twiddle(beta0);
      twiddle(beta1);
      twiddle(beta2);
      twiddle(beta3);
#endif

      hdr.ionBeta[0] = beta0;
      hdr.ionBeta[1] = beta1;
      hdr.ionBeta[2] = beta2;
      hdr.ionBeta[3] = beta3;

      hdr.valid |= RinexNavHeader::ionBetaValid;

      // Ref time parameters of Klobuchar model-------------------------------------------------

      double A0, A1;
      long UTCseconds;
      short UTCweek;

      memmove(&A1,         dptr+offset+32, 8);
      memmove(&A0,         dptr+offset+40, 8);
      memmove(&UTCseconds, dptr+offset+48, 4);
      memmove(&UTCweek,    dptr+offset+52, 2);

#if BYTE_ORDER == LITTLE_ENDIAN
      twiddle(A1);
      twiddle(A0);
      twiddle(UTCseconds);
      twiddle(UTCweek);
#endif

      hdr.A0 = A0;
      hdr.A1 = A1;
      hdr.UTCRefWeek = UTCweek;
      hdr.UTCRefTime = UTCseconds;

      hdr.valid |= RinexNavHeader::deltaUTCValid;

      // Leap seconds --------------------------------------------------------------------------

      short leapSeconds;

      memmove(&leapSeconds, dptr+52, 2);

#if BYTE_ORDER == LITTLE_ENDIAN
      twiddle(leapSeconds);
#endif

      hdr.leapSeconds = leapSeconds;

      hdr.valid |= RinexNavHeader::leapSecondsValid;

      return;
   }

} // End namespace
<commit_msg>Incorrect setup of epoch line in RINEX output.<commit_after>#pragma ident "$Id: //depot/sgl/gpstk/dev/apps/receiver/AshtechMessage.cpp#1 $"

/**
 * @file AshtechMessage.cpp
 * Containers for Ashtech data, conversions to RINEX - definitions.
 */

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk 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
//  any later version.
//
//  The GPSTk 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 GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

//============================================================================
//
//This software developed by Applied Research Laboratories at the University of
//Texas at Austin, under contract to an agency or agencies within the U.S.
//Department of Defense. The U.S. Government retains all rights to use,
//duplicate, distribute, disclose, or release this software.
//
//Pursuant to DoD Directive 523024
//
// DISTRIBUTION STATEMENT A: This software has been approved for public
//                           release, distribution is unlimited.
//
//=============================================================================

#include <string>
#include <iostream>
#include <iomanip>
#include <string.h>

#include "BinUtils.hpp"
#include "StringUtils.hpp"
#include "DayTime.hpp"
#include "EngEphemeris.hpp"
#include "RinexObsHeader.hpp"
#include "icd_200_constants.hpp"
#include "AshtechMessage.hpp"

static bool debug=false;

namespace gpstk
{

   static const double CFF=C_GPS_M/OSC_FREQ;
   static const double wl1=CFF/L1_MULT;
   static const double wl2=CFF/L2_MULT;

   AshtechMessage::AshtechMessage(const std::string& ibuff, ObsSource src,
                                  ObsFormat fmt)
         : msgSource(src), msgFormat(fmt), buffer(ibuff)
   {
      using namespace std;

      // Determine the type of observation
      string label=buffer.substr(0,3);
      if (label=="MCA") msgType = MCA;
      if (label=="MCL") msgType = MCL;
      if (label=="MP1") msgType = MP1;
      if (label=="MP2") msgType = MP2;
      if (label=="MPC") msgType = MPC;
      if (label=="PBN") msgType = PBEN;
      if (label=="SNV") msgType = SNAV;
      if (label=="EPB") msgType = EPB;
      if (label=="SAL") msgType = SALM;
      if (label=="ALB") msgType = ALB;
      if (label=="ION") msgType = ION;
   }

   bool AshtechMessage::isObs(void) const
   {
     return ( (msgType==MCA) || (msgType==MCL) || (msgType==MP1) ||
              (msgType==MP2) || (msgType==MPC) );
   }

   int AshtechMessage::getSequence(void) const
   {
      int result=-1;

      if ((msgType == MPC) && (msgFormat == ASCII))
      {
         result=
            StringUtils::asInt(StringUtils::word(buffer,1,','));
      }

      return result;
   }

   int AshtechMessage::getPRN(void) const
   {
      int result=-1;

      if   ((msgType == MPC) && (msgFormat == ASCII))
      {
         result=
            StringUtils::asInt(StringUtils::word(buffer,3,','));
      }

      if   (msgType==EPB)
      {
         result=StringUtils::asInt(buffer.substr(4,5));
      }

      return result;
   }

   int AshtechMessage::getTracker(void) const
   {
      int result=-1;

      if ((msgType == MPC) && (msgFormat == ASCII))
      {
         result=
            StringUtils::asInt(StringUtils::word(buffer,6,','));
      }

      return result;
   }

   DayTime AshtechMessage::getEpoch(const DayTime& prevTime) const
   {
      short oldweek = prevTime.GPSfullweek();
      short newweek = oldweek;

      double oldsow = prevTime.GPSsecond();
      double newsow;

      DayTime thisTime(prevTime);

      if ((msgType == PBEN)&&(msgFormat == ASCII))
      {
         newsow =
            StringUtils::asDouble(StringUtils::word(buffer,1,','));

            // A test for week rollover
         if ((newsow+6*DayTime::SEC_DAY)<oldsow)
            newweek++;

         thisTime = DayTime(newweek, newsow);
      }

      if ((msgType == MPC)&&(msgFormat == ASCII))
      {
         int seqDiff = getSequence() - calculateSequenceNumber(prevTime);
         // Nominally seqDiff should be small. Check if there is a rollover
         // between the two inputs sequences numbers.
         while (seqDiff > (1800*50/2))
		seqDiff -= 1800*50;

         thisTime.addMilliSeconds(50 * seqDiff);
      }

      return thisTime;
   }

   float AshtechMessage::engSNR(short value, float equivalentNoiseBW)
   {
      const int   n = 20000; // number of samples in 1 ms
      const float m = 4.14;  // magnitude of the carrier estimate;

      const float d = gpstk::PI/(n*n*m*m*4.0);
      float snr;

      if (value)
      {
         snr = exp(((float)value)/25.0);
         snr = snr*snr*equivalentNoiseBW*d;
         snr = 10 * log10(snr);
      }
      else
         snr = 0;

      return snr;
   }

   RinexObsData
      AshtechMessage::convertToRinexObsData(
            const std::list<AshtechMessage> obsMsgs,
            const DayTime& recentEpoch)
   throw(gpstk::Exception)
   {
      RinexObsData rod;
         // TODO: Should check to make sure this is really a PBEN
      DayTime epoch;
      std::list<AshtechMessage>::const_iterator first = obsMsgs.begin();
      epoch = (*first).getEpoch(recentEpoch);

      rod.time = epoch;
      rod.numSvs = 0;
      rod.epochFlag = 0;

      std::list<AshtechMessage>::const_iterator i;
      for (i=obsMsgs.begin(); i!=obsMsgs.end(); i++)
      {
         if ((i->msgType == MPC)&&(i->msgFormat == ASCII))
         {

            int prn      = StringUtils::asInt(    StringUtils::word(i->buffer,3,','));
            double C1    = StringUtils::asDouble( StringUtils::word(i->buffer,13,',')) * C_GPS_M / 1000.0;
            double P1    = StringUtils::asDouble( StringUtils::word(i->buffer,23,',')) * C_GPS_M / 1000.0;
            double P2    = StringUtils::asDouble( StringUtils::word(i->buffer,33,',')) * C_GPS_M / 1000.0;
            double L1    = StringUtils::asDouble( StringUtils::word(i->buffer,22,','));
            double L2    = StringUtils::asDouble( StringUtils::word(i->buffer,32,','));
            double D1    = StringUtils::asDouble( StringUtils::word(i->buffer,24,','));
            double D2    = StringUtils::asDouble( StringUtils::word(i->buffer,34,','));
            int snrL1    = StringUtils::asInt(    StringUtils::word(i->buffer,20,','));
            int snrL2    = StringUtils::asInt(    StringUtils::word(i->buffer,30,','));

            int warning  = StringUtils::asInt(    StringUtils::word(i->buffer,27,','));

            double S1    = engSNR(snrL1, 9.21e6);
            double S2    = engSNR(snrL2, 9.21e6);

               // Debug check
               // std::cout << prn << " " << D1 << " " << D2 << " " << L1 << " " << L2 << std::endl;
               // exit(0);

            RinexPrn thisSat(prn, systemGPS);
            RinexObsData::RinexObsTypeMap datamap;

            datamap[RinexObsHeader::C1].data = C1;
            datamap[RinexObsHeader::P1].data = P1;
            datamap[RinexObsHeader::P2].data = P2;
            datamap[RinexObsHeader::L1].data = L1;
            datamap[RinexObsHeader::L2].data = L2;
            datamap[RinexObsHeader::D1].data = -D1; // Note sign convention for Doppler is opposite that of RINEX.
            datamap[RinexObsHeader::D2].data = -D2;
            datamap[RinexObsHeader::S1].data = S1;
            datamap[RinexObsHeader::S2].data = S2;

            datamap[RinexObsHeader::L1].lli = 0;
            datamap[RinexObsHeader::L2].lli = 0;
            if (warning & 128)
            {
               datamap[RinexObsHeader::L1].lli = 1;
               datamap[RinexObsHeader::L2].lli = 1;
            }

            datamap[RinexObsHeader::L1].ssi = mapSNRtoSSI(snrL1);
            datamap[RinexObsHeader::L2].ssi = mapSNRtoSSI(snrL2);

            rod.obs[thisSat]=datamap;
            rod.numSvs++;
         }

      }

      return rod;
   }

   int AshtechMessage::calculateSequenceNumber(const DayTime& t)
   {
         // TODO: Throw if not a MBEN
      double secondsOfHour = t.minute()*60+t.second();
      double secondsOfSequence = secondsOfHour;
      while (secondsOfSequence >= 1800.)
         secondsOfSequence -= 1800.;
      double milliSecondsOfSequence = secondsOfSequence*1000.;
      // There is sequence tick every 50 milliseconds
      return (int)(milliSecondsOfSequence / 50.);
   }

   short AshtechMessage::mapSNRtoSSI(float snr)
   {
      if (snr>34) return 9;
      if (snr>29) return 8;
      if (snr>20) return 5;
      if (snr>10) return 1;
      return 0;
   }

   RinexNavData AshtechMessage::convertToRinexNavData(const AshtechMessage& msg, const DayTime& epoch)
   {
         // TODO: throw if not an EPB type
      using namespace BinUtils;

      int offset=5;
      const char *dptr = msg.buffer.data();

      EngEphemeris eph;
      short PRN = StringUtils::asInt(msg.buffer.substr(4,2));

      long subframe[30];

         //using namespace std;

      for (int i=0;i<30;i++)
      {
         subframe[i]=*((long *)(dptr+7+i*4));
#if BYTE_ORDER == LITTLE_ENDIAN
         BinUtils::twiddle(subframe[i]);
#endif
            //    cout << "Word " << dec << i << ": 0x" << hex << subframe[i] << endl << flush << dec;
      }

// TODO: throw an exception if these calls fail
      eph.addSubframe(subframe, epoch.GPSfullweek(), PRN, 0);
         //    cout << "sf1" << endl << flush;

      eph.addSubframe(subframe+10, epoch.GPSfullweek(), PRN, 0);
         //     cout << "sf2" << endl << flush;

      eph.addSubframe(subframe+20, epoch.GPSfullweek(), PRN, 0);
         // cout << "sf3" << endl << flush;

         // eph.dump(std::cout);

         // exit(0);

      return eph;
         //return RinexNavData();
   }

   void AshtechMessage::updateNavHeader(const AshtechMessage& ionMsg, RinexNavHeader& hdr)
   {
         // TODO: the ION message interpreter is broken. Make it work. Then have the main programm
         // regularly request an ION msg.

         // TODO: Throw if not an ION type... hmm, need an ASSERT macro for types
      using namespace BinUtils;
      using namespace std;

      // Offset between location in the buffer and the location defined in the
      // Ashtech document ZFamily.pdf -- ZFamily GPS Receivers, Technical Ref. Manual, dated 2002
      int offset=5;
      const char *dptr = ionMsg.buffer.data();

      // Alpha parameters of Klobuchar model-------------------------------------------------
      float alpha0, alpha1, alpha2, alpha3;

      memmove(&alpha0, dptr+offset+0,  4);
      memmove(&alpha1, dptr+offset+4,  4);
      memmove(&alpha2, dptr+offset+8,  4);
      memmove(&alpha3, dptr+offset+12, 4);

#if BYTE_ORDER == LITTLE_ENDIAN
      twiddle(alpha0);
      twiddle(alpha1);
      twiddle(alpha2);
      twiddle(alpha3);
#endif

      hdr.ionAlpha[0] = alpha0;
      hdr.ionAlpha[1] = alpha1;
      hdr.ionAlpha[2] = alpha2;
      hdr.ionAlpha[3] = alpha3;

      hdr.valid |= RinexNavHeader::ionAlphaValid;

      // Beta parameters of Klobuchar model-------------------------------------------------
      float beta0, beta1, beta2, beta3;

      memmove(&beta0, dptr+offset+16, 4);
      memmove(&beta1, dptr+offset+20, 4);
      memmove(&beta2, dptr+offset+24, 4);
      memmove(&beta3, dptr+offset+28, 4);

#if BYTE_ORDER == LITTLE_ENDIAN
      twiddle(beta0);
      twiddle(beta1);
      twiddle(beta2);
      twiddle(beta3);
#endif

      hdr.ionBeta[0] = beta0;
      hdr.ionBeta[1] = beta1;
      hdr.ionBeta[2] = beta2;
      hdr.ionBeta[3] = beta3;

      hdr.valid |= RinexNavHeader::ionBetaValid;

      // Ref time parameters of Klobuchar model-------------------------------------------------

      double A0, A1;
      long UTCseconds;
      short UTCweek;

      memmove(&A1,         dptr+offset+32, 8);
      memmove(&A0,         dptr+offset+40, 8);
      memmove(&UTCseconds, dptr+offset+48, 4);
      memmove(&UTCweek,    dptr+offset+52, 2);

#if BYTE_ORDER == LITTLE_ENDIAN
      twiddle(A1);
      twiddle(A0);
      twiddle(UTCseconds);
      twiddle(UTCweek);
#endif

      hdr.A0 = A0;
      hdr.A1 = A1;
      hdr.UTCRefWeek = UTCweek;
      hdr.UTCRefTime = UTCseconds;

      hdr.valid |= RinexNavHeader::deltaUTCValid;

      // Leap seconds --------------------------------------------------------------------------

      short leapSeconds;

      memmove(&leapSeconds, dptr+52, 2);

#if BYTE_ORDER == LITTLE_ENDIAN
      twiddle(leapSeconds);
#endif

      hdr.leapSeconds = leapSeconds;

      hdr.valid |= RinexNavHeader::leapSecondsValid;

      return;
   }

} // End namespace
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
**     the names of its contributors may be used to endorse or promote
**     products derived from this software without specific prior written
**     permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/

#include "remoteselector.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    RemoteSelector d;
    QObject::connect(&d, SIGNAL(accepted()), &app, SLOT(quit()));
    d.startDiscovery();
    d.show();

    app.exec();

    return 0;
}

<commit_msg>Symbian: make btfiletransfer example application fullscreen on Symbian<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
**     the names of its contributors may be used to endorse or promote
**     products derived from this software without specific prior written
**     permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/

#include "remoteselector.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    RemoteSelector d;
    QObject::connect(&d, SIGNAL(accepted()), &app, SLOT(quit()));
    d.startDiscovery();
#ifdef Q_OS_SYMBIAN
    d.showFullScreen();
#else
    d.show();
#endif

    app.exec();

    return 0;
}

<|endoftext|>


<commit_before>/******************************************************************************
* Copyright (c) 2012, Howard Butler (hobu.inc@gmail.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#ifndef INCLUDED_PDAL_MACROS_HPP
#define INCLUDED_PDAL_MACROS_HPP

#include <pdal/pdal_internal.hpp>
//
// macros for creating the various stage types
//
#define MAKE_READER_CREATOR(T, FullT) \
    pdal::Reader* create_##T(const pdal::Options& options) \
        { \
            return new FullT(options); \
        }

#define MAKE_FILTER_CREATOR(T, FullT) \
    pdal::Filter* create_##T(pdal::Stage& prevStage, const pdal::Options& options) \
        { return new FullT(prevStage, options); }
#define MAKE_MULTIFILTER_CREATOR(T, FullT) \
    pdal::MultiFilter* create_##T(const std::vector<pdal::Stage*>& prevStages, const pdal::Options& options) \
        { return new FullT(prevStages, options); }
#define MAKE_WRITER_CREATOR(T, FullT) \
    pdal::Writer* create_##T(pdal::Stage& prevStage, const pdal::Options& options) \
        { return new FullT(prevStage, options); }

//
// macros to register the stage creators
//
#define REGISTER_WRITER(T, FullT) \
    registerDriverInfo<FullT>(); \
    registerWriter(FullT::s_getName(), create_##T)
#define REGISTER_READER(T, FullT) \
    registerDriverInfo<FullT>(); \
    registerReader(FullT::s_getName(), create_##T)
#define REGISTER_FILTER(T, FullT) \
    registerDriverInfo<FullT>(); \
    registerFilter(FullT::s_getName(), create_##T)
#define REGISTER_MULTIFILTER(T, FullT) \
    registerDriverInfo<FullT>(); \
    registerMultiFilter(FullT::s_getName(), create_##T)

#define CREATE_READER_PLUGIN(DriverName, DriverFullType) \
    PDAL_C_START PDAL_DLL void PDALRegister_reader_##DriverName(void* factory) \
    { \
        pdal::StageFactory& f = *(pdal::StageFactory*) factory; \
        f.registerReader(DriverFullType::s_getName(), create_##DriverName##Reader); \
    } \
    PDAL_C_END

#define CREATE_FILTER_PLUGIN(DriverName, DriverFullType) \
    PDAL_C_START PDAL_DLL void PDALRegister_filter_##DriverName(void* factory) \
    { \
        pdal::StageFactory& f = *(pdal::StageFactory*) factory; \
        f.registerFilter(DriverFullType::s_getName(), create_##DriverName##Filter); \
    } \
    PDAL_C_END

#define CREATE_MULTIFILTER_PLUGIN(DriverName, DriverFullType) \
    PDAL_C_START PDAL_DLL void PDALRegister_multifilter_##DriverName(void* factory) \
    { \
        pdal::StageFactory& f = *(pdal::StageFactory*) factory; \
        f.registerMultiFilter(DriverFullType::s_getName(), create_##DriverName##MultiFilter); \
    } \
    PDAL_C_END

#define CREATE_WRITER_PLUGIN(DriverName, DriverFullType) \
    PDAL_C_START PDAL_DLL void PDALRegister_writer_##DriverName(void* factory) \
    { \
        pdal::StageFactory& f = *(pdal::StageFactory*) factory; \
        f.registerWriter(DriverFullType::s_getName(), create_##DriverName##Writer); \
    } \
    PDAL_C_END

#endif
<commit_msg>register driver info when we register Stages to factory<commit_after>/******************************************************************************
* Copyright (c) 2012, Howard Butler (hobu.inc@gmail.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#ifndef INCLUDED_PDAL_MACROS_HPP
#define INCLUDED_PDAL_MACROS_HPP

#include <pdal/pdal_internal.hpp>
//
// macros for creating the various stage types
//
#define MAKE_READER_CREATOR(T, FullT) \
    pdal::Reader* create_##T(const pdal::Options& options) \
        { \
            return new FullT(options); \
        }

#define MAKE_FILTER_CREATOR(T, FullT) \
    pdal::Filter* create_##T(pdal::Stage& prevStage, const pdal::Options& options) \
        { return new FullT(prevStage, options); }
#define MAKE_MULTIFILTER_CREATOR(T, FullT) \
    pdal::MultiFilter* create_##T(const std::vector<pdal::Stage*>& prevStages, const pdal::Options& options) \
        { return new FullT(prevStages, options); }
#define MAKE_WRITER_CREATOR(T, FullT) \
    pdal::Writer* create_##T(pdal::Stage& prevStage, const pdal::Options& options) \
        { return new FullT(prevStage, options); }

//
// macros to register the stage creators
//
#define REGISTER_WRITER(T, FullT) \
    registerDriverInfo<FullT>(); \
    registerWriter(FullT::s_getName(), create_##T)
#define REGISTER_READER(T, FullT) \
    registerDriverInfo<FullT>(); \
    registerReader(FullT::s_getName(), create_##T)
#define REGISTER_FILTER(T, FullT) \
    registerDriverInfo<FullT>(); \
    registerFilter(FullT::s_getName(), create_##T)
#define REGISTER_MULTIFILTER(T, FullT) \
    registerDriverInfo<FullT>(); \
    registerMultiFilter(FullT::s_getName(), create_##T)

#define CREATE_READER_PLUGIN(DriverName, DriverFullType) \
    PDAL_C_START PDAL_DLL void PDALRegister_reader_##DriverName(void* factory) \
    { \
        pdal::StageFactory& f = *(pdal::StageFactory*) factory; \
        f.registerDriverInfo< DriverFullType>(); \
        f.registerReader(DriverFullType::s_getName(), create_##DriverName##Reader); \
    } \
    PDAL_C_END

#define CREATE_FILTER_PLUGIN(DriverName, DriverFullType) \
    PDAL_C_START PDAL_DLL void PDALRegister_filter_##DriverName(void* factory) \
    { \
        pdal::StageFactory& f = *(pdal::StageFactory*) factory; \
        f.registerDriverInfo< DriverFullType>(); \
        f.registerFilter(DriverFullType::s_getName(), create_##DriverName##Filter); \
    } \
    PDAL_C_END

#define CREATE_MULTIFILTER_PLUGIN(DriverName, DriverFullType) \
    PDAL_C_START PDAL_DLL void PDALRegister_multifilter_##DriverName(void* factory) \
    { \
        pdal::StageFactory& f = *(pdal::StageFactory*) factory; \
        f.registerDriverInfo< DriverFullType>(); \
        f.registerMultiFilter(DriverFullType::s_getName(), create_##DriverName##MultiFilter); \
    } \
    PDAL_C_END

#define CREATE_WRITER_PLUGIN(DriverName, DriverFullType) \
    PDAL_C_START PDAL_DLL void PDALRegister_writer_##DriverName(void* factory) \
    { \
        pdal::StageFactory& f = *(pdal::StageFactory*) factory; \
        f.registerDriverInfo< DriverFullType>(); \
        f.registerWriter(DriverFullType::s_getName(), create_##DriverName##Writer); \
    } \
    PDAL_C_END

#endif
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "MarshalingTest.h"
#include "EventInputStream.h"
#include "EventOutputStream.h"
#include "Decompose.h"
#include "uuid.h"

/*
EXTRA SPECS to code to that have not yet been implemented as unit tests.

1. Sender and Client each import the same header file which defines a UUID event.
2. Sender encodes UUID of its event in the serialized stream
3. Client reads UUID and args, and reverse-look ups the correct memfn to call the memfn
4. Client gracefully handles receiving UUID events it can't reverse lookup
5. EVERYONE should know when you change ANY identifying properties of a DECLARE_UUID
you must change the UUID as well or you will get version incompatilibity erros.
Extra points for figuring out how to enforce this.

Other Goals:
Broader SFINAE: force server and client to define their own Autoserialize or Autodeserialized
If the types aren't POD. At the very least, tests need to be written which violate the
"I can do everything with stringstreams" implementation currently passing
*/

DECLARE_UUID(EventWithUuid, "6EC2129F-5DD7-43D5-ACB5-864E8BB5D6B4") :
  public virtual EventReceiver
{
public:
  virtual void SampleEventFiring(const std::string* str) = 0;
  virtual void SampleEventFiring0(void) = 0;
  virtual void SampleEventFiring3(const std::string* str1, const std::string* str2, const std::string* str3) = 0;
  virtual Deferred SampleEventDeferred(const std::string* str) = 0;
};

class ListenerForUuid :
  public CoreThread,
  public EventWithUuid
{
public:
  ListenerForUuid(void) :
    m_called(false)
  {
    //Need to call ready here. Should be refactored out of existence.
  }

  bool m_called;
  std::string m_str;

  void SampleEventFiring0() override {
    m_called = true;
  }

  void SampleEventFiring(const std::string* str) override {
    m_called = true;
    m_str = *str;
  }

  void SampleEventFiring3(const std::string* str1, const std::string* str2, const std::string* str3) override {
    m_called = true;
  }

  Deferred SampleEventDeferred(const std::string* str) override {
    return Deferred(this);
  }
};

template<class T>
void VerifyProperStreamReceipt(EventOutputStream<T>* os, const AutoFired<EventWithUuid>& ewuuid) {
  // Register our expected event type:
  os->template EnableIdentity(&EventWithUuid::SampleEventFiring);

  // Test fire an event:
  std::string str("012345678900123456789012345678901234567890");
  ewuuid(&EventWithUuid::SampleEventFiring)(&str);

  // Verify that the output stream is no longer empty and has some default properties:
  EXPECT_FALSE(os->IsEmpty()) << "An output stream on an event was empty, even though an event it should have caught was just fired";
  EXPECT_LT(0UL, os->GetSize()) << "The output stream should have had more than zero bytes in it after recording an event, but it did not";

  // Verify that the output stream is _at least as long_ as the string argument we passed earlier:
  EXPECT_LE(str.size(), os->GetSize()) << "An output stream contained fewer uncompressed bytes than were transmitted in a fired event";
}

template<class T>
void VerifyProperStreamReceiptZeroArgs(EventOutputStream<T>* os, const AutoFired<EventWithUuid>& ewuuid) {
  // Register our expected event type:
  os->template EnableIdentity(&EventWithUuid::SampleEventFiring0);

  // Test fire an event:
  ewuuid(&EventWithUuid::SampleEventFiring0)();

  // Verify that the output stream is no longer empty and has some default properties:
  EXPECT_FALSE(os->IsEmpty()) << "0Args: An output stream on an event was empty, even though an event it should have caught was just fired";
  EXPECT_LT(0UL, os->GetSize()) << "0Args: The output stream should have had more than zero bytes in it after recording an event, but it did not";
}

template<class T>
void VerifyProperStreamReceiptThreeArgs(EventOutputStream<T>* os, const AutoFired<EventWithUuid>& ewuuid) {
  // Register our expected event type:
  os->template EnableIdentity(&EventWithUuid::SampleEventFiring3);

  // Test fire an event:
  std::string str1("012345678900123456789012345678901234567890");
  std::string str2("012345678900123456789012345678901234567890");
  std::string str3("012345678900123456789012345678901234567890");
  ewuuid(&EventWithUuid::SampleEventFiring3)(&str1, &str2, &str3);

  // Verify that the output stream is no longer empty and has some default properties:
  EXPECT_FALSE(os->IsEmpty()) << "3Args: An output stream on an event was empty, even though an event it should have caught was just fired";
  EXPECT_LT(0UL, os->GetSize()) << "3Args: The output stream should have had more than zero bytes in it after recording an event, but it did not";

  // Verify that the output stream is _at least as long_ as the string argument we passed earlier:
  EXPECT_LE(str1.size() * 3, os->GetSize()) << "3Args: An output stream contained fewer uncompressed bytes than were transmitted in a fired event";
}

TEST_F(MarshalingTest, VerifyListenersUpdated) {
  AutoFired<EventWithUuid> ewuuid;
  EXPECT_FALSE(ewuuid.HasListeners()) << "A newly created event incorrectly reported that listeners existed where none were subscribed";

  AutoCurrentContext ctxt;
  std::shared_ptr<EventOutputStream<EventWithUuid>> os = ctxt->CreateEventOutputStream<EventWithUuid>();
  ASSERT_NE(nullptr, os.get()) << "Attempted to obtain an event stream from a context, but the returned pointer was null";

  // Should be listeners now:
  EXPECT_TRUE(ewuuid.HasListeners()) << "An output stream creation did not change the HasListeners disposition";
  os.reset();

  EXPECT_FALSE(ewuuid.HasListeners()) << "An event incorrectly reported that it had listeners, even though its only listener--an output stream--is out of scope";
}

TEST_F(MarshalingTest, VerifyOutOfOrderFiring) {
  // We should be able to create an output stream on an event even if nobody fires this event right now
  AutoCurrentContext ctxt;
  std::shared_ptr<EventOutputStream<EventWithUuid>> os = ctxt->CreateEventOutputStream<EventWithUuid>();
  ASSERT_NE(nullptr, os.get()) << "Failed to create an output stream in a context where no firers of the underlying event exist";

  // Verify that we get stream reciept even if we fire at _this_ point, after the stream exists
  VerifyProperStreamReceipt(os.get(), AutoFired<EventWithUuid>());
}

TEST_F(MarshalingTest, VerifySimpleSerialization) {
  AutoFired<EventWithUuid> ewuuid;

  AutoCurrentContext ctxt;
  std::shared_ptr<EventOutputStream<EventWithUuid>> os = ctxt->CreateEventOutputStream<EventWithUuid>();

  ASSERT_NE(nullptr, os.get());

  // Should be empty before we fire anything:
  EXPECT_TRUE(os->IsEmpty()) << "Output stream was empty, even though it was just created";
  EXPECT_EQ(0UL, os->GetSize()) << "Output stream reported " << os->GetSize() << " bytes contained, it should have been empty";

  // Scoping behavior
  VerifyProperStreamReceipt(os.get(), ewuuid);
  os->Reset();
  VerifyProperStreamReceiptZeroArgs(os.get(), ewuuid);
  os->Reset();
  VerifyProperStreamReceiptThreeArgs(os.get(), ewuuid);
  // Flush the output stream and verify it does, in fact, reset its properties:
  os->Reset();
  EXPECT_TRUE(os->IsEmpty()) << "Output stream was not empty after being reset";

  // Let the output stream fall out of scope and verify that the listener existence disposition is updated:
  os.reset();
  EXPECT_FALSE(ewuuid.HasListeners()) << "An event incorrectly reported that it had listeners, even though its only listener--an output stream--is out of scope";
}

TEST_F(MarshalingTest, VerifySimpleDeserialization) {
  AutoCurrentContext ctxt;

  // Serialize a fired event first:
  AutoFired<EventWithUuid> ewuuid;
  std::shared_ptr<EventOutputStream<EventWithUuid>> os = ctxt->CreateEventOutputStream<EventWithUuid>();
  ASSERT_NE(nullptr, os.get());

  std::string helloWorld = "Hello, world!";
  std::string helloWorldAgain = "Hello, world, again!";

  ewuuid(&EventWithUuid::SampleEventFiring)(&helloWorld);
  ewuuid(&EventWithUuid::SampleEventFiring)(&helloWorldAgain);
  ASSERT_FALSE(os->IsEmpty());

  // Inject the listener into the context:
  AutoRequired<ListenerForUuid> listener;

  ASSERT_TRUE(listener->m_str.empty()) << "Listener unexpectedly received messages fired before its construction";

  // Now we create an input stream and use it to replay events from the output stream:
  std::shared_ptr<EventInputStream<EventWithUuid>> is = ctxt->CreateEventInputStream<EventWithUuid>();
  ASSERT_NE(nullptr, is.get()) << "Event input stream was empty";

  // Register our expected event type:
  is->template EnableIdentity(&EventWithUuid::SampleEventFiring);
  is->template EnableIdentity(&EventWithUuid::SampleEventDeferred);

  const void* ptr = os->GetData(); //This is damn unsafe. Who is supposed to be doing cleanup?
  size_t nRemaining = os->GetSize();
  size_t advanceBy = is->FireSingle(ptr, nRemaining);

  ASSERT_NE(0UL, advanceBy) << "Input stream did not correctly report the number of bytes deserialized";
  ASSERT_LE(advanceBy, nRemaining) << "Input stream processed more bytes from the passed buffer than were available for processing";

  // Verify that the listener got _something_, and the thing it got was the thing we sent earlier:
  EXPECT_TRUE(listener->m_called) << "Listener failed to receive any events from the event input stream";
  EXPECT_EQ(helloWorld, listener->m_str) << "Listener received an event, but the payload of the event was not the same as what was originally serialized";

  // Clear, advance, and fire the next event:
  listener->m_called = false;
  listener->m_str.clear();
  (char*&) ptr += advanceBy;
  nRemaining -= advanceBy;
  advanceBy = is->FireSingle(ptr, nRemaining);
  ASSERT_NE(0UL, advanceBy) << "A second attempt to fire an event failed to parse any bytes";
  ASSERT_LE(advanceBy, nRemaining) << "Input stream overran its buffer for the second fired event";

  // Now verify that we got called again:
  ASSERT_TRUE(listener->m_called) << "Second event was not received from the event input stream";
  ASSERT_EQ(helloWorldAgain, listener->m_str) << "Listener did not receive the second message payload from the input stream";

  // Ensure that we processed EXACTLY the number of bytes that were in the output stream:
  EXPECT_EQ(advanceBy, nRemaining) << "Output stream wrote extraneous bytes to its buffer which were not used during deserialization";
}
<commit_msg>Added test checking no reversing of multi-ary funcs. Currently fails<commit_after>#include "stdafx.h"
#include "MarshalingTest.h"
#include "EventInputStream.h"
#include "EventOutputStream.h"
#include "Decompose.h"
#include "uuid.h"

/*
EXTRA SPECS to code to that have not yet been implemented as unit tests.

1. Sender and Client each import the same header file which defines a UUID event.
2. Sender encodes UUID of its event in the serialized stream
3. Client reads UUID and args, and reverse-look ups the correct memfn to call the memfn
4. Client gracefully handles receiving UUID events it can't reverse lookup
5. EVERYONE should know when you change ANY identifying properties of a DECLARE_UUID
you must change the UUID as well or you will get version incompatilibity erros.
Extra points for figuring out how to enforce this.

Other Goals:
Broader SFINAE: force server and client to define their own Autoserialize or Autodeserialized
If the types aren't POD. At the very least, tests need to be written which violate the
"I can do everything with stringstreams" implementation currently passing
*/

DECLARE_UUID(EventWithUuid, "6EC2129F-5DD7-43D5-ACB5-864E8BB5D6B4") :
  public virtual EventReceiver
{
public:
  virtual void SampleEventFiring(const std::string* str) = 0;
  virtual void SampleEventFiring0(void) = 0;
  virtual void SampleEventFiring3(const std::string* str1, const std::string* str2, const std::string* str3) = 0;
  virtual Deferred SampleEventDeferred(const std::string* str) = 0;
};

class ListenerForUuid :
  public CoreThread,
  public EventWithUuid
{
public:
  ListenerForUuid(void) :
    m_called(false)
  {
    //Need to call ready here. Should be refactored out of existence.
  }

  bool m_called;
  std::string m_str;
  std::string m_str2;
  std::string m_str3;

  void SampleEventFiring0() override {
    m_called = true;
  }

  void SampleEventFiring(const std::string* str) override {
    m_called = true;
    m_str = *str;
  }

  void SampleEventFiring3(const std::string* str1, const std::string* str2, const std::string* str3) override {
    m_called = true;
    m_str = *str1;
    m_str2 = *str2;
    m_str3 = *str3;
  }

  Deferred SampleEventDeferred(const std::string* str) override {
    return Deferred(this);
  }
};

template<class T>
void VerifyProperStreamReceipt(EventOutputStream<T>* os, const AutoFired<EventWithUuid>& ewuuid) {
  // Register our expected event type:
  os->template EnableIdentity(&EventWithUuid::SampleEventFiring);

  // Test fire an event:
  std::string str("012345678900123456789012345678901234567890");
  ewuuid(&EventWithUuid::SampleEventFiring)(&str);

  // Verify that the output stream is no longer empty and has some default properties:
  EXPECT_FALSE(os->IsEmpty()) << "An output stream on an event was empty, even though an event it should have caught was just fired";
  EXPECT_LT(0UL, os->GetSize()) << "The output stream should have had more than zero bytes in it after recording an event, but it did not";

  // Verify that the output stream is _at least as long_ as the string argument we passed earlier:
  EXPECT_LE(str.size(), os->GetSize()) << "An output stream contained fewer uncompressed bytes than were transmitted in a fired event";
}

template<class T>
void VerifyProperStreamReceiptZeroArgs(EventOutputStream<T>* os, const AutoFired<EventWithUuid>& ewuuid) {
  // Register our expected event type:
  os->template EnableIdentity(&EventWithUuid::SampleEventFiring0);

  // Test fire an event:
  ewuuid(&EventWithUuid::SampleEventFiring0)();

  // Verify that the output stream is no longer empty and has some default properties:
  EXPECT_FALSE(os->IsEmpty()) << "0Args: An output stream on an event was empty, even though an event it should have caught was just fired";
  EXPECT_LT(0UL, os->GetSize()) << "0Args: The output stream should have had more than zero bytes in it after recording an event, but it did not";
}

template<class T>
void VerifyProperStreamReceiptThreeArgs(EventOutputStream<T>* os, const AutoFired<EventWithUuid>& ewuuid) {
  // Register our expected event type:
  os->template EnableIdentity(&EventWithUuid::SampleEventFiring3);

  // Test fire an event:
  std::string str1("012345678900123456789012345678901234567890");
  std::string str2("012345678900123456789012345678901234567890");
  std::string str3("012345678900123456789012345678901234567890");
  ewuuid(&EventWithUuid::SampleEventFiring3)(&str1, &str2, &str3);

  // Verify that the output stream is no longer empty and has some default properties:
  EXPECT_FALSE(os->IsEmpty()) << "3Args: An output stream on an event was empty, even though an event it should have caught was just fired";
  EXPECT_LT(0UL, os->GetSize()) << "3Args: The output stream should have had more than zero bytes in it after recording an event, but it did not";

  // Verify that the output stream is _at least as long_ as the string argument we passed earlier:
  EXPECT_LE(str1.size() * 3, os->GetSize()) << "3Args: An output stream contained fewer uncompressed bytes than were transmitted in a fired event";
}

TEST_F(MarshalingTest, VerifyListenersUpdated) {
  AutoFired<EventWithUuid> ewuuid;
  EXPECT_FALSE(ewuuid.HasListeners()) << "A newly created event incorrectly reported that listeners existed where none were subscribed";

  AutoCurrentContext ctxt;
  std::shared_ptr<EventOutputStream<EventWithUuid>> os = ctxt->CreateEventOutputStream<EventWithUuid>();
  ASSERT_NE(nullptr, os.get()) << "Attempted to obtain an event stream from a context, but the returned pointer was null";

  // Should be listeners now:
  EXPECT_TRUE(ewuuid.HasListeners()) << "An output stream creation did not change the HasListeners disposition";
  os.reset();

  EXPECT_FALSE(ewuuid.HasListeners()) << "An event incorrectly reported that it had listeners, even though its only listener--an output stream--is out of scope";
}

TEST_F(MarshalingTest, VerifyOutOfOrderFiring) {
  // We should be able to create an output stream on an event even if nobody fires this event right now
  AutoCurrentContext ctxt;
  std::shared_ptr<EventOutputStream<EventWithUuid>> os = ctxt->CreateEventOutputStream<EventWithUuid>();
  ASSERT_NE(nullptr, os.get()) << "Failed to create an output stream in a context where no firers of the underlying event exist";

  // Verify that we get stream reciept even if we fire at _this_ point, after the stream exists
  VerifyProperStreamReceipt(os.get(), AutoFired<EventWithUuid>());
}

TEST_F(MarshalingTest, VerifySimpleSerialization) {
  AutoFired<EventWithUuid> ewuuid;

  AutoCurrentContext ctxt;
  std::shared_ptr<EventOutputStream<EventWithUuid>> os = ctxt->CreateEventOutputStream<EventWithUuid>();

  ASSERT_NE(nullptr, os.get());

  // Should be empty before we fire anything:
  EXPECT_TRUE(os->IsEmpty()) << "Output stream was empty, even though it was just created";
  EXPECT_EQ(0UL, os->GetSize()) << "Output stream reported " << os->GetSize() << " bytes contained, it should have been empty";

  // Scoping behavior
  VerifyProperStreamReceipt(os.get(), ewuuid);
  os->Reset();
  VerifyProperStreamReceiptZeroArgs(os.get(), ewuuid);
  os->Reset();
  VerifyProperStreamReceiptThreeArgs(os.get(), ewuuid);
  // Flush the output stream and verify it does, in fact, reset its properties:
  os->Reset();
  EXPECT_TRUE(os->IsEmpty()) << "Output stream was not empty after being reset";

  // Let the output stream fall out of scope and verify that the listener existence disposition is updated:
  os.reset();
  EXPECT_FALSE(ewuuid.HasListeners()) << "An event incorrectly reported that it had listeners, even though its only listener--an output stream--is out of scope";
}

TEST_F(MarshalingTest, VerifySimpleDeserialization) {
  AutoCurrentContext ctxt;

  // Serialize a fired event first:
  AutoFired<EventWithUuid> ewuuid;
  std::shared_ptr<EventOutputStream<EventWithUuid>> os = ctxt->CreateEventOutputStream<EventWithUuid>();
  ASSERT_NE(nullptr, os.get());

  std::string helloWorld = "Hello, world!";
  std::string helloWorldAgain = "Hello, world, again!";
  std::string helloWorldYetAgain = "Hello, world, yet again!";

  ewuuid(&EventWithUuid::SampleEventFiring)(&helloWorld);
  ewuuid(&EventWithUuid::SampleEventFiring)(&helloWorldAgain);
  ewuuid(&EventWithUuid::SampleEventFiring3)(&helloWorld, &helloWorldAgain, &helloWorldYetAgain);
  ASSERT_FALSE(os->IsEmpty());

  // Inject the listener into the context:
  AutoRequired<ListenerForUuid> listener;

  ASSERT_TRUE(listener->m_str.empty()) << "Listener unexpectedly received messages fired before its construction";

  // Now we create an input stream and use it to replay events from the output stream:
  std::shared_ptr<EventInputStream<EventWithUuid>> is = ctxt->CreateEventInputStream<EventWithUuid>();
  ASSERT_NE(nullptr, is.get()) << "Event input stream was empty";

  // Register our expected event type:
  is->template EnableIdentity(&EventWithUuid::SampleEventFiring3);
  is->template EnableIdentity(&EventWithUuid::SampleEventFiring);
  is->template EnableIdentity(&EventWithUuid::SampleEventDeferred);

  const void* ptr = os->GetData(); //This is damn unsafe. Who is supposed to be doing cleanup?
  size_t nRemaining = os->GetSize();
  size_t advanceBy = is->FireSingle(ptr, nRemaining);

  ASSERT_NE(0UL, advanceBy) << "Input stream did not correctly report the number of bytes deserialized";
  ASSERT_LE(advanceBy, nRemaining) << "Input stream processed more bytes from the passed buffer than were available for processing";

  // Verify that the listener got _something_, and the thing it got was the thing we sent earlier:
  EXPECT_TRUE(listener->m_called) << "Listener failed to receive any events from the event input stream";
  EXPECT_EQ(helloWorld, listener->m_str) << "Listener received an event, but the payload of the event was not the same as what was originally serialized";

  // Clear, advance, and fire the next event:
  listener->m_called = false;
  listener->m_str.clear();
  (char*&) ptr += advanceBy;
  nRemaining -= advanceBy;
  advanceBy = is->FireSingle(ptr, nRemaining);
  ASSERT_NE(0UL, advanceBy) << "A second attempt to fire an event failed to parse any bytes";
  ASSERT_LE(advanceBy, nRemaining) << "Input stream overran its buffer for the second fired event";

  // Now verify that we got called again:
  ASSERT_TRUE(listener->m_called) << "Second event was not received from the event input stream";
  ASSERT_EQ(helloWorldAgain, listener->m_str) << "Listener did not receive the second message payload from the input stream";

  // Clear, advance, and fire the next event:
  listener->m_called = false;
  listener->m_str.clear();
  (char*&)ptr += advanceBy;
  nRemaining -= advanceBy;
  advanceBy = is->FireSingle(ptr, nRemaining);
  ASSERT_NE(0UL, advanceBy) << "A third attempt to fire an event failed to parse any bytes";
  ASSERT_LE(advanceBy, nRemaining) << "Input stream overran its buffer for the third fired event";

  // Now verify that we got called again:
  ASSERT_TRUE(listener->m_called) << "Second event was not received from the event input stream";
  ASSERT_EQ(helloWorld, listener->m_str) << "Listener did not receive the third message payload, 1 arg,  from the input stream";
  ASSERT_EQ(helloWorldAgain, listener->m_str2) << "Listener did not receive the third message payload, 2 arg,  from the input stream";
  ASSERT_EQ(helloWorldYetAgain, listener->m_str3) << "Listener did not receive the third message payload, 3 arg,  from the input stream";

  // Ensure that we processed EXACTLY the number of bytes that were in the output stream:
  EXPECT_EQ(advanceBy, nRemaining) << "Output stream wrote extraneous bytes to its buffer which were not used during deserialization";
}<|endoftext|>


<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/*
 * Copyright 2014 Cloudius Systems
 */

#pragma once

#include <seastar/core/future.hh>
#include <seastar/util/std-compat.hh>
#include <exception>

namespace seastar {

/// \addtogroup fiber-module
/// @{

/// Exception thrown when a \ref gate object has been closed
/// by the \ref gate::close() method.
class gate_closed_exception : public std::exception {
public:
    virtual const char* what() const noexcept override {
        return "gate closed";
    }
};

/// Facility to stop new requests, and to tell when existing requests are done.
///
/// When stopping a service that serves asynchronous requests, we are faced with
/// two problems: preventing new requests from coming in, and knowing when existing
/// requests have completed.  The \c gate class provides a solution.
class gate {
    size_t _count = 0;
    std::optional<promise<>> _stopped;
public:
    gate() = default;
    gate(const gate&) = delete;
    gate(gate&&) = default;
    ~gate() {
        assert(!_count && "gate destroyed with outstanding requests");
    }
    /// Tries to register an in-progress request.
    ///
    /// If the gate is not closed, the request is registered and the function returns `true`,
    /// Otherwise the function just returns `false` and has no other effect.
    bool try_enter() noexcept {
        bool opened = !_stopped;
        if (opened) {
            ++_count;
        }
        return opened;
    }
    /// Registers an in-progress request.
    ///
    /// If the gate is not closed, the request is registered.  Otherwise,
    /// a \ref gate_closed_exception is thrown.
    void enter() {
        if (!try_enter()) {
            throw gate_closed_exception();
        }
    }
    /// Unregisters an in-progress request.
    ///
    /// If the gate is closed, and there are no more in-progress requests,
    /// the `_stopped` promise will be fulfilled.
    void leave() noexcept {
        --_count;
        if (!_count && _stopped) {
            _stopped->set_value();
        }
    }
    /// Potentially stop an in-progress request.
    ///
    /// If the gate is already closed, a \ref gate_closed_exception is thrown.
    /// By using \ref enter() and \ref leave(), the program can ensure that
    /// no further requests are serviced. However, long-running requests may
    /// continue to run. The check() method allows such a long operation to
    /// voluntarily stop itself after the gate is closed, by making calls to
    /// check() in appropriate places. check() with throw an exception and
    /// bail out of the long-running code if the gate is closed.
    void check() {
        if (_stopped) {
            throw gate_closed_exception();
        }
    }
    /// Closes the gate.
    ///
    /// Future calls to \ref enter() will fail with an exception, and when
    /// all current requests call \ref leave(), the returned future will be
    /// made ready.
    future<> close() noexcept {
        assert(!_stopped && "seastar::gate::close() cannot be called more than once");
        _stopped = std::make_optional(promise<>());
        if (!_count) {
            _stopped->set_value();
        }
        return _stopped->get_future();
    }

    /// Returns a current number of registered in-progress requests.
    size_t get_count() const noexcept {
        return _count;
    }

    /// Returns whether the gate is closed.
    bool is_closed() const noexcept {
        return bool(_stopped);
    }
};

namespace internal {

template <typename Func>
inline
auto
invoke_func_with_gate(gate& g, Func&& func) noexcept {
    return futurize_invoke(std::forward<Func>(func)).finally([&g] { g.leave(); });
}

} // namespace intgernal

/// Executes the function \c func making sure the gate \c g is properly entered
/// and later on, properly left.
///
/// \param func function to be executed
/// \param g the gate. Caller must make sure that it outlives this function.
/// \returns whatever \c func returns
///
/// \relates gate
template <typename Func>
inline
auto
with_gate(gate& g, Func&& func) {
    g.enter();
    return internal::invoke_func_with_gate(g, std::forward<Func>(func));
}

/// Executes the function \c func if the gate \c g can be entered
/// and later on, properly left.
///
/// \param func function to be executed
/// \param g the gate. Caller must make sure that it outlives this function.
///
/// If the gate is already closed, an exception future holding
/// \ref gate_closed_exception is returned, otherwise
/// \returns whatever \c func returns.
///
/// \relates gate
template <typename Func>
inline
auto
try_with_gate(gate& g, Func&& func) noexcept {
    if (!g.try_enter()) {
        using futurator = futurize<std::result_of_t<Func()>>;
        return futurator::make_exception_future(gate_closed_exception());
    }
    return internal::invoke_func_with_gate(g, std::forward<Func>(func));
}
/// @}

}
<commit_msg>gate: add default move assignment operator<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/*
 * Copyright 2014 Cloudius Systems
 */

#pragma once

#include <seastar/core/future.hh>
#include <seastar/util/std-compat.hh>
#include <exception>

namespace seastar {

/// \addtogroup fiber-module
/// @{

/// Exception thrown when a \ref gate object has been closed
/// by the \ref gate::close() method.
class gate_closed_exception : public std::exception {
public:
    virtual const char* what() const noexcept override {
        return "gate closed";
    }
};

/// Facility to stop new requests, and to tell when existing requests are done.
///
/// When stopping a service that serves asynchronous requests, we are faced with
/// two problems: preventing new requests from coming in, and knowing when existing
/// requests have completed.  The \c gate class provides a solution.
class gate {
    size_t _count = 0;
    std::optional<promise<>> _stopped;
public:
    gate() = default;
    gate(const gate&) = delete;
    gate(gate&&) = default;
    gate& operator=(gate&&) = default;
    ~gate() {
        assert(!_count && "gate destroyed with outstanding requests");
    }
    /// Tries to register an in-progress request.
    ///
    /// If the gate is not closed, the request is registered and the function returns `true`,
    /// Otherwise the function just returns `false` and has no other effect.
    bool try_enter() noexcept {
        bool opened = !_stopped;
        if (opened) {
            ++_count;
        }
        return opened;
    }
    /// Registers an in-progress request.
    ///
    /// If the gate is not closed, the request is registered.  Otherwise,
    /// a \ref gate_closed_exception is thrown.
    void enter() {
        if (!try_enter()) {
            throw gate_closed_exception();
        }
    }
    /// Unregisters an in-progress request.
    ///
    /// If the gate is closed, and there are no more in-progress requests,
    /// the `_stopped` promise will be fulfilled.
    void leave() noexcept {
        --_count;
        if (!_count && _stopped) {
            _stopped->set_value();
        }
    }
    /// Potentially stop an in-progress request.
    ///
    /// If the gate is already closed, a \ref gate_closed_exception is thrown.
    /// By using \ref enter() and \ref leave(), the program can ensure that
    /// no further requests are serviced. However, long-running requests may
    /// continue to run. The check() method allows such a long operation to
    /// voluntarily stop itself after the gate is closed, by making calls to
    /// check() in appropriate places. check() with throw an exception and
    /// bail out of the long-running code if the gate is closed.
    void check() {
        if (_stopped) {
            throw gate_closed_exception();
        }
    }
    /// Closes the gate.
    ///
    /// Future calls to \ref enter() will fail with an exception, and when
    /// all current requests call \ref leave(), the returned future will be
    /// made ready.
    future<> close() noexcept {
        assert(!_stopped && "seastar::gate::close() cannot be called more than once");
        _stopped = std::make_optional(promise<>());
        if (!_count) {
            _stopped->set_value();
        }
        return _stopped->get_future();
    }

    /// Returns a current number of registered in-progress requests.
    size_t get_count() const noexcept {
        return _count;
    }

    /// Returns whether the gate is closed.
    bool is_closed() const noexcept {
        return bool(_stopped);
    }
};

namespace internal {

template <typename Func>
inline
auto
invoke_func_with_gate(gate& g, Func&& func) noexcept {
    return futurize_invoke(std::forward<Func>(func)).finally([&g] { g.leave(); });
}

} // namespace intgernal

/// Executes the function \c func making sure the gate \c g is properly entered
/// and later on, properly left.
///
/// \param func function to be executed
/// \param g the gate. Caller must make sure that it outlives this function.
/// \returns whatever \c func returns
///
/// \relates gate
template <typename Func>
inline
auto
with_gate(gate& g, Func&& func) {
    g.enter();
    return internal::invoke_func_with_gate(g, std::forward<Func>(func));
}

/// Executes the function \c func if the gate \c g can be entered
/// and later on, properly left.
///
/// \param func function to be executed
/// \param g the gate. Caller must make sure that it outlives this function.
///
/// If the gate is already closed, an exception future holding
/// \ref gate_closed_exception is returned, otherwise
/// \returns whatever \c func returns.
///
/// \relates gate
template <typename Func>
inline
auto
try_with_gate(gate& g, Func&& func) noexcept {
    if (!g.try_enter()) {
        using futurator = futurize<std::result_of_t<Func()>>;
        return futurator::make_exception_future(gate_closed_exception());
    }
    return internal::invoke_func_with_gate(g, std::forward<Func>(func));
}
/// @}

}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Shota SUGIHARA
// Distributed under the MIT License.
#include <iostream>
#include <boost/format.hpp>
#include <Eigen/Dense>
#include "condition.h"
#include "grid.h"
#include "particles.h"

// Sample code using TinyMPS library.
int main() {
    tiny_mps::Condition condition("./input/input_cavitation.data");
    tiny_mps::Particles particles("./input/input.grid", condition);
    tiny_mps::Timer timer(condition);
    Eigen::Vector3d minpos(-0.02, -0.00042, 0);
    Eigen::Vector3d maxpos(0.02, 0.05, 0);
    while(particles.nextLoop("./output/output_%1%.vtk", timer)) {
        particles.moveInflowParticles(timer);
        particles.calculateTemporaryVelocity(condition.gravity, timer);
        particles.updateTemporaryPosition(timer);
        particles.giveCollisionRepulsionForce();
        particles.updateTemporaryPosition(timer);
        particles.calculateTemporaryParticleNumberDensity();
        particles.checkSurfaceParticlesWithTanakaMasunaga();
        particles.solvePressurePoission(timer);
        particles.correctVelocity(timer);
        particles.updateTemporaryPosition(timer);
        particles.updateVelocityAndPosition();
        particles.removeOutsideParticles(minpos, maxpos);
    }
}<commit_msg>Modified cavi_analysis<commit_after>// Copyright (c) 2017 Shota SUGIHARA
// Distributed under the MIT License.
#include <iostream>
#include <boost/format.hpp>
#include <Eigen/Dense>
#include "condition.h"
#include "grid.h"
#include "particles.h"

// Sample code using TinyMPS library.
int main() {
    tiny_mps::Condition condition("./input/input_cavitation.data");
    tiny_mps::Particles particles("./input/input.grid", condition);
    tiny_mps::Timer timer(condition);
    Eigen::Vector3d minpos(-0.02, -0.1, 0);
    Eigen::Vector3d maxpos(0.02, 0.05, 0);
    while(particles.nextLoop("./output/output_%1%.vtk", timer)) {
        particles.moveInflowParticles(timer);
        particles.calculateTemporaryVelocity(condition.gravity, timer);
        particles.updateTemporaryPosition(timer);
        particles.giveCollisionRepulsionForce();
        particles.updateTemporaryPosition(timer);
        particles.calculateTemporaryParticleNumberDensity();
        particles.checkSurfaceParticlesWithTanakaMasunaga();
        particles.solvePressurePoission(timer);
        particles.correctVelocity(timer);
        particles.updateTemporaryPosition(timer);
        particles.updateVelocityAndPosition();
        particles.removeOutsideParticles(minpos, maxpos);
    }
}<|endoftext|>