<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2011, 2012, 2013, 2014
Raffaello D. Di Napoli

This file is part of Application-Building Components (henceforth referred to as ABC).

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

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

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

#include <abc/testing/test_case.hxx>
#include <abc/trace.hxx>
#include <algorithm>
#include <abc/testing/utility.hxx>

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::test::vector_basic

namespace abc {

namespace test {

class vector_basic :
   public testing::test_case {
public:

   /** See testing::test_case::title().
   */
   virtual istr title() {
      return istr(SL("abc::*vector classes - basic operations"));
   }

   /** See testing::test_case::run().
   */
   virtual void run() {
      ABC_TRACE_FN((this));

      dmvector<int> v;

      ABC_TESTING_ASSERT_EQUAL(v.size(), 0u);

      v.append(1);
      ABC_TESTING_ASSERT_EQUAL(v.size(), 1u);
      ABC_TESTING_ASSERT_EQUAL(v[0], 1);

      v = v + v;
      ABC_TESTING_ASSERT_EQUAL(v.size(), 2u);
      ABC_TESTING_ASSERT_EQUAL(v[0], 1);
      ABC_TESTING_ASSERT_EQUAL(v[1], 1);

      v.insert(1, 2);
      ABC_TESTING_ASSERT_EQUAL(v.size(), 3u);
      ABC_TESTING_ASSERT_EQUAL(v[0], 1);
      ABC_TESTING_ASSERT_EQUAL(v[1], 2);
      ABC_TESTING_ASSERT_EQUAL(v[2], 1);

      v = v.slice(1, 3);
      ABC_TESTING_ASSERT_EQUAL(v.size(), 2u);
      ABC_TESTING_ASSERT_EQUAL(v[0], 2);
      ABC_TESTING_ASSERT_EQUAL(v[1], 1);

      v.append(3);
      ABC_TESTING_ASSERT_EQUAL(v.size(), 3u);
      ABC_TESTING_ASSERT_EQUAL(v[0], 2);
      ABC_TESTING_ASSERT_EQUAL(v[1], 1);
      ABC_TESTING_ASSERT_EQUAL(v[2], 3);

      ABC_TESTING_ASSERT_EQUAL(v.index_of(1), 1);

      ABC_TESTING_ASSERT_EQUAL(v.last_index_of(1), 1);

      ABC_TESTING_ASSERT_EQUAL(std::find(v.cbegin(), v.cend(), 1), v.cbegin() + 1);

      v.remove_at(std::find(v.cbegin(), v.cend(), 1));
      ABC_TESTING_ASSERT_EQUAL(v.size(), 2u);
      ABC_TESTING_ASSERT_EQUAL(v[0], 2);
      ABC_TESTING_ASSERT_EQUAL(v[1], 3);
   }
};

} //namespace test

} //namespace abc

ABC_TESTING_REGISTER_TEST_CASE(abc::test::vector_basic)

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::test::vector_memory_mgmt

namespace abc {

namespace test {

class vector_memory_mgmt :
   public testing::test_case {
public:

   /** See testing::test_case::title().
   */
   virtual istr title() {
      return istr(SL("abc::*vector classes - memory management"));
   }

   /** See testing::test_case::run().
   */
   virtual void run() {
      ABC_TRACE_FN((this));

      using testing::utility::make_container_data_ptr_tracker;

      dmvector<int> v1;
      auto cdpt1(make_container_data_ptr_tracker(v1));
      // Note: the embedded item array size will probably be > 2.
      smvector<int, 2> v2;
      auto cdpt2(make_container_data_ptr_tracker(v2));
      // Note: the embedded item array size will probably be > 10.
      smvector<int, 10> v3;
      auto cdpt3(make_container_data_ptr_tracker(v3));

      // Add one element to each vector, so they all allocate a new item array or begin using their
      // own embedded one.

      // Should allocate a new item array.
      v1.append(10);
      ABC_TESTING_ASSERT_TRUE(cdpt1.changed());
      ABC_TESTING_ASSERT_EQUAL(v1.size(), 1u);
      ABC_TESTING_ASSERT_EQUAL(v1[0], 10);

      // Should begin using the embedded item array.
      v2.append(20);
      ABC_TESTING_ASSERT_TRUE(cdpt2.changed());
      ABC_TESTING_ASSERT_EQUAL(v2.size(), 1u);
      ABC_TESTING_ASSERT_EQUAL(v2[0], 20);
      int const * const p2Static(v2.data());

      // Should begin using the embedded item array.
      v3.append(30);
      ABC_TESTING_ASSERT_TRUE(cdpt3.changed());
      ABC_TESTING_ASSERT_EQUAL(v3.size(), 1u);
      ABC_TESTING_ASSERT_EQUAL(v3[0], 30);
      int const * const p3Static(v3.data());

      // Add more elements to each vector.

      // These are too many for the newly-allocated item array, so a new one should be allocated.
      v1.append(11);
      v1.append(12);
      v1.append(13);
      v1.append(14);
      v1.append(15);
      v1.append(16);
      v1.append(17);
      v1.append(18);
      v1.append(19);
      ABC_TESTING_ASSERT_TRUE(cdpt1.changed());
      ABC_TESTING_ASSERT_EQUAL(v1.size(), 10u);
      ABC_TESTING_ASSERT_EQUAL(v1[0], 10);
      ABC_TESTING_ASSERT_EQUAL(v1[1], 11);
      ABC_TESTING_ASSERT_EQUAL(v1[2], 12);
      ABC_TESTING_ASSERT_EQUAL(v1[3], 13);
      ABC_TESTING_ASSERT_EQUAL(v1[4], 14);
      ABC_TESTING_ASSERT_EQUAL(v1[5], 15);
      ABC_TESTING_ASSERT_EQUAL(v1[6], 16);
      ABC_TESTING_ASSERT_EQUAL(v1[7], 17);
      ABC_TESTING_ASSERT_EQUAL(v1[8], 18);
      ABC_TESTING_ASSERT_EQUAL(v1[9], 19);

      // These are too many for the embedded item array, so a new item array should be allocated.
      v2.append(21);
      v2.append(22);
      v2.append(23);
      v2.append(24);
      v2.append(25);
      v2.append(26);
      v2.append(27);
      v2.append(28);
      v2.append(29);
      ABC_TESTING_ASSERT_TRUE(cdpt2.changed());
      ABC_TESTING_ASSERT_EQUAL(v2.size(), 10u);
      ABC_TESTING_ASSERT_EQUAL(v2[0], 20);
      ABC_TESTING_ASSERT_EQUAL(v2[1], 21);
      ABC_TESTING_ASSERT_EQUAL(v2[2], 22);
      ABC_TESTING_ASSERT_EQUAL(v2[3], 23);
      ABC_TESTING_ASSERT_EQUAL(v2[4], 24);
      ABC_TESTING_ASSERT_EQUAL(v2[5], 25);
      ABC_TESTING_ASSERT_EQUAL(v2[6], 26);
      ABC_TESTING_ASSERT_EQUAL(v2[7], 27);
      ABC_TESTING_ASSERT_EQUAL(v2[8], 28);
      ABC_TESTING_ASSERT_EQUAL(v2[9], 29);

      // The embedded item array has room for this, so no reallocation is needed.
      v3.append(31);
      ABC_TESTING_ASSERT_EQUAL(v3.data(), p3Static);
      ABC_TESTING_ASSERT_FALSE(cdpt3.changed());
      ABC_TESTING_ASSERT_EQUAL(v3.size(), 2u);
      ABC_TESTING_ASSERT_EQUAL(v3[0], 30);
      ABC_TESTING_ASSERT_EQUAL(v3[1], 31);

      // Check assignment from larger to smaller static vectors.

      // Should keep the current item array, copying v2’s items over.
      v1 = v2;
      ABC_TESTING_ASSERT_FALSE(cdpt1.changed());
      ABC_TESTING_ASSERT_EQUAL(v1.size(), 10u);
      ABC_TESTING_ASSERT_EQUAL(v1[0], 20);
      ABC_TESTING_ASSERT_EQUAL(v1[1], 21);
      ABC_TESTING_ASSERT_EQUAL(v1[2], 22);
      ABC_TESTING_ASSERT_EQUAL(v1[3], 23);
      ABC_TESTING_ASSERT_EQUAL(v1[4], 24);
      ABC_TESTING_ASSERT_EQUAL(v1[5], 25);
      ABC_TESTING_ASSERT_EQUAL(v1[6], 26);
      ABC_TESTING_ASSERT_EQUAL(v1[7], 27);
      ABC_TESTING_ASSERT_EQUAL(v1[8], 28);
      ABC_TESTING_ASSERT_EQUAL(v1[9], 29);

      // Should return to using the embedded item array, copying v3’s items over.
      v2 = v3;
      ABC_TESTING_ASSERT_EQUAL(v2.data(), p2Static);
      ABC_TESTING_ASSERT_TRUE(cdpt2.changed());
      ABC_TESTING_ASSERT_EQUAL(v2.size(), 2u);
      ABC_TESTING_ASSERT_EQUAL(v2[0], 30);
      ABC_TESTING_ASSERT_EQUAL(v2[1], 31);
      // “Rebrand” the items as 2x.
      v2[0] = 20;
      v2[1] = 21;

      // The current item array should still be large enough, but this should drop it to use the
      // temporary one created by operator+().
      v1 = v2 + v3;
      ABC_TESTING_ASSERT_TRUE(cdpt1.changed());
      ABC_TESTING_ASSERT_EQUAL(v1.size(), 4u);
      ABC_TESTING_ASSERT_EQUAL(v1[0], 20);
      ABC_TESTING_ASSERT_EQUAL(v1[1], 21);
      ABC_TESTING_ASSERT_EQUAL(v1[2], 30);
      ABC_TESTING_ASSERT_EQUAL(v1[3], 31);
      // “Rebrand” the items as 1x.
      v1[0] = 10;
      v1[1] = 11;
      v1[2] = 12;
      v1[3] = 13;

      // This should be too much for the embedded item array, so a new one should be allocated.
      v3 += v1 + v2 + v1 + v3 + v1;
      ABC_TESTING_ASSERT_TRUE(cdpt3.changed());
      ABC_TESTING_ASSERT_EQUAL(v3.size(), 18u);
      ABC_TESTING_ASSERT_EQUAL(v3[0], 30);
      ABC_TESTING_ASSERT_EQUAL(v3[1], 31);
      ABC_TESTING_ASSERT_EQUAL(v3[2], 10);
      ABC_TESTING_ASSERT_EQUAL(v3[3], 11);
      ABC_TESTING_ASSERT_EQUAL(v3[4], 12);
      ABC_TESTING_ASSERT_EQUAL(v3[5], 13);
      ABC_TESTING_ASSERT_EQUAL(v3[6], 20);
      ABC_TESTING_ASSERT_EQUAL(v3[7], 21);
      ABC_TESTING_ASSERT_EQUAL(v3[8], 10);
      ABC_TESTING_ASSERT_EQUAL(v3[9], 11);
      ABC_TESTING_ASSERT_EQUAL(v3[10], 12);
      ABC_TESTING_ASSERT_EQUAL(v3[11], 13);
      ABC_TESTING_ASSERT_EQUAL(v3[12], 30);
      ABC_TESTING_ASSERT_EQUAL(v3[13], 31);
      ABC_TESTING_ASSERT_EQUAL(v3[14], 10);
      ABC_TESTING_ASSERT_EQUAL(v3[15], 11);
      ABC_TESTING_ASSERT_EQUAL(v3[16], 12);
      ABC_TESTING_ASSERT_EQUAL(v3[17], 13);
   }
};

} //namespace test

} //namespace abc

ABC_TESTING_REGISTER_TEST_CASE(abc::test::vector_memory_mgmt)

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::test::vector_move

namespace abc {

namespace test {

class vector_move :
   public testing::test_case {

   typedef testing::utility::instances_counter instances_counter;

public:

   /** See testing::test_case::title().
   */
   virtual istr title() {
      return istr(SL("abc::*vector classes - item and item array movement"));
   }

   /** See testing::test_case::run().
   */
   virtual void run() {
      ABC_TRACE_FN((this));

      // This will move the item array from the returned vector to v1, so no item copies or moves
      // will occur other than the ones in return_dmvector().
      dmvector<instances_counter> v1(return_dmvector());
      ABC_TESTING_ASSERT_EQUAL(instances_counter::new_insts(), 1u);
      ABC_TESTING_ASSERT_EQUAL(instances_counter::moves(), 1u);
      ABC_TESTING_ASSERT_EQUAL(instances_counter::copies(), 0u);
      instances_counter::reset_counts();

      // This should create a new copy, with no intermediate moves because all passages are by
      // reference or pointer.
      v1.append(v1[0]);
      ABC_TESTING_ASSERT_EQUAL(instances_counter::new_insts(), 0u);
      ABC_TESTING_ASSERT_EQUAL(instances_counter::moves(), 0u);
      ABC_TESTING_ASSERT_EQUAL(instances_counter::copies(), 1u);
      instances_counter::reset_counts();

      smvector<instances_counter, 9> v2;
      // This will move the individual items from the returned vector to v2’s static item array.
      // Can’t just construct v2 with return_dmvector() because v2 would just use that item array
      // instead of its own embedded one, resulting in no additional moves other than the one in
      // return_dmvector().
      v2 += return_dmvector();
      ABC_TESTING_ASSERT_EQUAL(instances_counter::new_insts(), 1u);
      ABC_TESTING_ASSERT_EQUAL(instances_counter::moves(), 2u);
      ABC_TESTING_ASSERT_EQUAL(instances_counter::copies(), 0u);
      instances_counter::reset_counts();
   }

   /** Instantiates and returns a dynamic vector. The vector will contain one item, added in a way
   that should cause only one new instance of instances_counter to be created, one moved and none
   copied. Additional copies/moved may occur upon return.

   return
      Newly-instantiated dynamic vector.
   */
   dmvector<instances_counter> return_dmvector() {
      ABC_TRACE_FN((this));

      dmvector<instances_counter> v;
      // New instance, immediately moved.
      v.append(instances_counter());
      // This will move the item array or the items in it, depending on the destination type
      // (static or dynamic item array).
      return std::move(v);
   }
};

} //namespace test

} //namespace abc

ABC_TESTING_REGISTER_TEST_CASE(abc::test::vector_move)

<commit_msg>Remove unreliable test assertion<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2011, 2012, 2013, 2014
Raffaello D. Di Napoli

This file is part of Application-Building Components (henceforth referred to as ABC).

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

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

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

#include <abc/testing/test_case.hxx>
#include <abc/trace.hxx>
#include <algorithm>
#include <abc/testing/utility.hxx>

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::test::vector_basic

namespace abc {

namespace test {

class vector_basic :
   public testing::test_case {
public:

   /** See testing::test_case::title().
   */
   virtual istr title() {
      return istr(SL("abc::*vector classes - basic operations"));
   }

   /** See testing::test_case::run().
   */
   virtual void run() {
      ABC_TRACE_FN((this));

      dmvector<int> v;

      ABC_TESTING_ASSERT_EQUAL(v.size(), 0u);

      v.append(1);
      ABC_TESTING_ASSERT_EQUAL(v.size(), 1u);
      ABC_TESTING_ASSERT_EQUAL(v[0], 1);

      v = v + v;
      ABC_TESTING_ASSERT_EQUAL(v.size(), 2u);
      ABC_TESTING_ASSERT_EQUAL(v[0], 1);
      ABC_TESTING_ASSERT_EQUAL(v[1], 1);

      v.insert(1, 2);
      ABC_TESTING_ASSERT_EQUAL(v.size(), 3u);
      ABC_TESTING_ASSERT_EQUAL(v[0], 1);
      ABC_TESTING_ASSERT_EQUAL(v[1], 2);
      ABC_TESTING_ASSERT_EQUAL(v[2], 1);

      v = v.slice(1, 3);
      ABC_TESTING_ASSERT_EQUAL(v.size(), 2u);
      ABC_TESTING_ASSERT_EQUAL(v[0], 2);
      ABC_TESTING_ASSERT_EQUAL(v[1], 1);

      v.append(3);
      ABC_TESTING_ASSERT_EQUAL(v.size(), 3u);
      ABC_TESTING_ASSERT_EQUAL(v[0], 2);
      ABC_TESTING_ASSERT_EQUAL(v[1], 1);
      ABC_TESTING_ASSERT_EQUAL(v[2], 3);

      ABC_TESTING_ASSERT_EQUAL(v.index_of(1), 1);

      ABC_TESTING_ASSERT_EQUAL(v.last_index_of(1), 1);

      ABC_TESTING_ASSERT_EQUAL(std::find(v.cbegin(), v.cend(), 1), v.cbegin() + 1);

      v.remove_at(std::find(v.cbegin(), v.cend(), 1));
      ABC_TESTING_ASSERT_EQUAL(v.size(), 2u);
      ABC_TESTING_ASSERT_EQUAL(v[0], 2);
      ABC_TESTING_ASSERT_EQUAL(v[1], 3);
   }
};

} //namespace test

} //namespace abc

ABC_TESTING_REGISTER_TEST_CASE(abc::test::vector_basic)

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::test::vector_memory_mgmt

namespace abc {

namespace test {

class vector_memory_mgmt :
   public testing::test_case {
public:

   /** See testing::test_case::title().
   */
   virtual istr title() {
      return istr(SL("abc::*vector classes - memory management"));
   }

   /** See testing::test_case::run().
   */
   virtual void run() {
      ABC_TRACE_FN((this));

      using testing::utility::make_container_data_ptr_tracker;

      dmvector<int> v1;
      auto cdpt1(make_container_data_ptr_tracker(v1));
      // Note: the embedded item array size will probably be > 2.
      smvector<int, 2> v2;
      auto cdpt2(make_container_data_ptr_tracker(v2));
      // Note: the embedded item array size will probably be > 10.
      smvector<int, 10> v3;
      auto cdpt3(make_container_data_ptr_tracker(v3));

      // Add one element to each vector, so they all allocate a new item array or begin using their
      // own embedded one.

      // Should allocate a new item array.
      v1.append(10);
      ABC_TESTING_ASSERT_TRUE(cdpt1.changed());
      ABC_TESTING_ASSERT_EQUAL(v1.size(), 1u);
      ABC_TESTING_ASSERT_EQUAL(v1[0], 10);

      // Should begin using the embedded item array.
      v2.append(20);
      ABC_TESTING_ASSERT_TRUE(cdpt2.changed());
      ABC_TESTING_ASSERT_EQUAL(v2.size(), 1u);
      ABC_TESTING_ASSERT_EQUAL(v2[0], 20);
      int const * const p2Static(v2.data());

      // Should begin using the embedded item array.
      v3.append(30);
      ABC_TESTING_ASSERT_TRUE(cdpt3.changed());
      ABC_TESTING_ASSERT_EQUAL(v3.size(), 1u);
      ABC_TESTING_ASSERT_EQUAL(v3[0], 30);
      int const * const p3Static(v3.data());

      // Add more elements to each vector.

      // These are too many for the newly-allocated item array, so a new one should be allocated.
      v1.append(11);
      v1.append(12);
      v1.append(13);
      v1.append(14);
      v1.append(15);
      v1.append(16);
      v1.append(17);
      v1.append(18);
      v1.append(19);
      // Cannot ASSERT_TRUE on this change, because the item array may be resized in place.
      cdpt1.changed();
      ABC_TESTING_ASSERT_EQUAL(v1.size(), 10u);
      ABC_TESTING_ASSERT_EQUAL(v1[0], 10);
      ABC_TESTING_ASSERT_EQUAL(v1[1], 11);
      ABC_TESTING_ASSERT_EQUAL(v1[2], 12);
      ABC_TESTING_ASSERT_EQUAL(v1[3], 13);
      ABC_TESTING_ASSERT_EQUAL(v1[4], 14);
      ABC_TESTING_ASSERT_EQUAL(v1[5], 15);
      ABC_TESTING_ASSERT_EQUAL(v1[6], 16);
      ABC_TESTING_ASSERT_EQUAL(v1[7], 17);
      ABC_TESTING_ASSERT_EQUAL(v1[8], 18);
      ABC_TESTING_ASSERT_EQUAL(v1[9], 19);

      // These are too many for the embedded item array, so a new item array should be allocated.
      v2.append(21);
      v2.append(22);
      v2.append(23);
      v2.append(24);
      v2.append(25);
      v2.append(26);
      v2.append(27);
      v2.append(28);
      v2.append(29);
      ABC_TESTING_ASSERT_TRUE(cdpt2.changed());
      ABC_TESTING_ASSERT_EQUAL(v2.size(), 10u);
      ABC_TESTING_ASSERT_EQUAL(v2[0], 20);
      ABC_TESTING_ASSERT_EQUAL(v2[1], 21);
      ABC_TESTING_ASSERT_EQUAL(v2[2], 22);
      ABC_TESTING_ASSERT_EQUAL(v2[3], 23);
      ABC_TESTING_ASSERT_EQUAL(v2[4], 24);
      ABC_TESTING_ASSERT_EQUAL(v2[5], 25);
      ABC_TESTING_ASSERT_EQUAL(v2[6], 26);
      ABC_TESTING_ASSERT_EQUAL(v2[7], 27);
      ABC_TESTING_ASSERT_EQUAL(v2[8], 28);
      ABC_TESTING_ASSERT_EQUAL(v2[9], 29);

      // The embedded item array has room for this, so no reallocation is needed.
      v3.append(31);
      ABC_TESTING_ASSERT_EQUAL(v3.data(), p3Static);
      ABC_TESTING_ASSERT_FALSE(cdpt3.changed());
      ABC_TESTING_ASSERT_EQUAL(v3.size(), 2u);
      ABC_TESTING_ASSERT_EQUAL(v3[0], 30);
      ABC_TESTING_ASSERT_EQUAL(v3[1], 31);

      // Check assignment from larger to smaller static vectors.

      // Should keep the current item array, copying v2’s items over.
      v1 = v2;
      ABC_TESTING_ASSERT_FALSE(cdpt1.changed());
      ABC_TESTING_ASSERT_EQUAL(v1.size(), 10u);
      ABC_TESTING_ASSERT_EQUAL(v1[0], 20);
      ABC_TESTING_ASSERT_EQUAL(v1[1], 21);
      ABC_TESTING_ASSERT_EQUAL(v1[2], 22);
      ABC_TESTING_ASSERT_EQUAL(v1[3], 23);
      ABC_TESTING_ASSERT_EQUAL(v1[4], 24);
      ABC_TESTING_ASSERT_EQUAL(v1[5], 25);
      ABC_TESTING_ASSERT_EQUAL(v1[6], 26);
      ABC_TESTING_ASSERT_EQUAL(v1[7], 27);
      ABC_TESTING_ASSERT_EQUAL(v1[8], 28);
      ABC_TESTING_ASSERT_EQUAL(v1[9], 29);

      // Should return to using the embedded item array, copying v3’s items over.
      v2 = v3;
      ABC_TESTING_ASSERT_EQUAL(v2.data(), p2Static);
      ABC_TESTING_ASSERT_TRUE(cdpt2.changed());
      ABC_TESTING_ASSERT_EQUAL(v2.size(), 2u);
      ABC_TESTING_ASSERT_EQUAL(v2[0], 30);
      ABC_TESTING_ASSERT_EQUAL(v2[1], 31);
      // “Rebrand” the items as 2x.
      v2[0] = 20;
      v2[1] = 21;

      // The current item array should still be large enough, but this should drop it to use the
      // temporary one created by operator+().
      v1 = v2 + v3;
      ABC_TESTING_ASSERT_TRUE(cdpt1.changed());
      ABC_TESTING_ASSERT_EQUAL(v1.size(), 4u);
      ABC_TESTING_ASSERT_EQUAL(v1[0], 20);
      ABC_TESTING_ASSERT_EQUAL(v1[1], 21);
      ABC_TESTING_ASSERT_EQUAL(v1[2], 30);
      ABC_TESTING_ASSERT_EQUAL(v1[3], 31);
      // “Rebrand” the items as 1x.
      v1[0] = 10;
      v1[1] = 11;
      v1[2] = 12;
      v1[3] = 13;

      // This should be too much for the embedded item array, so a new one should be allocated.
      v3 += v1 + v2 + v1 + v3 + v1;
      ABC_TESTING_ASSERT_TRUE(cdpt3.changed());
      ABC_TESTING_ASSERT_EQUAL(v3.size(), 18u);
      ABC_TESTING_ASSERT_EQUAL(v3[0], 30);
      ABC_TESTING_ASSERT_EQUAL(v3[1], 31);
      ABC_TESTING_ASSERT_EQUAL(v3[2], 10);
      ABC_TESTING_ASSERT_EQUAL(v3[3], 11);
      ABC_TESTING_ASSERT_EQUAL(v3[4], 12);
      ABC_TESTING_ASSERT_EQUAL(v3[5], 13);
      ABC_TESTING_ASSERT_EQUAL(v3[6], 20);
      ABC_TESTING_ASSERT_EQUAL(v3[7], 21);
      ABC_TESTING_ASSERT_EQUAL(v3[8], 10);
      ABC_TESTING_ASSERT_EQUAL(v3[9], 11);
      ABC_TESTING_ASSERT_EQUAL(v3[10], 12);
      ABC_TESTING_ASSERT_EQUAL(v3[11], 13);
      ABC_TESTING_ASSERT_EQUAL(v3[12], 30);
      ABC_TESTING_ASSERT_EQUAL(v3[13], 31);
      ABC_TESTING_ASSERT_EQUAL(v3[14], 10);
      ABC_TESTING_ASSERT_EQUAL(v3[15], 11);
      ABC_TESTING_ASSERT_EQUAL(v3[16], 12);
      ABC_TESTING_ASSERT_EQUAL(v3[17], 13);
   }
};

} //namespace test

} //namespace abc

ABC_TESTING_REGISTER_TEST_CASE(abc::test::vector_memory_mgmt)

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::test::vector_move

namespace abc {

namespace test {

class vector_move :
   public testing::test_case {

   typedef testing::utility::instances_counter instances_counter;

public:

   /** See testing::test_case::title().
   */
   virtual istr title() {
      return istr(SL("abc::*vector classes - item and item array movement"));
   }

   /** See testing::test_case::run().
   */
   virtual void run() {
      ABC_TRACE_FN((this));

      // This will move the item array from the returned vector to v1, so no item copies or moves
      // will occur other than the ones in return_dmvector().
      dmvector<instances_counter> v1(return_dmvector());
      ABC_TESTING_ASSERT_EQUAL(instances_counter::new_insts(), 1u);
      ABC_TESTING_ASSERT_EQUAL(instances_counter::moves(), 1u);
      ABC_TESTING_ASSERT_EQUAL(instances_counter::copies(), 0u);
      instances_counter::reset_counts();

      // This should create a new copy, with no intermediate moves because all passages are by
      // reference or pointer.
      v1.append(v1[0]);
      ABC_TESTING_ASSERT_EQUAL(instances_counter::new_insts(), 0u);
      ABC_TESTING_ASSERT_EQUAL(instances_counter::moves(), 0u);
      ABC_TESTING_ASSERT_EQUAL(instances_counter::copies(), 1u);
      instances_counter::reset_counts();

      smvector<instances_counter, 9> v2;
      // This will move the individual items from the returned vector to v2’s static item array.
      // Can’t just construct v2 with return_dmvector() because v2 would just use that item array
      // instead of its own embedded one, resulting in no additional moves other than the one in
      // return_dmvector().
      v2 += return_dmvector();
      ABC_TESTING_ASSERT_EQUAL(instances_counter::new_insts(), 1u);
      ABC_TESTING_ASSERT_EQUAL(instances_counter::moves(), 2u);
      ABC_TESTING_ASSERT_EQUAL(instances_counter::copies(), 0u);
      instances_counter::reset_counts();
   }

   /** Instantiates and returns a dynamic vector. The vector will contain one item, added in a way
   that should cause only one new instance of instances_counter to be created, one moved and none
   copied. Additional copies/moved may occur upon return.

   return
      Newly-instantiated dynamic vector.
   */
   dmvector<instances_counter> return_dmvector() {
      ABC_TRACE_FN((this));

      dmvector<instances_counter> v;
      // New instance, immediately moved.
      v.append(instances_counter());
      // This will move the item array or the items in it, depending on the destination type
      // (static or dynamic item array).
      return std::move(v);
   }
};

} //namespace test

} //namespace abc

ABC_TESTING_REGISTER_TEST_CASE(abc::test::vector_move)

<|endoftext|>


<commit_before>/**
 * This file is part of TelepathyQt4
 *
 * @copyright Copyright (C) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
 * @copyright Copyright (C) 2011 Nokia Corporation
 * @license LGPL 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/StreamTubeClient>

#include "TelepathyQt4/stream-tube-client-internal.h"
#include "TelepathyQt4/_gen/stream-tube-client.moc.hpp"
#include "TelepathyQt4/_gen/stream-tube-client-internal.moc.hpp"

#include "TelepathyQt4/debug-internal.h"
#include "TelepathyQt4/simple-stream-tube-handler.h"

#include <TelepathyQt4/AccountManager>
#include <TelepathyQt4/ClientRegistrar>
#include <TelepathyQt4/IncomingStreamTubeChannel>
#include <TelepathyQt4/PendingStreamTubeConnection>
#include <TelepathyQt4/StreamTubeChannel>

#include <QHash>

namespace Tp
{

struct TELEPATHY_QT4_NO_EXPORT StreamTubeClient::Private
{
    Private(const ClientRegistrarPtr &registrar,
            const QStringList &services,
            const QString &maybeClientName,
            bool monitorConnections)
        : registrar(registrar),
          handler(SimpleStreamTubeHandler::create(services, false, monitorConnections)),
          clientName(maybeClientName),
          isRegistered(false),
          acceptsAsTcp(false), acceptsAsUnix(false),
          tcpGenerator(0), requireCredentials(false)
    {
        if (clientName.isEmpty()) {
            clientName = QString::fromLatin1("TpQt4STubeClient_%1_%2")
                .arg(registrar->dbusConnection().baseService()
                        .replace(QLatin1Char(':'), QLatin1Char('_'))
                        .replace(QLatin1Char('.'), QLatin1Char('_')))
                .arg((intptr_t) this, 0, 16);
        }
    }

    void ensureRegistered()
    {
        if (isRegistered) {
            return;
        }

        debug() << "Register StreamTubeClient with name " << clientName;

        if (registrar->registerClient(handler, clientName)) {
            isRegistered = true;
        } else {
            warning() << "StreamTubeClient" << clientName
                << "registration failed";
        }
    }

    ClientRegistrarPtr registrar;
    SharedPtr<SimpleStreamTubeHandler> handler;
    QString clientName;
    bool isRegistered;

    bool acceptsAsTcp, acceptsAsUnix;
    const TcpSourceAddressGenerator *tcpGenerator;
    bool requireCredentials;

    QHash<StreamTubeChannelPtr, TubeWrapper *> tubes;
};

StreamTubeClient::TubeWrapper::TubeWrapper(
        const AccountPtr &acc,
        const IncomingStreamTubeChannelPtr &tube,
        const QHostAddress &sourceAddress,
        quint16 sourcePort)
    : mAcc(acc), mTube(tube), sourceAddress(sourceAddress), sourcePort(sourcePort)
{
    connect(tube->acceptTubeAsTcpSocket(sourceAddress, sourcePort),
            SIGNAL(finished(Tp::PendingOperation*)),
            SLOT(onTubeAccepted(Tp::PendingOperation*)));
}

StreamTubeClient::TubeWrapper::TubeWrapper(
        const AccountPtr &acc,
        const IncomingStreamTubeChannelPtr &tube,
        bool requireCredentials)
    : mAcc(acc), mTube(tube), sourcePort(0)
{
    connect(tube->acceptTubeAsUnixSocket(requireCredentials),
            SIGNAL(finished(Tp::PendingOperation*)),
            SLOT(onTubeAccepted(Tp::PendingOperation*)));
}

void StreamTubeClient::TubeWrapper::onTubeAccepted(Tp::PendingOperation *op)
{
    emit acceptFinished(this, qobject_cast<Tp::PendingStreamTubeConnection *>(op));
}

StreamTubeClientPtr StreamTubeClient::create(
        const QStringList &services,
        const QString &clientName,
        bool monitorConnections,
        const AccountFactoryConstPtr &accountFactory,
        const ConnectionFactoryConstPtr &connectionFactory,
        const ChannelFactoryConstPtr &channelFactory,
        const ContactFactoryConstPtr &contactFactory)
{
    return create(
            QDBusConnection::sessionBus(),
            accountFactory,
            connectionFactory,
            channelFactory,
            contactFactory,
            services,
            clientName,
            monitorConnections);
}

StreamTubeClientPtr StreamTubeClient::create(
        const QDBusConnection &bus,
        const AccountFactoryConstPtr &accountFactory,
        const ConnectionFactoryConstPtr &connectionFactory,
        const ChannelFactoryConstPtr &channelFactory,
        const ContactFactoryConstPtr &contactFactory,
        const QStringList &services,
        const QString &clientName,
        bool monitorConnections)
{
    return create(
            ClientRegistrar::create(
                bus,
                accountFactory,
                connectionFactory,
                channelFactory,
                contactFactory),
            services,
            clientName,
            monitorConnections);
}

StreamTubeClientPtr StreamTubeClient::create(
        const AccountManagerPtr &accountManager,
        const QStringList &services,
        const QString &clientName,
        bool monitorConnections)
{
    return create(
            accountManager->dbusConnection(),
            accountManager->accountFactory(),
            accountManager->connectionFactory(),
            accountManager->channelFactory(),
            accountManager->contactFactory(),
            services,
            clientName,
            monitorConnections);
}

StreamTubeClientPtr StreamTubeClient::create(
        const ClientRegistrarPtr &registrar,
        const QStringList &services,
        const QString &clientName,
        bool monitorConnections)
{
    StreamTubeClientPtr client(
            new StreamTubeClient(registrar, services, clientName, monitorConnections));
    return client;
}

StreamTubeClient::StreamTubeClient(
        const ClientRegistrarPtr &registrar,
        const QStringList &services,
        const QString &clientName,
        bool monitorConnections)
: mPriv(new Private(registrar, services, clientName, monitorConnections))
{
    connect(mPriv->handler.data(),
            SIGNAL(invokedForTube(
                    Tp::AccountPtr,
                    Tp::StreamTubeChannelPtr,
                    QDateTime,
                    Tp::ChannelRequestHints)),
            SLOT(onInvokedForTube(
                    Tp::AccountPtr,
                    Tp::StreamTubeChannelPtr,
                    QDateTime,
                    Tp::ChannelRequestHints)));
}

/**
 * Class destructor.
 */
StreamTubeClient::~StreamTubeClient()
{
    if (!clientName().isNull()) {
        mPriv->registrar->unregisterClient(mPriv->handler);
    }

    foreach (TubeWrapper *wrapper, mPriv->tubes.values()) {
        wrapper->deleteLater();
    }
}

ClientRegistrarPtr StreamTubeClient::registrar() const
{
    return mPriv->registrar;
}

QString StreamTubeClient::clientName() const
{
    return mPriv->clientName;
}

bool StreamTubeClient::monitorsConnections() const
{
    return mPriv->handler->monitorsConnections();
}

bool StreamTubeClient::acceptsAsTcp() const
{
    return mPriv->acceptsAsTcp;
}

const StreamTubeClient::TcpSourceAddressGenerator *StreamTubeClient::generator() const
{
    if (!acceptsAsTcp()) {
        warning() << "StreamTubeClient::generator() used, but not accepting as TCP, returning 0";
        return 0;
    }

    return mPriv->tcpGenerator;
}

void StreamTubeClient::setToAcceptAsTcp(const TcpSourceAddressGenerator *generator)
{
    mPriv->tcpGenerator = generator;
    mPriv->acceptsAsTcp = true;
    mPriv->acceptsAsUnix = false;

    mPriv->ensureRegistered();
}

void StreamTubeClient::setToAcceptAsUnix(bool requireCredentials)
{
    mPriv->tcpGenerator = 0;
    mPriv->acceptsAsTcp = false;
    mPriv->acceptsAsUnix = true;
    mPriv->requireCredentials = requireCredentials;

    mPriv->ensureRegistered();
}

bool StreamTubeClient::acceptsAsUnix() const
{
    return mPriv->acceptsAsUnix;
}

void StreamTubeClient::onInvokedForTube(
        const AccountPtr &acc,
        const StreamTubeChannelPtr &tube,
        const QDateTime &time,
        const ChannelRequestHints &hints)
{
    Q_ASSERT(!tube->isRequested());

    if (mPriv->tubes.contains(tube)) {
        debug() << "Ignoring StreamTubeClient reinvocation for tube" << tube->objectPath();
        return;
    }

    IncomingStreamTubeChannelPtr incoming = IncomingStreamTubeChannelPtr::qObjectCast(tube);

    if (!incoming) {
        warning() << "The ChannelFactory used by StreamTubeClient must construct" <<
            "IncomingStreamTubeChannel subclasses for Requested=false StreamTubes";
        tube->requestClose();
        return;
    } else if (!mPriv->acceptsAsTcp && !mPriv->acceptsAsUnix) {
        warning() << "STubeClient not set to accept, closing tube" << tube->objectPath();
        tube->requestClose();
        return;
    }

    TubeWrapper *wrapper = 0;

    if (mPriv->acceptsAsTcp) {
        QPair<QHostAddress, quint16> srcAddr =
            qMakePair(QHostAddress(QHostAddress::Any), quint16(0));

        if (mPriv->tcpGenerator) {
            srcAddr = mPriv->tcpGenerator->nextSourceAddress(acc, incoming);
        }

        wrapper = new TubeWrapper(acc, incoming, srcAddr.first, srcAddr.second);
    } else {
        wrapper = new TubeWrapper(acc, incoming, mPriv->requireCredentials);
    }

    connect(wrapper,
            SIGNAL(acceptFinished(TubeWrapper*,Tp::PendingStreamTubeConnection*)),
            SLOT(onAcceptFinished(TubeWrapper*,Tp::PendingStreamTubeConnection*)));
    connect(tube.data(),
            SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
            SLOT(onTubeInvalidated(Tp::DBusProxy*,QString,QString)));
    mPriv->tubes.insert(tube, wrapper);

    emit tubeOffered(acc, incoming);

    // TODO: accept the tube, connect accept result to tracking wrapper, if successful before tube
    // is invalidated, emit tubeAcceptedAsTcp/Unix, if failure close tube and emit tubeClosed with
    // the acceptTubeAs*Socket() PendingOperation error, if invalidated first, just emit tubeClosed
    // and remove from tracking
}

void StreamTubeClient::onAcceptFinished(TubeWrapper *wrapper, PendingStreamTubeConnection *conn)
{
    Q_ASSERT(wrapper != NULL);
    Q_ASSERT(conn != NULL);

    if (!mPriv->tubes.contains(wrapper->mTube)) {
        debug() << "StreamTubeClient ignoring Accept result for invalidated tube"
            << wrapper->mTube->objectPath();
        return;
    }

    if (conn->isError()) {
        warning() << "StreamTubeClient couldn't accept tube" << wrapper->mTube->objectPath() << '-'
            << conn->errorName() << ':' << conn->errorMessage();
        wrapper->mTube->disconnect(this);
        emit tubeClosed(wrapper->mAcc, wrapper->mTube, conn->errorName(), conn->errorMessage());
        mPriv->tubes.remove(wrapper->mTube);
        wrapper->deleteLater();
        return;
    }

    debug() << "StreamTubeClient accepted tube" << wrapper->mTube->objectPath();

    if (conn->addressType() == SocketAddressTypeIPv4
            || conn->addressType() == SocketAddressTypeIPv6) {
        QPair<QHostAddress, quint16> addr = conn->ipAddress();
        emit tubeAcceptedAsTcp(wrapper->mAcc, wrapper->mTube, addr.first, addr.second,
                wrapper->sourceAddress, wrapper->sourcePort);
    } else {
        emit tubeAcceptedAsUnix(wrapper->mAcc, wrapper->mTube, conn->localAddress(),
                conn->requiresCredentials(), conn->credentialByte());
    }
}

void StreamTubeClient::onTubeInvalidated(Tp::DBusProxy *proxy, const QString &error,
        const QString &message)
{
    StreamTubeChannelPtr tube(qobject_cast<StreamTubeChannel *>(proxy));
    Q_ASSERT(!tube.isNull());

    TubeWrapper *wrapper = mPriv->tubes.value(tube);
    if (!wrapper) {
        // Accept finish with error already removed it
        return;
    }

    debug() << "Client StreamTube" << tube->objectPath() << "invalidated - " << error << ':'
        << message;

    emit tubeClosed(wrapper->mAcc, wrapper->mTube, error, message);
    mPriv->tubes.remove(tube);
    wrapper->deleteLater();
}

} // Tp
<commit_msg>StreamTubeClient: Only close tube on accept failure if not closed already<commit_after>/**
 * This file is part of TelepathyQt4
 *
 * @copyright Copyright (C) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
 * @copyright Copyright (C) 2011 Nokia Corporation
 * @license LGPL 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/StreamTubeClient>

#include "TelepathyQt4/stream-tube-client-internal.h"
#include "TelepathyQt4/_gen/stream-tube-client.moc.hpp"
#include "TelepathyQt4/_gen/stream-tube-client-internal.moc.hpp"

#include "TelepathyQt4/debug-internal.h"
#include "TelepathyQt4/simple-stream-tube-handler.h"

#include <TelepathyQt4/AccountManager>
#include <TelepathyQt4/ClientRegistrar>
#include <TelepathyQt4/IncomingStreamTubeChannel>
#include <TelepathyQt4/PendingStreamTubeConnection>
#include <TelepathyQt4/StreamTubeChannel>

#include <QHash>

namespace Tp
{

struct TELEPATHY_QT4_NO_EXPORT StreamTubeClient::Private
{
    Private(const ClientRegistrarPtr &registrar,
            const QStringList &services,
            const QString &maybeClientName,
            bool monitorConnections)
        : registrar(registrar),
          handler(SimpleStreamTubeHandler::create(services, false, monitorConnections)),
          clientName(maybeClientName),
          isRegistered(false),
          acceptsAsTcp(false), acceptsAsUnix(false),
          tcpGenerator(0), requireCredentials(false)
    {
        if (clientName.isEmpty()) {
            clientName = QString::fromLatin1("TpQt4STubeClient_%1_%2")
                .arg(registrar->dbusConnection().baseService()
                        .replace(QLatin1Char(':'), QLatin1Char('_'))
                        .replace(QLatin1Char('.'), QLatin1Char('_')))
                .arg((intptr_t) this, 0, 16);
        }
    }

    void ensureRegistered()
    {
        if (isRegistered) {
            return;
        }

        debug() << "Register StreamTubeClient with name " << clientName;

        if (registrar->registerClient(handler, clientName)) {
            isRegistered = true;
        } else {
            warning() << "StreamTubeClient" << clientName
                << "registration failed";
        }
    }

    ClientRegistrarPtr registrar;
    SharedPtr<SimpleStreamTubeHandler> handler;
    QString clientName;
    bool isRegistered;

    bool acceptsAsTcp, acceptsAsUnix;
    const TcpSourceAddressGenerator *tcpGenerator;
    bool requireCredentials;

    QHash<StreamTubeChannelPtr, TubeWrapper *> tubes;
};

StreamTubeClient::TubeWrapper::TubeWrapper(
        const AccountPtr &acc,
        const IncomingStreamTubeChannelPtr &tube,
        const QHostAddress &sourceAddress,
        quint16 sourcePort)
    : mAcc(acc), mTube(tube), sourceAddress(sourceAddress), sourcePort(sourcePort)
{
    connect(tube->acceptTubeAsTcpSocket(sourceAddress, sourcePort),
            SIGNAL(finished(Tp::PendingOperation*)),
            SLOT(onTubeAccepted(Tp::PendingOperation*)));
}

StreamTubeClient::TubeWrapper::TubeWrapper(
        const AccountPtr &acc,
        const IncomingStreamTubeChannelPtr &tube,
        bool requireCredentials)
    : mAcc(acc), mTube(tube), sourcePort(0)
{
    connect(tube->acceptTubeAsUnixSocket(requireCredentials),
            SIGNAL(finished(Tp::PendingOperation*)),
            SLOT(onTubeAccepted(Tp::PendingOperation*)));
}

void StreamTubeClient::TubeWrapper::onTubeAccepted(Tp::PendingOperation *op)
{
    emit acceptFinished(this, qobject_cast<Tp::PendingStreamTubeConnection *>(op));
}

StreamTubeClientPtr StreamTubeClient::create(
        const QStringList &services,
        const QString &clientName,
        bool monitorConnections,
        const AccountFactoryConstPtr &accountFactory,
        const ConnectionFactoryConstPtr &connectionFactory,
        const ChannelFactoryConstPtr &channelFactory,
        const ContactFactoryConstPtr &contactFactory)
{
    return create(
            QDBusConnection::sessionBus(),
            accountFactory,
            connectionFactory,
            channelFactory,
            contactFactory,
            services,
            clientName,
            monitorConnections);
}

StreamTubeClientPtr StreamTubeClient::create(
        const QDBusConnection &bus,
        const AccountFactoryConstPtr &accountFactory,
        const ConnectionFactoryConstPtr &connectionFactory,
        const ChannelFactoryConstPtr &channelFactory,
        const ContactFactoryConstPtr &contactFactory,
        const QStringList &services,
        const QString &clientName,
        bool monitorConnections)
{
    return create(
            ClientRegistrar::create(
                bus,
                accountFactory,
                connectionFactory,
                channelFactory,
                contactFactory),
            services,
            clientName,
            monitorConnections);
}

StreamTubeClientPtr StreamTubeClient::create(
        const AccountManagerPtr &accountManager,
        const QStringList &services,
        const QString &clientName,
        bool monitorConnections)
{
    return create(
            accountManager->dbusConnection(),
            accountManager->accountFactory(),
            accountManager->connectionFactory(),
            accountManager->channelFactory(),
            accountManager->contactFactory(),
            services,
            clientName,
            monitorConnections);
}

StreamTubeClientPtr StreamTubeClient::create(
        const ClientRegistrarPtr &registrar,
        const QStringList &services,
        const QString &clientName,
        bool monitorConnections)
{
    StreamTubeClientPtr client(
            new StreamTubeClient(registrar, services, clientName, monitorConnections));
    return client;
}

StreamTubeClient::StreamTubeClient(
        const ClientRegistrarPtr &registrar,
        const QStringList &services,
        const QString &clientName,
        bool monitorConnections)
: mPriv(new Private(registrar, services, clientName, monitorConnections))
{
    connect(mPriv->handler.data(),
            SIGNAL(invokedForTube(
                    Tp::AccountPtr,
                    Tp::StreamTubeChannelPtr,
                    QDateTime,
                    Tp::ChannelRequestHints)),
            SLOT(onInvokedForTube(
                    Tp::AccountPtr,
                    Tp::StreamTubeChannelPtr,
                    QDateTime,
                    Tp::ChannelRequestHints)));
}

/**
 * Class destructor.
 */
StreamTubeClient::~StreamTubeClient()
{
    if (!clientName().isNull()) {
        mPriv->registrar->unregisterClient(mPriv->handler);
    }

    foreach (TubeWrapper *wrapper, mPriv->tubes.values()) {
        wrapper->deleteLater();
    }
}

ClientRegistrarPtr StreamTubeClient::registrar() const
{
    return mPriv->registrar;
}

QString StreamTubeClient::clientName() const
{
    return mPriv->clientName;
}

bool StreamTubeClient::monitorsConnections() const
{
    return mPriv->handler->monitorsConnections();
}

bool StreamTubeClient::acceptsAsTcp() const
{
    return mPriv->acceptsAsTcp;
}

const StreamTubeClient::TcpSourceAddressGenerator *StreamTubeClient::generator() const
{
    if (!acceptsAsTcp()) {
        warning() << "StreamTubeClient::generator() used, but not accepting as TCP, returning 0";
        return 0;
    }

    return mPriv->tcpGenerator;
}

void StreamTubeClient::setToAcceptAsTcp(const TcpSourceAddressGenerator *generator)
{
    mPriv->tcpGenerator = generator;
    mPriv->acceptsAsTcp = true;
    mPriv->acceptsAsUnix = false;

    mPriv->ensureRegistered();
}

void StreamTubeClient::setToAcceptAsUnix(bool requireCredentials)
{
    mPriv->tcpGenerator = 0;
    mPriv->acceptsAsTcp = false;
    mPriv->acceptsAsUnix = true;
    mPriv->requireCredentials = requireCredentials;

    mPriv->ensureRegistered();
}

bool StreamTubeClient::acceptsAsUnix() const
{
    return mPriv->acceptsAsUnix;
}

void StreamTubeClient::onInvokedForTube(
        const AccountPtr &acc,
        const StreamTubeChannelPtr &tube,
        const QDateTime &time,
        const ChannelRequestHints &hints)
{
    Q_ASSERT(!tube->isRequested());

    if (mPriv->tubes.contains(tube)) {
        debug() << "Ignoring StreamTubeClient reinvocation for tube" << tube->objectPath();
        return;
    }

    IncomingStreamTubeChannelPtr incoming = IncomingStreamTubeChannelPtr::qObjectCast(tube);

    if (!incoming) {
        warning() << "The ChannelFactory used by StreamTubeClient must construct" <<
            "IncomingStreamTubeChannel subclasses for Requested=false StreamTubes";
        tube->requestClose();
        return;
    } else if (!mPriv->acceptsAsTcp && !mPriv->acceptsAsUnix) {
        warning() << "STubeClient not set to accept, closing tube" << tube->objectPath();
        tube->requestClose();
        return;
    }

    TubeWrapper *wrapper = 0;

    if (mPriv->acceptsAsTcp) {
        QPair<QHostAddress, quint16> srcAddr =
            qMakePair(QHostAddress(QHostAddress::Any), quint16(0));

        if (mPriv->tcpGenerator) {
            srcAddr = mPriv->tcpGenerator->nextSourceAddress(acc, incoming);
        }

        wrapper = new TubeWrapper(acc, incoming, srcAddr.first, srcAddr.second);
    } else {
        wrapper = new TubeWrapper(acc, incoming, mPriv->requireCredentials);
    }

    connect(wrapper,
            SIGNAL(acceptFinished(TubeWrapper*,Tp::PendingStreamTubeConnection*)),
            SLOT(onAcceptFinished(TubeWrapper*,Tp::PendingStreamTubeConnection*)));
    connect(tube.data(),
            SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
            SLOT(onTubeInvalidated(Tp::DBusProxy*,QString,QString)));
    mPriv->tubes.insert(tube, wrapper);

    emit tubeOffered(acc, incoming);

    // TODO: accept the tube, connect accept result to tracking wrapper, if successful before tube
    // is invalidated, emit tubeAcceptedAsTcp/Unix, if failure close tube and emit tubeClosed with
    // the acceptTubeAs*Socket() PendingOperation error, if invalidated first, just emit tubeClosed
    // and remove from tracking
}

void StreamTubeClient::onAcceptFinished(TubeWrapper *wrapper, PendingStreamTubeConnection *conn)
{
    Q_ASSERT(wrapper != NULL);
    Q_ASSERT(conn != NULL);

    if (!mPriv->tubes.contains(wrapper->mTube)) {
        debug() << "StreamTubeClient ignoring Accept result for invalidated tube"
            << wrapper->mTube->objectPath();
        return;
    }

    if (conn->isError()) {
        warning() << "StreamTubeClient couldn't accept tube" << wrapper->mTube->objectPath() << '-'
            << conn->errorName() << ':' << conn->errorMessage();

        if (wrapper->mTube->isValid())
            wrapper->mTube->requestClose();

        wrapper->mTube->disconnect(this);
        emit tubeClosed(wrapper->mAcc, wrapper->mTube, conn->errorName(), conn->errorMessage());
        mPriv->tubes.remove(wrapper->mTube);
        wrapper->deleteLater();
        return;
    }

    debug() << "StreamTubeClient accepted tube" << wrapper->mTube->objectPath();

    if (conn->addressType() == SocketAddressTypeIPv4
            || conn->addressType() == SocketAddressTypeIPv6) {
        QPair<QHostAddress, quint16> addr = conn->ipAddress();
        emit tubeAcceptedAsTcp(wrapper->mAcc, wrapper->mTube, addr.first, addr.second,
                wrapper->sourceAddress, wrapper->sourcePort);
    } else {
        emit tubeAcceptedAsUnix(wrapper->mAcc, wrapper->mTube, conn->localAddress(),
                conn->requiresCredentials(), conn->credentialByte());
    }
}

void StreamTubeClient::onTubeInvalidated(Tp::DBusProxy *proxy, const QString &error,
        const QString &message)
{
    StreamTubeChannelPtr tube(qobject_cast<StreamTubeChannel *>(proxy));
    Q_ASSERT(!tube.isNull());

    TubeWrapper *wrapper = mPriv->tubes.value(tube);
    if (!wrapper) {
        // Accept finish with error already removed it
        return;
    }

    debug() << "Client StreamTube" << tube->objectPath() << "invalidated - " << error << ':'
        << message;

    emit tubeClosed(wrapper->mAcc, wrapper->mTube, error, message);
    mPriv->tubes.remove(tube);
    wrapper->deleteLater();
}

} // Tp
<|endoftext|>


<commit_before>//
// SceneOSG.cpp
//
// Implementation of vtScene for the OSG library
//
// Copyright (c) 2001-2004 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "ProjectedShadows.h"

#include <osg/LightSource>
#include <osg/PolygonMode>
#include <osg/Switch>
#include <osg/Fog>
#include <osgDB/Registry>
#include <time.h>		// clock() & CLOCKS_PER_SEC

#ifdef __FreeBSD__
#  include <sys/types.h>
#  include <sys/time.h>
#  include <sys/resource.h>
#endif

#include <iostream>
#include "vtdata/vtLog.h"

using namespace osg;

///////////////////////////////////////////////////////////////
// Trap for OSG messages
//

class OsgMsgTrap : public std::streambuf
{
public:
	inline virtual int_type overflow(int_type c = std::streambuf::traits_type::eof())
	{
		if (c == std::streambuf::traits_type::eof()) return std::streambuf::traits_type::not_eof(c);
		g_Log._Log((char) c);
		return c;
	}
} g_Trap;

///////////////////////////////////////////////////////////////

// There is always and only one global vtScene object
vtScene g_Scene;

vtScene::vtScene() : vtSceneBase()
{
	m_bInitialized = false;
	m_bWireframe = false;
	m_bWinInfo = false;
}

vtScene::~vtScene()
{
	// Do not release camera, that is left for the application.
}

vtScene *vtGetScene()
{
	return &g_Scene;
}

float vtGetTime()
{
	return g_Scene.GetTime();
}

float vtGetFrameTime()
{
	return g_Scene.GetFrameTime();
}

void vtScene::SetBgColor(RGBf color)
{
	Vec4 color2;
	v2s(color, color2);
	m_pOsgSceneView->setClearColor(color2);
}

bool vtScene::Init()
{
	// Redirect cout messages (where OSG sends its messages) to our own log
	std::cout.rdbuf(&g_Trap);
	std::cerr.rdbuf(&g_Trap);

	SetCamera(new vtCamera());

	m_pOsgSceneView = new osgUtil::SceneView();
	m_pOsgSceneView->setDefaults();

	// OSG 0.9.0 and newer
	m_pOsgSceneView->setComputeNearFarMode(osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR);

	m_pOsgSceneView->setLightingMode(osgUtil::SceneView::NO_SCENEVIEW_LIGHT);

	// OSG 0.9.2 and newer: turn off "small feature culling"
	m_pOsgSceneView->setCullingMode( m_pOsgSceneView->getCullingMode() & ~osg::CullStack::SMALL_FEATURE_CULLING);

	m_bInitialized = true;

	_initialTick = _timer.tick();
	_frameTick = _initialTick;

	return true;
}

void vtScene::Shutdown()
{
	vtNode::ClearOsgModelCache();
	osgDB::Registry::instance()->clearObjectCache();
}

void vtScene::DoUpdate()
{
	if (!m_bInitialized)
		return;

	_lastFrameTick = _frameTick;
	_frameTick = _timer.tick();

	DoEngines();

	// As of OSG 0.9.5, we need to store our own camera params and recreate
	//  the projection matrix each frame.
	float aspect;
	if (m_WindowSize.x == 0 || m_WindowSize.y == 0)		// safety
		aspect = 1.0;
	else
		aspect = (float) m_WindowSize.x / m_WindowSize.y;

	if (m_pCamera->IsOrtho())
	{
		// Arguments are left, right, bottom, top, zNear, zFar
		float w2 = m_pCamera->GetWidth() /2;
		float h2 = w2 / aspect;
		m_pOsgSceneView->setProjectionMatrixAsOrtho(-w2, w2, -h2, h2,
			m_pCamera->GetHither(), m_pCamera->GetYon());
	}
	else
	{
		float fov_x = m_pCamera->GetFOV();
		float a = tan (fov_x/2);
		float b = a / aspect;
		float fov_y_div2 = atan(b);
		float fov_y_deg = RadiansToDegrees(fov_y_div2 * 2);

		m_pOsgSceneView->setProjectionMatrixAsPerspective(fov_y_deg,
			aspect, m_pCamera->GetHither(), m_pCamera->GetYon());
	}

	// And apply the rotation and translation of the camera itself
	osg::Matrix &mat2 = m_pCamera->m_pTransform->getMatrix();
	osg::Matrix imat;
	imat.invert(mat2);
	m_pOsgSceneView->setViewMatrix(imat);

	CalcCullPlanes();

	m_pOsgSceneView->setViewport(0, 0, m_WindowSize.x, m_WindowSize.y);
	m_pOsgSceneView->cull();
	m_pOsgSceneView->draw();
}

void vtScene::SetRoot(vtGroup *pRoot)
{
	if (pRoot)
		m_pOsgSceneRoot = pRoot->GetOsgGroup();
	else
		m_pOsgSceneRoot = NULL;
	if (m_pOsgSceneView != NULL)
		m_pOsgSceneView->setSceneData(m_pOsgSceneRoot.get());
	m_pRoot = pRoot;
}

/**
 * Convert window coordinates (in pixels) to a ray from the camera
 * in world coordinates.
 */
bool vtScene::CameraRay(const IPoint2 &win, FPoint3 &pos, FPoint3 &dir)
{
	Vec3 near_point, far_point, diff;

	// call the handy OSG function
	m_pOsgSceneView->projectWindowXYIntoObject(win.x, m_WindowSize.y-win.y, near_point, far_point);

	diff = far_point - near_point;
	diff.normalize();

	s2v(near_point, pos);
	s2v(diff, dir);

	return true;
}

// Debugging helper
void LogCullPlanes(FPlane *planes)
{
	for (int i = 0; i < 4; i++)
		VTLOG(" plane %d: %.3f %.3f %.3f %.3f\n", i, planes[i].x, planes[i].y, planes[i].z, planes[i].w);
	VTLOG("\n");
}

void vtScene::CalcCullPlanes()
{
#if 0
	// Non-API-Specific code - will work correctly as long as the Camera
	// methods are fully functional.
	FMatrix4 mat;
	m_pCamera->GetTransform1(mat);

	assert(( m_WindowSize.x > 0 ) && ( m_WindowSize.y > 0 ));

	double fov = m_pCamera->GetFOV();

	double aspect = (float)m_WindowSize.y / m_WindowSize.x;
	double hither = m_pCamera->GetHither();

	double a = hither * tan(fov / 2);
	double b = a * aspect;

	FPoint3 vec_l(-a, 0, -hither);
	FPoint3 vec_r(a, 0, -hither);
	FPoint3 vec_t(0, b, -hither);
	FPoint3 vec_b(0, -b, -hither);

	vec_l.Normalize();
	vec_r.Normalize();
	vec_t.Normalize();
	vec_b.Normalize();

	FPoint3 up(0.0f, 1.0f, 0.0f);
	FPoint3 right(1.0f, 0.0f, 0.0f);

	FPoint3 temp;

	FPoint3 center;
	FPoint3 norm_l, norm_r, norm_t, norm_b;

	temp = up.Cross(vec_l);
	mat.TransformVector(temp, norm_l);

	temp = vec_r.Cross(up);
	mat.TransformVector(temp, norm_r);

	temp = right.Cross(vec_t);
	mat.TransformVector(temp, norm_t);

	temp = vec_b.Cross(right);
	mat.TransformVector(temp, norm_b);

	mat.Transform(FPoint3(0.0f, 0.0f, 0.0f), center);

	// set up m_cullPlanes in world coordinates!
	m_cullPlanes[0].Set(center, norm_l);
	m_cullPlanes[1].Set(center, norm_r);
	m_cullPlanes[2].Set(center, norm_t);
	m_cullPlanes[3].Set(center, norm_b);
#else
	// Get the view frustum clipping planes directly from OSG

	// OSG 0.8.44
//	const ClippingVolume &clipvol = pCam->m_pOsgCamera->getClippingVolume();
	// OSG 0.8.45
//	const ClippingVolume &clipvol = hack_global_state->getClippingVolume();
	// OSG 0.9.0
	// clipvol1 is the global camera frustum (in world coordinates)
//	const Polytope &clipvol1 = pCam->m_pOsgCamera->getViewFrustum();
	// OSG 0.9.6
	// clipvol2 is the camera's frustum after it's been transformed to the
	//		local coordinates.
//	const Polytope &clipvol2 = hack_global_state->getViewFrustum();
//	const Polytope::PlaneList &planes = clipvol2.getPlaneList();
	// Actually no - we can't get the planes from the state, because
	//  the state includes the funny modelview matrix used to scale
	//  the heightfield.  We must get it from the 'scene' instead.

	osg::Matrixd &_projection = m_pOsgSceneView->getProjectionMatrix();
	osg::Matrixd &_modelView = m_pOsgSceneView->getViewMatrix();

	Polytope tope;
	tope.setToUnitFrustum();
	tope.transformProvidingInverse((_modelView)*(_projection));

	const Polytope::PlaneList &planes = tope.getPlaneList();

	int i = 0;
	for (Polytope::PlaneList::const_iterator itr=planes.begin();
		itr!=planes.end(); ++itr)
	{
		// make a copy of the clipping plane
		Plane plane = *itr;

		// extract the OSG plane to our own structure
		Vec4 pvec = plane.asVec4();
		m_cullPlanes[i++].Set(-pvec.x(), -pvec.y(), -pvec.z(), -pvec.w());
	}
#endif

	// For debugging
//	LogCullPlanes(m_cullPlanes);
}

void vtScene::DrawFrameRateChart()
{
	static float fps[100];
	static int s = 0;
	fps[s] = GetFrameRate();

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

//	glMatrixMode(GL_PROJECTION);
//	glLoadIdentity();

	glDisable(GL_TEXTURE_2D);
	glDisable(GL_LIGHTING);
	glColor3f(1.0f, 1.0f, 0.0f);

	glBegin(GL_LINE_STRIP);
	for (int i = 1; i <= 100; i++)
	{
		glVertex3f(-1.0 + i/200.0f, -1.0f + fps[(s+i)%100]/200.0f, 0.0f);
	}
	glEnd();

	s++;
	if (s == 100) s = 0;
}

void vtScene::SetGlobalWireframe(bool bWire)
{
	m_bWireframe = bWire;

	// Set the scene's global PolygonMode attribute, which will affect all
	// other materials in the scene, except those which explicitly override
	// the attribute themselves.
	StateSet *global_state = m_pOsgSceneView->getGlobalStateSet();
	PolygonMode *npm = new PolygonMode();
	if (m_bWireframe)
		npm->setMode(PolygonMode::FRONT_AND_BACK, PolygonMode::LINE);
	else
		npm->setMode(PolygonMode::FRONT_AND_BACK, PolygonMode::FILL);
	global_state->setAttributeAndModes(npm, StateAttribute::ON);
}

bool vtScene::GetGlobalWireframe()
{
	return m_bWireframe;
}

void vtScene::SetShadowedNode(vtTransform *pLight, vtNode *pShadowNode,
							  vtTransform *pTransform, int iRez)
{
	if (!m_pShadowVisitor.valid())
		m_pShadowVisitor = new CreateProjectedShadowTextureCullCallback(pShadowNode->GetOsgNode(), iRez);
	else
		m_pShadowVisitor->SetShadower(pShadowNode->GetOsgNode());
		m_pShadowVisitor->SetInitialLightPosition(v2s(-(pLight->GetDirection()) * 10000));
		pTransform->GetOsgNode()->setCullCallback(m_pShadowVisitor.get());
#ifdef _DEBUG
	{
		osg::Group *pGroup = (osg::Group*)pTransform->GetOsgNode();
		osg::Geode *pGeode = (osg::Geode*)pGroup->getChild(0);
		osg::Drawable* pDrawable = pGeode->getDrawable(0);
		pDrawable->setDrawCallback(new MyDrawCallback);
	}
#endif
}

void vtScene::UnsetShadowedNode(vtTransform *pTransform)
{
	pTransform->GetOsgNode()->setCullCallback(NULL);
#ifdef _DEBUG
	{
		osg::Group *pGroup = (osg::Group*)pTransform->GetOsgNode();
		osg::Geode *pGeode = (osg::Geode*)pGroup->getChild(0);
		osg::Drawable* pDrawable = pGeode->getDrawable(0);
		pDrawable->setDrawCallback(NULL);
	}
#endif
}

void vtScene::UpdateShadowLightDirection(vtTransform *pLight)
{
	if (m_pShadowVisitor.valid())
	{
		m_pShadowVisitor.get()->SetLightPosition(v2s(-(pLight->GetDirection()) * 10000));
	}
}

////////////////////////////////////////

<commit_msg>added ShadowVisibleNode (from Mark Baily)<commit_after>//
// SceneOSG.cpp
//
// Implementation of vtScene for the OSG library
//
// Copyright (c) 2001-2004 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "ProjectedShadows.h"

#include <osg/LightSource>
#include <osg/PolygonMode>
#include <osg/Switch>
#include <osg/Fog>
#include <osgDB/Registry>
#include <time.h>		// clock() & CLOCKS_PER_SEC

#ifdef __FreeBSD__
#  include <sys/types.h>
#  include <sys/time.h>
#  include <sys/resource.h>
#endif

#include <iostream>
#include "vtdata/vtLog.h"

using namespace osg;

///////////////////////////////////////////////////////////////
// Trap for OSG messages
//

class OsgMsgTrap : public std::streambuf
{
public:
	inline virtual int_type overflow(int_type c = std::streambuf::traits_type::eof())
	{
		if (c == std::streambuf::traits_type::eof()) return std::streambuf::traits_type::not_eof(c);
		g_Log._Log((char) c);
		return c;
	}
} g_Trap;

///////////////////////////////////////////////////////////////

// There is always and only one global vtScene object
vtScene g_Scene;

vtScene::vtScene() : vtSceneBase()
{
	m_bInitialized = false;
	m_bWireframe = false;
	m_bWinInfo = false;
}

vtScene::~vtScene()
{
	// Do not release camera, that is left for the application.
}

vtScene *vtGetScene()
{
	return &g_Scene;
}

float vtGetTime()
{
	return g_Scene.GetTime();
}

float vtGetFrameTime()
{
	return g_Scene.GetFrameTime();
}

void vtScene::SetBgColor(RGBf color)
{
	Vec4 color2;
	v2s(color, color2);
	m_pOsgSceneView->setClearColor(color2);
}

bool vtScene::Init()
{
	// Redirect cout messages (where OSG sends its messages) to our own log
	std::cout.rdbuf(&g_Trap);
	std::cerr.rdbuf(&g_Trap);

	SetCamera(new vtCamera());

	m_pOsgSceneView = new osgUtil::SceneView();
	m_pOsgSceneView->setDefaults();

	// OSG 0.9.0 and newer
	m_pOsgSceneView->setComputeNearFarMode(osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR);

	m_pOsgSceneView->setLightingMode(osgUtil::SceneView::NO_SCENEVIEW_LIGHT);

	// OSG 0.9.2 and newer: turn off "small feature culling"
	m_pOsgSceneView->setCullingMode( m_pOsgSceneView->getCullingMode() & ~osg::CullStack::SMALL_FEATURE_CULLING);

	m_bInitialized = true;

	_initialTick = _timer.tick();
	_frameTick = _initialTick;

	return true;
}

void vtScene::Shutdown()
{
	vtNode::ClearOsgModelCache();
	osgDB::Registry::instance()->clearObjectCache();
}

void vtScene::DoUpdate()
{
	if (!m_bInitialized)
		return;

	_lastFrameTick = _frameTick;
	_frameTick = _timer.tick();

	DoEngines();

	// As of OSG 0.9.5, we need to store our own camera params and recreate
	//  the projection matrix each frame.
	float aspect;
	if (m_WindowSize.x == 0 || m_WindowSize.y == 0)		// safety
		aspect = 1.0;
	else
		aspect = (float) m_WindowSize.x / m_WindowSize.y;

	if (m_pCamera->IsOrtho())
	{
		// Arguments are left, right, bottom, top, zNear, zFar
		float w2 = m_pCamera->GetWidth() /2;
		float h2 = w2 / aspect;
		m_pOsgSceneView->setProjectionMatrixAsOrtho(-w2, w2, -h2, h2,
			m_pCamera->GetHither(), m_pCamera->GetYon());
	}
	else
	{
		float fov_x = m_pCamera->GetFOV();
		float a = tan (fov_x/2);
		float b = a / aspect;
		float fov_y_div2 = atan(b);
		float fov_y_deg = RadiansToDegrees(fov_y_div2 * 2);

		m_pOsgSceneView->setProjectionMatrixAsPerspective(fov_y_deg,
			aspect, m_pCamera->GetHither(), m_pCamera->GetYon());
	}

	// And apply the rotation and translation of the camera itself
	osg::Matrix &mat2 = m_pCamera->m_pTransform->getMatrix();
	osg::Matrix imat;
	imat.invert(mat2);
	m_pOsgSceneView->setViewMatrix(imat);

	CalcCullPlanes();

	m_pOsgSceneView->setViewport(0, 0, m_WindowSize.x, m_WindowSize.y);
	m_pOsgSceneView->cull();
	m_pOsgSceneView->draw();
}

void vtScene::SetRoot(vtGroup *pRoot)
{
	if (pRoot)
		m_pOsgSceneRoot = pRoot->GetOsgGroup();
	else
		m_pOsgSceneRoot = NULL;
	if (m_pOsgSceneView != NULL)
		m_pOsgSceneView->setSceneData(m_pOsgSceneRoot.get());
	m_pRoot = pRoot;
}

/**
 * Convert window coordinates (in pixels) to a ray from the camera
 * in world coordinates.
 */
bool vtScene::CameraRay(const IPoint2 &win, FPoint3 &pos, FPoint3 &dir)
{
	Vec3 near_point, far_point, diff;

	// call the handy OSG function
	m_pOsgSceneView->projectWindowXYIntoObject(win.x, m_WindowSize.y-win.y, near_point, far_point);

	diff = far_point - near_point;
	diff.normalize();

	s2v(near_point, pos);
	s2v(diff, dir);

	return true;
}

// Debugging helper
void LogCullPlanes(FPlane *planes)
{
	for (int i = 0; i < 4; i++)
		VTLOG(" plane %d: %.3f %.3f %.3f %.3f\n", i, planes[i].x, planes[i].y, planes[i].z, planes[i].w);
	VTLOG("\n");
}

void vtScene::CalcCullPlanes()
{
#if 0
	// Non-API-Specific code - will work correctly as long as the Camera
	// methods are fully functional.
	FMatrix4 mat;
	m_pCamera->GetTransform1(mat);

	assert(( m_WindowSize.x > 0 ) && ( m_WindowSize.y > 0 ));

	double fov = m_pCamera->GetFOV();

	double aspect = (float)m_WindowSize.y / m_WindowSize.x;
	double hither = m_pCamera->GetHither();

	double a = hither * tan(fov / 2);
	double b = a * aspect;

	FPoint3 vec_l(-a, 0, -hither);
	FPoint3 vec_r(a, 0, -hither);
	FPoint3 vec_t(0, b, -hither);
	FPoint3 vec_b(0, -b, -hither);

	vec_l.Normalize();
	vec_r.Normalize();
	vec_t.Normalize();
	vec_b.Normalize();

	FPoint3 up(0.0f, 1.0f, 0.0f);
	FPoint3 right(1.0f, 0.0f, 0.0f);

	FPoint3 temp;

	FPoint3 center;
	FPoint3 norm_l, norm_r, norm_t, norm_b;

	temp = up.Cross(vec_l);
	mat.TransformVector(temp, norm_l);

	temp = vec_r.Cross(up);
	mat.TransformVector(temp, norm_r);

	temp = right.Cross(vec_t);
	mat.TransformVector(temp, norm_t);

	temp = vec_b.Cross(right);
	mat.TransformVector(temp, norm_b);

	mat.Transform(FPoint3(0.0f, 0.0f, 0.0f), center);

	// set up m_cullPlanes in world coordinates!
	m_cullPlanes[0].Set(center, norm_l);
	m_cullPlanes[1].Set(center, norm_r);
	m_cullPlanes[2].Set(center, norm_t);
	m_cullPlanes[3].Set(center, norm_b);
#else
	// Get the view frustum clipping planes directly from OSG

	// OSG 0.8.44
//	const ClippingVolume &clipvol = pCam->m_pOsgCamera->getClippingVolume();
	// OSG 0.8.45
//	const ClippingVolume &clipvol = hack_global_state->getClippingVolume();
	// OSG 0.9.0
	// clipvol1 is the global camera frustum (in world coordinates)
//	const Polytope &clipvol1 = pCam->m_pOsgCamera->getViewFrustum();
	// OSG 0.9.6
	// clipvol2 is the camera's frustum after it's been transformed to the
	//		local coordinates.
//	const Polytope &clipvol2 = hack_global_state->getViewFrustum();
//	const Polytope::PlaneList &planes = clipvol2.getPlaneList();
	// Actually no - we can't get the planes from the state, because
	//  the state includes the funny modelview matrix used to scale
	//  the heightfield.  We must get it from the 'scene' instead.

	osg::Matrixd &_projection = m_pOsgSceneView->getProjectionMatrix();
	osg::Matrixd &_modelView = m_pOsgSceneView->getViewMatrix();

	Polytope tope;
	tope.setToUnitFrustum();
	tope.transformProvidingInverse((_modelView)*(_projection));

	const Polytope::PlaneList &planes = tope.getPlaneList();

	int i = 0;
	for (Polytope::PlaneList::const_iterator itr=planes.begin();
		itr!=planes.end(); ++itr)
	{
		// make a copy of the clipping plane
		Plane plane = *itr;

		// extract the OSG plane to our own structure
		Vec4 pvec = plane.asVec4();
		m_cullPlanes[i++].Set(-pvec.x(), -pvec.y(), -pvec.z(), -pvec.w());
	}
#endif

	// For debugging
//	LogCullPlanes(m_cullPlanes);
}

void vtScene::DrawFrameRateChart()
{
	static float fps[100];
	static int s = 0;
	fps[s] = GetFrameRate();

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

//	glMatrixMode(GL_PROJECTION);
//	glLoadIdentity();

	glDisable(GL_TEXTURE_2D);
	glDisable(GL_LIGHTING);
	glColor3f(1.0f, 1.0f, 0.0f);

	glBegin(GL_LINE_STRIP);
	for (int i = 1; i <= 100; i++)
	{
		glVertex3f(-1.0 + i/200.0f, -1.0f + fps[(s+i)%100]/200.0f, 0.0f);
	}
	glEnd();

	s++;
	if (s == 100) s = 0;
}

void vtScene::SetGlobalWireframe(bool bWire)
{
	m_bWireframe = bWire;

	// Set the scene's global PolygonMode attribute, which will affect all
	// other materials in the scene, except those which explicitly override
	// the attribute themselves.
	StateSet *global_state = m_pOsgSceneView->getGlobalStateSet();
	PolygonMode *npm = new PolygonMode();
	if (m_bWireframe)
		npm->setMode(PolygonMode::FRONT_AND_BACK, PolygonMode::LINE);
	else
		npm->setMode(PolygonMode::FRONT_AND_BACK, PolygonMode::FILL);
	global_state->setAttributeAndModes(npm, StateAttribute::ON);
}

bool vtScene::GetGlobalWireframe()
{
	return m_bWireframe;
}

void printnode(osg::Node *node, int tab) {
	for (int i = 0; i < tab*2; i++) {
	   osg::notify(osg::WARN) << " ";
	}
	osg::notify(osg::WARN) << node->className() << " - " << node->getName() << " @ " << node << std::endl;
	osg::Group *group = node->asGroup();
	if (group) {
		for (int i = 0; i < group->getNumChildren(); i++) {
			printnode(group->getChild(i), tab+1);
		}
	}
}

void vtScene::ShadowVisibleNode(vtNode *node, bool bVis)
{
	if (!bVis) {
		m_pShadowVisitor->shadow_ignore_nodes->Append(node->GetOsgNode());
	}
	else {
		int i = m_pShadowVisitor->shadow_ignore_nodes->Find(node->GetOsgNode());
		if (i != -1) {
			m_pShadowVisitor->shadow_ignore_nodes->RemoveAt(i);
		}
	}
	m_pShadowVisitor->RecomputeShadows();
}

void vtScene::SetShadowedNode(vtTransform *pLight, vtNode *pShadowNode,
							  vtTransform *pTransform, int iRez)
{
	if (!m_pShadowVisitor.valid())
		m_pShadowVisitor = new CreateProjectedShadowTextureCullCallback(pShadowNode->GetOsgNode(), iRez);
	else
		m_pShadowVisitor->SetShadower(pShadowNode->GetOsgNode());
		m_pShadowVisitor->SetInitialLightPosition(v2s(-(pLight->GetDirection()) * 10000));
		pTransform->GetOsgNode()->setCullCallback(m_pShadowVisitor.get());
		m_pShadowVisitor->SetEnabled(true);

		osg::Node *node = pShadowNode->GetOsgNode();

#ifdef _DEBUG
	{
		osg::Group *pGroup = (osg::Group*)pTransform->GetOsgNode();
		osg::Geode *pGeode = (osg::Geode*)pGroup->getChild(0);
		osg::Drawable* pDrawable = pGeode->getDrawable(0);
		pDrawable->setDrawCallback(new MyDrawCallback);
	}
#endif
}

void vtScene::UnsetShadowedNode(vtTransform *pTransform)
{
	pTransform->GetOsgNode()->setCullCallback(NULL);
#ifdef _DEBUG
	{
		osg::Group *pGroup = (osg::Group*)pTransform->GetOsgNode();
		osg::Geode *pGeode = (osg::Geode*)pGroup->getChild(0);
		osg::Drawable* pDrawable = pGeode->getDrawable(0);
		pDrawable->setDrawCallback(NULL);
	}
#endif
}

void vtScene::UpdateShadowLightDirection(vtTransform *pLight)
{
	if (m_pShadowVisitor.valid())
	{
		m_pShadowVisitor.get()->SetLightPosition(v2s(-(pLight->GetDirection()) * 10000));
	}
}

////////////////////////////////////////

<|endoftext|>


<commit_before><commit_msg>COMP: round method have been changed to floor+0.5 for Windows comp issue.<commit_after><|endoftext|>


<commit_before>#include <api/gpu/compute.h>

#include <algorithm>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
#include <util/error.h>
#include <util/log.h>
#include <util/util.h>

namespace gpu {
namespace compute {

namespace {
    using std::string;
    using std::stringstream;
    using std::vector;

    typedef string extension;
    typedef vector<extension> extension_vector;

    void append_extensions(const extension& in, extension_vector& out)
    {
        typedef std::istream_iterator<extension> iter;
        auto ss = stringstream(in);
        std::copy(iter(ss), iter(), std::back_inserter(out));
    }

    bool check_extension_requirements(const extension_vector& required, const extension_vector& supported)
    {
        return std::all_of(required.begin(), required.end(), [&supported](const extension& extension) {
            return std::find(supported.begin(), supported.end(), extension) != supported.end(); });
    }

    compute::device get_device(cl_device_type device_type, const extension_vector& required_extensions)
    {
        vector<compute::platform> platforms;
        compute::platform::get(&platforms);
        for (auto& platform : platforms) {
            extension_vector platform_extensions;
            append_extensions(platform.getInfo<CL_PLATFORM_EXTENSIONS>(), platform_extensions);

            std::vector<compute::device> devices;
            platform.getDevices(device_type, &devices);
            for (const auto& device : devices) {
                extension_vector device_extensions = platform_extensions;
                append_extensions(device.getInfo<CL_DEVICE_EXTENSIONS>(), device_extensions);

                if (check_extension_requirements(required_extensions, device_extensions))
                    return device;
            }
        }

        DIE("No suitable compute device found.");
        return compute::device();
    }

} // unnamed namespace

command_queue init(os::window::graphics_context graphics_context)
{
    extension_vector required_extensions = { "cl_khr_gl_sharing", "cl_khr_gl_event" };

    auto c_device = get_device(CL_DEVICE_TYPE_GPU, required_extensions);
    auto c_platform_id = c_device.getInfo<CL_DEVICE_PLATFORM>();

    cl_context_properties context_properties[] = {
        CL_CONTEXT_PLATFORM, reinterpret_cast<cl_context_properties>(c_platform_id),
        CL_GL_CONTEXT_KHR, reinterpret_cast<cl_context_properties>(graphics_context),
        0 };
    auto c_context = context(c_device, context_properties, nullptr, nullptr);

    return command_queue(c_context, c_device, cl::QueueProperties::Profiling);
}

program create_program_from_file(context c_context, const char *file_name)
{
    auto source = util::read_file_contents(file_name);
    auto res = program(c_context, source, false);
    auto devices = c_context.getInfo<CL_CONTEXT_DEVICES>();

    try {
        res.build(devices);
    } catch (cl::Error e) {
        for (auto device : devices) {
            auto device_name = device.getInfo<CL_DEVICE_NAME>();
            auto build_log = res.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device);
            LOG("%s: %s\n", device_name.c_str(), build_log.c_str());
        }
        throw;
    }

    return res;
}

const char *get_error_string(cl_int status)
{
    switch (status) {
    // run-time and JIT compiler errors
    case 0: return "CL_SUCCESS";
    case -1: return "CL_DEVICE_NOT_FOUND";
    case -2: return "CL_DEVICE_NOT_AVAILABLE";
    case -3: return "CL_COMPILER_NOT_AVAILABLE";
    case -4: return "CL_MEM_OBJECT_ALLOCATION_FAILURE";
    case -5: return "CL_OUT_OF_RESOURCES";
    case -6: return "CL_OUT_OF_HOST_MEMORY";
    case -7: return "CL_PROFILING_INFO_NOT_AVAILABLE";
    case -8: return "CL_MEM_COPY_OVERLAP";
    case -9: return "CL_IMAGE_FORMAT_MISMATCH";
    case -10: return "CL_IMAGE_FORMAT_NOT_SUPPORTED";
    case -11: return "CL_BUILD_PROGRAM_FAILURE";
    case -12: return "CL_MAP_FAILURE";
    case -13: return "CL_MISALIGNED_SUB_BUFFER_OFFSET";
    case -14: return "CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST";
    case -15: return "CL_COMPILE_PROGRAM_FAILURE";
    case -16: return "CL_LINKER_NOT_AVAILABLE";
    case -17: return "CL_LINK_PROGRAM_FAILURE";
    case -18: return "CL_DEVICE_PARTITION_FAILED";
    case -19: return "CL_KERNEL_ARG_INFO_NOT_AVAILABLE";

    // compile-time errors
    case -30: return "CL_INVALID_VALUE";
    case -31: return "CL_INVALID_DEVICE_TYPE";
    case -32: return "CL_INVALID_PLATFORM";
    case -33: return "CL_INVALID_DEVICE";
    case -34: return "CL_INVALID_CONTEXT";
    case -35: return "CL_INVALID_QUEUE_PROPERTIES";
    case -36: return "CL_INVALID_COMMAND_QUEUE";
    case -37: return "CL_INVALID_HOST_PTR";
    case -38: return "CL_INVALID_MEM_OBJECT";
    case -39: return "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR";
    case -40: return "CL_INVALID_IMAGE_SIZE";
    case -41: return "CL_INVALID_SAMPLER";
    case -42: return "CL_INVALID_BINARY";
    case -43: return "CL_INVALID_BUILD_OPTIONS";
    case -44: return "CL_INVALID_PROGRAM";
    case -45: return "CL_INVALID_PROGRAM_EXECUTABLE";
    case -46: return "CL_INVALID_KERNEL_NAME";
    case -47: return "CL_INVALID_KERNEL_DEFINITION";
    case -48: return "CL_INVALID_KERNEL";
    case -49: return "CL_INVALID_ARG_INDEX";
    case -50: return "CL_INVALID_ARG_VALUE";
    case -51: return "CL_INVALID_ARG_SIZE";
    case -52: return "CL_INVALID_KERNEL_ARGS";
    case -53: return "CL_INVALID_WORK_DIMENSION";
    case -54: return "CL_INVALID_WORK_GROUP_SIZE";
    case -55: return "CL_INVALID_WORK_ITEM_SIZE";
    case -56: return "CL_INVALID_GLOBAL_OFFSET";
    case -57: return "CL_INVALID_EVENT_WAIT_LIST";
    case -58: return "CL_INVALID_EVENT";
    case -59: return "CL_INVALID_OPERATION";
    case -60: return "CL_INVALID_GL_OBJECT";
    case -61: return "CL_INVALID_BUFFER_SIZE";
    case -62: return "CL_INVALID_MIP_LEVEL";
    case -63: return "CL_INVALID_GLOBAL_WORK_SIZE";
    case -64: return "CL_INVALID_PROPERTY";
    case -65: return "CL_INVALID_IMAGE_DESCRIPTOR";
    case -66: return "CL_INVALID_COMPILER_OPTIONS";
    case -67: return "CL_INVALID_LINKER_OPTIONS";
    case -68: return "CL_INVALID_DEVICE_PARTITION_COUNT";

    // extension errors
    case -1000: return "CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR";
    case -1001: return "CL_PLATFORM_NOT_FOUND_KHR";
    case -1002: return "CL_INVALID_D3D10_DEVICE_KHR";
    case -1003: return "CL_INVALID_D3D10_RESOURCE_KHR";
    case -1004: return "CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR";
    case -1005: return "CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR";
    default: return "Unknown error";
    }
}

} // namespace compute
} // namespace gpu
<commit_msg>add verbose output on unsupported extension<commit_after>#include <api/gpu/compute.h>

#include <algorithm>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
#include <util/error.h>
#include <util/log.h>
#include <util/util.h>

namespace gpu {
namespace compute {

namespace {
    using std::string;
    using std::stringstream;
    using std::vector;

    typedef string extension;
    typedef vector<extension> extension_vector;

    void append_extensions(const extension& in, extension_vector& out)
    {
        typedef std::istream_iterator<extension> iter;
        auto ss = stringstream(in);
        std::copy(iter(ss), iter(), std::back_inserter(out));
    }

    bool check_extension_requirements(const extension_vector& required, const extension_vector& supported)
    {
        return std::all_of(required.begin(), required.end(), [&supported](const extension& extension) {
            return std::find(supported.begin(), supported.end(), extension) != supported.end(); });
    }

    std::string dump_extensions(const gpu::compute::extension_vector& extensions)
    {
        std::stringstream ss;
        for (int i = 0; i < extensions.size(); ++i) {
            if (i != 0)
                ss << ", ";
            ss << extensions[i];
        }
        return ss.str();
    }

    compute::device get_device(cl_device_type device_type, const extension_vector& required_extensions)
    {
        vector<compute::platform> platforms;
        compute::platform::get(&platforms);
        for (auto& platform : platforms) {
            extension_vector platform_extensions;
            append_extensions(platform.getInfo<CL_PLATFORM_EXTENSIONS>(), platform_extensions);

            std::vector<compute::device> devices;
            platform.getDevices(device_type, &devices);
            for (const auto& device : devices) {
                extension_vector device_extensions = platform_extensions;
                append_extensions(device.getInfo<CL_DEVICE_EXTENSIONS>(), device_extensions);

                if (check_extension_requirements(required_extensions, device_extensions)) {
                    return device;
                } else {
                    LOG("Found GPU device '%s', but some required extensions are not supported.\n", device.getInfo<CL_DEVICE_NAME>().c_str());
                    LOG("  required extensions are: %s\n", dump_extensions(required_extensions).c_str());
                    LOG("  device extensions are: %s\n", dump_extensions(device_extensions).c_str());
                }
            }
        }

        DIE("No suitable compute device found.");
        return compute::device();
    }

} // unnamed namespace

command_queue init(os::window::graphics_context graphics_context)
{
    extension_vector required_extensions = { "cl_khr_gl_sharing", "cl_khr_gl_event" };

    auto c_device = get_device(CL_DEVICE_TYPE_GPU, required_extensions);
    auto c_platform_id = c_device.getInfo<CL_DEVICE_PLATFORM>();

    cl_context_properties context_properties[] = {
        CL_CONTEXT_PLATFORM, reinterpret_cast<cl_context_properties>(c_platform_id),
        CL_GL_CONTEXT_KHR, reinterpret_cast<cl_context_properties>(graphics_context),
        0 };
    auto c_context = context(c_device, context_properties, nullptr, nullptr);

    return command_queue(c_context, c_device, cl::QueueProperties::Profiling);
}

program create_program_from_file(context c_context, const char *file_name)
{
    auto source = util::read_file_contents(file_name);
    auto res = program(c_context, source, false);
    auto devices = c_context.getInfo<CL_CONTEXT_DEVICES>();

    try {
        res.build(devices);
    } catch (cl::Error e) {
        for (auto device : devices) {
            auto device_name = device.getInfo<CL_DEVICE_NAME>();
            auto build_log = res.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device);
            LOG("%s: %s\n", device_name.c_str(), build_log.c_str());
        }
        throw;
    }

    return res;
}

const char *get_error_string(cl_int status)
{
    switch (status) {
    // run-time and JIT compiler errors
    case 0: return "CL_SUCCESS";
    case -1: return "CL_DEVICE_NOT_FOUND";
    case -2: return "CL_DEVICE_NOT_AVAILABLE";
    case -3: return "CL_COMPILER_NOT_AVAILABLE";
    case -4: return "CL_MEM_OBJECT_ALLOCATION_FAILURE";
    case -5: return "CL_OUT_OF_RESOURCES";
    case -6: return "CL_OUT_OF_HOST_MEMORY";
    case -7: return "CL_PROFILING_INFO_NOT_AVAILABLE";
    case -8: return "CL_MEM_COPY_OVERLAP";
    case -9: return "CL_IMAGE_FORMAT_MISMATCH";
    case -10: return "CL_IMAGE_FORMAT_NOT_SUPPORTED";
    case -11: return "CL_BUILD_PROGRAM_FAILURE";
    case -12: return "CL_MAP_FAILURE";
    case -13: return "CL_MISALIGNED_SUB_BUFFER_OFFSET";
    case -14: return "CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST";
    case -15: return "CL_COMPILE_PROGRAM_FAILURE";
    case -16: return "CL_LINKER_NOT_AVAILABLE";
    case -17: return "CL_LINK_PROGRAM_FAILURE";
    case -18: return "CL_DEVICE_PARTITION_FAILED";
    case -19: return "CL_KERNEL_ARG_INFO_NOT_AVAILABLE";

    // compile-time errors
    case -30: return "CL_INVALID_VALUE";
    case -31: return "CL_INVALID_DEVICE_TYPE";
    case -32: return "CL_INVALID_PLATFORM";
    case -33: return "CL_INVALID_DEVICE";
    case -34: return "CL_INVALID_CONTEXT";
    case -35: return "CL_INVALID_QUEUE_PROPERTIES";
    case -36: return "CL_INVALID_COMMAND_QUEUE";
    case -37: return "CL_INVALID_HOST_PTR";
    case -38: return "CL_INVALID_MEM_OBJECT";
    case -39: return "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR";
    case -40: return "CL_INVALID_IMAGE_SIZE";
    case -41: return "CL_INVALID_SAMPLER";
    case -42: return "CL_INVALID_BINARY";
    case -43: return "CL_INVALID_BUILD_OPTIONS";
    case -44: return "CL_INVALID_PROGRAM";
    case -45: return "CL_INVALID_PROGRAM_EXECUTABLE";
    case -46: return "CL_INVALID_KERNEL_NAME";
    case -47: return "CL_INVALID_KERNEL_DEFINITION";
    case -48: return "CL_INVALID_KERNEL";
    case -49: return "CL_INVALID_ARG_INDEX";
    case -50: return "CL_INVALID_ARG_VALUE";
    case -51: return "CL_INVALID_ARG_SIZE";
    case -52: return "CL_INVALID_KERNEL_ARGS";
    case -53: return "CL_INVALID_WORK_DIMENSION";
    case -54: return "CL_INVALID_WORK_GROUP_SIZE";
    case -55: return "CL_INVALID_WORK_ITEM_SIZE";
    case -56: return "CL_INVALID_GLOBAL_OFFSET";
    case -57: return "CL_INVALID_EVENT_WAIT_LIST";
    case -58: return "CL_INVALID_EVENT";
    case -59: return "CL_INVALID_OPERATION";
    case -60: return "CL_INVALID_GL_OBJECT";
    case -61: return "CL_INVALID_BUFFER_SIZE";
    case -62: return "CL_INVALID_MIP_LEVEL";
    case -63: return "CL_INVALID_GLOBAL_WORK_SIZE";
    case -64: return "CL_INVALID_PROPERTY";
    case -65: return "CL_INVALID_IMAGE_DESCRIPTOR";
    case -66: return "CL_INVALID_COMPILER_OPTIONS";
    case -67: return "CL_INVALID_LINKER_OPTIONS";
    case -68: return "CL_INVALID_DEVICE_PARTITION_COUNT";

    // extension errors
    case -1000: return "CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR";
    case -1001: return "CL_PLATFORM_NOT_FOUND_KHR";
    case -1002: return "CL_INVALID_D3D10_DEVICE_KHR";
    case -1003: return "CL_INVALID_D3D10_RESOURCE_KHR";
    case -1004: return "CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR";
    case -1005: return "CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR";
    default: return "Unknown error";
    }
}

} // namespace compute
} // namespace gpu
<|endoftext|>


<commit_before>/*
 * @COPYRIGHT@
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE
 */

#include <clxx/app/clinfo/main.hpp>
#include <clxx/exception.hpp>
#include <iostream>

int main(int argc, char const* argv[])
{
  try
    {
      return clxx::app::clinfo::run(argc, argv);
    }
  catch(std::exception const& e)
    {
      std::cerr << "error: " << e.what() << std::endl;
    }
  catch(...)
    {
      std::cerr << "error: caught unhandled exception" << std::endl;
    }
  return 1;
}
<commit_msg>include <exception> instead of <clxx/exception.hpp> in clinfo app<commit_after>/*
 * @COPYRIGHT@
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE
 */

#include <clxx/app/clinfo/main.hpp>
#include <exception>
#include <iostream>

int main(int argc, char const* argv[])
{
  try
    {
      return clxx::app::clinfo::run(argc, argv);
    }
  catch(std::exception const& e)
    {
      std::cerr << "error: " << e.what() << std::endl;
    }
  catch(...)
    {
      std::cerr << "error: caught unhandled exception" << std::endl;
    }
  return 1;
}
<|endoftext|>


<commit_before>/******************************************************************************
 *
 * Project:  laszip - http://liblas.org -
 * Purpose:
 * Author:   Martin Isenburg
 *           isenburg at cs.unc.edu
 *
 ******************************************************************************
 * Copyright (c) 2009, Martin Isenburg
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Licence as published
 * by the Free Software Foundation.
 *
 * See the COPYING file for more information.
 *
 ****************************************************************************/

/*
===============================================================================

  FILE:  arithmeticmodel.cpp

  CONTENTS:

    see header file

  PROGRAMMERS:

    martin isenburg@cs.unc.edu

  COPYRIGHT:

    copyright (C) 2009  martin isenburg@cs.unc.edu

    This software is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  CHANGE HISTORY:

    see header file

===============================================================================
*/
#include "arithmeticmodel.h"

#include <stdio.h>
#include <stdlib.h>

void AC_ERROR(const char* msg) {
  fprintf(stderr, "Arithmetic coding ERROR: %s\n", msg); exit(1);
};

ArithmeticModel::ArithmeticModel(unsigned int n, unsigned int *init, int compress)
{
  data_symbols = 0;
  distribution = 0;
  reset(n, init, compress);
}

ArithmeticModel::~ArithmeticModel()
{
  if (distribution) delete [] distribution;
}

void ArithmeticModel::reset(unsigned int n, unsigned int *init, int compress)
{
  if ( (n < 2) || (n > (1 << 11)) ) AC_ERROR("invalid number of symbols");

  if (data_symbols != n) {
    data_symbols = n;
    last_symbol = data_symbols - 1;
    if (distribution) delete [] distribution;
                                     // define size of table for fast decoding
    if ((compress == 0) && (data_symbols > 16)) {
      unsigned int table_bits = 3;
      while (data_symbols > (1U << (table_bits + 2))) ++table_bits;
      table_size  = 1 << table_bits;
      table_shift = DM__LengthShift - table_bits;
      distribution = new unsigned int[2*data_symbols+table_size+2];
      decoder_table = distribution + 2 * data_symbols;
    }
    else {                                  // small alphabet: no table needed
      decoder_table = 0;
      table_size = table_shift = 0;
      distribution = new unsigned int[2*data_symbols];
    }
    if (distribution == 0) AC_ERROR("cannot allocate model memory");
    symbol_count = distribution + data_symbols;
  }

  total_count = 0;
  update_cycle = data_symbols;
  if (init)
    for (unsigned int k = 0; k < data_symbols; k++) symbol_count[k] = init[k];
  else
    for (unsigned int k = 0; k < data_symbols; k++) symbol_count[k] = 1;

  update(compress == 1);
  symbols_until_update = update_cycle = (data_symbols + 6) >> 1;
}

void ArithmeticModel::update(bool from_encoder)
{
                                   // halve counts when a threshold is reached
  if ((total_count += update_cycle) > DM__MaxCount) {
    total_count = 0;
    for (unsigned int n = 0; n < data_symbols; n++)
      total_count += (symbol_count[n] = (symbol_count[n] + 1) >> 1);
  }
                             // compute cumulative distribution, decoder table
  unsigned int k, sum = 0, s = 0;
  unsigned int scale = 0x80000000U / total_count;

  if (from_encoder || (table_size == 0))
    for (k = 0; k < data_symbols; k++) {
      distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
      sum += symbol_count[k];
    }
  else {
    for (k = 0; k < data_symbols; k++) {
      distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
      sum += symbol_count[k];
      unsigned int w = distribution[k] >> table_shift;
      while (s < w) decoder_table[++s] = k - 1;
    }
    decoder_table[0] = 0;
    while (s <= table_size) decoder_table[++s] = data_symbols - 1;
  }
                                             // set frequency of model updates
  update_cycle = (5 * update_cycle) >> 2;
  unsigned int max_cycle = (data_symbols + 6) << 3;
  if (update_cycle > max_cycle) update_cycle = max_cycle;
  symbols_until_update = update_cycle;
}

ArithmeticBitModel::ArithmeticBitModel()
{
  reset();
}

ArithmeticBitModel::~ArithmeticBitModel()
{
}

void ArithmeticBitModel::reset()
{
                                       // initialization to equiprobable model
  bit_0_count = 1;
  bit_count   = 2;
  bit_0_prob  = 1U << (BM__LengthShift - 1);
  update_cycle = bits_until_update = 4;         // start with frequent updates
}

void ArithmeticBitModel::update()
{
                                   // halve counts when a threshold is reached
  if ((bit_count += update_cycle) > BM__MaxCount) {
    bit_count = (bit_count + 1) >> 1;
    bit_0_count = (bit_0_count + 1) >> 1;
    if (bit_0_count == bit_count) ++bit_count;
  }
                                           // compute scaled bit 0 probability
  unsigned int scale = 0x80000000U / bit_count;
  bit_0_prob = (bit_0_count * scale) >> (31 - BM__LengthShift);

                                             // set frequency of model updates
  update_cycle = (5 * update_cycle) >> 2;
  if (update_cycle > 64) update_cycle = 64;
  bits_until_update = update_cycle;
}
<commit_msg>remove extraneous ;<commit_after>/******************************************************************************
 *
 * Project:  laszip - http://liblas.org -
 * Purpose:
 * Author:   Martin Isenburg
 *           isenburg at cs.unc.edu
 *
 ******************************************************************************
 * Copyright (c) 2009, Martin Isenburg
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Licence as published
 * by the Free Software Foundation.
 *
 * See the COPYING file for more information.
 *
 ****************************************************************************/

/*
===============================================================================

  FILE:  arithmeticmodel.cpp

  CONTENTS:

    see header file

  PROGRAMMERS:

    martin isenburg@cs.unc.edu

  COPYRIGHT:

    copyright (C) 2009  martin isenburg@cs.unc.edu

    This software is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  CHANGE HISTORY:

    see header file

===============================================================================
*/
#include "arithmeticmodel.h"

#include <stdio.h>
#include <stdlib.h>

void AC_ERROR(const char* msg) {
  fprintf(stderr, "Arithmetic coding ERROR: %s\n", msg); exit(1);
}

ArithmeticModel::ArithmeticModel(unsigned int n, unsigned int *init, int compress)
{
  data_symbols = 0;
  distribution = 0;
  reset(n, init, compress);
}

ArithmeticModel::~ArithmeticModel()
{
  if (distribution) delete [] distribution;
}

void ArithmeticModel::reset(unsigned int n, unsigned int *init, int compress)
{
  if ( (n < 2) || (n > (1 << 11)) ) AC_ERROR("invalid number of symbols");

  if (data_symbols != n) {
    data_symbols = n;
    last_symbol = data_symbols - 1;
    if (distribution) delete [] distribution;
                                     // define size of table for fast decoding
    if ((compress == 0) && (data_symbols > 16)) {
      unsigned int table_bits = 3;
      while (data_symbols > (1U << (table_bits + 2))) ++table_bits;
      table_size  = 1 << table_bits;
      table_shift = DM__LengthShift - table_bits;
      distribution = new unsigned int[2*data_symbols+table_size+2];
      decoder_table = distribution + 2 * data_symbols;
    }
    else {                                  // small alphabet: no table needed
      decoder_table = 0;
      table_size = table_shift = 0;
      distribution = new unsigned int[2*data_symbols];
    }
    if (distribution == 0) AC_ERROR("cannot allocate model memory");
    symbol_count = distribution + data_symbols;
  }

  total_count = 0;
  update_cycle = data_symbols;
  if (init)
    for (unsigned int k = 0; k < data_symbols; k++) symbol_count[k] = init[k];
  else
    for (unsigned int k = 0; k < data_symbols; k++) symbol_count[k] = 1;

  update(compress == 1);
  symbols_until_update = update_cycle = (data_symbols + 6) >> 1;
}

void ArithmeticModel::update(bool from_encoder)
{
                                   // halve counts when a threshold is reached
  if ((total_count += update_cycle) > DM__MaxCount) {
    total_count = 0;
    for (unsigned int n = 0; n < data_symbols; n++)
      total_count += (symbol_count[n] = (symbol_count[n] + 1) >> 1);
  }
                             // compute cumulative distribution, decoder table
  unsigned int k, sum = 0, s = 0;
  unsigned int scale = 0x80000000U / total_count;

  if (from_encoder || (table_size == 0))
    for (k = 0; k < data_symbols; k++) {
      distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
      sum += symbol_count[k];
    }
  else {
    for (k = 0; k < data_symbols; k++) {
      distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
      sum += symbol_count[k];
      unsigned int w = distribution[k] >> table_shift;
      while (s < w) decoder_table[++s] = k - 1;
    }
    decoder_table[0] = 0;
    while (s <= table_size) decoder_table[++s] = data_symbols - 1;
  }
                                             // set frequency of model updates
  update_cycle = (5 * update_cycle) >> 2;
  unsigned int max_cycle = (data_symbols + 6) << 3;
  if (update_cycle > max_cycle) update_cycle = max_cycle;
  symbols_until_update = update_cycle;
}

ArithmeticBitModel::ArithmeticBitModel()
{
  reset();
}

ArithmeticBitModel::~ArithmeticBitModel()
{
}

void ArithmeticBitModel::reset()
{
                                       // initialization to equiprobable model
  bit_0_count = 1;
  bit_count   = 2;
  bit_0_prob  = 1U << (BM__LengthShift - 1);
  update_cycle = bits_until_update = 4;         // start with frequent updates
}

void ArithmeticBitModel::update()
{
                                   // halve counts when a threshold is reached
  if ((bit_count += update_cycle) > BM__MaxCount) {
    bit_count = (bit_count + 1) >> 1;
    bit_0_count = (bit_0_count + 1) >> 1;
    if (bit_0_count == bit_count) ++bit_count;
  }
                                           // compute scaled bit 0 probability
  unsigned int scale = 0x80000000U / bit_count;
  bit_0_prob = (bit_0_count * scale) >> (31 - BM__LengthShift);

                                             // set frequency of model updates
  update_cycle = (5 * update_cycle) >> 2;
  if (update_cycle > 64) update_cycle = 64;
  bits_until_update = update_cycle;
}
<|endoftext|>