<commit_before>#include <bf/counter_vector.h>

#include <cassert>

namespace bf {

counter_vector::counter_vector(size_t cells, size_t width)
  : bits_(cells * width), width_(width)
{
  assert(cells > 0);
  assert(width > 0);
}

bool counter_vector::increment(size_t cell, size_t value)
{
  assert(cell < size());
  assert(value != 0);
  size_t lsb = cell * width_;
  if (value >= max())
  {
    bool r = false;
    for (size_t i = 0; i < width_; ++i)
      if (! bits_[lsb + i])
      {
        bits_[lsb + i] = true;
        if (! r)
          r = true;
      }
    return r;
  }
  bool carry = false;
  for (size_t i = 0; i < width_; ++i)
  {
    bool b1 = bits_[lsb + i];
    bool b2 = value & (1 << i);
    bits_[lsb + i] ^= b2 != carry; // bit1 ^ bit2 ^ carry
    carry = carry ? b1 || b2 : b1 && b2;
  }
  if (! carry)
    return true;
  for (size_t i = 0; i < width_; ++i)
    bits_[lsb + i] = true;
  return false;
}

bool counter_vector::decrement(size_t cell, size_t value)
{
  assert(value == 1); // TODO: adapt function to values > 1.
  assert(cell < size());
  size_t lsb = cell * width_;
  for (auto i = lsb; i < lsb + width_; ++i)
    if (bits_[i])
    {
      bits_[i] = false;
      while (i && i > lsb)
        bits_[--i] = true;
      return true;
    }
  return false;
}

size_t counter_vector::count(size_t cell) const
{
  assert(cell < size());
  size_t cnt = 0, order = 1;
  size_t lsb = cell * width_;
  for (auto i = lsb; i < lsb + width_; ++i, order <<= 1)
    if (bits_[i])
      cnt |= order;
  return cnt;
}

void counter_vector::set(size_t cell, size_t value)
{
  assert(cell < size());
  assert(value <= max());
  bitvector bits(width_, value);
  auto lsb = cell * width_;
  for (size_t i = 0; i < width_; ++i)
    bits_[lsb + i] = bits[i];
}

void counter_vector::clear()
{
  bits_.reset();
}

size_t counter_vector::size() const
{
  return bits_.size() / width_;
}

size_t counter_vector::max() const
{
  using limits = std::numeric_limits<size_t>;
  return limits::max() >> (limits::digits - width());
}

size_t counter_vector::width() const
{
  return width_;
}

std::string to_string(counter_vector const& v, bool all, size_t cut_off)
{
  return to_string(v.bits_, false, all, cut_off);
}

} // namespace bf
<commit_msg>Implement brute-force decrement for values > 1.<commit_after>#include <bf/counter_vector.h>

#include <cassert>

namespace bf {

counter_vector::counter_vector(size_t cells, size_t width)
  : bits_(cells * width), width_(width)
{
  assert(cells > 0);
  assert(width > 0);
}

bool counter_vector::increment(size_t cell, size_t value)
{
  assert(cell < size());
  assert(value != 0);
  size_t lsb = cell * width_;
  if (value >= max())
  {
    bool r = false;
    for (size_t i = 0; i < width_; ++i)
      if (! bits_[lsb + i])
      {
        bits_[lsb + i] = true;
        if (! r)
          r = true;
      }
    return r;
  }
  bool carry = false;
  for (size_t i = 0; i < width_; ++i)
  {
    bool b1 = bits_[lsb + i];
    bool b2 = value & (1 << i);
    bits_[lsb + i] ^= b2 != carry; // bit1 ^ bit2 ^ carry
    carry = carry ? b1 || b2 : b1 && b2;
  }
  if (! carry)
    return true;
  for (size_t i = 0; i < width_; ++i)
    bits_[lsb + i] = true;
  return false;
}

bool counter_vector::decrement(size_t cell, size_t value)
{
  assert(cell < size());
  size_t lsb = cell * width_;
  bool success;
  while (value --> 0)
  {
    success = false;
    for (auto i = lsb; i < lsb + width_; ++i)
      if (bits_[i])
      {
        bits_[i] = false;
        while (i && i > lsb)
          bits_[--i] = true;
        success = true;
        break;
      }
  }
  return success;
}

size_t counter_vector::count(size_t cell) const
{
  assert(cell < size());
  size_t cnt = 0, order = 1;
  size_t lsb = cell * width_;
  for (auto i = lsb; i < lsb + width_; ++i, order <<= 1)
    if (bits_[i])
      cnt |= order;
  return cnt;
}

void counter_vector::set(size_t cell, size_t value)
{
  assert(cell < size());
  assert(value <= max());
  bitvector bits(width_, value);
  auto lsb = cell * width_;
  for (size_t i = 0; i < width_; ++i)
    bits_[lsb + i] = bits[i];
}

void counter_vector::clear()
{
  bits_.reset();
}

size_t counter_vector::size() const
{
  return bits_.size() / width_;
}

size_t counter_vector::max() const
{
  using limits = std::numeric_limits<size_t>;
  return limits::max() >> (limits::digits - width());
}

size_t counter_vector::width() const
{
  return width_;
}

std::string to_string(counter_vector const& v, bool all, size_t cut_off)
{
  return to_string(v.bits_, false, all, cut_off);
}

} // namespace bf
<|endoftext|>


<commit_before>/// \file TFormulaGradientTests.cxx
///
/// \brief The file contain unit tests which test the clad-based gradient
///        computations.
///
/// \author Vassil Vassilev <vvasilev@cern.ch>
///
/// \date Oct, 2018
///
/*************************************************************************
 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "ROOTUnitTestSupport.h"

#include <Math/MinimizerOptions.h>
#include <TFormula.h>
#include <TF1.h>
#include <TFitResult.h>

TEST(TFormulaGradientPar, Sanity)
{
   TFormula f("f", "x*std::sin([0]) - y*std::cos([1])");
   double p[] = {30, 60};
   f.SetParameters(p);
   double x[] = {1, 2};
   TFormula::GradientStorage result(2);
   f.GradientPar(x, result);

   ASSERT_FLOAT_EQ(x[0] * std::cos(30), result[0]);
   ASSERT_FLOAT_EQ(-x[1] * -std::sin(60), result[1]);
}

TEST(TFormulaGradientPar, ResultUpsize)
{
   TFormula f("f", "std::sin([1]) - std::cos([0])");
   double p[] = {60, 30};
   f.SetParameters(p);
   TFormula::GradientStorage result;
   double x[] = {2, 1};

   ASSERT_TRUE(0 == result.size());
   ROOT_EXPECT_WARNING(f.GradientPar(x, result),
                       "TFormula::GradientPar",
                       "The size of gradient result is 0 but 2 is required. Resizing."
                       );

   ASSERT_FLOAT_EQ(std::cos(30), result[1]);
   ASSERT_FLOAT_EQ(std::sin(60), result[0]);
   ASSERT_TRUE(2 == result.size());
}

TEST(TFormulaGradientPar, ResultDownsize)
{
   TFormula f("f", "std::sin([0])");
   double p[] = {60};
   f.SetParameters(p);
   TFormula::GradientStorage result(2);
   double x[] = {1};

   ASSERT_TRUE(2 == result.size());

   ROOT_EXPECT_NODIAG(f.GradientPar(x, result));

   ASSERT_FLOAT_EQ(std::cos(60), result[0]);
   ASSERT_TRUE(2 == result.size());
}

TEST(TFormulaGradientPar, GausCrossCheck)
{
   auto h = new TF1("f1", "gaus");
   // auto h = new TF1("f1", "landau"); -- inheritently does not work. See DIFLAN
   //crystalball, breitwigner, cheb3, bigaus,
   //auto h = new TF1("f1", "");
   double p[] = {3, 1, 2};
   h->SetParameters(p);
   double x[] = {0};
   TFormula::GradientStorage result_clad(3);
   h->GetFormula()->GradientPar(x, result_clad);

   TFormula::GradientStorage result_num(3);
   h->GradientPar(x, result_num.data());

   ASSERT_FLOAT_EQ(result_num[0], result_clad[0]);
   ASSERT_FLOAT_EQ(result_num[1], result_clad[1]);
   ASSERT_FLOAT_EQ(result_num[2], result_clad[2]);
}

TEST(TFormulaGradientPar, BreitWignerCrossCheck)
{
   auto h = new TF1("f1", "breitwigner");
   double p[] = {3, 1, 2.1};
   h->SetParameters(p);
   double x[] = {0};
   TFormula::GradientStorage result_clad(3);
   TFormula* formula = h->GetFormula();
   formula->GradientPar(x, result_clad);
   TFormula::GradientStorage result_num(3);
   h->GradientPar(x, result_num.data());

   ASSERT_FLOAT_EQ(result_num[0], result_clad[0]);
   ASSERT_FLOAT_EQ(result_num[1], result_clad[1]);
   ASSERT_FLOAT_EQ(result_num[2], result_clad[2]);
}

TEST(TFormulaGradientPar, BreitWignerCrossCheckAccuracyDemo)
{
   auto h = new TF1("f1", "breitwigner");
   double p[] = {3, 1, 2};
   h->SetParameters(p);
   double x[] = {0};
   TFormula::GradientStorage result_clad(3);
   TFormula* formula = h->GetFormula();
   formula->GradientPar(x, result_clad);
   TFormula::GradientStorage result_num(3);
   h->GradientPar(x, result_num.data());

   // This is a classical example why clad is better.
   // The gradient with respect to gamma leads to a cancellation when gamma is
   // set to 2. This is not a problem for clad yielding the correct result of 0
   ASSERT_FLOAT_EQ(0, result_clad[2]);

   // However, that is not the case for the numerical approach where we give
   // a small but non-zero result.
   EXPECT_NEAR(0, result_num[2], /*abs_error*/1e-13);
}

// FIXME: Add more: crystalball, cheb3, bigaus?

// FIXME: Disable because of a known failure in -Druntime_cxxmodules=On.
// This is identical to getFuncBody test failure in roottest.
TEST(DISABLED_TFormulaGradientPar, GetGradFormula)
{
   TFormula f("f", "gaus");
   double p[] = {3, 1, 2};
   f.SetParameters(p);
   ASSERT_TRUE(f.GenerateGradientPar());
   std::string s = f.GetGradientFormula().Data();
   ASSERT_THAT(s, testing::ContainsRegex("void TFormula____id[0-9]*_grad"));
}

<commit_msg>[gradients] Re-enable test.<commit_after>/// \file TFormulaGradientTests.cxx
///
/// \brief The file contain unit tests which test the clad-based gradient
///        computations.
///
/// \author Vassil Vassilev <vvasilev@cern.ch>
///
/// \date Oct, 2018
///
/*************************************************************************
 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "ROOTUnitTestSupport.h"

#include <Math/MinimizerOptions.h>
#include <TFormula.h>
#include <TF1.h>
#include <TFitResult.h>

TEST(TFormulaGradientPar, Sanity)
{
   TFormula f("f", "x*std::sin([0]) - y*std::cos([1])");
   double p[] = {30, 60};
   f.SetParameters(p);
   double x[] = {1, 2};
   TFormula::GradientStorage result(2);
   f.GradientPar(x, result);

   ASSERT_FLOAT_EQ(x[0] * std::cos(30), result[0]);
   ASSERT_FLOAT_EQ(-x[1] * -std::sin(60), result[1]);
}

TEST(TFormulaGradientPar, ResultUpsize)
{
   TFormula f("f", "std::sin([1]) - std::cos([0])");
   double p[] = {60, 30};
   f.SetParameters(p);
   TFormula::GradientStorage result;
   double x[] = {2, 1};

   ASSERT_TRUE(0 == result.size());
   ROOT_EXPECT_WARNING(f.GradientPar(x, result),
                       "TFormula::GradientPar",
                       "The size of gradient result is 0 but 2 is required. Resizing."
                       );

   ASSERT_FLOAT_EQ(std::cos(30), result[1]);
   ASSERT_FLOAT_EQ(std::sin(60), result[0]);
   ASSERT_TRUE(2 == result.size());
}

TEST(TFormulaGradientPar, ResultDownsize)
{
   TFormula f("f", "std::sin([0])");
   double p[] = {60};
   f.SetParameters(p);
   TFormula::GradientStorage result(2);
   double x[] = {1};

   ASSERT_TRUE(2 == result.size());

   ROOT_EXPECT_NODIAG(f.GradientPar(x, result));

   ASSERT_FLOAT_EQ(std::cos(60), result[0]);
   ASSERT_TRUE(2 == result.size());
}

TEST(TFormulaGradientPar, GausCrossCheck)
{
   auto h = new TF1("f1", "gaus");
   // auto h = new TF1("f1", "landau"); -- inheritently does not work. See DIFLAN
   //crystalball, breitwigner, cheb3, bigaus,
   //auto h = new TF1("f1", "");
   double p[] = {3, 1, 2};
   h->SetParameters(p);
   double x[] = {0};
   TFormula::GradientStorage result_clad(3);
   h->GetFormula()->GradientPar(x, result_clad);

   TFormula::GradientStorage result_num(3);
   h->GradientPar(x, result_num.data());

   ASSERT_FLOAT_EQ(result_num[0], result_clad[0]);
   ASSERT_FLOAT_EQ(result_num[1], result_clad[1]);
   ASSERT_FLOAT_EQ(result_num[2], result_clad[2]);
}

TEST(TFormulaGradientPar, BreitWignerCrossCheck)
{
   auto h = new TF1("f1", "breitwigner");
   double p[] = {3, 1, 2.1};
   h->SetParameters(p);
   double x[] = {0};
   TFormula::GradientStorage result_clad(3);
   TFormula* formula = h->GetFormula();
   formula->GradientPar(x, result_clad);
   TFormula::GradientStorage result_num(3);
   h->GradientPar(x, result_num.data());

   ASSERT_FLOAT_EQ(result_num[0], result_clad[0]);
   ASSERT_FLOAT_EQ(result_num[1], result_clad[1]);
   ASSERT_FLOAT_EQ(result_num[2], result_clad[2]);
}

TEST(TFormulaGradientPar, BreitWignerCrossCheckAccuracyDemo)
{
   auto h = new TF1("f1", "breitwigner");
   double p[] = {3, 1, 2};
   h->SetParameters(p);
   double x[] = {0};
   TFormula::GradientStorage result_clad(3);
   TFormula* formula = h->GetFormula();
   formula->GradientPar(x, result_clad);
   TFormula::GradientStorage result_num(3);
   h->GradientPar(x, result_num.data());

   // This is a classical example why clad is better.
   // The gradient with respect to gamma leads to a cancellation when gamma is
   // set to 2. This is not a problem for clad yielding the correct result of 0
   ASSERT_FLOAT_EQ(0, result_clad[2]);

   // However, that is not the case for the numerical approach where we give
   // a small but non-zero result.
   EXPECT_NEAR(0, result_num[2], /*abs_error*/1e-13);
}

// FIXME: Add more: crystalball, cheb3, bigaus?

TEST(TFormulaGradientPar, GetGradFormula)
{
   TFormula f("f", "gaus");
   double p[] = {3, 1, 2};
   f.SetParameters(p);
   ASSERT_TRUE(f.GenerateGradientPar());
   std::string s = f.GetGradientFormula().Data();
   ASSERT_THAT(s, testing::ContainsRegex("void TFormula____id[0-9]*_grad"));
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: TColumnsHelper.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: obo $ $Date: 2006-07-10 14:18:48 $
 *
 *  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 CONNECTIVITY_COLUMNSHELPER_HXX
#include "connectivity/TColumnsHelper.hxx"
#endif
#ifndef _CONNECTIVITY_SDBCX_COLUMN_HXX_
#include "connectivity/sdbcx/VColumn.hxx"
#endif
#ifndef _CONNECTIVITY_SDBCX_COLUMN_HXX_
#include "connectivity/sdbcx/VColumn.hxx"
#endif
#ifndef _COM_SUN_STAR_SDBC_XROW_HPP_
#include <com/sun/star/sdbc/XRow.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_XRESULTSET_HPP_
#include <com/sun/star/sdbc/XResultSet.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_DATATYPE_HPP_
#include <com/sun/star/sdbc/DataType.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_COLUMNVALUE_HPP_
#include <com/sun/star/sdbc/ColumnValue.hpp>
#endif
#ifndef _COMPHELPER_TYPES_HXX_
#include <comphelper/types.hxx>
#endif
#ifndef _CONNECTIVITY_DBTOOLS_HXX_
#include "connectivity/dbtools.hxx"
#endif
#ifndef CONNECTIVITY_CONNECTION_HXX
#include "TConnection.hxx"
#endif
#ifndef CONNECTIVITY_TABLEHELPER_HXX
#include "connectivity/TTableHelper.hxx"
#endif
#ifndef _COMPHELPER_PROPERTY_HXX_
#include <comphelper/property.hxx>
#endif

using namespace ::comphelper;

using namespace connectivity::sdbcx;
using namespace connectivity;
using namespace dbtools;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
//  using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::lang;
typedef connectivity::sdbcx::OCollection OCollection_TYPE;

namespace connectivity
{
    class OColumnsHelperImpl
    {
    public:
        OColumnsHelperImpl(sal_Bool _bCase)
            : m_aColumnInfo(_bCase)
        {
        }
        ColumnInformationMap m_aColumnInfo;
    };
}

OColumnsHelper::OColumnsHelper( ::cppu::OWeakObject& _rParent
                                ,sal_Bool _bCase
                                ,::osl::Mutex& _rMutex
                                ,const TStringVector &_rVector
                                ,sal_Bool _bUseHardRef
            ) : OCollection(_rParent,_bCase,_rMutex,_rVector,sal_False,_bUseHardRef)
    ,m_pImpl(NULL)
    ,m_pTable(NULL)
{
}
// -----------------------------------------------------------------------------
OColumnsHelper::~OColumnsHelper()
{
    delete m_pImpl;
    m_pImpl = NULL;
}
// -----------------------------------------------------------------------------

sdbcx::ObjectType OColumnsHelper::createObject(const ::rtl::OUString& _rName)
{
    OSL_ENSURE(m_pTable,"NO Table set. Error!");
    Reference<XConnection> xConnection = m_pTable->getConnection();

    if ( !m_pImpl )
        m_pImpl = new OColumnsHelperImpl(isCaseSensitive());

    sal_Bool bQueryInfo     = sal_True;
    sal_Bool bAutoIncrement = sal_False;
    sal_Bool bIsCurrency    = sal_False;
    sal_Int32 nDataType     = DataType::OTHER;

    ColumnInformationMap::iterator aFind = m_pImpl->m_aColumnInfo.find(_rName);
    if ( aFind == m_pImpl->m_aColumnInfo.end() ) // we have to fill it
    {
        ::rtl::OUString sComposedName = ::dbtools::composeTableNameForSelect( xConnection, m_pTable );
        collectColumnInformation(xConnection,sComposedName,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")) ,m_pImpl->m_aColumnInfo);
        aFind = m_pImpl->m_aColumnInfo.find(_rName);
    }
    if ( aFind != m_pImpl->m_aColumnInfo.end() )
    {
        bQueryInfo      = sal_False;
        bAutoIncrement  = aFind->second.first.first;
        bIsCurrency     = aFind->second.first.second;
        nDataType       = aFind->second.second;
    }

    sdbcx::ObjectType xRet(::dbtools::createSDBCXColumn(    m_pTable,
                                                            xConnection,
                                                            _rName,
                                                            isCaseSensitive(),
                                                            bQueryInfo,
                                                            bAutoIncrement,
                                                            bIsCurrency,
                                                            nDataType),UNO_QUERY);
    return xRet;
}

// -------------------------------------------------------------------------
void OColumnsHelper::impl_refresh() throw(RuntimeException)
{
    if ( m_pTable )
    {
        m_pImpl->m_aColumnInfo.clear();
        m_pTable->refreshColumns();
    }
}
// -------------------------------------------------------------------------
Reference< XPropertySet > OColumnsHelper::createDescriptor()
{
    return new OColumn(sal_True);
}
// -----------------------------------------------------------------------------
// XAppend
sdbcx::ObjectType OColumnsHelper::appendObject( const ::rtl::OUString& _rForName, const Reference< XPropertySet >& descriptor )
{
    ::osl::MutexGuard aGuard(m_rMutex);
    OSL_ENSURE(m_pTable,"OColumnsHelper::appendByDescriptor: Table is null!");
    if ( !m_pTable || m_pTable->isNew() )
        return cloneDescriptor( descriptor );

    Reference<XDatabaseMetaData> xMetaData = m_pTable->getConnection()->getMetaData();
    ::rtl::OUString aSql    = ::rtl::OUString::createFromAscii("ALTER TABLE ");
    ::rtl::OUString aQuote  = xMetaData->getIdentifierQuoteString(  );

    aSql += ::dbtools::composeTableName( xMetaData, m_pTable, ::dbtools::eInTableDefinitions, false, false, true );
    aSql += ::rtl::OUString::createFromAscii(" ADD ");
    aSql += ::dbtools::createStandardColumnPart(descriptor,m_pTable->getConnection());

    Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement(  );
    if ( xStmt.is() )
    {
        xStmt->execute(aSql);
        ::comphelper::disposeComponent(xStmt);
    }
    return createObject( _rForName );
}
// -------------------------------------------------------------------------
// XDrop
void OColumnsHelper::dropObject(sal_Int32 /*_nPos*/,const ::rtl::OUString _sElementName)
{
    OSL_ENSURE(m_pTable,"OColumnsHelper::dropByName: Table is null!");
    if ( m_pTable && !m_pTable->isNew() )
    {
        ::rtl::OUString aSql    = ::rtl::OUString::createFromAscii("ALTER TABLE ");
        Reference<XDatabaseMetaData> xMetaData = m_pTable->getConnection()->getMetaData();
        ::rtl::OUString aQuote  = xMetaData->getIdentifierQuoteString(  );

        aSql += ::dbtools::composeTableName( xMetaData, m_pTable, ::dbtools::eInTableDefinitions, false, false, true );
        aSql += ::rtl::OUString::createFromAscii(" DROP ");
        aSql += ::dbtools::quoteName( aQuote,_sElementName);

        Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement(  );
        if ( xStmt.is() )
        {
            xStmt->execute(aSql);
            ::comphelper::disposeComponent(xStmt);
        }
    }
}
// -----------------------------------------------------------------------------

<commit_msg>INTEGRATION: CWS pchfix02 (1.8.42); FILE MERGED 2006/09/01 17:21:45 kaib 1.8.42.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: TColumnsHelper.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 01:58:51 $
 *
 *  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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_connectivity.hxx"
#ifndef CONNECTIVITY_COLUMNSHELPER_HXX
#include "connectivity/TColumnsHelper.hxx"
#endif
#ifndef _CONNECTIVITY_SDBCX_COLUMN_HXX_
#include "connectivity/sdbcx/VColumn.hxx"
#endif
#ifndef _CONNECTIVITY_SDBCX_COLUMN_HXX_
#include "connectivity/sdbcx/VColumn.hxx"
#endif
#ifndef _COM_SUN_STAR_SDBC_XROW_HPP_
#include <com/sun/star/sdbc/XRow.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_XRESULTSET_HPP_
#include <com/sun/star/sdbc/XResultSet.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_DATATYPE_HPP_
#include <com/sun/star/sdbc/DataType.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_COLUMNVALUE_HPP_
#include <com/sun/star/sdbc/ColumnValue.hpp>
#endif
#ifndef _COMPHELPER_TYPES_HXX_
#include <comphelper/types.hxx>
#endif
#ifndef _CONNECTIVITY_DBTOOLS_HXX_
#include "connectivity/dbtools.hxx"
#endif
#ifndef CONNECTIVITY_CONNECTION_HXX
#include "TConnection.hxx"
#endif
#ifndef CONNECTIVITY_TABLEHELPER_HXX
#include "connectivity/TTableHelper.hxx"
#endif
#ifndef _COMPHELPER_PROPERTY_HXX_
#include <comphelper/property.hxx>
#endif

using namespace ::comphelper;

using namespace connectivity::sdbcx;
using namespace connectivity;
using namespace dbtools;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
//  using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::lang;
typedef connectivity::sdbcx::OCollection OCollection_TYPE;

namespace connectivity
{
    class OColumnsHelperImpl
    {
    public:
        OColumnsHelperImpl(sal_Bool _bCase)
            : m_aColumnInfo(_bCase)
        {
        }
        ColumnInformationMap m_aColumnInfo;
    };
}

OColumnsHelper::OColumnsHelper( ::cppu::OWeakObject& _rParent
                                ,sal_Bool _bCase
                                ,::osl::Mutex& _rMutex
                                ,const TStringVector &_rVector
                                ,sal_Bool _bUseHardRef
            ) : OCollection(_rParent,_bCase,_rMutex,_rVector,sal_False,_bUseHardRef)
    ,m_pImpl(NULL)
    ,m_pTable(NULL)
{
}
// -----------------------------------------------------------------------------
OColumnsHelper::~OColumnsHelper()
{
    delete m_pImpl;
    m_pImpl = NULL;
}
// -----------------------------------------------------------------------------

sdbcx::ObjectType OColumnsHelper::createObject(const ::rtl::OUString& _rName)
{
    OSL_ENSURE(m_pTable,"NO Table set. Error!");
    Reference<XConnection> xConnection = m_pTable->getConnection();

    if ( !m_pImpl )
        m_pImpl = new OColumnsHelperImpl(isCaseSensitive());

    sal_Bool bQueryInfo     = sal_True;
    sal_Bool bAutoIncrement = sal_False;
    sal_Bool bIsCurrency    = sal_False;
    sal_Int32 nDataType     = DataType::OTHER;

    ColumnInformationMap::iterator aFind = m_pImpl->m_aColumnInfo.find(_rName);
    if ( aFind == m_pImpl->m_aColumnInfo.end() ) // we have to fill it
    {
        ::rtl::OUString sComposedName = ::dbtools::composeTableNameForSelect( xConnection, m_pTable );
        collectColumnInformation(xConnection,sComposedName,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")) ,m_pImpl->m_aColumnInfo);
        aFind = m_pImpl->m_aColumnInfo.find(_rName);
    }
    if ( aFind != m_pImpl->m_aColumnInfo.end() )
    {
        bQueryInfo      = sal_False;
        bAutoIncrement  = aFind->second.first.first;
        bIsCurrency     = aFind->second.first.second;
        nDataType       = aFind->second.second;
    }

    sdbcx::ObjectType xRet(::dbtools::createSDBCXColumn(    m_pTable,
                                                            xConnection,
                                                            _rName,
                                                            isCaseSensitive(),
                                                            bQueryInfo,
                                                            bAutoIncrement,
                                                            bIsCurrency,
                                                            nDataType),UNO_QUERY);
    return xRet;
}

// -------------------------------------------------------------------------
void OColumnsHelper::impl_refresh() throw(RuntimeException)
{
    if ( m_pTable )
    {
        m_pImpl->m_aColumnInfo.clear();
        m_pTable->refreshColumns();
    }
}
// -------------------------------------------------------------------------
Reference< XPropertySet > OColumnsHelper::createDescriptor()
{
    return new OColumn(sal_True);
}
// -----------------------------------------------------------------------------
// XAppend
sdbcx::ObjectType OColumnsHelper::appendObject( const ::rtl::OUString& _rForName, const Reference< XPropertySet >& descriptor )
{
    ::osl::MutexGuard aGuard(m_rMutex);
    OSL_ENSURE(m_pTable,"OColumnsHelper::appendByDescriptor: Table is null!");
    if ( !m_pTable || m_pTable->isNew() )
        return cloneDescriptor( descriptor );

    Reference<XDatabaseMetaData> xMetaData = m_pTable->getConnection()->getMetaData();
    ::rtl::OUString aSql    = ::rtl::OUString::createFromAscii("ALTER TABLE ");
    ::rtl::OUString aQuote  = xMetaData->getIdentifierQuoteString(  );

    aSql += ::dbtools::composeTableName( xMetaData, m_pTable, ::dbtools::eInTableDefinitions, false, false, true );
    aSql += ::rtl::OUString::createFromAscii(" ADD ");
    aSql += ::dbtools::createStandardColumnPart(descriptor,m_pTable->getConnection());

    Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement(  );
    if ( xStmt.is() )
    {
        xStmt->execute(aSql);
        ::comphelper::disposeComponent(xStmt);
    }
    return createObject( _rForName );
}
// -------------------------------------------------------------------------
// XDrop
void OColumnsHelper::dropObject(sal_Int32 /*_nPos*/,const ::rtl::OUString _sElementName)
{
    OSL_ENSURE(m_pTable,"OColumnsHelper::dropByName: Table is null!");
    if ( m_pTable && !m_pTable->isNew() )
    {
        ::rtl::OUString aSql    = ::rtl::OUString::createFromAscii("ALTER TABLE ");
        Reference<XDatabaseMetaData> xMetaData = m_pTable->getConnection()->getMetaData();
        ::rtl::OUString aQuote  = xMetaData->getIdentifierQuoteString(  );

        aSql += ::dbtools::composeTableName( xMetaData, m_pTable, ::dbtools::eInTableDefinitions, false, false, true );
        aSql += ::rtl::OUString::createFromAscii(" DROP ");
        aSql += ::dbtools::quoteName( aQuote,_sElementName);

        Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement(  );
        if ( xStmt.is() )
        {
            xStmt->execute(aSql);
            ::comphelper::disposeComponent(xStmt);
        }
    }
}
// -----------------------------------------------------------------------------

<|endoftext|>


<commit_before>/*
 * zsummerX License
 * -----------
 *
 * zsummerX is licensed under the terms of the MIT license reproduced below.
 * This means that zsummerX is free software and can be used for both academic
 * and commercial purposes at absolutely no cost.
 *
 *
 * ===============================================================================
 *
 * Copyright (C) 2010-2014 YaweiZhang <yawei_zhang@foxmail.com>.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * ===============================================================================
 *
 * (end of COPYRIGHT)
 */

#include "Schedule.h"

#include "Process.h"

CSchedule::CSchedule()
{
	m_summer = zsummer::network::CZSummerPtr(new zsummer::network::CZSummer());
	m_accept = zsummer::network::CTcpAcceptPtr(new zsummer::network::CTcpAccept(m_summer));
}

void CSchedule::Start()
{

	if (!m_summer->Initialize())
	{
		return ;
	}

	for (int i=0; i< 1; i++)
	{
		CProcess * p = new CProcess();
		if (p->Start())
		{
			m_process.push_back(p);
		}
	}

	if (g_startType == 0)
	{
		if (m_accept->OpenAccept(g_remoteIP.c_str(), g_remotePort))
		{
			LOGI("open server port [" << g_remotePort << "] success");
		}
		CTcpSocketPtr s(new zsummer::network::CTcpSocket());
		s->Initialize(m_process[m_iCurProcess]->GetZSummer());
		m_accept->DoAccept(s, std::bind(&CSchedule::OnAccept, this, std::placeholders::_1, std::placeholders::_2, m_process[m_iCurProcess]));
	}
	else
	{
		doConnect(g_maxClient);
	}

	m_thread = std::thread(std::bind(&CSchedule::Run, this));
}
void CSchedule::Stop()
{
	m_bRunning = false;
}
void CSchedule::Run()
{
	m_bRunning = true;

	while (m_bRunning)
	{
		m_summer->RunOnce();
	}
}

void CSchedule::doConnect(unsigned int maxClient)
{
	for (unsigned int i = 1; i <= maxClient; i++)
	{
		CTcpSocketPtr s(new zsummer::network::CTcpSocket());
		CProcess * proc = m_process[m_iCurProcess];
		s->Initialize(proc->GetZSummer());
		proc->Post(std::bind(&CProcess::RecvSocketPtr, proc, s));
		m_iCurProcess++;
		m_iCurProcess = m_iCurProcess%(int)m_process.size();
		if (i >= 100 && maxClient > 100)
		{
			m_summer->CreateTimer(1000, std::bind(&CSchedule::doConnect, this, maxClient - i));
			break;
		}
	}
}
void CSchedule::OnAccept(zsummer::network::ErrorCode ec, CTcpSocketPtr sockptr, CProcess * process)
{
	if (ec)
	{
		LOGE("OnAccept error. ec=" <<ec );
		return;
	}

	unsigned long long allClosed = 0;
	unsigned long long allOpen = 0;
	for (std::vector<CProcess *>::const_iterator iter = m_process.begin(); iter != m_process.end(); ++iter)
	{
		allClosed += (*iter)->GetTotalClosed();
		allOpen += (*iter)->GetTotalOpen();
	}
	if (allOpen - allClosed > g_maxClient )
	{
		LOGW("OnAccept success but current links is too many.");
		return;
	}

	LOGD("OnAccept one socket");
	process->Post(std::bind(&CProcess::RecvSocketPtr, process, sockptr));

	m_iCurProcess++;
	m_iCurProcess = m_iCurProcess%(int)m_process.size();
	CTcpSocketPtr s(new zsummer::network::CTcpSocket());
	s->Initialize(m_process[m_iCurProcess]->GetZSummer());
	m_accept->DoAccept(s, std::bind(&CSchedule::OnAccept, this, std::placeholders::_1, std::placeholders::_2, m_process[m_iCurProcess]));
}

<commit_msg>tcpTest server端最大客户端连接数超出后应继续accept下一个<commit_after>/*
 * zsummerX License
 * -----------
 *
 * zsummerX is licensed under the terms of the MIT license reproduced below.
 * This means that zsummerX is free software and can be used for both academic
 * and commercial purposes at absolutely no cost.
 *
 *
 * ===============================================================================
 *
 * Copyright (C) 2010-2014 YaweiZhang <yawei_zhang@foxmail.com>.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * ===============================================================================
 *
 * (end of COPYRIGHT)
 */

#include "Schedule.h"

#include "Process.h"

CSchedule::CSchedule()
{
	m_summer = zsummer::network::CZSummerPtr(new zsummer::network::CZSummer());
	m_accept = zsummer::network::CTcpAcceptPtr(new zsummer::network::CTcpAccept(m_summer));
}

void CSchedule::Start()
{

	if (!m_summer->Initialize())
	{
		return ;
	}

	for (int i=0; i< 1; i++)
	{
		CProcess * p = new CProcess();
		if (p->Start())
		{
			m_process.push_back(p);
		}
	}

	if (g_startType == 0)
	{
		if (m_accept->OpenAccept(g_remoteIP.c_str(), g_remotePort))
		{
			LOGI("open server port [" << g_remotePort << "] success");
		}
		CTcpSocketPtr s(new zsummer::network::CTcpSocket());
		s->Initialize(m_process[m_iCurProcess]->GetZSummer());
		m_accept->DoAccept(s, std::bind(&CSchedule::OnAccept, this, std::placeholders::_1, std::placeholders::_2, m_process[m_iCurProcess]));
	}
	else
	{
		doConnect(g_maxClient);
	}

	m_thread = std::thread(std::bind(&CSchedule::Run, this));
}
void CSchedule::Stop()
{
	m_bRunning = false;
}
void CSchedule::Run()
{
	m_bRunning = true;

	while (m_bRunning)
	{
		m_summer->RunOnce();
	}
}

void CSchedule::doConnect(unsigned int maxClient)
{
	for (unsigned int i = 1; i <= maxClient; i++)
	{
		CTcpSocketPtr s(new zsummer::network::CTcpSocket());
		CProcess * proc = m_process[m_iCurProcess];
		s->Initialize(proc->GetZSummer());
		proc->Post(std::bind(&CProcess::RecvSocketPtr, proc, s));
		m_iCurProcess++;
		m_iCurProcess = m_iCurProcess%(int)m_process.size();
		if (i >= 100 && maxClient > 100)
		{
			m_summer->CreateTimer(1000, std::bind(&CSchedule::doConnect, this, maxClient - i));
			break;
		}
	}
}
void CSchedule::OnAccept(zsummer::network::ErrorCode ec, CTcpSocketPtr sockptr, CProcess * process)
{
	if (ec)
	{
		LOGE("OnAccept error. ec=" <<ec );
		return;
	}

	unsigned long long allClosed = 0;
	unsigned long long allOpen = 0;
	for (std::vector<CProcess *>::const_iterator iter = m_process.begin(); iter != m_process.end(); ++iter)
	{
		allClosed += (*iter)->GetTotalClosed();
		allOpen += (*iter)->GetTotalOpen();
	}
	if (allOpen - allClosed > g_maxClient )
	{
		LOGW("OnAccept success but current links is too many.");
	}
	else
	{
		LOGD("OnAccept one socket");
		process->Post(std::bind(&CProcess::RecvSocketPtr, process, sockptr));
	}

	m_iCurProcess++;
	m_iCurProcess = m_iCurProcess%(int)m_process.size();
	CTcpSocketPtr s(new zsummer::network::CTcpSocket());
	s->Initialize(m_process[m_iCurProcess]->GetZSummer());
	m_accept->DoAccept(s, std::bind(&CSchedule::OnAccept, this, std::placeholders::_1, std::placeholders::_2, m_process[m_iCurProcess]));
}

<|endoftext|>


<commit_before>//#define NEU_DISABLE_ASSERTION
#include <iostream>
#include <boost/timer.hpp>
#include <boost/progress.hpp>
#include <neu/vector_io.hpp>
#include <neu/kernel.hpp>
#include <neu/activation_func/sigmoid_loss.hpp>
#include <neu/activation_func/rectifier.hpp>
#include <neu/activation_func/sigmoid.hpp>
#include <neu/layer/activation.hpp>
#include <neu/optimizer/momentum.hpp>
#include <neu/layer/inner_product.hpp>
#include <neu/layer/bias.hpp>
#include <neu/layer/any_layer.hpp>
#include <neu/layer/any_layer_vector.hpp>
#include <neu/layer/branch_reduce.hpp>
#include <neu/layer/load.hpp>

int main(int argc, char** argv) {
	std::cout << "hello world" << std::endl;
	auto& queue = boost::compute::system::default_queue();
	auto context = boost::compute::system::default_context();

	std::random_device device; std::mt19937 rand(device());
	//std::mt19937 rand(0);

	const auto input_dim = 2u;
	const auto output_dim = 1u;
	const auto batch_size = 4u;

	std::vector<neu::cpu_vector> cpu_input = {
		{0.f, 0.f}, {1.f, 0.f}, {0.f, 1.f}, {1.f, 1.f}
	};
	std::vector<neu::cpu_vector> cpu_teach = {
		{0.f}, {1.f}, {1.f}, {0.f}
	};

	const auto input = neu::to_gpu_vector(neu::flatten(cpu_input), queue);
	const auto teach = neu::to_gpu_vector(neu::flatten(cpu_teach), queue);

	auto fc12_g = [&rand, dist=std::normal_distribution<>(0.f, 1.f)]
		() mutable { return dist(rand); };
	auto constant_g = [](){ return 0.f; };

	constexpr neu::scalar base_lr = 0.1;
	constexpr neu::scalar momentum = 0.9;
	constexpr std::size_t hidden_node_num = 10u;

	std::vector<neu::layer::any_layer> nn;
	nn.push_back(neu::layer::make_inner_product(
		input_dim, hidden_node_num, batch_size, fc12_g,
		neu::optimizer::momentum(base_lr, momentum, input_dim*hidden_node_num, queue),
		queue));
	nn.push_back(neu::layer::make_bias(neu::layer::output_dim(nn), batch_size, constant_g,
		neu::optimizer::momentum(base_lr, momentum, neu::layer::output_dim(nn), queue),
		queue));
	nn.push_back(neu::layer::make_activation(neu::layer::output_dim(nn), batch_size,
		neu::rectifier()));
	nn.push_back(neu::layer::make_inner_product(
		neu::layer::output_dim(nn), output_dim, batch_size, fc12_g,
		neu::optimizer::momentum(base_lr, momentum,
			neu::layer::output_dim(nn)*output_dim, queue), queue));
	nn.push_back(neu::layer::make_bias(neu::layer::output_dim(nn), batch_size, constant_g,
		neu::optimizer::momentum(base_lr, momentum, neu::layer::output_dim(nn), queue),
		queue));
	nn.push_back(neu::layer::make_activation(neu::layer::output_dim(nn), batch_size,
		neu::sigmoid_loss()));

	neu::gpu_vector output(neu::layer::output_size(nn), context);
	neu::gpu_vector prev_delta(neu::layer::input_size(nn), context);

	std::ofstream cel_error_log("cel_error.txt");
	std::ofstream output_log("output.txt");
	std::ofstream del_weight_log("del_weight.txt");

	const auto iteration_limit = 100u;
	boost::progress_display progress(iteration_limit);
	boost::timer timer;
	for(auto i = 0u; i < iteration_limit; ++i) {
		neu::layer::forward(nn, input, output, queue);
		{
			neu::print(output_log, output, output_dim);
			auto cel = neu::range::cross_entropy_loss(output, teach);
			cel_error_log << i << " " << cel << std::endl;
		}
		neu::gpu_vector error(output.size(), context);
		neu::range::calc_last_layer_delta(output, teach, error, queue);
		neu::layer::backward(nn, error, prev_delta, false, queue);
		neu::layer::update(nn, queue);
		++progress;
	}
	std::cout << timer.elapsed() << " sec" << std::endl;
	neu::print(std::cout, output, output_dim);
	boost::compute::system::finish();
	YAML::Emitter emitter;
	neu::layer::save(nn, emitter, queue);
	std::cout << emitter.c_str() << std::endl;

	std::ofstream ofs("nn.yaml");
	ofs << emitter.c_str();

	{
		auto node = YAML::Load(emitter.c_str());
		auto loaded = neu::layer::load(node, queue);
		YAML::Emitter emitter;
		neu::layer::save(loaded, emitter, queue);
		std::ofstream ofs("loaded_nn.yaml");
		ofs << emitter.c_str();
	}

}
<commit_msg>update for backward_top<commit_after>//#define NEU_DISABLE_ASSERTION
#include <iostream>
#include <boost/timer.hpp>
#include <boost/progress.hpp>
#include <neu/vector_io.hpp>
#include <neu/kernel.hpp>
#include <neu/layer/activation/rectifier.hpp>
#include <neu/layer/activation/sigmoid_loss.hpp>
#include <neu/optimizer/momentum.hpp>
#include <neu/layer/inner_product.hpp>
#include <neu/layer/bias.hpp>
#include <neu/layer/any_layer.hpp>
#include <neu/layer/any_layer_vector.hpp>
#include <neu/layer/branch_reduce.hpp>
#include <neu/layer/load.hpp>

int main(int argc, char** argv) {
	std::cout << "hello world" << std::endl;
	auto& queue = boost::compute::system::default_queue();
	auto context = boost::compute::system::default_context();

	std::random_device device; std::mt19937 rand(device());
	//std::mt19937 rand(0);

	const auto input_dim = 2u;
	const auto output_dim = 1u;
	const auto batch_size = 4u;

	std::vector<neu::cpu_vector> cpu_input = {
		{0.f, 0.f}, {1.f, 0.f}, {0.f, 1.f}, {1.f, 1.f}
	};
	std::vector<neu::cpu_vector> cpu_teach = {
		{0.f}, {1.f}, {1.f}, {0.f}
	};

	const auto input = neu::to_gpu_vector(neu::flatten(cpu_input), queue);
	const auto teach = neu::to_gpu_vector(neu::flatten(cpu_teach), queue);

	auto fc12_g = [&rand, dist=std::normal_distribution<>(0.f, 1.f)]
		() mutable { return dist(rand); };
	auto constant_g = [](){ return 0.f; };

	constexpr neu::scalar base_lr = 0.1;
	constexpr neu::scalar momentum = 0.9;
	constexpr std::size_t hidden_node_num = 10u;

	std::vector<neu::layer::any_layer> nn;
	nn.push_back(neu::layer::make_inner_product(
		input_dim, hidden_node_num, batch_size, fc12_g,
		neu::optimizer::momentum(base_lr, momentum, input_dim*hidden_node_num, queue),
		queue));
	nn.push_back(neu::layer::make_bias(neu::layer::output_dim(nn), batch_size, constant_g,
		neu::optimizer::momentum(base_lr, momentum, neu::layer::output_dim(nn), queue),
		queue));
	nn.push_back(neu::layer::make_activation(neu::layer::output_dim(nn), batch_size,
		neu::rectifier()));
	nn.push_back(neu::layer::make_inner_product(
		neu::layer::output_dim(nn), output_dim, batch_size, fc12_g,
		neu::optimizer::momentum(base_lr, momentum,
			neu::layer::output_dim(nn)*output_dim, queue), queue));
	nn.push_back(neu::layer::make_bias(neu::layer::output_dim(nn), batch_size, constant_g,
		neu::optimizer::momentum(base_lr, momentum, neu::layer::output_dim(nn), queue),
		queue));
	nn.push_back(neu::layer::make_activation(neu::layer::output_dim(nn), batch_size,
		neu::sigmoid_loss()));

	neu::gpu_vector output(neu::layer::output_size(nn), context);
	neu::gpu_vector prev_delta(neu::layer::input_size(nn), context);

	std::ofstream cel_error_log("cel_error.txt");
	std::ofstream output_log("output.txt");
	std::ofstream del_weight_log("del_weight.txt");

	const auto iteration_limit = 100u;
	boost::progress_display progress(iteration_limit);
	boost::timer timer;
	for(auto i = 0u; i < iteration_limit; ++i) {
		neu::layer::forward(nn, input, output, queue);
		{
			neu::print(output_log, output, output_dim);
			auto cel = neu::range::cross_entropy_loss(output, teach);
			cel_error_log << i << " " << cel << std::endl;
		}
		neu::gpu_vector error(output.size(), context);
		neu::range::calc_last_layer_delta(output, teach, error, queue);
		neu::layer::backward(nn, error, prev_delta, queue); //or neu::layer::backward_top(nn, error, queue);
		neu::layer::update(nn, queue);
		++progress;
	}
	std::cout << timer.elapsed() << " sec" << std::endl;
	neu::print(std::cout, output, output_dim);
	boost::compute::system::finish();
	YAML::Emitter emitter;
	neu::layer::save(nn, emitter, queue);
	std::cout << emitter.c_str() << std::endl;

	std::ofstream ofs("nn.yaml");
	ofs << emitter.c_str();

	{
		auto node = YAML::Load(emitter.c_str());
		auto loaded = neu::layer::load(node, queue);
		YAML::Emitter emitter;
		neu::layer::save(loaded, emitter, queue);
		std::ofstream ofs("loaded_nn.yaml");
		ofs << emitter.c_str();
	}

}
<|endoftext|>


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

#include "base/win/registry.h"

#include <shlwapi.h>

#include "base/logging.h"
#include "base/threading/thread_restrictions.h"

#pragma comment(lib, "shlwapi.lib")  // for SHDeleteKey

namespace base {
namespace win {

// RegKey ----------------------------------------------------------------------

RegKey::RegKey()
    : key_(NULL),
      watch_event_(0) {
}

RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
    : key_(NULL),
      watch_event_(0) {
  base::ThreadRestrictions::AssertIOAllowed();
  if (rootkey) {
    if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
      Create(rootkey, subkey, access);
    else
      Open(rootkey, subkey, access);
  } else {
    DCHECK(!subkey);
  }
}

RegKey::~RegKey() {
  Close();
}

GONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
  DWORD disposition_value;
  return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
}

GONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
                                   DWORD* disposition, REGSAM access) {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(rootkey && subkey && access && disposition);
  Close();

  LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
                               REG_OPTION_NON_VOLATILE, access, NULL, &key_,
                               disposition);
  return result;
}

GONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(rootkey && subkey && access);
  Close();

  LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
  return result;
}

GONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(name && access);

  HKEY subkey = NULL;
  LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
                               access, NULL, &subkey, NULL);
  Close();

  key_ = subkey;
  return result;
}

GONG RegKey::OpenKey(const wchar_t* name, REGSAM access) {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(name && access);

  HKEY subkey = NULL;
  LONG result = RegOpenKeyEx(key_, name, 0, access, &subkey);

  Close();

  key_ = subkey;
  return result;
}

void RegKey::Close() {
  base::ThreadRestrictions::AssertIOAllowed();
  StopWatching();
  if (key_) {
    ::RegCloseKey(key_);
    key_ = NULL;
  }
}

DWORD RegKey::ValueCount() const {
  base::ThreadRestrictions::AssertIOAllowed();
  DWORD count = 0;
  LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
                                NULL, NULL, NULL, NULL);
  return (result != ERROR_SUCCESS) ? 0 : count;
}

GONG RegKey::ReadName(int index, std::wstring* name) const {
  base::ThreadRestrictions::AssertIOAllowed();
  wchar_t buf[256];
  DWORD bufsize = arraysize(buf);
  LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL);
  if (r == ERROR_SUCCESS)
    *name = buf;

  return r;
}

GONG RegKey::DeleteKey(const wchar_t* name) {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(key_);
  DCHECK(name);
  LONG result = SHDeleteKey(key_, name);
  return result;
}

GONG RegKey::DeleteValue(const wchar_t* value_name) {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(key_);
  DCHECK(value_name);
  LONG result = RegDeleteValue(key_, value_name);
  return result;
}

bool RegKey::ValueExists(const wchar_t* name) const {
  base::ThreadRestrictions::AssertIOAllowed();
  LONG result = RegQueryValueEx(key_, name, 0, NULL, NULL, NULL);
  return result == ERROR_SUCCESS;
}

GONG RegKey::ReadValue(const wchar_t* name, void* data, DWORD* dsize,
                       DWORD* dtype) const {
  base::ThreadRestrictions::AssertIOAllowed();
  LONG result = RegQueryValueEx(key_, name, 0, dtype,
                                reinterpret_cast<LPBYTE>(data), dsize);
  return result;
}

GONG RegKey::ReadValue(const wchar_t* name, std::wstring* value) const {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(value);
  const size_t kMaxStringLength = 1024;  // This is after expansion.
  // Use the one of the other forms of ReadValue if 1024 is too small for you.
  wchar_t raw_value[kMaxStringLength];
  DWORD type = REG_SZ, size = sizeof(raw_value);
  LONG result = ReadValue(name, raw_value, &size, &type);
  if (result == ERROR_SUCCESS) {
    if (type == REG_SZ) {
      *value = raw_value;
    } else if (type == REG_EXPAND_SZ) {
      wchar_t expanded[kMaxStringLength];
      size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
      // Success: returns the number of wchar_t's copied
      // Fail: buffer too small, returns the size required
      // Fail: other, returns 0
      if (size == 0 || size > kMaxStringLength) {
        result = ERROR_MORE_DATA;
      } else {
        *value = expanded;
      }
    } else {
      // Not a string. Oops.
      result = ERROR_CANTREAD;
    }
  }

  return result;
}

GONG RegKey::ReadValueDW(const wchar_t* name, DWORD* value) const {
  DCHECK(value);
  DWORD type = REG_DWORD;
  DWORD size = sizeof(DWORD);
  DWORD local_value = 0;
  LONG result = ReadValue(name, &local_value, &size, &type);
  if (result == ERROR_SUCCESS) {
    if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD)) {
      *value = local_value;
    } else {
      result = ERROR_CANTREAD;
    }
  }

  return result;
}

GONG RegKey::ReadInt64(const wchar_t* name, int64* value) const {
  DCHECK(value);
  DWORD type = REG_QWORD;
  int64 local_value = 0;
  DWORD size = sizeof(local_value);
  LONG result = ReadValue(name, &local_value, &size, &type);
  if (result == ERROR_SUCCESS) {
    if ((type == REG_QWORD || type == REG_BINARY) &&
        size == sizeof(local_value)) {
      *value = local_value;
    } else {
      result = ERROR_CANTREAD;
    }
  }

  return result;
}

GONG RegKey::WriteValue(const wchar_t* name, const void * data,
                        DWORD dsize, DWORD dtype) {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(data);
  DCHECK(key_);

  LONG result = RegSetValueEx(key_, name, 0, dtype,
      reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
  return result;
}

GONG RegKey::WriteValue(const wchar_t * name, const wchar_t* value) {
  return WriteValue(name, value,
      static_cast<DWORD>(sizeof(*value) * (wcslen(value) + 1)), REG_SZ);
}

GONG RegKey::WriteValue(const wchar_t* name, DWORD value) {
  return WriteValue(name, &value, static_cast<DWORD>(sizeof(value)), REG_DWORD);
}

GONG RegKey::StartWatching() {
  DCHECK(key_);
  if (!watch_event_)
    watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);

  DWORD filter = REG_NOTIFY_CHANGE_NAME |
                 REG_NOTIFY_CHANGE_ATTRIBUTES |
                 REG_NOTIFY_CHANGE_LAST_SET |
                 REG_NOTIFY_CHANGE_SECURITY;

  // Watch the registry key for a change of value.
  LONG result = RegNotifyChangeKeyValue(key_, TRUE, filter, watch_event_, TRUE);
  if (result != ERROR_SUCCESS) {
    CloseHandle(watch_event_);
    watch_event_ = 0;
  }

  return result;
}

bool RegKey::HasChanged() {
  if (watch_event_) {
    if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
      StartWatching();
      return true;
    }
  }
  return false;
}

GONG RegKey::StopWatching() {
  LONG result = ERROR_INVALID_HANDLE;
  if (watch_event_) {
    CloseHandle(watch_event_);
    watch_event_ = 0;
    result = ERROR_SUCCESS;
  }
  return result;
}

// RegistryValueIterator ------------------------------------------------------

RegistryValueIterator::RegistryValueIterator(HKEY root_key,
                                             const wchar_t* folder_key) {
  base::ThreadRestrictions::AssertIOAllowed();

  LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
  if (result != ERROR_SUCCESS) {
    key_ = NULL;
  } else {
    DWORD count = 0;
    result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
                               NULL, NULL, NULL, NULL);

    if (result != ERROR_SUCCESS) {
      ::RegCloseKey(key_);
      key_ = NULL;
    } else {
      index_ = count - 1;
    }
  }

  Read();
}

RegistryValueIterator::~RegistryValueIterator() {
  base::ThreadRestrictions::AssertIOAllowed();
  if (key_)
    ::RegCloseKey(key_);
}

DWORD RegistryValueIterator::ValueCount() const {
  base::ThreadRestrictions::AssertIOAllowed();
  DWORD count = 0;
  LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
                                  &count, NULL, NULL, NULL, NULL);
  if (result != ERROR_SUCCESS)
    return 0;

  return count;
}

bool RegistryValueIterator::Valid() const {
  return key_ != NULL && index_ >= 0;
}

void RegistryValueIterator::operator++() {
  --index_;
  Read();
}

bool RegistryValueIterator::Read() {
  base::ThreadRestrictions::AssertIOAllowed();
  if (Valid()) {
    DWORD ncount = arraysize(name_);
    value_size_ = sizeof(value_);
    LONG r = ::RegEnumValue(key_, index_, name_, &ncount, NULL, &type_,
                            reinterpret_cast<BYTE*>(value_), &value_size_);
    if (ERROR_SUCCESS == r)
      return true;
  }

  name_[0] = '\0';
  value_[0] = '\0';
  value_size_ = 0;
  return false;
}

// RegistryKeyIterator --------------------------------------------------------

RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
                                         const wchar_t* folder_key) {
  base::ThreadRestrictions::AssertIOAllowed();
  LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
  if (result != ERROR_SUCCESS) {
    key_ = NULL;
  } else {
    DWORD count = 0;
    LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
                                    NULL, NULL, NULL, NULL, NULL);

    if (result != ERROR_SUCCESS) {
      ::RegCloseKey(key_);
      key_ = NULL;
    } else {
      index_ = count - 1;
    }
  }

  Read();
}

RegistryKeyIterator::~RegistryKeyIterator() {
  base::ThreadRestrictions::AssertIOAllowed();
  if (key_)
    ::RegCloseKey(key_);
}

DWORD RegistryKeyIterator::SubkeyCount() const {
  base::ThreadRestrictions::AssertIOAllowed();
  DWORD count = 0;
  LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
                                  NULL, NULL, NULL, NULL, NULL);
  if (result != ERROR_SUCCESS)
    return 0;

  return count;
}

bool RegistryKeyIterator::Valid() const {
  return key_ != NULL && index_ >= 0;
}

void RegistryKeyIterator::operator++() {
  --index_;
  Read();
}

bool RegistryKeyIterator::Read() {
  base::ThreadRestrictions::AssertIOAllowed();
  if (Valid()) {
    DWORD ncount = arraysize(name_);
    FILETIME written;
    LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
                            NULL, &written);
    if (ERROR_SUCCESS == r)
      return true;
  }

  name_[0] = '\0';
  return false;
}

}  // namespace win
}  // namespace base
<commit_msg>Remove unnecessary DCHECK causing unit test failure.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/win/registry.h"

#include <shlwapi.h>

#include "base/logging.h"
#include "base/threading/thread_restrictions.h"

#pragma comment(lib, "shlwapi.lib")  // for SHDeleteKey

namespace base {
namespace win {

// RegKey ----------------------------------------------------------------------

RegKey::RegKey()
    : key_(NULL),
      watch_event_(0) {
}

RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
    : key_(NULL),
      watch_event_(0) {
  base::ThreadRestrictions::AssertIOAllowed();
  if (rootkey) {
    if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
      Create(rootkey, subkey, access);
    else
      Open(rootkey, subkey, access);
  } else {
    DCHECK(!subkey);
  }
}

RegKey::~RegKey() {
  Close();
}

GONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
  DWORD disposition_value;
  return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
}

GONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
                                   DWORD* disposition, REGSAM access) {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(rootkey && subkey && access && disposition);
  Close();

  LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
                               REG_OPTION_NON_VOLATILE, access, NULL, &key_,
                               disposition);
  return result;
}

GONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(rootkey && subkey && access);
  Close();

  LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
  return result;
}

GONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(name && access);

  HKEY subkey = NULL;
  LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
                               access, NULL, &subkey, NULL);
  Close();

  key_ = subkey;
  return result;
}

GONG RegKey::OpenKey(const wchar_t* name, REGSAM access) {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(name && access);

  HKEY subkey = NULL;
  LONG result = RegOpenKeyEx(key_, name, 0, access, &subkey);

  Close();

  key_ = subkey;
  return result;
}

void RegKey::Close() {
  base::ThreadRestrictions::AssertIOAllowed();
  StopWatching();
  if (key_) {
    ::RegCloseKey(key_);
    key_ = NULL;
  }
}

DWORD RegKey::ValueCount() const {
  base::ThreadRestrictions::AssertIOAllowed();
  DWORD count = 0;
  LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
                                NULL, NULL, NULL, NULL);
  return (result != ERROR_SUCCESS) ? 0 : count;
}

GONG RegKey::ReadName(int index, std::wstring* name) const {
  base::ThreadRestrictions::AssertIOAllowed();
  wchar_t buf[256];
  DWORD bufsize = arraysize(buf);
  LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL);
  if (r == ERROR_SUCCESS)
    *name = buf;

  return r;
}

GONG RegKey::DeleteKey(const wchar_t* name) {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(key_);
  DCHECK(name);
  LONG result = SHDeleteKey(key_, name);
  return result;
}

GONG RegKey::DeleteValue(const wchar_t* value_name) {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(key_);
  DCHECK(value_name);
  LONG result = RegDeleteValue(key_, value_name);
  return result;
}

bool RegKey::ValueExists(const wchar_t* name) const {
  base::ThreadRestrictions::AssertIOAllowed();
  LONG result = RegQueryValueEx(key_, name, 0, NULL, NULL, NULL);
  return result == ERROR_SUCCESS;
}

GONG RegKey::ReadValue(const wchar_t* name, void* data, DWORD* dsize,
                       DWORD* dtype) const {
  base::ThreadRestrictions::AssertIOAllowed();
  LONG result = RegQueryValueEx(key_, name, 0, dtype,
                                reinterpret_cast<LPBYTE>(data), dsize);
  return result;
}

GONG RegKey::ReadValue(const wchar_t* name, std::wstring* value) const {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(value);
  const size_t kMaxStringLength = 1024;  // This is after expansion.
  // Use the one of the other forms of ReadValue if 1024 is too small for you.
  wchar_t raw_value[kMaxStringLength];
  DWORD type = REG_SZ, size = sizeof(raw_value);
  LONG result = ReadValue(name, raw_value, &size, &type);
  if (result == ERROR_SUCCESS) {
    if (type == REG_SZ) {
      *value = raw_value;
    } else if (type == REG_EXPAND_SZ) {
      wchar_t expanded[kMaxStringLength];
      size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
      // Success: returns the number of wchar_t's copied
      // Fail: buffer too small, returns the size required
      // Fail: other, returns 0
      if (size == 0 || size > kMaxStringLength) {
        result = ERROR_MORE_DATA;
      } else {
        *value = expanded;
      }
    } else {
      // Not a string. Oops.
      result = ERROR_CANTREAD;
    }
  }

  return result;
}

GONG RegKey::ReadValueDW(const wchar_t* name, DWORD* value) const {
  DCHECK(value);
  DWORD type = REG_DWORD;
  DWORD size = sizeof(DWORD);
  DWORD local_value = 0;
  LONG result = ReadValue(name, &local_value, &size, &type);
  if (result == ERROR_SUCCESS) {
    if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD)) {
      *value = local_value;
    } else {
      result = ERROR_CANTREAD;
    }
  }

  return result;
}

GONG RegKey::ReadInt64(const wchar_t* name, int64* value) const {
  DCHECK(value);
  DWORD type = REG_QWORD;
  int64 local_value = 0;
  DWORD size = sizeof(local_value);
  LONG result = ReadValue(name, &local_value, &size, &type);
  if (result == ERROR_SUCCESS) {
    if ((type == REG_QWORD || type == REG_BINARY) &&
        size == sizeof(local_value)) {
      *value = local_value;
    } else {
      result = ERROR_CANTREAD;
    }
  }

  return result;
}

GONG RegKey::WriteValue(const wchar_t* name, const void * data,
                        DWORD dsize, DWORD dtype) {
  base::ThreadRestrictions::AssertIOAllowed();
  DCHECK(data);

  LONG result = RegSetValueEx(key_, name, 0, dtype,
      reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
  return result;
}

GONG RegKey::WriteValue(const wchar_t * name, const wchar_t* value) {
  return WriteValue(name, value,
      static_cast<DWORD>(sizeof(*value) * (wcslen(value) + 1)), REG_SZ);
}

GONG RegKey::WriteValue(const wchar_t* name, DWORD value) {
  return WriteValue(name, &value, static_cast<DWORD>(sizeof(value)), REG_DWORD);
}

GONG RegKey::StartWatching() {
  DCHECK(key_);
  if (!watch_event_)
    watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);

  DWORD filter = REG_NOTIFY_CHANGE_NAME |
                 REG_NOTIFY_CHANGE_ATTRIBUTES |
                 REG_NOTIFY_CHANGE_LAST_SET |
                 REG_NOTIFY_CHANGE_SECURITY;

  // Watch the registry key for a change of value.
  LONG result = RegNotifyChangeKeyValue(key_, TRUE, filter, watch_event_, TRUE);
  if (result != ERROR_SUCCESS) {
    CloseHandle(watch_event_);
    watch_event_ = 0;
  }

  return result;
}

bool RegKey::HasChanged() {
  if (watch_event_) {
    if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
      StartWatching();
      return true;
    }
  }
  return false;
}

GONG RegKey::StopWatching() {
  LONG result = ERROR_INVALID_HANDLE;
  if (watch_event_) {
    CloseHandle(watch_event_);
    watch_event_ = 0;
    result = ERROR_SUCCESS;
  }
  return result;
}

// RegistryValueIterator ------------------------------------------------------

RegistryValueIterator::RegistryValueIterator(HKEY root_key,
                                             const wchar_t* folder_key) {
  base::ThreadRestrictions::AssertIOAllowed();

  LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
  if (result != ERROR_SUCCESS) {
    key_ = NULL;
  } else {
    DWORD count = 0;
    result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
                               NULL, NULL, NULL, NULL);

    if (result != ERROR_SUCCESS) {
      ::RegCloseKey(key_);
      key_ = NULL;
    } else {
      index_ = count - 1;
    }
  }

  Read();
}

RegistryValueIterator::~RegistryValueIterator() {
  base::ThreadRestrictions::AssertIOAllowed();
  if (key_)
    ::RegCloseKey(key_);
}

DWORD RegistryValueIterator::ValueCount() const {
  base::ThreadRestrictions::AssertIOAllowed();
  DWORD count = 0;
  LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
                                  &count, NULL, NULL, NULL, NULL);
  if (result != ERROR_SUCCESS)
    return 0;

  return count;
}

bool RegistryValueIterator::Valid() const {
  return key_ != NULL && index_ >= 0;
}

void RegistryValueIterator::operator++() {
  --index_;
  Read();
}

bool RegistryValueIterator::Read() {
  base::ThreadRestrictions::AssertIOAllowed();
  if (Valid()) {
    DWORD ncount = arraysize(name_);
    value_size_ = sizeof(value_);
    LONG r = ::RegEnumValue(key_, index_, name_, &ncount, NULL, &type_,
                            reinterpret_cast<BYTE*>(value_), &value_size_);
    if (ERROR_SUCCESS == r)
      return true;
  }

  name_[0] = '\0';
  value_[0] = '\0';
  value_size_ = 0;
  return false;
}

// RegistryKeyIterator --------------------------------------------------------

RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
                                         const wchar_t* folder_key) {
  base::ThreadRestrictions::AssertIOAllowed();
  LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
  if (result != ERROR_SUCCESS) {
    key_ = NULL;
  } else {
    DWORD count = 0;
    LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
                                    NULL, NULL, NULL, NULL, NULL);

    if (result != ERROR_SUCCESS) {
      ::RegCloseKey(key_);
      key_ = NULL;
    } else {
      index_ = count - 1;
    }
  }

  Read();
}

RegistryKeyIterator::~RegistryKeyIterator() {
  base::ThreadRestrictions::AssertIOAllowed();
  if (key_)
    ::RegCloseKey(key_);
}

DWORD RegistryKeyIterator::SubkeyCount() const {
  base::ThreadRestrictions::AssertIOAllowed();
  DWORD count = 0;
  LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
                                  NULL, NULL, NULL, NULL, NULL);
  if (result != ERROR_SUCCESS)
    return 0;

  return count;
}

bool RegistryKeyIterator::Valid() const {
  return key_ != NULL && index_ >= 0;
}

void RegistryKeyIterator::operator++() {
  --index_;
  Read();
}

bool RegistryKeyIterator::Read() {
  base::ThreadRestrictions::AssertIOAllowed();
  if (Valid()) {
    DWORD ncount = arraysize(name_);
    FILETIME written;
    LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
                            NULL, &written);
    if (ERROR_SUCCESS == r)
      return true;
  }

  name_[0] = '\0';
  return false;
}

}  // namespace win
}  // namespace base
<|endoftext|>


<commit_before>#ifndef _EIGEN3_HDF5_HPP
#define _EIGEN3_HDF5_HPP

#include <array>
#include <cassert>
#include <complex>
#include <cstddef>
#include <stdexcept>
#include <string>
#include <vector>

//#include <hdf5.h>
#include <H5Cpp.h>
#include <Eigen/Dense>

namespace EigenHDF5
{

template <typename T>
struct DatatypeSpecialization;

// floating-point types

template <>
struct DatatypeSpecialization<float>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_FLOAT;
        }
};

template <>
struct DatatypeSpecialization<double>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_DOUBLE;
        }
};

template <>
struct DatatypeSpecialization<long double>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_LDOUBLE;
        }
};

// integer types

template <>
struct DatatypeSpecialization<int>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_INT;
        }
};

template <>
struct DatatypeSpecialization<unsigned int>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_UINT;
        }
};

// complex types
//
// inspired by http://www.mail-archive.com/hdf-forum@hdfgroup.org/msg00759.html

template <typename T>
class ComplexH5Type : public H5::CompType
{
public:
    ComplexH5Type (void)
        : CompType(sizeof(std::complex<T>))
        {
            const H5::DataType * const datatype = DatatypeSpecialization<T>::get();
            assert(datatype->getSize() == sizeof(T));
            // If we call the members "r" and "i", h5py interprets the
            // structure correctly as complex numbers.
            this->insertMember(std::string("r"), 0, *datatype);
            this->insertMember(std::string("i"), sizeof(T), *datatype);
            this->pack();
        }

    static const ComplexH5Type<T> * get_singleton (void)
        {
            // NOTE: constructing this could be a race condition
            static ComplexH5Type<T> singleton;
            return &singleton;
        }
};

template <typename T>
struct DatatypeSpecialization<std::complex<T> >
{
    static inline const H5::DataType * get (void)
        {
            return ComplexH5Type<T>::get_singleton();
        }
};

// see http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html

template <typename Derived>
void save (H5::H5File &file, const std::string &name, const Eigen::EigenBase<Derived> &mat)
{
    typedef typename Derived::Scalar Scalar;
    const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> row_major_mat(mat);
    const std::array<hsize_t, 2> dimensions = { {
        static_cast<hsize_t>(mat.rows()),
        static_cast<hsize_t>(mat.cols())
    } };
    const H5::DataSpace dataspace(dimensions.size(), dimensions.data());
    const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
    H5::DataSet dataset = file.createDataSet(name, *datatype, dataspace);
    dataset.write(row_major_mat.data(), *datatype);
}

template <typename Derived>
void load (const H5::H5File &file, const std::string &name, const Eigen::DenseBase<Derived> &mat)
{
    typedef typename Derived::Scalar Scalar;
    const H5::DataSet dataset = file.openDataSet(name);
    const H5::DataSpace dataspace = dataset.getSpace();
    const std::size_t ndims = dataspace.getSimpleExtentNdims();
    assert(ndims > 0);
    std::array<hsize_t, 2> dimensions;
    dimensions[1] = 1; // in case it's 1D
    if (ndims > dimensions.size()) {
        throw std::runtime_error("HDF5 array has too many dimensions.");
    }
    dataspace.getSimpleExtentDims(dimensions.data());
    const hsize_t rows = dimensions[0], cols = dimensions[1];
    std::vector<Scalar> data(rows * cols);
    const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
    dataset.read(data.data(), *datatype, dataspace);
    // see http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
    Eigen::DenseBase<Derived> &mat_ = const_cast<Eigen::DenseBase<Derived> &>(mat);
    mat_.derived().resize(rows, cols);
    mat_ = Eigen::Map<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> >(data.data(), rows, cols);
}

} // namespace EigenHDF5

#endif
<commit_msg>now works with H5::Group objects in addition to files<commit_after>#ifndef _EIGEN3_HDF5_HPP
#define _EIGEN3_HDF5_HPP

#include <array>
#include <cassert>
#include <complex>
#include <cstddef>
#include <stdexcept>
#include <string>
#include <vector>

//#include <hdf5.h>
#include <H5Cpp.h>
#include <Eigen/Dense>

namespace EigenHDF5
{

template <typename T>
struct DatatypeSpecialization;

// floating-point types

template <>
struct DatatypeSpecialization<float>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_FLOAT;
        }
};

template <>
struct DatatypeSpecialization<double>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_DOUBLE;
        }
};

template <>
struct DatatypeSpecialization<long double>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_LDOUBLE;
        }
};

// integer types

template <>
struct DatatypeSpecialization<int>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_INT;
        }
};

template <>
struct DatatypeSpecialization<unsigned int>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_UINT;
        }
};

// complex types
//
// inspired by http://www.mail-archive.com/hdf-forum@hdfgroup.org/msg00759.html

template <typename T>
class ComplexH5Type : public H5::CompType
{
public:
    ComplexH5Type (void)
        : CompType(sizeof(std::complex<T>))
        {
            const H5::DataType * const datatype = DatatypeSpecialization<T>::get();
            assert(datatype->getSize() == sizeof(T));
            // If we call the members "r" and "i", h5py interprets the
            // structure correctly as complex numbers.
            this->insertMember(std::string("r"), 0, *datatype);
            this->insertMember(std::string("i"), sizeof(T), *datatype);
            this->pack();
        }

    static const ComplexH5Type<T> * get_singleton (void)
        {
            // NOTE: constructing this could be a race condition
            static ComplexH5Type<T> singleton;
            return &singleton;
        }
};

template <typename T>
struct DatatypeSpecialization<std::complex<T> >
{
    static inline const H5::DataType * get (void)
        {
            return ComplexH5Type<T>::get_singleton();
        }
};

// see http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html

template <typename Derived>
void save (H5::CommonFG &h5group, const std::string &name, const Eigen::EigenBase<Derived> &mat)
{
    typedef typename Derived::Scalar Scalar;
    const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> row_major_mat(mat);
    const std::array<hsize_t, 2> dimensions = { {
        static_cast<hsize_t>(mat.rows()),
        static_cast<hsize_t>(mat.cols())
    } };
    const H5::DataSpace dataspace(dimensions.size(), dimensions.data());
    const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
    H5::DataSet dataset = h5group.createDataSet(name, *datatype, dataspace);
    dataset.write(row_major_mat.data(), *datatype);
}

template <typename Derived>
void load (const H5::CommonFG &h5group, const std::string &name, const Eigen::DenseBase<Derived> &mat)
{
    typedef typename Derived::Scalar Scalar;
    const H5::DataSet dataset = h5group.openDataSet(name);
    const H5::DataSpace dataspace = dataset.getSpace();
    const std::size_t ndims = dataspace.getSimpleExtentNdims();
    assert(ndims > 0);
    std::array<hsize_t, 2> dimensions;
    dimensions[1] = 1; // in case it's 1D
    if (ndims > dimensions.size()) {
        throw std::runtime_error("HDF5 array has too many dimensions.");
    }
    dataspace.getSimpleExtentDims(dimensions.data());
    const hsize_t rows = dimensions[0], cols = dimensions[1];
    std::vector<Scalar> data(rows * cols);
    const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
    dataset.read(data.data(), *datatype, dataspace);
    // see http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
    Eigen::DenseBase<Derived> &mat_ = const_cast<Eigen::DenseBase<Derived> &>(mat);
    mat_.derived().resize(rows, cols);
    mat_ = Eigen::Map<Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> >(data.data(), rows, cols);
}

} // namespace EigenHDF5

#endif
<|endoftext|>


<commit_before>// Clip Library
// Copyright (c) 2018 David Capello

#include "clip.h"
#include "clip_x11.h"

#include <xcb/xcb.h>

#include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <map>
#include <memory>
#include <mutex>
#include <thread>
#include <vector>

namespace clip {

class Manager {
public:
  typedef std::shared_ptr<std::vector<uint8_t>> buffer_ptr;
  typedef std::vector<xcb_atom_t> atoms;

  Manager()
    : m_connection(xcb_connect(nullptr, nullptr))
    , m_stop(false) {
    xcb_screen_t* screen =
      xcb_setup_roots_iterator(xcb_get_setup(m_connection)).data;
    m_window = xcb_generate_id(m_connection);
    xcb_create_window(m_connection, 0,
                      m_window,
                      screen->root,
                      0, 0, 1, 1, 0,
                      XCB_WINDOW_CLASS_INPUT_OUTPUT,
                      screen->root_visual,
                      0, nullptr);

    m_thread = std::thread(
      [this]{
        process_x11_events();
      });
  }

  ~Manager() {
    // TODO remove this and create some method to keep the clipboard alive.
    std::this_thread::sleep_for(std::chrono::seconds(10));

    m_stop = true;
    m_thread.join();

    xcb_destroy_window(m_connection, m_window);
    xcb_disconnect(m_connection);
  }

  bool try_lock() { return m_mutex.try_lock(); }
  void unlock() { m_mutex.unlock(); }

  void clear() {
    m_data.clear();
  }

  bool is_convertible(format f) const {
    if (f == text_format()) {
      xcb_window_t owner = get_x11_selection_owner();
      if (owner == m_window) {
        for (xcb_atom_t atom : get_text_format_atoms()) {
          auto it = m_data.find(atom);
          if (it != m_data.end())
            return true;
        }
      }
      else {
        // TODO ask atoms to selection owner
      }
    }
    return false;
  }

  bool set_data(format f, const char* buf, size_t len) {
    if (!set_x11_selection_owner())
      return false;

    if (f == text_format()) {
      buffer_ptr shared_text_buf = std::make_shared<std::vector<uint8_t>>(len);
      std::copy(buf,
                buf+len,
                shared_text_buf->begin());
      for (xcb_atom_t atom : get_text_format_atoms())
        m_data[atom] = shared_text_buf;
      return true;
    }
    return false;
  }

  bool get_data(format f, char* buf, size_t len) const {
    if (f == text_format()) {
      xcb_window_t owner = get_x11_selection_owner();
      if (owner == m_window) {
        for (xcb_atom_t atom : get_text_format_atoms()) {
          auto it = m_data.find(atom);
          if (it != m_data.end()) {
            std::copy(it->second->begin(),
                      it->second->begin()+std::min(len, it->second->size()),
                      buf);
            return true;
          }
        }
      }
      else {
        // TODO ask data content to selection owner
      }
    }
    return false;
  }

  size_t get_data_length(format f) const {
    if (f == text_format()) {
      xcb_window_t owner = get_x11_selection_owner();
      if (owner == m_window) {
        for (xcb_atom_t atom : get_text_format_atoms()) {
          auto it = m_data.find(atom);
          if (it != m_data.end())
            return it->second->size();
        }
      }
      else {
        // TODO ask data length to selection owner
      }
    }
    return 0;
  }

private:

  void process_x11_events() {
    xcb_generic_event_t* event;
    while (!m_stop) {
      while ((event = xcb_poll_for_event(m_connection))) {
        int type = (event->response_type & ~0x80);
        switch (type) {

          // Someone else has new content in the clipboard, so is
          // notifying us that we should delete our data now.
          case XCB_SELECTION_CLEAR:
            handle_selection_clear_event(
              (xcb_selection_clear_event_t*)event);
            break;

          // Someone is requesting the clipboard content from us.
          case XCB_SELECTION_REQUEST:
            handle_selection_request_event(
              (xcb_selection_request_event_t*)event);
            break;

          // We've requested the clipboard content and this is the
          // answer.
          case XCB_SELECTION_NOTIFY:
            handle_selection_notify_event(
              (xcb_selection_notify_event_t*)event);
            break;
        }

        free(event);
      }

      std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
  }

  void handle_selection_clear_event(xcb_selection_clear_event_t* event) {
    if (event->selection == get_atom("CLIPBOARD")) {
      std::lock_guard<std::mutex> lock(m_mutex);
      clear(); // Clear our clipboard data
    }
  }

  void handle_selection_request_event(xcb_selection_request_event_t* event) {
    std::lock_guard<std::mutex> lock(m_mutex);

    if (event->target == get_atom("TARGETS")) {
      atoms targets;
      for (const auto& it : m_data)
        targets.push_back(it.first);

      // Set the "property" of "requestor" with the clipboard
      // formats ("targets", atoms) that we provide.
      xcb_change_property(
        m_connection,
        XCB_PROP_MODE_REPLACE,
        event->requestor,
        event->property,
        event->target,
        8*sizeof(xcb_atom_t),
        targets.size(),
        &targets[0]);
    }
    else {
      auto it = m_data.find(event->target);
      if (it != m_data.end()) {
        // Set the "property" of "requestor" with the
        // clipboard content in the requested format ("target").
        xcb_change_property(
          m_connection,
          XCB_PROP_MODE_REPLACE,
          event->requestor,
          event->property,
          event->target,
          8,
          it->second->size(),
          &(*it->second)[0]);
      }
    }

    // Notify the "requestor" that we've already updated the property.
    xcb_selection_notify_event_t notify;
    notify.response_type = XCB_SELECTION_NOTIFY;
    notify.pad0          = 0;
    notify.sequence      = 0;
    notify.time          = XCB_CURRENT_TIME;
    notify.requestor     = event->requestor;
    notify.selection     = event->selection;
    notify.target        = event->target;
    notify.property      = event->property;
    xcb_send_event(m_connection, false,
                   event->requestor,
                   XCB_EVENT_MASK_PROPERTY_CHANGE,
                   (const char*)&notify);

    xcb_flush(m_connection);
  }

  void handle_selection_notify_event(xcb_selection_notify_event_t* event) {
    // TODO
  }

  atoms get_atoms(const char** names,
                  const int n) const {
    atoms result(n, 0);
    std::vector<xcb_intern_atom_cookie_t> cookies(n);

    for (int i=0; i<n; ++i) {
      auto it = m_atoms.find(names[i]);
      if (it != m_atoms.end())
        result[i] = it->second;
      else
        cookies[i] = xcb_intern_atom(
          m_connection, 0,
          std::strlen(names[i]), names[i]);
    }

    for (int i=0; i<n; ++i) {
      if (result[i] == 0) {
        xcb_intern_atom_reply_t* reply =
          xcb_intern_atom_reply(m_connection,
                                cookies[i],
                                nullptr);
        if (reply) {
          result[i] = m_atoms[names[i]] = reply->atom;
          free(reply);
        }
      }
    }

    return result;
  }

  xcb_atom_t get_atom(const char* name) const {
    auto it = m_atoms.find(name);
    if (it != m_atoms.end())
      return it->second;

    xcb_atom_t result = 0;
    xcb_intern_atom_cookie_t cookie =
      xcb_intern_atom(m_connection, 0,
                      std::strlen(name), name);

    xcb_intern_atom_reply_t* reply =
      xcb_intern_atom_reply(m_connection,
                            cookie,
                            nullptr);
    if (reply) {
      result = m_atoms[name] = reply->atom;
      free(reply);
    }
    return result;
  }

  const atoms& get_text_format_atoms() const {
    if (m_text_atoms.empty()) {
      const char* names[] = {
        "UTF8_STRING",
        "STRING",
        "TEXT",
        "text/plain",
        "text/plain;charset=utf-8",
        "text/plain;charset=UTF-8"
      };
      m_text_atoms = get_atoms(names, sizeof(names) / sizeof(names[0]));
    }
    return m_text_atoms;
  }

  bool set_x11_selection_owner() const {
    xcb_void_cookie_t cookie =
      xcb_set_selection_owner_checked(m_connection,
                                      m_window,
                                      get_atom("CLIPBOARD"),
                                      XCB_CURRENT_TIME);
    xcb_generic_error_t* err =
      xcb_request_check(m_connection,
                        cookie);
    if (err) {
      free(err);
      return false;
    }
    return true;
  }

  xcb_window_t get_x11_selection_owner() const {
    xcb_window_t result = 0;
    xcb_get_selection_owner_cookie_t cookie =
      xcb_get_selection_owner(m_connection,
                              get_atom("CLIPBOARD"));

    xcb_get_selection_owner_reply_t* reply =
      xcb_get_selection_owner_reply(m_connection, cookie, nullptr);
    if (reply) {
      result = reply->owner;
      free(reply);
    }
    return result;
  }

  xcb_connection_t* m_connection;
  xcb_window_t m_window;
  bool m_stop;
  std::thread m_thread;
  mutable std::map<std::string, xcb_atom_t> m_atoms; // Cache of known atoms
  mutable atoms m_text_atoms;                        // Cache of atoms related to text content
  std::map<xcb_atom_t, buffer_ptr> m_data;           // Actual clipboard data
  std::mutex m_mutex;
};

static Manager* manager = nullptr;
static void delete_manager_atexit() {
  if (manager) {
    delete manager;
    manager = nullptr;
  }
}

lock::impl::impl(void*) : m_locked(false) {
  if (!manager) {
    manager = new Manager;
    std::atexit(delete_manager_atexit);
  }
  m_locked = manager->try_lock();
}

lock::impl::~impl() {
  if (m_locked)
    manager->unlock();
}

bool lock::impl::locked() const {
  return m_locked;
}

bool lock::impl::clear() {
  manager->clear();
  return true;
}

bool lock::impl::is_convertible(format f) const {
  return manager->is_convertible(f);
}

bool lock::impl::set_data(format f, const char* buf, size_t len) {
  return manager->set_data(f, buf, len);
}

bool lock::impl::get_data(format f, char* buf, size_t len) const {
  return manager->get_data(f, buf, len);
}

size_t lock::impl::get_data_length(format f) const {
  return manager->get_data_length(f);
}

bool lock::impl::set_image(const image& image) {
  return false;                 // TODO
}

bool lock::impl::get_image(image& output_img) const {
  return false;                 // TODO
}

bool lock::impl::get_image_spec(image_spec& spec) const {
  return false;                 // TODO
}

format register_format(const std::string& name) {
  return 0;                     // TODO
}

} // namespace clip
<commit_msg>Use an anonymous namespace instead of static definitions<commit_after>// Clip Library
// Copyright (c) 2018 David Capello

#include "clip.h"
#include "clip_x11.h"

#include <xcb/xcb.h>

#include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <map>
#include <memory>
#include <mutex>
#include <thread>
#include <vector>

namespace clip {

namespace {

class Manager {
public:
  typedef std::shared_ptr<std::vector<uint8_t>> buffer_ptr;
  typedef std::vector<xcb_atom_t> atoms;

  Manager()
    : m_connection(xcb_connect(nullptr, nullptr))
    , m_stop(false) {
    xcb_screen_t* screen =
      xcb_setup_roots_iterator(xcb_get_setup(m_connection)).data;
    m_window = xcb_generate_id(m_connection);
    xcb_create_window(m_connection, 0,
                      m_window,
                      screen->root,
                      0, 0, 1, 1, 0,
                      XCB_WINDOW_CLASS_INPUT_OUTPUT,
                      screen->root_visual,
                      0, nullptr);

    m_thread = std::thread(
      [this]{
        process_x11_events();
      });
  }

  ~Manager() {
    // TODO remove this and create some method to keep the clipboard alive.
    std::this_thread::sleep_for(std::chrono::seconds(10));

    m_stop = true;
    m_thread.join();

    xcb_destroy_window(m_connection, m_window);
    xcb_disconnect(m_connection);
  }

  bool try_lock() { return m_mutex.try_lock(); }
  void unlock() { m_mutex.unlock(); }

  void clear() {
    m_data.clear();
  }

  bool is_convertible(format f) const {
    if (f == text_format()) {
      xcb_window_t owner = get_x11_selection_owner();
      if (owner == m_window) {
        for (xcb_atom_t atom : get_text_format_atoms()) {
          auto it = m_data.find(atom);
          if (it != m_data.end())
            return true;
        }
      }
      else {
        // TODO ask atoms to selection owner
      }
    }
    return false;
  }

  bool set_data(format f, const char* buf, size_t len) {
    if (!set_x11_selection_owner())
      return false;

    if (f == text_format()) {
      buffer_ptr shared_text_buf = std::make_shared<std::vector<uint8_t>>(len);
      std::copy(buf,
                buf+len,
                shared_text_buf->begin());
      for (xcb_atom_t atom : get_text_format_atoms())
        m_data[atom] = shared_text_buf;
      return true;
    }
    return false;
  }

  bool get_data(format f, char* buf, size_t len) const {
    if (f == text_format()) {
      xcb_window_t owner = get_x11_selection_owner();
      if (owner == m_window) {
        for (xcb_atom_t atom : get_text_format_atoms()) {
          auto it = m_data.find(atom);
          if (it != m_data.end()) {
            std::copy(it->second->begin(),
                      it->second->begin()+std::min(len, it->second->size()),
                      buf);
            return true;
          }
        }
      }
      else {
        // TODO ask data content to selection owner
      }
    }
    return false;
  }

  size_t get_data_length(format f) const {
    if (f == text_format()) {
      xcb_window_t owner = get_x11_selection_owner();
      if (owner == m_window) {
        for (xcb_atom_t atom : get_text_format_atoms()) {
          auto it = m_data.find(atom);
          if (it != m_data.end())
            return it->second->size();
        }
      }
      else {
        // TODO ask data length to selection owner
      }
    }
    return 0;
  }

private:

  void process_x11_events() {
    xcb_generic_event_t* event;
    while (!m_stop) {
      while ((event = xcb_poll_for_event(m_connection))) {
        int type = (event->response_type & ~0x80);
        switch (type) {

          // Someone else has new content in the clipboard, so is
          // notifying us that we should delete our data now.
          case XCB_SELECTION_CLEAR:
            handle_selection_clear_event(
              (xcb_selection_clear_event_t*)event);
            break;

          // Someone is requesting the clipboard content from us.
          case XCB_SELECTION_REQUEST:
            handle_selection_request_event(
              (xcb_selection_request_event_t*)event);
            break;

          // We've requested the clipboard content and this is the
          // answer.
          case XCB_SELECTION_NOTIFY:
            handle_selection_notify_event(
              (xcb_selection_notify_event_t*)event);
            break;
        }

        free(event);
      }

      std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
  }

  void handle_selection_clear_event(xcb_selection_clear_event_t* event) {
    if (event->selection == get_atom("CLIPBOARD")) {
      std::lock_guard<std::mutex> lock(m_mutex);
      clear(); // Clear our clipboard data
    }
  }

  void handle_selection_request_event(xcb_selection_request_event_t* event) {
    std::lock_guard<std::mutex> lock(m_mutex);

    if (event->target == get_atom("TARGETS")) {
      atoms targets;
      for (const auto& it : m_data)
        targets.push_back(it.first);

      // Set the "property" of "requestor" with the clipboard
      // formats ("targets", atoms) that we provide.
      xcb_change_property(
        m_connection,
        XCB_PROP_MODE_REPLACE,
        event->requestor,
        event->property,
        event->target,
        8*sizeof(xcb_atom_t),
        targets.size(),
        &targets[0]);
    }
    else {
      auto it = m_data.find(event->target);
      if (it != m_data.end()) {
        // Set the "property" of "requestor" with the
        // clipboard content in the requested format ("target").
        xcb_change_property(
          m_connection,
          XCB_PROP_MODE_REPLACE,
          event->requestor,
          event->property,
          event->target,
          8,
          it->second->size(),
          &(*it->second)[0]);
      }
    }

    // Notify the "requestor" that we've already updated the property.
    xcb_selection_notify_event_t notify;
    notify.response_type = XCB_SELECTION_NOTIFY;
    notify.pad0          = 0;
    notify.sequence      = 0;
    notify.time          = XCB_CURRENT_TIME;
    notify.requestor     = event->requestor;
    notify.selection     = event->selection;
    notify.target        = event->target;
    notify.property      = event->property;
    xcb_send_event(m_connection, false,
                   event->requestor,
                   XCB_EVENT_MASK_PROPERTY_CHANGE,
                   (const char*)&notify);

    xcb_flush(m_connection);
  }

  void handle_selection_notify_event(xcb_selection_notify_event_t* event) {
    // TODO
  }

  atoms get_atoms(const char** names,
                  const int n) const {
    atoms result(n, 0);
    std::vector<xcb_intern_atom_cookie_t> cookies(n);

    for (int i=0; i<n; ++i) {
      auto it = m_atoms.find(names[i]);
      if (it != m_atoms.end())
        result[i] = it->second;
      else
        cookies[i] = xcb_intern_atom(
          m_connection, 0,
          std::strlen(names[i]), names[i]);
    }

    for (int i=0; i<n; ++i) {
      if (result[i] == 0) {
        xcb_intern_atom_reply_t* reply =
          xcb_intern_atom_reply(m_connection,
                                cookies[i],
                                nullptr);
        if (reply) {
          result[i] = m_atoms[names[i]] = reply->atom;
          free(reply);
        }
      }
    }

    return result;
  }

  xcb_atom_t get_atom(const char* name) const {
    auto it = m_atoms.find(name);
    if (it != m_atoms.end())
      return it->second;

    xcb_atom_t result = 0;
    xcb_intern_atom_cookie_t cookie =
      xcb_intern_atom(m_connection, 0,
                      std::strlen(name), name);

    xcb_intern_atom_reply_t* reply =
      xcb_intern_atom_reply(m_connection,
                            cookie,
                            nullptr);
    if (reply) {
      result = m_atoms[name] = reply->atom;
      free(reply);
    }
    return result;
  }

  const atoms& get_text_format_atoms() const {
    if (m_text_atoms.empty()) {
      const char* names[] = {
        "UTF8_STRING",
        "STRING",
        "TEXT",
        "text/plain",
        "text/plain;charset=utf-8",
        "text/plain;charset=UTF-8"
      };
      m_text_atoms = get_atoms(names, sizeof(names) / sizeof(names[0]));
    }
    return m_text_atoms;
  }

  bool set_x11_selection_owner() const {
    xcb_void_cookie_t cookie =
      xcb_set_selection_owner_checked(m_connection,
                                      m_window,
                                      get_atom("CLIPBOARD"),
                                      XCB_CURRENT_TIME);
    xcb_generic_error_t* err =
      xcb_request_check(m_connection,
                        cookie);
    if (err) {
      free(err);
      return false;
    }
    return true;
  }

  xcb_window_t get_x11_selection_owner() const {
    xcb_window_t result = 0;
    xcb_get_selection_owner_cookie_t cookie =
      xcb_get_selection_owner(m_connection,
                              get_atom("CLIPBOARD"));

    xcb_get_selection_owner_reply_t* reply =
      xcb_get_selection_owner_reply(m_connection, cookie, nullptr);
    if (reply) {
      result = reply->owner;
      free(reply);
    }
    return result;
  }

  xcb_connection_t* m_connection;
  xcb_window_t m_window;
  bool m_stop;
  std::thread m_thread;
  mutable std::map<std::string, xcb_atom_t> m_atoms; // Cache of known atoms
  mutable atoms m_text_atoms;                        // Cache of atoms related to text content
  std::map<xcb_atom_t, buffer_ptr> m_data;           // Actual clipboard data
  std::mutex m_mutex;
};

Manager* manager = nullptr;
void delete_manager_atexit() {
  if (manager) {
    delete manager;
    manager = nullptr;
  }
}

} // anonymous namespace

lock::impl::impl(void*) : m_locked(false) {
  if (!manager) {
    manager = new Manager;
    std::atexit(delete_manager_atexit);
  }
  m_locked = manager->try_lock();
}

lock::impl::~impl() {
  if (m_locked)
    manager->unlock();
}

bool lock::impl::locked() const {
  return m_locked;
}

bool lock::impl::clear() {
  manager->clear();
  return true;
}

bool lock::impl::is_convertible(format f) const {
  return manager->is_convertible(f);
}

bool lock::impl::set_data(format f, const char* buf, size_t len) {
  return manager->set_data(f, buf, len);
}

bool lock::impl::get_data(format f, char* buf, size_t len) const {
  return manager->get_data(f, buf, len);
}

size_t lock::impl::get_data_length(format f) const {
  return manager->get_data_length(f);
}

bool lock::impl::set_image(const image& image) {
  return false;                 // TODO
}

bool lock::impl::get_image(image& output_img) const {
  return false;                 // TODO
}

bool lock::impl::get_image_spec(image_spec& spec) const {
  return false;                 // TODO
}

format register_format(const std::string& name) {
  return 0;                     // TODO
}

} // namespace clip
<|endoftext|>