<commit_before>#ifdef JOEDB_HAS_SSH

#include "joedb/concurrency/SSH_Connection.h"
#include "joedb/Exception.h"

#include <fcntl.h>
#include <thread>
#include <chrono>
#include <iostream>

//
// Windows does not define those
//
#ifndef S_IRUSR
#define	S_IRUSR	0000400
#endif

#ifndef S_IWUSR
#define	S_IWUSR	0000200
#endif

namespace joedb
{
 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::lock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": lock()... ";

  bool done = false;
  const int max_attempts = 60;

  for (int attempt = 1; attempt <= max_attempts; attempt++)
  {
   sftp_file file = sftp_open
   (
    sftp.get(),
    mutex_file_name.c_str(),
    O_CREAT | O_EXCL,
    S_IRUSR
   );

   if (file)
   {
    done = true;
    sftp_close(file);
    break;
   }
   else
   {
    if (trace)
     std::cerr << "Retrying(" << attempt << "/" << max_attempts << ")... ";
    std::this_thread::sleep_for(std::chrono::seconds(1));
   }
  }

  if (trace)
  {
   if (done)
    std::cerr << "done.\n";
   else
    std::cerr << "timeout.\n";
  }

  if (!done)
   throw Exception("SSH_Connection::lock: timeout");
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::unlock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": unlock()\n";

  if (sftp_unlink(sftp.get(), mutex_file_name.c_str()) < 0)
   throw Exception("Error removing remote mutex");
 }

 ////////////////////////////////////////////////////////////////////////////
 int64_t SSH_Connection::raw_pull(Writable_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": pull()... ";

  int64_t server_position = 0;

  try
  {
   ssh::SFTP_Attributes attributes
   (
    sftp_stat(sftp.get(), remote_file_name.c_str())
   );

   server_position = int64_t(attributes.get()->size);
  }
  catch (const joedb::Exception &)
  {
  }

  const int64_t client_position = client_journal.get_checkpoint_position();

  if (client_position < server_position)
  {
   std::vector<char> v(size_t(server_position - client_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_RDONLY,
    S_IRUSR | S_IWUSR
   );

   if (file)
   {
    const int seek_result = sftp_seek64(file, uint64_t(client_position));
    if (seek_result < 0)
    {
     sftp_close(file);
     throw Exception("Error while seeking");
    }

    ssize_t total_read = 0;

    while (total_read < ssize_t(v.size()))
    {
     const ssize_t read_result = sftp_read
     (
      file,
      &v[size_t(total_read)],
      v.size() - size_t(total_read)
     );

     if (read_result < 0)
     {
      sftp_close(file);
      throw Exception("Error during sftp_read");
     }

     total_read += read_result;
     if (trace)
      std::cerr << read_result << ' ';
    }

    sftp_close(file);
    client_journal.append_raw_tail(v);
   }
   else
    throw Exception("Could not open remote file for reading");
  }
  else if (server_position > 0 && client_position > server_position)
   throw Exception("Trying to pull when ahead of server");

  if (trace)
   std::cerr << "done.\n";

  return server_position;
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::raw_push
 ////////////////////////////////////////////////////////////////////////////
 (
  Readonly_Journal &client_journal,
  int64_t server_position
 )
 {
  if (trace)
   std::cerr << full_remote_name << ": push()... ";

  const int64_t client_position = client_journal.get_checkpoint_position();
  if (client_position > server_position)
  {
   std::vector<char> v(client_journal.get_raw_tail(server_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_WRONLY | O_CREAT,
    S_IRUSR | S_IWUSR
   );

   const int seek_result = sftp_seek64(file, uint64_t(server_position));

   if (file)
   {
    //
    // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-00
    //
    // The maximum size of a packet is in practise determined by the client
    // (the maximum size of read or write requests that it sends, plus a few
    // bytes of packet overhead).  All servers SHOULD support packets of at
    // least 34000 bytes (where the packet size refers to the full length,
    // including the header above).  This should allow for reads and writes of
    // at most 32768 bytes.
    //
    const size_t max_block_size = 32768;
    const size_t size = v.size();
    size_t written = 0;

    while (seek_result >= 0 && written < size)
    {
     size_t block_size = size - written;

     if (block_size > max_block_size)
      block_size = max_block_size;

     const ssize_t result = sftp_write(file, v.data() + written, block_size);

     if (result <= 0)
      break;

     written += size_t(result);
    }

    sftp_close(file);

    if (written < size)
     throw Exception("Incomplete write during push");
   }
   else
    throw Exception("Could not open remote file for writing");
  }

  if (trace)
   std::cerr << "done.\n";
 }

 ////////////////////////////////////////////////////////////////////////////
 SSH_Connection::SSH_Connection
 ////////////////////////////////////////////////////////////////////////////
 (
  std::string user,
  std::string host,
  int port,
  std::string remote_file_name,
  bool trace,
  int ssh_log_level
 ):
  remote_file_name(remote_file_name),
  trace(trace),
  mutex_file_name(remote_file_name + ".mutex"),
  full_remote_name(user + "@" + host + ":" + remote_file_name),
  session
  (
   user,
   host,
   port,
   ssh_log_level
  ),
  sftp(session)
 {
 }
}

#endif
<commit_msg>SSH_Connection: fail to pull if remote file does not exist<commit_after>#ifdef JOEDB_HAS_SSH

#include "joedb/concurrency/SSH_Connection.h"
#include "joedb/Exception.h"

#include <fcntl.h>
#include <thread>
#include <chrono>
#include <iostream>

//
// Windows does not define those
//
#ifndef S_IRUSR
#define	S_IRUSR	0000400
#endif

#ifndef S_IWUSR
#define	S_IWUSR	0000200
#endif

namespace joedb
{
 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::lock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": lock()... ";

  bool done = false;
  const int max_attempts = 60;

  for (int attempt = 1; attempt <= max_attempts; attempt++)
  {
   sftp_file file = sftp_open
   (
    sftp.get(),
    mutex_file_name.c_str(),
    O_CREAT | O_EXCL,
    S_IRUSR
   );

   if (file)
   {
    done = true;
    sftp_close(file);
    break;
   }
   else
   {
    if (trace)
     std::cerr << "Retrying(" << attempt << "/" << max_attempts << ")... ";
    std::this_thread::sleep_for(std::chrono::seconds(1));
   }
  }

  if (trace)
  {
   if (done)
    std::cerr << "done.\n";
   else
    std::cerr << "timeout.\n";
  }

  if (!done)
   throw Exception("SSH_Connection::lock: timeout");
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::unlock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": unlock()\n";

  if (sftp_unlink(sftp.get(), mutex_file_name.c_str()) < 0)
   throw Exception("Error removing remote mutex");
 }

 ////////////////////////////////////////////////////////////////////////////
 int64_t SSH_Connection::raw_pull(Writable_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": pull()... ";

  int64_t server_position = 0;

  try
  {
   ssh::SFTP_Attributes attributes
   (
    sftp_stat(sftp.get(), remote_file_name.c_str())
   );

   server_position = int64_t(attributes.get()->size);
  }
  catch (const joedb::Exception &)
  {
   throw Exception("Could not stat remote file");
  }

  const int64_t client_position = client_journal.get_checkpoint_position();

  if (client_position < server_position)
  {
   std::vector<char> v(size_t(server_position - client_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_RDONLY,
    S_IRUSR | S_IWUSR
   );

   if (file)
   {
    const int seek_result = sftp_seek64(file, uint64_t(client_position));
    if (seek_result < 0)
    {
     sftp_close(file);
     throw Exception("Error while seeking");
    }

    ssize_t total_read = 0;

    while (total_read < ssize_t(v.size()))
    {
     const ssize_t read_result = sftp_read
     (
      file,
      &v[size_t(total_read)],
      v.size() - size_t(total_read)
     );

     if (read_result < 0)
     {
      sftp_close(file);
      throw Exception("Error during sftp_read");
     }

     total_read += read_result;
     if (trace)
      std::cerr << read_result << ' ';
    }

    sftp_close(file);
    client_journal.append_raw_tail(v);
   }
   else
    throw Exception("Could not open remote file for reading");
  }
  else if (client_position > server_position)
   throw Exception("Trying to pull when ahead of server");

  if (trace)
   std::cerr << "done.\n";

  return server_position;
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::raw_push
 ////////////////////////////////////////////////////////////////////////////
 (
  Readonly_Journal &client_journal,
  int64_t server_position
 )
 {
  if (trace)
   std::cerr << full_remote_name << ": push()... ";

  const int64_t client_position = client_journal.get_checkpoint_position();
  if (client_position > server_position)
  {
   std::vector<char> v(client_journal.get_raw_tail(server_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_WRONLY | O_CREAT,
    S_IRUSR | S_IWUSR
   );

   const int seek_result = sftp_seek64(file, uint64_t(server_position));

   if (file)
   {
    //
    // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-00
    //
    // The maximum size of a packet is in practise determined by the client
    // (the maximum size of read or write requests that it sends, plus a few
    // bytes of packet overhead).  All servers SHOULD support packets of at
    // least 34000 bytes (where the packet size refers to the full length,
    // including the header above).  This should allow for reads and writes of
    // at most 32768 bytes.
    //
    const size_t max_block_size = 32768;
    const size_t size = v.size();
    size_t written = 0;

    while (seek_result >= 0 && written < size)
    {
     size_t block_size = size - written;

     if (block_size > max_block_size)
      block_size = max_block_size;

     const ssize_t result = sftp_write(file, v.data() + written, block_size);

     if (result <= 0)
      break;

     written += size_t(result);
    }

    sftp_close(file);

    if (written < size)
     throw Exception("Incomplete write during push");
   }
   else
    throw Exception("Could not open remote file for writing");
  }

  if (trace)
   std::cerr << "done.\n";
 }

 ////////////////////////////////////////////////////////////////////////////
 SSH_Connection::SSH_Connection
 ////////////////////////////////////////////////////////////////////////////
 (
  std::string user,
  std::string host,
  int port,
  std::string remote_file_name,
  bool trace,
  int ssh_log_level
 ):
  remote_file_name(remote_file_name),
  trace(trace),
  mutex_file_name(remote_file_name + ".mutex"),
  full_remote_name(user + "@" + host + ":" + remote_file_name),
  session
  (
   user,
   host,
   port,
   ssh_log_level
  ),
  sftp(session)
 {
 }
}

#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: headertablistbox.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: obo $ $Date: 2004-07-06 13:15:41 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _HEADERTABLISTBOX_HXX
#define _HEADERTABLISTBOX_HXX

#ifndef _HEADBAR_HXX
#include <svtools/headbar.hxx>
#endif
#ifndef _SVTABBX_HXX
#include <svtools/svtabbx.hxx>
#endif

class _HeaderTabListBox : public Control
{
private:
    SvHeaderTabListBox          maListBox;
    HeaderBar                   maHeaderBar;
protected:
    DECL_LINK( HeaderEndDrag_Impl, HeaderBar* );
    virtual long                Notify( NotifyEvent& rNEvt );
public:
                                _HeaderTabListBox( Window* pParent, const ResId& rId );
    virtual                     ~_HeaderTabListBox();

    inline SvHeaderTabListBox&  GetListBox( void );
    inline HeaderBar&           GetHeaderBar( void );

    void                        ConnectElements( void );
                                    // should be called after all manipulations on elements are done
                                    // calcs real sizes depending on sizes of this
    void                        Show( BOOL bVisible = TRUE, USHORT nFlags = 0 );    // same meaning as Windows::Show()
    void                        Enable( BOOL bEnable = TRUE, BOOL bChild = TRUE );  // same meaning as Windows::Enable()
};

inline SvHeaderTabListBox& _HeaderTabListBox::GetListBox( void )
{
    return maListBox;
}

inline HeaderBar& _HeaderTabListBox::GetHeaderBar( void )
{
    return maHeaderBar;
}

#endif
<commit_msg>INTEGRATION: CWS ooo19126 (1.2.830); FILE MERGED 2005/09/05 14:25:16 rt 1.2.830.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: headertablistbox.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 23:23:59 $
 *
 *  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 _HEADERTABLISTBOX_HXX
#define _HEADERTABLISTBOX_HXX

#ifndef _HEADBAR_HXX
#include <svtools/headbar.hxx>
#endif
#ifndef _SVTABBX_HXX
#include <svtools/svtabbx.hxx>
#endif

class _HeaderTabListBox : public Control
{
private:
    SvHeaderTabListBox          maListBox;
    HeaderBar                   maHeaderBar;
protected:
    DECL_LINK( HeaderEndDrag_Impl, HeaderBar* );
    virtual long                Notify( NotifyEvent& rNEvt );
public:
                                _HeaderTabListBox( Window* pParent, const ResId& rId );
    virtual                     ~_HeaderTabListBox();

    inline SvHeaderTabListBox&  GetListBox( void );
    inline HeaderBar&           GetHeaderBar( void );

    void                        ConnectElements( void );
                                    // should be called after all manipulations on elements are done
                                    // calcs real sizes depending on sizes of this
    void                        Show( BOOL bVisible = TRUE, USHORT nFlags = 0 );    // same meaning as Windows::Show()
    void                        Enable( BOOL bEnable = TRUE, BOOL bChild = TRUE );  // same meaning as Windows::Enable()
};

inline SvHeaderTabListBox& _HeaderTabListBox::GetListBox( void )
{
    return maListBox;
}

inline HeaderBar& _HeaderTabListBox::GetHeaderBar( void )
{
    return maHeaderBar;
}

#endif
<|endoftext|>


<commit_before>// @(#)root/thread:$Id$
// Authors: Enric Tejedor CERN  12/09/2016
//          Philippe Canal FNAL 12/09/2016

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

/** \class TReentrantRWLock
    \brief An implementation of a reentrant read-write lock with a
           configurable internal mutex/lock (default Spin Lock).

This class provides an implementation of a rreentrant ead-write lock
that uses an internal lock and a condition variable to synchronize
readers and writers when necessary.

The implementation allows a single reader to take the write lock without
releasing the reader lock.  It also allows the writer to take a read lock.
In other word, the lock is re-entrant for both reading and writing.

The implementation tries to make faster the scenario when readers come
and go but there is no writer. In that case, readers will not pay the
price of taking the internal spin lock.

Moreover, this RW lock tries to be fair with writers, giving them the
possibility to claim the lock and wait for only the remaining readers,
thus preventing starvation.
*/

#include "ROOT/TReentrantRWLock.hxx"
#include "ROOT/TSpinMutex.hxx"
#include "TMutex.h"
#include "TError.h"
#include <assert.h>

using namespace ROOT;

Internal::UniqueLockRecurseCount::UniqueLockRecurseCount()
{
   static bool singleton = false;
   if (singleton) {
      ::Fatal("UniqueLockRecurseCount Ctor", "Only one TReentrantRWLock using a UniqueLockRecurseCount is allowed.");
   }
   singleton = true;
}

////////////////////////////////////////////////////////////////////////////
/// Acquire the lock in read mode.
template <typename MutexT, typename RecurseCountsT>
TVirtualRWMutex::Hint_t *TReentrantRWLock<MutexT, RecurseCountsT>::ReadLock()
{
   ++fReaderReservation;

   // if (fReaders == std::numeric_limits<decltype(fReaders)>::max()) {
   //    ::Fatal("TRWSpinLock::WriteLock", "Too many recursions in TRWSpinLock!");
   // }

   auto local = fRecurseCounts.GetLocal();

   TVirtualRWMutex::Hint_t *hint = nullptr;

   if (!fWriter) {
      // There is no writer, go freely to the critical section
      ++fReaders;
      --fReaderReservation;

      hint = fRecurseCounts.IncrementReadCount(local, fMutex);

   } else if (! fRecurseCounts.IsNotCurrentWriter(local)) {

      --fReaderReservation;
      // This can run concurrently with another thread trying to get
      // the read lock and ending up in the next section ("Wait for writers, if any")
      // which need to also get the local readers count and thus can
      // modify the map.
      hint = fRecurseCounts.IncrementReadCount(local, fMutex);
      ++fReaders;

   } else {
      // A writer claimed the RW lock, we will need to wait on the
      // internal lock
      --fReaderReservation;

      std::unique_lock<MutexT> lock(fMutex);

      // Wait for writers, if any
      if (fWriter && fRecurseCounts.IsNotCurrentWriter(local)) {
         auto readerCount = fRecurseCounts.GetLocalReadersCount(local);
         if (readerCount == 0)
            fCond.wait(lock, [this] { return !fWriter; });
         // else
         //   There is a writer **but** we have outstanding readers
         //   locks, this must mean that the writer is actually
         //   waiting on this thread to release its read locks.
         //   This can be done in only two ways:
         //     * request the writer lock
         //     * release the reader lock
         //   Either way, this thread needs to proceed to
         //   be able to reach a point whether it does one
         //   of the two.
      }

      hint = fRecurseCounts.IncrementReadCount(local);

      // This RW lock now belongs to the readers
      ++fReaders;

      lock.unlock();
   }

   return hint;
}

//////////////////////////////////////////////////////////////////////////
/// Release the lock in read mode.
template <typename MutexT, typename RecurseCountsT>
void TReentrantRWLock<MutexT, RecurseCountsT>::ReadUnLock(TVirtualRWMutex::Hint_t *hint)
{
   size_t *localReaderCount;
   if (!hint) {
      // This should be very rare.
      auto local = fRecurseCounts.GetLocal();
      std::lock_guard<MutexT> lock(fMutex);
      localReaderCount = &(fRecurseCounts.GetLocalReadersCount(local));
   } else {
      localReaderCount = reinterpret_cast<size_t*>(hint);
   }

   --fReaders;
   if (fWriterReservation && fReaders == 0) {
      // We still need to lock here to prevent interleaving with a writer
      std::lock_guard<MutexT> lock(fMutex);

      --(*localReaderCount);

      // Make sure you wake up a writer, if any
      // Note: spurrious wakeups are okay, fReaders
      // will be checked again in WriteLock
      fCond.notify_all();
   } else {

      --(*localReaderCount);
   }
}

//////////////////////////////////////////////////////////////////////////
/// Acquire the lock in write mode.
template <typename MutexT, typename RecurseCountsT>
TVirtualRWMutex::Hint_t *TReentrantRWLock<MutexT, RecurseCountsT>::WriteLock()
{
   ++fWriterReservation;

   std::unique_lock<MutexT> lock(fMutex);

   auto local = fRecurseCounts.GetLocal();

   // Release this thread's reader lock(s)
   auto &readerCount = fRecurseCounts.GetLocalReadersCount(local);
   TVirtualRWMutex::Hint_t *hint = reinterpret_cast<TVirtualRWMutex::Hint_t *>(&readerCount);

   fReaders -= readerCount;

   // Wait for other writers, if any
   if (fWriter && fRecurseCounts.IsNotCurrentWriter(local)) {
      if (readerCount && fReaders == 0) {
         // we decrease fReaders to zero, let's wake up the
         // other writer.
         fCond.notify_all();
      }
      fCond.wait(lock, [this] { return !fWriter; });
   }

   // Claim the lock for this writer
   fWriter = true;
   fRecurseCounts.SetIsWriter(local);

   // Wait until all reader reservations finish
   while (fReaderReservation) {
   };

   // Wait for remaining readers
   fCond.wait(lock, [this] { return fReaders == 0; });

   // Restore this thread's reader lock(s)
   fReaders += readerCount;

   --fWriterReservation;

   lock.unlock();

   return hint;
}

//////////////////////////////////////////////////////////////////////////
/// Release the lock in write mode.
template <typename MutexT, typename RecurseCountsT>
void TReentrantRWLock<MutexT, RecurseCountsT>::WriteUnLock(TVirtualRWMutex::Hint_t *)
{
   // We need to lock here to prevent interleaving with a reader
   std::lock_guard<MutexT> lock(fMutex);

   if (!fWriter || fRecurseCounts.fWriteRecurse == 0) {
      Error("TReentrantRWLock::WriteUnLock", "Write lock already released for %p", this);
      return;
   }

   fRecurseCounts.DecrementWriteCount();

   if (!fRecurseCounts.fWriteRecurse) {
      fWriter = false;

      auto local = fRecurseCounts.GetLocal();
      fRecurseCounts.ResetIsWriter(local);

      // Notify all potential readers/writers that are waiting
      fCond.notify_all();
   }
}

namespace {
template <typename MutexT, typename RecurseCountsT>
struct TReentrantRWLockState: public TVirtualMutex::State {
    int fReadersCount = 0;
    size_t *fReadersCountLoc = nullptr;
    size_t fWriteRecurse = 0;
    bool fIsWriter = false;
};
}

template <typename MutexT, typename RecurseCountsT>
std::unique_ptr<TVirtualMutex::State> TReentrantRWLock<MutexT, RecurseCountsT>::Reset()
{
   using State_t = TReentrantRWLockState<MutexT, RecurseCountsT>;

   std::unique_ptr<State_t> pState(new State_t);
   auto local = fRecurseCounts.GetLocal();

   {
      std::unique_lock<MutexT> lock(fMutex);
      pState->fReadersCountLoc = &(fRecurseCounts.GetLocalReadersCount(local));
   }
   size_t &readerCount(*(pState->fReadersCountLoc));

   pState->fReadersCount = readerCount;

   if (fWriter && !fRecurseCounts.IsNotCurrentWriter(local)) {

      // We are holding the write lock.
      pState->fIsWriter = true;
      pState->fWriteRecurse = fRecurseCounts.fWriteRecurse;

      // Now set the lock (and potential read locks) for immediate release.
      fReaders -= readerCount;
      fRecurseCounts.fWriteRecurse = 1;

      *(pState->fReadersCountLoc) = 0;

      // Release this thread's write lock
      WriteUnLock(reinterpret_cast<TVirtualRWMutex::Hint_t *>(pState->fReadersCountLoc));
   } else if (readerCount) {
      // Now set the lock for release.
      fReaders -= (readerCount-1);
      *(pState->fReadersCountLoc) = 1;

      // Release this thread's reader lock(s)
      ReadUnLock(reinterpret_cast<TVirtualRWMutex::Hint_t *>(pState->fReadersCountLoc));
   }

   // Do something.
   //::Fatal("Reset()", "Not implemented, contact pcanal@fnal.gov");
   return std::move(pState);
}

template <typename MutexT, typename RecurseCountsT>
void TReentrantRWLock<MutexT, RecurseCountsT>::Restore(std::unique_ptr<TVirtualMutex::State> &&state)
{
   TReentrantRWLockState<MutexT, RecurseCountsT> *pState = dynamic_cast<TReentrantRWLockState<MutexT, RecurseCountsT> *>(state.get());
   if (!pState) {
      if (state) {
         SysError("Restore", "LOGIC ERROR - invalid state object!");
         return;
      }
      // No state, do nothing.
      return;
   }

   if (pState->fIsWriter) {
      WriteLock();
      // Now that we go the lock, fix up the recursion count.
      std::unique_lock<MutexT> lock(fMutex);
      fRecurseCounts.fWriteRecurse = pState->fWriteRecurse;
      *(pState->fReadersCountLoc) = pState->fReadersCount;
      fReaders +=  pState->fReadersCount;
   } else {
      ReadLock();
      // Now that we go the read lock, fix up the local recursion count.
      assert( pState->fReadersCount  >= 1 );
      auto readerCount = pState->fReadersCount;

      std::unique_lock<MutexT> lock(fMutex);
      *(pState->fReadersCountLoc) = pState->fReadersCount;
      fReaders += readerCount - 1;
   }

   // Do something.
   //::Fatal("Restore()", "Not implemented, contact pcanal@fnal.gov");
}

namespace ROOT {
template class TReentrantRWLock<ROOT::TSpinMutex, ROOT::Internal::RecurseCounts>;
template class TReentrantRWLock<TMutex, ROOT::Internal::RecurseCounts>;
template class TReentrantRWLock<std::mutex, ROOT::Internal::RecurseCounts>;

template class TReentrantRWLock<ROOT::TSpinMutex, ROOT::Internal::UniqueLockRecurseCount>;
template class TReentrantRWLock<TMutex, ROOT::Internal::UniqueLockRecurseCount>;
}
<commit_msg>Fix typo in comment<commit_after>// @(#)root/thread:$Id$
// Authors: Enric Tejedor CERN  12/09/2016
//          Philippe Canal FNAL 12/09/2016

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

/** \class TReentrantRWLock
    \brief An implementation of a reentrant read-write lock with a
           configurable internal mutex/lock (default Spin Lock).

This class provides an implementation of a reentrant read-write lock
that uses an internal lock and a condition variable to synchronize
readers and writers when necessary.

The implementation allows a single reader to take the write lock without
releasing the reader lock.  It also allows the writer to take a read lock.
In other word, the lock is re-entrant for both reading and writing.

The implementation tries to make faster the scenario when readers come
and go but there is no writer. In that case, readers will not pay the
price of taking the internal spin lock.

Moreover, this RW lock tries to be fair with writers, giving them the
possibility to claim the lock and wait for only the remaining readers,
thus preventing starvation.
*/

#include "ROOT/TReentrantRWLock.hxx"
#include "ROOT/TSpinMutex.hxx"
#include "TMutex.h"
#include "TError.h"
#include <assert.h>

using namespace ROOT;

Internal::UniqueLockRecurseCount::UniqueLockRecurseCount()
{
   static bool singleton = false;
   if (singleton) {
      ::Fatal("UniqueLockRecurseCount Ctor", "Only one TReentrantRWLock using a UniqueLockRecurseCount is allowed.");
   }
   singleton = true;
}

////////////////////////////////////////////////////////////////////////////
/// Acquire the lock in read mode.
template <typename MutexT, typename RecurseCountsT>
TVirtualRWMutex::Hint_t *TReentrantRWLock<MutexT, RecurseCountsT>::ReadLock()
{
   ++fReaderReservation;

   // if (fReaders == std::numeric_limits<decltype(fReaders)>::max()) {
   //    ::Fatal("TRWSpinLock::WriteLock", "Too many recursions in TRWSpinLock!");
   // }

   auto local = fRecurseCounts.GetLocal();

   TVirtualRWMutex::Hint_t *hint = nullptr;

   if (!fWriter) {
      // There is no writer, go freely to the critical section
      ++fReaders;
      --fReaderReservation;

      hint = fRecurseCounts.IncrementReadCount(local, fMutex);

   } else if (! fRecurseCounts.IsNotCurrentWriter(local)) {

      --fReaderReservation;
      // This can run concurrently with another thread trying to get
      // the read lock and ending up in the next section ("Wait for writers, if any")
      // which need to also get the local readers count and thus can
      // modify the map.
      hint = fRecurseCounts.IncrementReadCount(local, fMutex);
      ++fReaders;

   } else {
      // A writer claimed the RW lock, we will need to wait on the
      // internal lock
      --fReaderReservation;

      std::unique_lock<MutexT> lock(fMutex);

      // Wait for writers, if any
      if (fWriter && fRecurseCounts.IsNotCurrentWriter(local)) {
         auto readerCount = fRecurseCounts.GetLocalReadersCount(local);
         if (readerCount == 0)
            fCond.wait(lock, [this] { return !fWriter; });
         // else
         //   There is a writer **but** we have outstanding readers
         //   locks, this must mean that the writer is actually
         //   waiting on this thread to release its read locks.
         //   This can be done in only two ways:
         //     * request the writer lock
         //     * release the reader lock
         //   Either way, this thread needs to proceed to
         //   be able to reach a point whether it does one
         //   of the two.
      }

      hint = fRecurseCounts.IncrementReadCount(local);

      // This RW lock now belongs to the readers
      ++fReaders;

      lock.unlock();
   }

   return hint;
}

//////////////////////////////////////////////////////////////////////////
/// Release the lock in read mode.
template <typename MutexT, typename RecurseCountsT>
void TReentrantRWLock<MutexT, RecurseCountsT>::ReadUnLock(TVirtualRWMutex::Hint_t *hint)
{
   size_t *localReaderCount;
   if (!hint) {
      // This should be very rare.
      auto local = fRecurseCounts.GetLocal();
      std::lock_guard<MutexT> lock(fMutex);
      localReaderCount = &(fRecurseCounts.GetLocalReadersCount(local));
   } else {
      localReaderCount = reinterpret_cast<size_t*>(hint);
   }

   --fReaders;
   if (fWriterReservation && fReaders == 0) {
      // We still need to lock here to prevent interleaving with a writer
      std::lock_guard<MutexT> lock(fMutex);

      --(*localReaderCount);

      // Make sure you wake up a writer, if any
      // Note: spurrious wakeups are okay, fReaders
      // will be checked again in WriteLock
      fCond.notify_all();
   } else {

      --(*localReaderCount);
   }
}

//////////////////////////////////////////////////////////////////////////
/// Acquire the lock in write mode.
template <typename MutexT, typename RecurseCountsT>
TVirtualRWMutex::Hint_t *TReentrantRWLock<MutexT, RecurseCountsT>::WriteLock()
{
   ++fWriterReservation;

   std::unique_lock<MutexT> lock(fMutex);

   auto local = fRecurseCounts.GetLocal();

   // Release this thread's reader lock(s)
   auto &readerCount = fRecurseCounts.GetLocalReadersCount(local);
   TVirtualRWMutex::Hint_t *hint = reinterpret_cast<TVirtualRWMutex::Hint_t *>(&readerCount);

   fReaders -= readerCount;

   // Wait for other writers, if any
   if (fWriter && fRecurseCounts.IsNotCurrentWriter(local)) {
      if (readerCount && fReaders == 0) {
         // we decrease fReaders to zero, let's wake up the
         // other writer.
         fCond.notify_all();
      }
      fCond.wait(lock, [this] { return !fWriter; });
   }

   // Claim the lock for this writer
   fWriter = true;
   fRecurseCounts.SetIsWriter(local);

   // Wait until all reader reservations finish
   while (fReaderReservation) {
   };

   // Wait for remaining readers
   fCond.wait(lock, [this] { return fReaders == 0; });

   // Restore this thread's reader lock(s)
   fReaders += readerCount;

   --fWriterReservation;

   lock.unlock();

   return hint;
}

//////////////////////////////////////////////////////////////////////////
/// Release the lock in write mode.
template <typename MutexT, typename RecurseCountsT>
void TReentrantRWLock<MutexT, RecurseCountsT>::WriteUnLock(TVirtualRWMutex::Hint_t *)
{
   // We need to lock here to prevent interleaving with a reader
   std::lock_guard<MutexT> lock(fMutex);

   if (!fWriter || fRecurseCounts.fWriteRecurse == 0) {
      Error("TReentrantRWLock::WriteUnLock", "Write lock already released for %p", this);
      return;
   }

   fRecurseCounts.DecrementWriteCount();

   if (!fRecurseCounts.fWriteRecurse) {
      fWriter = false;

      auto local = fRecurseCounts.GetLocal();
      fRecurseCounts.ResetIsWriter(local);

      // Notify all potential readers/writers that are waiting
      fCond.notify_all();
   }
}

namespace {
template <typename MutexT, typename RecurseCountsT>
struct TReentrantRWLockState: public TVirtualMutex::State {
    int fReadersCount = 0;
    size_t *fReadersCountLoc = nullptr;
    size_t fWriteRecurse = 0;
    bool fIsWriter = false;
};
}

template <typename MutexT, typename RecurseCountsT>
std::unique_ptr<TVirtualMutex::State> TReentrantRWLock<MutexT, RecurseCountsT>::Reset()
{
   using State_t = TReentrantRWLockState<MutexT, RecurseCountsT>;

   std::unique_ptr<State_t> pState(new State_t);
   auto local = fRecurseCounts.GetLocal();

   {
      std::unique_lock<MutexT> lock(fMutex);
      pState->fReadersCountLoc = &(fRecurseCounts.GetLocalReadersCount(local));
   }
   size_t &readerCount(*(pState->fReadersCountLoc));

   pState->fReadersCount = readerCount;

   if (fWriter && !fRecurseCounts.IsNotCurrentWriter(local)) {

      // We are holding the write lock.
      pState->fIsWriter = true;
      pState->fWriteRecurse = fRecurseCounts.fWriteRecurse;

      // Now set the lock (and potential read locks) for immediate release.
      fReaders -= readerCount;
      fRecurseCounts.fWriteRecurse = 1;

      *(pState->fReadersCountLoc) = 0;

      // Release this thread's write lock
      WriteUnLock(reinterpret_cast<TVirtualRWMutex::Hint_t *>(pState->fReadersCountLoc));
   } else if (readerCount) {
      // Now set the lock for release.
      fReaders -= (readerCount-1);
      *(pState->fReadersCountLoc) = 1;

      // Release this thread's reader lock(s)
      ReadUnLock(reinterpret_cast<TVirtualRWMutex::Hint_t *>(pState->fReadersCountLoc));
   }

   // Do something.
   //::Fatal("Reset()", "Not implemented, contact pcanal@fnal.gov");
   return std::move(pState);
}

template <typename MutexT, typename RecurseCountsT>
void TReentrantRWLock<MutexT, RecurseCountsT>::Restore(std::unique_ptr<TVirtualMutex::State> &&state)
{
   TReentrantRWLockState<MutexT, RecurseCountsT> *pState = dynamic_cast<TReentrantRWLockState<MutexT, RecurseCountsT> *>(state.get());
   if (!pState) {
      if (state) {
         SysError("Restore", "LOGIC ERROR - invalid state object!");
         return;
      }
      // No state, do nothing.
      return;
   }

   if (pState->fIsWriter) {
      WriteLock();
      // Now that we go the lock, fix up the recursion count.
      std::unique_lock<MutexT> lock(fMutex);
      fRecurseCounts.fWriteRecurse = pState->fWriteRecurse;
      *(pState->fReadersCountLoc) = pState->fReadersCount;
      fReaders +=  pState->fReadersCount;
   } else {
      ReadLock();
      // Now that we go the read lock, fix up the local recursion count.
      assert( pState->fReadersCount  >= 1 );
      auto readerCount = pState->fReadersCount;

      std::unique_lock<MutexT> lock(fMutex);
      *(pState->fReadersCountLoc) = pState->fReadersCount;
      fReaders += readerCount - 1;
   }

   // Do something.
   //::Fatal("Restore()", "Not implemented, contact pcanal@fnal.gov");
}

namespace ROOT {
template class TReentrantRWLock<ROOT::TSpinMutex, ROOT::Internal::RecurseCounts>;
template class TReentrantRWLock<TMutex, ROOT::Internal::RecurseCounts>;
template class TReentrantRWLock<std::mutex, ROOT::Internal::RecurseCounts>;

template class TReentrantRWLock<ROOT::TSpinMutex, ROOT::Internal::UniqueLockRecurseCount>;
template class TReentrantRWLock<TMutex, ROOT::Internal::UniqueLockRecurseCount>;
}
<|endoftext|>


<commit_before>#include <cassert>

#include "dg/SystemDependenceGraph/DependenceGraph.h"
#include "dg/SystemDependenceGraph/DGNode.h"
#include "dg/SystemDependenceGraph/DGNodeCall.h"
#include "dg/SystemDependenceGraph/DGArgumentPair.h"
#include "dg/SystemDependenceGraph/DGParameters.h"

namespace dg {
namespace sdg {

// ------------------------------------------------------------------
// -- Parameters --
// ------------------------------------------------------------------

DGArgumentPair::DGArgumentPair(DGParameters& p)
: DGElement(p.getDG(), DGElementType::ARG_PAIR),
  _parameters(p), _input(p.getDG()), _output(p.getDG()) {}

DGActualParameters::DGActualParameters(DGNodeCall& call)
: DGParameters(call.getDG()), _call(call) {}

DGNodeArtificial& DGFormalParameters::createVarArg() {
    auto& dg = getDG();
    _vararg.reset(&dg.createArtificial());
    return *_vararg.get();
}

DGNode& DGParameters::createNoReturn() {
    auto& dg = getDG();
    _noreturn.reset(&dg.createArtificial());
    return *_noreturn.get();
}

// ------------------------------------------------------------------
// -- Node --
// ------------------------------------------------------------------

unsigned DGNode::getNewID(DependenceGraph& g) {
    assert(_id == 0 && "Used outside of ctor");
    return g.getNextNodeID();
}

DGNode::DGNode(DependenceGraph& g, DGElementType t)
: DGElement(g, t), _id(getNewID(g)) {}

} // namespace sdg
} // namespace dg

<commit_msg>sdg: remove invalid assertion<commit_after>#include <cassert>

#include "dg/SystemDependenceGraph/DependenceGraph.h"
#include "dg/SystemDependenceGraph/DGNode.h"
#include "dg/SystemDependenceGraph/DGNodeCall.h"
#include "dg/SystemDependenceGraph/DGArgumentPair.h"
#include "dg/SystemDependenceGraph/DGParameters.h"

namespace dg {
namespace sdg {

// ------------------------------------------------------------------
// -- Parameters --
// ------------------------------------------------------------------

DGArgumentPair::DGArgumentPair(DGParameters& p)
: DGElement(p.getDG(), DGElementType::ARG_PAIR),
  _parameters(p), _input(p.getDG()), _output(p.getDG()) {}

DGActualParameters::DGActualParameters(DGNodeCall& call)
: DGParameters(call.getDG()), _call(call) {}

DGNodeArtificial& DGFormalParameters::createVarArg() {
    auto& dg = getDG();
    _vararg.reset(&dg.createArtificial());
    return *_vararg.get();
}

DGNode& DGParameters::createNoReturn() {
    auto& dg = getDG();
    _noreturn.reset(&dg.createArtificial());
    return *_noreturn.get();
}

// ------------------------------------------------------------------
// -- Node --
// ------------------------------------------------------------------

unsigned DGNode::getNewID(DependenceGraph& g) {
    return g.getNextNodeID();
}

DGNode::DGNode(DependenceGraph& g, DGElementType t)
: DGElement(g, t), _id(getNewID(g)) {}

} // namespace sdg
} // namespace dg

<|endoftext|>


<commit_before>#include "dsa/message.h"
#include "gtest/gtest.h"

using namespace dsa;

class SetRequestMessageExt : public SetRequestMessage {
 public:
  SetRequestMessageExt() : SetRequestMessage() {}

  bool check_static_headers(uint8_t *expected_values, size_t size) {
    uint8_t buf[1024];
    static_headers.write(buf);

    return (memcmp(expected_values, buf, size) == 0);
  }
};

class SetResponseMessageExt : public SetResponseMessage {
 public:
  SetResponseMessageExt() : SetResponseMessage() {}

  bool check_static_headers(uint8_t *expected_values, size_t size) {
    uint8_t buf[1024];
    static_headers.write(buf);

    return (memcmp(expected_values, buf, size) == 0);
  }
};

TEST(MessageTest, SetRequest__Constructor_01) {
  // public methods
  // SetRequestMessage();

  SetRequestMessage request;

  EXPECT_EQ(15, request.size());
  EXPECT_EQ(0, request.get_sequence_id());
  EXPECT_EQ(0, request.get_page_id());
  EXPECT_EQ(MessageType::SetRequest, request.type());
  EXPECT_EQ(true, request.is_request());
  EXPECT_EQ(0, request.request_id());

  EXPECT_EQ(false, request.get_priority());
  EXPECT_EQ("", request.get_target_path());
  EXPECT_EQ("", request.get_permission_token());
  EXPECT_EQ(false, request.get_no_stream());
  EXPECT_EQ(0, request.get_alias_count());
}

TEST(MessageTest, SetRequest__Constructor_02) {
  //   SetRequestMessage(const SetRequestMessage&);

  const SetRequestMessage src__request;
  SetRequestMessage target__request(src__request);

  EXPECT_EQ(15, target__request.size());
  EXPECT_EQ(0, target__request.get_sequence_id());
  EXPECT_EQ(0, target__request.get_page_id());
  EXPECT_EQ(MessageType::SetRequest, target__request.type());
  EXPECT_EQ(true, target__request.is_request());
  EXPECT_EQ(0, target__request.request_id());

  EXPECT_EQ(false, target__request.get_priority());
  EXPECT_EQ("", target__request.get_target_path());
  EXPECT_EQ("", target__request.get_permission_token());
  EXPECT_EQ(false, target__request.get_no_stream());
  EXPECT_EQ(0, target__request.get_alias_count());

  std::string target_path("path/to/abc");
  target__request.set_target_path(target_path);

  EXPECT_EQ("", src__request.get_target_path());
  EXPECT_EQ(target_path, target__request.get_target_path());

  EXPECT_EQ(29, target__request.size());
}

TEST(MessageTest, SetRequest__Constructor_03) {
  //   SetRequestMessage(const uint8_t* data, size_t size);

  const uint8_t data[] = {0xf, 0x0, 0x0, 0x0, 0xf, 0x0, 0x4, 0x0,
                          0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
  size_t data_size = sizeof(data) / sizeof(uint8_t);

  SetRequestMessage request(data, data_size);

  EXPECT_EQ(15, request.size());
  EXPECT_EQ(0, request.get_sequence_id());
  EXPECT_EQ(0, request.get_page_id());
  EXPECT_EQ(MessageType::SetRequest, request.type());
  EXPECT_EQ(true, request.is_request());
  EXPECT_EQ(0, request.request_id());

  EXPECT_EQ(false, request.get_priority());
  EXPECT_EQ("", request.get_target_path());
  EXPECT_EQ("", request.get_permission_token());
  EXPECT_EQ(false, request.get_no_stream());
  EXPECT_EQ(0, request.get_alias_count());
}

TEST(MessageTest, SetRequest__Constructor_04) {
  //   SetRequestMessage(const uint8_t* data, size_t size);

  SetRequestMessage request;
  request.set_target_path("/request");
  SetRequestMessage other = request;
  EXPECT_EQ("/request", other.get_target_path());
  other.set_target_path("/other");
  EXPECT_EQ("/request", request.get_target_path());
  EXPECT_EQ("/other", other.get_target_path());

  EXPECT_EQ(24, other.size());
  EXPECT_EQ(0, other.get_sequence_id());
  EXPECT_EQ(0, other.get_page_id());
  EXPECT_EQ(MessageType::SetRequest, other.type());
  EXPECT_EQ(true, other.is_request());
  EXPECT_EQ(0, other.request_id());

  EXPECT_EQ(false, other.get_priority());
  EXPECT_EQ("/other", other.get_target_path());
  EXPECT_EQ("", other.get_permission_token());
  EXPECT_EQ(false, other.get_no_stream());
  EXPECT_EQ(0, other.get_alias_count());
}

TEST(MessageTest, SetRequest__get_set_options) {
  //   SetOptions get_set_options() const;

  SetRequestMessage request;
  SetOptions option = request.get_set_options();

  EXPECT_EQ(1, sizeof(option));
}

TEST(MessageTest, SetRequest__update_static_header) {
  // void update_static_header();
  SetRequestMessageExt request;
  request.size();

  uint8_t expect_values[] = {0xf, 0x0, 0x0, 0x0, 0xf, 0x0};
  EXPECT_EQ(true,
            request.check_static_headers(
                expect_values, sizeof(expect_values) / sizeof(uint8_t)));
}

TEST(MessageTest, SetRequest__priority) {
  SetRequestMessage request;

  EXPECT_EQ(false, request.get_priority());
  request.set_priority(true);
  EXPECT_EQ(true, request.get_priority());
}

TEST(MessageTest, SetRequest__target_path) {
  SetRequestMessage request;

  EXPECT_EQ("", request.get_target_path());
  request.set_target_path("path/to/node");
  EXPECT_EQ("path/to/node", request.get_target_path());
}

TEST(MessageTest, SetRequest__permission_token) {
  // TODO: to be implemented
  SetRequestMessage request;

  EXPECT_EQ("", request.get_permission_token());
  request.set_permission_token("permission-token");
  EXPECT_EQ("permission-token", request.get_permission_token());
}

TEST(MessageTest, SetRequest__no_stream) {
  SetRequestMessage request;

  EXPECT_EQ(false, request.get_no_stream());
  request.set_no_stream(true);
  EXPECT_EQ(true, request.get_no_stream());
}

TEST(MessageTest, SetRequest__write) {
  SetRequestMessage request;

  request.set_target_path("path/to/dsa");
  request.set_no_stream(true);

  request.size();

  uint8_t buf[1024];
  request.write(buf);

  uint8_t expected_values[] = {0x1e, 0x0,  0x0,  0x0,  0x1e, 0x0,  0x4,  0x0,
                               0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x80,
                               0x0b, 0x0,  0x70, 0x61, 0x74, 0x68, 0x2f, 0x74,
                               0x6f, 0x2f, 0x64, 0x73, 0x61, 0x11};

  EXPECT_EQ(0, memcmp(expected_values, buf,
                      sizeof(expected_values) / sizeof(uint8_t)));
}

TEST(MessageTest, SetRequest__dynamic_structure) {
  SetRequestMessage request;

  //    request.set_status(MessageStatus::Closed);
  request.set_sequence_id(1234);  // no effect
  request.set_page_id(4321);      // no effect
  request.set_alias_count(11);
  request.set_priority(true);
  //      request.set_no_stream(); // TODO: TBI
  //      request.set_qos(1); //
  //      request.set_queue_size();
  //      request.set_queue_time();
  //      request.set_base_path();
  //      request.skippable();
  //      request.set_max_permission();
  request.set_permission_token("ptoken");
  request.set_target_path("/target/path");
  //    request.set_source_path("/source/path");  // no effect

  request.size();

  uint8_t buf[1024];
  request.write(buf);

  uint8_t expected_values[] = {
      0x2f, 0x0,  0x0,  0x0,  0x2f, 0x0,  0x04, 0x0,  0x0,  0x0,  0x0,  0x0,
      0x0,  0x0,  0x0,  0x10, 0x02, 0xe1, 0x10, 0x0,  0x0,  0x08, 0x0b, 0x80,
      0x0c, 0x0,  0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, 0x70, 0x61,
      0x74, 0x68, 0x60, 0x06, 0x0,  0x70, 0x74, 0x6f, 0x6b, 0x65, 0x6e};

  EXPECT_EQ(0, memcmp(expected_values, buf,
                      sizeof(expected_values) / sizeof(uint8_t)));
}

TEST(MessageTest, SetResponse__Constructor) {
  SetResponseMessage response;

  EXPECT_EQ(15, response.size());
  EXPECT_EQ(0, response.get_sequence_id());
  EXPECT_EQ(0, response.get_page_id());
  EXPECT_EQ(MessageType::SetResponse, response.type());
  EXPECT_EQ(false, response.is_request());
  EXPECT_EQ(0, response.request_id());
}

TEST(MessageTest, SetResponse__source_path) {
  SetResponseMessage response;

  EXPECT_EQ("", response.get_source_path());
  response.set_source_path("/source/path");
  EXPECT_EQ("/source/path", response.get_source_path());
}

TEST(MessageTest, SetResponse__status) {
  SetResponseMessage response;

  static const MessageStatus message_status_all[]{
      MessageStatus::Ok,
      MessageStatus::Initializing,
      MessageStatus::Refreshed,
      MessageStatus::NotAvailable,
      MessageStatus::Closed,
      MessageStatus::Disconnected,
      MessageStatus::PermissionDenied,
      MessageStatus::InvalidMessage,
      MessageStatus::InvalidParameter,
      MessageStatus::Busy,
      MessageStatus::AliasLoop,
      MessageStatus::ConnectionError,
  };
  for (const auto status : message_status_all) {
    response.set_status(status);
    EXPECT_EQ(status, response.get_status());
  }
}

TEST(MessageTest, SetResponse__write) {
  SetResponseMessage response;

  response.set_source_path("source/path");
  response.set_status(MessageStatus::Busy);

  response.size();

  uint8_t buf[1024];
  response.write(buf);

  uint8_t expected_values[] = {0x11, 0x0, 0x0, 0x0, 0x11, 0x0, 0x84, 0x0, 0x0,
                               0x0,  0x0, 0x0, 0x0, 0x0,  0x0, 0x0,  0x28};

  EXPECT_EQ(0, memcmp(expected_values, buf,
                      sizeof(expected_values) / sizeof(uint8_t)));
}

TEST(MessageTest, SetResponse__dynamic_structure) {
  SetResponseMessage response;

  response.set_status(MessageStatus::Closed);
  response.set_sequence_id(1234);  // no effect
  response.set_page_id(4321);      // no effect
                                   //  response.set_alias_count(11);
                                   //  response.set_priority(0x80); // TODO: TBI
                                   //  response.set_no_stream();
                                   //  response.set_qos(1); //
                                   //  response.set_queue_size();
                                   //  response.set_queue_time();
                                   //  response.set_base_path();
                                   //  response.skippable();
                                   //  response.set_max_permission();
                                   //  response.set_permission_token();
                                   //  response.set_target_path("/target/path");
  response.set_source_path("/source/path");  // no effect

  response.size();

  uint8_t buf[1024];
  response.write(buf);

  uint8_t expected_values[] = {0x11, 0x0, 0x0, 0x0, 0x11, 0x0, 0x84, 0x0, 0x0,
                               0x0,  0x0, 0x0, 0x0, 0x0,  0x0, 0x0,  0x10};

  EXPECT_EQ(0, memcmp(expected_values, buf,
                      sizeof(expected_values) / sizeof(uint8_t)));
}
<commit_msg>correct set message's unittest<commit_after>#include "dsa/message.h"
#include "gtest/gtest.h"

using namespace dsa;

class SetRequestMessageExt : public SetRequestMessage {
 public:
  SetRequestMessageExt() : SetRequestMessage() {}

  bool check_static_headers(uint8_t *expected_values, size_t size) {
    uint8_t buf[1024];
    static_headers.write(buf);

    return (memcmp(expected_values, buf, size) == 0);
  }
};

class SetResponseMessageExt : public SetResponseMessage {
 public:
  SetResponseMessageExt() : SetResponseMessage() {}

  bool check_static_headers(uint8_t *expected_values, size_t size) {
    uint8_t buf[1024];
    static_headers.write(buf);

    return (memcmp(expected_values, buf, size) == 0);
  }
};

TEST(MessageTest, SetRequest__Constructor_01) {
  // public methods
  // SetRequestMessage();

  SetRequestMessage request;

  EXPECT_EQ(15, request.size());
  EXPECT_EQ(0, request.get_sequence_id());
  EXPECT_EQ(0, request.get_page_id());
  EXPECT_EQ(MessageType::SetRequest, request.type());
  EXPECT_EQ(true, request.is_request());
  EXPECT_EQ(0, request.request_id());

  EXPECT_EQ(false, request.get_priority());
  EXPECT_EQ("", request.get_target_path());
  EXPECT_EQ("", request.get_permission_token());
  EXPECT_EQ(false, request.get_no_stream());
  EXPECT_EQ(0, request.get_alias_count());
}

TEST(MessageTest, SetRequest__Constructor_02) {
  //   SetRequestMessage(const SetRequestMessage&);

  const SetRequestMessage src__request;
  SetRequestMessage target__request(src__request);

  EXPECT_EQ(15, target__request.size());
  EXPECT_EQ(0, target__request.get_sequence_id());
  EXPECT_EQ(0, target__request.get_page_id());
  EXPECT_EQ(MessageType::SetRequest, target__request.type());
  EXPECT_EQ(true, target__request.is_request());
  EXPECT_EQ(0, target__request.request_id());

  EXPECT_EQ(false, target__request.get_priority());
  EXPECT_EQ("", target__request.get_target_path());
  EXPECT_EQ("", target__request.get_permission_token());
  EXPECT_EQ(false, target__request.get_no_stream());
  EXPECT_EQ(0, target__request.get_alias_count());

  std::string target_path("path/to/abc");
  target__request.set_target_path(target_path);

  EXPECT_EQ("", src__request.get_target_path());
  EXPECT_EQ(target_path, target__request.get_target_path());

  EXPECT_EQ(29, target__request.size());
}

TEST(MessageTest, SetRequest__Constructor_03) {
  //   SetRequestMessage(const uint8_t* data, size_t size);

  const uint8_t data[] = {0xf, 0x0, 0x0, 0x0, 0xf, 0x0, 0x4, 0x0,
                          0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
  size_t data_size = sizeof(data) / sizeof(uint8_t);

  SetRequestMessage request(data, data_size);

  EXPECT_EQ(15, request.size());
  EXPECT_EQ(0, request.get_sequence_id());
  EXPECT_EQ(0, request.get_page_id());
  EXPECT_EQ(MessageType::SetRequest, request.type());
  EXPECT_EQ(true, request.is_request());
  EXPECT_EQ(0, request.request_id());

  EXPECT_EQ(false, request.get_priority());
  EXPECT_EQ("", request.get_target_path());
  EXPECT_EQ("", request.get_permission_token());
  EXPECT_EQ(false, request.get_no_stream());
  EXPECT_EQ(0, request.get_alias_count());
}

TEST(MessageTest, SetRequest__Constructor_04) {
  //   SetRequestMessage(const uint8_t* data, size_t size);

  SetRequestMessage request;
  request.set_target_path("/request");
  SetRequestMessage other = request;
  EXPECT_EQ("/request", other.get_target_path());
  other.set_target_path("/other");
  EXPECT_EQ("/request", request.get_target_path());
  EXPECT_EQ("/other", other.get_target_path());

  EXPECT_EQ(24, other.size());
  EXPECT_EQ(0, other.get_sequence_id());
  EXPECT_EQ(0, other.get_page_id());
  EXPECT_EQ(MessageType::SetRequest, other.type());
  EXPECT_EQ(true, other.is_request());
  EXPECT_EQ(0, other.request_id());

  EXPECT_EQ(false, other.get_priority());
  EXPECT_EQ("/other", other.get_target_path());
  EXPECT_EQ("", other.get_permission_token());
  EXPECT_EQ(false, other.get_no_stream());
  EXPECT_EQ(0, other.get_alias_count());
}

TEST(MessageTest, SetRequest__get_set_options) {
  //   SetOptions get_set_options() const;

  SetRequestMessage request;
  SetOptions option = request.get_set_options();

  EXPECT_EQ(1, sizeof(option));
}

TEST(MessageTest, SetRequest__update_static_header) {
  // void update_static_header();
  SetRequestMessageExt request;
  request.size();

  uint8_t expect_values[] = {0xf, 0x0, 0x0, 0x0, 0xf, 0x0};
  EXPECT_EQ(true,
            request.check_static_headers(
                expect_values, sizeof(expect_values) / sizeof(uint8_t)));
}

TEST(MessageTest, SetRequest__priority) {
  SetRequestMessage request;

  EXPECT_EQ(false, request.get_priority());
  request.set_priority(true);
  EXPECT_EQ(true, request.get_priority());
}

TEST(MessageTest, SetRequest__target_path) {
  SetRequestMessage request;

  EXPECT_EQ("", request.get_target_path());
  request.set_target_path("path/to/node");
  EXPECT_EQ("path/to/node", request.get_target_path());
}

TEST(MessageTest, SetRequest__permission_token) {
  // TODO: to be implemented
  SetRequestMessage request;

  EXPECT_EQ("", request.get_permission_token());
  request.set_permission_token("permission-token");
  EXPECT_EQ("permission-token", request.get_permission_token());
}

TEST(MessageTest, SetRequest__no_stream) {
  SetRequestMessage request;

  EXPECT_EQ(false, request.get_no_stream());
  request.set_no_stream(true);
  EXPECT_EQ(true, request.get_no_stream());
}

TEST(MessageTest, SetRequest__write) {
  SetRequestMessage request;

  request.set_target_path("path/to/dsa");
  request.set_no_stream(true);

  request.size();

  uint8_t buf[1024];
  request.write(buf);

  uint8_t expected_values[] = {0x1e, 0x0,  0x0,  0x0,  0x1e, 0x0,  0x4,  0x0,
                               0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x80,
                               0x0b, 0x0,  0x70, 0x61, 0x74, 0x68, 0x2f, 0x74,
                               0x6f, 0x2f, 0x64, 0x73, 0x61, 0x11};

  EXPECT_EQ(0, memcmp(expected_values, buf,
                      sizeof(expected_values) / sizeof(uint8_t)));
}

TEST(MessageTest, SetRequest__dynamic_structure) {
  SetRequestMessage request;

  //    request.set_status(MessageStatus::Closed);
  request.set_sequence_id(1234);  // no effect
  request.set_page_id(4321);
  request.set_alias_count(11);
  request.set_priority(true);
  request.set_no_stream(true);
  //      request.set_qos(1); //
  //      request.set_queue_size();
  //      request.set_queue_time();
  //      request.set_base_path();
  //      request.skippable();
  //      request.set_max_permission();
  request.set_permission_token("ptoken");
  request.set_target_path("/target/path");
  //    request.set_source_path("/source/path");  // no effect

  request.size();

  uint8_t buf[1024];
  request.write(buf);

  uint8_t expected_values[] = {
      0x30, 0x0,  0x0,  0x0,  0x30, 0x0,  0x04, 0x0,  0x0,  0x0,  0x0,  0x0,
      0x0,  0x0,  0x0,  0x10, 0x02, 0xe1, 0x10, 0x0,  0x0,  0x08, 0x0b, 0x80,
      0x0c, 0x0,  0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, 0x70, 0x61,
      0x74, 0x68, 0x60, 0x06, 0x0,  0x70, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x11};

  EXPECT_EQ(0, memcmp(expected_values, buf,
                      sizeof(expected_values) / sizeof(uint8_t)));
}

TEST(MessageTest, SetResponse__Constructor) {
  SetResponseMessage response;

  EXPECT_EQ(15, response.size());
  EXPECT_EQ(0, response.get_sequence_id());
  EXPECT_EQ(0, response.get_page_id());
  EXPECT_EQ(MessageType::SetResponse, response.type());
  EXPECT_EQ(false, response.is_request());
  EXPECT_EQ(0, response.request_id());
}

TEST(MessageTest, SetResponse__source_path) {
  SetResponseMessage response;

  EXPECT_EQ("", response.get_source_path());
  response.set_source_path("/source/path");
  EXPECT_EQ("/source/path", response.get_source_path());
}

TEST(MessageTest, SetResponse__status) {
  SetResponseMessage response;

  static const MessageStatus message_status_all[]{
      MessageStatus::Ok,
      MessageStatus::Initializing,
      MessageStatus::Refreshed,
      MessageStatus::NotAvailable,
      MessageStatus::Closed,
      MessageStatus::Disconnected,
      MessageStatus::PermissionDenied,
      MessageStatus::InvalidMessage,
      MessageStatus::InvalidParameter,
      MessageStatus::Busy,
      MessageStatus::AliasLoop,
      MessageStatus::ConnectionError,
  };
  for (const auto status : message_status_all) {
    response.set_status(status);
    EXPECT_EQ(status, response.get_status());
  }
}

TEST(MessageTest, SetResponse__write) {
  SetResponseMessage response;

  response.set_source_path("source/path");
  response.set_status(MessageStatus::Busy);

  response.size();

  uint8_t buf[1024];
  response.write(buf);

  uint8_t expected_values[] = {0x11, 0x0, 0x0, 0x0, 0x11, 0x0, 0x84, 0x0, 0x0,
                               0x0,  0x0, 0x0, 0x0, 0x0,  0x0, 0x0,  0x28};

  EXPECT_EQ(0, memcmp(expected_values, buf,
                      sizeof(expected_values) / sizeof(uint8_t)));
}

TEST(MessageTest, SetResponse__dynamic_structure) {
  SetResponseMessage response;

  response.set_status(MessageStatus::Closed);
  response.set_sequence_id(1234);  // no effect
  response.set_page_id(4321);      // no effect
  //  response.set_alias_count(11);
  //  response.set_priority(true);
  //  response.set_no_stream(true);
  //  response.set_qos(1); //
  //  response.set_queue_size();
  //  response.set_queue_time();
  //  response.set_base_path();
  //  response.skippable();
  //  response.set_max_permission();
  //  response.set_permission_token();
  //  response.set_target_path("/target/path");
  response.set_source_path("/source/path");  // no effect

  response.size();

  uint8_t buf[1024];
  response.write(buf);

  uint8_t expected_values[] = {0x11, 0x0, 0x0, 0x0, 0x11, 0x0, 0x84, 0x0, 0x0,
                               0x0,  0x0, 0x0, 0x0, 0x0,  0x0, 0x0,  0x10};

  EXPECT_EQ(0, memcmp(expected_values, buf,
                      sizeof(expected_values) / sizeof(uint8_t)));
}
<|endoftext|>


<commit_before>#include "dsa/network.h"
#include "dsa/message.h"
#include "gtest/gtest.h"

using namespace dsa;

TEST(RequesterTest, basic_flow) {

  shared_ptr_<App> app;
  ASSERT_NO_FATAL_FAILURE(app.reset(new App("RequesterTest")));

  app->async_start(2);

  Server::Config server_config("/test/path", 8080);
  Client::Config client_config("127.0.0.1", 8080);

  ServerPtr tcp_server(app->new_server(Server::TCP, server_config));
  tcp_server->start();

  app->sleep(500);

  ClientPtr tcp_client(app->new_client(Client::TCP, client_config));
  tcp_client->connect();

  // requester = client->session()->requester();

  // stream = requester.subscribe("/abc", func);
  // stream.close();

  // Construct a subscribe message request
  SubscribeRequestMessage subscribe_request;
  subscribe_request.set_qos(StreamQos::_2);
  subscribe_request.set_target_path("/path/name");

  shared_ptr_<Buffer> b = make_shared_<Buffer>(256);
  subscribe_request.write(b->data());

  app->sleep(2000);

  app->graceful_stop(1000);

  app->wait();
}
<commit_msg>correct the unittest<commit_after>#include "dsa/network.h"
#include "dsa/message.h"
#include "gtest/gtest.h"

using namespace dsa;

TEST(RequesterTest, basic_flow) {

  shared_ptr_<App> app;
  ASSERT_NO_FATAL_FAILURE(app.reset(new App("RequesterTest")));

  app->async_start(2);

  Server::Config server_config("/test/path", 8080);
  Client::Config client_config("127.0.0.1", 8080);

  ServerPtr tcp_server(app->new_server(Server::TCP, server_config));
  tcp_server->start();

  app->sleep(500);

  ClientPtr tcp_client(app->new_client(Client::TCP, client_config));
  tcp_client->connect();

  // requester = client->session()->requester();

  // stream = requester.subscribe("/abc", func);
  // stream.close();

  // Construct a subscribe message request
  SubscribeRequestMessage subscribe_request;
  subscribe_request.set_qos(StreamQos::_2);
  subscribe_request.set_target_path("/path/name");

  shared_ptr_<Buffer> b = make_shared_<Buffer>(256);
  // subscribe_request.write(b->data());

  app->sleep(2000);

  app->graceful_stop(1000);

  app->wait();
}
<|endoftext|>


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

#include "U16InputStream.h"

#include <assert.h>
#include <string.h>

#include <unicode/ucnv.h>

#include <algorithm>

const char* U16InputStream::DefaultEncoding = "utf-8";

namespace {

struct Override
{
    const char* input;
    const char* replacement;
};

// cf. HTML Living Standard 13.2.2.2 Character encodings
// cf. http://bugs.icu-project.org/trac/browser/icu/trunk/source/data/mappings/convrtrs.txt
Override overrides[] = {
    { "euc-kr", "windows-949" },
    { "euc-jp", "windows-51932" },    // ucnv_open() may not understand 'CP51932'.
    { "gb2312", "GBK" },
    { "gb_2312-80", "GBK" },
    // { "iso-2022-jp", "CP50220" },  // ucnv_open() may not understand 'CP50220'; iso-2022-jp appears to be the same as CP50220 in ICU.
    { "iso-8859-1", "windows-1252" },
    { "iso-8859-9", "windows-1254" },
    { "iso-8859-11", "windows-874" },
    { "ks_c_5601-1987", "windows-949" },
    { "shift_jis", "Windows-31j" },
    { "tis-620", "windows-874" },
    { "us-ascii", "windows-1252" }
};

}  // namespace

U16InputStream::U16InputStream(std::istream& stream, const std::string& optionalEncoding) :
    confidence(Certain),
    encoding(optionalEncoding),
    stream(stream)
{
    initializeConverter();
    encoding = checkEncoding(encoding);
    if (encoding.empty())
        confidence = Tentative;
}

U16InputStream::~U16InputStream()
{
    if (converter)
        ucnv_close(converter);
}

const char* U16InputStream::skipSpace(const char* p)
{
    while (*p) {
        if (strchr(" \t\r\n\f", *p) == 0)
            return p;
        ++p;
    }
    return p;
};

const char* U16InputStream::skipOver(const char* p, const char* target, size_t length)
{
    while (*p) {
        if (strncmp(p, target, length) == 0)
            return p + length;
        ++p;
    }
    return p;
};

void U16InputStream::detect(const char* p)
{
    if (confidence != Tentative)
        return;
    if (strncmp(p, "\xfe\xff", 2) == 0) {
        encoding = "utf-16be";
        confidence = Irrelevant;
        return;
    }
    if (strncmp(p, "\xff\xfe", 2) == 0) {
        encoding = "utf-16le";
        confidence = Irrelevant;
        return;
    }
    if (strncmp(p, "\xef\xbb\xbf", 3) == 0) {
        encoding = "utf-8";
        confidence = Irrelevant;
        return;
    }
    encoding = "";
}

std::string U16InputStream::checkEncoding(std::string value)
{
    // Remove any leading or trailing space characters
    std::string::iterator i = value.begin();
    while (i < value.end() && strchr("\t\n\f\r ", *i))
        ++i;
    value.erase(value.begin(), i);
    int j;
    for (j = value.length(); 0 < j && strchr("\t\n\f\r ", value[j - 1]); --j)
        ;
    value.erase(j, value.length());

    if (value.empty())
        return "";

    // Override character encoding
    for (Override* override = overrides;
         override < &overrides[sizeof overrides / sizeof overrides[0]];
         ++override) {
        if (!strcasecmp(value.c_str(), override->input)) {
            value = override->replacement;
            break;
        }
    }
    return value;
}

void U16InputStream::setEncoding(std::string value)
{
    value = checkEncoding(value);
    if (value.empty())
        value = DefaultEncoding;

    // Re-check encoding with ICU for conversion
    UErrorCode error = U_ZERO_ERROR;
    converter = ucnv_open(value.c_str(), &error);
    if (!converter) {
        value = DefaultEncoding;
        converter = ucnv_open(value.c_str(), &error);
        if (!converter)
            eof = true;
    }
    encoding = value;
}

void U16InputStream::initializeConverter()
{
    flush = false;
    eof = !stream;
    converter = 0;
    source = sourceLimit = sourceBuffer;
    target = targetBuffer;
    nextChar = target;
    lastChar = 0;
}

void U16InputStream::updateSource()
{
    assert(!flush);
    size_t count = sourceLimit - source;
    if (0 < count && sourceBuffer != source)
        memmove(sourceBuffer, source, count);
    source = sourceBuffer;
    sourceLimit = sourceBuffer + count;
    count = ChunkSize - count;
    if (0 < count) {
        stream.read(sourceLimit, count);
        count = stream.gcount();
        if (!converter) {
            if (encoding.empty()) {
                sourceLimit[count] = '\0';
                detect(sourceLimit);
            }
            setEncoding(encoding);
        }
        sourceLimit += count;
        if (count == 0)
            flush = true;
    }
}

void U16InputStream::readChunk()
{
    nextChar = target = targetBuffer;
    updateSource();
    UErrorCode err = U_ZERO_ERROR;
    ucnv_toUnicode(converter,
                   reinterpret_cast<UChar**>(&target),
                   reinterpret_cast<UChar*>(targetBuffer) + ChunkSize,
                   const_cast<const char**>(&source),
                   sourceLimit, 0, flush, &err);
}

U16InputStream::operator std::u16string()
{
    std::u16string text;
    char16_t c;
    while (getChar(c))
        text += c;
    return text;
}<commit_msg>(U16InputStream::detect) : Support the utf-16 encodings without BOM; cf. at-charset-029.<commit_after>/*
 * Copyright 2010-2012 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "U16InputStream.h"

#include <assert.h>
#include <string.h>

#include <unicode/ucnv.h>

#include <algorithm>

const char* U16InputStream::DefaultEncoding = "utf-8";

namespace {

struct Override
{
    const char* input;
    const char* replacement;
};

// cf. HTML Living Standard 13.2.2.2 Character encodings
// cf. http://bugs.icu-project.org/trac/browser/icu/trunk/source/data/mappings/convrtrs.txt
Override overrides[] = {
    { "euc-kr", "windows-949" },
    { "euc-jp", "windows-51932" },    // ucnv_open() may not understand 'CP51932'.
    { "gb2312", "GBK" },
    { "gb_2312-80", "GBK" },
    // { "iso-2022-jp", "CP50220" },  // ucnv_open() may not understand 'CP50220'; iso-2022-jp appears to be the same as CP50220 in ICU.
    { "iso-8859-1", "windows-1252" },
    { "iso-8859-9", "windows-1254" },
    { "iso-8859-11", "windows-874" },
    { "ks_c_5601-1987", "windows-949" },
    { "shift_jis", "Windows-31j" },
    { "tis-620", "windows-874" },
    { "us-ascii", "windows-1252" }
};

}  // namespace

U16InputStream::U16InputStream(std::istream& stream, const std::string& optionalEncoding) :
    confidence(Certain),
    encoding(optionalEncoding),
    stream(stream)
{
    initializeConverter();
    encoding = checkEncoding(encoding);
    if (encoding.empty())
        confidence = Tentative;
}

U16InputStream::~U16InputStream()
{
    if (converter)
        ucnv_close(converter);
}

const char* U16InputStream::skipSpace(const char* p)
{
    while (*p) {
        if (strchr(" \t\r\n\f", *p) == 0)
            return p;
        ++p;
    }
    return p;
};

const char* U16InputStream::skipOver(const char* p, const char* target, size_t length)
{
    while (*p) {
        if (strncmp(p, target, length) == 0)
            return p + length;
        ++p;
    }
    return p;
};

void U16InputStream::detect(const char* p)
{
    static char le[] = { 0x40, 0x00, 0x63, 0x00, 0x68, 0x00, 0x61, 0x00, 0x72, 0x00, 0x73, 0x00, 0x65, 0x00, 0x74, 0x00 };
    static char be[] = { 0x00, 0x40, 0x00, 0x63, 0x00, 0x68, 0x00, 0x61, 0x00, 0x72, 0x00, 0x73, 0x00, 0x65, 0x00, 0x74 };

    if (confidence != Tentative)
        return;
    if (strncmp(p, "\xfe\xff", 2) == 0 || strncmp(p, be, sizeof(be)) == 0) {
        encoding = "utf-16be";
        confidence = Irrelevant;
        return;
    }
    if (strncmp(p, "\xff\xfe", 2) == 0 || strncmp(p, le, sizeof(le)) == 0) {
        encoding = "utf-16le";
        confidence = Irrelevant;
        return;
    }
    if (strncmp(p, "\xef\xbb\xbf", 3) == 0) {
        encoding = "utf-8";
        confidence = Irrelevant;
        return;
    }
    encoding = "";
}

std::string U16InputStream::checkEncoding(std::string value)
{
    // Remove any leading or trailing space characters
    std::string::iterator i = value.begin();
    while (i < value.end() && strchr("\t\n\f\r ", *i))
        ++i;
    value.erase(value.begin(), i);
    int j;
    for (j = value.length(); 0 < j && strchr("\t\n\f\r ", value[j - 1]); --j)
        ;
    value.erase(j, value.length());

    if (value.empty())
        return "";

    // Override character encoding
    for (Override* override = overrides;
         override < &overrides[sizeof overrides / sizeof overrides[0]];
         ++override) {
        if (!strcasecmp(value.c_str(), override->input)) {
            value = override->replacement;
            break;
        }
    }
    return value;
}

void U16InputStream::setEncoding(std::string value)
{
    value = checkEncoding(value);
    if (value.empty())
        value = DefaultEncoding;

    // Re-check encoding with ICU for conversion
    UErrorCode error = U_ZERO_ERROR;
    converter = ucnv_open(value.c_str(), &error);
    if (!converter) {
        value = DefaultEncoding;
        converter = ucnv_open(value.c_str(), &error);
        if (!converter)
            eof = true;
    }
    encoding = value;
}

void U16InputStream::initializeConverter()
{
    flush = false;
    eof = !stream;
    converter = 0;
    source = sourceLimit = sourceBuffer;
    target = targetBuffer;
    nextChar = target;
    lastChar = 0;
}

void U16InputStream::updateSource()
{
    assert(!flush);
    size_t count = sourceLimit - source;
    if (0 < count && sourceBuffer != source)
        memmove(sourceBuffer, source, count);
    source = sourceBuffer;
    sourceLimit = sourceBuffer + count;
    count = ChunkSize - count;
    if (0 < count) {
        stream.read(sourceLimit, count);
        count = stream.gcount();
        if (!converter) {
            if (encoding.empty()) {
                sourceLimit[count] = '\0';
                detect(sourceLimit);
            }
            setEncoding(encoding);
        }
        sourceLimit += count;
        if (count == 0)
            flush = true;
    }
}

void U16InputStream::readChunk()
{
    nextChar = target = targetBuffer;
    updateSource();
    UErrorCode err = U_ZERO_ERROR;
    ucnv_toUnicode(converter,
                   reinterpret_cast<UChar**>(&target),
                   reinterpret_cast<UChar*>(targetBuffer) + ChunkSize,
                   const_cast<const char**>(&source),
                   sourceLimit, 0, flush, &err);
}

U16InputStream::operator std::u16string()
{
    std::u16string text;
    char16_t c;
    while (getChar(c))
        text += c;
    return text;
}<|endoftext|>


<commit_before>#include <cmath>
#include <cstdlib>
#include <ctime>
#include <string>
#include <sstream>
#include "StateSpace.h"
#include "PriorityQueue.h"
#include "State.h"
#include "encoder.h"
#include "CreateModule.h"

/**
 * @brief Gives a std::string representation of a primitive type
 *
 * @param x Primitive type such as int, double, long
 * @return std::string conversion of param x
 */
template<typename T> std::string to_string(T x) {
	return static_cast<std::ostringstream&>((std::ostringstream() << std::dec << x)).str();
}

//function to calculate a temperature for the select action function as a function of time
double temperature();

//function to select next action
int selectAction(PriorityQueue<int,double>& a_queue);

//function to update a q value
void updateQ(StateSpace & space, int action, State & new_state, State & old_state, double alpha, double gamma);

int main()
{
	// STUFF WE DONT UNDERSTAND, AND DONT NEED TO
	//__________________________________________________________________________________________
	//__________________________________________________________________________________________
	// Libraries to load
	std::string bodyLibName = "bodyinfo";
	std::string movementLibName = "movementtools";

	// Name of camera module in library
	std::string bodyModuleName = "BodyInfo";
	std::string movementModuleName = "MovementTools";

	// Set broker name, ip and port, finding first available port from 54000
	const std::string brokerName = "MotionTimingBroker";
	int brokerPort = qi::os::findAvailablePort(54000);
	const std::string brokerIp = "0.0.0.0";

	// Default parent port and ip
	int pport = 9559;
	std::string pip = "127.0.0.1";

	// Need this for SOAP serialisation of floats to work
	setlocale(LC_NUMERIC, "C");

	// Create a broker
	boost::shared_ptr<AL::ALBroker> broker;
	try
	{
		broker = AL::ALBroker::createBroker(
				brokerName,
				brokerIp,
				brokerPort,
				pip,
				pport,
				0);
	}
	// Throw error and quit if a broker could not be created
	catch(...)
	{
		std::cerr << "Failed to connect broker to: "
			  << pip
			  << ":"
			  << pport
			  << std::endl;
		AL::ALBrokerManager::getInstance()->killAllBroker();
		AL::ALBrokerManager::kill();

		return 1;
	}

	// Add the broker to NAOqi
	AL::ALBrokerManager::setInstance(broker->fBrokerManager.lock());
	AL::ALBrokerManager::getInstance()->addBroker(broker);

	CreateModule(movementLibName, movementModuleName, broker, false, true);
	CreateModule(bodyLibName, bodyModuleName, broker, false, true);

	AL::ALProxy bodyInfoProxy(bodyModuleName, pip, pport);
	AL::ALProxy movementToolsProxy(movementModuleName, pip, pport);
	AL::ALMotionProxy motion(pip, pport);
	//__________________________________________________________________________________________
	//__________________________________________________________________________________________
	//END OF STUFF WE DONT UNDERSTAND, BREATHE NOW

	//learning factor
	const double alpha=0.5;
	//discount factor
	const double gamma=0.5;

	//seed rng
	std::srand(std::time(NULL));

	int action_forwards = FORWARD;
	int action_backwards = BACKWARD;
	int chosen_action = &action_forwards;

	//create a priority queue to copy to all the state space priority queues
	PriorityQueue<int,double> initiator_queue(MAX);
	initiator_queue.enqueueWithPriority(action_forwards,0);
	initiator_queue.enqueueWithPriority(action_backwards,0);

	//create encoder
	Encoder encoder();
	encoder.calibrate();

	//create the state space
	StateSpace space(initiator_queue);
	space.setAngleBins(100);
	space.setVelocityBins(50);

	//state objects
	State current_state(0,0,FORWARD);
	State old_state(0,0,FORWARD);

	while(true)
	{
		current_state.theta= M_PI * encoder.GetAngle()/180;
		current_state.theta_dot=(current_state.theta - old_state.theta)/700; //Needs actual time
		current_state.robot_state=chosen_action;

		updateQ(space, chosen_action, old_state, current_state, alpha, gamma);

		old_state=current_state;

		chosen_action=selectAction(space[current_state]);

		(chosen_action)?movementToolsProxy.callVoid("swingForwards"):movementToolsProxy.callVoid("swingBackwards");
	}

	return 1;
}

double temperature()
{
	return std::time(NULL);
}

//function is fed with a priority queue of action-values
//generates Boltzmann distribution of these action-values
//and selects an action based on probabilities
int selectAction(PriorityQueue<int,double>& a_queue)
{
	typedef PriorityQueue<int,double> PQ;
	typedef std::vector< std::pair<int, double> > Vec_Pair;
	typedef std::pair<int, double> Pair;

	double sum= 0;
	int i = 0;

	int size = a_queue.getSize();
	Vec_Pair action_vec(size);

	//Calculate partition function by iterating over action-values
	for(PQ::const_iterator iter = a_queue.begin(),end=a_queue.end(); iter < end; ++iter)
	{
		sum += std::exp((iter->second)/temperature());
	}
	//Calculate boltzmann factors for action-values
	for(Vec_Pair::iterator it = action_vec.begin(),end=action_vec.end(); it < end; ++it)
	{
	    it->first = a_queue[i].first;
	    it->second = std::exp(a_queue[i].second /temperature()) / sum;
	    ++i;
	}

	//calculate cumulative probability distribution
	for(Vec_Pair::iterator it1 = action_vec.begin()++,it2 = action_vec.begin(),end=action_vec.end(); it < end; ++it1,++it2)
	{
	    it1->second += it2->second;
	}

	//generate RN between 0 and 1
	double rand_num = static_cast<double>(rand()/ (RAND_MAX));

	//select action based on probability
	for(Vec_Pair::iterator it = action_vec.begin(),end=action_vec.end(); it < end; ++it)
	{
		//if RN falls within cumulative probability bin return the corresponding action
		if(rand_num < it->second)return &(it->first);
	}

	return NULL; //note that this line should never be reached
}

void updateQ(StateSpace & space, int action, State & new_state, State & old_state, double alpha, double gamma)
{
    //oldQ value reference
    double oldQ = space[old_state].search(action).second;

    //reward given to current state
    double R = new_state.getReward();

    //optimal Q value for new state i.e. first element
    double maxQ = space[current_state].peekFront().second;

    //new Q value determined by Q learning algorithm
    double newQ = oldQ + alpha * (R + (gamma * maxQ) - oldQ);

    // change priority of action to new Q value
    space[old_state].changePriority(action, newQ);
}

<commit_msg>Update Main.cpp<commit_after>#include <cmath>
#include <cstdlib>
#include <ctime>
#include <string>
#include <sstream>
#include "StateSpace.h"
#include "PriorityQueue.h"
#include "State.h"
#include "encoder.h"
#include "CreateModule.h"

/**
 * @brief Gives a std::string representation of a primitive type
 *
 * @param x Primitive type such as int, double, long
 * @return std::string conversion of param x
 */
template<typename T> std::string to_string(T x) {
	return static_cast<std::ostringstream&>((std::ostringstream() << std::dec << x)).str();
}

//function to calculate a temperature for the select action function as a function of time
double temperature();

//function to select next action
int selectAction(PriorityQueue<int,double>& a_queue);

//function to update a q value
void updateQ(StateSpace & space, int action, State & new_state, State & old_state, double alpha, double gamma);

int main()
{
	// STUFF WE DONT UNDERSTAND, AND DONT NEED TO
	//__________________________________________________________________________________________
	//__________________________________________________________________________________________
	// Libraries to load
	std::string bodyLibName = "bodyinfo";
	std::string movementLibName = "movementtools";

	// Name of camera module in library
	std::string bodyModuleName = "BodyInfo";
	std::string movementModuleName = "MovementTools";

	// Set broker name, ip and port, finding first available port from 54000
	const std::string brokerName = "MotionTimingBroker";
	int brokerPort = qi::os::findAvailablePort(54000);
	const std::string brokerIp = "0.0.0.0";

	// Default parent port and ip
	int pport = 9559;
	std::string pip = "127.0.0.1";

	// Need this for SOAP serialisation of floats to work
	setlocale(LC_NUMERIC, "C");

	// Create a broker
	boost::shared_ptr<AL::ALBroker> broker;
	try
	{
		broker = AL::ALBroker::createBroker(
				brokerName,
				brokerIp,
				brokerPort,
				pip,
				pport,
				0);
	}
	// Throw error and quit if a broker could not be created
	catch(...)
	{
		std::cerr << "Failed to connect broker to: "
			  << pip
			  << ":"
			  << pport
			  << std::endl;
		AL::ALBrokerManager::getInstance()->killAllBroker();
		AL::ALBrokerManager::kill();

		return 1;
	}

	// Add the broker to NAOqi
	AL::ALBrokerManager::setInstance(broker->fBrokerManager.lock());
	AL::ALBrokerManager::getInstance()->addBroker(broker);

	CreateModule(movementLibName, movementModuleName, broker, false, true);
	CreateModule(bodyLibName, bodyModuleName, broker, false, true);

	AL::ALProxy bodyInfoProxy(bodyModuleName, pip, pport);
	AL::ALProxy movementToolsProxy(movementModuleName, pip, pport);
	AL::ALMotionProxy motion(pip, pport);
	//__________________________________________________________________________________________
	//__________________________________________________________________________________________
	//END OF STUFF WE DONT UNDERSTAND, BREATHE NOW

	//learning factor
	const double alpha=0.5;
	//discount factor
	const double gamma=0.5;

	//seed rng
	std::srand(std::time(NULL));

	int action_forwards = FORWARD;
	int action_backwards = BACKWARD;
	int chosen_action = action_forwards;

	//create a priority queue to copy to all the state space priority queues
	PriorityQueue<int,double> initiator_queue(MAX);
	initiator_queue.enqueueWithPriority(action_forwards,0);
	initiator_queue.enqueueWithPriority(action_backwards,0);

	//create encoder
	Encoder encoder();
	encoder.calibrate();

	//create the state space
	StateSpace space(initiator_queue);
	space.setAngleBins(100);
	space.setVelocityBins(50);

	//state objects
	State current_state(0,0,FORWARD);
	State old_state(0,0,FORWARD);

	while(true)
	{
		current_state.theta= M_PI * encoder.GetAngle()/180;
		current_state.theta_dot=(current_state.theta - old_state.theta)/700; //Needs actual time
		current_state.robot_state=chosen_action;

		updateQ(space, chosen_action, old_state, current_state, alpha, gamma);

		old_state=current_state;

		chosen_action=selectAction(space[current_state]);

		(chosen_action)?movementToolsProxy.callVoid("swingForwards"):movementToolsProxy.callVoid("swingBackwards");
	}

	return 1;
}

double temperature()
{
	return std::time(NULL);
}

//function is fed with a priority queue of action-values
//generates Boltzmann distribution of these action-values
//and selects an action based on probabilities
int selectAction(PriorityQueue<int,double>& a_queue)
{
	typedef PriorityQueue<int,double> PQ;
	typedef std::vector< std::pair<int, double> > Vec_Pair;
	typedef std::pair<int, double> Pair;

	double sum= 0;
	int i = 0;

	int size = a_queue.getSize();
	Vec_Pair action_vec(size);

	//Calculate partition function by iterating over action-values
	for(PQ::const_iterator iter = a_queue.begin(),end=a_queue.end(); iter < end; ++iter)
	{
		sum += std::exp((iter->second)/temperature());
	}
	//Calculate boltzmann factors for action-values
	for(Vec_Pair::iterator it = action_vec.begin(),end=action_vec.end(); it < end; ++it)
	{
	    it->first = a_queue[i].first;
	    it->second = std::exp(a_queue[i].second /temperature()) / sum;
	    ++i;
	}

	//calculate cumulative probability distribution
	for(Vec_Pair::iterator it1 = action_vec.begin()++,it2 = action_vec.begin(),end=action_vec.end(); it < end; ++it1,++it2)
	{
	    it1->second += it2->second;
	}

	//generate RN between 0 and 1
	double rand_num = static_cast<double>(rand()/ (RAND_MAX));

	//select action based on probability
	for(Vec_Pair::iterator it = action_vec.begin(),end=action_vec.end(); it < end; ++it)
	{
		//if RN falls within cumulative probability bin return the corresponding action
		if(rand_num < it->second)return it->first;
	}

	return NULL; //note that this line should never be reached
}

void updateQ(StateSpace & space, int action, State & new_state, State & old_state, double alpha, double gamma)
{
    //oldQ value reference
    double oldQ = space[old_state].search(action).second;

    //reward given to current state
    double R = new_state.getReward();

    //optimal Q value for new state i.e. first element
    double maxQ = space[current_state].peekFront().second;

    //new Q value determined by Q learning algorithm
    double newQ = oldQ + alpha * (R + (gamma * maxQ) - oldQ);

    // change priority of action to new Q value
    space[old_state].changePriority(action, newQ);
}

<|endoftext|>


<commit_before>//* This file is part of Zapdos, an open-source
//* application for the simulation of plasmas
//* https://github.com/shannon-lab/zapdos
//*
//* Zapdos is powered by the MOOSE Framework
//* https://www.mooseframework.org
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "LymberopoulosElectronBC.h"

registerMooseObject("ZapdosApp", LymberopoulosElectronBC);

template <>
InputParameters
validParams<LymberopoulosElectronBC>()
{
  InputParameters params = validParams<IntegratedBC>();
  params.addRequiredParam<Real>("ks", "The recombination coefficient");
  params.addRequiredParam<Real>("gamma", "The secondary electron coefficient");
  params.addRequiredCoupledVar("potential", "The electric potential");
  params.addRequiredCoupledVar("ion", "The ion density.");
  params.addRequiredParam<Real>("position_units", "Units of position.");
  params.addClassDescription("Simpified kinetic electron boundary condition"
                             "(Based on DOI: https://doi.org/10.1063/1.352926)");
  return params;
}

LymberopoulosElectronBC::LymberopoulosElectronBC(const InputParameters & parameters)
  : IntegratedBC(parameters),

    _r_units(1. / getParam<Real>("position_units")),
    _ks(getParam<Real>("ks")),
    _gamma(getParam<Real>("gamma")),

    // Coupled Variables
    _grad_potential(coupledGradient("potential")),
    _potential_id(coupled("potential")),
    _Arp(coupledValue("ion")),
    _grad_Arp(coupledGradient("ion")),
    _Arp_id(coupled("ion")),

    _muion(getMaterialProperty<Real>("mu" + (*getVar("ion", 0)).name())),
    _diffion(getMaterialProperty<Real>("diff" + (*getVar("ion", 0)).name())),

    _sign(1)
{
}

Real
LymberopoulosElectronBC::computeQpResidual()
{

  RealVectorValue _ion_flux =
      (_muion[_qp] * -_grad_potential[_qp] * _r_units * std::exp(_Arp[_qp]));

  // RealVectorValue _ion_flux = (_muion[_qp] * -_grad_potential[_qp] * _r_units *
  // std::exp(_Arp[_qp]) -
  //            _diffion[_qp] * std::exp(_Arp[_qp]) * _grad_Arp[_qp] * _r_units);

  return _test[_i][_qp] * _r_units *
         (_sign * _ks * std::exp(_u[_qp]) * _normals[_qp] * _normals[_qp] -
          _gamma * _ion_flux * _normals[_qp]);
}

Real
LymberopoulosElectronBC::computeQpJacobian()
{

  RealVectorValue _ion_flux =
      (_muion[_qp] * -_grad_potential[_qp] * _r_units * std::exp(_Arp[_qp]));

  // RealVectorValue _ion_flux = (_muion[_qp] * -_grad_potential[_qp] * _r_units *
  // std::exp(_Arp[_qp]) -
  //            _diffion[_qp] * std::exp(_Arp[_qp]) * _grad_Arp[_qp] * _r_units);

  return _test[_i][_qp] * _r_units *
         (_sign * _ks * std::exp(_u[_qp]) * _phi[_j][_qp] * _normals[_qp] * _normals[_qp]);
}

Real
LymberopoulosElectronBC::computeQpOffDiagJacobian(unsigned int jvar) // need to fix
{
  if (jvar == _potential_id)
  {

    RealVectorValue _d_ion_flux_d_V =
        (_muion[_qp] * -_grad_phi[_j][_qp] * _r_units * std::exp(_Arp[_qp]));

    // RealVectorValue _d_ion_flux_d_V = (_muion[_qp] * -_grad_phi[_j][_qp] * _r_units *
    // std::exp(_Arp[_qp]) -
    //            _diffion[_qp] * std::exp(_Arp[_qp]) * _grad_Arp[_qp] * _r_units);

    return _test[_i][_qp] * _r_units * ((-_gamma * _d_ion_flux_d_V * _normals[_qp]));
  }

  else if (jvar == _Arp_id)
  {

    RealVectorValue _d_ion_flux_d_ion =
        (_muion[_qp] * -_grad_potential[_qp] * _r_units * std::exp(_Arp[_qp]) * _phi[_j][_qp]);

    // RealVectorValue _d_ion_flux_d_ion = (_muion[_qp] * -_grad_potential[_qp] * _r_units *
    // std::exp(_Arp[_qp]) * _phi[_j][_qp] -
    //                      _diffion[_qp] * (std::exp(_Arp[_qp]) * _grad_phi[_j][_qp] * _r_units +
    //                      std::exp(_Arp[_qp]) * _phi[_j][_qp] * _grad_Arp[_qp] * _r_units));

    return _test[_i][_qp] * _r_units * ((-_gamma * _d_ion_flux_d_ion * _normals[_qp]));
  }

  else
    return 0.0;
}
<commit_msg>Move comment in LymberopoulosElectronBC to avoid clang format complaint<commit_after>//* This file is part of Zapdos, an open-source
//* application for the simulation of plasmas
//* https://github.com/shannon-lab/zapdos
//*
//* Zapdos is powered by the MOOSE Framework
//* https://www.mooseframework.org
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "LymberopoulosElectronBC.h"

registerMooseObject("ZapdosApp", LymberopoulosElectronBC);

template <>
InputParameters
validParams<LymberopoulosElectronBC>()
{
  InputParameters params = validParams<IntegratedBC>();
  params.addRequiredParam<Real>("ks", "The recombination coefficient");
  params.addRequiredParam<Real>("gamma", "The secondary electron coefficient");
  params.addRequiredCoupledVar("potential", "The electric potential");
  params.addRequiredCoupledVar("ion", "The ion density.");
  params.addRequiredParam<Real>("position_units", "Units of position.");
  params.addClassDescription("Simpified kinetic electron boundary condition"
                             "(Based on DOI: https://doi.org/10.1063/1.352926)");
  return params;
}

LymberopoulosElectronBC::LymberopoulosElectronBC(const InputParameters & parameters)
  : IntegratedBC(parameters),

    _r_units(1. / getParam<Real>("position_units")),
    _ks(getParam<Real>("ks")),
    _gamma(getParam<Real>("gamma")),

    // Coupled Variables
    _grad_potential(coupledGradient("potential")),
    _potential_id(coupled("potential")),
    _Arp(coupledValue("ion")),
    _grad_Arp(coupledGradient("ion")),
    _Arp_id(coupled("ion")),

    _muion(getMaterialProperty<Real>("mu" + (*getVar("ion", 0)).name())),
    _diffion(getMaterialProperty<Real>("diff" + (*getVar("ion", 0)).name())),

    _sign(1)
{
}

Real
LymberopoulosElectronBC::computeQpResidual()
{

  RealVectorValue _ion_flux =
      (_muion[_qp] * -_grad_potential[_qp] * _r_units * std::exp(_Arp[_qp]));

  // RealVectorValue _ion_flux = (_muion[_qp] * -_grad_potential[_qp] * _r_units *
  // std::exp(_Arp[_qp]) -
  //            _diffion[_qp] * std::exp(_Arp[_qp]) * _grad_Arp[_qp] * _r_units);

  return _test[_i][_qp] * _r_units *
         (_sign * _ks * std::exp(_u[_qp]) * _normals[_qp] * _normals[_qp] -
          _gamma * _ion_flux * _normals[_qp]);
}

Real
LymberopoulosElectronBC::computeQpJacobian()
{

  RealVectorValue _ion_flux =
      (_muion[_qp] * -_grad_potential[_qp] * _r_units * std::exp(_Arp[_qp]));

  // RealVectorValue _ion_flux = (_muion[_qp] * -_grad_potential[_qp] * _r_units *
  // std::exp(_Arp[_qp]) -
  //            _diffion[_qp] * std::exp(_Arp[_qp]) * _grad_Arp[_qp] * _r_units);

  return _test[_i][_qp] * _r_units *
         (_sign * _ks * std::exp(_u[_qp]) * _phi[_j][_qp] * _normals[_qp] * _normals[_qp]);
}

// need to fix
Real
LymberopoulosElectronBC::computeQpOffDiagJacobian(unsigned int jvar)
{
  if (jvar == _potential_id)
  {

    RealVectorValue _d_ion_flux_d_V =
        (_muion[_qp] * -_grad_phi[_j][_qp] * _r_units * std::exp(_Arp[_qp]));

    // RealVectorValue _d_ion_flux_d_V = (_muion[_qp] * -_grad_phi[_j][_qp] * _r_units *
    // std::exp(_Arp[_qp]) -
    //            _diffion[_qp] * std::exp(_Arp[_qp]) * _grad_Arp[_qp] * _r_units);

    return _test[_i][_qp] * _r_units * ((-_gamma * _d_ion_flux_d_V * _normals[_qp]));
  }

  else if (jvar == _Arp_id)
  {

    RealVectorValue _d_ion_flux_d_ion =
        (_muion[_qp] * -_grad_potential[_qp] * _r_units * std::exp(_Arp[_qp]) * _phi[_j][_qp]);

    // RealVectorValue _d_ion_flux_d_ion = (_muion[_qp] * -_grad_potential[_qp] * _r_units *
    // std::exp(_Arp[_qp]) * _phi[_j][_qp] -
    //                      _diffion[_qp] * (std::exp(_Arp[_qp]) * _grad_phi[_j][_qp] * _r_units +
    //                      std::exp(_Arp[_qp]) * _phi[_j][_qp] * _grad_Arp[_qp] * _r_units));

    return _test[_i][_qp] * _r_units * ((-_gamma * _d_ion_flux_d_ion * _normals[_qp]));
  }

  else
    return 0.0;
}
<|endoftext|>