<commit_before>/*************************************************************************
 *
 *  $RCSfile: admininvokationimpl.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hjs $ $Date: 2004-06-28 17:10:49 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef EXTENSIONS_ABP_ADMININVOKATIONIMPL_HXX
#include "admininvokationimpl.hxx"
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_DIALOGS_XEXECUTABLEDIALOG_HPP_
#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
#endif
#ifndef _COM_SUN_STAR_AWT_XWINDOW_HPP_
#include <com/sun/star/awt/XWindow.hpp>
#endif
#ifndef _VCL_STDTEXT_HXX
#include <vcl/stdtext.hxx>
#endif
#ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_
#include <toolkit/unohlp.hxx>
#endif
#ifndef EXTENSIONS_ABPRESID_HRC
#include "abpresid.hrc"
#endif
#ifndef _EXTENSIONS_COMPONENT_MODULE_HXX_
#include "componentmodule.hxx"
#endif
#ifndef _SV_WAITOBJ_HXX
#include <vcl/waitobj.hxx>
#endif

//.........................................................................
namespace abp
{
//.........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::lang;
    using namespace ::com::sun::star::beans;
    using namespace ::com::sun::star::awt;
    using namespace ::com::sun::star::ui::dialogs;

    //=====================================================================
    //= OAdminDialogInvokation
    //=====================================================================
    //---------------------------------------------------------------------
    OAdminDialogInvokation::OAdminDialogInvokation(const Reference< XMultiServiceFactory >& _rxORB, const ::rtl::OUString& _rPreferredName, Window* _pMessageParent)
        :m_xORB(_rxORB)
        ,m_sPreferredName(_rPreferredName)
        ,m_pMessageParent(_pMessageParent)
    {
        DBG_ASSERT(m_xORB.is(), "OAdminDialogInvokation::OAdminDialogInvokation: invalid service factory!");
        DBG_ASSERT(m_sPreferredName.getLength(), "OAdminDialogInvokation::OAdminDialogInvokation: invalid preferred name!");
        DBG_ASSERT(m_pMessageParent, "OAdminDialogInvokation::OAdminDialogInvokation: invalid message parent!");
    }

    //---------------------------------------------------------------------
    sal_Bool OAdminDialogInvokation::invokeAdministration( sal_Bool _bFixedType )
    {
        if (!m_xORB.is())
            return sal_False;

        try
        {
            // the service name of the administration dialog
            static ::rtl::OUString s_sAdministrationServiceName = ::rtl::OUString::createFromAscii("com.sun.star.sdb.DatasourceAdministrationDialog");

            // the parameters for the call
            Sequence< Any > aArguments(4);
            Any* pArguments = aArguments.getArray();

            // the parent window
            Reference< XWindow > xDialogParent = VCLUnoHelper::GetInterface(m_pMessageParent);
            *pArguments++ <<= PropertyValue(::rtl::OUString::createFromAscii("ParentWindow"), -1, makeAny(xDialogParent), PropertyState_DIRECT_VALUE);

            // the mode indicating that we want allow creation of one single data source only
            ::rtl::OUString sDialogMode = ::rtl::OUString::createFromAscii( _bFixedType ? "SingleEditFixedType" : "SingleEdit" );
            *pArguments++ <<= PropertyValue(::rtl::OUString::createFromAscii("Mode"), -1, makeAny( sDialogMode ), PropertyState_DIRECT_VALUE);

            // the title of the dialog
            String sAdminDialogTitle(ModuleRes(RID_STR_ADMINDIALOGTITLE));
            *pArguments++ <<= PropertyValue(::rtl::OUString::createFromAscii("Title"), -1, makeAny(::rtl::OUString(sAdminDialogTitle)), PropertyState_DIRECT_VALUE);

            // the name of the new data source
            *pArguments++ <<= PropertyValue(::rtl::OUString::createFromAscii("InitialSelection"), -1, makeAny(m_sPreferredName), PropertyState_DIRECT_VALUE);

            // create the dialog
            Reference< XExecutableDialog > xDialog;
            {
                // creating the dialog service is potentially expensive (if all the libraries invoked need to be loaded)
                // so we display a wait cursor
                WaitObject aWaitCursor(m_pMessageParent);
                xDialog = Reference< XExecutableDialog >( m_xORB->createInstanceWithArguments( s_sAdministrationServiceName , aArguments ), UNO_QUERY );

                // just for a smoother UI: What the dialog does upon execution, is (amongst other things) creating
                // the DriverManager service
                // If this context has never been accessed before, this may be expensive (it includes loading of
                // at least one library).
                // As this wizard is intended to run on the first office start, it is very likely that the
                // context needs to be freshly created
                // Thus, we access the context here (within the WaitCursor), which means the user sees a waitcursor
                // while his/her office blocks a few seconds ....
                m_xORB->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.sdbc.DriverManager" ) );
            }

            if (xDialog.is())
            {   // execute it
                if (xDialog->execute())
                    return sal_True;
            }
            else
                ShowServiceNotAvailableError(m_pMessageParent, s_sAdministrationServiceName, sal_True);
        }
        catch(const Exception&)
        {
            DBG_ERROR("OAdminDialogInvokation::invokeAdministration: caught an exception while executing the dialog!");
        }
        return sal_False;
    }

//.........................................................................
}   // namespace abp
//.........................................................................

<commit_msg>INTEGRATION: CWS insight01 (1.2.182); FILE MERGED 2004/07/06 09:23:12 oj 1.2.182.2: RESYNC: (1.2-1.3); FILE MERGED 2004/04/16 12:07:05 oj 1.2.182.1: correct alignment and default<commit_after>/*************************************************************************
 *
 *  $RCSfile: admininvokationimpl.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: hr $ $Date: 2004-08-02 17:35:40 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef EXTENSIONS_ABP_ADMININVOKATIONIMPL_HXX
#include "admininvokationimpl.hxx"
#endif
#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_DIALOGS_XEXECUTABLEDIALOG_HPP_
#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
#endif
#ifndef _COM_SUN_STAR_AWT_XWINDOW_HPP_
#include <com/sun/star/awt/XWindow.hpp>
#endif
#ifndef _VCL_STDTEXT_HXX
#include <vcl/stdtext.hxx>
#endif
#ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_
#include <toolkit/unohlp.hxx>
#endif
#ifndef EXTENSIONS_ABPRESID_HRC
#include "abpresid.hrc"
#endif
#ifndef _EXTENSIONS_COMPONENT_MODULE_HXX_
#include "componentmodule.hxx"
#endif
#ifndef _SV_WAITOBJ_HXX
#include <vcl/waitobj.hxx>
#endif

//.........................................................................
namespace abp
{
//.........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::lang;
    using namespace ::com::sun::star::beans;
    using namespace ::com::sun::star::awt;
    using namespace ::com::sun::star::ui::dialogs;

    //=====================================================================
    //= OAdminDialogInvokation
    //=====================================================================
    //---------------------------------------------------------------------
    OAdminDialogInvokation::OAdminDialogInvokation(const Reference< XMultiServiceFactory >& _rxORB
                    , const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > _xDataSource
                    , Window* _pMessageParent)
        :m_xORB(_rxORB)
        ,m_xDataSource(_xDataSource)
        ,m_pMessageParent(_pMessageParent)
    {
        DBG_ASSERT(m_xORB.is(), "OAdminDialogInvokation::OAdminDialogInvokation: invalid service factory!");
        DBG_ASSERT(m_xDataSource.is(), "OAdminDialogInvokation::OAdminDialogInvokation: invalid preferred name!");
        DBG_ASSERT(m_pMessageParent, "OAdminDialogInvokation::OAdminDialogInvokation: invalid message parent!");
    }

    //---------------------------------------------------------------------
    sal_Bool OAdminDialogInvokation::invokeAdministration( sal_Bool _bFixedType )
    {
        if (!m_xORB.is())
            return sal_False;

        try
        {
            // the service name of the administration dialog
            const static ::rtl::OUString s_sAdministrationServiceName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sdb.DatasourceAdministrationDialog"));
            const static ::rtl::OUString s_sDataSourceTypeChangeDialog = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sdb.DataSourceTypeChangeDialog"));

            // the parameters for the call
            Sequence< Any > aArguments(3);
            Any* pArguments = aArguments.getArray();

            // the parent window
            Reference< XWindow > xDialogParent = VCLUnoHelper::GetInterface(m_pMessageParent);
            *pArguments++ <<= PropertyValue(::rtl::OUString::createFromAscii("ParentWindow"), -1, makeAny(xDialogParent), PropertyState_DIRECT_VALUE);

            // the title of the dialog
            String sAdminDialogTitle(ModuleRes(RID_STR_ADMINDIALOGTITLE));
            *pArguments++ <<= PropertyValue(::rtl::OUString::createFromAscii("Title"), -1, makeAny(::rtl::OUString(sAdminDialogTitle)), PropertyState_DIRECT_VALUE);

            // the name of the new data source
            *pArguments++ <<= PropertyValue(::rtl::OUString::createFromAscii("InitialSelection"), -1, makeAny(m_xDataSource), PropertyState_DIRECT_VALUE);

            // create the dialog
            Reference< XExecutableDialog > xDialog;
            {
                // creating the dialog service is potentially expensive (if all the libraries invoked need to be loaded)
                // so we display a wait cursor
                WaitObject aWaitCursor(m_pMessageParent);
                xDialog = Reference< XExecutableDialog >( m_xORB->createInstanceWithArguments( _bFixedType ? s_sAdministrationServiceName : s_sDataSourceTypeChangeDialog, aArguments ), UNO_QUERY );

                // just for a smoother UI: What the dialog does upon execution, is (amongst other things) creating
                // the DriverManager service
                // If this context has never been accessed before, this may be expensive (it includes loading of
                // at least one library).
                // As this wizard is intended to run on the first office start, it is very likely that the
                // context needs to be freshly created
                // Thus, we access the context here (within the WaitCursor), which means the user sees a waitcursor
                // while his/her office blocks a few seconds ....
                m_xORB->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.sdbc.DriverManager" ) );
            }

            if (xDialog.is())
            {   // execute it
                if (xDialog->execute())
                    return sal_True;
            }
            else
                ShowServiceNotAvailableError(m_pMessageParent, s_sAdministrationServiceName, sal_True);
        }
        catch(const Exception&)
        {
            DBG_ERROR("OAdminDialogInvokation::invokeAdministration: caught an exception while executing the dialog!");
        }
        return sal_False;
    }

//.........................................................................
}   // namespace abp
//.........................................................................

<|endoftext|>


<commit_before>#include "bbmh.h"
#include "hll.h"
using namespace sketch;
using namespace common;

int main() {
    static_assert(sizeof(schism::Schismatic<int32_t>) == sizeof(schism::Schismatic<uint32_t>), "wrong size!");
    for(size_t i = 7; i < 20; ++i) {
        for(const auto b: {7u, 13u, 14u, 17u, 9u}) {
            std::fprintf(stderr, "b: %u. i: %zu\n", b, i);
            mh::SuperMinHash<> smh(12);
            hll::hll_t h1(i), h2(i);
            mh::BBitMinHasher<uint64_t> b1(i, b), b2(i, b), b3(i, b);
            mh::DivBBitMinHasher<uint64_t> db1(2000 * i, b), db2(2000 * i, b), db3(2000 * i, b);
            //mh::DivBBitMinHasher<uint64_t> fb(i, b);
            mh::CountingBBitMinHasher<uint64_t, uint32_t> cb1(i, b), cb2(i, b), cb3(i, b);
            DefaultRNGType gen(137);
            size_t shared = 0, b1c = 0, b2c = 0;
            for(size_t i = 50000000; --i;) {
                auto v = gen();
                switch(v & 0x3uL) {
                    case 0:
                    case 1: h1.addh(v); h2.addh(v); b2.addh(v); b1.addh(v); ++shared; b3.addh(v); /*fb.addh(v);*/ break;
                    case 2: h1.addh(v); b1.addh(v); ++b1c; b3.addh(v); cb3.addh(v);break;
                    case 3: h2.addh(v); b2.addh(v); ++b2c; cb1.addh(v); break;
                }
            }
            b1.densify();
            b2.densify();
            auto f1 = b1.finalize(), f2 = b2.finalize(), f3 = b3.finalize();
            auto fdb1 = db1.finalize();
            auto fdb2 = db2.finalize();
            auto fdb3 = db3.finalize();
            std::fprintf(stderr, "Expected Cardinality [shared:%zu/b1:%zu/b2:%zu]\n", shared, b1c, b2c);
            std::fprintf(stderr, "h1 est %lf, h2 est: %lf\n", h1.report(), h2.report());
            std::fprintf(stderr, "Estimate Harmonicard [b1:%lf/b2:%lf]\n", b1.cardinality_estimate(HARMONIC_MEAN), b2.cardinality_estimate(HARMONIC_MEAN));
            std::fprintf(stderr, "Estimate HLL [b1:%lf/b2:%lf/b3:%lf]\n", b1.cardinality_estimate(HLL_METHOD), b2.cardinality_estimate(HLL_METHOD), b3.cardinality_estimate(HLL_METHOD));
            std::fprintf(stderr, "Estimate arithmetic mean [b1:%lf/b2:%lf]\n", b1.cardinality_estimate(ARITHMETIC_MEAN), b2.cardinality_estimate(ARITHMETIC_MEAN));
            std::fprintf(stderr, "Estimate (median) b1:%lf/b2:%lf]\n", b1.cardinality_estimate(MEDIAN), b2.cardinality_estimate(MEDIAN));
            std::fprintf(stderr, "Estimate geometic mean [b1:%lf/b2:%lf]\n", b1.cardinality_estimate(GEOMETRIC_MEAN), b2.cardinality_estimate(GEOMETRIC_MEAN));
            std::fprintf(stderr, "JI for f3 and f2: %lf\n", f2.jaccard_index(f3));
            std::fprintf(stderr, "equal blocks: %zu\n", size_t(f2.equal_bblocks(f3)));
            std::fprintf(stderr, "f1, f2, and f3 cardinalities: %lf, %lf, %lf\n", f1.est_cardinality_, f2.est_cardinality_, f3.est_cardinality_);
            //auto cb13res = cb1.finalize().histogram_sums(cb3.finalize());
            //std::fprintf(stderr, "cb13res %lf, %lf\n", cb13res.weighted_jaccard_index(), cb13res.jaccard_index());
            cb1.finalize().write("ZOMG.cb");
        }
    }
}
<commit_msg>Correctly demonstrate callling of SuperMinHash constructors with different policies.<commit_after>#include "bbmh.h"
#include "hll.h"
using namespace sketch;
using namespace common;

int main() {
    static_assert(sizeof(schism::Schismatic<int32_t>) == sizeof(schism::Schismatic<uint32_t>), "wrong size!");
    for(size_t i = 7; i < 20; ++i) {
        for(const auto b: {7u, 13u, 14u, 17u, 9u}) {
            std::fprintf(stderr, "b: %u. i: %zu\n", b, i);
            mh::SuperMinHash<policy::SizePow2Policy> smh(12);
            mh::SuperMinHash<policy::SizeDivPolicy> smh2(1 << 12);
            hll::hll_t h1(i), h2(i);
            mh::BBitMinHasher<uint64_t> b1(i, b), b2(i, b), b3(i, b);
            mh::DivBBitMinHasher<uint64_t> db1(2000 * i, b), db2(2000 * i, b), db3(2000 * i, b);
            //mh::DivBBitMinHasher<uint64_t> fb(i, b);
            mh::CountingBBitMinHasher<uint64_t, uint32_t> cb1(i, b), cb2(i, b), cb3(i, b);
            DefaultRNGType gen(137);
            size_t shared = 0, b1c = 0, b2c = 0;
            for(size_t i = 50000000; --i;) {
                auto v = gen();
                switch(v & 0x3uL) {
                    case 0:
                    case 1: h1.addh(v); h2.addh(v); b2.addh(v); b1.addh(v); ++shared; b3.addh(v); /*fb.addh(v);*/ break;
                    case 2: h1.addh(v); b1.addh(v); ++b1c; b3.addh(v); cb3.addh(v);break;
                    case 3: h2.addh(v); b2.addh(v); ++b2c; cb1.addh(v); break;
                }
            }
            b1.densify();
            b2.densify();
            auto f1 = b1.finalize(), f2 = b2.finalize(), f3 = b3.finalize();
            auto fdb1 = db1.finalize();
            auto fdb2 = db2.finalize();
            auto fdb3 = db3.finalize();
            std::fprintf(stderr, "Expected Cardinality [shared:%zu/b1:%zu/b2:%zu]\n", shared, b1c, b2c);
            std::fprintf(stderr, "h1 est %lf, h2 est: %lf\n", h1.report(), h2.report());
            std::fprintf(stderr, "Estimate Harmonicard [b1:%lf/b2:%lf]\n", b1.cardinality_estimate(HARMONIC_MEAN), b2.cardinality_estimate(HARMONIC_MEAN));
            std::fprintf(stderr, "Estimate HLL [b1:%lf/b2:%lf/b3:%lf]\n", b1.cardinality_estimate(HLL_METHOD), b2.cardinality_estimate(HLL_METHOD), b3.cardinality_estimate(HLL_METHOD));
            std::fprintf(stderr, "Estimate arithmetic mean [b1:%lf/b2:%lf]\n", b1.cardinality_estimate(ARITHMETIC_MEAN), b2.cardinality_estimate(ARITHMETIC_MEAN));
            std::fprintf(stderr, "Estimate (median) b1:%lf/b2:%lf]\n", b1.cardinality_estimate(MEDIAN), b2.cardinality_estimate(MEDIAN));
            std::fprintf(stderr, "Estimate geometic mean [b1:%lf/b2:%lf]\n", b1.cardinality_estimate(GEOMETRIC_MEAN), b2.cardinality_estimate(GEOMETRIC_MEAN));
            std::fprintf(stderr, "JI for f3 and f2: %lf\n", f2.jaccard_index(f3));
            std::fprintf(stderr, "equal blocks: %zu\n", size_t(f2.equal_bblocks(f3)));
            std::fprintf(stderr, "f1, f2, and f3 cardinalities: %lf, %lf, %lf\n", f1.est_cardinality_, f2.est_cardinality_, f3.est_cardinality_);
            //auto cb13res = cb1.finalize().histogram_sums(cb3.finalize());
            //std::fprintf(stderr, "cb13res %lf, %lf\n", cb13res.weighted_jaccard_index(), cb13res.jaccard_index());
            cb1.finalize().write("ZOMG.cb");
        }
    }
}
<|endoftext|>


<commit_before>/*
  This file is part of Ingen.
  Copyright 2007-2012 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

  Ingen 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 Affero General Public License for details.

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <assert.h>
#include <stddef.h>
#include <stdint.h>

#include "lv2/lv2plug.in/ns/ext/atom/atom.h"

#include "AudioBuffer.hpp"

using namespace std;

/* TODO: Be sure these functions are vectorized by GCC when its vectorizer
 * stops sucking.  Probably a good idea to inline them as well */

namespace Ingen {
namespace Server {

AudioBuffer::AudioBuffer(BufferFactory& bufs, LV2_URID type, uint32_t size)
	: Buffer(bufs, type, size)
	, _state(OK)
	, _set_value(0)
	, _set_time(0)
{
	assert(size >= sizeof(LV2_Atom) + sizeof(Sample));
	assert(this->capacity() >= size);
	assert(data());

	if (type == bufs.uris().atom_Sound) {
		// Audio port (Vector of float)
		LV2_Atom_Vector* vec = (LV2_Atom_Vector*)_atom;
		vec->body.child_size = sizeof(float);
		vec->body.child_type = bufs.uris().atom_Float;
		_atom->size = size - sizeof(LV2_Atom_Vector);
	} else {
		_atom->size = size - sizeof(LV2_Atom);
	}

	_atom->type = type;
	clear();
}

/** Empty (ie zero) the buffer.
 */
void
AudioBuffer::clear()
{
	assert(nframes() != 0);
	set_block(0, 0, nframes() - 1);
	_state = OK;
}

/** Set value of buffer to @a val after @a start_sample.
 *
 * The Buffer will handle setting the intial portion of the buffer to the
 * value on the next cycle automatically (if @a start_sample is > 0), as
 * long as pre_process() is called every cycle.
 */
void
AudioBuffer::set_value(Sample val, FrameTime cycle_start, FrameTime time)
{
	if (is_control())
		time = cycle_start;

	const FrameTime offset = time - cycle_start;
	assert(nframes() != 0);
	assert(offset <= nframes());

	if (offset < nframes()) {
		set_block(val, offset, nframes() - 1);

		if (offset == 0)
			_state = OK;
		else
			_state = HALF_SET_CYCLE_1;
	} // else trigger at very end of block

	_set_time = time;
	_set_value = val;
}

/** Set a block of buffer to @a val.
 *
 * @a start_sample and @a end_sample define the inclusive range to be set.
 */
void
AudioBuffer::set_block(Sample val, size_t start_offset, size_t end_offset)
{
	assert(end_offset >= start_offset);
	assert(end_offset < nframes());

	Sample* const buf = data();
	assert(buf);

	for (size_t i = start_offset; i <= end_offset; ++i)
		buf[i] = val;
}

/** Copy a block of @a src into buffer.
 *
 * @a start_sample and @a end_sample define the inclusive range to be set.
 * This function only copies the same range in one buffer to another.
 */
void
AudioBuffer::copy(const Sample* src, size_t start_sample, size_t end_sample)
{
	assert(end_sample >= start_sample);
	assert(nframes() != 0);

	Sample* const buf = data();
	assert(buf);

	const size_t copy_end = std::min(end_sample, (size_t)nframes() - 1);
	for (size_t i = start_sample; i <= copy_end; ++i)
		buf[i] = src[i];
}

void
AudioBuffer::copy(Context& context, const Buffer* src)
{
	const AudioBuffer* src_abuf = dynamic_cast<const AudioBuffer*>(src);
	if (!src_abuf) {
		clear();
		return;
	}

	if (src_abuf->is_control() == is_control()) {
		// Control => Control
		Buffer::copy(context, src);
	} else if (!src_abuf->is_control() && !is_control()) {
		// Audio => Audio
		copy(src_abuf->data(),
		     context.offset(), context.offset() + context.nframes() - 1);
	} else if (!src_abuf->is_control() && is_control()) {
		// Audio => Control
		data()[0] = src_abuf->data()[context.offset()];
	} else if (src_abuf->is_control() && !is_control()) {
		// Control => Audio
		data()[context.offset()] = src_abuf->data()[0];
	} else {
		// Control => Audio or Audio => Control
		set_block(src_abuf->data()[0], 0, nframes());
	}
}

float
AudioBuffer::peak(Context& context) const
{
	float peak = 0.0f;
	// FIXME: use context time range?
	for (FrameTime i = 0; i < nframes(); ++i) {
		peak = fmaxf(peak, value_at(i));
	}
	return peak;
}

void
AudioBuffer::prepare_read(Context& context)
{
	assert(nframes() != 0);
	switch (_state) {
	case HALF_SET_CYCLE_1:
		if (context.start() > _set_time)
			_state = HALF_SET_CYCLE_2;
		break;
	case HALF_SET_CYCLE_2:
		set_block(_set_value, 0, nframes() - 1);
		_state = OK;
		break;
	default:
		break;
	}
}

} // namespace Server
} // namespace Ingen
<commit_msg>Fix glitchy audio.<commit_after>/*
  This file is part of Ingen.
  Copyright 2007-2012 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

  Ingen 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 Affero General Public License for details.

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <assert.h>
#include <stddef.h>
#include <stdint.h>

#include "lv2/lv2plug.in/ns/ext/atom/atom.h"

#include "AudioBuffer.hpp"

using namespace std;

/* TODO: Be sure these functions are vectorized by GCC when its vectorizer
 * stops sucking.  Probably a good idea to inline them as well */

namespace Ingen {
namespace Server {

AudioBuffer::AudioBuffer(BufferFactory& bufs, LV2_URID type, uint32_t size)
	: Buffer(bufs, type, size)
	, _state(OK)
	, _set_value(0)
	, _set_time(0)
{
	assert(size >= sizeof(LV2_Atom) + sizeof(Sample));
	assert(this->capacity() >= size);
	assert(data());

	if (type == bufs.uris().atom_Sound) {
		// Audio port (Vector of float)
		LV2_Atom_Vector* vec = (LV2_Atom_Vector*)_atom;
		vec->body.child_size = sizeof(float);
		vec->body.child_type = bufs.uris().atom_Float;
	}

	_atom->size = size - sizeof(LV2_Atom);
	_atom->type = type;

	clear();
}

/** Empty (ie zero) the buffer.
 */
void
AudioBuffer::clear()
{
	assert(nframes() != 0);
	set_block(0, 0, nframes() - 1);
	_state = OK;
}

/** Set value of buffer to @a val after @a start_sample.
 *
 * The Buffer will handle setting the intial portion of the buffer to the
 * value on the next cycle automatically (if @a start_sample is > 0), as
 * long as pre_process() is called every cycle.
 */
void
AudioBuffer::set_value(Sample val, FrameTime cycle_start, FrameTime time)
{
	if (is_control())
		time = cycle_start;

	const FrameTime offset = time - cycle_start;
	assert(nframes() != 0);
	assert(offset <= nframes());

	if (offset < nframes()) {
		set_block(val, offset, nframes() - 1);

		if (offset == 0)
			_state = OK;
		else
			_state = HALF_SET_CYCLE_1;
	} // else trigger at very end of block

	_set_time = time;
	_set_value = val;
}

/** Set a block of buffer to @a val.
 *
 * @a start_sample and @a end_sample define the inclusive range to be set.
 */
void
AudioBuffer::set_block(Sample val, size_t start_offset, size_t end_offset)
{
	assert(end_offset >= start_offset);
	assert(end_offset < nframes());

	Sample* const buf = data();
	assert(buf);

	for (size_t i = start_offset; i <= end_offset; ++i)
		buf[i] = val;
}

/** Copy a block of @a src into buffer.
 *
 * @a start_sample and @a end_sample define the inclusive range to be set.
 * This function only copies the same range in one buffer to another.
 */
void
AudioBuffer::copy(const Sample* src, size_t start_sample, size_t end_sample)
{
	assert(end_sample >= start_sample);
	assert(nframes() != 0);

	Sample* const buf = data();
	assert(buf);

	const size_t copy_end = std::min(end_sample, (size_t)nframes() - 1);
	for (size_t i = start_sample; i <= copy_end; ++i)
		buf[i] = src[i];
}

void
AudioBuffer::copy(Context& context, const Buffer* src)
{
	const AudioBuffer* src_abuf = dynamic_cast<const AudioBuffer*>(src);
	if (!src_abuf) {
		clear();
		return;
	}

	if (src_abuf->is_control() == is_control()) {
		// Rates match, direct copy
		Buffer::copy(context, src);
	} else if (!src_abuf->is_control() && is_control()) {
		// Audio => Control
		data()[0] = src_abuf->data()[context.offset()];
	} else if (src_abuf->is_control() && !is_control()) {
		// Control => Audio
		data()[context.offset()] = src_abuf->data()[0];
	}
}

float
AudioBuffer::peak(Context& context) const
{
	float peak = 0.0f;
	// FIXME: use context time range?
	for (FrameTime i = 0; i < nframes(); ++i) {
		peak = fmaxf(peak, value_at(i));
	}
	return peak;
}

void
AudioBuffer::prepare_read(Context& context)
{
	assert(nframes() != 0);
	switch (_state) {
	case HALF_SET_CYCLE_1:
		if (context.start() > _set_time)
			_state = HALF_SET_CYCLE_2;
		break;
	case HALF_SET_CYCLE_2:
		set_block(_set_value, 0, nframes() - 1);
		_state = OK;
		break;
	default:
		break;
	}
}

} // namespace Server
} // namespace Ingen
<|endoftext|>


<commit_before>// [WriteFile Name=LineOfSightLocation, Category=Analysis]
// [Legal]
// Copyright 2017 Esri.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// [Legal]

#include "LineOfSightLocation.h"

#include "ArcGISTiledElevationSource.h"
#include "Scene.h"
#include "SceneQuickView.h"
#include "LocationLineOfSight.h"
#include "AnalysisOverlay.h"
#include "Camera.h"

using namespace Esri::ArcGISRuntime;

LineOfSightLocation::LineOfSightLocation(QQuickItem* parent /* = nullptr */):
  QQuickItem(parent)
{
}

void LineOfSightLocation::init()
{
  // Register classes for QML
  qmlRegisterType<SceneQuickView>("Esri.Samples", 1, 0, "SceneView");
  qmlRegisterType<LineOfSightLocation>("Esri.Samples", 1, 0, "LineOfSightLocationSample");
}

void LineOfSightLocation::componentComplete()
{
  QQuickItem::componentComplete();

  // Create a scene and give it to the SceneView
  m_sceneView = findChild<SceneQuickView*>("sceneView");

  Scene* scene = new Scene(Basemap::topographic(this), this);
  Surface* surface = new Surface(this);
  surface->elevationSources()->append(
        new ArcGISTiledElevationSource(
          QUrl("http://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer"),
          this));
  scene->setBaseSurface(surface);
  m_sceneView->setArcGISScene(scene);

  // Add an Analysis Overlay
  m_analysisOverlay = new AnalysisOverlay(this);
  m_sceneView->analysisOverlays()->append(m_analysisOverlay);

  // set initial viewpoint
  setInitialViewpoint();

  // create LocationLineOfSight
  createLineOfSight();

  // connect signals
  connectSignals();
}

void LineOfSightLocation::createLineOfSight()
{
  // create the observer/target points
  Point observerPt(-73.06958032962375, -49.253112971555446, 2000, SpatialReference::wgs84());
  Point targetPt(-73.079266999709162, -49.300457676730559, 1312, SpatialReference::wgs84());

  // create the line of site
  m_lineOfSight = new LocationLineOfSight(observerPt, targetPt, this);
  m_analysisOverlay->analyses()->append(m_lineOfSight);

  // configure the LoS color and width
  LineOfSight::setVisibleColor(QColor("cyan"));
  LineOfSight::setObstructedColor(QColor("magenta"));
  LineOfSight::setLineWidth(2.0f);
}

void LineOfSightLocation::setInitialViewpoint()
{
  // Set a viewpoint
  double x = -73.0815;
  double y = -49.3272;
  double z = 4059;
  Point point(x, y, z, SpatialReference::wgs84());
  double heading = 11;
  double pitch = 62;
  double roll = 0;
  Camera camera(point, heading, pitch, roll);
  m_sceneView->setViewpointCamera(camera);
}

void LineOfSightLocation::connectSignals()
{
  // on mouse click perform the location viewshed
  connect(m_sceneView, &SceneQuickView::mouseClicked, this, [this](QMouseEvent& event)
  {
    const Point pt = m_sceneView->screenToBaseSurface(event.x(), event.y());
    m_lineOfSight->setTargetLocation(pt);
  });

  connect(m_sceneView, &SceneQuickView::mousePressedAndHeld, this, [this]
  {
    m_calculating = true;
  });

  connect(m_sceneView, &SceneQuickView::mouseMoved, this, [this](QMouseEvent& event)
  {
    if (m_calculating)
    {
      const Point pt = m_sceneView->screenToBaseSurface(event.x(), event.y());
      m_lineOfSight->setTargetLocation(pt);
    }
  });

  connect(m_sceneView, &SceneQuickView::mouseReleased, this, [this]
  {
    m_calculating = false;
  });
}
<commit_msg>code cleanup<commit_after>// [WriteFile Name=LineOfSightLocation, Category=Analysis]
// [Legal]
// Copyright 2017 Esri.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// [Legal]

#include "LineOfSightLocation.h"

#include "ArcGISTiledElevationSource.h"
#include "Scene.h"
#include "SceneQuickView.h"
#include "LocationLineOfSight.h"
#include "AnalysisOverlay.h"
#include "Camera.h"

using namespace Esri::ArcGISRuntime;

LineOfSightLocation::LineOfSightLocation(QQuickItem* parent /* = nullptr */):
  QQuickItem(parent)
{
}

void LineOfSightLocation::init()
{
  // Register classes for QML
  qmlRegisterType<SceneQuickView>("Esri.Samples", 1, 0, "SceneView");
  qmlRegisterType<LineOfSightLocation>("Esri.Samples", 1, 0, "LineOfSightLocationSample");
}

void LineOfSightLocation::componentComplete()
{
  QQuickItem::componentComplete();

  // Create a scene and give it to the SceneView
  m_sceneView = findChild<SceneQuickView*>("sceneView");

  Scene* scene = new Scene(Basemap::topographic(this), this);
  Surface* surface = new Surface(this);
  surface->elevationSources()->append(
        new ArcGISTiledElevationSource(
          QUrl("http://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer"),
          this));
  scene->setBaseSurface(surface);
  m_sceneView->setArcGISScene(scene);

  // Add an Analysis Overlay
  m_analysisOverlay = new AnalysisOverlay(this);
  m_sceneView->analysisOverlays()->append(m_analysisOverlay);

  // set initial viewpoint
  setInitialViewpoint();

  // create LocationLineOfSight
  createLineOfSight();

  // connect signals
  connectSignals();
}

void LineOfSightLocation::createLineOfSight()
{
  // create the observer/target points
  const Point observerPt(-73.06958032962375, -49.253112971555446, 2000, SpatialReference::wgs84());
  const Point targetPt(-73.079266999709162, -49.300457676730559, 1312, SpatialReference::wgs84());

  // create the line of site
  m_lineOfSight = new LocationLineOfSight(observerPt, targetPt, this);
  m_analysisOverlay->analyses()->append(m_lineOfSight);

  // configure the LoS color and width
  LineOfSight::setVisibleColor(QColor("cyan"));
  LineOfSight::setObstructedColor(QColor("magenta"));
  LineOfSight::setLineWidth(2.0f);
}

void LineOfSightLocation::setInitialViewpoint()
{
  // Set a viewpoint
  Point point(-73.0815, -49.3272, 4059, SpatialReference::wgs84());
  const double heading = 11;
  const double pitch = 62;
  const double roll = 0;
  Camera camera(point, heading, pitch, roll);
  m_sceneView->setViewpointCamera(camera);
}

void LineOfSightLocation::connectSignals()
{
  // on mouse click perform the location viewshed
  connect(m_sceneView, &SceneQuickView::mouseClicked, this, [this](QMouseEvent& event)
  {
    const Point pt = m_sceneView->screenToBaseSurface(event.x(), event.y());
    m_lineOfSight->setTargetLocation(pt);
  });

  connect(m_sceneView, &SceneQuickView::mousePressedAndHeld, this, [this]
  {
    m_calculating = true;
  });

  connect(m_sceneView, &SceneQuickView::mouseMoved, this, [this](QMouseEvent& event)
  {
    if (m_calculating)
    {
      const Point pt = m_sceneView->screenToBaseSurface(event.x(), event.y());
      m_lineOfSight->setTargetLocation(pt);
    }
  });

  connect(m_sceneView, &SceneQuickView::mouseReleased, this, [this]
  {
    m_calculating = false;
  });
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2014, Intel Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 * may be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "FixedPointParameterType.h"
#include <stdlib.h>
#include <sstream>
#include <iomanip>
#include <assert.h>
#include <math.h>
#include "Parameter.h"
#include "ParameterAccessContext.h"
#include "ConfigurationAccessContext.h"
#include <errno.h>
#include <convert.hpp>

#define base CParameterType

CFixedPointParameterType::CFixedPointParameterType(const string& strName) : base(strName), _uiIntegral(0), _uiFractional(0)
{
}

string CFixedPointParameterType::getKind() const
{
    return "FixedPointParameter";
}

// Element properties
void CFixedPointParameterType::showProperties(string& strResult) const
{
    base::showProperties(strResult);

    // Notation
    strResult += "Notation: Q";
    strResult += toString(_uiIntegral);
    strResult += ".";
    strResult += toString(_uiFractional);
    strResult += "\n";
}

// XML Serialization value space handling
// Value space handling for configuration import
void CFixedPointParameterType::handleValueSpaceAttribute(CXmlElement& xmlConfigurableElementSettingsElement, CConfigurationAccessContext& configurationAccessContext) const
{
    // Direction?
    if (!configurationAccessContext.serializeOut()) {

        // Get Value space from XML
        if (xmlConfigurableElementSettingsElement.hasAttribute("ValueSpace")) {

            configurationAccessContext.setValueSpaceRaw(xmlConfigurableElementSettingsElement.getAttributeBoolean("ValueSpace", "Raw"));
        } else {

            configurationAccessContext.setValueSpaceRaw(false);
        }
    } else {
        // Provide value space only if not the default one
        if (configurationAccessContext.valueSpaceIsRaw()) {

            xmlConfigurableElementSettingsElement.setAttributeString("ValueSpace", "Raw");
        }
    }
}

bool CFixedPointParameterType::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
{
    // Size
    uint32_t uiSizeInBits = xmlElement.getAttributeInteger("Size");

    // Q notation
    _uiIntegral = xmlElement.getAttributeInteger("Integral");
    _uiFractional = xmlElement.getAttributeInteger("Fractional");

    // Size vs. Q notation integrity check
    if (uiSizeInBits < getUtilSizeInBits()) {

        serializingContext.setError("Inconsistent Size vs. Q notation for " + getKind() + " " + xmlElement.getPath() + ": Summing (Integral + _uiFractional + 1) should not exceed given Size (" + xmlElement.getAttributeString("Size") + ")");

        return false;
    }

    // Set the size
    setSize(uiSizeInBits / 8);

    return base::fromXml(xmlElement, serializingContext);
}

bool CFixedPointParameterType::toBlackboard(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    bool bValueProvidedAsHexa = isHexadecimal(strValue);

    // Check data integrity
    if (bValueProvidedAsHexa && !parameterAccessContext.valueSpaceIsRaw()) {

        parameterAccessContext.setError("Hexadecimal values are not supported for " + getKind() + " when selected value space is real:");

        return false;
    }

    if (parameterAccessContext.valueSpaceIsRaw()) {

        if (bValueProvidedAsHexa) {

            return convertFromHexadecimal(strValue, uiValue, parameterAccessContext);

        }
        return convertFromDecimal(strValue, uiValue, parameterAccessContext);
    }
    return convertFromQiQf(strValue, uiValue, parameterAccessContext);
}

void CFixedPointParameterType::setOutOfRangeError(const string& strValue, CParameterAccessContext& parameterAccessContext) const
{
    ostringstream strStream;

    strStream << "Value " << strValue << " standing out of admitted ";

    if (!parameterAccessContext.valueSpaceIsRaw()) {

        // Min/Max computation
        double dMin = 0;
        double dMax = 0;
        getRange(dMin, dMax);

        strStream << "real range [" << dMin << ", " << dMax << "]";
    } else {

        // Min/Max computation
        int32_t iMax = getMaxValue<uint32_t>();
        int32_t iMin = -iMax - 1;

        strStream << "raw range [";

        if (isHexadecimal(strValue)) {

            // Format Min
            strStream << "0x" << hex << uppercase <<
                setw(getSize() * 2) << setfill('0') << makeEncodable(iMin);
            // Format Max
            strStream << ", 0x" << hex << uppercase <<
                setw(getSize() * 2) << setfill('0') << makeEncodable(iMax);

        } else {

            strStream << iMin << ", " << iMax;
        }

        strStream << "]";
    }
    strStream << " for " << getKind();

    parameterAccessContext.setError(strStream.str());
}

bool CFixedPointParameterType::fromBlackboard(string& strValue, const uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    int32_t iData = uiValue;

    // Check encodability
    assert(isEncodable((uint32_t)iData, false));

    // Format
    ostringstream strStream;

    // Raw formatting?
    if (parameterAccessContext.valueSpaceIsRaw()) {

        // Hexa formatting?
        if (parameterAccessContext.outputRawFormatIsHex()) {

            strStream << "0x" << hex << uppercase << setw(getSize()*2) << setfill('0') << (uint32_t)iData;
        } else {

            // Sign extend
            signExtend(iData);

            strStream << iData;
        }
    } else {

        // Sign extend
        signExtend(iData);

        // Conversion
        double dData = asDouble(iData);

        // Set up the precision of the display and notation type
        // For a Qn.m number, the step between each storable number is 2^(-m).
        // Hence, on a decimal representation, the Dth digit after the decimal
        // point can take all possible values (1..9) - meaning that it is
        // significant - only if
        //
        //         2^(-m) <= 10^(-D)
        //             -m <= log2(10^(-D))
        //             -m <= log10(10^(-D)) / log10(2)
        //             -m <= -D / log10(2)
        //   m * log10(2) >= D
        //
        // Conversly, the Dth digit can be represented if
        //
        //   D <= m * log10(2)
        //
        // Since floor(x) <= x, we can write (replacing D with iPrecision and m
        // with _uiFractional) this next line.
        // (we add 1 to avoid losing precision even though this last digit is
        // not 100% significant)
        int iPrecision = (_uiFractional  * log10(2.0)) + 1;
        strStream << fixed << setprecision(iPrecision) << dData;
    }

    strValue = strStream.str();

    return true;
}

// Value access
bool CFixedPointParameterType::toBlackboard(double dUserValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    // Check that the value is within the allowed range for this type
    if (!checkValueAgainstRange(dUserValue)) {

        // Illegal value provided
        parameterAccessContext.setError("Value out of range");

        return false;
    }

    // Do the conversion
    int32_t iData = asInteger(dUserValue);

    // Check integrity
    assert(isEncodable((uint32_t)iData, true));

    uiValue = iData;

    return true;
}

bool CFixedPointParameterType::fromBlackboard(double& dUserValue, uint32_t uiValue, CParameterAccessContext& parameterAccessContext) const
{
    (void)parameterAccessContext;

    int32_t iData = uiValue;

    // Check unsigned value is encodable
    assert(isEncodable(uiValue, false));

    // Sign extend
    signExtend(iData);

    dUserValue = asDouble(iData);

    return true;
}

// Util size
uint32_t CFixedPointParameterType::getUtilSizeInBits() const
{
    return _uiIntegral + _uiFractional + 1;
}

// Compute the range for the type (minimum and maximum values)
void CFixedPointParameterType::getRange(double& dMin, double& dMax) const
{
    dMax = (double)((1UL << (_uiIntegral + _uiFractional)) - 1) / (1UL << _uiFractional);
    dMin = -(double)(1UL << (_uiIntegral + _uiFractional)) / (1UL << _uiFractional);
}

bool CFixedPointParameterType::isHexadecimal(const string& strValue) const
{
    return !strValue.compare(0, 2, "0x");
}

bool CFixedPointParameterType::convertFromHexadecimal(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    // For hexadecimal representation, we need full 32 bit range conversion.
    uint32_t uiData;
    if (!convertTo(strValue, uiData) || !isEncodable(uiData, false)) {

        setOutOfRangeError(strValue, parameterAccessContext);
        return false;
    }
    signExtend((int32_t&)uiData);

    // check that the data is encodable and can been safely written to the blackboard
    assert(isEncodable(uiData, true));
    uiValue = uiData;

    return true;
}

bool CFixedPointParameterType::convertFromDecimal(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    int32_t iData;

    if (!convertTo(strValue, iData) || !isEncodable((uint32_t)iData, true)) {

        setOutOfRangeError(strValue, parameterAccessContext);
        return false;
    }
    uiValue = static_cast<uint32_t>(iData);

    return true;
}

bool CFixedPointParameterType::convertFromQiQf(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    double dData;

    if (!convertTo(strValue, dData) || !checkValueAgainstRange(dData)) {

        setOutOfRangeError(strValue, parameterAccessContext);
        return false;
    }
    uiValue = static_cast<uint32_t>(asInteger(dData));

    // check that the data is encodable and has been safely written to the blackboard
    assert(isEncodable(uiValue, true));

    return true;
}

// Check that the value is within available range for this type
bool CFixedPointParameterType::checkValueAgainstRange(double dValue) const
{
    double dMin = 0;
    double dMax = 0;
    getRange(dMin, dMax);

    /**
     * Bijective transformation is only ensured in raw format.
     * So, as the double stored in the XML may be significant, and as the std::setprecision used
     * may round up, double representation may go outside the range.
     */
    int32_t rawValue = asInteger(dValue);
    return (rawValue <= asInteger(dMax)) && (rawValue >= asInteger(dMin));
}

// Data conversion
int32_t CFixedPointParameterType::asInteger(double dValue) const
{
    // Do the conversion
    // For Qn.m number, multiply by 2^n and round to the nearest integer
    int32_t iData = (int32_t)(round(dValue * (1UL << _uiFractional)));
    // Left justify
    // For a Qn.m number, shift 32 - (n + m + 1) bits to the left (the rest of
    // the bits aren't used)
    iData <<= getSize() * 8 - getUtilSizeInBits();

    return iData;
}

double CFixedPointParameterType::asDouble(int32_t iValue) const
{
    // Unjustify
    iValue >>= getSize() * 8 - getUtilSizeInBits();
    // Convert
    return (double)iValue / (1UL << _uiFractional);
}

// From IXmlSource
void CFixedPointParameterType::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
{
    // Size
    xmlElement.setAttributeString("Size", toString(getSize() * 8));

    // Integral
    xmlElement.setAttributeString("Integral", toString(_uiIntegral));

    // Fractional
    xmlElement.setAttributeString("Fractional", toString(_uiFractional));

    base::toXml(xmlElement, serializingContext);
}
<commit_msg>FixedPointParameter: Removed precision notion<commit_after>/*
 * Copyright (c) 2011-2014, Intel Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 * may be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "FixedPointParameterType.h"
#include <stdlib.h>
#include <sstream>
#include <iomanip>
#include <assert.h>
#include <math.h>
#include "Parameter.h"
#include "ParameterAccessContext.h"
#include "ConfigurationAccessContext.h"
#include <errno.h>
#include <convert.hpp>

#define base CParameterType

CFixedPointParameterType::CFixedPointParameterType(const string& strName) : base(strName), _uiIntegral(0), _uiFractional(0)
{
}

string CFixedPointParameterType::getKind() const
{
    return "FixedPointParameter";
}

// Element properties
void CFixedPointParameterType::showProperties(string& strResult) const
{
    base::showProperties(strResult);

    // Notation
    strResult += "Notation: Q";
    strResult += toString(_uiIntegral);
    strResult += ".";
    strResult += toString(_uiFractional);
    strResult += "\n";
}

// XML Serialization value space handling
// Value space handling for configuration import
void CFixedPointParameterType::handleValueSpaceAttribute(CXmlElement& xmlConfigurableElementSettingsElement, CConfigurationAccessContext& configurationAccessContext) const
{
    // Direction?
    if (!configurationAccessContext.serializeOut()) {

        // Get Value space from XML
        if (xmlConfigurableElementSettingsElement.hasAttribute("ValueSpace")) {

            configurationAccessContext.setValueSpaceRaw(xmlConfigurableElementSettingsElement.getAttributeBoolean("ValueSpace", "Raw"));
        } else {

            configurationAccessContext.setValueSpaceRaw(false);
        }
    } else {
        // Provide value space only if not the default one
        if (configurationAccessContext.valueSpaceIsRaw()) {

            xmlConfigurableElementSettingsElement.setAttributeString("ValueSpace", "Raw");
        }
    }
}

bool CFixedPointParameterType::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
{
    // Size
    uint32_t uiSizeInBits = xmlElement.getAttributeInteger("Size");

    // Q notation
    _uiIntegral = xmlElement.getAttributeInteger("Integral");
    _uiFractional = xmlElement.getAttributeInteger("Fractional");

    // Size vs. Q notation integrity check
    if (uiSizeInBits < getUtilSizeInBits()) {

        serializingContext.setError("Inconsistent Size vs. Q notation for " + getKind() + " " + xmlElement.getPath() + ": Summing (Integral + _uiFractional + 1) should not exceed given Size (" + xmlElement.getAttributeString("Size") + ")");

        return false;
    }

    // Set the size
    setSize(uiSizeInBits / 8);

    return base::fromXml(xmlElement, serializingContext);
}

bool CFixedPointParameterType::toBlackboard(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    bool bValueProvidedAsHexa = isHexadecimal(strValue);

    // Check data integrity
    if (bValueProvidedAsHexa && !parameterAccessContext.valueSpaceIsRaw()) {

        parameterAccessContext.setError("Hexadecimal values are not supported for " + getKind() + " when selected value space is real:");

        return false;
    }

    if (parameterAccessContext.valueSpaceIsRaw()) {

        if (bValueProvidedAsHexa) {

            return convertFromHexadecimal(strValue, uiValue, parameterAccessContext);

        }
        return convertFromDecimal(strValue, uiValue, parameterAccessContext);
    }
    return convertFromQiQf(strValue, uiValue, parameterAccessContext);
}

void CFixedPointParameterType::setOutOfRangeError(const string& strValue, CParameterAccessContext& parameterAccessContext) const
{
    ostringstream strStream;

    strStream << "Value " << strValue << " standing out of admitted ";

    if (!parameterAccessContext.valueSpaceIsRaw()) {

        // Min/Max computation
        double dMin = 0;
        double dMax = 0;
        getRange(dMin, dMax);

        strStream << fixed << setprecision(_uiFractional)
                  << "real range [" << dMin << ", " << dMax << "]";
    } else {

        // Min/Max computation
        int32_t iMax = getMaxValue<uint32_t>();
        int32_t iMin = -iMax - 1;

        strStream << "raw range [";

        if (isHexadecimal(strValue)) {

            // Format Min
            strStream << "0x" << hex << uppercase <<
                setw(getSize() * 2) << setfill('0') << makeEncodable(iMin);
            // Format Max
            strStream << ", 0x" << hex << uppercase <<
                setw(getSize() * 2) << setfill('0') << makeEncodable(iMax);

        } else {

            strStream << iMin << ", " << iMax;
        }

        strStream << "]";
    }
    strStream << " for " << getKind();

    parameterAccessContext.setError(strStream.str());
}

bool CFixedPointParameterType::fromBlackboard(string& strValue, const uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    int32_t iData = uiValue;

    // Check encodability
    assert(isEncodable((uint32_t)iData, false));

    // Format
    ostringstream strStream;

    // Raw formatting?
    if (parameterAccessContext.valueSpaceIsRaw()) {

        // Hexa formatting?
        if (parameterAccessContext.outputRawFormatIsHex()) {

            strStream << "0x" << hex << uppercase << setw(getSize()*2) << setfill('0') << (uint32_t)iData;
        } else {

            // Sign extend
            signExtend(iData);

            strStream << iData;
        }
    } else {

        // Sign extend
        signExtend(iData);

        // Conversion
        double dData = asDouble(iData);

        strStream << fixed << setprecision(_uiFractional) << dData;
    }

    strValue = strStream.str();

    return true;
}

// Value access
bool CFixedPointParameterType::toBlackboard(double dUserValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    // Check that the value is within the allowed range for this type
    if (!checkValueAgainstRange(dUserValue)) {

        // Illegal value provided
        parameterAccessContext.setError("Value out of range");

        return false;
    }

    // Do the conversion
    int32_t iData = asInteger(dUserValue);

    // Check integrity
    assert(isEncodable((uint32_t)iData, true));

    uiValue = iData;

    return true;
}

bool CFixedPointParameterType::fromBlackboard(double& dUserValue, uint32_t uiValue, CParameterAccessContext& parameterAccessContext) const
{
    (void)parameterAccessContext;

    int32_t iData = uiValue;

    // Check unsigned value is encodable
    assert(isEncodable(uiValue, false));

    // Sign extend
    signExtend(iData);

    dUserValue = asDouble(iData);

    return true;
}

// Util size
uint32_t CFixedPointParameterType::getUtilSizeInBits() const
{
    return _uiIntegral + _uiFractional + 1;
}

// Compute the range for the type (minimum and maximum values)
void CFixedPointParameterType::getRange(double& dMin, double& dMax) const
{
    dMax = (double)((1UL << (_uiIntegral + _uiFractional)) - 1) / (1UL << _uiFractional);
    dMin = -(double)(1UL << (_uiIntegral + _uiFractional)) / (1UL << _uiFractional);
}

bool CFixedPointParameterType::isHexadecimal(const string& strValue) const
{
    return !strValue.compare(0, 2, "0x");
}

bool CFixedPointParameterType::convertFromHexadecimal(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    // For hexadecimal representation, we need full 32 bit range conversion.
    uint32_t uiData;
    if (!convertTo(strValue, uiData) || !isEncodable(uiData, false)) {

        setOutOfRangeError(strValue, parameterAccessContext);
        return false;
    }
    signExtend((int32_t&)uiData);

    // check that the data is encodable and can been safely written to the blackboard
    assert(isEncodable(uiData, true));
    uiValue = uiData;

    return true;
}

bool CFixedPointParameterType::convertFromDecimal(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    int32_t iData;

    if (!convertTo(strValue, iData) || !isEncodable((uint32_t)iData, true)) {

        setOutOfRangeError(strValue, parameterAccessContext);
        return false;
    }
    uiValue = static_cast<uint32_t>(iData);

    return true;
}

bool CFixedPointParameterType::convertFromQiQf(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
{
    double dData;

    if (!convertTo(strValue, dData) || !checkValueAgainstRange(dData)) {

        setOutOfRangeError(strValue, parameterAccessContext);
        return false;
    }
    uiValue = static_cast<uint32_t>(asInteger(dData));

    // check that the data is encodable and has been safely written to the blackboard
    assert(isEncodable(uiValue, true));

    return true;
}

// Check that the value is within available range for this type
bool CFixedPointParameterType::checkValueAgainstRange(double dValue) const
{
    double dMin = 0;
    double dMax = 0;
    getRange(dMin, dMax);

    /**
     * Bijective transformation is only ensured in raw format.
     * So, as the double stored in the XML may be significant, and as the std::setprecision used
     * may round up, double representation may go outside the range.
     */
    int32_t rawValue = asInteger(dValue);
    return (rawValue <= asInteger(dMax)) && (rawValue >= asInteger(dMin));
}

// Data conversion
int32_t CFixedPointParameterType::asInteger(double dValue) const
{
    // Do the conversion
    // For Qn.m number, multiply by 2^n and round to the nearest integer
    int32_t iData = (int32_t)(round(dValue * (1UL << _uiFractional)));
    // Left justify
    // For a Qn.m number, shift 32 - (n + m + 1) bits to the left (the rest of
    // the bits aren't used)
    iData <<= getSize() * 8 - getUtilSizeInBits();

    return iData;
}

double CFixedPointParameterType::asDouble(int32_t iValue) const
{
    // Unjustify
    iValue >>= getSize() * 8 - getUtilSizeInBits();
    // Convert
    return (double)iValue / (1UL << _uiFractional);
}

// From IXmlSource
void CFixedPointParameterType::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
{
    // Size
    xmlElement.setAttributeString("Size", toString(getSize() * 8));

    // Integral
    xmlElement.setAttributeString("Integral", toString(_uiIntegral));

    // Fractional
    xmlElement.setAttributeString("Fractional", toString(_uiFractional));

    base::toXml(xmlElement, serializingContext);
}
<|endoftext|>


<commit_before>/*
 * ===============================================================
 *    Description:  C client implementation.
 *
 *         Author:  Ayush Dubey, dubey@cs.cornell.edu
 *
 * Copyright (C) 2014, Cornell University, see the LICENSE file
 *                     for licensing agreement
 * ===============================================================
 */

#include "client/weaver/weaver_client.h"
#include "client/client.h"

#define C_WRAP_EXCEPT(X) \
    cl::client *cl = reinterpret_cast<cl::client*>(_cl); \
    try { \
        X \
    } \
    catch (std::bad_alloc& ba) { \
        returncode = WEAVER_CLIENT_NOMEM; \
    } \
    catch (...) { \
        returncode = WEAVER_CLIENT_EXCEPTION; \
    }

#ifdef __cplusplus
extern "C"
{
#endif

struct weaver_client*
weaver_client_create(const char *coordinator, uint16_t port, const char *config_file)
{
    try {
        return reinterpret_cast<weaver_client*>(new cl::client(coordinator, port, config_file));
    }
    catch (std::bad_alloc& ba) {
        return NULL;
    }
    catch (...) {
        return NULL;
    }
}

void
weaver_client_destroy(struct weaver_client *client)
{
    delete reinterpret_cast<cl::client*>(client);
}

void
pre_create_handle(std::string &handle, char **c_handle, int create_handle)
{
    if (!create_handle) {
        handle = *c_handle;
    }
}

void
convert_c_handle(const std::string &handle, char **c_handle)
{
    char *new_handle = (char*)malloc(handle.size()+1);
    strncpy(new_handle, handle.c_str(), handle.size());
    new_handle[handle.size()] = '\0';

    *c_handle = new_handle;
}

void
post_create_handle(const std::string &handle, char **c_handle, int create_handle)
{
    if (create_handle) {
        convert_c_handle(handle, c_handle);
    }
}

void
prepare_handle_or_alias(std::string &node, std::string &alias,
                        const char *_node, int handle_or_alias)
{
    if (_node) {
        if (handle_or_alias) {
            alias = _node;
        } else {
            node = _node;
        }
    }
}

weaver_client_returncode
weaver_client_begin_tx(struct weaver_client *_cl)
{
    weaver_client_returncode returncode;

    C_WRAP_EXCEPT(
        returncode = cl->begin_tx();
    );

    return returncode;
}

weaver_client_returncode
weaver_client_create_node(struct weaver_client *_cl,
                          char **_handle,
                          int create_handle,
                          const char **_aliases,
                          size_t aliases_sz)
{
    weaver_client_returncode returncode;
    std::string handle;
    std::vector<std::string> aliases;
    pre_create_handle(handle, _handle, create_handle);
    for (size_t i = 0; i < aliases_sz; i++) {
        aliases.emplace_back(_aliases[i]);
    }

    C_WRAP_EXCEPT(
        returncode = cl->create_node(handle, aliases);
    )

    if (returncode == WEAVER_CLIENT_SUCCESS) {
        post_create_handle(handle, _handle, create_handle);
    }

    return returncode;
}

weaver_client_returncode
weaver_client_create_edge(struct weaver_client *_cl,
                          char **_handle,
                          int create_handle,
                          const char *_node1, int handle_or_alias1,
                          const char *_node2, int handle_or_alias2)
{
    weaver_client_returncode returncode;
    std::string handle;
    pre_create_handle(handle, _handle, create_handle);

    std::string node1, alias1;
    prepare_handle_or_alias(node1, alias1, _node1, handle_or_alias1);

    std::string node2, alias2;
    prepare_handle_or_alias(node2, alias2, _node2, handle_or_alias2);

    C_WRAP_EXCEPT(
        returncode = cl->create_edge(handle, node1, alias1, node2, alias2);
    )

    if (returncode == WEAVER_CLIENT_SUCCESS) {
        post_create_handle(handle, _handle, create_handle);
    }

    return returncode;
}

weaver_client_returncode
weaver_client_delete_node(struct weaver_client *_cl,
                          const char *_node, int handle_or_alias)
{
    weaver_client_returncode returncode;
    std::string node, alias;
    prepare_handle_or_alias(node, alias, _node, handle_or_alias);

    C_WRAP_EXCEPT(
        returncode = cl->delete_node(node, alias);
    );

    return returncode;
}

weaver_client_returncode
weaver_client_delete_edge(struct weaver_client *_cl,
                          const char *edge,
                          const char *_node, int handle_or_alias)
{
    weaver_client_returncode returncode;
    std::string node, alias;
    prepare_handle_or_alias(node, alias, _node, handle_or_alias);

    C_WRAP_EXCEPT(
        returncode = cl->delete_edge(edge, node, alias);
    );

    return returncode;
}

weaver_client_returncode
weaver_client_set_node_property(struct weaver_client *_cl,
                                const char *_node, int handle_or_alias,
                                const struct property *prop)
{
    weaver_client_returncode returncode;
    std::string node, alias;
    prepare_handle_or_alias(node, alias, _node, handle_or_alias);

    C_WRAP_EXCEPT(
        returncode = cl->set_node_property(node, alias, prop->key, prop->value);
    );

    return returncode;
}

weaver_client_returncode
weaver_client_set_edge_property(struct weaver_client *_cl,
                                const char *_node, int handle_or_alias,
                                const char *edge,
                                const struct property *prop)
{
    weaver_client_returncode returncode;
    std::string node, alias;
    prepare_handle_or_alias(node, alias, _node, handle_or_alias);

    C_WRAP_EXCEPT(
        returncode = cl->set_edge_property(node, alias, edge, prop->key, prop->value);
    );

    return returncode;
}

weaver_client_returncode
weaver_client_add_alias(struct weaver_client *_cl,
                        const char *alias, const char *node)
{
    weaver_client_returncode returncode;

    C_WRAP_EXCEPT(
        returncode = cl->add_alias(alias, node);
    );

    return returncode;
}

weaver_client_returncode
weaver_client_end_tx(struct weaver_client *_cl)
{
    weaver_client_returncode returncode;

    C_WRAP_EXCEPT(
        returncode = cl->end_tx();
    );

    return returncode;
}

weaver_client_returncode
weaver_client_abort_tx(struct weaver_client *_cl)
{
    weaver_client_returncode returncode;

    C_WRAP_EXCEPT(
        returncode = cl->abort_tx();
    );

    return returncode;
}

void
convert_c_properties(const std::vector<std::shared_ptr<cl::property>> &props,
                     struct property **c_props, size_t *props_sz)
{
    *props_sz = props.size();
    if (props.size() > 0) {
        *c_props = (struct property*)malloc(sizeof(struct property) * props.size());
    }

    for (size_t i = 0; i < props.size(); i++) {
        struct property &c_p = (*c_props)[i];
        const cl::property &p = *props[i];
        convert_c_handle(p.key, &c_p.key);
        convert_c_handle(p.value, &c_p.value);
    }
}

void
convert_c_edge(const cl::edge &edge,
               struct edge *c_edge)
{
    convert_c_handle(edge.handle, &c_edge->handle);
    convert_c_handle(edge.start_node, &c_edge->start_node);
    convert_c_handle(edge.end_node, &c_edge->end_node);
    convert_c_properties(edge.properties, &c_edge->properties, &c_edge->properties_sz);
}

void
convert_c_node(const cl::node &n, struct node *c_n)
{
    convert_c_handle(n.handle, &c_n->handle);
    convert_c_properties(n.properties, &c_n->properties, &c_n->properties_sz);

    c_n->out_edges_sz = n.out_edges.size();
    if (c_n->out_edges_sz > 0) {
        c_n->out_edges = (struct edge*)malloc(sizeof(struct edge) * c_n->out_edges_sz);
        size_t i = 0;
        for (const auto &p: n.out_edges) {
            convert_c_edge(p.second, c_n->out_edges+i);
            i++;
        }
    }

    c_n->aliases_sz = n.aliases.size();
    if (c_n->aliases_sz > 0) {
        c_n->aliases = (char**)malloc(sizeof(char*) * c_n->aliases_sz);
        size_t i = 0;
        for (const std::string &alias: n.aliases) {
            convert_c_handle(alias, c_n->aliases + i);
            i++;
        }
    }
}

weaver_client_returncode
weaver_client_get_node(struct weaver_client *_cl,
                       const char *node_handle,
                       struct node **n)
{
    weaver_client_returncode returncode;
    std::vector<std::pair<std::string, node_prog::node_get_params>> arg_vec;
    node_prog::node_get_params arg_params, ret_params;
    arg_params.props = true;
    arg_params.edges = true;
    arg_params.aliases = true;
    arg_vec.emplace_back(std::make_pair(node_handle, arg_params));

    C_WRAP_EXCEPT(
        returncode = cl->node_get_program(arg_vec, ret_params);
    );

    if (returncode == WEAVER_CLIENT_SUCCESS) {
        *n = (struct node*)malloc(sizeof(struct node));
        convert_c_node(ret_params.node, *n);
    }

    return returncode;
}

weaver_client_returncode
weaver_client_get_edge(struct weaver_client *_cl,
                       const char *edge_handle,
                       struct edge **e)
{
    weaver_client_returncode returncode;
    std::vector<std::pair<std::string, node_prog::edge_get_params>> arg_vec;
    node_prog::edge_get_params arg_params, ret_params;
    arg_vec.emplace_back(std::make_pair(edge_handle, arg_params));

    C_WRAP_EXCEPT(
        returncode = cl->edge_get_program(arg_vec, ret_params);
    );

    if (returncode == WEAVER_CLIENT_SUCCESS) {
        *e = (struct edge*)malloc(sizeof(struct edge));
        convert_c_edge(ret_params.response_edges.front(), *e);
    }

    return returncode;
}

enum weaver_client_returncode
weaver_client_destroy_handles(char *handles,
                              size_t handles_sz)
{
    if (handles_sz > 0) {
        free(handles);
    }

    return WEAVER_CLIENT_SUCCESS;
}

enum weaver_client_returncode
weaver_client_destroy_properties(struct property *props,
                                 size_t properties_sz)
{
    if (properties_sz > 0) {
        for (size_t i = 0; i < properties_sz; i++) {
            weaver_client_destroy_handles(props[i].key, 1);
            weaver_client_destroy_handles(props[i].value, 1);
        }
        free(props);
    }

    return WEAVER_CLIENT_SUCCESS;
}

enum weaver_client_returncode
weaver_client_destroy_edges(struct edge *edges,
                            size_t edges_sz)
{
    if (edges_sz > 0) {
        for (size_t i = 0; i < edges_sz; i++) {
            weaver_client_destroy_handles(edges[i].handle, 1);
            weaver_client_destroy_handles(edges[i].start_node, 1);
            weaver_client_destroy_handles(edges[i].end_node, 1);
            weaver_client_destroy_properties(edges[i].properties, edges[i].properties_sz);
        }
        free(edges);
    }

    return WEAVER_CLIENT_SUCCESS;
}

enum weaver_client_returncode
weaver_client_destroy_nodes(struct node *nodes,
                            size_t nodes_sz)
{
    if (nodes_sz > 0) {
        for (size_t i = 0; i < nodes_sz; i++) {
            weaver_client_destroy_handles(nodes[i].handle, 1);
            weaver_client_destroy_properties(nodes[i].properties, nodes[i].properties_sz);
            weaver_client_destroy_edges(nodes[i].out_edges, nodes[i].out_edges_sz);

            if (nodes[i].aliases_sz > 0) {
                for (size_t j = 0; j < nodes[i].aliases_sz; j++) {
                    weaver_client_destroy_handles(nodes[i].aliases[j], 1);
                }
            }
            free(nodes[i].aliases);
        }
        free(nodes);
    }

    return WEAVER_CLIENT_SUCCESS;
}

#ifdef __cplusplus
}
#endif
<commit_msg>C.cc: Aliases should only be freed if they exist. <commit_after>/*
 * ===============================================================
 *    Description:  C client implementation.
 *
 *         Author:  Ayush Dubey, dubey@cs.cornell.edu
 *
 * Copyright (C) 2014, Cornell University, see the LICENSE file
 *                     for licensing agreement
 * ===============================================================
 */

#include "client/weaver/weaver_client.h"
#include "client/client.h"

#define C_WRAP_EXCEPT(X) \
    cl::client *cl = reinterpret_cast<cl::client*>(_cl); \
    try { \
        X \
    } \
    catch (std::bad_alloc& ba) { \
        returncode = WEAVER_CLIENT_NOMEM; \
    } \
    catch (...) { \
        returncode = WEAVER_CLIENT_EXCEPTION; \
    }

#ifdef __cplusplus
extern "C"
{
#endif

struct weaver_client*
weaver_client_create(const char *coordinator, uint16_t port, const char *config_file)
{
    try {
        return reinterpret_cast<weaver_client*>(new cl::client(coordinator, port, config_file));
    }
    catch (std::bad_alloc& ba) {
        return NULL;
    }
    catch (...) {
        return NULL;
    }
}

void
weaver_client_destroy(struct weaver_client *client)
{
    delete reinterpret_cast<cl::client*>(client);
}

void
pre_create_handle(std::string &handle, char **c_handle, int create_handle)
{
    if (!create_handle) {
        handle = *c_handle;
    }
}

void
convert_c_handle(const std::string &handle, char **c_handle)
{
    char *new_handle = (char*)malloc(handle.size()+1);
    strncpy(new_handle, handle.c_str(), handle.size());
    new_handle[handle.size()] = '\0';

    *c_handle = new_handle;
}

void
post_create_handle(const std::string &handle, char **c_handle, int create_handle)
{
    if (create_handle) {
        convert_c_handle(handle, c_handle);
    }
}

void
prepare_handle_or_alias(std::string &node, std::string &alias,
                        const char *_node, int handle_or_alias)
{
    if (_node) {
        if (handle_or_alias) {
            alias = _node;
        } else {
            node = _node;
        }
    }
}

weaver_client_returncode
weaver_client_begin_tx(struct weaver_client *_cl)
{
    weaver_client_returncode returncode;

    C_WRAP_EXCEPT(
        returncode = cl->begin_tx();
    );

    return returncode;
}

weaver_client_returncode
weaver_client_create_node(struct weaver_client *_cl,
                          char **_handle,
                          int create_handle,
                          const char **_aliases,
                          size_t aliases_sz)
{
    weaver_client_returncode returncode;
    std::string handle;
    std::vector<std::string> aliases;
    pre_create_handle(handle, _handle, create_handle);
    for (size_t i = 0; i < aliases_sz; i++) {
        aliases.emplace_back(_aliases[i]);
    }

    C_WRAP_EXCEPT(
        returncode = cl->create_node(handle, aliases);
    )

    if (returncode == WEAVER_CLIENT_SUCCESS) {
        post_create_handle(handle, _handle, create_handle);
    }

    return returncode;
}

weaver_client_returncode
weaver_client_create_edge(struct weaver_client *_cl,
                          char **_handle,
                          int create_handle,
                          const char *_node1, int handle_or_alias1,
                          const char *_node2, int handle_or_alias2)
{
    weaver_client_returncode returncode;
    std::string handle;
    pre_create_handle(handle, _handle, create_handle);

    std::string node1, alias1;
    prepare_handle_or_alias(node1, alias1, _node1, handle_or_alias1);

    std::string node2, alias2;
    prepare_handle_or_alias(node2, alias2, _node2, handle_or_alias2);

    C_WRAP_EXCEPT(
        returncode = cl->create_edge(handle, node1, alias1, node2, alias2);
    )

    if (returncode == WEAVER_CLIENT_SUCCESS) {
        post_create_handle(handle, _handle, create_handle);
    }

    return returncode;
}

weaver_client_returncode
weaver_client_delete_node(struct weaver_client *_cl,
                          const char *_node, int handle_or_alias)
{
    weaver_client_returncode returncode;
    std::string node, alias;
    prepare_handle_or_alias(node, alias, _node, handle_or_alias);

    C_WRAP_EXCEPT(
        returncode = cl->delete_node(node, alias);
    );

    return returncode;
}

weaver_client_returncode
weaver_client_delete_edge(struct weaver_client *_cl,
                          const char *edge,
                          const char *_node, int handle_or_alias)
{
    weaver_client_returncode returncode;
    std::string node, alias;
    prepare_handle_or_alias(node, alias, _node, handle_or_alias);

    C_WRAP_EXCEPT(
        returncode = cl->delete_edge(edge, node, alias);
    );

    return returncode;
}

weaver_client_returncode
weaver_client_set_node_property(struct weaver_client *_cl,
                                const char *_node, int handle_or_alias,
                                const struct property *prop)
{
    weaver_client_returncode returncode;
    std::string node, alias;
    prepare_handle_or_alias(node, alias, _node, handle_or_alias);

    C_WRAP_EXCEPT(
        returncode = cl->set_node_property(node, alias, prop->key, prop->value);
    );

    return returncode;
}

weaver_client_returncode
weaver_client_set_edge_property(struct weaver_client *_cl,
                                const char *_node, int handle_or_alias,
                                const char *edge,
                                const struct property *prop)
{
    weaver_client_returncode returncode;
    std::string node, alias;
    prepare_handle_or_alias(node, alias, _node, handle_or_alias);

    C_WRAP_EXCEPT(
        returncode = cl->set_edge_property(node, alias, edge, prop->key, prop->value);
    );

    return returncode;
}

weaver_client_returncode
weaver_client_add_alias(struct weaver_client *_cl,
                        const char *alias, const char *node)
{
    weaver_client_returncode returncode;

    C_WRAP_EXCEPT(
        returncode = cl->add_alias(alias, node);
    );

    return returncode;
}

weaver_client_returncode
weaver_client_end_tx(struct weaver_client *_cl)
{
    weaver_client_returncode returncode;

    C_WRAP_EXCEPT(
        returncode = cl->end_tx();
    );

    return returncode;
}

weaver_client_returncode
weaver_client_abort_tx(struct weaver_client *_cl)
{
    weaver_client_returncode returncode;

    C_WRAP_EXCEPT(
        returncode = cl->abort_tx();
    );

    return returncode;
}

void
convert_c_properties(const std::vector<std::shared_ptr<cl::property>> &props,
                     struct property **c_props, size_t *props_sz)
{
    *props_sz = props.size();
    if (props.size() > 0) {
        *c_props = (struct property*)malloc(sizeof(struct property) * props.size());
    }

    for (size_t i = 0; i < props.size(); i++) {
        struct property &c_p = (*c_props)[i];
        const cl::property &p = *props[i];
        convert_c_handle(p.key, &c_p.key);
        convert_c_handle(p.value, &c_p.value);
    }
}

void
convert_c_edge(const cl::edge &edge,
               struct edge *c_edge)
{
    convert_c_handle(edge.handle, &c_edge->handle);
    convert_c_handle(edge.start_node, &c_edge->start_node);
    convert_c_handle(edge.end_node, &c_edge->end_node);
    convert_c_properties(edge.properties, &c_edge->properties, &c_edge->properties_sz);
}

void
convert_c_node(const cl::node &n, struct node *c_n)
{
    convert_c_handle(n.handle, &c_n->handle);
    convert_c_properties(n.properties, &c_n->properties, &c_n->properties_sz);

    c_n->out_edges_sz = n.out_edges.size();
    if (c_n->out_edges_sz > 0) {
        c_n->out_edges = (struct edge*)malloc(sizeof(struct edge) * c_n->out_edges_sz);
        size_t i = 0;
        for (const auto &p: n.out_edges) {
            convert_c_edge(p.second, c_n->out_edges+i);
            i++;
        }
    }

    c_n->aliases_sz = n.aliases.size();
    if (c_n->aliases_sz > 0) {
        c_n->aliases = (char**)malloc(sizeof(char*) * c_n->aliases_sz);
        size_t i = 0;
        for (const std::string &alias: n.aliases) {
            convert_c_handle(alias, c_n->aliases + i);
            i++;
        }
    }
}

weaver_client_returncode
weaver_client_get_node(struct weaver_client *_cl,
                       const char *node_handle,
                       struct node **n)
{
    weaver_client_returncode returncode;
    std::vector<std::pair<std::string, node_prog::node_get_params>> arg_vec;
    node_prog::node_get_params arg_params, ret_params;
    arg_params.props = true;
    arg_params.edges = true;
    arg_params.aliases = true;
    arg_vec.emplace_back(std::make_pair(node_handle, arg_params));

    C_WRAP_EXCEPT(
        returncode = cl->node_get_program(arg_vec, ret_params);
    );

    if (returncode == WEAVER_CLIENT_SUCCESS) {
        *n = (struct node*)malloc(sizeof(struct node));
        convert_c_node(ret_params.node, *n);
    }

    return returncode;
}

weaver_client_returncode
weaver_client_get_edge(struct weaver_client *_cl,
                       const char *edge_handle,
                       struct edge **e)
{
    weaver_client_returncode returncode;
    std::vector<std::pair<std::string, node_prog::edge_get_params>> arg_vec;
    node_prog::edge_get_params arg_params, ret_params;
    arg_vec.emplace_back(std::make_pair(edge_handle, arg_params));

    C_WRAP_EXCEPT(
        returncode = cl->edge_get_program(arg_vec, ret_params);
    );

    if (returncode == WEAVER_CLIENT_SUCCESS) {
        *e = (struct edge*)malloc(sizeof(struct edge));
        convert_c_edge(ret_params.response_edges.front(), *e);
    }

    return returncode;
}

enum weaver_client_returncode
weaver_client_destroy_handles(char *handles,
                              size_t handles_sz)
{
    if (handles_sz > 0) {
        free(handles);
    }

    return WEAVER_CLIENT_SUCCESS;
}

enum weaver_client_returncode
weaver_client_destroy_properties(struct property *props,
                                 size_t properties_sz)
{
    if (properties_sz > 0) {
        for (size_t i = 0; i < properties_sz; i++) {
            weaver_client_destroy_handles(props[i].key, 1);
            weaver_client_destroy_handles(props[i].value, 1);
        }
        free(props);
    }

    return WEAVER_CLIENT_SUCCESS;
}

enum weaver_client_returncode
weaver_client_destroy_edges(struct edge *edges,
                            size_t edges_sz)
{
    if (edges_sz > 0) {
        for (size_t i = 0; i < edges_sz; i++) {
            weaver_client_destroy_handles(edges[i].handle, 1);
            weaver_client_destroy_handles(edges[i].start_node, 1);
            weaver_client_destroy_handles(edges[i].end_node, 1);
            weaver_client_destroy_properties(edges[i].properties, edges[i].properties_sz);
        }
        free(edges);
    }

    return WEAVER_CLIENT_SUCCESS;
}

enum weaver_client_returncode
weaver_client_destroy_nodes(struct node *nodes,
                            size_t nodes_sz)
{
    if (nodes_sz > 0) {
        for (size_t i = 0; i < nodes_sz; i++) {
            weaver_client_destroy_handles(nodes[i].handle, 1);
            weaver_client_destroy_properties(nodes[i].properties, nodes[i].properties_sz);
            weaver_client_destroy_edges(nodes[i].out_edges, nodes[i].out_edges_sz);

            if (nodes[i].aliases_sz > 0) {
                for (size_t j = 0; j < nodes[i].aliases_sz; j++) {
                    weaver_client_destroy_handles(nodes[i].aliases[j], 1);
                }
                free(nodes[i].aliases);
            }
        }
        free(nodes);
    }

    return WEAVER_CLIENT_SUCCESS;
}

#ifdef __cplusplus
}
#endif
<|endoftext|>


<commit_before>/*
    This file is part of tgl-library

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    Copyright Topology LP 2016
*/

#include "tgl-dc.h"

#include "mtproto-client.h"
#include "queries.h"
#include "tgl-net.h"
#include "tgl-timer.h"

static const float SESSION_CLEANUP_TIMEOUT = 5.0;

void tglq_query_remove(std::shared_ptr<query> q);
bool send_pending_query(std::shared_ptr<query> q) {
    assert(q->DC);
    std::string name;
    double timeout;
    if (q->is_v2()) {
        auto q2 = std::static_pointer_cast<query_v2>(q);
        name = q2->name();
        timeout = q2->timeout_interval();
    } else {
        name = q->methods->name ? q->methods->name : "";
        timeout = q->methods->timeout;
    }

    if (!q->DC->auth_key_id || !q->DC->sessions[0]) {
        TGL_DEBUG("not ready to send pending query " << q << " (" << name << "), re-queuing");
        tglmp_dc_create_session(q->DC);
        q->DC->add_pending_query(q);
        return false;
    }
    if (!tgl_signed_dc(q->DC) && !(q->flags & QUERY_LOGIN)) {
        TGL_DEBUG("not ready to send pending non-login query " << q << " (" << name << "), re-queuing");
        q->DC->add_pending_query(q);
        return false;
    }

    q->flags &= ~QUERY_ACK_RECEIVED;
    tglq_query_remove(q);
    q->session = q->DC->sessions[0];
    q->msg_id = tglmp_encrypt_send_message (q->session->c, (int*)q->data, q->data_len, (q->flags & QUERY_FORCE_SEND) | 1);
    tgl_state::instance()->queries_tree.push_back(q);
    q->session_id = q->session->session_id;
    auto dc = q->session->dc.lock();
    if (dc && !(dc->flags & TGLDCF_CONFIGURED) && !(q->flags & QUERY_FORCE_SEND)) {
        q->session_id = 0;
    }

    TGL_DEBUG("Sending pending query \"" << name << "\" (" << q->msg_id << ") of size " << 4 * q->data_len << " to DC " << q->DC->id);

    q->ev->start(timeout ? timeout : DEFAULT_QUERY_TIMEOUT);

    return true;
}

tgl_dc::tgl_dc()
    : session_cleanup_timer(tgl_state::instance()->timer_factory()->create_timer(std::bind(&tgl_dc::cleanup_timer_expired, this)))
{
}

void tgl_dc::reset()
{
    TGL_DEBUG("resetting DC " << id);
    for (size_t i = 0; i < sessions.size(); ++i) {
        std::shared_ptr<tgl_session> session = sessions[i];
        if (session) {
            session->c->close();
            session->ev->cancel();
            session->c = nullptr;
            session->ev = nullptr;
            sessions[i] = nullptr;
        }
    }
    flags = 0;
    rsa_key_idx = 0;
    state = st_init;
    memset(auth_key, 0, 256);
    memset(temp_auth_key, 0, 256);
    memset(nonce, 0, 256);
    memset(new_nonce, 0, 256);
    memset(server_nonce, 0, 256);
    auth_key_id = 0;
    temp_auth_key_id = 0;
    server_salt = 0;
}

void tgl_dc::send_pending_queries() {
    TGL_NOTICE("sending pending queries for DC " << id);
    std::list<std::shared_ptr<query>> queries = pending_queries; // make a copy since queries can get re-enqueued
    for (std::shared_ptr<query> q : queries) {
        if (send_pending_query(q)) {
            pending_queries.remove(q);
        } else {
            TGL_DEBUG("sending pending query failed for DC " << id);
        }
    }
}

void tgl_dc::add_query(std::shared_ptr<query> q) {
    active_queries.push_back(q);
    session_cleanup_timer->cancel();
}

void tgl_dc::remove_query(std::shared_ptr<query> q) {
    active_queries.remove(q);

    if (active_queries.empty() && pending_queries.empty() && tgl_state::instance()->DC_working.get() != this) {
        session_cleanup_timer->start(SESSION_CLEANUP_TIMEOUT);
    }
}

void tgl_dc::add_pending_query(std::shared_ptr<query> q) {
    if (std::find(pending_queries.cbegin(), pending_queries.cend(), q) == pending_queries.cend()) {
        pending_queries.push_back(q);
    }
}

void tgl_dc::remove_pending_query(std::shared_ptr<query> q) {
    pending_queries.remove(q);
}

void tgl_dc::cleanup_timer_expired() {
    if (active_queries.empty() && pending_queries.empty()) {
        TGL_DEBUG("cleanup timer expired for DC " << id << ", deleting sessions");
        for (size_t i = 0; i < sessions.size(); ++i) {
            std::shared_ptr<tgl_session> session = sessions[i];
            if (session) {
                session->c->close();
                session->ev->cancel();
                session->c = nullptr;
                session->ev = nullptr;
                sessions[i] = nullptr;
            }
        }
    }
}
<commit_msg>cleanup reset and pending query handling<commit_after>/*
    This file is part of tgl-library

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    Copyright Topology LP 2016
*/

#include "tgl-dc.h"

#include "mtproto-client.h"
#include "queries.h"
#include "tgl-net.h"
#include "tgl-timer.h"

static const float SESSION_CLEANUP_TIMEOUT = 5.0;

void tglq_query_remove(std::shared_ptr<query> q);
bool send_pending_query(std::shared_ptr<query> q) {
    assert(q->DC);
    std::string name;
    double timeout;
    if (q->is_v2()) {
        auto q2 = std::static_pointer_cast<query_v2>(q);
        name = q2->name();
        timeout = q2->timeout_interval();
    } else {
        name = q->methods->name ? q->methods->name : "";
        timeout = q->methods->timeout;
    }

    if (!q->DC->sessions[0]) {
        tglmp_dc_create_session(q->DC);
    }
    if (!q->DC->auth_key_id) {
        TGL_DEBUG("not ready to send pending query " << q << " (" << name << "), re-queuing");
        q->DC->add_pending_query(q);
        return false;
    }
    if (!tgl_signed_dc(q->DC) && !(q->flags & QUERY_LOGIN)) {
        TGL_DEBUG("not ready to send pending non-login query " << q << " (" << name << "), re-queuing");
        q->DC->add_pending_query(q);
        return false;
    }

    q->flags &= ~QUERY_ACK_RECEIVED;
    tglq_query_remove(q);
    q->session = q->DC->sessions[0];
    q->msg_id = tglmp_encrypt_send_message (q->session->c, (int*)q->data, q->data_len, (q->flags & QUERY_FORCE_SEND) | 1);
    tgl_state::instance()->queries_tree.push_back(q);
    q->session_id = q->session->session_id;
    auto dc = q->session->dc.lock();
    if (dc && !(dc->flags & TGLDCF_CONFIGURED) && !(q->flags & QUERY_FORCE_SEND)) {
        q->session_id = 0;
    }

    TGL_DEBUG("Sending pending query \"" << name << "\" (" << q->msg_id << ") of size " << 4 * q->data_len << " to DC " << q->DC->id);

    q->ev->start(timeout ? timeout : DEFAULT_QUERY_TIMEOUT);

    return true;
}

tgl_dc::tgl_dc()
    : session_cleanup_timer(tgl_state::instance()->timer_factory()->create_timer(std::bind(&tgl_dc::cleanup_timer_expired, this)))
{
}

void tgl_dc::reset()
{
    TGL_DEBUG("resetting DC " << id);
    for (size_t i = 0; i < sessions.size(); ++i) {
        std::shared_ptr<tgl_session> session = sessions[i];
        if (session) {
            session->c->close();
            session->ev->cancel();
            session->c = nullptr;
            session->ev = nullptr;
            sessions[i] = nullptr;
        }
    }
    if (temp_auth_key_bind_query_id) {
        tglq_query_delete(temp_auth_key_bind_query_id);
        temp_auth_key_bind_query_id = 0;
    }
    flags = 0;
    rsa_key_idx = 0;
    state = st_init;
    memset(auth_key, 0, 256);
    memset(temp_auth_key, 0, 256);
    memset(nonce, 0, 256);
    memset(new_nonce, 0, 256);
    memset(server_nonce, 0, 256);
    auth_key_id = 0;
    temp_auth_key_id = 0;
    server_salt = 0;
    if (!pending_queries.empty()) {
        send_pending_queries();
    }
}

void tgl_dc::send_pending_queries() {
    TGL_NOTICE("sending pending queries for DC " << id);
    std::list<std::shared_ptr<query>> queries = pending_queries; // make a copy since queries can get re-enqueued
    for (std::shared_ptr<query> q : queries) {
        if (send_pending_query(q)) {
            pending_queries.remove(q);
        } else {
            TGL_DEBUG("sending pending query failed for DC " << id);
        }
    }
}

void tgl_dc::add_query(std::shared_ptr<query> q) {
    active_queries.push_back(q);
    session_cleanup_timer->cancel();
}

void tgl_dc::remove_query(std::shared_ptr<query> q) {
    active_queries.remove(q);

    if (active_queries.empty() && pending_queries.empty() && tgl_state::instance()->DC_working.get() != this) {
        session_cleanup_timer->start(SESSION_CLEANUP_TIMEOUT);
    }
}

void tgl_dc::add_pending_query(std::shared_ptr<query> q) {
    if (std::find(pending_queries.cbegin(), pending_queries.cend(), q) == pending_queries.cend()) {
        pending_queries.push_back(q);
    }
}

void tgl_dc::remove_pending_query(std::shared_ptr<query> q) {
    pending_queries.remove(q);
}

void tgl_dc::cleanup_timer_expired() {
    if (active_queries.empty() && pending_queries.empty()) {
        TGL_DEBUG("cleanup timer expired for DC " << id << ", deleting sessions");
        for (size_t i = 0; i < sessions.size(); ++i) {
            std::shared_ptr<tgl_session> session = sessions[i];
            if (session) {
                session->c->close();
                session->ev->cancel();
                session->c = nullptr;
                session->ev = nullptr;
                sessions[i] = nullptr;
            }
        }
    }
}
<|endoftext|>