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

#include "chrome/browser/ui/webui/options/language_options_handler.h"

#include <string>

#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "testing/gtest/include/gtest/gtest.h"

#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/input_method_library.h"
#include "chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.h"
#endif  // defined(OS_CHROMEOS)

#if defined(OS_CHROMEOS)
static chromeos::InputMethodDescriptors CreateInputMethodDescriptors() {
  chromeos::InputMethodDescriptors descriptors;
  descriptors.push_back(
      chromeos::InputMethodDescriptor("xkb:us::eng", "USA", "us", "eng"));
  descriptors.push_back(
      chromeos::InputMethodDescriptor("xkb:fr::fra", "France", "fr", "fra"));
  descriptors.push_back(
      chromeos::InputMethodDescriptor("xkb:be::fra", "Belgium", "be", "fr"));
  descriptors.push_back(
      chromeos::InputMethodDescriptor("mozc", "Mozc (US keyboard layout)", "us",
                                      "ja"));
  return descriptors;
}

TEST(LanguageOptionsHandlerTest, GetInputMethodList) {
  // Use the stub libcros. The object will take care of the cleanup.
  chromeos::ScopedStubCrosEnabler stub_cros_enabler;

  // Reset the library implementation so it will be initialized
  // again. Otherwise, non-stub implementation can be reused, if it's
  // already initialized elsewhere, which results in a crash.
  chromeos::CrosLibrary::Get()->GetTestApi()->SetInputMethodLibrary(NULL,
                                                                    false);

  chromeos::InputMethodDescriptors descriptors = CreateInputMethodDescriptors();
  scoped_ptr<ListValue> list(
      chromeos::CrosLanguageOptionsHandler::GetInputMethodList(descriptors));
  ASSERT_EQ(4U, list->GetSize());

  DictionaryValue* entry = NULL;
  DictionaryValue *language_code_set = NULL;
  std::string input_method_id;
  std::string display_name;
  std::string language_code;

  // As shown below, the list should be input method ids should appear in
  // the same order of the descriptors.
  ASSERT_TRUE(list->GetDictionary(0, &entry));
  ASSERT_TRUE(entry->GetString("id", &input_method_id));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set));
  EXPECT_EQ("xkb:us::eng", input_method_id);
  // Commented out as it depends on translation in generated_resources.grd
  // (i.e. makes the test fragile).
  // EXPECT_EQ("English (USA) keyboard layout", display_name);
  ASSERT_TRUE(language_code_set->HasKey("en-US"));
  ASSERT_TRUE(language_code_set->HasKey("id"));  // From kExtraLanguages.
  ASSERT_TRUE(language_code_set->HasKey("fil"));  // From kExtraLanguages.

  ASSERT_TRUE(list->GetDictionary(1, &entry));
  ASSERT_TRUE(entry->GetString("id", &input_method_id));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set));
  EXPECT_EQ("xkb:fr::fra", input_method_id);
  // Commented out. See above.
  // EXPECT_EQ("French keyboard layout", display_name);
  ASSERT_TRUE(language_code_set->HasKey("fr"));

  ASSERT_TRUE(list->GetDictionary(2, &entry));
  ASSERT_TRUE(entry->GetString("id", &input_method_id));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set));
  EXPECT_EQ("xkb:be::fra", input_method_id);
  // Commented out. See above.
  // EXPECT_EQ("Belgian keyboard layout", display_name);
  ASSERT_TRUE(language_code_set->HasKey("fr"));

  ASSERT_TRUE(list->GetDictionary(3, &entry));
  ASSERT_TRUE(entry->GetString("id", &input_method_id));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set));
  EXPECT_EQ("mozc", input_method_id);
  // Commented out. See above.
  // EXPECT_EQ("Japanese input method (for US keyboard)", display_name);
  ASSERT_TRUE(language_code_set->HasKey("ja"));
}

TEST(LanguageOptionsHandlerTest, GetLanguageList) {
  chromeos::InputMethodDescriptors descriptors = CreateInputMethodDescriptors();
  scoped_ptr<ListValue> list(
      chromeos::CrosLanguageOptionsHandler::GetLanguageList(descriptors));
  ASSERT_EQ(6U, list->GetSize());

  DictionaryValue* entry = NULL;
  std::string language_code;
  std::string display_name;
  std::string native_display_name;

  // As shown below, the list should be sorted by the display names,
  // and these names should not have duplicates.
  ASSERT_TRUE(list->GetDictionary(0, &entry));
  ASSERT_TRUE(entry->GetString("code", &language_code));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name));
  EXPECT_EQ("en-US", language_code);
  EXPECT_EQ("English (United States)", display_name);
  EXPECT_EQ("English (United States)", native_display_name);

  // This comes from kExtraLanguages.
  ASSERT_TRUE(list->GetDictionary(1, &entry));
  ASSERT_TRUE(entry->GetString("code", &language_code));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name));
  EXPECT_EQ("fil", language_code);
  EXPECT_EQ("Filipino", display_name);
  EXPECT_EQ("Filipino", native_display_name);

  ASSERT_TRUE(list->GetDictionary(2, &entry));
  ASSERT_TRUE(entry->GetString("code", &language_code));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name));
  EXPECT_EQ("fr", language_code);
  EXPECT_EQ("French", display_name);
  EXPECT_EQ("fran\u00E7ais", native_display_name);

  // This comes from kExtraLanguages.
  ASSERT_TRUE(list->GetDictionary(3, &entry));
  ASSERT_TRUE(entry->GetString("code", &language_code));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name));
  EXPECT_EQ("id", language_code);
  EXPECT_EQ("Indonesian", display_name);
  EXPECT_EQ("Bahasa Indonesia", native_display_name);

  ASSERT_TRUE(list->GetDictionary(4, &entry));
  ASSERT_TRUE(entry->GetString("code", &language_code));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name));
  EXPECT_EQ("ja", language_code);
  EXPECT_EQ("Japanese", display_name);
  EXPECT_EQ("\u65E5\u672C\u8A9E", native_display_name);

  // This comes from kExtraLanguages.
  ASSERT_TRUE(list->GetDictionary(5, &entry));
  ASSERT_TRUE(entry->GetString("code", &language_code));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name));
  EXPECT_EQ("es-419", language_code);
  EXPECT_EQ("Spanish (Latin America)", display_name);
  EXPECT_EQ("espa\u00F1ol (Latinoam\u00E9rica y el Caribe)",
            native_display_name);
}
#endif  // defined(OS_CHROMEOS)

#if !defined(OS_MACOSX)
TEST(LanguageOptionsHandlerTest, GetUILanguageCodeSet) {
  scoped_ptr<DictionaryValue> dictionary(
      LanguageOptionsHandler::GetUILanguageCodeSet());
  EXPECT_TRUE(dictionary->HasKey("en-US"));
  // Note that we don't test a false case, as such an expectation will
  // fail when we add support for the language.
  // EXPECT_FALSE(dictionary->HasKey("no"));
}
#endif  // !defined(OS_MACOSX)

TEST(LanguageOptionsHandlerTest, GetSpellCheckLanguageCodeSet) {
  scoped_ptr<DictionaryValue> dictionary(
      LanguageOptionsHandler::GetSpellCheckLanguageCodeSet());
  EXPECT_TRUE(dictionary->HasKey("en-US"));
}
<commit_msg>Fix the unit test expectations to handle Australia<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/options/language_options_handler.h"

#include <string>

#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "testing/gtest/include/gtest/gtest.h"

#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/input_method_library.h"
#include "chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.h"
#endif  // defined(OS_CHROMEOS)

#if defined(OS_CHROMEOS)
static chromeos::InputMethodDescriptors CreateInputMethodDescriptors() {
  chromeos::InputMethodDescriptors descriptors;
  descriptors.push_back(
      chromeos::InputMethodDescriptor("xkb:us::eng", "USA", "us", "eng"));
  descriptors.push_back(
      chromeos::InputMethodDescriptor("xkb:fr::fra", "France", "fr", "fra"));
  descriptors.push_back(
      chromeos::InputMethodDescriptor("xkb:be::fra", "Belgium", "be", "fr"));
  descriptors.push_back(
      chromeos::InputMethodDescriptor("mozc", "Mozc (US keyboard layout)", "us",
                                      "ja"));
  return descriptors;
}

TEST(LanguageOptionsHandlerTest, GetInputMethodList) {
  // Use the stub libcros. The object will take care of the cleanup.
  chromeos::ScopedStubCrosEnabler stub_cros_enabler;

  // Reset the library implementation so it will be initialized
  // again. Otherwise, non-stub implementation can be reused, if it's
  // already initialized elsewhere, which results in a crash.
  chromeos::CrosLibrary::Get()->GetTestApi()->SetInputMethodLibrary(NULL,
                                                                    false);

  chromeos::InputMethodDescriptors descriptors = CreateInputMethodDescriptors();
  scoped_ptr<ListValue> list(
      chromeos::CrosLanguageOptionsHandler::GetInputMethodList(descriptors));
  ASSERT_EQ(4U, list->GetSize());

  DictionaryValue* entry = NULL;
  DictionaryValue *language_code_set = NULL;
  std::string input_method_id;
  std::string display_name;
  std::string language_code;

  // As shown below, the list should be input method ids should appear in
  // the same order of the descriptors.
  ASSERT_TRUE(list->GetDictionary(0, &entry));
  ASSERT_TRUE(entry->GetString("id", &input_method_id));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set));
  EXPECT_EQ("xkb:us::eng", input_method_id);
  // Commented out as it depends on translation in generated_resources.grd
  // (i.e. makes the test fragile).
  // EXPECT_EQ("English (USA) keyboard layout", display_name);
  ASSERT_TRUE(language_code_set->HasKey("en-US"));
  ASSERT_TRUE(language_code_set->HasKey("id"));  // From kExtraLanguages.
  ASSERT_TRUE(language_code_set->HasKey("fil"));  // From kExtraLanguages.

  ASSERT_TRUE(list->GetDictionary(1, &entry));
  ASSERT_TRUE(entry->GetString("id", &input_method_id));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set));
  EXPECT_EQ("xkb:fr::fra", input_method_id);
  // Commented out. See above.
  // EXPECT_EQ("French keyboard layout", display_name);
  ASSERT_TRUE(language_code_set->HasKey("fr"));

  ASSERT_TRUE(list->GetDictionary(2, &entry));
  ASSERT_TRUE(entry->GetString("id", &input_method_id));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set));
  EXPECT_EQ("xkb:be::fra", input_method_id);
  // Commented out. See above.
  // EXPECT_EQ("Belgian keyboard layout", display_name);
  ASSERT_TRUE(language_code_set->HasKey("fr"));

  ASSERT_TRUE(list->GetDictionary(3, &entry));
  ASSERT_TRUE(entry->GetString("id", &input_method_id));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set));
  EXPECT_EQ("mozc", input_method_id);
  // Commented out. See above.
  // EXPECT_EQ("Japanese input method (for US keyboard)", display_name);
  ASSERT_TRUE(language_code_set->HasKey("ja"));
}

TEST(LanguageOptionsHandlerTest, GetLanguageList) {
  chromeos::InputMethodDescriptors descriptors = CreateInputMethodDescriptors();
  scoped_ptr<ListValue> list(
      chromeos::CrosLanguageOptionsHandler::GetLanguageList(descriptors));
  ASSERT_EQ(7U, list->GetSize());

  DictionaryValue* entry = NULL;
  std::string language_code;
  std::string display_name;
  std::string native_display_name;

  // As shown below, the list should be sorted by the display names,
  // and these names should not have duplicates.

  // This comes from kExtraLanguages.
  ASSERT_TRUE(list->GetDictionary(0, &entry));
  ASSERT_TRUE(entry->GetString("code", &language_code));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name));
  EXPECT_EQ("en-AU", language_code);
  EXPECT_EQ("English (Australia)", display_name);
  EXPECT_EQ("English (Australia)", native_display_name);

  ASSERT_TRUE(list->GetDictionary(1, &entry));
  ASSERT_TRUE(entry->GetString("code", &language_code));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name));
  EXPECT_EQ("en-US", language_code);
  EXPECT_EQ("English (United States)", display_name);
  EXPECT_EQ("English (United States)", native_display_name);

  // This comes from kExtraLanguages.
  ASSERT_TRUE(list->GetDictionary(2, &entry));
  ASSERT_TRUE(entry->GetString("code", &language_code));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name));
  EXPECT_EQ("fil", language_code);
  EXPECT_EQ("Filipino", display_name);
  EXPECT_EQ("Filipino", native_display_name);

  ASSERT_TRUE(list->GetDictionary(3, &entry));
  ASSERT_TRUE(entry->GetString("code", &language_code));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name));
  EXPECT_EQ("fr", language_code);
  EXPECT_EQ("French", display_name);
  EXPECT_EQ("fran\u00E7ais", native_display_name);

  // This comes from kExtraLanguages.
  ASSERT_TRUE(list->GetDictionary(4, &entry));
  ASSERT_TRUE(entry->GetString("code", &language_code));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name));
  EXPECT_EQ("id", language_code);
  EXPECT_EQ("Indonesian", display_name);
  EXPECT_EQ("Bahasa Indonesia", native_display_name);

  ASSERT_TRUE(list->GetDictionary(5, &entry));
  ASSERT_TRUE(entry->GetString("code", &language_code));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name));
  EXPECT_EQ("ja", language_code);
  EXPECT_EQ("Japanese", display_name);
  EXPECT_EQ("\u65E5\u672C\u8A9E", native_display_name);

  // This comes from kExtraLanguages.
  ASSERT_TRUE(list->GetDictionary(6, &entry));
  ASSERT_TRUE(entry->GetString("code", &language_code));
  ASSERT_TRUE(entry->GetString("displayName", &display_name));
  ASSERT_TRUE(entry->GetString("nativeDisplayName", &native_display_name));
  EXPECT_EQ("es-419", language_code);
  EXPECT_EQ("Spanish (Latin America)", display_name);
  EXPECT_EQ("espa\u00F1ol (Latinoam\u00E9rica y el Caribe)",
            native_display_name);
}
#endif  // defined(OS_CHROMEOS)

#if !defined(OS_MACOSX)
TEST(LanguageOptionsHandlerTest, GetUILanguageCodeSet) {
  scoped_ptr<DictionaryValue> dictionary(
      LanguageOptionsHandler::GetUILanguageCodeSet());
  EXPECT_TRUE(dictionary->HasKey("en-US"));
  // Note that we don't test a false case, as such an expectation will
  // fail when we add support for the language.
  // EXPECT_FALSE(dictionary->HasKey("no"));
}
#endif  // !defined(OS_MACOSX)

TEST(LanguageOptionsHandlerTest, GetSpellCheckLanguageCodeSet) {
  scoped_ptr<DictionaryValue> dictionary(
      LanguageOptionsHandler::GetSpellCheckLanguageCodeSet());
  EXPECT_TRUE(dictionary->HasKey("en-US"));
}
<|endoftext|>


<commit_before><?php
define('APP_ENV', 'MAIN');
require(__DIR__.'/core/app-load.php');
header('Content-Type: text/html; charset=utf-8');
echo Helper::go(HTTP::GET, $_GET, $_POST, $_SERVER, $_COOKIE);
<commit_msg>:bug: Ignore any post data in main website<commit_after><?php
define('APP_ENV', 'MAIN');
require(__DIR__.'/core/app-load.php');
header('Content-Type: text/html; charset=utf-8');
echo Helper::go(HTTP::GET, $_GET, [], $_SERVER, $_COOKIE);
<|endoftext|>


<commit_before>#include <iostream>

#include "memfun.hpp"

struct S
{
  void f() const noexcept
  {
    std::cout << "Hello world!" << std::endl;
  }

  void g(int const a) const noexcept
  {
    std::cout << a << std::endl;
  }
};

int main()
{
  S s;

  auto const f(gnr::memfun<MEMFUN(S::f)>(s));

  f();

  auto const g(gnr::memfun<MEMFUN(S::f)>(&s));

  g();

  auto const h(gnr::memfun<MEMFUN(S::f)>());

  h(s);

  auto const i(gnr::memfun<MEMFUN(S::g)>());

  i(s, 10);
  i(&s, 10);

  return 0;
}
<commit_msg>some fixes<commit_after>#include <iostream>

#include "memfun.hpp"

struct S
{
  void f() const noexcept
  {
    std::cout << "Hello world!" << std::endl;
  }

  void g(int const a) const noexcept
  {
    std::cout << a << std::endl;
  }
};

int main()
{
  S s;

  auto const f(gnr::memfun<MEMFUN(S::f)>(s));

  f();

  auto const g(gnr::memfun<MEMFUN(S::f)>(&s));

  g();

  auto const h(gnr::memfun<MEMFUN(S::f)>());

  h(s);

  auto const i(gnr::memfun<MEMFUN(S::g)>());

  i(s, 10);
  i(&s, 10);

  return 0;
}
<|endoftext|>


<commit_before>// -------------------------------------------------------------------------
//    @FileName         :    NFCProperty.cpp
//    @Author           :    LvSheng.Huang
//    @Date             :    2012-03-01
//    @Module           :    NFCProperty
//
// -------------------------------------------------------------------------

#include "NFCProperty.h"
#include <complex>

NFCProperty::NFCProperty()
{
    mbPublic = false;
    mbPrivate = false;
    mbSave = false;
    mSelf = NFGUID();
    eType = TDATA_UNKNOWN;

    msPropertyName = "";
}

NFCProperty::NFCProperty(const NFGUID& self, const std::string& strPropertyName, const TDATA_TYPE varType, bool bPublic,  bool bPrivate,  bool bSave, bool bView, int nIndex, const std::string& strScriptFunction)
{

    mbPublic = bPublic;
    mbPrivate = bPrivate;
    mbSave = bSave;
    mbView = bView;
    mnIndex = nIndex;
    mSelf = self;

    msPropertyName = strPropertyName;
    eType = varType;
}

NFCProperty::~NFCProperty()
{
    for (TPROPERTYCALLBACKEX::iterator iter = mtPropertyCallback.begin(); iter != mtPropertyCallback.end(); ++iter)
    {
        iter->reset();
    }

    mtPropertyCallback.clear();
    mxData.reset();
}

void NFCProperty::SetValue(const NFIDataList::TData& TData)
{
    if (eType != TData.GetType())
    {
        return;
    }

    if (!mxData.get())
    {
        if (!TData.IsNullValue())
        {
            return;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TData));
    }

    NFCDataList::TData oldValue;
    oldValue = *mxData;

    mxData->variantData = TData.variantData;

    NFCDataList::TData newValue;
    newValue = *mxData;

    OnEventHandler(oldValue , newValue);
}

void NFCProperty::SetValue(const NFIProperty* pProperty)
{
    SetValue(pProperty->GetValue());
}

const NFIDataList::TData& NFCProperty::GetValue() const
{
    if (mxData.get())
    {
        return *mxData;
    }

    return NULL_TDATA;
}

const std::string&  NFCProperty::GetKey() const
{
    return msPropertyName;
}

const bool NFCProperty::GetSave() const
{
    return mbSave;
}

const bool NFCProperty::GetView() const
{
    return mbView;
}

const bool NFCProperty::GetPublic() const
{
    return mbPublic;
}

const bool NFCProperty::GetPrivate() const
{
    return mbPrivate;
}

const int NFCProperty::GetIndex() const
{
    return mnIndex;
};

const std::string& NFCProperty::GetRelationValue() const
{
    return NULL_STR;//msScriptFunction;
}

void NFCProperty::SetSave(bool bSave)
{
    mbSave = bSave;
}

void NFCProperty::SetView(bool bView)
{
    mbView = bView;
}

void NFCProperty::SetPublic(bool bPublic)
{
    mbPublic = bPublic;
}

void NFCProperty::SetPrivate(bool bPrivate)
{
    mbPrivate = bPrivate;
}

void NFCProperty::SetScriptFunction(const std::string& strScriptFunction)
{
    //msScriptFunction = strScriptFunction;
}

NFINT64 NFCProperty::GetInt() const
{
    if (!mxData.get())
    {
        return 0;
    }

    return mxData->GetInt();
}

double NFCProperty::GetFloat() const
{
    if (!mxData.get())
    {
        return 0.0;
    }

    return mxData->GetFloat();
}

const std::string& NFCProperty::GetString() const
{
    if (!mxData.get())
    {
        return NULL_STR;
    }

    return mxData->GetString();
}

const NFGUID& NFCProperty::GetObject() const
{
    if (!mxData.get())
    {
        return NULL_OBJECT;
    }

    return mxData->GetObject();
}

void NFCProperty::RegisterCallback(const PROPERTY_EVENT_FUNCTOR_PTR& cb)
{
    mtPropertyCallback.push_back(cb);
}

int NFCProperty::OnEventHandler(const NFIDataList::TData& oldVar, const NFIDataList::TData& newVar)
{
    if (mtPropertyCallback.size() <= 0)
    {
        return 0;
    }

    TPROPERTYCALLBACKEX::iterator it = mtPropertyCallback.begin();
    TPROPERTYCALLBACKEX::iterator end = mtPropertyCallback.end();
    for (it; it != end; ++it)
    {
        //NFIDataList:OLDֵNEWֵ, ARG(pKernel,self)
        PROPERTY_EVENT_FUNCTOR_PTR& pFunPtr = *it;
        PROPERTY_EVENT_FUNCTOR* pFunc = pFunPtr.get();
        int nTemRet = pFunc->operator()(mSelf, msPropertyName, oldVar, newVar);
    }

    return 0;
}

bool NFCProperty::SetInt(const NFINT64 value)
{
    if (eType != TDATA_INT)
    {
        return false;
    }

	if (!mxData.get())
	{
		//ǿվΪûݣûݵľͲ
		if (0 == value)
		{
			return false;
		}

		mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_INT));
		mxData->SetInt(0);
	}

	if (value == mxData->GetInt())
	{
		return false;
	}

	NFCDataList::TData oldValue;
	oldValue = *mxData;

	mxData->SetInt(value);

	OnEventHandler(oldValue , *mxData);

	return true;
}

bool NFCProperty::SetFloat(const double value)
{
    if (eType != TDATA_FLOAT)
    {
        return false;
    }

    if (!mxData.get())
    {
        //ǿվΪûݣûݵľͲ
		if (std::abs(value) < 0.001)
		{
            return false;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_FLOAT));
        mxData->SetFloat(0.0);
    }

    if (value - mxData->GetFloat() < 0.001)
    {
        return false;
    }

	NFCDataList::TData oldValue;
	oldValue = *mxData;

	mxData->SetFloat(value);

	OnEventHandler(oldValue , *mxData);

	return true;
}

bool NFCProperty::SetString(const std::string& value)
{
    if (eType != TDATA_STRING)
    {
        return false;
    }

    if (!mxData.get())
    {
        //ǿվΪûݣûݵľͲ
        if (value.empty())
        {
            return false;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_STRING));
        mxData->SetString(NULL_STR);
    }

    if (value == mxData->GetString())
    {
        return false;
    }

	NFCDataList::TData oldValue;
	oldValue = *mxData;

	mxData->SetString(value);

	OnEventHandler(oldValue , *mxData);

	return true;
}

bool NFCProperty::SetObject(const NFGUID& value)
{
    if (eType != TDATA_OBJECT)
    {
        return false;
    }

    if (!mxData.get())
    {
        //ǿվΪûݣûݵľͲ
        if (value.IsNull())
        {
            return false;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_OBJECT));
        mxData->SetObject(NFGUID());

    }

    if (value == mxData->GetObject())
    {
        return false;
    }

    NFCDataList::TData oldValue;
    oldValue = *mxData;

    mxData->SetObject(value);

    OnEventHandler(oldValue , *mxData);

    return true;
}

bool NFCProperty::Changed() const
{
    return GetValue().IsNullValue();
}

const TDATA_TYPE NFCProperty::GetType() const
{
    return eType;
}

const bool NFCProperty::GeUsed() const
{
    if (mxData.get())
    {
        return true;
    }

    return false;
}

std::string NFCProperty::ToString()
{
    std::string strData;
    const TDATA_TYPE eType = GetType();
    switch (eType)
    {
    case TDATA_INT:
        strData = lexical_cast<std::string> (GetInt());
        break;

    case TDATA_FLOAT:
        strData = lexical_cast<std::string> (GetFloat());
        break;

    case TDATA_STRING:
        strData = lexical_cast<std::string> (GetString());
        break;
    case TDATA_OBJECT:
        strData = GetObject().ToString();
        break;
    default:

        strData = NULL_STR;
        break;
    }

    return strData;
}

bool NFCProperty::FromString( const std::string& strData )
{
    const TDATA_TYPE eType = GetType();
    bool bRet = false;
    switch (eType)
    {
    case TDATA_INT:
        {
            NFINT64  nValue = 0;
            bRet = NF_StrTo(strData, nValue);
            SetInt(nValue);
        }
        break;

    case TDATA_FLOAT:
        {
            double  dValue = 0;
            bRet = NF_StrTo(strData, dValue);
            SetFloat(dValue);
        }
        break;

    case TDATA_STRING:
        {
            SetString(strData);
            bRet = true;
        }
        break;
    case TDATA_OBJECT:
        {
            NFGUID xID;

            bRet = xID.FromString(strData);
            SetObject(xID);
        }
        break;
    default:
        break;
    }

    return bRet;
}
<commit_msg>optimize code when property been set<commit_after>// -------------------------------------------------------------------------
//    @FileName         :    NFCProperty.cpp
//    @Author           :    LvSheng.Huang
//    @Date             :    2012-03-01
//    @Module           :    NFCProperty
//
// -------------------------------------------------------------------------

#include "NFCProperty.h"
#include <complex>

NFCProperty::NFCProperty()
{
    mbPublic = false;
    mbPrivate = false;
    mbSave = false;
    mSelf = NFGUID();
    eType = TDATA_UNKNOWN;

    msPropertyName = "";
}

NFCProperty::NFCProperty(const NFGUID& self, const std::string& strPropertyName, const TDATA_TYPE varType, bool bPublic,  bool bPrivate,  bool bSave, bool bView, int nIndex, const std::string& strScriptFunction)
{

    mbPublic = bPublic;
    mbPrivate = bPrivate;
    mbSave = bSave;
    mbView = bView;
    mnIndex = nIndex;
    mSelf = self;

    msPropertyName = strPropertyName;
    eType = varType;
}

NFCProperty::~NFCProperty()
{
    for (TPROPERTYCALLBACKEX::iterator iter = mtPropertyCallback.begin(); iter != mtPropertyCallback.end(); ++iter)
    {
        iter->reset();
    }

    mtPropertyCallback.clear();
    mxData.reset();
}

void NFCProperty::SetValue(const NFIDataList::TData& TData)
{
    if (eType != TData.GetType())
    {
        return;
    }

    if (!mxData.get())
    {
        if (!TData.IsNullValue())
        {
            return;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TData));
    }

    NFCDataList::TData oldValue;
    oldValue = *mxData;

    mxData->variantData = TData.variantData;

    NFCDataList::TData newValue;
    newValue = *mxData;

    OnEventHandler(oldValue , newValue);
}

void NFCProperty::SetValue(const NFIProperty* pProperty)
{
    SetValue(pProperty->GetValue());
}

const NFIDataList::TData& NFCProperty::GetValue() const
{
    if (mxData.get())
    {
        return *mxData;
    }

    return NULL_TDATA;
}

const std::string&  NFCProperty::GetKey() const
{
    return msPropertyName;
}

const bool NFCProperty::GetSave() const
{
    return mbSave;
}

const bool NFCProperty::GetView() const
{
    return mbView;
}

const bool NFCProperty::GetPublic() const
{
    return mbPublic;
}

const bool NFCProperty::GetPrivate() const
{
    return mbPrivate;
}

const int NFCProperty::GetIndex() const
{
    return mnIndex;
};

const std::string& NFCProperty::GetRelationValue() const
{
    return NULL_STR;//msScriptFunction;
}

void NFCProperty::SetSave(bool bSave)
{
    mbSave = bSave;
}

void NFCProperty::SetView(bool bView)
{
    mbView = bView;
}

void NFCProperty::SetPublic(bool bPublic)
{
    mbPublic = bPublic;
}

void NFCProperty::SetPrivate(bool bPrivate)
{
    mbPrivate = bPrivate;
}

void NFCProperty::SetScriptFunction(const std::string& strScriptFunction)
{
    //msScriptFunction = strScriptFunction;
}

NFINT64 NFCProperty::GetInt() const
{
    if (!mxData.get())
    {
        return 0;
    }

    return mxData->GetInt();
}

double NFCProperty::GetFloat() const
{
    if (!mxData.get())
    {
        return 0.0;
    }

    return mxData->GetFloat();
}

const std::string& NFCProperty::GetString() const
{
    if (!mxData.get())
    {
        return NULL_STR;
    }

    return mxData->GetString();
}

const NFGUID& NFCProperty::GetObject() const
{
    if (!mxData.get())
    {
        return NULL_OBJECT;
    }

    return mxData->GetObject();
}

void NFCProperty::RegisterCallback(const PROPERTY_EVENT_FUNCTOR_PTR& cb)
{
    mtPropertyCallback.push_back(cb);
}

int NFCProperty::OnEventHandler(const NFIDataList::TData& oldVar, const NFIDataList::TData& newVar)
{
    if (mtPropertyCallback.size() <= 0)
    {
        return 0;
    }

    TPROPERTYCALLBACKEX::iterator it = mtPropertyCallback.begin();
    TPROPERTYCALLBACKEX::iterator end = mtPropertyCallback.end();
    for (it; it != end; ++it)
    {
        //NFIDataList:OLDֵNEWֵ, ARG(pKernel,self)
        PROPERTY_EVENT_FUNCTOR_PTR& pFunPtr = *it;
        PROPERTY_EVENT_FUNCTOR* pFunc = pFunPtr.get();
        int nTemRet = pFunc->operator()(mSelf, msPropertyName, oldVar, newVar);
    }

    return 0;
}

bool NFCProperty::SetInt(const NFINT64 value)
{
    if (eType != TDATA_INT)
    {
        return false;
    }

	if (!mxData.get())
	{
		//ǿվΪûݣûݵľͲ
		if (0 == value)
		{
			return false;
		}

		mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_INT));
		mxData->SetInt(0);
	}

	if (value == mxData->GetInt())
	{
		return false;
	}

	NFCDataList::TData oldValue;
	oldValue = *mxData;

	mxData->SetInt(value);

	OnEventHandler(oldValue , value);

	return true;
}

bool NFCProperty::SetFloat(const double value)
{
    if (eType != TDATA_FLOAT)
    {
        return false;
    }

    if (!mxData.get())
    {
        //ǿվΪûݣûݵľͲ
		if (std::abs(value) < 0.001)
		{
            return false;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_FLOAT));
        mxData->SetFloat(0.0);
    }

    if (value - mxData->GetFloat() < 0.001)
    {
        return false;
    }

	NFCDataList::TData oldValue;
	oldValue = *mxData;

	mxData->SetFloat(value);

	OnEventHandler(oldValue , newValue);

	return true;
}

bool NFCProperty::SetString(const std::string& value)
{
    if (eType != TDATA_STRING)
    {
        return false;
    }

    if (!mxData.get())
    {
        //ǿվΪûݣûݵľͲ
        if (value.empty())
        {
            return false;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_STRING));
        mxData->SetString(NULL_STR);
    }

    if (value == mxData->GetString())
    {
        return false;
    }

	NFCDataList::TData oldValue;
	oldValue = *mxData;

	mxData->SetString(value);

	OnEventHandler(oldValue , newValue);

	return true;
}

bool NFCProperty::SetObject(const NFGUID& value)
{
    if (eType != TDATA_OBJECT)
    {
        return false;
    }

    if (!mxData.get())
    {
        //ǿվΪûݣûݵľͲ
        if (value.IsNull())
        {
            return false;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_OBJECT));
        mxData->SetObject(NFGUID());

    }

    if (value == mxData->GetObject())
    {
        return false;
    }

    NFCDataList::TData oldValue;
    oldValue = *mxData;

    mxData->SetObject(value);

    OnEventHandler(oldValue , *mxData);

    return true;
}

bool NFCProperty::Changed() const
{
    return GetValue().IsNullValue();
}

const TDATA_TYPE NFCProperty::GetType() const
{
    return eType;
}

const bool NFCProperty::GeUsed() const
{
    if (mxData.get())
    {
        return true;
    }

    return false;
}

std::string NFCProperty::ToString()
{
    std::string strData;
    const TDATA_TYPE eType = GetType();
    switch (eType)
    {
    case TDATA_INT:
        strData = lexical_cast<std::string> (GetInt());
        break;

    case TDATA_FLOAT:
        strData = lexical_cast<std::string> (GetFloat());
        break;

    case TDATA_STRING:
        strData = lexical_cast<std::string> (GetString());
        break;
    case TDATA_OBJECT:
        strData = GetObject().ToString();
        break;
    default:

        strData = NULL_STR;
        break;
    }

    return strData;
}

bool NFCProperty::FromString( const std::string& strData )
{
    const TDATA_TYPE eType = GetType();
    bool bRet = false;
    switch (eType)
    {
    case TDATA_INT:
        {
            NFINT64  nValue = 0;
            bRet = NF_StrTo(strData, nValue);
            SetInt(nValue);
        }
        break;

    case TDATA_FLOAT:
        {
            double  dValue = 0;
            bRet = NF_StrTo(strData, dValue);
            SetFloat(dValue);
        }
        break;

    case TDATA_STRING:
        {
            SetString(strData);
            bRet = true;
        }
        break;
    case TDATA_OBJECT:
        {
            NFGUID xID;

            bRet = xID.FromString(strData);
            SetObject(xID);
        }
        break;
    default:
        break;
    }

    return bRet;
}
<|endoftext|>


<commit_before><commit_msg>Messages<commit_after><|endoftext|>


<commit_before>#include "alpha-expansion.hpp"

MultiLabelCRF::MultiLabelCRF(Label max_label)
    : m_num_labels(max_label),
    m_constant_term(0),
    m_cliques(),
    m_unary_cost(),
    m_labels()
{ }

MultiLabelCRF::NodeId MultiLabelCRF::AddNode(int n) {
    NodeId ret = m_labels.size();
    for (int i = 0; i < n; ++i) {
        m_labels.push_back(0);
        UnaryCost uc(m_num_labels, 0);
        m_unary_cost.push_back(uc);
    }
    return ret;
}

int MultiLabelCRF::GetLabel(NodeId i) const {
    return m_labels[i];
}

void MultiLabelCRF::AddConstantTerm(REAL c) {
    m_constant_term += c;
}

void MultiLabelCRF::AddUnaryTerm(NodeId i, const std::vector<REAL>& coeffs) {
    ASSERT(coeffs.size() == m_num_labels);
    for (size_t j = 0; j < m_num_labels; ++j) {
        m_unary_cost[i][j] += coeffs[j];
    }
}

void MultiLabelCRF::AddClique(const CliquePtr& cp) {
    m_cliques.push_back(cp);
}

void MultiLabelCRF::SetupAlphaEnergy(Label alpha, SubmodularFlow& crf) const {
    typedef int32_t Assgn;
    for (const CliquePtr& cp : m_cliques) {
        const Clique& c = *cp;
        const size_t k = c.Size();
        ASSERT(k < 32);
        const Assgn max_assgn = 1 << k;
        std::vector<REAL> energy_table;
        std::vector<Label> label_buf;
        for (Assgn a = 0; a < max_assgn; ++a) {
            label_buf.clear();
            for (size_t i_idx = 0; i_idx < k; ++i_idx) {
                if (a & (1 << i_idx))
                    label_buf.push_back(alpha);
                else
                    label_buf.push_back(m_labels[c.Nodes()[i_idx]]);
            }
            energy_table.push_back(c.Energy(label_buf));
        }
        crf.AddClique(c.Nodes(), energy_table);
    }
}

void MultiLabelCRF::AlphaExpansion() {
    std::cout << "Starting Alpha Expansion\n";
    REAL last_energy = std::numeric_limits<REAL>::max();
    REAL energy = ComputeEnergy();
    const NodeId n = m_labels.size();
    size_t num_rounds = 0;
    while (energy < last_energy) {
        std::cout << "\tRound: " << num_rounds;
        std::cout.flush();
        for (Label alpha = 0; alpha < m_num_labels; ++alpha) {
            std::cout << ".";
            std::cout.flush();
            SubmodularFlow crf;
            crf.AddNode(m_labels.size());
            SetupAlphaEnergy(alpha, crf);
            crf.Solve();
            for (NodeId i = 0; i < n; ++i) {
                int crf_label = crf.GetLabel(i);
                if (crf_label == 1)
                    m_labels[i] = alpha;
            }
        }
        std::cout << "\n";
        last_energy = energy;
        energy = ComputeEnergy();
        num_rounds++;
    }
}

void MultiLabelCRF::Solve() {
    AlphaExpansion();
}

REAL MultiLabelCRF::ComputeEnergy() const {
    return ComputeEnergy(m_labels);
}

REAL MultiLabelCRF::ComputeEnergy(const std::vector<Label>& labels) const {
    REAL energy = m_constant_term;
    std::vector<Label> labelBuf;
    for (const CliquePtr& cp : m_cliques) {
        const Clique& c = *cp;
        labelBuf.clear();
        for (NodeId i : c.Nodes())
            labelBuf.push_back(m_labels[i]);
        energy += c.Energy(labelBuf);
    }
    return energy;
}

<commit_msg>Actually adding unary terms to AlphaExpansion Energy<commit_after>#include "alpha-expansion.hpp"

MultiLabelCRF::MultiLabelCRF(Label max_label)
    : m_num_labels(max_label),
    m_constant_term(0),
    m_cliques(),
    m_unary_cost(),
    m_labels()
{ }

MultiLabelCRF::NodeId MultiLabelCRF::AddNode(int n) {
    NodeId ret = m_labels.size();
    for (int i = 0; i < n; ++i) {
        m_labels.push_back(0);
        UnaryCost uc(m_num_labels, 0);
        m_unary_cost.push_back(uc);
    }
    return ret;
}

int MultiLabelCRF::GetLabel(NodeId i) const {
    return m_labels[i];
}

void MultiLabelCRF::AddConstantTerm(REAL c) {
    m_constant_term += c;
}

void MultiLabelCRF::AddUnaryTerm(NodeId i, const std::vector<REAL>& coeffs) {
    ASSERT(coeffs.size() == m_num_labels);
    for (size_t j = 0; j < m_num_labels; ++j) {
        m_unary_cost[i][j] += coeffs[j];
    }
}

void MultiLabelCRF::AddClique(const CliquePtr& cp) {
    m_cliques.push_back(cp);
}

void MultiLabelCRF::SetupAlphaEnergy(Label alpha, SubmodularFlow& crf) const {
    typedef int32_t Assgn;
    for (const CliquePtr& cp : m_cliques) {
        const Clique& c = *cp;
        const size_t k = c.Size();
        ASSERT(k < 32);
        const Assgn max_assgn = 1 << k;
        std::vector<REAL> energy_table;
        std::vector<Label> label_buf;
        for (Assgn a = 0; a < max_assgn; ++a) {
            label_buf.clear();
            for (size_t i_idx = 0; i_idx < k; ++i_idx) {
                if (a & (1 << i_idx))
                    label_buf.push_back(alpha);
                else
                    label_buf.push_back(m_labels[c.Nodes()[i_idx]]);
            }
            energy_table.push_back(c.Energy(label_buf));
        }
        crf.AddClique(c.Nodes(), energy_table);
    }
    const NodeId n = m_unary_cost.size();
    for (NodeId i = 0; i < n; ++i) {
        crf.AddUnaryTerm(i, m_unary_cost[i][m_labels[i]], m_unary_cost[i][alpha]);
    }
}

void MultiLabelCRF::AlphaExpansion() {
    std::cout << "Starting Alpha Expansion\n";
    REAL last_energy = std::numeric_limits<REAL>::max();
    REAL energy = ComputeEnergy();
    const NodeId n = m_labels.size();
    size_t num_rounds = 0;
    while (energy < last_energy) {
        std::cout << "\tRound: " << num_rounds;
        std::cout.flush();
        for (Label alpha = 0; alpha < m_num_labels; ++alpha) {
            std::cout << ".";
            std::cout.flush();
            SubmodularFlow crf;
            crf.AddNode(m_labels.size());
            SetupAlphaEnergy(alpha, crf);
            crf.Solve();
            for (NodeId i = 0; i < n; ++i) {
                int crf_label = crf.GetLabel(i);
                if (crf_label == 1)
                    m_labels[i] = alpha;
            }
        }
        std::cout << "\n";
        last_energy = energy;
        energy = ComputeEnergy();
        num_rounds++;
    }
}

void MultiLabelCRF::Solve() {
    AlphaExpansion();
}

REAL MultiLabelCRF::ComputeEnergy() const {
    return ComputeEnergy(m_labels);
}

REAL MultiLabelCRF::ComputeEnergy(const std::vector<Label>& labels) const {
    REAL energy = m_constant_term;
    std::vector<Label> labelBuf;
    for (const CliquePtr& cp : m_cliques) {
        const Clique& c = *cp;
        labelBuf.clear();
        for (NodeId i : c.Nodes())
            labelBuf.push_back(m_labels[i]);
        energy += c.Energy(labelBuf);
    }
    const NodeId n = m_labels.size();
    for (NodeId i = 0; i < n; ++i)
        energy += m_unary_cost[i][labels[i]];
    return energy;
}

<|endoftext|>


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

#include "DpaTransfer.h"
#include "DpaTransaction.h"

#include "unexpected_packet_type.h"
#include "unexpected_command.h"
#include "unexpected_peripheral.h"

#include "IqrfLogging.h"

DpaTransfer::DpaTransfer()
  : m_status(kCreated), m_sentMessage(nullptr), m_responseMessage(nullptr),
  m_expectedDurationMs(400), m_timeoutMs(400), m_currentCommunicationMode(kStd), m_dpaTransaction(nullptr)
{
}

DpaTransfer::DpaTransfer(DpaTransaction* dpaTransaction, IqrfRfCommunicationMode comMode)
  : m_status(kCreated), m_sentMessage(nullptr), m_responseMessage(nullptr),
  m_expectedDurationMs(400), m_timeoutMs(400), m_currentCommunicationMode(comMode), m_dpaTransaction(dpaTransaction)
{
}

DpaTransfer::~DpaTransfer()
{
  delete m_sentMessage;
  delete m_responseMessage;
}

void DpaTransfer::ProcessSentMessage(const DpaMessage& sentMessage)
{
  TRC_ENTER("");

  if (m_status != kCreated)
  {
    throw std::logic_error("Sent message already set.");
  }

  // current request status is set as sent
  if (sentMessage.NodeAddress() == COORDINATOR_ADDRESS) {
    SetStatus(kSentCoordinator);
  }
  else {
    SetStatus(kSent);
  }

  // message itself is destroyed after being sent
  delete m_sentMessage;
  // creating object to hold new request
  m_sentMessage = new DpaMessage(sentMessage);

  // setting default timeout, no estimation yet
  SetTimingForCurrentTransfer();

  TRC_LEAVE("");
}

void DpaTransfer::ProcessReceivedMessage(const DpaMessage& receivedMessage)
{
  TRC_ENTER("");

  if (receivedMessage.MessageDirection() != DpaMessage::kResponse
    && receivedMessage.MessageDirection() != DpaMessage::kConfirmation)
    throw unexpected_packet_type("Response is expected.");

  std::lock_guard<std::mutex> lck(m_statusMutex);

  // checks
  if (!IsInProgressStatus(m_status)) {
    throw unexpected_packet_type("Request has not been sent, yet.");
  }

  if (receivedMessage.PeripheralType() != m_sentMessage->PeripheralType()) {
    throw unexpected_peripheral("Different peripheral type than in sent message.");
  }

  if ((receivedMessage.PeripheralCommand() & ~0x80) != m_sentMessage->PeripheralCommand()) {
    throw unexpected_command("Different peripheral command than in sent message.");
  }

  // direction
  auto messageDirection = receivedMessage.MessageDirection();
  if (messageDirection == DpaMessage::kConfirmation) {
    if (m_dpaTransaction) {
      m_dpaTransaction->processConfirmationMessage(receivedMessage);
    }

    ProcessConfirmationMessage(receivedMessage);
    TRC_INF("Confirmation processed.");
  }
  else {
    if (m_dpaTransaction) {
      m_dpaTransaction->processResponseMessage(receivedMessage);
    }

    ProcessResponseMessage(receivedMessage);
    TRC_INF("Response processed.");
  }
  TRC_LEAVE("");
}

void DpaTransfer::ProcessConfirmationMessage(const DpaMessage& confirmationMessage)
{
  if (confirmationMessage.NodeAddress() == DpaMessage::kBroadCastAddress) {
    m_status = kConfirmationBroadcast;
  }
  else {
    m_status = kConfirmation;
  }

  // setting timeout based on the confirmation
  SetTimingForCurrentTransfer(EstimatedTimeout(confirmationMessage));
}

void DpaTransfer::ProcessResponseMessage(const DpaMessage& responseMessage)
{
  // if there is a request to coordinator then after receiving response it is allowed to send another
  if (m_status == kSentCoordinator) {
    // done, next request gets ready
    m_status = kProcessed;
  }
  else {
    // only if there is not infinite timeout
    if (m_expectedDurationMs != 0) {
      m_status = kReceivedResponse;
      // adjust timing before allowing next request
      SetTimingForCurrentTransfer(EstimatedTimeout(responseMessage));
    }
    // infinite timeout
    else {
      // done, next request gets ready
      m_status = kProcessed;
    }
  }

  delete m_responseMessage;
  m_responseMessage = new DpaMessage(responseMessage);
}

int32_t DpaTransfer::EstimatedTimeout(const DpaMessage& receivedMessage)
{
  // direction
  auto direction = receivedMessage.MessageDirection();

  // double check
  if (direction != DpaMessage::kConfirmation && direction != DpaMessage::kResponse) {
    throw std::invalid_argument("Parameter is not a received message type.");
  }

  // confirmation
  if (direction == DpaMessage::kConfirmation) {
    auto iFace = receivedMessage.DpaPacket().DpaResponsePacket_t.DpaMessage.IFaceConfirmation;

    // save for later use with response
    m_hops = iFace.Hops;
    m_timeslotLength = iFace.TimeSlotLength;
    m_hopsResponse = iFace.HopsResponse;

    // lp
    if (m_currentCommunicationMode == kLp) {
      return EstimateLpTimeout(m_hops, m_timeslotLength, m_hopsResponse);
    }
    // std
    return EstimateStdTimeout(m_hops, m_timeslotLength, m_hopsResponse);
  }

  // response
  if (direction == DpaMessage::kResponse) {
    // lp
    if (m_currentCommunicationMode == kLp) {
      return EstimateLpTimeout(m_hops, m_timeslotLength, m_hopsResponse,
        receivedMessage.GetLength() - (sizeof(TDpaIFaceHeader) + 2));
    }
    // std
    return EstimateStdTimeout(m_hops, m_timeslotLength, m_hopsResponse,
      receivedMessage.GetLength() - (sizeof(TDpaIFaceHeader) + 2));
  }
}

int32_t DpaTransfer::EstimateStdTimeout(uint8_t hopsRequest, uint8_t timeslotReq, uint8_t hopsResponse, int8_t responseDataLength)
{
  TRC_ENTER("");
  int32_t responseTimeSlotLengthMs;

  auto estimatedTimeoutMs = (hopsRequest + 1) * timeslotReq * 10;

  // estimation from confirmation
  if (responseDataLength == -1) {
    if (timeslotReq == 20) {
      responseTimeSlotLengthMs = 200;
    }
    else {
      // worst case
      responseTimeSlotLengthMs = 60;
    }
  }
  // correction of the estimation from response
  else {
    TRC_DBG("PData length of the received response: " << PAR((int)responseDataLength));
    if (responseDataLength >= 0 && responseDataLength < 16)
    {
      responseTimeSlotLengthMs = 40;
    }
    else if (responseDataLength >= 16 && responseDataLength <= 39)
    {
      responseTimeSlotLengthMs = 50;
    }
    else if (responseDataLength > 39)
    {
      responseTimeSlotLengthMs = 60;
    }
    TRC_DBG("Correction of the response timeout: " << PAR(responseTimeSlotLengthMs));
  }

  estimatedTimeoutMs += (hopsResponse + 1) * responseTimeSlotLengthMs + m_safetyTimeoutMs;

  TRC_DBG("Estimated STD timeout: " << PAR(estimatedTimeoutMs));
  TRC_LEAVE("");
  return estimatedTimeoutMs;
}

int32_t DpaTransfer::EstimateLpTimeout(uint8_t hopsRequest, uint8_t timeslotReq, uint8_t hopsResponse, int8_t responseDataLength)
{
  TRC_ENTER("");
  int32_t responseTimeSlotLengthMs;

  auto estimatedTimeoutMs = (hopsRequest + 1) * timeslotReq * 10;

  // estimation from confirmation
  if (responseDataLength == -1) {
    if (timeslotReq == 20) {
      responseTimeSlotLengthMs = 200;
    }
    else {
      // worst case
      responseTimeSlotLengthMs = 110;
    }
  }
  // correction of the estimation from response
  else {
    TRC_DBG("PData length of the received response: " << PAR((int)responseDataLength));
    if (responseDataLength >= 0 && responseDataLength < 11)
    {
      responseTimeSlotLengthMs = 80;
    }
    else if (responseDataLength >= 11 && responseDataLength <= 33)
    {
      responseTimeSlotLengthMs = 90;
    }
    else if (responseDataLength >= 34 && responseDataLength <= 56)
    {
      responseTimeSlotLengthMs = 100;
    }
    else if (responseDataLength > 56)
    {
      responseTimeSlotLengthMs = 110;
    }
    TRC_DBG("Correction of the response timeout: " << PAR(responseTimeSlotLengthMs));
  }

  estimatedTimeoutMs += (hopsResponse + 1) * responseTimeSlotLengthMs + m_safetyTimeoutMs;

  TRC_DBG("Estimated LP timeout: " << PAR(estimatedTimeoutMs));
  TRC_LEAVE("");
  return estimatedTimeoutMs;
}

void DpaTransfer::SetTimingForCurrentTransfer(int32_t estimatedTimeMs)
{
  TRC_ENTER("");

  // waiting forever
  if (m_timeoutMs == 0) {
    m_expectedDurationMs = m_timeoutMs;
    TRC_DBG("Expected duration to wait :" << PAR(m_expectedDurationMs));
    return;
  }

  // adjust time to wait before allowing next request to go the iqrf network
  if (m_status == kReceivedResponse) {
    //adjust new timing based on length of PData in response
    m_expectedDurationMs = estimatedTimeMs;
    TRC_DBG("New expected duration to wait :" << PAR(m_expectedDurationMs));
    return;
  }

  // estimation done
  if (estimatedTimeMs >= 0) {
    // either default timeout is 400 or user sets lower time than estimated
    if (m_timeoutMs < estimatedTimeMs) {
      // in both cases use estimation from confirmation
      m_timeoutMs = estimatedTimeMs;
    }
    // set new duration
    // there is also case when user sets higher than estimation then user choice is set
    m_expectedDurationMs = m_timeoutMs;
    TRC_DBG("Expected duration to wait :" << PAR(m_expectedDurationMs));
  }

  // start time when dpa request is sent and rerun again when confirmation is received
  m_startTime = std::chrono::system_clock::now();
  TRC_INF("Transfer status: started");

  TRC_LEAVE("");
}

DpaTransfer::DpaTransferStatus DpaTransfer::ProcessStatus() {
  std::lock_guard<std::mutex> lck(m_statusMutex);

  // changes m_status, does not care about remains
  // todo: refactor and rename - two functions
  CheckTimeout();
  return m_status;
}

int32_t DpaTransfer::CheckTimeout()
{
  int32_t remains(0);

  if (m_status == kCreated) {
    TRC_INF("Transfer status: created");
    return remains;
  }

  if (m_status == kAborted) {
    TRC_INF("Transfer status: aborted");
    return remains;
  }

  bool timingFinished(false);

  // infinite (0) is out of this statement
  if (m_expectedDurationMs > 0) {
    // passed time from sent request
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - m_startTime);
    remains = m_expectedDurationMs - duration.count();
    TRC_DBG("Time to wait: " << PAR(remains));

    // already over?
    timingFinished = remains < 0;
  }

  // not yet set and yes time is over
  // processed or timeouted can be set only after finished timing
  if (m_status != kProcessed && m_status != kTimeout) {
    if (timingFinished) {
      // and we have received confirmation for broadcast or response
      if (m_status == kConfirmationBroadcast || m_status == kReceivedResponse) {
        SetStatus(kProcessed);
        TRC_INF("Transfer status: processed");
      }
      else {
        SetStatus(kTimeout);
        TRC_INF("Transfer status: timeout");
      }
    }
  }

  // time to wait
  return remains;
}

bool DpaTransfer::IsInProgress() {
  return IsInProgressStatus(ProcessStatus());
}

bool DpaTransfer::IsInProgress(int32_t& expectedDuration) {
  std::lock_guard<std::mutex> lck(m_statusMutex);

  expectedDuration = CheckTimeout();
  return IsInProgressStatus(m_status);
}

bool DpaTransfer::IsInProgressStatus(DpaTransferStatus status)
{
  switch (status)
  {
  case kSent:
  case kSentCoordinator:
  case kConfirmation:
  case kConfirmationBroadcast:
  case kReceivedResponse:
    return true;
  // kCreated, kProcessed, kTimeout, kAbort, kError
  default:
    return false;
  }
}

void DpaTransfer::Abort() {
  std::lock_guard<std::mutex> lck(m_statusMutex);

  m_status = kAborted;
}

void DpaTransfer::SetStatus(DpaTransfer::DpaTransferStatus status)
{
  m_status = status;
}
<commit_msg>Adding more traces around CheckTimeout()<commit_after>/**
 * Copyright 2015-2017 MICRORISC s.r.o.
 * Copyright 2017 IQRF Tech s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "DpaTransfer.h"
#include "DpaTransaction.h"

#include "unexpected_packet_type.h"
#include "unexpected_command.h"
#include "unexpected_peripheral.h"

#include "IqrfLogging.h"

DpaTransfer::DpaTransfer()
  : m_status(kCreated), m_sentMessage(nullptr), m_responseMessage(nullptr),
  m_expectedDurationMs(400), m_timeoutMs(400), m_currentCommunicationMode(kStd), m_dpaTransaction(nullptr)
{
}

DpaTransfer::DpaTransfer(DpaTransaction* dpaTransaction, IqrfRfCommunicationMode comMode)
  : m_status(kCreated), m_sentMessage(nullptr), m_responseMessage(nullptr),
  m_expectedDurationMs(400), m_timeoutMs(400), m_currentCommunicationMode(comMode), m_dpaTransaction(dpaTransaction)
{
}

DpaTransfer::~DpaTransfer()
{
  delete m_sentMessage;
  delete m_responseMessage;
}

void DpaTransfer::ProcessSentMessage(const DpaMessage& sentMessage)
{
  TRC_ENTER("");

  if (m_status != kCreated)
  {
    throw std::logic_error("Sent message already set.");
  }

  // current request status is set as sent
  if (sentMessage.NodeAddress() == COORDINATOR_ADDRESS) {
    SetStatus(kSentCoordinator);
  }
  else {
    SetStatus(kSent);
  }

  // message itself is destroyed after being sent
  delete m_sentMessage;
  // creating object to hold new request
  m_sentMessage = new DpaMessage(sentMessage);

  // setting default timeout, no estimation yet
  SetTimingForCurrentTransfer();

  TRC_LEAVE("");
}

void DpaTransfer::ProcessReceivedMessage(const DpaMessage& receivedMessage)
{
  TRC_ENTER("");

  if (receivedMessage.MessageDirection() != DpaMessage::kResponse
    && receivedMessage.MessageDirection() != DpaMessage::kConfirmation)
    throw unexpected_packet_type("Response is expected.");

  std::lock_guard<std::mutex> lck(m_statusMutex);

  // checks
  if (!IsInProgressStatus(m_status)) {
    throw unexpected_packet_type("Request has not been sent, yet.");
  }

  if (receivedMessage.PeripheralType() != m_sentMessage->PeripheralType()) {
    throw unexpected_peripheral("Different peripheral type than in sent message.");
  }

  if ((receivedMessage.PeripheralCommand() & ~0x80) != m_sentMessage->PeripheralCommand()) {
    throw unexpected_command("Different peripheral command than in sent message.");
  }

  // direction
  auto messageDirection = receivedMessage.MessageDirection();
  if (messageDirection == DpaMessage::kConfirmation) {
    if (m_dpaTransaction) {
      m_dpaTransaction->processConfirmationMessage(receivedMessage);
    }

    ProcessConfirmationMessage(receivedMessage);
    TRC_INF("Confirmation processed.");
  }
  else {
    if (m_dpaTransaction) {
      m_dpaTransaction->processResponseMessage(receivedMessage);
    }

    ProcessResponseMessage(receivedMessage);
    TRC_INF("Response processed.");
  }
  TRC_LEAVE("");
}

void DpaTransfer::ProcessConfirmationMessage(const DpaMessage& confirmationMessage)
{
  if (confirmationMessage.NodeAddress() == DpaMessage::kBroadCastAddress) {
    m_status = kConfirmationBroadcast;
  }
  else {
    m_status = kConfirmation;
  }

  // setting timeout based on the confirmation
  SetTimingForCurrentTransfer(EstimatedTimeout(confirmationMessage));
}

void DpaTransfer::ProcessResponseMessage(const DpaMessage& responseMessage)
{
  // if there is a request to coordinator then after receiving response it is allowed to send another
  if (m_status == kSentCoordinator) {
    // done, next request gets ready
    m_status = kProcessed;
  }
  else {
    // only if there is not infinite timeout
    if (m_expectedDurationMs != 0) {
      m_status = kReceivedResponse;
      // adjust timing before allowing next request
      SetTimingForCurrentTransfer(EstimatedTimeout(responseMessage));
    }
    // infinite timeout
    else {
      // done, next request gets ready
      m_status = kProcessed;
    }
  }

  delete m_responseMessage;
  m_responseMessage = new DpaMessage(responseMessage);
}

int32_t DpaTransfer::EstimatedTimeout(const DpaMessage& receivedMessage)
{
  // direction
  auto direction = receivedMessage.MessageDirection();

  // double check
  if (direction != DpaMessage::kConfirmation && direction != DpaMessage::kResponse) {
    throw std::invalid_argument("Parameter is not a received message type.");
  }

  // confirmation
  if (direction == DpaMessage::kConfirmation) {
    auto iFace = receivedMessage.DpaPacket().DpaResponsePacket_t.DpaMessage.IFaceConfirmation;

    // save for later use with response
    m_hops = iFace.Hops;
    m_timeslotLength = iFace.TimeSlotLength;
    m_hopsResponse = iFace.HopsResponse;

    // lp
    if (m_currentCommunicationMode == kLp) {
      return EstimateLpTimeout(m_hops, m_timeslotLength, m_hopsResponse);
    }
    // std
    return EstimateStdTimeout(m_hops, m_timeslotLength, m_hopsResponse);
  }

  // response
  if (direction == DpaMessage::kResponse) {
    // lp
    if (m_currentCommunicationMode == kLp) {
      return EstimateLpTimeout(m_hops, m_timeslotLength, m_hopsResponse,
        receivedMessage.GetLength() - (sizeof(TDpaIFaceHeader) + 2));
    }
    // std
    return EstimateStdTimeout(m_hops, m_timeslotLength, m_hopsResponse,
      receivedMessage.GetLength() - (sizeof(TDpaIFaceHeader) + 2));
  }
}

int32_t DpaTransfer::EstimateStdTimeout(uint8_t hopsRequest, uint8_t timeslotReq, uint8_t hopsResponse, int8_t responseDataLength)
{
  TRC_ENTER("");
  int32_t responseTimeSlotLengthMs;

  auto estimatedTimeoutMs = (hopsRequest + 1) * timeslotReq * 10;

  // estimation from confirmation
  if (responseDataLength == -1) {
    if (timeslotReq == 20) {
      responseTimeSlotLengthMs = 200;
    }
    else {
      // worst case
      responseTimeSlotLengthMs = 60;
    }
  }
  // correction of the estimation from response
  else {
    TRC_DBG("PData length of the received response: " << PAR((int)responseDataLength));
    if (responseDataLength >= 0 && responseDataLength < 16)
    {
      responseTimeSlotLengthMs = 40;
    }
    else if (responseDataLength >= 16 && responseDataLength <= 39)
    {
      responseTimeSlotLengthMs = 50;
    }
    else if (responseDataLength > 39)
    {
      responseTimeSlotLengthMs = 60;
    }
    TRC_DBG("Correction of the response timeout: " << PAR(responseTimeSlotLengthMs));
  }

  estimatedTimeoutMs += (hopsResponse + 1) * responseTimeSlotLengthMs + m_safetyTimeoutMs;

  TRC_DBG("Estimated STD timeout: " << PAR(estimatedTimeoutMs));
  TRC_LEAVE("");
  return estimatedTimeoutMs;
}

int32_t DpaTransfer::EstimateLpTimeout(uint8_t hopsRequest, uint8_t timeslotReq, uint8_t hopsResponse, int8_t responseDataLength)
{
  TRC_ENTER("");
  int32_t responseTimeSlotLengthMs;

  auto estimatedTimeoutMs = (hopsRequest + 1) * timeslotReq * 10;

  // estimation from confirmation
  if (responseDataLength == -1) {
    if (timeslotReq == 20) {
      responseTimeSlotLengthMs = 200;
    }
    else {
      // worst case
      responseTimeSlotLengthMs = 110;
    }
  }
  // correction of the estimation from response
  else {
    TRC_DBG("PData length of the received response: " << PAR((int)responseDataLength));
    if (responseDataLength >= 0 && responseDataLength < 11)
    {
      responseTimeSlotLengthMs = 80;
    }
    else if (responseDataLength >= 11 && responseDataLength <= 33)
    {
      responseTimeSlotLengthMs = 90;
    }
    else if (responseDataLength >= 34 && responseDataLength <= 56)
    {
      responseTimeSlotLengthMs = 100;
    }
    else if (responseDataLength > 56)
    {
      responseTimeSlotLengthMs = 110;
    }
    TRC_DBG("Correction of the response timeout: " << PAR(responseTimeSlotLengthMs));
  }

  estimatedTimeoutMs += (hopsResponse + 1) * responseTimeSlotLengthMs + m_safetyTimeoutMs;

  TRC_DBG("Estimated LP timeout: " << PAR(estimatedTimeoutMs));
  TRC_LEAVE("");
  return estimatedTimeoutMs;
}

void DpaTransfer::SetTimingForCurrentTransfer(int32_t estimatedTimeMs)
{
  TRC_ENTER("");

  // waiting forever
  if (m_timeoutMs == 0) {
    m_expectedDurationMs = m_timeoutMs;
    TRC_DBG("Expected duration to wait :" << PAR(m_expectedDurationMs));
    return;
  }

  // adjust time to wait before allowing next request to go the iqrf network
  if (m_status == kReceivedResponse) {
    //adjust new timing based on length of PData in response
    m_expectedDurationMs = estimatedTimeMs;
    TRC_DBG("New expected duration to wait :" << PAR(m_expectedDurationMs));
    return;
  }

  // estimation done
  if (estimatedTimeMs >= 0) {
    // either default timeout is 400 or user sets lower time than estimated
    if (m_timeoutMs < estimatedTimeMs) {
      // in both cases use estimation from confirmation
      m_timeoutMs = estimatedTimeMs;
    }
    // set new duration
    // there is also case when user sets higher than estimation then user choice is set
    m_expectedDurationMs = m_timeoutMs;
    TRC_DBG("Expected duration to wait :" << PAR(m_expectedDurationMs));
  }

  // start time when dpa request is sent and rerun again when confirmation is received
  m_startTime = std::chrono::system_clock::now();
  TRC_INF("Transfer status: started");

  TRC_LEAVE("");
}

DpaTransfer::DpaTransferStatus DpaTransfer::ProcessStatus() {
  TRC_ENTER("");
  std::lock_guard<std::mutex> lck(m_statusMutex);

  // changes m_status, does not care about remains
  // todo: refactor and rename - two functions
  CheckTimeout();

  TRC_LEAVE("");
  return m_status;
}

int32_t DpaTransfer::CheckTimeout()
{
  int32_t remains(0);

  if (m_status == kCreated) {
    TRC_INF("Transfer status: created");
    return remains;
  }

  if (m_status == kAborted) {
    TRC_INF("Transfer status: aborted");
    return remains;
  }

  bool timingFinished(false);

  // infinite (0) is out of this statement
  if (m_expectedDurationMs > 0) {
    // passed time from sent request
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - m_startTime);
    remains = m_expectedDurationMs - duration.count();
    TRC_DBG("Time to wait: " << PAR(remains));

    // already over?
    timingFinished = remains < 0;
  }

  // not yet set and yes time is over
  // processed or timeouted can be set only after finished timing
  if (m_status != kProcessed && m_status != kTimeout) {
    if (timingFinished) {
      // and we have received confirmation for broadcast or response
      if (m_status == kConfirmationBroadcast || m_status == kReceivedResponse) {
        SetStatus(kProcessed);
        TRC_INF("Transfer status: processed");
      }
      else {
        SetStatus(kTimeout);
        TRC_INF("Transfer status: timeout");
      }
    }
  }

  // time to wait
  return remains;
}

bool DpaTransfer::IsInProgress() {
  return IsInProgressStatus(ProcessStatus());
}

bool DpaTransfer::IsInProgress(int32_t& expectedDuration) {
  TRC_ENTER("");
  std::lock_guard<std::mutex> lck(m_statusMutex);

  expectedDuration = CheckTimeout();
  return IsInProgressStatus(m_status);
  TRC_LEAVE("");
}

bool DpaTransfer::IsInProgressStatus(DpaTransferStatus status)
{
  switch (status)
  {
  case kSent:
  case kSentCoordinator:
  case kConfirmation:
  case kConfirmationBroadcast:
  case kReceivedResponse:
    return true;
  // kCreated, kProcessed, kTimeout, kAbort, kError
  default:
    return false;
  }
}

void DpaTransfer::Abort() {
  std::lock_guard<std::mutex> lck(m_statusMutex);

  m_status = kAborted;
}

void DpaTransfer::SetStatus(DpaTransfer::DpaTransferStatus status)
{
  m_status = status;
}
<|endoftext|>


<commit_before>#include "sample_protocol.h"
#include "snapl/dispatcher.h"
#include "snapl/net/inbox.h"
#include "snapl/net/outbox.h"
#include "connection_acceptor.h"

int main( int argc, char **argv )
{
	short port( 9000 );

	sample_protocol_c sample_protocol( port );

	queue_c< server_message_c > request_queue;
	queue_c< server_message_c > response_queue;
	queue_c< server_message_c > complete_queue;

	connection_acceptor_c acceptor;
	inbox_c inbox( acceptor, request_queue, complete_queue );
	dispatcher_c dispatch( request_queue, response_queue );
	outbox_c outbox( response_queue, complete_queue );

	dispatch.add( sample_protocol );

	for (;;) {
		inbox.iterate();
		dispatch.iterate();
		outbox.iterate();
	}

	return 0;
}

<commit_msg>set the sample app to listen on the given port<commit_after>#include "sample_protocol.h"
#include "snapl/dispatcher.h"
#include "snapl/net/inbox.h"
#include "snapl/net/outbox.h"
#include "connection_acceptor.h"

int main( int argc, char **argv )
{
	short port( 9000 );

	sample_protocol_c sample_protocol( port );

	queue_c< server_message_c > request_queue;
	queue_c< server_message_c > response_queue;
	queue_c< server_message_c > complete_queue;

	connection_acceptor_c acceptor;
	inbox_c inbox( acceptor, request_queue, complete_queue );
	dispatcher_c dispatch( request_queue, response_queue );
	outbox_c outbox( response_queue, complete_queue );

	inbox.listen( port );

	dispatch.add( sample_protocol );

	for (;;) {
		inbox.iterate();
		dispatch.iterate();
		outbox.iterate();
	}

	return 0;
}

<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  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. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.6  2000/02/06 07:47:33  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.5  2000/02/04 01:49:26  aruna1
 * TreeWalker and NodeIterator changes
 *
 * Revision 1.4  1999/11/30 21:16:25  roddey
 * Changes to add the transcode() method to DOMString, which returns a transcoded
 * version (to local code page) of the DOM string contents. And I changed all of the
 * exception 'throw by pointer' to 'throw by value' style.
 *
 * Revision 1.3  1999/11/23 01:48:16  rahulj
 * Changed 0L to 0. CC under HPUX is happy now.
 *
 * Revision 1.2  1999/11/20 00:56:39  rahulj
 * Source files must end with an un-escaped newline.
 *
 * Revision 1.1.1.1  1999/11/09 01:09:15  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:44:30  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// NodeIteratorImpl.cpp: implementation of the NodeIteratorImpl class.
//
//////////////////////////////////////////////////////////////////////

#include "NodeIteratorImpl.hpp"
#include "DOM_Document.hpp"
#include "DOM_DOMException.hpp"
#include "DocumentImpl.hpp"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

NodeIteratorImpl::NodeIteratorImpl ()
: fDetached(false),
    fNodeFilter(0)
{
}

NodeIteratorImpl::~NodeIteratorImpl ()
{
	fDetached = false;
}

void NodeIteratorImpl::detach ()
{
	fDetached = true;
}

NodeIteratorImpl::NodeIteratorImpl (
                                    DOM_Node root,
                                    unsigned long whatToShow,
                                    DOM_NodeFilter* nodeFilter,
                                    bool expandEntityRef)
:   fDetached(false),
    fRoot(root),
    fCurrentNode(0),
    fWhatToShow(whatToShow),
    fNodeFilter(nodeFilter),
    fForward(true),
    fExpandEntityReferences(expandEntityRef)
{

}

NodeIteratorImpl::NodeIteratorImpl ( const NodeIteratorImpl& toCopy)
    :   fDetached(toCopy.fDetached),
    fRoot(toCopy.fRoot),
    fCurrentNode(toCopy.fCurrentNode),
    fWhatToShow(toCopy.fWhatToShow),
    fNodeFilter(toCopy.fNodeFilter),
    fForward(toCopy.fForward),
    fExpandEntityReferences(toCopy.fExpandEntityReferences)
{
}

NodeIteratorImpl& NodeIteratorImpl::operator= (const NodeIteratorImpl& other) {
    fRoot                   = other.fRoot;
    fCurrentNode            = other.fRoot;
    fWhatToShow             = other.fWhatToShow;
    fNodeFilter             = other.fNodeFilter;
    fForward                = other.fForward;
	fDetached               = other.fDetached;
    fExpandEntityReferences = other.fExpandEntityReferences;
    return *this;
}

// Implementation Note: Note that the iterator looks at whatToShow
// and filter values at each call, and therefore one _could_ add
// setters for these values and alter them while iterating!

/** Return the whatToShow value */

unsigned long NodeIteratorImpl::getWhatToShow () {
    return fWhatToShow;
}

/** Return the filter */

DOM_NodeFilter* NodeIteratorImpl::getFilter () {
    return fNodeFilter;
}

/** Get the expandEntity reference flag. */
bool NodeIteratorImpl::getExpandEntityReferences()
{
    return fExpandEntityReferences;
}

/** Return the next DOM_Node in the Iterator. The node is the next node in
 *  depth-first order which also passes the filter, and whatToShow.
 *  A null return means either that
 */

DOM_Node NodeIteratorImpl::nextNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if root is null there is no next node.
    if (fRoot.isNull())
			return result;

    DOM_Node aNextNode = fCurrentNode;
    bool accepted = false; // the next node has not been accepted.

    while (!accepted) {

        // if last direction is not forward, repeat node.
        if (!fForward && !aNextNode.isNull()) {
            //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
            aNextNode = fCurrentNode;
        } else {
        // else get the next node via depth-first
            aNextNode = nextNode(aNextNode, true);
        }

        fForward = true; //REVIST: should direction be set forward before null check?

        // nothing in the list. return null.
        if (aNextNode.isNull())
					return result;

        // does node pass the filters and whatToShow?
        accepted = acceptNode(aNextNode);
        if (accepted) {
            // if so, then the node is the current node.
            fCurrentNode = aNextNode;
            return fCurrentNode;
				}

    }

    // no nodes, or no accepted nodes.
    return result;
}

/** Return the previous Node in the Iterator. The node is the next node in
 *  _backwards_ depth-first order which also passes the filter, and whatToShow.
 */

DOM_Node NodeIteratorImpl::previousNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if the root is null, or the current node is null, return null.
    if (fRoot.isNull() || fCurrentNode.isNull())
			return result;

    DOM_Node aPreviousNode = fCurrentNode;
    bool accepted = false;

    while (!accepted) {

        if (fForward && ! aPreviousNode.isNull()) {
            //repeat last node.
            aPreviousNode = fCurrentNode;
        } else {
            // get previous node in backwards depth first order.
            aPreviousNode = previousNode(aPreviousNode);
        }

        // we are going backwards
        fForward = false;

        // if the new previous node is null, we're at head or past the root,
        // so return null.
        if (aPreviousNode.isNull())
					return result;

        // check if node passes filters and whatToShow.
        accepted = acceptNode(aPreviousNode);
        if (accepted) {
            // if accepted, update the current node, and return it.
            fCurrentNode = aPreviousNode;
            return fCurrentNode;
        }
    }
    // there are no nodes?
    return result;
}

/** The node is accepted if it passes the whatToShow and the filter. */
bool NodeIteratorImpl::acceptNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (fNodeFilter == 0) {
        return ((fWhatToShow & ((1 << node.getNodeType()) - 1)) != 0);
    } else {
        return ((fWhatToShow & ((1 << node.getNodeType()) - 1)) != 0 )
            && fNodeFilter->acceptNode(node) == DOM_NodeFilter::FILTER_ACCEPT;
    }
}

/** Return node, if matches or any parent if matches. */
DOM_Node NodeIteratorImpl::matchNodeOrParent (DOM_Node node) {
		DOM_Node result;

    for (DOM_Node n = node; n != fRoot; n = n.getParentNode()) {
        if (node == n) return n;
    }

    return result;
}

/** The method nextNode(DOM_Node, bool) returns the next node
 *  from the actual DOM tree.
 *
 *  The bool visitChildren determines whether to visit the children.
 *  The result is the nextNode.
 */

DOM_Node NodeIteratorImpl::nextNode (DOM_Node node, bool visitChildren) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (node.isNull()) return fRoot;

    DOM_Node result;
    // only check children if we visit children.
    if (visitChildren) {
        //if hasChildren, return 1st child.
        if (node.hasChildNodes()) {
            result = node.getFirstChild();
            return result;
        }
    }

    // if hasSibling, return sibling
    result = node.getNextSibling();
    if (! result.isNull()) return result;

    // return parent's 1st sibling.
    DOM_Node parent = node.getParentNode();
    while (!parent.isNull() && parent != fRoot) {
        result = parent.getNextSibling();
        if (!result.isNull()) {
            return result;
        } else {
            parent = parent.getParentNode();
        }

    } // while (parent != null && parent != fRoot) {

    // end of list, return null
		DOM_Node aNull;
    return aNull;
}

/** The method previousNode(DOM_Node) returns the previous node
 *  from the actual DOM tree.
 */

DOM_Node NodeIteratorImpl::previousNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    DOM_Node result;

    // if we're at the root, return null.
    if (node == fRoot)
			return result;

    // get sibling
    result = node.getPreviousSibling();
    if (result.isNull()) {
        //if 1st sibling, return parent
        result = node.getParentNode();
        return result;
    }

    // if sibling has children, keep getting last child of child.
    if (result.hasChildNodes()) {
        while (result.hasChildNodes()) {
            result = result.getLastChild();
        }
    }

    return result;
}

/** Fix-up the iterator on a remove. Called by DOM or otherwise,
 *  before an actual DOM remove.
 */

void NodeIteratorImpl::removeNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    // Implementation note: Fix-up means setting the current node properly
    // after a remove.

    if (node.isNull())
				return;

    DOM_Node deleted = matchNodeOrParent(node);

    if (deleted.isNull()) return;

    if (fForward) {
        fCurrentNode = previousNode(deleted);
    } else
    // if (!fForward)
    {
        DOM_Node next = nextNode(deleted, false);
        if (! next.isNull()) {
            // normal case: there _are_ nodes following this in the iterator.
            fCurrentNode = next;
        } else {
            // the last node in the iterator is to be removed,
            // so we set the current node to be the previous one.
            fCurrentNode = previousNode(deleted);
            fForward = true;
        }

    }

}

void NodeIteratorImpl::unreferenced()
{
    DOM_Document doc = fRoot.getOwnerDocument();
    DocumentImpl* impl;

    if (! doc.isNull()) {
        impl = (DocumentImpl *) doc.fImpl;
    }
    else
        impl = (DocumentImpl *) fRoot.fImpl;

    if (impl->iterators != 0L) {
        int i;
        int sz = impl->iterators->size();
        for (i = 0; i < sz; i++)
            if (impl->iterators->elementAt(i) == this) {
                impl->iterators->removeElementAt(i);
                break;
            }
    }

    delete this;
}
<commit_msg>nodeIterator previous tracking problem solved<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  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. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.7  2000/02/08 01:16:18  aruna1
 * nodeIterator previous tracking problem solved
 *
 * Revision 1.6  2000/02/06 07:47:33  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.5  2000/02/04 01:49:26  aruna1
 * TreeWalker and NodeIterator changes
 *
 * Revision 1.4  1999/11/30 21:16:25  roddey
 * Changes to add the transcode() method to DOMString, which returns a transcoded
 * version (to local code page) of the DOM string contents. And I changed all of the
 * exception 'throw by pointer' to 'throw by value' style.
 *
 * Revision 1.3  1999/11/23 01:48:16  rahulj
 * Changed 0L to 0. CC under HPUX is happy now.
 *
 * Revision 1.2  1999/11/20 00:56:39  rahulj
 * Source files must end with an un-escaped newline.
 *
 * Revision 1.1.1.1  1999/11/09 01:09:15  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:44:30  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// NodeIteratorImpl.cpp: implementation of the NodeIteratorImpl class.
//
//////////////////////////////////////////////////////////////////////

#include "NodeIteratorImpl.hpp"
#include "DOM_Document.hpp"
#include "DOM_DOMException.hpp"
#include "DocumentImpl.hpp"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

NodeIteratorImpl::NodeIteratorImpl ()
: fDetached(false),
    fNodeFilter(0)
{
}

NodeIteratorImpl::~NodeIteratorImpl ()
{
	fDetached = false;
}

void NodeIteratorImpl::detach ()
{
	fDetached = true;
}

NodeIteratorImpl::NodeIteratorImpl (
                                    DOM_Node root,
                                    unsigned long whatToShow,
                                    DOM_NodeFilter* nodeFilter,
                                    bool expandEntityRef)
:   fDetached(false),
    fRoot(root),
    fCurrentNode(0),
    fWhatToShow(whatToShow),
    fNodeFilter(nodeFilter),
    fForward(true),
    fExpandEntityReferences(expandEntityRef)
{

}

NodeIteratorImpl::NodeIteratorImpl ( const NodeIteratorImpl& toCopy)
    :   fDetached(toCopy.fDetached),
    fRoot(toCopy.fRoot),
    fCurrentNode(toCopy.fCurrentNode),
    fWhatToShow(toCopy.fWhatToShow),
    fNodeFilter(toCopy.fNodeFilter),
    fForward(toCopy.fForward),
    fExpandEntityReferences(toCopy.fExpandEntityReferences)
{
}

NodeIteratorImpl& NodeIteratorImpl::operator= (const NodeIteratorImpl& other) {
    fRoot                   = other.fRoot;
    fCurrentNode            = other.fRoot;
    fWhatToShow             = other.fWhatToShow;
    fNodeFilter             = other.fNodeFilter;
    fForward                = other.fForward;
	fDetached               = other.fDetached;
    fExpandEntityReferences = other.fExpandEntityReferences;
    return *this;
}

// Implementation Note: Note that the iterator looks at whatToShow
// and filter values at each call, and therefore one _could_ add
// setters for these values and alter them while iterating!

/** Return the whatToShow value */

unsigned long NodeIteratorImpl::getWhatToShow () {
    return fWhatToShow;
}

/** Return the filter */

DOM_NodeFilter* NodeIteratorImpl::getFilter () {
    return fNodeFilter;
}

/** Get the expandEntity reference flag. */
bool NodeIteratorImpl::getExpandEntityReferences()
{
    return fExpandEntityReferences;
}

/** Return the next DOM_Node in the Iterator. The node is the next node in
 *  depth-first order which also passes the filter, and whatToShow.
 *  A null return means either that
 */

DOM_Node NodeIteratorImpl::nextNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if root is null there is no next node.
    if (fRoot.isNull())
			return result;

    DOM_Node aNextNode = fCurrentNode;
    bool accepted = false; // the next node has not been accepted.

    while (!accepted) {

        // if last direction is not forward, repeat node.
        if (!fForward && !aNextNode.isNull()) {
            //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
            aNextNode = fCurrentNode;
        } else {
        // else get the next node via depth-first
            aNextNode = nextNode(aNextNode, true);
        }

        fForward = true; //REVIST: should direction be set forward before null check?

        // nothing in the list. return null.
        if (aNextNode.isNull())
					return result;

        // does node pass the filters and whatToShow?
        accepted = acceptNode(aNextNode);
        if (accepted) {
            // if so, then the node is the current node.
            fCurrentNode = aNextNode;
            return fCurrentNode;
				}

    }

    // no nodes, or no accepted nodes.
    return result;
}

/** Return the previous Node in the Iterator. The node is the next node in
 *  _backwards_ depth-first order which also passes the filter, and whatToShow.
 */

DOM_Node NodeIteratorImpl::previousNode () {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

	DOM_Node result;

    // if the root is null, or the current node is null, return null.
    if (fRoot.isNull() || fCurrentNode.isNull())
			return result;

    DOM_Node aPreviousNode = fCurrentNode;
    bool accepted = false;

    while (!accepted) {
        // we are going backwards
        fForward = false;

        if (fForward && ! aPreviousNode.isNull()) {
            //repeat last node.
            aPreviousNode = fCurrentNode;
        } else {
            // get previous node in backwards depth first order.
            aPreviousNode = previousNode(aPreviousNode);
        }

        // if the new previous node is null, we're at head or past the root,
        // so return null.
        if (aPreviousNode.isNull())
					return result;

        // check if node passes filters and whatToShow.
        accepted = acceptNode(aPreviousNode);
        if (accepted) {
            // if accepted, update the current node, and return it.
            fCurrentNode = aPreviousNode;
            return fCurrentNode;
        }
    }
    // there are no nodes?
    return result;
}

/** The node is accepted if it passes the whatToShow and the filter. */
bool NodeIteratorImpl::acceptNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (fNodeFilter == 0) {
        return ((fWhatToShow & ((1 << node.getNodeType()) - 1)) != 0);
    } else {
        return ((fWhatToShow & ((1 << node.getNodeType()) - 1)) != 0 )
            && fNodeFilter->acceptNode(node) == DOM_NodeFilter::FILTER_ACCEPT;
    }
}

/** Return node, if matches or any parent if matches. */
DOM_Node NodeIteratorImpl::matchNodeOrParent (DOM_Node node) {
		DOM_Node result;

    for (DOM_Node n = node; n != fRoot; n = n.getParentNode()) {
        if (node == n) return n;
    }

    return result;
}

/** The method nextNode(DOM_Node, bool) returns the next node
 *  from the actual DOM tree.
 *
 *  The bool visitChildren determines whether to visit the children.
 *  The result is the nextNode.
 */

DOM_Node NodeIteratorImpl::nextNode (DOM_Node node, bool visitChildren) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    if (node.isNull()) return fRoot;

    DOM_Node result;
    // only check children if we visit children.
    if (visitChildren) {
        //if hasChildren, return 1st child.
        if (node.hasChildNodes()) {
            result = node.getFirstChild();
            return result;
        }
    }

    // if hasSibling, return sibling
    result = node.getNextSibling();
    if (! result.isNull()) return result;

    // return parent's 1st sibling.
    DOM_Node parent = node.getParentNode();
    while (!parent.isNull() && parent != fRoot) {
        result = parent.getNextSibling();
        if (!result.isNull()) {
            return result;
        } else {
            parent = parent.getParentNode();
        }

    } // while (parent != null && parent != fRoot) {

    // end of list, return null
		DOM_Node aNull;
    return aNull;
}

/** The method previousNode(DOM_Node) returns the previous node
 *  from the actual DOM tree.
 */

DOM_Node NodeIteratorImpl::previousNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    DOM_Node result;

    // if we're at the root, return null.
    if (node == fRoot)
			return result;

    // get sibling
    result = node.getPreviousSibling();
    if (result.isNull()) {
        //if 1st sibling, return parent
        result = node.getParentNode();
        return result;
    }

    // if sibling has children, keep getting last child of child.
    if (result.hasChildNodes()) {
        while (result.hasChildNodes()) {
            result = result.getLastChild();
        }
    }

    return result;
}

/** Fix-up the iterator on a remove. Called by DOM or otherwise,
 *  before an actual DOM remove.
 */

void NodeIteratorImpl::removeNode (DOM_Node node) {
	if (fDetached)
		throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);

    // Implementation note: Fix-up means setting the current node properly
    // after a remove.

    if (node.isNull())
				return;

    DOM_Node deleted = matchNodeOrParent(node);

    if (deleted.isNull()) return;

    if (fForward) {
        fCurrentNode = previousNode(deleted);
    } else
    // if (!fForward)
    {
        DOM_Node next = nextNode(deleted, false);
        if (! next.isNull()) {
            // normal case: there _are_ nodes following this in the iterator.
            fCurrentNode = next;
        } else {
            // the last node in the iterator is to be removed,
            // so we set the current node to be the previous one.
            fCurrentNode = previousNode(deleted);
            fForward = true;
        }

    }

}

void NodeIteratorImpl::unreferenced()
{
    DOM_Document doc = fRoot.getOwnerDocument();
    DocumentImpl* impl;

    if (! doc.isNull()) {
        impl = (DocumentImpl *) doc.fImpl;
    }
    else
        impl = (DocumentImpl *) fRoot.fImpl;

    if (impl->iterators != 0L) {
        int i;
        int sz = impl->iterators->size();
        for (i = 0; i < sz; i++)
            if (impl->iterators->elementAt(i) == this) {
                impl->iterators->removeElementAt(i);
                break;
            }
    }

    delete this;
}
<|endoftext|>


<commit_before>#include "sslpkix/iosink.h"

namespace sslpkix {

IoSink& operator<<(IoSink& sink, const std::string& str) {
	const size_t total_size = str.length();
	const char *buf = str.data();
	const char *current = buf;
	size_t written_size = 0;
	int ret = 0;

	do {
		ret = BIO_write(sink.handle(), current, total_size - written_size);
		if (ret > 0) {
			current += ret;
			written_size += static_cast<size_t>(ret);
		}
	} while (ret > 0 && written_size < total_size);

	if (ret == 0 || ret == -1)
		throw std::ios_base::failure("BIO_write failed");
	else if (ret == -2)
		throw std::ios_base::failure("BIO_write is not implemented for this BIO");

	// TODO: Need to check result? 1=success, 0 or -1=failure
	ret = BIO_flush(sink.handle());

	return sink;
}

IoSink& operator>>(IoSink& sink, std::string& str) {
	char buf[1024];
	int ret = 0;

	do {
		ret = BIO_read(sink.handle(), buf, sizeof(buf));
		if (ret > 0)
			str.append(buf, ret);
	} while (ret > 0);

	if (ret == -1)
		throw std::ios_base::failure("BIO_read failed");
	else if (ret == -2)
		throw std::ios_base::failure("BIO_read is not implemented for this BIO");

	return sink;
}

std::ostream& operator<<(std::ostream& stream, IoSink& sink) {
	char buf[1024];
	int ret = 0;

	do {
		ret = BIO_read(sink.handle(), buf, sizeof(buf)-1);
		if (ret > 0) {
			buf[ret] = '\0';
			stream << buf;
		}
	} while (ret > 0);

	if (ret == -1)
		; // EOF?
	else if (ret == -2)
		throw std::ios_base::failure("BIO_read is not implemented for this BIO");

	return stream;
}

std::istream& operator>>(std::istream& stream, IoSink& sink) {
	char buf[1024];
	int ret = 0;

	while (!stream.eof()) {
		stream.read(buf, sizeof(buf));
		ret = BIO_write(sink.handle(), buf, stream.gcount());
		// BIO_write must succeed writing the exact amount of bytes we pass to it.
		if (ret == 0 || ret == -1)
			throw std::ios_base::failure("BIO_write failed");
		else if (ret == -2)
			throw std::ios_base::failure("BIO_write is not implemented for this BIO");
	}

	// TODO: Need to check result? 1=success, 0 or -1=failure
	ret = BIO_flush(sink.handle());

	return stream;
}

} // namespace sslpkix
<commit_msg>BIO_read: A return of -1 is not necessarily an indication of error.<commit_after>#include "sslpkix/iosink.h"

namespace sslpkix {

IoSink& operator<<(IoSink& sink, const std::string& str) {
	const size_t total_size = str.length();
	const char *buf = str.data();
	const char *current = buf;
	size_t written_size = 0;
	int ret = 0;

	do {
		ret = BIO_write(sink.handle(), current, total_size - written_size);
		if (ret > 0) {
			current += ret;
			written_size += static_cast<size_t>(ret);
		}
	} while (ret > 0 && written_size < total_size);

	if (ret == 0 || ret == -1)
		throw std::ios_base::failure("BIO_write failed");
	else if (ret == -2)
		throw std::ios_base::failure("BIO_write is not implemented for this BIO");

	// TODO: Need to check result? 1=success, 0 or -1=failure
	ret = BIO_flush(sink.handle());

	return sink;
}

IoSink& operator>>(IoSink& sink, std::string& str) {
	char buf[1024];
	int ret = 0;

	do {
		ret = BIO_read(sink.handle(), buf, sizeof(buf));
		if (ret > 0)
			str.append(buf, ret);
	} while (ret > 0);

	// man BIO_read - http://www.manpagez.com/man/3/BIO_read/
	// NOTES
	// 		A 0 or -1 return is not necessarily an indication of an error. In
	//		particular when the source/sink is non-blocking or of a certain type it
	// 		may merely be an indication that no data is currently available and
	// 		that the application should retry the operation later.

	if (ret == -1)
		; // EOF?
	else if (ret == -2)
		throw std::ios_base::failure("BIO_read is not implemented for this BIO");

	return sink;
}

std::ostream& operator<<(std::ostream& stream, IoSink& sink) {
	char buf[1024];
	int ret = 0;

	do {
		ret = BIO_read(sink.handle(), buf, sizeof(buf)-1);
		if (ret > 0) {
			buf[ret] = '\0';
			stream << buf;
		}
	} while (ret > 0);

	if (ret == -1)
		; // EOF?
	else if (ret == -2)
		throw std::ios_base::failure("BIO_read is not implemented for this BIO");

	return stream;
}

std::istream& operator>>(std::istream& stream, IoSink& sink) {
	char buf[1024];
	int ret = 0;

	while (!stream.eof()) {
		stream.read(buf, sizeof(buf));
		ret = BIO_write(sink.handle(), buf, stream.gcount());
		// BIO_write must succeed writing the exact amount of bytes we pass to it.
		if (ret == 0 || ret == -1)
			throw std::ios_base::failure("BIO_write failed");
		else if (ret == -2)
			throw std::ios_base::failure("BIO_write is not implemented for this BIO");
	}

	// TODO: Need to check result? 1=success, 0 or -1=failure
	ret = BIO_flush(sink.handle());

	return stream;
}

} // namespace sslpkix
<|endoftext|>


<commit_before><commit_msg>missing pointer check in new multiline input code, fdo#43856<commit_after><|endoftext|>