<commit_before>#ifndef COMPRESS__H__
#define COMPRESS__H__

#include <iterbase.hpp>

#include <utility>
#include <initializer_list>

namespace iter {

    //Forward declarations of Compressed and compress
    template <typename Container, typename Selector>
    class Compressed;

    template <typename Container, typename Selector>
    Compressed<Container, Selector> compress(Container &&, Selector &&);

    template <typename T, typename Selector>
    Compressed<std::initializer_list<T>, Selector> compress(
            std::initializer_list<T> &&, Selector &&);

    template <typename Container, typename T>
    Compressed<Container, std::initializer_list<T>> compress(
            Container &&, std::initializer_list<T> &&);

    template <typename Container, typename Selector>
    class Compressed : public IterBase<Container> {
        private:
            Container & container;
            Selector & selectors;

            // The only thing allowed to directly instantiate an Compressed is
            // the compress function
            friend Compressed compress<Container, Selector>(
                    Container &&, Selector &&);

            template <typename T, typename Sel>
            friend Compressed<std::initializer_list<T>, Sel> compress(
                    std::initializer_list<T> &&, Sel &&);

            template <typename Con, typename T>
            friend Compressed<Con, std::initializer_list<T>> compress(
                    Con &&, std::initializer_list<T> &&);

            using typename IterBase<Container>::contained_iter_type;

            using typename IterBase<Container>::contained_iter_ret;

            // Selector::Iterator type
            using selector_iter_type = decltype(std::begin(selectors));

            // Value constructor for use only in the compress function
            Compressed(Container && container, Selector && selectors) :
                container(container),
                selectors(selectors)
            { }
            Compressed () = delete;
            Compressed & operator=(const Compressed &) = delete;

        public:
            Compressed (const Compressed &) = default;

            class Iterator {
                private:
                    contained_iter_type sub_iter;
                    const contained_iter_type sub_end;

                    selector_iter_type selector_iter;
                    const selector_iter_type selector_end;

                    void increment_iterators() {
                        ++this->sub_iter;
                        ++this->selector_iter;
                    }

                    void skip_failures() {
                        while (this->sub_iter != this->sub_end &&
                                !*this->selector_iter) {
                            this->increment_iterators();
                        }
                    }

                public:
                    Iterator (contained_iter_type cont_iter,
                              contained_iter_type cont_end,
                              selector_iter_type sel_iter,
                              selector_iter_type sel_end) :
                        sub_iter(cont_iter),
                        sub_end(cont_end),
                        selector_iter(sel_iter),
                        selector_end(sel_end)
                    {
                        this->skip_failures();
                    }

                    contained_iter_ret operator*() const {
                        return *this->sub_iter;
                    }

                    Iterator & operator++() {
                        this->increment_iterators();
                        this->skip_failures();
                        return *this;
                    }

                    bool operator!=(const Iterator & other) const {
                        return this->sub_iter != other.sub_iter &&
                            this->selector_iter != other.selector_iter;
                    }
            };

            Iterator begin() const {
                return Iterator(
                        std::begin(this->container), std::end(this->container),
                        std::begin(this->selectors), std::end(this->selectors));
            }

            Iterator end() const {
                return Iterator(
                        std::end(this->container), std::end(this->container),
                        std::end(this->selectors), std::end(this->selectors));
            }

    };

    // Helper function to instantiate an Compressed
    template <typename Container, typename Selector>
    Compressed<Container, Selector> compress(
            Container && container, Selector && selectors) {
        return Compressed<Container, Selector>(
                std::forward<Container>(container),
                std::forward<Selector>(selectors));
    }

    template <typename T, typename Selector>
    Compressed<std::initializer_list<T>, Selector> compress(
            std::initializer_list<T> && il, Selector && selectors) {
        return Compressed<std::initializer_list<T>, Selector>(
                std::move(il),
                std::forward<Selector>(selectors));
    }

    template <typename Container, typename T>
    Compressed<Container, std::initializer_list<T>> compress(
            Container && container, std::initializer_list<T> && il) {
        return Compressed<Container, std::initializer_list<T>>(
                std::forward<Container>(container),
                std::move(il));
    }
}

#endif //ifndef COMPRESS__H__
<commit_msg>Adds support for two init lists<commit_after>#ifndef COMPRESS__H__
#define COMPRESS__H__

#include <iterbase.hpp>

#include <utility>
#include <initializer_list>

namespace iter {

    //Forward declarations of Compressed and compress
    template <typename Container, typename Selector>
    class Compressed;

    template <typename Container, typename Selector>
    Compressed<Container, Selector> compress(Container &&, Selector &&);

    template <typename T, typename Selector>
    Compressed<std::initializer_list<T>, Selector> compress(
            std::initializer_list<T> &&, Selector &&);

    template <typename Container, typename T>
    Compressed<Container, std::initializer_list<T>> compress(
            Container &&, std::initializer_list<T> &&);

    template <typename T, typename U>
    Compressed<std::initializer_list<T>, std::initializer_list<U>> compress(
            std::initializer_list<T> &&, std::initializer_list<U> &&);

    template <typename Container, typename Selector>
    class Compressed : public IterBase<Container> {
        private:
            Container & container;
            Selector & selectors;

            // The only thing allowed to directly instantiate an Compressed is
            // the compress function
            friend Compressed compress<Container, Selector>(
                    Container &&, Selector &&);

            template <typename T, typename Sel>
            friend Compressed<std::initializer_list<T>, Sel> compress(
                    std::initializer_list<T> &&, Sel &&);

            template <typename Con, typename T>
            friend Compressed<Con, std::initializer_list<T>> compress(
                    Con &&, std::initializer_list<T> &&);

            template <typename T, typename U>
            friend Compressed<std::initializer_list<T>, std::initializer_list<U>> compress(
                    std::initializer_list<T> &&, std::initializer_list<U> &&);

            using typename IterBase<Container>::contained_iter_type;

            using typename IterBase<Container>::contained_iter_ret;

            // Selector::Iterator type
            using selector_iter_type = decltype(std::begin(selectors));

            // Value constructor for use only in the compress function
            Compressed(Container && container, Selector && selectors) :
                container(container),
                selectors(selectors)
            { }
            Compressed () = delete;
            Compressed & operator=(const Compressed &) = delete;

        public:
            Compressed (const Compressed &) = default;

            class Iterator {
                private:
                    contained_iter_type sub_iter;
                    const contained_iter_type sub_end;

                    selector_iter_type selector_iter;
                    const selector_iter_type selector_end;

                    void increment_iterators() {
                        ++this->sub_iter;
                        ++this->selector_iter;
                    }

                    void skip_failures() {
                        while (this->sub_iter != this->sub_end &&
                                !*this->selector_iter) {
                            this->increment_iterators();
                        }
                    }

                public:
                    Iterator (contained_iter_type cont_iter,
                              contained_iter_type cont_end,
                              selector_iter_type sel_iter,
                              selector_iter_type sel_end) :
                        sub_iter(cont_iter),
                        sub_end(cont_end),
                        selector_iter(sel_iter),
                        selector_end(sel_end)
                    {
                        this->skip_failures();
                    }

                    contained_iter_ret operator*() const {
                        return *this->sub_iter;
                    }

                    Iterator & operator++() {
                        this->increment_iterators();
                        this->skip_failures();
                        return *this;
                    }

                    bool operator!=(const Iterator & other) const {
                        return this->sub_iter != other.sub_iter &&
                            this->selector_iter != other.selector_iter;
                    }
            };

            Iterator begin() const {
                return Iterator(
                        std::begin(this->container), std::end(this->container),
                        std::begin(this->selectors), std::end(this->selectors));
            }

            Iterator end() const {
                return Iterator(
                        std::end(this->container), std::end(this->container),
                        std::end(this->selectors), std::end(this->selectors));
            }

    };

    // Helper function to instantiate an Compressed
    template <typename Container, typename Selector>
    Compressed<Container, Selector> compress(
            Container && container, Selector && selectors) {
        return Compressed<Container, Selector>(
                std::forward<Container>(container),
                std::forward<Selector>(selectors));
    }

    template <typename T, typename Selector>
    Compressed<std::initializer_list<T>, Selector> compress(
            std::initializer_list<T> && data, Selector && selectors) {
        return Compressed<std::initializer_list<T>, Selector>(
                std::move(data),
                std::forward<Selector>(selectors));
    }

    template <typename Container, typename T>
    Compressed<Container, std::initializer_list<T>> compress(
            Container && container, std::initializer_list<T> && selectors) {
        return Compressed<Container, std::initializer_list<T>>(
                std::forward<Container>(container),
                std::move(selectors));
    }

    template <typename T, typename U>
    Compressed<std::initializer_list<T>, std::initializer_list<U>> compress(
            std::initializer_list<T> && data,
            std::initializer_list<U> && selectors) {
        return Compressed<std::initializer_list<T>, std::initializer_list<U>>(
                std::move(data),
                std::move(selectors));
    }
}

#endif //ifndef COMPRESS__H__
<|endoftext|>


<commit_before>#include "DySySim.h"
#include "LibInfoDySySim.h"

#include <UnitTest++/UnitTest++.h>

#include <iostream>

namespace dss = dysysim;
using namespace std;

const double EPS{0.01};

SUITE(DySySim)
{
   TEST(Attenuator)
   {
      cout << "-- Attenuator" << endl;
      dss::Attenuator att{1, 10.0};
      att.input(1.0);
      CHECK_CLOSE(0.1, att.output(), EPS);
      att.input(-1.0);
      CHECK_CLOSE(-0.1, att.output(), EPS);
   }

   TEST(Constant)
   {
      cout << "-- Constant" << endl;
      dss::Constant con{1, 10.0};
      CHECK_CLOSE(10.0, con.output(), EPS);
   }

   TEST(Gain)
   {
      cout << "-- Gain" << endl;
      dss::Gain gain{1, 10.0};
      gain.input(1.0);
      CHECK_CLOSE(10.0, gain.output(), EPS);
      gain.input(-1.0);
      CHECK_CLOSE(-10.0, gain.output(), EPS);
   }

   TEST(Limit)
   {
      cout << "-- Limit" << endl;
      dss::Limit limit{1, -10.0, 20.0};
      limit.input(0.0);
      CHECK_CLOSE(0.0, limit.output(), EPS);
      limit.input(-12.0);
      CHECK_CLOSE(-10.0, limit.output(), EPS);
      limit.input(22.0);
      CHECK_CLOSE(20.0, limit.output(), EPS);
   }

   TEST(OnOff)
   {
      cout << "-- OnOff" << endl;
      dss::OnOff onoff{2, 10, 1.0, 0.0};
      onoff.input(-1.0);
      CHECK_CLOSE(0.0, onoff.output(), EPS);
      onoff.input(0.0);
      CHECK_CLOSE(0.0, onoff.output(), EPS);
      onoff.input(5.0);
      CHECK_CLOSE(0.0, onoff.output(), EPS);
      onoff.input(10.0);
      CHECK_CLOSE(1.0, onoff.output(), EPS);
      onoff.input(20.0);
      CHECK_CLOSE(1.0, onoff.output(), EPS);
   }

   TEST(Time)
   {
      cout << "-- Time" << endl;
      const double delta_t{0.1};
      dss::Time time{1, delta_t};
      CHECK_CLOSE(0.0, time.output(), EPS);
      for (int i = 1; i < 10; ++i) {
         time.next();
         CHECK_CLOSE(i * delta_t, time.output(), EPS);
      }
   }

   TEST(Step)
   {
      const double delta_t{0.1};
      dss::Time time{1, delta_t};
      cout << "-- Step" << endl;
      dss::Step step{2, 0.0, 1.0, 4 * delta_t};
      CHECK_CLOSE(0.0, step.output(), EPS);
      time.next();
      step.next();
      CHECK_CLOSE(0.0, step.output(), EPS);
      time.next();
      step.next();
      CHECK_CLOSE(0.0, step.output(), EPS);
      time.next();
      step.next();
      CHECK_CLOSE(0.0, step.output(), EPS);
      time.next();
      step.next();
      CHECK_CLOSE(1.0, step.output(), EPS);
      time.next();
      step.next();
      CHECK_CLOSE(1.0, step.output(), EPS);
   }

   TEST(Delay)
   {
      const double delta_t{0.1};
      const double delayTime{3 * delta_t};
      dss::Time time{1, delta_t};
      cout << "-- Delay" << endl;
      dss::Step step{2, 0.0, 1.0, 2 * delta_t};
      dss::Delay delay{3, delayTime, 0.0};
      for (int i = 0; i < 10; ++i) {
         auto input = step.output();
         delay.input(input);
         if (i < 5) {
            CHECK_CLOSE(0.0, delay.output(), EPS);
         } else {
            CHECK_CLOSE(1.0, delay.output(), EPS);
         }
         time.next();
         step.next();
      }
   }

   TEST(FirstOrder)
   {
      const double delta_t{0.005};
      const double tau{100 * delta_t};
      const double stp{1.0};
      const double stp_t{5 * delta_t};

      dss::Time time{1, delta_t};
      auto fio_response = [tau, stp_t, stp](double t) {
         return (t < stp_t) ? 0.0 : (stp * (1 - exp(-(t - stp_t) / tau)));
      };

      cout << "-- FirstOrder" << endl;

      dss::Step step{2, 0.0, stp, stp_t};
      dss::FirstOrder fio{3, tau, 0.0};

      while (time.output() < stp_t + 10 * tau) {
         auto input = step.output();
         fio.input(input);
         auto out1 = fio.output();
         auto out2 = fio_response(time.output());
         // std::cout << out1 << " == " << out2 << std::endl;
         if (time.output() < stp_t) {
            CHECK_CLOSE(0.0, out1, EPS);
         } else {
            CHECK_CLOSE(out1, out2, EPS);
         }
         time.next();
         step.next();
      }
   }
}

int main()
{
   cout << "\n== Tests DySySim lib: " << dss::libVersion << " "
        << string(50, '=') << endl
        << endl;

   auto result = UnitTest::RunAllTests();

   cout << endl << string(80, '=') << endl;

   return result;
}
<commit_msg>Added test comparing RCfilter and FirstOrder block<commit_after>#include "DySySim.h"
#include "LibInfoDySySim.h"

#include <UnitTest++/UnitTest++.h>

#include <iostream>

namespace dss = dysysim;
using namespace std;

const double EPS{0.01};

SUITE(DySySim)
{
   TEST(Attenuator)
   {
      cout << "-- Attenuator" << endl;
      dss::Attenuator att{1, 10.0};
      att.input(1.0);
      CHECK_CLOSE(0.1, att.output(), EPS);
      att.input(-1.0);
      CHECK_CLOSE(-0.1, att.output(), EPS);
   }

   TEST(Constant)
   {
      cout << "-- Constant" << endl;
      dss::Constant con{1, 10.0};
      CHECK_CLOSE(10.0, con.output(), EPS);
   }

   TEST(Gain)
   {
      cout << "-- Gain" << endl;
      dss::Gain gain{1, 10.0};
      gain.input(1.0);
      CHECK_CLOSE(10.0, gain.output(), EPS);
      gain.input(-1.0);
      CHECK_CLOSE(-10.0, gain.output(), EPS);
   }

   TEST(Limit)
   {
      cout << "-- Limit" << endl;
      dss::Limit limit{1, -10.0, 20.0};
      limit.input(0.0);
      CHECK_CLOSE(0.0, limit.output(), EPS);
      limit.input(-12.0);
      CHECK_CLOSE(-10.0, limit.output(), EPS);
      limit.input(22.0);
      CHECK_CLOSE(20.0, limit.output(), EPS);
   }

   TEST(OnOff)
   {
      cout << "-- OnOff" << endl;
      dss::OnOff onoff{2, 10, 1.0, 0.0};
      onoff.input(-1.0);
      CHECK_CLOSE(0.0, onoff.output(), EPS);
      onoff.input(0.0);
      CHECK_CLOSE(0.0, onoff.output(), EPS);
      onoff.input(5.0);
      CHECK_CLOSE(0.0, onoff.output(), EPS);
      onoff.input(10.0);
      CHECK_CLOSE(1.0, onoff.output(), EPS);
      onoff.input(20.0);
      CHECK_CLOSE(1.0, onoff.output(), EPS);
   }

   TEST(Time)
   {
      cout << "-- Time" << endl;
      const double delta_t{0.1};
      dss::Time time{1, delta_t};
      CHECK_CLOSE(0.0, time.output(), EPS);
      for (int i = 1; i < 10; ++i) {
         time.next();
         CHECK_CLOSE(i * delta_t, time.output(), EPS);
      }
   }

   TEST(Step)
   {
      const double delta_t{0.1};
      dss::Time time{1, delta_t};
      cout << "-- Step" << endl;
      dss::Step step{2, 0.0, 1.0, 4 * delta_t};
      CHECK_CLOSE(0.0, step.output(), EPS);
      time.next();
      step.next();
      CHECK_CLOSE(0.0, step.output(), EPS);
      time.next();
      step.next();
      CHECK_CLOSE(0.0, step.output(), EPS);
      time.next();
      step.next();
      CHECK_CLOSE(0.0, step.output(), EPS);
      time.next();
      step.next();
      CHECK_CLOSE(1.0, step.output(), EPS);
      time.next();
      step.next();
      CHECK_CLOSE(1.0, step.output(), EPS);
   }

   TEST(Delay)
   {
      const double delta_t{0.1};
      const double delayTime{3 * delta_t};
      dss::Time time{1, delta_t};
      cout << "-- Delay" << endl;
      dss::Step step{2, 0.0, 1.0, 2 * delta_t};
      dss::Delay delay{3, delayTime, 0.0};
      for (int i = 0; i < 10; ++i) {
         auto input = step.output();
         delay.input(input);
         if (i < 5) {
            CHECK_CLOSE(0.0, delay.output(), EPS);
         } else {
            CHECK_CLOSE(1.0, delay.output(), EPS);
         }
         time.next();
         step.next();
      }
   }

   TEST(FirstOrder)
   {
      const double delta_t{0.005};
      const double tau{100 * delta_t};
      const double stp{1.0};
      const double stp_t{5 * delta_t};

      dss::Time time{1, delta_t};
      auto fio_response = [tau, stp_t, stp](double t) {
         return (t < stp_t) ? 0.0 : (stp * (1 - exp(-(t - stp_t) / tau)));
      };

      cout << "-- FirstOrder" << endl;

      dss::Step step{2, 0.0, stp, stp_t};
      dss::FirstOrder fio{3, tau, 0.0};

      while (time.output() < stp_t + 10 * tau) {
         auto input = step.output();
         fio.input(input);
         auto out1 = fio.output();
         auto out2 = fio_response(time.output());
         // std::cout << out1 << " == " << out2 << std::endl;
         if (time.output() < stp_t) {
            CHECK_CLOSE(0.0, out1, EPS);
         } else {
            CHECK_CLOSE(out1, out2, EPS);
         }
         time.next();
         step.next();
      }
   }

   TEST(RC_FirstOrder)
   {
      const double delta_t{0.005};
      const double tau{100 * delta_t};
      const double stp{1.0};
      const double stp_t{5 * delta_t};

      cout << "-- compare RC filter and FirstOrder" << endl;

      dss::Time time{0, delta_t};
      dss::Step step{1, 0.0, stp, stp_t};
      dss::Attenuator att{2, tau};
      dss::Integrator intgt{3, 0.0};

      dss::FirstOrder fio{4, tau, 0.0};

      while (time.output() < stp_t + 10 * tau) {
         auto input = step.output();

         att.input(input);
         att.input(step.output() - intgt.output());
         intgt.input(att.output());

         fio.input(input);

         auto out1 = intgt.output();
         auto out2 = fio.output();
         // std::cout << out1 << " == " << out2 << std::endl;

         CHECK_CLOSE(out1, out2, EPS);

         time.next();
         step.next();
      }
   }
}

int main()
{
   cout << "\n== Tests DySySim lib: " << dss::libVersion << " "
        << string(50, '=') << endl
        << endl;

   auto result = UnitTest::RunAllTests();

   cout << endl << string(80, '=') << endl;

   return result;
}
<|endoftext|>


<commit_before>// -*- mode: C++; c-file-style: "gnu" -*-
// kaddrbook.cpp
// Author: Stefan Taferner <taferner@kde.org>
// This code is under GPL

#include <config.h>
#include <unistd.h>

#include "kaddrbook.h"

#include <kapplication.h>
#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kabc/stdaddressbook.h>
#include <kabc/distributionlist.h>
#include <kabc/vcardconverter.h>
#include <dcopref.h>

#include <qregexp.h>

//-----------------------------------------------------------------------------
void KAddrBookExternal::openEmail( const QString &email, const QString &addr, QWidget *) {
  //QString email = KMMessage::getEmailAddr(addr);
  KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
  KABC::Addressee::List addresseeList = addressBook->findByEmail(email);
  kapp->startServiceByDesktopName( "kaddressbook" );
  DCOPRef call( "kaddressbook", "KAddressBookIface" );
  if( !addresseeList.isEmpty() ) {
    call.send( "showContactEditor(QString)", addresseeList.first().uid() );
  }
  else {
    call.send( "addEmail(QString)", addr );
  }
}

//-----------------------------------------------------------------------------
void KAddrBookExternal::addEmail( const QString& addr, QWidget *parent) {
  QString email;
  QString name;

  KABC::Addressee::parseEmailAddress( addr, name, email );

  KABC::AddressBook *ab = KABC::StdAddressBook::self();

  // force a reload of the address book file so that changes that were made
  // by other programs are loaded
  ab->load();

  KABC::Addressee::List addressees = ab->findByEmail( email );

  if ( addressees.isEmpty() ) {
    KABC::Addressee a;
    a.setNameFromString( name );
    a.insertEmail( email, true );

    if ( !KAddrBookExternal::addAddressee( a ) ) {
      KMessageBox::error( parent, i18n("Cannot save to addressbook.") );
    } else {
      QString text = i18n("<qt>The email address %1 was added to your "
                          "addressbook; you can add more information to this "
                          "entry by opening the addressbook.</qt>").arg( addr );
      KMessageBox::information( parent, text, QString::null, "addedtokabc" );
    }
  } else {
    QString text = i18n("<qt>The email address %1 is already in your "
                        "addressbook.</qt>").arg( addr );
    KMessageBox::information( parent, text, QString::null,
                              "alreadyInAddressBook" );
  }
}

void KAddrBookExternal::openAddressBook(QWidget *) {
  kapp->startServiceByDesktopName( "kaddressbook" );
}

void KAddrBookExternal::addNewAddressee( QWidget* )
{
  kapp->startServiceByDesktopName("kaddressbook");
  sleep(2);
  DCOPRef call("kaddressbook", "KAddressBookIface");
  call.send("newContact()");
}

bool KAddrBookExternal::addVCard( const KABC::Addressee& addressee, QWidget *parent )
{
  KABC::AddressBook *ab = KABC::StdAddressBook::self();
  bool inserted = false;

  KABC::Addressee::List addressees =
      ab->findByEmail( addressee.preferredEmail() );

  if ( addressees.isEmpty() ) {
    if ( !KAddrBookExternal::addAddressee( addressee ) ) {
      KMessageBox::error( parent, i18n("Cannot save to addressbook.") );
      inserted = false;
    } else {
      QString text = i18n("The VCard was added to your addressbook; "
                          "you can add more information to this "
                          "entry by opening the addressbook.");
      KMessageBox::information( parent, text, QString::null, "addedtokabc" );
      inserted = true;
    }
  } else {
    QString text = i18n("The VCard's primary email address is already in "
                        "your addressbook; however, you may save the VCard "
                        "into a file and import it into the addressbook "
                        "manually.");
    KMessageBox::information( parent, text );
    inserted = true;
  }

  return inserted;
}

bool KAddrBookExternal::addAddressee( const KABC::Addressee& addressee )
{
  KABC::AddressBook *ab = KABC::StdAddressBook::self();
  KABC::Ticket *t = ab->requestSaveTicket();
  bool saved = false;
  if ( t ) {
    ab->insertAddressee( addressee );
    saved = ab->save( t );
    if ( !saved )
      ab->releaseSaveTicket( t );
  }
  return saved;
}

QString KAddrBookExternal::expandDistributionList( const QString& listName )
{
  if ( listName.isEmpty() )
    return QString::null;

  const QString lowerListName = listName.lower();
  KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
  KABC::DistributionListManager manager( addressBook );
  manager.load();
  const QStringList listNames = manager.listNames();

  for ( QStringList::ConstIterator it = listNames.begin();
        it != listNames.end(); ++it) {
    if ( (*it).lower() == lowerListName ) {
      const QStringList addressList = manager.list( *it )->emails();
      return addressList.join( ", " );
    }
  }
  return QString::null;
}
<commit_msg>fixes bug #87233 loads kaddressbook first before you can do a "open in addressbook" in kmail within kontact<commit_after>// -*- mode: C++; c-file-style: "gnu" -*-
// kaddrbook.cpp
// Author: Stefan Taferner <taferner@kde.org>
// This code is under GPL

#include <config.h>
#include <unistd.h>

#include "kaddrbook.h"

#include <kapplication.h>
#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kabc/stdaddressbook.h>
#include <kabc/distributionlist.h>
#include <kabc/vcardconverter.h>
#include <dcopref.h>
#include <dcopclient.h>

#include <qregexp.h>

//-----------------------------------------------------------------------------
void KAddrBookExternal::openEmail( const QString &email, const QString &addr, QWidget *) {
  //QString email = KMMessage::getEmailAddr(addr);
  KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
  KABC::Addressee::List addresseeList = addressBook->findByEmail(email);
  if ( kapp->dcopClient()->isApplicationRegistered( "kaddressbook" ) ){
    //make sure kaddressbook is loaded, otherwise showContactEditor
    //won't work as desired, see bug #87233
    DCOPRef call ( "kaddressbook", "kaddressbook" );
    call.send( "newInstance()" );
  }
  else
    kapp->startServiceByDesktopName( "kaddressbook" );

  DCOPRef call( "kaddressbook", "KAddressBookIface" );
  if( !addresseeList.isEmpty() ) {
    call.send( "showContactEditor(QString)", addresseeList.first().uid() );
  }
  else {
    call.send( "addEmail(QString)", addr );
  }
}

//-----------------------------------------------------------------------------
void KAddrBookExternal::addEmail( const QString& addr, QWidget *parent) {
  QString email;
  QString name;

  KABC::Addressee::parseEmailAddress( addr, name, email );

  KABC::AddressBook *ab = KABC::StdAddressBook::self();

  // force a reload of the address book file so that changes that were made
  // by other programs are loaded
  ab->load();

  KABC::Addressee::List addressees = ab->findByEmail( email );

  if ( addressees.isEmpty() ) {
    KABC::Addressee a;
    a.setNameFromString( name );
    a.insertEmail( email, true );

    if ( !KAddrBookExternal::addAddressee( a ) ) {
      KMessageBox::error( parent, i18n("Cannot save to addressbook.") );
    } else {
      QString text = i18n("<qt>The email address %1 was added to your "
                          "addressbook; you can add more information to this "
                          "entry by opening the addressbook.</qt>").arg( addr );
      KMessageBox::information( parent, text, QString::null, "addedtokabc" );
    }
  } else {
    QString text = i18n("<qt>The email address %1 is already in your "
                        "addressbook.</qt>").arg( addr );
    KMessageBox::information( parent, text, QString::null,
                              "alreadyInAddressBook" );
  }
}

void KAddrBookExternal::openAddressBook(QWidget *) {
  kapp->startServiceByDesktopName( "kaddressbook" );
}

void KAddrBookExternal::addNewAddressee( QWidget* )
{
  kapp->startServiceByDesktopName("kaddressbook");
  sleep(2);
  DCOPRef call("kaddressbook", "KAddressBookIface");
  call.send("newContact()");
}

bool KAddrBookExternal::addVCard( const KABC::Addressee& addressee, QWidget *parent )
{
  KABC::AddressBook *ab = KABC::StdAddressBook::self();
  bool inserted = false;

  KABC::Addressee::List addressees =
      ab->findByEmail( addressee.preferredEmail() );

  if ( addressees.isEmpty() ) {
    if ( !KAddrBookExternal::addAddressee( addressee ) ) {
      KMessageBox::error( parent, i18n("Cannot save to addressbook.") );
      inserted = false;
    } else {
      QString text = i18n("The VCard was added to your addressbook; "
                          "you can add more information to this "
                          "entry by opening the addressbook.");
      KMessageBox::information( parent, text, QString::null, "addedtokabc" );
      inserted = true;
    }
  } else {
    QString text = i18n("The VCard's primary email address is already in "
                        "your addressbook; however, you may save the VCard "
                        "into a file and import it into the addressbook "
                        "manually.");
    KMessageBox::information( parent, text );
    inserted = true;
  }

  return inserted;
}

bool KAddrBookExternal::addAddressee( const KABC::Addressee& addressee )
{
  KABC::AddressBook *ab = KABC::StdAddressBook::self();
  KABC::Ticket *t = ab->requestSaveTicket();
  bool saved = false;
  if ( t ) {
    ab->insertAddressee( addressee );
    saved = ab->save( t );
    if ( !saved )
      ab->releaseSaveTicket( t );
  }
  return saved;
}

QString KAddrBookExternal::expandDistributionList( const QString& listName )
{
  if ( listName.isEmpty() )
    return QString::null;

  const QString lowerListName = listName.lower();
  KABC::AddressBook *addressBook = KABC::StdAddressBook::self();
  KABC::DistributionListManager manager( addressBook );
  manager.load();
  const QStringList listNames = manager.listNames();

  for ( QStringList::ConstIterator it = listNames.begin();
        it != listNames.end(); ++it) {
    if ( (*it).lower() == lowerListName ) {
      const QStringList addressList = manager.list( *it )->emails();
      return addressList.join( ", " );
    }
  }
  return QString::null;
}
<|endoftext|>


<commit_before># // sets delimiter, until which the serial is going to read in order to retrieve messages
#include "client.hpp"

const char Client::delimiter{'~'}; // sets delimiter, until which the serial is going to read in order to retrieve messages

Client::Client(std::string userName, int baud) : // constructor
  serial("/dev/ttyACM0", baud),   // initializes serial-port
  userName(userName)      // sets client's userName
{
  // std::cout << "finished constructing client '" << userName << std::endl;
}

void Client::setUsername(std::string name) {  // sets client's userName
  sendExpression("server", "CHANGENAME "+name+" "+userName);
  userName = name;
}

// retrieves the servers on the network by making a ping request and retrieving the server response
std::string Client::getServers() {
  std::string servers;
  // std::cout << "Attempting to get servers" << std::endl;
  // std::cout << "Sending Ping" << std::endl;
  // for (int i{0}; i < 3; ++i) {
  //   sendExpression("server","PING");
  //   serial.readUntil(delimiter);
  // }

  sendExpression("server","PING");
  Envelope pong;
  try {
    pong = retrieveEnvelope();
  }
  catch (...) {
    throw;
  }
  // std::cout << "received server pong envelope '" << pong.toString() << "'" << std::endl;
  try {
    servers += pong.getServer()+"\n";
  }
  catch (...) {
    throw;
  }

    // std::cout << "returning server set" << std::endl;
  return servers;
}

// connects to the server by sending an expressing and changes the serverName associated with the client
void Client::connectServer(std::string server) {
    // std::cout << "Sending a request to '" << server << "' for connection" << std::endl;
  sendExpression("server","CONNECT "+userName);
  serverName = server;
}

void Client::disconnectServer() {
  sendExpression("server", "DISCONNECT "+serverName+" "+userName);
  serverName = "";
}

// std::set<std::string> Client::getChannels() {
//   std::cout << "Attempting to get channel listing" << std::endl;
//   std::cout << "Sending a server request for getchannels" << std::endl;
//   sendServerRequest("GETCHANNELS");
//   std::cout << "server request for channel listing sent" << std::endl;

//   std::set<std::string> channels;
//   std::cout << "getting channel listing response..." << std::endl;
//   std::string response(retrieveResponse());
//   std::cout << "received channel listing response '" << response << "'" << std::endl;

//   std::cout << "splitting channel listing by spaces" << std::endl;
//   boost::split(channels, response, boost::is_any_of(" "));
//   std::cout << "split done" << std::endl;

//   std::cout << "returning channel set" << std::endl;
//   return channels;
// }

// adds a channel to the set of channels
void Client::joinChannel(std::string channel) {
    // std::cout << "Attempting to join a channel '" << channel << "'" << std::endl;
  sendExpression("server", "JOINCHANNEL "+channel+" "+userName);
  channels.insert(channel);
}

void Client::createChannel(std::string channel) {
  //assumes success
  sendExpression("server", "CREATECHANNEL "+channel+" "+userName);
  channels.insert(channel);
}

// builds up an Envelope using the parameters and calls sendEnvelope()
void Client::sendExpression(std::string destination, std::string expression) {
  // if (destination == "server") {
  //   std::cout << "sending a server request" << std::endl;
  //   sendServerRequest(expression);
  // }
  // else {
  //   std::cout << "sending a channel request" << std::endl;
  //   sendChannelRequest(expression);
  // }
  sendEnvelope(Envelope(serverName, destination, userName, expression));
}

std::string Client::retrieveResponse() {
    // std::cout << "Attempting to retrieve a response envelope" << std::endl;
  Envelope response(retrieveEnvelope());
      // std::cout << "Response envelope received......" << std::endl;
    // std::cout << "RELEVANT response envelope received" << std::endl;

    // std::cout << "converting envelope to string and returning" << std::endl;
  return response.getExpression();
}
// calls retrieveEnvelope() to retrieve Enveloped from the serial until the Envelope's destiantion matches that of the client, then returns that Envelope's expression
std::string Client::retrieveResponse(std::string destinationToListenFor) {
    // std::cout << "Attempting to retrieve a response envelope" << std::endl;
  Envelope response(retrieveEnvelope());
  while (response.getDestination() != destinationToListenFor) {
      // std::cout << "Response envelope received......" << std::endl;
    response = retrieveEnvelope();
  }
    // std::cout << "RELEVANT response envelope received" << std::endl;

    // std::cout << "converting envelope to string and returning" << std::endl;
  return response.getExpression();
}

// void Client::sendChannelRequest(std::string command) {
//   sendEnvelope(Envelope(serverName, channelName, userName, command));
// }

// void Client::sendServerRequest(std::string command) {
//   std::cout << "Sending server request for command '" << command << "'" << std::endl;
//   sendEnvelope(Envelope(serverName, "server", userName, command));
// }

// writes envelope in  string fromat alongside delimiter to serial
void Client::sendEnvelope(Envelope env) {
    // std::cout << "Attempting to send envelope '" << env.toString() << "'" << std::endl;
  serial.write(env.toString()+delimiter);
}

// reads from serial until the delimiter, and returns an Envelope built from the retrieved string
Envelope Client::retrieveEnvelope() {
  Envelope response;
  while (response.getDestination() != userName &&
         channels.count(response.getDestination()) == 0) {

    // std::cout << "Attempting to retrieve an envelope" << std::endl;

    // std::cout << "  retrieved string: '" << resp << "'" << std::endl;
    // std::cout << "  Attempting to convert to envelope" << std::endl;
    response = Envelope(serial.readUntil(delimiter));
    // std::cout << "  Conversion complete" << std::endl;
      // std::cout << "Response envelope received......" << std::endl;
  }
  return response;
}
<commit_msg>pewkjog<commit_after># // sets delimiter, until which the serial is going to read in order to retrieve messages
#include "client.hpp"

const char Client::delimiter{'~'}; // sets delimiter, until which the serial is going to read in order to retrieve messages

Client::Client(std::string userName, int baud) : // constructor
  serial("/dev/ttyACM0", baud),   // initializes serial-port
  userName(userName)      // sets client's userName
{
  // std::cout << "finished constructing client '" << userName << std::endl;
}

void Client::setUsername(std::string name) {  // sets client's userName
  sendExpression("server", "CHANGENAME "+name+" "+userName);
  userName = name;
}

// retrieves the servers on the network by making a ping request and retrieving the server response
std::string Client::getServers() {
  std::string servers;
  // std::cout << "Attempting to get servers" << std::endl;
  // std::cout << "Sending Ping" << std::endl;
  // for (int i{0}; i < 3; ++i) {
  //   sendExpression("server","PING");
  //   serial.readUntil(delimiter);
  // }

  sendExpression("server","PING");
  Envelope pong;
  try {
    std::cout << "about to get ping response" << std::endl;
    pong = retrieveEnvelope();
  }
  catch (...) {
    std::cout << "failed to get ping response, threw exception" << std::endl;
    throw;
  }
  // std::cout << "received server pong envelope '" << pong.toString() << "'" << std::endl;
  try {
    std::cout << "About to try pong.getServer()" << std::endl;
    servers += pong.getServer()+"\n";
  }
  catch (...) {
    std::cout << "faild to pong.getServer() throwing exception" << std::endl;
    throw;
  }
  std::cout << "everything went fin in getServers()" << std::endl;
    // std::cout << "returning server set" << std::endl;
  return servers;
}

// connects to the server by sending an expressing and changes the serverName associated with the client
void Client::connectServer(std::string server) {
    // std::cout << "Sending a request to '" << server << "' for connection" << std::endl;
  sendExpression("server","CONNECT "+userName);
  serverName = server;
}

void Client::disconnectServer() {
  sendExpression("server", "DISCONNECT "+serverName+" "+userName);
  serverName = "";
}

// std::set<std::string> Client::getChannels() {
//   std::cout << "Attempting to get channel listing" << std::endl;
//   std::cout << "Sending a server request for getchannels" << std::endl;
//   sendServerRequest("GETCHANNELS");
//   std::cout << "server request for channel listing sent" << std::endl;

//   std::set<std::string> channels;
//   std::cout << "getting channel listing response..." << std::endl;
//   std::string response(retrieveResponse());
//   std::cout << "received channel listing response '" << response << "'" << std::endl;

//   std::cout << "splitting channel listing by spaces" << std::endl;
//   boost::split(channels, response, boost::is_any_of(" "));
//   std::cout << "split done" << std::endl;

//   std::cout << "returning channel set" << std::endl;
//   return channels;
// }

// adds a channel to the set of channels
void Client::joinChannel(std::string channel) {
    // std::cout << "Attempting to join a channel '" << channel << "'" << std::endl;
  sendExpression("server", "JOINCHANNEL "+channel+" "+userName);
  channels.insert(channel);
}

void Client::createChannel(std::string channel) {
  //assumes success
  sendExpression("server", "CREATECHANNEL "+channel+" "+userName);
  channels.insert(channel);
}

// builds up an Envelope using the parameters and calls sendEnvelope()
void Client::sendExpression(std::string destination, std::string expression) {
  // if (destination == "server") {
  //   std::cout << "sending a server request" << std::endl;
  //   sendServerRequest(expression);
  // }
  // else {
  //   std::cout << "sending a channel request" << std::endl;
  //   sendChannelRequest(expression);
  // }
  sendEnvelope(Envelope(serverName, destination, userName, expression));
}

std::string Client::retrieveResponse() {
    // std::cout << "Attempting to retrieve a response envelope" << std::endl;
  Envelope response(retrieveEnvelope());
      // std::cout << "Response envelope received......" << std::endl;
    // std::cout << "RELEVANT response envelope received" << std::endl;

    // std::cout << "converting envelope to string and returning" << std::endl;
  return response.getExpression();
}
// calls retrieveEnvelope() to retrieve Enveloped from the serial until the Envelope's destiantion matches that of the client, then returns that Envelope's expression
std::string Client::retrieveResponse(std::string destinationToListenFor) {
    // std::cout << "Attempting to retrieve a response envelope" << std::endl;
  Envelope response(retrieveEnvelope());
  while (response.getDestination() != destinationToListenFor) {
      // std::cout << "Response envelope received......" << std::endl;
    response = retrieveEnvelope();
  }
    // std::cout << "RELEVANT response envelope received" << std::endl;

    // std::cout << "converting envelope to string and returning" << std::endl;
  return response.getExpression();
}

// void Client::sendChannelRequest(std::string command) {
//   sendEnvelope(Envelope(serverName, channelName, userName, command));
// }

// void Client::sendServerRequest(std::string command) {
//   std::cout << "Sending server request for command '" << command << "'" << std::endl;
//   sendEnvelope(Envelope(serverName, "server", userName, command));
// }

// writes envelope in  string fromat alongside delimiter to serial
void Client::sendEnvelope(Envelope env) {
    // std::cout << "Attempting to send envelope '" << env.toString() << "'" << std::endl;
  serial.write(env.toString()+delimiter);
}

// reads from serial until the delimiter, and returns an Envelope built from the retrieved string
Envelope Client::retrieveEnvelope() {
  Envelope response;
  while (response.getDestination() != userName &&
         channels.count(response.getDestination()) == 0) {

    // std::cout << "Attempting to retrieve an envelope" << std::endl;

    // std::cout << "  retrieved string: '" << resp << "'" << std::endl;
    // std::cout << "  Attempting to convert to envelope" << std::endl;
    response = Envelope(serial.readUntil(delimiter));
    // std::cout << "  Conversion complete" << std::endl;
      // std::cout << "Response envelope received......" << std::endl;
  }
  return response;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: unocontrolbase.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 12:51:57 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _TOOLKIT_AWT_UNOCONTROLBASE_HXX_
#define _TOOLKIT_AWT_UNOCONTROLBASE_HXX_

#ifndef _COM_SUN_STAR_AWT_SIZE_HPP_
#include <com/sun/star/awt/Size.hpp>
#endif

#include <toolkit/controls/unocontrol.hxx>

//  ----------------------------------------------------
//  class UnoControlBase
//  ----------------------------------------------------

class UnoControlBase : public UnoControl
{
protected:
    sal_Bool                    ImplHasProperty( sal_uInt16 nProp );
    sal_Bool                    ImplHasProperty( const ::rtl::OUString& aPropertyName );
    void                        ImplSetPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue, sal_Bool bUpdateThis );
    ::com::sun::star::uno::Any  ImplGetPropertyValue( const ::rtl::OUString& aPropertyName );

    sal_Bool        ImplGetPropertyValue_BOOL( sal_uInt16 nProp );
    sal_Int16       ImplGetPropertyValue_INT16( sal_uInt16 nProp );
    sal_uInt16      ImplGetPropertyValue_UINT16( sal_uInt16 nProp );
    sal_Int32       ImplGetPropertyValue_INT32( sal_uInt16 nProp );
    sal_uInt32      ImplGetPropertyValue_UINT32( sal_uInt16 nProp );
    double          ImplGetPropertyValue_DOUBLE( sal_uInt16 nProp );
    ::rtl::OUString ImplGetPropertyValue_UString( sal_uInt16 nProp );

    // XLayoutConstrains (nur wenn das Control es unterstuetzt!)
    ::com::sun::star::awt::Size Impl_getMinimumSize();
    ::com::sun::star::awt::Size Impl_getPreferredSize();
    ::com::sun::star::awt::Size Impl_calcAdjustedSize( const ::com::sun::star::awt::Size& rNewSize );

    // XTextLayoutConstrains (nur wenn das Control es unterstuetzt!)
    ::com::sun::star::awt::Size Impl_getMinimumSize( sal_Int16 nCols, sal_Int16 nLines );
    void                        Impl_getColumnsAndLines( sal_Int16& nCols, sal_Int16& nLines );
};

#endif // _TOOLKIT_AWT_UNOCONTROLBASE_HXX_

<commit_msg>INTEGRATION: CWS fmtfield_SRC680 (1.3.200); FILE MERGED 2007/02/12 14:26:22 fs 1.3.200.1: #i74443# +ImplSetPropertyValues<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: unocontrolbase.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: kz $ $Date: 2007-02-14 15:33:19 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _TOOLKIT_AWT_UNOCONTROLBASE_HXX_
#define _TOOLKIT_AWT_UNOCONTROLBASE_HXX_

#ifndef _COM_SUN_STAR_AWT_SIZE_HPP_
#include <com/sun/star/awt/Size.hpp>
#endif

#include <toolkit/controls/unocontrol.hxx>

//  ----------------------------------------------------
//  class UnoControlBase
//  ----------------------------------------------------

class UnoControlBase : public UnoControl
{
protected:
    sal_Bool                    ImplHasProperty( sal_uInt16 nProp );
    sal_Bool                    ImplHasProperty( const ::rtl::OUString& aPropertyName );
    void                        ImplSetPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue, sal_Bool bUpdateThis );
    void                        ImplSetPropertyValues( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyNames, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aValues, sal_Bool bUpdateThis );
    ::com::sun::star::uno::Any  ImplGetPropertyValue( const ::rtl::OUString& aPropertyName );

    sal_Bool        ImplGetPropertyValue_BOOL( sal_uInt16 nProp );
    sal_Int16       ImplGetPropertyValue_INT16( sal_uInt16 nProp );
    sal_uInt16      ImplGetPropertyValue_UINT16( sal_uInt16 nProp );
    sal_Int32       ImplGetPropertyValue_INT32( sal_uInt16 nProp );
    sal_uInt32      ImplGetPropertyValue_UINT32( sal_uInt16 nProp );
    double          ImplGetPropertyValue_DOUBLE( sal_uInt16 nProp );
    ::rtl::OUString ImplGetPropertyValue_UString( sal_uInt16 nProp );

    // XLayoutConstrains (nur wenn das Control es unterstuetzt!)
    ::com::sun::star::awt::Size Impl_getMinimumSize();
    ::com::sun::star::awt::Size Impl_getPreferredSize();
    ::com::sun::star::awt::Size Impl_calcAdjustedSize( const ::com::sun::star::awt::Size& rNewSize );

    // XTextLayoutConstrains (nur wenn das Control es unterstuetzt!)
    ::com::sun::star::awt::Size Impl_getMinimumSize( sal_Int16 nCols, sal_Int16 nLines );
    void                        Impl_getColumnsAndLines( sal_Int16& nCols, sal_Int16& nLines );
};

#endif // _TOOLKIT_AWT_UNOCONTROLBASE_HXX_

<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 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 "webkit/tools/test_shell/webwidget_host.h"

#include <cairo/cairo.h>
#include <gtk/gtk.h>

#include "base/logging.h"
#include "base/gfx/platform_canvas_linux.h"
#include "base/gfx/platform_device_linux.h"
#include "base/gfx/bitmap_platform_device_linux.h"
#include "webkit/glue/webinputevent.h"
#include "webkit/glue/webwidget.h"

namespace {

// -----------------------------------------------------------------------------
// Callback functions to proxy to host...

gboolean ConfigureEvent(GtkWidget* widget, GdkEventConfigure* config,
                        WebWidgetHost* host) {
  host->Resize(gfx::Size(config->width, config->height));
  return FALSE;
}

gboolean ExposeEvent(GtkWidget* widget, GdkEventExpose* expose,
                     WebWidgetHost* host) {
  gfx::Rect rect(expose->area);
  host->UpdatePaintRect(rect);
  host->Paint();
  return FALSE;
}

gboolean DestroyEvent(GtkWidget* widget, GdkEvent* event,
                      WebWidgetHost* host) {
  host->WindowDestroyed();
  return FALSE;
}

gboolean KeyPressReleaseEvent(GtkWidget* widget, GdkEventKey* event,
                              WebWidgetHost* host) {
  WebKeyboardEvent wke(event);
  host->webwidget()->HandleInputEvent(&wke);

  // The WebKeyboardEvent model, when holding down a key, is:
  //   KEY_DOWN, CHAR, (repeated CHAR as key repeats,) KEY_UP
  // The GDK model for the same sequence is just:
  //   KEY_PRESS, (repeated KEY_PRESS as key repeats,) KEY_RELEASE
  // So we must simulate a CHAR event for every key press.
  if (event->type == GDK_KEY_PRESS) {
    wke.type = WebKeyboardEvent::CHAR;
    host->webwidget()->HandleInputEvent(&wke);
  }

  return FALSE;
}

// This signal is called when arrow keys or tab is pressed.  If we return true,
// we prevent focus from being moved to another widget.  If we want to allow
// focus to be moved outside of web contents, we need to implement
// WebViewDelegate::TakeFocus in the test webview delegate.
gboolean FocusMove(GtkWidget* widget, GdkEventFocus* focus,
                   WebWidgetHost* host) {
  return TRUE;
}

gboolean FocusIn(GtkWidget* widget, GdkEventFocus* focus,
                 WebWidgetHost* host) {
  host->webwidget()->SetFocus(true);
  return FALSE;
}

gboolean FocusOut(GtkWidget* widget, GdkEventFocus* focus,
                  WebWidgetHost* host) {
  host->webwidget()->SetFocus(false);
  return FALSE;
}

gboolean ButtonPressReleaseEvent(GtkWidget* widget, GdkEventButton* event,
                                 WebWidgetHost* host) {
  WebMouseEvent wme(event);
  host->webwidget()->HandleInputEvent(&wme);
  return FALSE;
}

gboolean MouseMoveEvent(GtkWidget* widget, GdkEventMotion* event,
                        WebWidgetHost* host) {
  WebMouseEvent wme(event);
  host->webwidget()->HandleInputEvent(&wme);
  return FALSE;
}

gboolean MouseScrollEvent(GtkWidget* widget, GdkEventScroll* event,
                          WebWidgetHost* host) {
  WebMouseWheelEvent wmwe(event);
  host->webwidget()->HandleInputEvent(&wmwe);
  return FALSE;
}

}  // anonymous namespace

// -----------------------------------------------------------------------------

gfx::WindowHandle WebWidgetHost::CreateWindow(gfx::WindowHandle box,
                                              void* host) {
  GtkWidget* widget = gtk_drawing_area_new();
  gtk_box_pack_start(GTK_BOX(box), widget, TRUE, TRUE, 0);

  gtk_widget_add_events(widget, GDK_EXPOSURE_MASK |
                                GDK_POINTER_MOTION_MASK |
                                GDK_BUTTON_PRESS_MASK |
                                GDK_BUTTON_RELEASE_MASK |
                                GDK_KEY_PRESS_MASK |
                                GDK_KEY_RELEASE_MASK);
  GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS);
  g_signal_connect(widget, "configure-event", G_CALLBACK(ConfigureEvent), host);
  g_signal_connect(widget, "expose-event", G_CALLBACK(ExposeEvent), host);
  g_signal_connect(widget, "destroy-event", G_CALLBACK(DestroyEvent), host);
  g_signal_connect(widget, "key-press-event", G_CALLBACK(KeyPressReleaseEvent),
                   host);
  g_signal_connect(widget, "key-release-event",
                   G_CALLBACK(KeyPressReleaseEvent), host);
  g_signal_connect(widget, "focus", G_CALLBACK(FocusMove), host);
  g_signal_connect(widget, "focus-in-event", G_CALLBACK(FocusIn), host);
  g_signal_connect(widget, "focus-out-event", G_CALLBACK(FocusOut), host);
  g_signal_connect(widget, "button-press-event",
                   G_CALLBACK(ButtonPressReleaseEvent), host);
  g_signal_connect(widget, "button-release-event",
                   G_CALLBACK(ButtonPressReleaseEvent), host);
  g_signal_connect(widget, "motion-notify-event", G_CALLBACK(MouseMoveEvent),
                   host);
  g_signal_connect(widget, "scroll-event", G_CALLBACK(MouseScrollEvent),
                   host);

  return widget;
}

WebWidgetHost* WebWidgetHost::Create(gfx::WindowHandle box,
                                     WebWidgetDelegate* delegate) {
  WebWidgetHost* host = new WebWidgetHost();
  host->view_ = CreateWindow(box, host);
  host->webwidget_ = WebWidget::Create(delegate);

  return host;
}

void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) {
  paint_rect_ = paint_rect_.Union(rect);
}

void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) {
  DLOG_IF(WARNING, painting_) << "unexpected invalidation while painting";

  UpdatePaintRect(damaged_rect);

  gtk_widget_queue_draw_area(GTK_WIDGET(view_), damaged_rect.x(),
      damaged_rect.y(), damaged_rect.width(), damaged_rect.height());
}

void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) {
  // This is used for optimizing painting when the renderer is scrolled. We're
  // currently not doing any optimizations so just invalidate the region.
  DidInvalidateRect(clip_rect);
}

WebWidgetHost* FromWindow(gfx::WindowHandle view) {
  const gpointer p = g_object_get_data(G_OBJECT(view), "webwidgethost");
  return (WebWidgetHost* ) p;
}

WebWidgetHost::WebWidgetHost()
    : view_(NULL),
      webwidget_(NULL),
      scroll_dx_(0),
      scroll_dy_(0),
      track_mouse_leave_(false) {
  set_painting(false);
}

WebWidgetHost::~WebWidgetHost() {
  webwidget_->Close();
  webwidget_->Release();
}

void WebWidgetHost::Resize(const gfx::Size &newsize) {
  // The pixel buffer backing us is now the wrong size
  canvas_.reset();

  webwidget_->Resize(gfx::Size(newsize.width(), newsize.height()));
}

void WebWidgetHost::Paint() {
  int width = view_->allocation.width;
  int height = view_->allocation.height;
  gfx::Rect client_rect(width, height);

  // Allocate a canvas if necessary
  if (!canvas_.get()) {
    ResetScrollRect();
    paint_rect_ = client_rect;
    canvas_.reset(new gfx::PlatformCanvas(width, height, true));
    if (!canvas_.get()) {
      // memory allocation failed, we can't paint.
      LOG(ERROR) << "Failed to allocate memory for " << width << "x" << height;
      return;
    }
  }

  // This may result in more invalidation
  webwidget_->Layout();

  // Paint the canvas if necessary.  Allow painting to generate extra rects the
  // first time we call it.  This is necessary because some WebCore rendering
  // objects update their layout only when painted.
  for (int i = 0; i < 2; ++i) {
    paint_rect_ = client_rect.Intersect(paint_rect_);
    if (!paint_rect_.IsEmpty()) {
      gfx::Rect rect(paint_rect_);
      paint_rect_ = gfx::Rect();

      DLOG_IF(WARNING, i == 1) << "painting caused additional invalidations";
      PaintRect(rect);
    }
  }
  DCHECK(paint_rect_.IsEmpty());

  // BitBlit to the X server
  gfx::PlatformDeviceLinux &platdev = canvas_->getTopPlatformDevice();
  gfx::BitmapPlatformDeviceLinux* const bitdev =
    static_cast<gfx::BitmapPlatformDeviceLinux* >(&platdev);

  cairo_t* cairo_drawable = gdk_cairo_create(view_->window);
  cairo_set_source_surface(cairo_drawable, bitdev->surface(), 0, 0);
  cairo_paint(cairo_drawable);
  cairo_destroy(cairo_drawable);
}

void WebWidgetHost::ResetScrollRect() {
  // This method is only needed for optimized scroll painting, which we don't
  // care about in the test shell, yet.
}

void WebWidgetHost::PaintRect(const gfx::Rect& rect) {
  set_painting(true);
  webwidget_->Paint(canvas_.get(), rect);
  set_painting(false);
}

// -----------------------------------------------------------------------------
// This is called when the GTK window is destroyed. In the Windows code this
// deletes this object. Since it's only test_shell it probably doesn't matter
// that much.
// -----------------------------------------------------------------------------
void WebWidgetHost::WindowDestroyed() {
  delete this;
}
<commit_msg>Fix infinite paint loop on Linux.<commit_after>// Copyright (c) 2006-2008 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 "webkit/tools/test_shell/webwidget_host.h"

#include <cairo/cairo.h>
#include <gtk/gtk.h>

#include "base/logging.h"
#include "base/gfx/platform_canvas_linux.h"
#include "base/gfx/platform_device_linux.h"
#include "base/gfx/bitmap_platform_device_linux.h"
#include "webkit/glue/webinputevent.h"
#include "webkit/glue/webwidget.h"

namespace {

// In response to an invalidation, we call into WebKit to do layout. On
// Windows, WM_PAINT is a virtual message so any extra invalidates that come up
// while it's doing layout are implicitly swallowed as soon as we actually do
// drawing via BeginPaint.
//
// Though GTK does know how to collapse multiple paint requests, it won't erase
// paint requests from the future when we start drawing.  To avoid an infinite
// cycle of repaints, we track whether we're currently handling a redraw, and
// during that if we get told by WebKit that a region has become invalid, we
// still add that region to the local dirty rect but *don't* enqueue yet
// another "do a paint" message.
bool handling_expose = false;

// -----------------------------------------------------------------------------
// Callback functions to proxy to host...

gboolean ConfigureEvent(GtkWidget* widget, GdkEventConfigure* config,
                        WebWidgetHost* host) {
  host->Resize(gfx::Size(config->width, config->height));
  return FALSE;
}

gboolean ExposeEvent(GtkWidget* widget, GdkEventExpose* expose,
                     WebWidgetHost* host) {
  // See comments above about what handling_expose is for.
  handling_expose = true;
  gfx::Rect rect(expose->area);
  host->UpdatePaintRect(rect);
  host->Paint();
  handling_expose = false;
  return FALSE;
}

gboolean DestroyEvent(GtkWidget* widget, GdkEvent* event,
                      WebWidgetHost* host) {
  host->WindowDestroyed();
  return FALSE;
}

gboolean KeyPressReleaseEvent(GtkWidget* widget, GdkEventKey* event,
                              WebWidgetHost* host) {
  WebKeyboardEvent wke(event);
  host->webwidget()->HandleInputEvent(&wke);

  // The WebKeyboardEvent model, when holding down a key, is:
  //   KEY_DOWN, CHAR, (repeated CHAR as key repeats,) KEY_UP
  // The GDK model for the same sequence is just:
  //   KEY_PRESS, (repeated KEY_PRESS as key repeats,) KEY_RELEASE
  // So we must simulate a CHAR event for every key press.
  if (event->type == GDK_KEY_PRESS) {
    wke.type = WebKeyboardEvent::CHAR;
    host->webwidget()->HandleInputEvent(&wke);
  }

  return FALSE;
}

// This signal is called when arrow keys or tab is pressed.  If we return true,
// we prevent focus from being moved to another widget.  If we want to allow
// focus to be moved outside of web contents, we need to implement
// WebViewDelegate::TakeFocus in the test webview delegate.
gboolean FocusMove(GtkWidget* widget, GdkEventFocus* focus,
                   WebWidgetHost* host) {
  return TRUE;
}

gboolean FocusIn(GtkWidget* widget, GdkEventFocus* focus,
                 WebWidgetHost* host) {
  host->webwidget()->SetFocus(true);
  return FALSE;
}

gboolean FocusOut(GtkWidget* widget, GdkEventFocus* focus,
                  WebWidgetHost* host) {
  host->webwidget()->SetFocus(false);
  return FALSE;
}

gboolean ButtonPressReleaseEvent(GtkWidget* widget, GdkEventButton* event,
                                 WebWidgetHost* host) {
  WebMouseEvent wme(event);
  host->webwidget()->HandleInputEvent(&wme);
  return FALSE;
}

gboolean MouseMoveEvent(GtkWidget* widget, GdkEventMotion* event,
                        WebWidgetHost* host) {
  WebMouseEvent wme(event);
  host->webwidget()->HandleInputEvent(&wme);
  return FALSE;
}

gboolean MouseScrollEvent(GtkWidget* widget, GdkEventScroll* event,
                          WebWidgetHost* host) {
  WebMouseWheelEvent wmwe(event);
  host->webwidget()->HandleInputEvent(&wmwe);
  return FALSE;
}

}  // anonymous namespace

// -----------------------------------------------------------------------------

gfx::WindowHandle WebWidgetHost::CreateWindow(gfx::WindowHandle box,
                                              void* host) {
  GtkWidget* widget = gtk_drawing_area_new();
  gtk_box_pack_start(GTK_BOX(box), widget, TRUE, TRUE, 0);

  gtk_widget_add_events(widget, GDK_EXPOSURE_MASK |
                                GDK_POINTER_MOTION_MASK |
                                GDK_BUTTON_PRESS_MASK |
                                GDK_BUTTON_RELEASE_MASK |
                                GDK_KEY_PRESS_MASK |
                                GDK_KEY_RELEASE_MASK);
  GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS);
  g_signal_connect(widget, "configure-event", G_CALLBACK(ConfigureEvent), host);
  g_signal_connect(widget, "expose-event", G_CALLBACK(ExposeEvent), host);
  g_signal_connect(widget, "destroy-event", G_CALLBACK(DestroyEvent), host);
  g_signal_connect(widget, "key-press-event", G_CALLBACK(KeyPressReleaseEvent),
                   host);
  g_signal_connect(widget, "key-release-event",
                   G_CALLBACK(KeyPressReleaseEvent), host);
  g_signal_connect(widget, "focus", G_CALLBACK(FocusMove), host);
  g_signal_connect(widget, "focus-in-event", G_CALLBACK(FocusIn), host);
  g_signal_connect(widget, "focus-out-event", G_CALLBACK(FocusOut), host);
  g_signal_connect(widget, "button-press-event",
                   G_CALLBACK(ButtonPressReleaseEvent), host);
  g_signal_connect(widget, "button-release-event",
                   G_CALLBACK(ButtonPressReleaseEvent), host);
  g_signal_connect(widget, "motion-notify-event", G_CALLBACK(MouseMoveEvent),
                   host);
  g_signal_connect(widget, "scroll-event", G_CALLBACK(MouseScrollEvent),
                   host);

  return widget;
}

WebWidgetHost* WebWidgetHost::Create(gfx::WindowHandle box,
                                     WebWidgetDelegate* delegate) {
  WebWidgetHost* host = new WebWidgetHost();
  host->view_ = CreateWindow(box, host);
  host->webwidget_ = WebWidget::Create(delegate);

  return host;
}

void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) {
  paint_rect_ = paint_rect_.Union(rect);
}

void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) {
  DLOG_IF(WARNING, painting_) << "unexpected invalidation while painting";

  UpdatePaintRect(damaged_rect);

  if (!handling_expose) {
    gtk_widget_queue_draw_area(GTK_WIDGET(view_), damaged_rect.x(),
        damaged_rect.y(), damaged_rect.width(), damaged_rect.height());
  }
}

void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) {
  // This is used for optimizing painting when the renderer is scrolled. We're
  // currently not doing any optimizations so just invalidate the region.
  DidInvalidateRect(clip_rect);
}

WebWidgetHost* FromWindow(gfx::WindowHandle view) {
  const gpointer p = g_object_get_data(G_OBJECT(view), "webwidgethost");
  return (WebWidgetHost* ) p;
}

WebWidgetHost::WebWidgetHost()
    : view_(NULL),
      webwidget_(NULL),
      scroll_dx_(0),
      scroll_dy_(0),
      track_mouse_leave_(false) {
  set_painting(false);
}

WebWidgetHost::~WebWidgetHost() {
  webwidget_->Close();
  webwidget_->Release();
}

void WebWidgetHost::Resize(const gfx::Size &newsize) {
  // The pixel buffer backing us is now the wrong size
  canvas_.reset();

  webwidget_->Resize(gfx::Size(newsize.width(), newsize.height()));
}

void WebWidgetHost::Paint() {
  int width = view_->allocation.width;
  int height = view_->allocation.height;
  gfx::Rect client_rect(width, height);

  // Allocate a canvas if necessary
  if (!canvas_.get()) {
    ResetScrollRect();
    paint_rect_ = client_rect;
    canvas_.reset(new gfx::PlatformCanvas(width, height, true));
    if (!canvas_.get()) {
      // memory allocation failed, we can't paint.
      LOG(ERROR) << "Failed to allocate memory for " << width << "x" << height;
      return;
    }
  }

  // This may result in more invalidation
  webwidget_->Layout();

  // Paint the canvas if necessary.  Allow painting to generate extra rects the
  // first time we call it.  This is necessary because some WebCore rendering
  // objects update their layout only when painted.
  for (int i = 0; i < 2; ++i) {
    paint_rect_ = client_rect.Intersect(paint_rect_);
    if (!paint_rect_.IsEmpty()) {
      gfx::Rect rect(paint_rect_);
      paint_rect_ = gfx::Rect();

      DLOG_IF(WARNING, i == 1) << "painting caused additional invalidations";
      PaintRect(rect);
    }
  }
  DCHECK(paint_rect_.IsEmpty());

  // BitBlit to the X server
  gfx::PlatformDeviceLinux &platdev = canvas_->getTopPlatformDevice();
  gfx::BitmapPlatformDeviceLinux* const bitdev =
    static_cast<gfx::BitmapPlatformDeviceLinux* >(&platdev);

  cairo_t* cairo_drawable = gdk_cairo_create(view_->window);
  cairo_set_source_surface(cairo_drawable, bitdev->surface(), 0, 0);
  cairo_paint(cairo_drawable);
  cairo_destroy(cairo_drawable);
}

void WebWidgetHost::ResetScrollRect() {
  // This method is only needed for optimized scroll painting, which we don't
  // care about in the test shell, yet.
}

void WebWidgetHost::PaintRect(const gfx::Rect& rect) {
  set_painting(true);
  webwidget_->Paint(canvas_.get(), rect);
  set_painting(false);
}

// -----------------------------------------------------------------------------
// This is called when the GTK window is destroyed. In the Windows code this
// deletes this object. Since it's only test_shell it probably doesn't matter
// that much.
// -----------------------------------------------------------------------------
void WebWidgetHost::WindowDestroyed() {
  delete this;
}
<|endoftext|>


<commit_before>/* Copyright 2016 Google Inc. All Rights Reserved.

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.
==============================================================================*/

// Run with:
// bazel run -c opt --dynamic_mode=off \
// tensorflow_serving/core:aspired_versions_manager_benchmark --
// --benchmarks=.
// For a longer run time and more consistent results, consider a min time
// e.g.: --benchmark_min_time=60.0

#include <algorithm>
#include <functional>
#include <memory>
#include <string>
#include <vector>

#include "tensorflow/core/kernels/batching_util/periodic_function.h"
#include "tensorflow/core/lib/core/notification.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/core/threadpool.h"
#include "tensorflow/core/lib/random/philox_random.h"
#include "tensorflow/core/lib/random/simple_philox.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/platform/test.h"
#include "tensorflow/core/platform/test_benchmark.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow_serving/core/aspired_version_policy.h"
#include "tensorflow_serving/core/aspired_versions_manager.h"
#include "tensorflow_serving/core/availability_preserving_policy.h"
#include "tensorflow_serving/core/loader.h"
#include "tensorflow_serving/core/manager.h"
#include "tensorflow_serving/core/servable_data.h"
#include "tensorflow_serving/core/servable_handle.h"
#include "tensorflow_serving/core/simple_loader.h"
#include "tensorflow_serving/core/test_util/manager_test_util.h"

namespace tensorflow {
namespace serving {
namespace {

constexpr char kServableName[] = "kServableName";

// Benchmarks for read performance of the AspiredVersionsManager class both with
// and without concurrent updates. These simulate the common expected access
// pattern of AspiredVersionsManager for systems with high read rates and low
// update rates.
//
// This class maintains all state for a benchmark and handles the concurrency
// concerns around the concurrent read and update threads.
//
// Example:
//    BenchmarkState state;
//    state.RunBenchmark(42 /* iters */, 5 /* num_threads */);
class BenchmarkState {
 public:
  BenchmarkState(const int interval_micros, const bool do_work)
      : interval_micros_(interval_micros), do_work_(do_work) {
    AspiredVersionsManager::Options options;
    // Do policy thread won't be run automatically.
    options.manage_state_interval_micros = -1;
    options.aspired_version_policy.reset(new AvailabilityPreservingPolicy());
    TF_CHECK_OK(AspiredVersionsManager::Create(std::move(options), &manager_));
  }

  // Actually perform iters reads on the fast read ptr.
  void RunBenchmark(::testing::benchmark::State& state, int num_threads);

 private:
  void SetUp();
  void TearDown();

  // Runs iters number of reads.
  void RunReads(int iters);

  // Runs continuously after setup and until teardown, if interval_micros was
  // greater than 0.
  void RunUpdate();

  // Starts serving this loader version.
  void StartServing(int64_t loader_version);

  // Gets the latest version of the loader available for serving.
  int64_t GetLatestVersion(bool do_work);

  // To avoid having the benchmark timing include time spent scheduling threads,
  // we use this notification to notify when the read threads should begin.
  // This is notified immediately after the benchmark timing is started.
  Notification all_read_threads_scheduled_;

  // Store the update thread as it is only safe to complete teardown and
  // destruct state after it has exited.
  std::unique_ptr<PeriodicFunction> update_thread_;

  // The AspiredVersionsManager being benchmarked primarily for read
  // performance.
  std::unique_ptr<AspiredVersionsManager> manager_;

  // Interval in microseconds for running the update thread.
  const int interval_micros_;

  // In each iteration, to simulate a more realistic access pattern that does
  // more than content for the mutex.
  bool do_work_;
};

void BenchmarkState::StartServing(const int64_t loader_version) {
  std::unique_ptr<Loader> loader(new SimpleLoader<int64_t>(
      [loader_version](std::unique_ptr<int64_t>* const servable) {
        servable->reset(new int64);
        **servable = loader_version;
        return Status::OK();
      },
      SimpleLoader<int64_t>::EstimateNoResources()));
  std::vector<ServableData<std::unique_ptr<Loader>>> versions;
  versions.push_back({{kServableName, loader_version}, std::move(loader)});
  manager_->GetAspiredVersionsCallback()(kServableName, std::move(versions));
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .HandlePendingAspiredVersionsRequests();
  // Will load the latest.
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .InvokePolicyAndExecuteAction();
  // Will quiesce the previous.
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .InvokePolicyAndExecuteAction();
  // Will delete the previous.
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .InvokePolicyAndExecuteAction();
  CHECK_EQ(1, manager_->ListAvailableServableIds().size());
}

int64_t BenchmarkState::GetLatestVersion(const bool do_work) {
  ServableHandle<int64_t> handle;
  const Status status = manager_->GetServableHandle(
      ServableRequest::Latest(kServableName), &handle);
  TF_CHECK_OK(status) << status;
  if (do_work) {
    // Let's do some work, so that we are not just measuring contention in the
    // mutex.
    float count = 0;
    for (int i = 1; i < 10000; ++i) {
      count *= i;
    }
    CHECK_GE(count, 0);
  }

  return *handle;
}

void BenchmarkState::RunUpdate() { StartServing(GetLatestVersion(false) + 1); }

void BenchmarkState::SetUp() {
  StartServing(0);
  if (interval_micros_ > 0) {
    PeriodicFunction::Options pf_options;
    pf_options.thread_name_prefix =
        "AspiredVersionsManager_Benchmark_Update_Thread";
    update_thread_.reset(new PeriodicFunction([this] { RunUpdate(); },
                                              interval_micros_, pf_options));
  }
}

void BenchmarkState::TearDown() {
  // Destruct the update thread which blocks until it exits.
  update_thread_.reset();
}

void BenchmarkState::RunReads(int iters) {
  for (int i = 0; i < iters; ++i) {
    // Prevents the compiler from optimizing this away.
    CHECK_GE(GetLatestVersion(do_work_), 0);
  }
}

void BenchmarkState::RunBenchmark(::testing::benchmark::State& state,
                                  int num_threads) {
  SetUp();

  // To be compatible with the Google benchmark framework, the tensorflow new
  // benchmark API requires that each benchmark routine has exactly one.
  // `for (auto s : state)` benchmark loop (in all threads).
  // Therefore we cannot have multiple threads executing the same for-each loop.
  // We need to introduce a new parameter for the fixed number of iteration in
  // each thread.

  // Pick a reasonably large value.
  const int kSubIters = 500;

  // The benchmark timing loop. Timer automatically starts/stops.
  // In each iteration, we spin up a thread-pool and execute kSubIters in each
  // thread.
  for (auto s : state) {
    // Exclude the scheduling setup time.
    state.PauseTiming();
    std::unique_ptr<thread::ThreadPool> pool(new thread::ThreadPool(
        Env::Default(), "RunBenchmarkReadThread", num_threads));
    for (int thread_index = 0; thread_index < num_threads; ++thread_index) {
      std::function<void()> run_reads_fn = [&]() {
        // Wait until all_read_threads_scheduled_ has been notified.
        all_read_threads_scheduled_.WaitForNotification();
        RunReads(kSubIters);
      };
      pool->Schedule(run_reads_fn);
    }
    state.ResumeTiming();
    if (!all_read_threads_scheduled_.HasBeenNotified())
      all_read_threads_scheduled_.Notify();

    // Note that destructing the threadpool blocks on completion of all
    // scheduled execution.  This is intentional as we want all threads to
    // complete iters iterations.  It also means that the timing may be off
    // (work done == iters * num_threads) and includes time scheduling work on
    // the threads.
    pool.reset();
  }

  state.SetItemsProcessed(num_threads * kSubIters * state.iterations());
  TearDown();
}

void BenchmarkReadsAndUpdates(::testing::benchmark::State& state,
                              int num_threads, int interval_micros,
                              bool do_work) {
  BenchmarkState bm_state(interval_micros, do_work);
  bm_state.RunBenchmark(state, num_threads);
}

void BM_Work_NoUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // No updates. 0 interval_micros signals not to update at all.
  BenchmarkReadsAndUpdates(state, num_threads, 0, true);
}

void BM_Work_FrequentUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // Frequent updates: 1000 micros == 1 millisecond or 1000qps of updates
  BenchmarkReadsAndUpdates(state, num_threads, 1000, true);
}

void BM_NoWork_NoUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // No updates. 0 interval_micros signals not to update at all.
  BenchmarkReadsAndUpdates(state, num_threads, 0, false);
}

void BM_NoWork_FrequentUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // Frequent updates: 1000 micros == 1 millisecond or 1000qps of updates
  BenchmarkReadsAndUpdates(state, num_threads, 1000, false);
}

// The benchmarking system by default uses cpu time to calculate items per
// second, which would include time spent by all the threads on the cpu.
// Instead of that we use real-time here so that we can see items/s increasing
// with increasing threads, which is easier to understand.
BENCHMARK(BM_Work_NoUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

BENCHMARK(BM_Work_FrequentUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

BENCHMARK(BM_NoWork_NoUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

BENCHMARK(BM_NoWork_FrequentUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

void BM_GetServableHandle(::testing::benchmark::State& state) {
  // Number of different servable streams.
  constexpr int kNumServableStreams = 10;
  // Number of versions of a particular servable stream.
  constexpr int kNumServableVersions = 2;

  static AspiredVersionsManager* const manager = []() {
    AspiredVersionsManager::Options options;
    // Do policy thread won't be run automatically.
    options.manage_state_interval_micros = -1;
    options.aspired_version_policy.reset(new AvailabilityPreservingPolicy());
    std::unique_ptr<AspiredVersionsManager> manager;
    TF_CHECK_OK(AspiredVersionsManager::Create(std::move(options), &manager));
    auto aspired_versions_callback = manager->GetAspiredVersionsCallback();
    for (int i = 0; i < kNumServableStreams; ++i) {
      const string servable_name = strings::StrCat(kServableName, i);
      std::vector<ServableData<std::unique_ptr<Loader>>> versions;
      for (int j = 0; j < kNumServableVersions; ++j) {
        std::unique_ptr<Loader> loader(new SimpleLoader<int64_t>(
            [j](std::unique_ptr<int64_t>* const servable) {
              servable->reset(new int64);
              **servable = j;
              return Status::OK();
            },
            SimpleLoader<int64_t>::EstimateNoResources()));
        versions.push_back({{servable_name, j}, std::move(loader)});
      }

      aspired_versions_callback(servable_name, std::move(versions));
      test_util::AspiredVersionsManagerTestAccess(manager.get())
          .HandlePendingAspiredVersionsRequests();
      for (int j = 0; j < kNumServableVersions; ++j) {
        test_util::AspiredVersionsManagerTestAccess(manager.get())
            .InvokePolicyAndExecuteAction();
      }
    }
    return manager.release();
  }();
  CHECK_EQ(kNumServableStreams * kNumServableVersions,
           manager->ListAvailableServableIds().size());

  constexpr int kNumRequests = 1024;
  // Ratio of requests which are asking for the latest servable as opposed to a
  // specific version.
  constexpr float kLatestRatio = 0.8;
  static const std::vector<ServableRequest>* requests = []() {
    std::vector<ServableRequest>* requests(new std::vector<ServableRequest>());
    random::PhiloxRandom philox(testing::RandomSeed());
    random::SimplePhilox random(&philox);
    for (int i = 0; i < kNumRequests; ++i) {
      const string name =
          strings::StrCat(kServableName, random.Uniform(kNumServableStreams));
      if (random.RandFloat() > kLatestRatio) {
        const int64_t version = random.Uniform(kNumServableVersions);
        requests->push_back(ServableRequest::Specific(name, version));
      } else {
        requests->push_back(ServableRequest::Latest(name));
      }
    }
    return requests;
  }();

  ServableHandle<int64_t> handle;
  int i = 0;
  for (auto s : state) {
    const Status status =
        manager->GetServableHandle(requests->at(i % kNumRequests), &handle);
    TF_CHECK_OK(status) << status;
    ++i;
  }
  state.SetItemsProcessed(state.iterations());
}
BENCHMARK(BM_GetServableHandle);

}  // namespace
}  // namespace serving
}  // namespace tensorflow

int main(int argc, char** argv) {
  tensorflow::port::InitMain(argv[0], &argc, &argv);
  tensorflow::testing::RunBenchmarks();
  return 0;
}
<commit_msg>Replace remaining deprecated int64 with int64_t.<commit_after>/* Copyright 2016 Google Inc. All Rights Reserved.

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.
==============================================================================*/

// Run with:
// bazel run -c opt --dynamic_mode=off \
// tensorflow_serving/core:aspired_versions_manager_benchmark --
// --benchmarks=.
// For a longer run time and more consistent results, consider a min time
// e.g.: --benchmark_min_time=60.0

#include <algorithm>
#include <functional>
#include <memory>
#include <string>
#include <vector>

#include "tensorflow/core/kernels/batching_util/periodic_function.h"
#include "tensorflow/core/lib/core/notification.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/core/threadpool.h"
#include "tensorflow/core/lib/random/philox_random.h"
#include "tensorflow/core/lib/random/simple_philox.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/platform/test.h"
#include "tensorflow/core/platform/test_benchmark.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow_serving/core/aspired_version_policy.h"
#include "tensorflow_serving/core/aspired_versions_manager.h"
#include "tensorflow_serving/core/availability_preserving_policy.h"
#include "tensorflow_serving/core/loader.h"
#include "tensorflow_serving/core/manager.h"
#include "tensorflow_serving/core/servable_data.h"
#include "tensorflow_serving/core/servable_handle.h"
#include "tensorflow_serving/core/simple_loader.h"
#include "tensorflow_serving/core/test_util/manager_test_util.h"

namespace tensorflow {
namespace serving {
namespace {

constexpr char kServableName[] = "kServableName";

// Benchmarks for read performance of the AspiredVersionsManager class both with
// and without concurrent updates. These simulate the common expected access
// pattern of AspiredVersionsManager for systems with high read rates and low
// update rates.
//
// This class maintains all state for a benchmark and handles the concurrency
// concerns around the concurrent read and update threads.
//
// Example:
//    BenchmarkState state;
//    state.RunBenchmark(42 /* iters */, 5 /* num_threads */);
class BenchmarkState {
 public:
  BenchmarkState(const int interval_micros, const bool do_work)
      : interval_micros_(interval_micros), do_work_(do_work) {
    AspiredVersionsManager::Options options;
    // Do policy thread won't be run automatically.
    options.manage_state_interval_micros = -1;
    options.aspired_version_policy.reset(new AvailabilityPreservingPolicy());
    TF_CHECK_OK(AspiredVersionsManager::Create(std::move(options), &manager_));
  }

  // Actually perform iters reads on the fast read ptr.
  void RunBenchmark(::testing::benchmark::State& state, int num_threads);

 private:
  void SetUp();
  void TearDown();

  // Runs iters number of reads.
  void RunReads(int iters);

  // Runs continuously after setup and until teardown, if interval_micros was
  // greater than 0.
  void RunUpdate();

  // Starts serving this loader version.
  void StartServing(int64_t loader_version);

  // Gets the latest version of the loader available for serving.
  int64_t GetLatestVersion(bool do_work);

  // To avoid having the benchmark timing include time spent scheduling threads,
  // we use this notification to notify when the read threads should begin.
  // This is notified immediately after the benchmark timing is started.
  Notification all_read_threads_scheduled_;

  // Store the update thread as it is only safe to complete teardown and
  // destruct state after it has exited.
  std::unique_ptr<PeriodicFunction> update_thread_;

  // The AspiredVersionsManager being benchmarked primarily for read
  // performance.
  std::unique_ptr<AspiredVersionsManager> manager_;

  // Interval in microseconds for running the update thread.
  const int interval_micros_;

  // In each iteration, to simulate a more realistic access pattern that does
  // more than content for the mutex.
  bool do_work_;
};

void BenchmarkState::StartServing(const int64_t loader_version) {
  std::unique_ptr<Loader> loader(new SimpleLoader<int64_t>(
      [loader_version](std::unique_ptr<int64_t>* const servable) {
        servable->reset(new int64_t);
        **servable = loader_version;
        return Status::OK();
      },
      SimpleLoader<int64_t>::EstimateNoResources()));
  std::vector<ServableData<std::unique_ptr<Loader>>> versions;
  versions.push_back({{kServableName, loader_version}, std::move(loader)});
  manager_->GetAspiredVersionsCallback()(kServableName, std::move(versions));
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .HandlePendingAspiredVersionsRequests();
  // Will load the latest.
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .InvokePolicyAndExecuteAction();
  // Will quiesce the previous.
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .InvokePolicyAndExecuteAction();
  // Will delete the previous.
  test_util::AspiredVersionsManagerTestAccess(manager_.get())
      .InvokePolicyAndExecuteAction();
  CHECK_EQ(1, manager_->ListAvailableServableIds().size());
}

int64_t BenchmarkState::GetLatestVersion(const bool do_work) {
  ServableHandle<int64_t> handle;
  const Status status = manager_->GetServableHandle(
      ServableRequest::Latest(kServableName), &handle);
  TF_CHECK_OK(status) << status;
  if (do_work) {
    // Let's do some work, so that we are not just measuring contention in the
    // mutex.
    float count = 0;
    for (int i = 1; i < 10000; ++i) {
      count *= i;
    }
    CHECK_GE(count, 0);
  }

  return *handle;
}

void BenchmarkState::RunUpdate() { StartServing(GetLatestVersion(false) + 1); }

void BenchmarkState::SetUp() {
  StartServing(0);
  if (interval_micros_ > 0) {
    PeriodicFunction::Options pf_options;
    pf_options.thread_name_prefix =
        "AspiredVersionsManager_Benchmark_Update_Thread";
    update_thread_.reset(new PeriodicFunction([this] { RunUpdate(); },
                                              interval_micros_, pf_options));
  }
}

void BenchmarkState::TearDown() {
  // Destruct the update thread which blocks until it exits.
  update_thread_.reset();
}

void BenchmarkState::RunReads(int iters) {
  for (int i = 0; i < iters; ++i) {
    // Prevents the compiler from optimizing this away.
    CHECK_GE(GetLatestVersion(do_work_), 0);
  }
}

void BenchmarkState::RunBenchmark(::testing::benchmark::State& state,
                                  int num_threads) {
  SetUp();

  // To be compatible with the Google benchmark framework, the tensorflow new
  // benchmark API requires that each benchmark routine has exactly one.
  // `for (auto s : state)` benchmark loop (in all threads).
  // Therefore we cannot have multiple threads executing the same for-each loop.
  // We need to introduce a new parameter for the fixed number of iteration in
  // each thread.

  // Pick a reasonably large value.
  const int kSubIters = 500;

  // The benchmark timing loop. Timer automatically starts/stops.
  // In each iteration, we spin up a thread-pool and execute kSubIters in each
  // thread.
  for (auto s : state) {
    // Exclude the scheduling setup time.
    state.PauseTiming();
    std::unique_ptr<thread::ThreadPool> pool(new thread::ThreadPool(
        Env::Default(), "RunBenchmarkReadThread", num_threads));
    for (int thread_index = 0; thread_index < num_threads; ++thread_index) {
      std::function<void()> run_reads_fn = [&]() {
        // Wait until all_read_threads_scheduled_ has been notified.
        all_read_threads_scheduled_.WaitForNotification();
        RunReads(kSubIters);
      };
      pool->Schedule(run_reads_fn);
    }
    state.ResumeTiming();
    if (!all_read_threads_scheduled_.HasBeenNotified())
      all_read_threads_scheduled_.Notify();

    // Note that destructing the threadpool blocks on completion of all
    // scheduled execution.  This is intentional as we want all threads to
    // complete iters iterations.  It also means that the timing may be off
    // (work done == iters * num_threads) and includes time scheduling work on
    // the threads.
    pool.reset();
  }

  state.SetItemsProcessed(num_threads * kSubIters * state.iterations());
  TearDown();
}

void BenchmarkReadsAndUpdates(::testing::benchmark::State& state,
                              int num_threads, int interval_micros,
                              bool do_work) {
  BenchmarkState bm_state(interval_micros, do_work);
  bm_state.RunBenchmark(state, num_threads);
}

void BM_Work_NoUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // No updates. 0 interval_micros signals not to update at all.
  BenchmarkReadsAndUpdates(state, num_threads, 0, true);
}

void BM_Work_FrequentUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // Frequent updates: 1000 micros == 1 millisecond or 1000qps of updates
  BenchmarkReadsAndUpdates(state, num_threads, 1000, true);
}

void BM_NoWork_NoUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // No updates. 0 interval_micros signals not to update at all.
  BenchmarkReadsAndUpdates(state, num_threads, 0, false);
}

void BM_NoWork_FrequentUpdates_Reads(::testing::benchmark::State& state) {
  const int num_threads = state.range(0);

  // Frequent updates: 1000 micros == 1 millisecond or 1000qps of updates
  BenchmarkReadsAndUpdates(state, num_threads, 1000, false);
}

// The benchmarking system by default uses cpu time to calculate items per
// second, which would include time spent by all the threads on the cpu.
// Instead of that we use real-time here so that we can see items/s increasing
// with increasing threads, which is easier to understand.
BENCHMARK(BM_Work_NoUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

BENCHMARK(BM_Work_FrequentUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

BENCHMARK(BM_NoWork_NoUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

BENCHMARK(BM_NoWork_FrequentUpdates_Reads)
    ->UseRealTime()
    ->Arg(1)
    ->Arg(2)
    ->Arg(4)
    ->Arg(8)
    ->Arg(16)
    ->Arg(32)
    ->Arg(64);

void BM_GetServableHandle(::testing::benchmark::State& state) {
  // Number of different servable streams.
  constexpr int kNumServableStreams = 10;
  // Number of versions of a particular servable stream.
  constexpr int kNumServableVersions = 2;

  static AspiredVersionsManager* const manager = []() {
    AspiredVersionsManager::Options options;
    // Do policy thread won't be run automatically.
    options.manage_state_interval_micros = -1;
    options.aspired_version_policy.reset(new AvailabilityPreservingPolicy());
    std::unique_ptr<AspiredVersionsManager> manager;
    TF_CHECK_OK(AspiredVersionsManager::Create(std::move(options), &manager));
    auto aspired_versions_callback = manager->GetAspiredVersionsCallback();
    for (int i = 0; i < kNumServableStreams; ++i) {
      const string servable_name = strings::StrCat(kServableName, i);
      std::vector<ServableData<std::unique_ptr<Loader>>> versions;
      for (int j = 0; j < kNumServableVersions; ++j) {
        std::unique_ptr<Loader> loader(new SimpleLoader<int64_t>(
            [j](std::unique_ptr<int64_t>* const servable) {
              servable->reset(new int64_t);
              **servable = j;
              return Status::OK();
            },
            SimpleLoader<int64_t>::EstimateNoResources()));
        versions.push_back({{servable_name, j}, std::move(loader)});
      }

      aspired_versions_callback(servable_name, std::move(versions));
      test_util::AspiredVersionsManagerTestAccess(manager.get())
          .HandlePendingAspiredVersionsRequests();
      for (int j = 0; j < kNumServableVersions; ++j) {
        test_util::AspiredVersionsManagerTestAccess(manager.get())
            .InvokePolicyAndExecuteAction();
      }
    }
    return manager.release();
  }();
  CHECK_EQ(kNumServableStreams * kNumServableVersions,
           manager->ListAvailableServableIds().size());

  constexpr int kNumRequests = 1024;
  // Ratio of requests which are asking for the latest servable as opposed to a
  // specific version.
  constexpr float kLatestRatio = 0.8;
  static const std::vector<ServableRequest>* requests = []() {
    std::vector<ServableRequest>* requests(new std::vector<ServableRequest>());
    random::PhiloxRandom philox(testing::RandomSeed());
    random::SimplePhilox random(&philox);
    for (int i = 0; i < kNumRequests; ++i) {
      const string name =
          strings::StrCat(kServableName, random.Uniform(kNumServableStreams));
      if (random.RandFloat() > kLatestRatio) {
        const int64_t version = random.Uniform(kNumServableVersions);
        requests->push_back(ServableRequest::Specific(name, version));
      } else {
        requests->push_back(ServableRequest::Latest(name));
      }
    }
    return requests;
  }();

  ServableHandle<int64_t> handle;
  int i = 0;
  for (auto s : state) {
    const Status status =
        manager->GetServableHandle(requests->at(i % kNumRequests), &handle);
    TF_CHECK_OK(status) << status;
    ++i;
  }
  state.SetItemsProcessed(state.iterations());
}
BENCHMARK(BM_GetServableHandle);

}  // namespace
}  // namespace serving
}  // namespace tensorflow

int main(int argc, char** argv) {
  tensorflow::port::InitMain(argv[0], &argc, &argv);
  tensorflow::testing::RunBenchmarks();
  return 0;
}
<|endoftext|>