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

#include <iostream>
#include <string>

#include "src/common/testing/gtest.h"

namespace raksha {
namespace {

class RefCountedType {
 public:
  RefCountedType(std::string id = "<unknown>", bool some_flag = false)
      : id_(id), some_flag_(some_flag), count_(0) {}

  unsigned int count() const { return count_; }
  bool some_flag() const { return some_flag_; }
  void set_id(std::string id) { std::swap(id_, id); }
  const std::string& id() const { return id_; }
  void Retain() { count_++; }
  void Release() {
    count_--;
    if (count_ == 0) {
      delete this;
    }
  }

 private:
  std::string id_;
  bool some_flag_;
  unsigned int count_;
};

class RefCountedTypeDerived: public RefCountedType {};

using RefCountedTypePtr = intrusive_ptr<RefCountedType>;

// We create a raw pointer for test. However, in practice, we should avoid
// creating raw pointers and use `make_intrusive_ptr` factory method to create
// and warp the object immediately.
RefCountedType* MakeRefCountedTypeInstance(std::string id = "<unknown>",
                                           bool some_flag = false) {
  return new RefCountedType(id, some_flag);
}

TEST(IntrusivePtrTest, DefaultConstructorInitializesToNullptr) {
  RefCountedTypePtr null;
  EXPECT_EQ(null.get(), nullptr);
}

TEST(IntrusivePtrTest, ConstructorIncreasesCountAndSavesPtr) {
  RefCountedType* value = MakeRefCountedTypeInstance();
  EXPECT_EQ(value->count(), 0);
  RefCountedTypePtr ptr(value);
  EXPECT_EQ(value->count(), 1);

  EXPECT_EQ(ptr.get(), value);
  // When `ptr` is destroyed, object pointed to by `value` gets destroyed.
}

TEST(IntrusivePtrTest, CopyConstructorIncreasesCountAndSharesPtr) {
  RefCountedType* value = MakeRefCountedTypeInstance();
  EXPECT_EQ(value->count(), 0);
  RefCountedTypePtr ptr(value);
  EXPECT_EQ(value->count(), 1);

  RefCountedTypePtr copy = ptr;
  EXPECT_EQ(value->count(), 2);
  EXPECT_EQ(ptr.get(), copy.get());
  // When `ptr` and `object` are destroyed, object pointed to by `value` gets
  // destroyed.
}

TEST(IntrusivePtrTest, MoveConstructorMaintainsCountAndNullifiesOther) {
  RefCountedType* value = MakeRefCountedTypeInstance();
  EXPECT_EQ(value->count(), 0);
  RefCountedTypePtr ptr(value);
  EXPECT_EQ(value->count(), 1);

  RefCountedTypePtr moved = std::move(ptr);
  EXPECT_EQ(value->count(), 1);
  EXPECT_EQ(ptr.get(), nullptr);
  // When `moved` is destroyed, object pointed to by `value` gets destroyed.
}

TEST(IntrusivePtrTest, AssignmentIncreasesCountAndSharesPtr) {
  RefCountedType* value = MakeRefCountedTypeInstance();
  EXPECT_EQ(value->count(), 0);
  RefCountedTypePtr ptr(value);
  EXPECT_EQ(value->count(), 1);

  RefCountedTypePtr assigned;
  EXPECT_EQ(assigned.get(), nullptr);

  assigned = ptr;
  EXPECT_EQ(value->count(), 2);
  EXPECT_EQ(ptr.get(), assigned.get());
  // When `ptr` and `assigned` are destroyed, the object pointed to by `value`
  // gets destroyed.
}

TEST(IntrusivePtrTest, GetReturnsSavedPointer) {
  auto value = MakeRefCountedTypeInstance();
  RefCountedTypePtr ptr(value);
  EXPECT_EQ(ptr.get(), value);
  // When `ptr` is destroyed, the object pointed to by `value` is destroyed.
}

TEST(IntrusivePtrTest, DereferenceReturnsSavedObject) {
  auto value = MakeRefCountedTypeInstance();
  RefCountedTypePtr ptr(value);
  EXPECT_EQ(&(*ptr), value);
  // When `ptr` is destroyed, the object pointed to by `value` is destroyed.
}

TEST(IntrusivePtrTest, DereferencingNullCausesFailure) {
  EXPECT_DEATH(
      {
        RefCountedTypePtr null;
        EXPECT_EQ((*null).count(), 0);
      },
      "Dereferencing a nullptr!");
}

TEST(IntrusivePtrTest, ArrowOperatorProvidesAccessToSavedPtr) {
  auto value = MakeRefCountedTypeInstance("NewValue");
  RefCountedTypePtr ptr(value);
  EXPECT_EQ(value->id(), "NewValue");
  ptr->set_id("UpdatedValue");
  EXPECT_EQ(value->id(), "UpdatedValue");
  // When `ptr` is destroyed, the object pointed to by `value` is destroyed.
}

TEST(IntrusivePtrTest, FactoryConstructionWorks) {
  auto default_obj = make_intrusive_ptr<RefCountedType>();
  EXPECT_EQ(default_obj->count(), 1);
  EXPECT_EQ(default_obj->id(), "<unknown>");
  EXPECT_EQ(default_obj->some_flag(), false);

  auto ptr = make_intrusive_ptr<RefCountedType>("NewValue");
  EXPECT_EQ(ptr->count(), 1);
  EXPECT_EQ(ptr->id(), "NewValue");
  EXPECT_EQ(ptr->some_flag(), false);

  auto another_ptr = make_intrusive_ptr<RefCountedType>("AnotherValue", true);
  EXPECT_EQ(another_ptr->count(), 1);
  EXPECT_EQ(another_ptr->id(), "AnotherValue");
  EXPECT_EQ(another_ptr->some_flag(), true);
  EXPECT_NE(ptr.get(), another_ptr.get());
  // All objects will be destroyed when the intrusive_pointers go out of scope.
}

TEST(IntrusivePtrTest, CanConvertBetweenConvertiblePtrs){
  auto derived_ptr = make_intrusive_ptr<RefCountedTypeDerived>();
  EXPECT_EQ(derived_ptr->count(), 1);
  intrusive_ptr<RefCountedType> base_ptr(derived_ptr);
  EXPECT_EQ(derived_ptr.get(), base_ptr.get());
  EXPECT_EQ(derived_ptr, base_ptr);
  EXPECT_EQ(derived_ptr->count(), 2);
  EXPECT_EQ(base_ptr->count(), 2);

  intrusive_ptr<RefCountedType> another_base_ptr = derived_ptr;
  EXPECT_EQ(derived_ptr, another_base_ptr);
}

TEST(IntrusivePtrTest, DestructorReducesCount) {
  RefCountedTypePtr ptr = make_intrusive_ptr<RefCountedType>();
  EXPECT_EQ(ptr->count(), 1);
  {
    RefCountedTypePtr copy = ptr;
    EXPECT_EQ(ptr->count(), 2);
    {
      RefCountedTypePtr another_copy = copy;
      EXPECT_EQ(ptr->count(), 3);
      // `another_copy` is destroyed at the end of this scope, but `copy` is
      // alive.
    }
    EXPECT_EQ(ptr->count(), 2);
    // `copy` is destroyed at the end of this scope.
  }
  EXPECT_EQ(ptr->count(), 1);
}

TEST(IntrusivePtrTest, EqualReturnsTrueForIdenticalPtrs) {
  RefCountedTypePtr ptr = make_intrusive_ptr<RefCountedType>();

  RefCountedTypePtr copy = ptr;
  EXPECT_EQ(ptr, copy);

  RefCountedTypePtr another_copy = intrusive_ptr<RefCountedType>(ptr);
  EXPECT_EQ(ptr, another_copy);
}

TEST(IntrusivePtrTest, ComparePtrsOfDifferentTypes) {
  intrusive_ptr<RefCountedTypeDerived> derived_ptr = make_intrusive_ptr<RefCountedTypeDerived>();
  intrusive_ptr<RefCountedType> base_ptr(derived_ptr.get());
  EXPECT_EQ(base_ptr, derived_ptr);
}

TEST(IntrusivePtrTest, NotEqualReturnsTrueDifferentPtrs) {
  RefCountedTypePtr ptr = make_intrusive_ptr<RefCountedType>();
  RefCountedTypePtr another_ptr = make_intrusive_ptr<RefCountedType>();
  EXPECT_NE(ptr, another_ptr);
}

TEST(IntrusivePtrTest, ComparisionAgainstRawPtrs) {
  auto raw_ptr = MakeRefCountedTypeInstance("NewValue");
  RefCountedTypePtr ptr(raw_ptr);
  EXPECT_EQ(ptr, raw_ptr);
  EXPECT_EQ(raw_ptr, ptr);

  auto another_raw_ptr = MakeRefCountedTypeInstance();
  EXPECT_NE(ptr, another_raw_ptr);
  EXPECT_NE(another_raw_ptr, ptr);
}

TEST(IntrusivePtrTest, ComparisionAgainstNullPtrs) {
  RefCountedTypePtr ptr = make_intrusive_ptr<RefCountedType>();
  RefCountedTypePtr null;
  EXPECT_NE(nullptr, ptr);
  EXPECT_NE(ptr, nullptr);
  EXPECT_EQ(null, nullptr);
  EXPECT_EQ(nullptr, null);
}
}  // namespace
}  // namespace raksha
<commit_msg>Fix memory leak in intrusive_ptr_test. (#397)<commit_after>//-----------------------------------------------------------------------------
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//-----------------------------------------------------------------------------
#include "src/utils/intrusive_ptr.h"

#include <iostream>
#include <string>

#include "src/common/testing/gtest.h"

namespace raksha {
namespace {

class RefCountedType {
 public:
  RefCountedType(std::string id = "<unknown>", bool some_flag = false)
      : id_(id), some_flag_(some_flag), count_(0) {}

  unsigned int count() const { return count_; }
  bool some_flag() const { return some_flag_; }
  void set_id(std::string id) { std::swap(id_, id); }
  const std::string& id() const { return id_; }
  void Retain() { count_++; }
  void Release() {
    count_--;
    if (count_ == 0) {
      delete this;
    }
  }

 private:
  std::string id_;
  bool some_flag_;
  unsigned int count_;
};

class RefCountedTypeDerived: public RefCountedType {};

using RefCountedTypePtr = intrusive_ptr<RefCountedType>;

// We create a raw pointer for test. However, in practice, we should avoid
// creating raw pointers and use `make_intrusive_ptr` factory method to create
// and warp the object immediately.
RefCountedType* MakeRefCountedTypeInstance(std::string id = "<unknown>",
                                           bool some_flag = false) {
  return new RefCountedType(id, some_flag);
}

TEST(IntrusivePtrTest, DefaultConstructorInitializesToNullptr) {
  RefCountedTypePtr null;
  EXPECT_EQ(null.get(), nullptr);
}

TEST(IntrusivePtrTest, ConstructorIncreasesCountAndSavesPtr) {
  RefCountedType* value = MakeRefCountedTypeInstance();
  EXPECT_EQ(value->count(), 0);
  RefCountedTypePtr ptr(value);
  EXPECT_EQ(value->count(), 1);

  EXPECT_EQ(ptr.get(), value);
  // When `ptr` is destroyed, object pointed to by `value` gets destroyed.
}

TEST(IntrusivePtrTest, CopyConstructorIncreasesCountAndSharesPtr) {
  RefCountedType* value = MakeRefCountedTypeInstance();
  EXPECT_EQ(value->count(), 0);
  RefCountedTypePtr ptr(value);
  EXPECT_EQ(value->count(), 1);

  RefCountedTypePtr copy = ptr;
  EXPECT_EQ(value->count(), 2);
  EXPECT_EQ(ptr.get(), copy.get());
  // When `ptr` and `object` are destroyed, object pointed to by `value` gets
  // destroyed.
}

TEST(IntrusivePtrTest, MoveConstructorMaintainsCountAndNullifiesOther) {
  RefCountedType* value = MakeRefCountedTypeInstance();
  EXPECT_EQ(value->count(), 0);
  RefCountedTypePtr ptr(value);
  EXPECT_EQ(value->count(), 1);

  RefCountedTypePtr moved = std::move(ptr);
  EXPECT_EQ(value->count(), 1);
  EXPECT_EQ(ptr.get(), nullptr);
  // When `moved` is destroyed, object pointed to by `value` gets destroyed.
}

TEST(IntrusivePtrTest, AssignmentIncreasesCountAndSharesPtr) {
  RefCountedType* value = MakeRefCountedTypeInstance();
  EXPECT_EQ(value->count(), 0);
  RefCountedTypePtr ptr(value);
  EXPECT_EQ(value->count(), 1);

  RefCountedTypePtr assigned;
  EXPECT_EQ(assigned.get(), nullptr);

  assigned = ptr;
  EXPECT_EQ(value->count(), 2);
  EXPECT_EQ(ptr.get(), assigned.get());
  // When `ptr` and `assigned` are destroyed, the object pointed to by `value`
  // gets destroyed.
}

TEST(IntrusivePtrTest, GetReturnsSavedPointer) {
  auto value = MakeRefCountedTypeInstance();
  RefCountedTypePtr ptr(value);
  EXPECT_EQ(ptr.get(), value);
  // When `ptr` is destroyed, the object pointed to by `value` is destroyed.
}

TEST(IntrusivePtrTest, DereferenceReturnsSavedObject) {
  auto value = MakeRefCountedTypeInstance();
  RefCountedTypePtr ptr(value);
  EXPECT_EQ(&(*ptr), value);
  // When `ptr` is destroyed, the object pointed to by `value` is destroyed.
}

TEST(IntrusivePtrTest, DereferencingNullCausesFailure) {
  EXPECT_DEATH(
      {
        RefCountedTypePtr null;
        EXPECT_EQ((*null).count(), 0);
      },
      "Dereferencing a nullptr!");
}

TEST(IntrusivePtrTest, ArrowOperatorProvidesAccessToSavedPtr) {
  auto value = MakeRefCountedTypeInstance("NewValue");
  RefCountedTypePtr ptr(value);
  EXPECT_EQ(value->id(), "NewValue");
  ptr->set_id("UpdatedValue");
  EXPECT_EQ(value->id(), "UpdatedValue");
  // When `ptr` is destroyed, the object pointed to by `value` is destroyed.
}

TEST(IntrusivePtrTest, FactoryConstructionWorks) {
  auto default_obj = make_intrusive_ptr<RefCountedType>();
  EXPECT_EQ(default_obj->count(), 1);
  EXPECT_EQ(default_obj->id(), "<unknown>");
  EXPECT_EQ(default_obj->some_flag(), false);

  auto ptr = make_intrusive_ptr<RefCountedType>("NewValue");
  EXPECT_EQ(ptr->count(), 1);
  EXPECT_EQ(ptr->id(), "NewValue");
  EXPECT_EQ(ptr->some_flag(), false);

  auto another_ptr = make_intrusive_ptr<RefCountedType>("AnotherValue", true);
  EXPECT_EQ(another_ptr->count(), 1);
  EXPECT_EQ(another_ptr->id(), "AnotherValue");
  EXPECT_EQ(another_ptr->some_flag(), true);
  EXPECT_NE(ptr.get(), another_ptr.get());
  // All objects will be destroyed when the intrusive_pointers go out of scope.
}

TEST(IntrusivePtrTest, CanConvertBetweenConvertiblePtrs){
  auto derived_ptr = make_intrusive_ptr<RefCountedTypeDerived>();
  EXPECT_EQ(derived_ptr->count(), 1);
  intrusive_ptr<RefCountedType> base_ptr(derived_ptr);
  EXPECT_EQ(derived_ptr.get(), base_ptr.get());
  EXPECT_EQ(derived_ptr, base_ptr);
  EXPECT_EQ(derived_ptr->count(), 2);
  EXPECT_EQ(base_ptr->count(), 2);

  intrusive_ptr<RefCountedType> another_base_ptr = derived_ptr;
  EXPECT_EQ(derived_ptr, another_base_ptr);
}

TEST(IntrusivePtrTest, DestructorReducesCount) {
  RefCountedTypePtr ptr = make_intrusive_ptr<RefCountedType>();
  EXPECT_EQ(ptr->count(), 1);
  {
    RefCountedTypePtr copy = ptr;
    EXPECT_EQ(ptr->count(), 2);
    {
      RefCountedTypePtr another_copy = copy;
      EXPECT_EQ(ptr->count(), 3);
      // `another_copy` is destroyed at the end of this scope, but `copy` is
      // alive.
    }
    EXPECT_EQ(ptr->count(), 2);
    // `copy` is destroyed at the end of this scope.
  }
  EXPECT_EQ(ptr->count(), 1);
}

TEST(IntrusivePtrTest, EqualReturnsTrueForIdenticalPtrs) {
  RefCountedTypePtr ptr = make_intrusive_ptr<RefCountedType>();

  RefCountedTypePtr copy = ptr;
  EXPECT_EQ(ptr, copy);

  RefCountedTypePtr another_copy = intrusive_ptr<RefCountedType>(ptr);
  EXPECT_EQ(ptr, another_copy);
}

TEST(IntrusivePtrTest, ComparePtrsOfDifferentTypes) {
  intrusive_ptr<RefCountedTypeDerived> derived_ptr = make_intrusive_ptr<RefCountedTypeDerived>();
  intrusive_ptr<RefCountedType> base_ptr(derived_ptr.get());
  EXPECT_EQ(base_ptr, derived_ptr);
}

TEST(IntrusivePtrTest, NotEqualReturnsTrueDifferentPtrs) {
  RefCountedTypePtr ptr = make_intrusive_ptr<RefCountedType>();
  RefCountedTypePtr another_ptr = make_intrusive_ptr<RefCountedType>();
  EXPECT_NE(ptr, another_ptr);
}

TEST(IntrusivePtrTest, ComparisionAgainstRawPtrs) {
  auto raw_ptr = MakeRefCountedTypeInstance("NewValue");
  RefCountedTypePtr ptr(raw_ptr);
  EXPECT_EQ(ptr, raw_ptr);
  EXPECT_EQ(raw_ptr, ptr);

  auto another_raw_ptr = MakeRefCountedTypeInstance();
  RefCountedTypePtr another_ptr(another_raw_ptr);
  EXPECT_NE(ptr, another_raw_ptr);
  EXPECT_NE(another_raw_ptr, ptr);
}

TEST(IntrusivePtrTest, ComparisionAgainstNullPtrs) {
  RefCountedTypePtr ptr = make_intrusive_ptr<RefCountedType>();
  RefCountedTypePtr null;
  EXPECT_NE(nullptr, ptr);
  EXPECT_NE(ptr, nullptr);
  EXPECT_EQ(null, nullptr);
  EXPECT_EQ(nullptr, null);
}
}  // namespace
}  // namespace raksha
<|endoftext|>


<commit_before>// __BEGIN_LICENSE__
// Copyright (C) 2006-2011 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

#include <vw/Plate/SnapshotManager.h>
#include <vw/Plate/detail/MipmapHelpers.h>
#include <vw/Plate/PlateFile.h>
#include <vw/Plate/TileManipulation.h>
#include <vw/Mosaic/ImageComposite.h>
#include <vw/Image/ImageView.h>
#include <boost/foreach.hpp>

namespace d = vw::platefile::detail;

namespace {
  using namespace vw;
  using namespace vw::platefile;

  // row, col at target level, tile headers from next level down (sorted in Tid order)
  typedef std::map<d::rowcol_t, std::vector<d::tile_order_t> > composite_map_t;
  // Cache of parsed images
  template <typename PixelT>
  struct tile_cache_t : public std::map<d::rowcoltid_t, ImageView<PixelT> > {};

  // composite_order_override lets you override the composite order
  void schedule_tile(const TileHeader& hdr, std::vector<d::tile_order_t>& stack, Datastore::TileSearch& tile_lookup, uint32 order) {
    stack.push_back(boost::make_tuple(order, d::rowcoltid_t(hdr.row(), hdr.col(), hdr.transaction_id())));
    tile_lookup.push_back(hdr);
  }

  template <typename PixelT>
  void parse_image_and_store(const Tile& t, tile_cache_t<PixelT>& tile_cache) {
    ImageView<PixelT>& image = tile_cache[d::rowcoltid_t(t.hdr.row(), t.hdr.col(), t.hdr.transaction_id())];
    boost::scoped_ptr<SrcImageResource> r(SrcMemoryImageResource::open(t.hdr.filetype(), &t.data->operator[](0), t.data->size()));
    read_image(image, *r);
  }
}

namespace vw {
namespace platefile {

template <class PixelT>
void SnapshotManager<PixelT>::snapshot(uint32 level, BBox2i const& tile_region, TransactionRange range, const ProgressCallback &progress_) const {
  typedef ImageView<PixelT> image_t;

  const uint64 TILE_BYTES  = m_platefile->default_tile_size() * m_platefile->default_tile_size() * uint32(PixelNumBytes<PixelT>::value);
  const uint64 CACHE_BYTES = uint64(2) * 1024 * 1024 * 1024; // 2GB
  const uint64 REGION_SIZE = boost::numeric_cast<uint64>(sqrt(CACHE_BYTES / TILE_BYTES));

  // Divide up the region into moderately-sized chunks
  std::list<BBox2i> regions = bbox_tiles(tile_region, REGION_SIZE, REGION_SIZE);
  BOOST_FOREACH(const BBox2i& region, regions) {
    SubProgressCallback progress(progress_, progress_.progress(), progress_.progress() + 1./regions.size());

    // Declare these inside the loop so we keep the memory use down to a dull roar
    // This map holds the headers for the current level
    composite_map_t composite_map;
    tile_cache_t<PixelT> tile_cache;

    {
      // List of tiles we need to fetch
      Datastore::TileSearch tile_lookup;

      // Grab the tiles in the zone
      BOOST_FOREACH(const TileHeader& hdr, m_platefile->search_by_region(level, region, range))
        schedule_tile(hdr, composite_map[d::rowcol_t(hdr.row(), hdr.col())], tile_lookup, hdr.transaction_id());

      // Now load the images from disk, decode them, and store them back to the cache
      d::RememberCallback tile_load_pc(progress, 0.2, tile_lookup.size());
      BOOST_FOREACH(const Tile& t, m_platefile->batch_read(tile_lookup)) {
        parse_image_and_store(t, tile_cache);
        tile_load_pc.tick();
      }
    }

    {
      d::RememberCallback composite_pc(progress, 0.8, composite_map.size());
      // now iterate the output tile set and create the composites
      BOOST_FOREACH(composite_map_t::value_type& t, composite_map) {
        std::sort(t.second.begin(), t.second.end(), d::SortByTidDesc());
        mosaic::ImageComposite<PixelT> composite;
        composite.set_draft_mode(true);
        // Insert the images into the composite from highest to lowest tid (already sorted due to SoryByTidDesc)
        BOOST_FOREACH(const d::tile_order_t& order, t.second) {
          const d::rowcoltid_t& hdr = order.get<1>();
          image_t& img = tile_cache[d::rowcoltid_t(d::therow(hdr), d::thecol(hdr), d::thetid(hdr))];
          if (!img) {
            vw_out(WarningMessage, "platefile.snapshot") << "Failed to load image for " << hdr << std::endl;
            continue;
          }
          composite.insert(img, 0, 0);
          if (is_opaque(img))
            break;
        }
        if (composite.cols() == 0 || composite.rows() == 0) {
          vw_out(WarningMessage, "platefile.snapshot") << "Empty tile list, skipping writing tile row=" << d::therow(t.first) << " col=" << d::thecol(t.first) << std::endl;
          continue;
        }
        composite.prepare(BBox2i(0,0,m_platefile->default_tile_size(), m_platefile->default_tile_size()));
        image_t tile = composite;
        m_platefile->write_update(tile, d::thecol(t.first), d::therow(t.first), level);
        composite_pc.tick();
      }
    }
  }
  progress_.report_finished();
}

// Create a full snapshot of every level and every region in the mosaic.
template <class PixelT>
void SnapshotManager<PixelT>::full_snapshot(TransactionRange read_transaction_range) const {
  for (int32 level = m_platefile->num_levels()-1; level >= 0; --level) {
    TerminalProgressCallback prog("plate.snapshot", std::string("Snapshot level ") + stringify(level));
    snapshot(level, d::move_down(BBox2i(0,0,1,1), level), read_transaction_range, prog);
  }
}

}} // namespace vw::platefile

// Explicit template instatiation
#define _VW_INSTANTIATE(Px)\
  template\
  void vw::platefile::SnapshotManager<Px >::snapshot(uint32 level, BBox2i const& bbox, TransactionRange, const ProgressCallback &progress) const;\
  template\
  void vw::platefile::SnapshotManager<Px >::full_snapshot(TransactionRange) const;

_VW_INSTANTIATE(vw::PixelGrayA<vw::uint8>);
_VW_INSTANTIATE(vw::PixelGrayA<vw::int16>);
_VW_INSTANTIATE(vw::PixelGrayA<vw::float32>);
_VW_INSTANTIATE(vw::PixelRGBA<vw::uint8>);
<commit_msg>round the block size to nearest power of two<commit_after>// __BEGIN_LICENSE__
// Copyright (C) 2006-2011 United States Government as represented by
// the Administrator of the National Aeronautics and Space Administration.
// All Rights Reserved.
// __END_LICENSE__

#include <vw/Plate/SnapshotManager.h>
#include <vw/Plate/detail/MipmapHelpers.h>
#include <vw/Plate/PlateFile.h>
#include <vw/Plate/TileManipulation.h>
#include <vw/Mosaic/ImageComposite.h>
#include <vw/Image/ImageView.h>
#include <boost/foreach.hpp>

namespace d = vw::platefile::detail;

namespace {
  using namespace vw;
  using namespace vw::platefile;

  // row, col at target level, tile headers from next level down (sorted in Tid order)
  typedef std::map<d::rowcol_t, std::vector<d::tile_order_t> > composite_map_t;
  // Cache of parsed images
  template <typename PixelT>
  struct tile_cache_t : public std::map<d::rowcoltid_t, ImageView<PixelT> > {};

  // composite_order_override lets you override the composite order
  void schedule_tile(const TileHeader& hdr, std::vector<d::tile_order_t>& stack, Datastore::TileSearch& tile_lookup, uint32 order) {
    stack.push_back(boost::make_tuple(order, d::rowcoltid_t(hdr.row(), hdr.col(), hdr.transaction_id())));
    tile_lookup.push_back(hdr);
  }

  template <typename PixelT>
  void parse_image_and_store(const Tile& t, tile_cache_t<PixelT>& tile_cache) {
    ImageView<PixelT>& image = tile_cache[d::rowcoltid_t(t.hdr.row(), t.hdr.col(), t.hdr.transaction_id())];
    boost::scoped_ptr<SrcImageResource> r(SrcMemoryImageResource::open(t.hdr.filetype(), &t.data->operator[](0), t.data->size()));
    read_image(image, *r);
  }
}

namespace vw {
namespace platefile {

template <class PixelT>
void SnapshotManager<PixelT>::snapshot(uint32 level, BBox2i const& tile_region, TransactionRange range, const ProgressCallback &progress_) const {
  typedef ImageView<PixelT> image_t;

  const uint64 TILE_BYTES  = m_platefile->default_tile_size() * m_platefile->default_tile_size() * uint32(PixelNumBytes<PixelT>::value);
  const uint64 CACHE_BYTES = uint64(2) * 1024 * 1024 * 1024; // 2GB
  const uint64 REGION_SIZE = 1 << boost::numeric_cast<uint32>(::floor(::log(::sqrt(CACHE_BYTES / TILE_BYTES)) / ::log(2)));
  VW_ASSERT(REGION_SIZE > 0, LogicErr() << "Cannot iterate regions with REGION_SIZE 0");

  // Divide up the region into moderately-sized chunks
  std::list<BBox2i> regions = bbox_tiles(tile_region, REGION_SIZE, REGION_SIZE);
  BOOST_FOREACH(const BBox2i& region, regions) {
    SubProgressCallback progress(progress_, progress_.progress(), progress_.progress() + 1./regions.size());

    // Declare these inside the loop so we keep the memory use down to a dull roar
    // This map holds the headers for the current level
    composite_map_t composite_map;
    tile_cache_t<PixelT> tile_cache;

    {
      // List of tiles we need to fetch
      Datastore::TileSearch tile_lookup;

      // Grab the tiles in the zone
      BOOST_FOREACH(const TileHeader& hdr, m_platefile->search_by_region(level, region, range))
        schedule_tile(hdr, composite_map[d::rowcol_t(hdr.row(), hdr.col())], tile_lookup, hdr.transaction_id());

      // Now load the images from disk, decode them, and store them back to the cache
      d::RememberCallback tile_load_pc(progress, 0.2, tile_lookup.size());
      BOOST_FOREACH(const Tile& t, m_platefile->batch_read(tile_lookup)) {
        parse_image_and_store(t, tile_cache);
        tile_load_pc.tick();
      }
    }

    {
      d::RememberCallback composite_pc(progress, 0.8, composite_map.size());
      // now iterate the output tile set and create the composites
      BOOST_FOREACH(composite_map_t::value_type& t, composite_map) {
        std::sort(t.second.begin(), t.second.end(), d::SortByTidDesc());
        mosaic::ImageComposite<PixelT> composite;
        composite.set_draft_mode(true);
        // Insert the images into the composite from highest to lowest tid (already sorted due to SoryByTidDesc)
        BOOST_FOREACH(const d::tile_order_t& order, t.second) {
          const d::rowcoltid_t& hdr = order.get<1>();
          image_t& img = tile_cache[d::rowcoltid_t(d::therow(hdr), d::thecol(hdr), d::thetid(hdr))];
          if (!img) {
            vw_out(WarningMessage, "platefile.snapshot") << "Failed to load image for " << hdr << std::endl;
            continue;
          }
          composite.insert(img, 0, 0);
          if (is_opaque(img))
            break;
        }
        if (composite.cols() == 0 || composite.rows() == 0) {
          vw_out(WarningMessage, "platefile.snapshot") << "Empty tile list, skipping writing tile row=" << d::therow(t.first) << " col=" << d::thecol(t.first) << std::endl;
          continue;
        }
        composite.prepare(BBox2i(0,0,m_platefile->default_tile_size(), m_platefile->default_tile_size()));
        image_t tile = composite;
        m_platefile->write_update(tile, d::thecol(t.first), d::therow(t.first), level);
        composite_pc.tick();
      }
    }
  }
  progress_.report_finished();
}

// Create a full snapshot of every level and every region in the mosaic.
template <class PixelT>
void SnapshotManager<PixelT>::full_snapshot(TransactionRange read_transaction_range) const {
  for (int32 level = m_platefile->num_levels()-1; level >= 0; --level) {
    TerminalProgressCallback prog("plate.snapshot", std::string("Snapshot level ") + stringify(level));
    snapshot(level, d::move_down(BBox2i(0,0,1,1), level), read_transaction_range, prog);
  }
}

}} // namespace vw::platefile

// Explicit template instatiation
#define _VW_INSTANTIATE(Px)\
  template\
  void vw::platefile::SnapshotManager<Px >::snapshot(uint32 level, BBox2i const& bbox, TransactionRange, const ProgressCallback &progress) const;\
  template\
  void vw::platefile::SnapshotManager<Px >::full_snapshot(TransactionRange) const;

_VW_INSTANTIATE(vw::PixelGrayA<vw::uint8>);
_VW_INSTANTIATE(vw::PixelGrayA<vw::int16>);
_VW_INSTANTIATE(vw::PixelGrayA<vw::float32>);
_VW_INSTANTIATE(vw::PixelRGBA<vw::uint8>);
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.4  2002/11/04 15:17:00  tng
 * C++ Namespace Support.
 *
 * Revision 1.3  2002/10/15 18:11:02  knoaman
 * [Bug 13489]: missing 'return' in Token.cpp
 *
 * Revision 1.2  2002/03/18 19:29:53  knoaman
 * Change constant names to eliminate possible conflict with user defined ones.
 *
 * Revision 1.1.1.1  2002/02/01 22:22:31  peiyongz
 * sane_include
 *
 * Revision 1.3  2001/05/11 13:26:50  tng
 * Copyright update.
 *
 * Revision 1.2  2001/05/03 18:17:49  knoaman
 * Some design changes:
 * o Changed the TokenFactory from a single static instance, to a
 *    normal class. Each RegularExpression object will have its own
 *    instance of TokenFactory, and that instance will be passed to
 *    other classes that need to use a TokenFactory to create Token
 *    objects (with the exception of RangeTokenMap).
 * o Added a new class RangeTokenMap to map a the different ranges
 *    in a given category to a specific RangeFactory object. In the old
 *    design RangeFactory had dual functionality (act as a Map, and as
 *    a factory for creating RangeToken(s)). The RangeTokenMap will
 *    have its own copy of the TokenFactory. There will be only one
 *    instance of the RangeTokenMap class, and that instance will be
 *    lazily deleted when XPlatformUtils::Terminate is called.
 *
 * Revision 1.1  2001/03/02 19:22:58  knoaman
 * Schema: Regular expression handling part I
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/regx/RangeToken.hpp>
#include <xercesc/util/regx/ModifierToken.hpp>
#include <xercesc/util/regx/RegularExpression.hpp>
#include <xercesc/util/regx/RegxUtil.hpp>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  Static member data initialization
// ---------------------------------------------------------------------------
const XMLInt32		 Token::UTF16_MAX = 0x10FFFF;
const unsigned short Token::FC_CONTINUE = 0;
const unsigned short Token::FC_TERMINAL = 1;
const unsigned short Token::FC_ANY = 2;

// ---------------------------------------------------------------------------
//  Token: Constructors and Destructors
// ---------------------------------------------------------------------------
Token::Token(const unsigned short tokType) : fTokenType(tokType) {

}

Token::~Token() {

}

// ---------------------------------------------------------------------------
//  Token: Getter mthods
// ---------------------------------------------------------------------------
int Token::getMinLength() const {

	switch (fTokenType) {

	case T_CONCAT:
        {
            int sum = 0;
            unsigned int childSize = size();

            for (unsigned int i=0; i<childSize; i++) {
                sum += getChild(i)->getMinLength();
            }
            return sum;
        }
	case T_CONDITION:
	case T_UNION:
        {
			unsigned int childSize = size();

            if (childSize == 0) {
                return 0;
            }
			int ret = getChild(0)->getMinLength();

            for (unsigned int i=1; i < childSize; i++) {

                int min = getChild(i)->getMinLength();
                if (min < ret)
                    ret = min;
            }
			return ret;
        }
	case T_CLOSURE:
	case T_NONGREEDYCLOSURE:
        if (getMin() >= 0)
            return getMin() * getChild(0)->getMinLength();

		return 0;
	case T_EMPTY:
	case T_ANCHOR:
		return 0;
	case T_DOT:
	case T_CHAR:
	case T_RANGE:
	case T_NRANGE:
		return 1;
	case T_INDEPENDENT:
	case T_PAREN:
	case T_MODIFIERGROUP:
		return getChild(0)->getMinLength();
	case T_BACKREFERENCE:
		return 0; // *****  - REVISIT
	case T_STRING:
		return XMLString::stringLen(getString());
	case T_LOOKAHEAD:
	case T_NEGATIVELOOKAHEAD:
	case T_LOOKBEHIND:
	case T_NEGATIVELOOKBEHIND:
		return 0; // *****  - REVIST
//	default:
//		throw;
	}

	// We should not get here, but we have it to make some compilers happy
	return -1;
}

int Token::getMaxLength() const {

	switch (fTokenType) {

	case T_CONCAT:
        {
            int sum = 0;
            unsigned int childSize = size();

            for (unsigned int i=0; i<childSize; i++) {

                int val = getChild(i)->getMaxLength();

				if (val < 0){
					return -1;
				}
                sum += val;
            }
            return sum;
        }
    case T_CONDITION:
    case T_UNION:
        {
            unsigned int childSize = size();

			if (childSize == 0)
                return 0;

            int ret = getChild(0)->getMaxLength();

            for (unsigned i = 1; ret > 0 && i < childSize; i++) {

                int max = getChild(i)->getMaxLength();

                if (max < 0) {

                    ret = -1;
                    break;
                }

                if (max > ret)
                    ret = max;
            }
			return ret;
        }
    case T_CLOSURE:
    case T_NONGREEDYCLOSURE:
        if (getMax() >= 0) {
            return getMax() * getChild(0)->getMaxLength();
		}
		return -1;
    case T_EMPTY:
    case T_ANCHOR:
        return 0;
    case T_CHAR:
        return 1;
    case T_DOT:
    case T_RANGE:
    case T_NRANGE:
        return 2;
    case T_INDEPENDENT:
    case T_PAREN:
    case T_MODIFIERGROUP:
        return getChild(0)->getMaxLength();
    case T_BACKREFERENCE:
		return -1; // REVISIT
    case T_STRING:
        return XMLString::stringLen(getString());
    case T_LOOKAHEAD:
    case T_NEGATIVELOOKAHEAD:
    case T_LOOKBEHIND:
    case T_NEGATIVELOOKBEHIND:
		return 0; // REVISIT
//    default:
//		throw; //ThrowXML(RuntimeException, ...)
    } // end switch

	return -1;
}

// ---------------------------------------------------------------------------
//  Token: Helper mthods
// ---------------------------------------------------------------------------
int Token::analyzeFirstCharacter(RangeToken* const rangeTok,
								 const int options,
                                 TokenFactory* const tokFactory)
{
	switch(fTokenType) {
	case T_CONCAT:
		{
			int ret = FC_CONTINUE;
			for (int i=0; i<size(); i++) {

				Token* tok = getChild(i);
				if (tok
					&& (ret=tok->analyzeFirstCharacter(rangeTok,
                                    options, tokFactory))!= FC_CONTINUE)
					break;
			}
			return ret;
		}
	case T_UNION:
		{
			unsigned int childSize = size();
            if (childSize == 0)
                return FC_CONTINUE;

            int ret = FC_CONTINUE;
			bool hasEmpty = false;

			for (unsigned int i=0; i < childSize; i++) {

                ret = getChild(i)->analyzeFirstCharacter(rangeTok, options, tokFactory);

				if (ret == FC_ANY)
					break;
				else
					hasEmpty = true;
			}
			return hasEmpty ? FC_CONTINUE : ret;
		}
	case T_CONDITION:
		{
            int ret1 = getChild(0)->analyzeFirstCharacter(rangeTok, options, tokFactory);

            if (size() == 1)
                return FC_CONTINUE;

			int ret2;
			if (ret1 != FC_ANY) {
			    ret2 = getChild(1)->analyzeFirstCharacter(rangeTok, options, tokFactory);
			}

			if (ret1 == FC_ANY || ret2 == FC_ANY)
				return FC_ANY;

			if (ret1 == FC_CONTINUE || ret2 == FC_CONTINUE)
				return FC_CONTINUE;

			return FC_TERMINAL;
		}
	case T_CLOSURE:
	case T_NONGREEDYCLOSURE:
		{
			Token* tok = getChild(0);
			if (tok)
				tok->analyzeFirstCharacter(rangeTok, options, tokFactory);
			return FC_CONTINUE;
		}
	case T_DOT:
	case T_EMPTY:
	case T_ANCHOR:
		return FC_CONTINUE;
	case T_CHAR:
		{
            XMLInt32 ch = getChar();
			rangeTok->addRange(ch, ch);
			if (ch < 0x1000 && isSet(options,RegularExpression::IGNORE_CASE)) {
				//REVISIT
			}
		}
		return FC_TERMINAL;
	case T_RANGE:
		{
			if (isSet(options, RegularExpression::IGNORE_CASE)) {
                rangeTok->mergeRanges(((RangeToken*)
                                         this)->getCaseInsensitiveToken(tokFactory));
			}
			else {
				rangeTok->mergeRanges(this);
			}
			return FC_TERMINAL;
		}
	case T_NRANGE:
		{
			if (isSet(options, RegularExpression::IGNORE_CASE)) {

				RangeToken* caseITok = (((RangeToken*)
					                       this)->getCaseInsensitiveToken(tokFactory));
				rangeTok->mergeRanges(RangeToken::complementRanges(caseITok, tokFactory));
			}
			else {
				rangeTok->mergeRanges(
					RangeToken::complementRanges((RangeToken*) this, tokFactory));
			}
		}
	case T_INDEPENDENT:
	case T_PAREN:
		{
			Token* tok = getChild(0);
			if (tok)
				return tok->analyzeFirstCharacter(rangeTok,options, tokFactory);
		}
	case T_MODIFIERGROUP:
	case T_BACKREFERENCE:
		rangeTok->addRange(0, UTF16_MAX);
		return FC_ANY;
	case T_STRING:
		{
			const XMLCh* str = getString();
            XMLInt32 ch = str[0];

			if (RegxUtil::isHighSurrogate((XMLCh) ch)) {
			}

		    rangeTok->addRange(ch, ch);
		    if (ch<0x10000 && isSet(options,RegularExpression::IGNORE_CASE)) {
                //REVISIT
            }
		}
		return FC_TERMINAL;
	case T_LOOKAHEAD:
	case T_NEGATIVELOOKAHEAD:
	case T_LOOKBEHIND:
	case T_NEGATIVELOOKBEHIND:
		return FC_CONTINUE;
//	default:
//		throw;
	}

	return 0;
}

Token* Token::findFixedString(int options, int& outOptions) {

    switch(fTokenType) {

    case T_CHAR:
		return 0;
    case T_STRING:
		outOptions = options;
		return this;
    case T_UNION:
    case T_CLOSURE:
    case T_NONGREEDYCLOSURE:
    case T_EMPTY:
    case T_ANCHOR:
    case T_RANGE:
    case T_NRANGE:
    case T_DOT:
    case T_BACKREFERENCE:
    case T_LOOKAHEAD:
    case T_NEGATIVELOOKAHEAD:
    case T_LOOKBEHIND:
    case T_NEGATIVELOOKBEHIND:
    case T_CONDITION:
		return 0;
    case T_INDEPENDENT:
    case T_PAREN:
		return getChild(0)->findFixedString(options, outOptions);
    case T_CONCAT:
        {
            Token* prevTok = 0;
            int prevOptions = 0;

            for (int i=0; i<size(); i++) {

                Token* tok = getChild(i)->findFixedString(options, outOptions);

                if (prevTok == 0 || prevTok->isShorterThan(tok)) {

                    prevTok = tok;
					prevOptions = outOptions;
                }
            }

			outOptions = prevOptions;
            return prevTok;
        }
    case T_MODIFIERGROUP:
        {
            options |= ((ModifierToken *) this)->getOptions();
            options &= ~((ModifierToken *) this)->getOptionsMask();
            return getChild(0)->findFixedString(options, outOptions);
        }
    } // end switch

    return 0;
}

bool Token::isShorterThan(Token* const tok) {

	if (tok == 0)
		return false;

	if (getTokenType() != T_STRING && tok->getTokenType() != T_STRING)
		return false; //Should we throw an exception?

    int length = XMLString::stringLen(getString());
    int tokLength = XMLString::stringLen(tok->getString());

	return length < tokLength;
}

XERCES_CPP_NAMESPACE_END

/**
  *	End of file Token.cpp
  */
<commit_msg>Fixed bug in Token::analyzeFirstCharacter so that . matches new line with head character optimisation enabled. As per discussion Jennifer Schachter had with Khaled.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.5  2002/11/21 14:56:35  gareth
 * Fixed bug in Token::analyzeFirstCharacter so that . matches new line with head character optimisation enabled. As per discussion Jennifer Schachter had with Khaled.
 *
 * Revision 1.4  2002/11/04 15:17:00  tng
 * C++ Namespace Support.
 *
 * Revision 1.3  2002/10/15 18:11:02  knoaman
 * [Bug 13489]: missing 'return' in Token.cpp
 *
 * Revision 1.2  2002/03/18 19:29:53  knoaman
 * Change constant names to eliminate possible conflict with user defined ones.
 *
 * Revision 1.1.1.1  2002/02/01 22:22:31  peiyongz
 * sane_include
 *
 * Revision 1.3  2001/05/11 13:26:50  tng
 * Copyright update.
 *
 * Revision 1.2  2001/05/03 18:17:49  knoaman
 * Some design changes:
 * o Changed the TokenFactory from a single static instance, to a
 *    normal class. Each RegularExpression object will have its own
 *    instance of TokenFactory, and that instance will be passed to
 *    other classes that need to use a TokenFactory to create Token
 *    objects (with the exception of RangeTokenMap).
 * o Added a new class RangeTokenMap to map a the different ranges
 *    in a given category to a specific RangeFactory object. In the old
 *    design RangeFactory had dual functionality (act as a Map, and as
 *    a factory for creating RangeToken(s)). The RangeTokenMap will
 *    have its own copy of the TokenFactory. There will be only one
 *    instance of the RangeTokenMap class, and that instance will be
 *    lazily deleted when XPlatformUtils::Terminate is called.
 *
 * Revision 1.1  2001/03/02 19:22:58  knoaman
 * Schema: Regular expression handling part I
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/regx/RangeToken.hpp>
#include <xercesc/util/regx/ModifierToken.hpp>
#include <xercesc/util/regx/RegularExpression.hpp>
#include <xercesc/util/regx/RegxUtil.hpp>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  Static member data initialization
// ---------------------------------------------------------------------------
const XMLInt32		 Token::UTF16_MAX = 0x10FFFF;
const unsigned short Token::FC_CONTINUE = 0;
const unsigned short Token::FC_TERMINAL = 1;
const unsigned short Token::FC_ANY = 2;

// ---------------------------------------------------------------------------
//  Token: Constructors and Destructors
// ---------------------------------------------------------------------------
Token::Token(const unsigned short tokType) : fTokenType(tokType) {

}

Token::~Token() {

}

// ---------------------------------------------------------------------------
//  Token: Getter mthods
// ---------------------------------------------------------------------------
int Token::getMinLength() const {

	switch (fTokenType) {

	case T_CONCAT:
        {
            int sum = 0;
            unsigned int childSize = size();

            for (unsigned int i=0; i<childSize; i++) {
                sum += getChild(i)->getMinLength();
            }
            return sum;
        }
	case T_CONDITION:
	case T_UNION:
        {
			unsigned int childSize = size();

            if (childSize == 0) {
                return 0;
            }
			int ret = getChild(0)->getMinLength();

            for (unsigned int i=1; i < childSize; i++) {

                int min = getChild(i)->getMinLength();
                if (min < ret)
                    ret = min;
            }
			return ret;
        }
	case T_CLOSURE:
	case T_NONGREEDYCLOSURE:
        if (getMin() >= 0)
            return getMin() * getChild(0)->getMinLength();

		return 0;
	case T_EMPTY:
	case T_ANCHOR:
		return 0;
	case T_DOT:
	case T_CHAR:
	case T_RANGE:
	case T_NRANGE:
		return 1;
	case T_INDEPENDENT:
	case T_PAREN:
	case T_MODIFIERGROUP:
		return getChild(0)->getMinLength();
	case T_BACKREFERENCE:
		return 0; // *****  - REVISIT
	case T_STRING:
		return XMLString::stringLen(getString());
	case T_LOOKAHEAD:
	case T_NEGATIVELOOKAHEAD:
	case T_LOOKBEHIND:
	case T_NEGATIVELOOKBEHIND:
		return 0; // *****  - REVIST
//	default:
//		throw;
	}

	// We should not get here, but we have it to make some compilers happy
	return -1;
}

int Token::getMaxLength() const {

	switch (fTokenType) {

	case T_CONCAT:
        {
            int sum = 0;
            unsigned int childSize = size();

            for (unsigned int i=0; i<childSize; i++) {

                int val = getChild(i)->getMaxLength();

				if (val < 0){
					return -1;
				}
                sum += val;
            }
            return sum;
        }
    case T_CONDITION:
    case T_UNION:
        {
            unsigned int childSize = size();

			if (childSize == 0)
                return 0;

            int ret = getChild(0)->getMaxLength();

            for (unsigned i = 1; ret > 0 && i < childSize; i++) {

                int max = getChild(i)->getMaxLength();

                if (max < 0) {

                    ret = -1;
                    break;
                }

                if (max > ret)
                    ret = max;
            }
			return ret;
        }
    case T_CLOSURE:
    case T_NONGREEDYCLOSURE:
        if (getMax() >= 0) {
            return getMax() * getChild(0)->getMaxLength();
		}
		return -1;
    case T_EMPTY:
    case T_ANCHOR:
        return 0;
    case T_CHAR:
        return 1;
    case T_DOT:
    case T_RANGE:
    case T_NRANGE:
        return 2;
    case T_INDEPENDENT:
    case T_PAREN:
    case T_MODIFIERGROUP:
        return getChild(0)->getMaxLength();
    case T_BACKREFERENCE:
		return -1; // REVISIT
    case T_STRING:
        return XMLString::stringLen(getString());
    case T_LOOKAHEAD:
    case T_NEGATIVELOOKAHEAD:
    case T_LOOKBEHIND:
    case T_NEGATIVELOOKBEHIND:
		return 0; // REVISIT
//    default:
//		throw; //ThrowXML(RuntimeException, ...)
    } // end switch

	return -1;
}

// ---------------------------------------------------------------------------
//  Token: Helper mthods
// ---------------------------------------------------------------------------
int Token::analyzeFirstCharacter(RangeToken* const rangeTok,
								 const int options,
                                 TokenFactory* const tokFactory)
{
	switch(fTokenType) {
	case T_CONCAT:
		{
			int ret = FC_CONTINUE;
			for (int i=0; i<size(); i++) {

				Token* tok = getChild(i);
				if (tok
					&& (ret=tok->analyzeFirstCharacter(rangeTok,
                                    options, tokFactory))!= FC_CONTINUE)
					break;
			}
			return ret;
		}
	case T_UNION:
		{
			unsigned int childSize = size();
            if (childSize == 0)
                return FC_CONTINUE;

            int ret = FC_CONTINUE;
			bool hasEmpty = false;

			for (unsigned int i=0; i < childSize; i++) {

                ret = getChild(i)->analyzeFirstCharacter(rangeTok, options, tokFactory);

				if (ret == FC_ANY)
					break;
				else
					hasEmpty = true;
			}
			return hasEmpty ? FC_CONTINUE : ret;
		}
	case T_CONDITION:
		{
            int ret1 = getChild(0)->analyzeFirstCharacter(rangeTok, options, tokFactory);

            if (size() == 1)
                return FC_CONTINUE;

			int ret2;
			if (ret1 != FC_ANY) {
			    ret2 = getChild(1)->analyzeFirstCharacter(rangeTok, options, tokFactory);
			}

			if (ret1 == FC_ANY || ret2 == FC_ANY)
				return FC_ANY;

			if (ret1 == FC_CONTINUE || ret2 == FC_CONTINUE)
				return FC_CONTINUE;

			return FC_TERMINAL;
		}
	case T_CLOSURE:
	case T_NONGREEDYCLOSURE:
		{
			Token* tok = getChild(0);
			if (tok)
				tok->analyzeFirstCharacter(rangeTok, options, tokFactory);
			return FC_CONTINUE;
		}
	case T_DOT:
    return FC_ANY;
	case T_EMPTY:
	case T_ANCHOR:
		return FC_CONTINUE;
	case T_CHAR:
		{
            XMLInt32 ch = getChar();
			rangeTok->addRange(ch, ch);
			if (ch < 0x1000 && isSet(options,RegularExpression::IGNORE_CASE)) {
				//REVISIT
			}
		}
		return FC_TERMINAL;
	case T_RANGE:
		{
			if (isSet(options, RegularExpression::IGNORE_CASE)) {
                rangeTok->mergeRanges(((RangeToken*)
                                         this)->getCaseInsensitiveToken(tokFactory));
			}
			else {
				rangeTok->mergeRanges(this);
			}
			return FC_TERMINAL;
		}
	case T_NRANGE:
		{
			if (isSet(options, RegularExpression::IGNORE_CASE)) {

				RangeToken* caseITok = (((RangeToken*)
					                       this)->getCaseInsensitiveToken(tokFactory));
				rangeTok->mergeRanges(RangeToken::complementRanges(caseITok, tokFactory));
			}
			else {
				rangeTok->mergeRanges(
					RangeToken::complementRanges((RangeToken*) this, tokFactory));
			}
		}
	case T_INDEPENDENT:
	case T_PAREN:
		{
			Token* tok = getChild(0);
			if (tok)
				return tok->analyzeFirstCharacter(rangeTok,options, tokFactory);
		}
	case T_MODIFIERGROUP:
	case T_BACKREFERENCE:
		rangeTok->addRange(0, UTF16_MAX);
		return FC_ANY;
	case T_STRING:
		{
			const XMLCh* str = getString();
            XMLInt32 ch = str[0];

			if (RegxUtil::isHighSurrogate((XMLCh) ch)) {
			}

		    rangeTok->addRange(ch, ch);
		    if (ch<0x10000 && isSet(options,RegularExpression::IGNORE_CASE)) {
                //REVISIT
            }
		}
		return FC_TERMINAL;
	case T_LOOKAHEAD:
	case T_NEGATIVELOOKAHEAD:
	case T_LOOKBEHIND:
	case T_NEGATIVELOOKBEHIND:
		return FC_CONTINUE;
//	default:
//		throw;
	}

	return 0;
}

Token* Token::findFixedString(int options, int& outOptions) {

    switch(fTokenType) {

    case T_CHAR:
		return 0;
    case T_STRING:
		outOptions = options;
		return this;
    case T_UNION:
    case T_CLOSURE:
    case T_NONGREEDYCLOSURE:
    case T_EMPTY:
    case T_ANCHOR:
    case T_RANGE:
    case T_NRANGE:
    case T_DOT:
    case T_BACKREFERENCE:
    case T_LOOKAHEAD:
    case T_NEGATIVELOOKAHEAD:
    case T_LOOKBEHIND:
    case T_NEGATIVELOOKBEHIND:
    case T_CONDITION:
		return 0;
    case T_INDEPENDENT:
    case T_PAREN:
		return getChild(0)->findFixedString(options, outOptions);
    case T_CONCAT:
        {
            Token* prevTok = 0;
            int prevOptions = 0;

            for (int i=0; i<size(); i++) {

                Token* tok = getChild(i)->findFixedString(options, outOptions);

                if (prevTok == 0 || prevTok->isShorterThan(tok)) {

                    prevTok = tok;
					prevOptions = outOptions;
                }
            }

			outOptions = prevOptions;
            return prevTok;
        }
    case T_MODIFIERGROUP:
        {
            options |= ((ModifierToken *) this)->getOptions();
            options &= ~((ModifierToken *) this)->getOptionsMask();
            return getChild(0)->findFixedString(options, outOptions);
        }
    } // end switch

    return 0;
}

bool Token::isShorterThan(Token* const tok) {

	if (tok == 0)
		return false;

	if (getTokenType() != T_STRING && tok->getTokenType() != T_STRING)
		return false; //Should we throw an exception?

    int length = XMLString::stringLen(getString());
    int tokLength = XMLString::stringLen(tok->getString());

	return length < tokLength;
}

XERCES_CPP_NAMESPACE_END

/**
  *	End of file Token.cpp
  */
<|endoftext|>


<commit_before>/* You can use one of the both BSD 3-Clause License or GNU Lesser General Public License 3.0 for this source. */
/* BSD 3-Clause License:
 * Copyright (c) 2013 - 2020, kazunobu watatsu.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 *    Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *    Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation or other materials provided with the distribution.
 *    Neither the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#if !defined(_LINEAR_OPT_)

template <typename T> class Linner {
public:
#if defined(_WITHOUT_EIGEN_)
  typedef SimpleMatrix<T> Mat;
  typedef SimpleVector<T> Vec;
#else
  typedef Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> Mat;
  typedef Eigen::Matrix<T, Eigen::Dynamic, 1> Vec;
#endif

  inline Linner();
  inline ~Linner();

  inline bool inner(bool* fix_partial, const Mat& A, const Vec& b) const;
  inline bool inner(Vec& rvec, const Mat& A, const Vec& b) const;
         bool inner(bool* fix_partial, Vec& rvec, const Mat& A, const Vec& b) const;
  inline bool isErrorMargin(const Mat& A, const Vec& b, const Vec& x, const bool& disp = true) const;

private:
         bool gainVectors(bool* fix, bool* checked, Vec& rvec, const Mat& Pt, const Vec& b) const;
  inline Mat  roughQR(const Mat& At) const;

  T threshold_feas;
  T threshold_p0;
  T threshold_loop;
  T threshold_inner;
  T err_error;
  T large;
};

template <typename T> inline Linner<T>::Linner() {
  const auto epsilon(numeric_limits<T>::epsilon());
  // const auto epsilon(T(1) >> short(62));

  // error rate for orthogonalized b.
  threshold_feas    = pow(epsilon, T(5) / T(6));

  // if SimpleVector<T>::solve fails, increase this:
  threshold_p0      = pow(epsilon, T(4) / T(6));

  // is we gain inner or not:
  threshold_inner   = pow(epsilon, T(2) / T(6));

  // last stage error rate:
  err_error         = pow(epsilon, T(1) / T(6));

  // guarantee b is positive.
  large             = T(1) / sqrt(sqrt(err_error));

  // XXX: Please configure me first.
  // if threshold_loop < 0, extends some regions.
  threshold_loop    = T(0);

  assert(T(1) < large);
  return;
}

template <typename T> inline Linner<T>::~Linner() {
  return;
}

template <typename T> inline bool Linner<T>::inner(bool* fix_partial, const Mat& A, const Vec& b) const {
  Vec rvec;
  return inner(fix_partial, rvec, A, b);
}

template <typename T> inline bool Linner<T>::inner(Vec& rvec, const Mat& A, const Vec& b) const {
  return inner(0, rvec, A, b);
}

template <typename T> bool Linner<T>::inner(bool* fix_partial, Vec& rvec, const Mat& A, const Vec& b) const {
  assert(A.rows() == b.size() && 0 < A.cols() && 0 < b.size());
  // cout << A << endl << b << endl << c.transpose() << endl;
  cerr << " (" << A.rows() << ", " << A.cols() << ")";
  Mat AA(A.rows() + A.cols() * 2, A.cols());
  Vec bb(AA.rows());
  for(int i = 0; i < A.rows(); i ++) {
    AA.row(i) = A.row(i);
    bb[i]     = b[i];
  }
  T M(1);
  T m(1);
  for(int i = 0; i < A.rows(); i ++) {
    for(int j = 0; j < AA.cols(); j ++) {
      const T buf(abs(AA(i, j)));
      if(buf != T(0)) m = min(m, buf);
      M = max(M, buf);
      assert(isfinite(buf) && !isnan(buf));
    }
    const T buf(abs(bb[i]));
    if(buf != T(0)) m = min(m, buf);
    M = max(M, buf);
    assert(isfinite(buf) && !isnan(buf));
  }
  cerr << " err_error(" << sqrt(err_error) * M / m << ")" << flush;
  const auto Mm(sqrt(M * m));
  for(int i = A.rows(); i < AA.rows(); i ++) {
    for(int j = 0; j < A.cols(); j ++)
      AA(i, j) = (i - A.rows()) / 2 == j
        ? ((i - A.rows()) % 2 ? Mm : - Mm)
        : T(0);
    bb[i] = large * m;
  }
  bool* bfix_partial = new bool[AA.rows()];
  bool* checked = new bool[AA.rows()];
  const auto Pt(roughQR(AA.transpose()));
  cerr << "Q" << flush;
  const Mat  R(Pt * AA);
  cerr << "R" << flush;
  const bool f_inner(gainVectors(bfix_partial, checked, rvec, Pt, bb));
  if(fix_partial)
    for(int i = 0; i < A.rows(); i ++)
      fix_partial[i] = bfix_partial[i];
  delete[] bfix_partial;
  delete[] checked;
#if defined(_WITHOUT_EIGEN_)
  rvec = R.solve(rvec);
#else
  rvec = R.inverse() * rvec;
#endif
  cerr << "I" << flush;
  return f_inner || isErrorMargin(A, b, rvec, true);
}

template <typename T> bool Linner<T>::gainVectors(bool* fix, bool* checked, Vec& rvec, const Mat& Pt, const Vec& b) const {
  rvec.resize(Pt.rows());
#if defined(_OPENMP)
#pragma omp simd
#endif
  for(int i = 0; i < rvec.size(); i ++)
    rvec[i] = T(0);
  int n_fixed;
  Vec one(b.size());
#if defined(_OPENMP)
#pragma omp simd
#endif
  for(int i = 0; i < Pt.cols(); i ++) {
    one[i]     = T(1);
    fix[i]     = false;
    checked[i] = false;
  }

  // set value, orthogonalize, and scale t.
#if defined(_WITHOUT_EIGEN_)
  Vec bb(b - Pt.projectionPt(b));
#else
  Vec bb(b - Pt.transpose() * (Pt * b));
#endif
  if(sqrt(bb.dot(bb)) <= threshold_feas * sqrt(b.dot(b))) {
    for(int i = 0; i < Pt.cols() - Pt.rows() * 2; i ++)
      bb[i] = sqrt(Pt.col(i).dot(Pt.col(i)));
    for(int i = Pt.cols() - Pt.rows() * 2; i < Pt.cols(); i ++)
      bb[i] = b[i];
#if defined(_WITHOUT_EIGEN_)
    const Vec bbb(bb - Pt.projectionPt(bb));
#else
    const Vec bbb(bb - Pt.transpose() * (Pt * bb));
#endif
    if(sqrt(bbb.dot(bbb)) <= threshold_feas * sqrt(bb.dot(bb))) {
      rvec = Pt * (b - bb);
      cerr << "t" << flush;
      return isErrorMargin(Pt.transpose(), b, rvec, ! false);
    }
    for(int i = 0; i < bb.size(); i ++)
      bb[i] = T(0);
    std::cerr << "0" << flush;
  }
  Vec mbb(- bb);
  const auto normb00(sqrt(mbb.dot(mbb)));
  const auto normb0(normb00 == T(0) ? T(1) : normb00);
  Mat Pverb(Pt);
  Vec on;
  Vec deltab;
  Vec orth;
  Vec norm(one.size());
  T   ratiob(1);
  for(n_fixed = 0; n_fixed < Pverb.rows(); n_fixed ++) {
#if defined(_OPENMP)
#pragma omp parallel for schedule(static, 1)
#endif
    for(int j = 0; j < Pverb.cols(); j ++) {
      norm[j]    = sqrt(Pverb.col(j).dot(Pverb.col(j)));
      checked[j] = fix[j] || norm[j] <= threshold_p0;
    }
    // extend b with threshold_loop. N.B. mbb = - b'.
    Vec mb(mbb + norm / sqrt(norm.dot(norm)) * normb0 * threshold_loop);
#if defined(_WITHOUT_EIGEN_)
    mb -= (deltab = Pverb.projectionPt(mb));
#else
    mb -= (deltab = Pverb.transpose() * (Pverb * mb));
#endif
    mb /= (ratiob = sqrt(mb.dot(mb)));

    // O(mn^2) check for inner or not.
#if defined(_WITHOUT_EIGEN_)
    on = Pverb.projectionPt(- one) + mb * mb.dot(- one);
#else
    on = Pverb.transpose() * (Pverb * (- one)) + mb * mb.dot(- one);
#endif

    // N.B. This might be rewrited as fix once with sorted fidxs.
    //   When the hypothesis is true, next loop must fix or get inner vector.
    //   Also, it takes O(lg(mn)) time order for this function.
    //   But to do so, theoretical proof is needed and it seems not
    //   because we use mb with little extended and its norm is in error order.
    int  fidx(0);
    for( ; fidx < on.size(); fidx ++)
      if(!checked[fidx])
        break;
    for(int j = fidx + 1; j < on.size(); j ++)
      if(!checked[j] && on[fidx] / norm[fidx] < on[j] / norm[j])
        fidx = j;
    if(fidx >= one.size())
      assert(0 && "rank is not full : should not be reached");
    on *= sqrt(norm.dot(norm)) / abs(mb.dot(on));
    if(on[fidx] / norm[fidx] <= threshold_inner)
      break;

    // O(mn^2) over all in this function.
    orth = Pverb.col(fidx);
    const auto norm2orth(orth.dot(orth));
    const auto mbb0(mbb[fidx]);
#if defined(_OPENMP)
#pragma omp parallel for schedule(static, 1)
#endif
    for(int j = 0; j < Pverb.cols(); j ++) {
      const auto work(Pverb.col(j).dot(orth) / norm2orth);
#if defined(_WITHOUT_EIGEN_)
      Pverb.setCol(j, Pverb.col(j) - orth * work);
#else
      Pverb.col(j) -= orth * work;
#endif
      mbb[j]       -= mbb0 * work;
    }
    fix[fidx] = true;
  }
  if(n_fixed == Pt.rows()) {
    Mat F(Pt.rows(), Pt.rows());
    Vec f(Pt.rows());
    for(int i = 0, j = 0; i < Pt.cols() && j < f.size(); i ++)
      if(fix[i]) {
        const auto ratio(sqrt(Pt.col(i).dot(Pt.col(i)) + b[i] * b[i]));
        F.row(j) = Pt.col(i) / ratio;
        f[j]     = b[i]      / ratio + threshold_loop;
        j ++;
      }
#if defined(_WITHOUT_EIGEN_)
    rvec = F.solve(f);
#else
    rvec = F.inverse() * f;
#endif
    cerr << "F" << flush;
  } else {
    rvec = Pt * (on * ratiob + deltab + b);
    cerr << "G" << flush;
  }
  return isErrorMargin(Pt.transpose(), b, rvec, ! false);
}

template <typename T> inline bool Linner<T>::isErrorMargin(const Mat& A, const Vec& b, const Vec& x, const bool& disp) const {
  T result(0);
  const Vec err(A * x - b);
  for(int i = 0; i < b.size(); i ++) {
    const auto& lerr(err[i]);
    if(!isfinite(lerr) || isnan(lerr) ||
       result < lerr) result = lerr;
  }
  if(disp)
    cerr << " errorMargin?(" << result / max(err_error, sqrt(x.dot(x))) << ")";
  return isfinite(result)   && !isnan(result)   &&
         isfinite(x.dot(x)) && !isnan(x.dot(x)) &&
         ((x.dot(x) == T(0) && result == T(0)) ||
          (x.dot(x) != T(0) && result / sqrt(x.dot(x)) <= err_error));
}

template <typename T> inline typename Linner<T>::Mat Linner<T>::roughQR(const Mat& At) const {
  Mat Q(At.rows(), At.cols());
  for(int i = 0; i < Q.rows(); i ++)
    for(int j = 0; j < Q.cols(); j ++)
      Q(i, j) = T(0);
  for(int i = 0; i < At.rows(); i ++) {
    // N.B. in this case, At is full rank.
#if defined(_WITHOUT_EIGEN_)
    const Vec work(At.row(i) - Q.projectionPt(At.row(i)));
#else
    const Vec work(At.row(i) - (Q.transpose() * (Q * At.row(i).transpose())).transpose());
#endif
    // generally, assert norm > error is needed.
    // in this case, not.
    Q.row(i) = work / sqrt(work.dot(work));
  }
  return Q;
}

#define _LINEAR_OPT_
#endif

<commit_msg>fix last ratio.<commit_after>/* You can use one of the both BSD 3-Clause License or GNU Lesser General Public License 3.0 for this source. */
/* BSD 3-Clause License:
 * Copyright (c) 2013 - 2020, kazunobu watatsu.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 *    Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *    Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation or other materials provided with the distribution.
 *    Neither the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#if !defined(_LINEAR_OPT_)

template <typename T> class Linner {
public:
#if defined(_WITHOUT_EIGEN_)
  typedef SimpleMatrix<T> Mat;
  typedef SimpleVector<T> Vec;
#else
  typedef Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> Mat;
  typedef Eigen::Matrix<T, Eigen::Dynamic, 1> Vec;
#endif

  inline Linner();
  inline ~Linner();

  inline bool inner(bool* fix_partial, const Mat& A, const Vec& b) const;
  inline bool inner(Vec& rvec, const Mat& A, const Vec& b) const;
         bool inner(bool* fix_partial, Vec& rvec, const Mat& A, const Vec& b) const;
  inline bool isErrorMargin(const Mat& A, const Vec& b, const Vec& x, const bool& disp = true) const;

private:
         bool gainVectors(bool* fix, bool* checked, Vec& rvec, const Mat& Pt, const Vec& b) const;
  inline Mat  roughQR(const Mat& At) const;

  T threshold_feas;
  T threshold_p0;
  T threshold_loop;
  T threshold_inner;
  T err_error;
  T large;
};

template <typename T> inline Linner<T>::Linner() {
  const auto epsilon(numeric_limits<T>::epsilon());
  // const auto epsilon(T(1) >> short(62));

  // error rate for orthogonalized b.
  threshold_feas    = pow(epsilon, T(5) / T(6));

  // if SimpleVector<T>::solve fails, increase this:
  threshold_p0      = pow(epsilon, T(4) / T(6));

  // is we gain inner or not:
  threshold_inner   = pow(epsilon, T(2) / T(6));

  // last stage error rate:
  err_error         = pow(epsilon, T(1) / T(6));

  // guarantee b is positive.
  large             = T(1) / sqrt(sqrt(err_error));

  // XXX: Please configure me first.
  // if threshold_loop < 0, extends some regions.
  threshold_loop    = T(0);

  assert(T(1) < large);
  return;
}

template <typename T> inline Linner<T>::~Linner() {
  return;
}

template <typename T> inline bool Linner<T>::inner(bool* fix_partial, const Mat& A, const Vec& b) const {
  Vec rvec;
  return inner(fix_partial, rvec, A, b);
}

template <typename T> inline bool Linner<T>::inner(Vec& rvec, const Mat& A, const Vec& b) const {
  return inner(0, rvec, A, b);
}

template <typename T> bool Linner<T>::inner(bool* fix_partial, Vec& rvec, const Mat& A, const Vec& b) const {
  assert(A.rows() == b.size() && 0 < A.cols() && 0 < b.size());
  // cout << A << endl << b << endl << c.transpose() << endl;
  cerr << " (" << A.rows() << ", " << A.cols() << ")";
  Mat AA(A.rows() + A.cols() * 2, A.cols());
  Vec bb(AA.rows());
  for(int i = 0; i < A.rows(); i ++) {
    AA.row(i) = A.row(i);
    bb[i]     = b[i];
  }
  T M(1);
  T m(1);
  for(int i = 0; i < A.rows(); i ++) {
    for(int j = 0; j < AA.cols(); j ++) {
      const T buf(abs(AA(i, j)));
      if(buf != T(0)) m = min(m, buf);
      M = max(M, buf);
      assert(isfinite(buf) && !isnan(buf));
    }
    const T buf(abs(bb[i]));
    if(buf != T(0)) m = min(m, buf);
    M = max(M, buf);
    assert(isfinite(buf) && !isnan(buf));
  }
  cerr << " err_error(" << sqrt(err_error) * M / m << ")" << flush;
  const auto Mm(sqrt(M * m));
  for(int i = A.rows(); i < AA.rows(); i ++) {
    for(int j = 0; j < A.cols(); j ++)
      AA(i, j) = (i - A.rows()) / 2 == j
        ? ((i - A.rows()) % 2 ? Mm : - Mm)
        : T(0);
    bb[i] = large * m;
  }
  bool* bfix_partial = new bool[AA.rows()];
  bool* checked = new bool[AA.rows()];
  const auto Pt(roughQR(AA.transpose()));
  cerr << "Q" << flush;
  const Mat  R(Pt * AA);
  cerr << "R" << flush;
  const bool f_inner(gainVectors(bfix_partial, checked, rvec, Pt, bb));
  if(fix_partial)
    for(int i = 0; i < A.rows(); i ++)
      fix_partial[i] = bfix_partial[i];
  delete[] bfix_partial;
  delete[] checked;
#if defined(_WITHOUT_EIGEN_)
  rvec = R.solve(rvec);
#else
  rvec = R.inverse() * rvec;
#endif
  cerr << "I" << flush;
  return f_inner || isErrorMargin(A, b, rvec, true);
}

template <typename T> bool Linner<T>::gainVectors(bool* fix, bool* checked, Vec& rvec, const Mat& Pt, const Vec& b) const {
  rvec.resize(Pt.rows());
#if defined(_OPENMP)
#pragma omp simd
#endif
  for(int i = 0; i < rvec.size(); i ++)
    rvec[i] = T(0);
  int n_fixed;
  Vec one(b.size());
#if defined(_OPENMP)
#pragma omp simd
#endif
  for(int i = 0; i < Pt.cols(); i ++) {
    one[i]     = T(1);
    fix[i]     = false;
    checked[i] = false;
  }

  // set value, orthogonalize, and scale t.
#if defined(_WITHOUT_EIGEN_)
  Vec bb(b - Pt.projectionPt(b));
#else
  Vec bb(b - Pt.transpose() * (Pt * b));
#endif
  if(sqrt(bb.dot(bb)) <= threshold_feas * sqrt(b.dot(b))) {
    for(int i = 0; i < Pt.cols() - Pt.rows() * 2; i ++)
      bb[i] = sqrt(Pt.col(i).dot(Pt.col(i)));
    for(int i = Pt.cols() - Pt.rows() * 2; i < Pt.cols(); i ++)
      bb[i] = b[i];
#if defined(_WITHOUT_EIGEN_)
    const Vec bbb(bb - Pt.projectionPt(bb));
#else
    const Vec bbb(bb - Pt.transpose() * (Pt * bb));
#endif
    if(sqrt(bbb.dot(bbb)) <= threshold_feas * sqrt(bb.dot(bb))) {
      rvec = Pt * (b - bb);
      cerr << "t" << flush;
      return isErrorMargin(Pt.transpose(), b, rvec, ! false);
    }
    for(int i = 0; i < bb.size(); i ++)
      bb[i] = T(0);
    std::cerr << "0" << flush;
  }
  Vec mbb(- bb);
  const auto normb00(sqrt(mbb.dot(mbb)));
  const auto normb0(normb00 == T(0) ? T(1) : normb00);
  Mat Pverb(Pt);
  Vec on;
  Vec deltab;
  Vec orth;
  Vec norm(one.size());
  T   ratiob(1);
  for(n_fixed = 0; n_fixed < Pverb.rows(); n_fixed ++) {
#if defined(_OPENMP)
#pragma omp parallel for schedule(static, 1)
#endif
    for(int j = 0; j < Pverb.cols(); j ++) {
      norm[j]    = sqrt(Pverb.col(j).dot(Pverb.col(j)));
      checked[j] = fix[j] || norm[j] <= threshold_p0;
    }
    // extend b with threshold_loop. N.B. mbb = - b'.
    Vec mb(mbb + norm / sqrt(norm.dot(norm)) * normb0 * threshold_loop);
#if defined(_WITHOUT_EIGEN_)
    mb -= (deltab = Pverb.projectionPt(mb));
#else
    mb -= (deltab = Pverb.transpose() * (Pverb * mb));
#endif
    mb /= (ratiob = sqrt(mb.dot(mb)));

    // O(mn^2) check for inner or not.
#if defined(_WITHOUT_EIGEN_)
    on = Pverb.projectionPt(- one) + mb * mb.dot(- one);
#else
    on = Pverb.transpose() * (Pverb * (- one)) + mb * mb.dot(- one);
#endif

    // N.B. This might be rewrited as fix once with sorted fidxs.
    //   When the hypothesis is true, next loop must fix or get inner vector.
    //   Also, it takes O(lg(mn)) time order for this function.
    //   But to do so, theoretical proof is needed and it seems not
    //   because we use mb with little extended and its norm is in error order.
    int  fidx(0);
    for( ; fidx < on.size(); fidx ++)
      if(!checked[fidx])
        break;
    for(int j = fidx + 1; j < on.size(); j ++)
      if(!checked[j] && on[fidx] / norm[fidx] < on[j] / norm[j])
        fidx = j;
    if(fidx >= one.size())
      assert(0 && "rank is not full : should not be reached");
    on *= sqrt(norm.dot(norm)) / abs(mb.dot(on)) / norm[fidx];
    if(on[fidx] <= threshold_inner)
      break;

    // O(mn^2) over all in this function.
    orth = Pverb.col(fidx);
    const auto norm2orth(orth.dot(orth));
    const auto mbb0(mbb[fidx]);
#if defined(_OPENMP)
#pragma omp parallel for schedule(static, 1)
#endif
    for(int j = 0; j < Pverb.cols(); j ++) {
      const auto work(Pverb.col(j).dot(orth) / norm2orth);
#if defined(_WITHOUT_EIGEN_)
      Pverb.setCol(j, Pverb.col(j) - orth * work);
#else
      Pverb.col(j) -= orth * work;
#endif
      mbb[j]       -= mbb0 * work;
    }
    fix[fidx] = true;
  }
  if(n_fixed == Pt.rows()) {
    Mat F(Pt.rows(), Pt.rows());
    Vec f(Pt.rows());
    for(int i = 0, j = 0; i < Pt.cols() && j < f.size(); i ++)
      if(fix[i]) {
        const auto ratio(sqrt(Pt.col(i).dot(Pt.col(i)) + b[i] * b[i]));
        F.row(j) = Pt.col(i) / ratio;
        f[j]     = b[i]      / ratio + threshold_loop;
        j ++;
      }
#if defined(_WITHOUT_EIGEN_)
    rvec = F.solve(f);
#else
    rvec = F.inverse() * f;
#endif
    cerr << "F" << flush;
  } else {
    rvec = Pt * (on * ratiob + deltab + b);
    cerr << "G" << flush;
  }
  return isErrorMargin(Pt.transpose(), b, rvec, ! false);
}

template <typename T> inline bool Linner<T>::isErrorMargin(const Mat& A, const Vec& b, const Vec& x, const bool& disp) const {
  T result(0);
  const Vec err(A * x - b);
  for(int i = 0; i < b.size(); i ++) {
    const auto& lerr(err[i]);
    if(!isfinite(lerr) || isnan(lerr) ||
       result < lerr) result = lerr;
  }
  if(disp)
    cerr << " errorMargin?(" << result / max(err_error, sqrt(x.dot(x))) << ")";
  return isfinite(result)   && !isnan(result)   &&
         isfinite(x.dot(x)) && !isnan(x.dot(x)) &&
         ((x.dot(x) == T(0) && result == T(0)) ||
          (x.dot(x) != T(0) && result / sqrt(x.dot(x)) <= err_error));
}

template <typename T> inline typename Linner<T>::Mat Linner<T>::roughQR(const Mat& At) const {
  Mat Q(At.rows(), At.cols());
  for(int i = 0; i < Q.rows(); i ++)
    for(int j = 0; j < Q.cols(); j ++)
      Q(i, j) = T(0);
  for(int i = 0; i < At.rows(); i ++) {
    // N.B. in this case, At is full rank.
#if defined(_WITHOUT_EIGEN_)
    const Vec work(At.row(i) - Q.projectionPt(At.row(i)));
#else
    const Vec work(At.row(i) - (Q.transpose() * (Q * At.row(i).transpose())).transpose());
#endif
    // generally, assert norm > error is needed.
    // in this case, not.
    Q.row(i) = work / sqrt(work.dot(work));
  }
  return Q;
}

#define _LINEAR_OPT_
#endif

<|endoftext|>


<commit_before>
#include "Movie.h"
#include <SFML/Graphics.hpp>
#include <iostream>

#define MOVIE_FILE "some_movie.avi"

int main()
{
	// Create window and movie
	sf::RenderWindow window(sf::VideoMode(800, 600), "SFE Movie Player", sf::Style::Close);
	sfe::Movie movie;
	bool fullscreen = false;

	if (!movie.OpenFromFile(MOVIE_FILE))
		return 1;

	// Scale movie to the window drawing area and enable VSync
	movie.ResizeToFrame(0, 0, window.GetWidth(), window.GetHeight());
	window.EnableVerticalSync(true);

	// Start movie playback
	movie.Play();

	while (window.IsOpened())
	{
		sf::Event ev;
		while (window.PollEvent(ev))
		{
			if (ev.Type == sf::Event::Closed ||
				(ev.Type == sf::Event::KeyPressed && ev.Key.Code == sf::Keyboard::Escape))
			{
				//movie.Stop();
				window.Close();
			}

			if (ev.Type == sf::Event::KeyPressed)
			{
				// Handle basic controls
				if (ev.Key.Code == sf::Keyboard::Space)
				{
					if (movie.GetStatus() == sfe::Movie::Paused || movie.GetStatus() == sfe::Movie::Stopped)
						movie.Play();
					else
						movie.Pause();
				}

				if (ev.Key.Code == sf::Keyboard::S)
					movie.Stop();

				if (ev.Key.Code == sf::Keyboard::F)
				{
					fullscreen = !fullscreen;

					if (fullscreen)
					{
						window.Close();
						window.Create(sf::VideoMode::GetDesktopMode(), "SFE Movie Player", sf::Style::Fullscreen);
						window.EnableVerticalSync(true);
						movie.ResizeToFrame(0, 0, window.GetWidth(), window.GetHeight());
					}
					else
					{
						window.Close();
						window.Create(sf::VideoMode(1024, 768), "SFE Movie Player", sf::Style::Close);
						window.EnableVerticalSync(true);
						movie.ResizeToFrame(0, 0, window.GetWidth(), window.GetHeight());
					}
				}

				if (ev.Key.Code ==sf::Keyboard::Escape)
				{
					//movie.Stop();
					window.Close();
				}

				if (ev.Key.Code == sf::Keyboard::R)
				{
					movie.Stop();
					movie.Play();
				}
			}
		}

		// Render movie
		window.Clear();
		window.Draw(movie);
		window.Display();
	}

	return 0;
}

<commit_msg>Updated and cleaned sample code.<commit_after>
#include "../include/Movie.h"
#include <SFML/Graphics.hpp>

#ifndef MOVIE_FILE
#define MOVIE_FILE "some_movie.avi"
#endif

/*
 * Here is a little use sample for sfeMovie.
 * It'll open and display the movie specified by MOVIE_FILE above.
 *
 * This sample implements basic controls as follow:
 *  - Escape key to exit
 *  - Space key to play/pause the movie playback
 *  - S key to stop and go back to the beginning of the movie
 *  - R key to restart playing from the beginning of the movie
 *  - F key to toggle between windowed and fullscreen mode
 */

int main()
{
	// Some settings
	const std::string windowTitle = "sfeMovie Player";
	const int windowWidth = 800;
	const int windowHeight = 600;
	bool fullscreen = false;

	// Create window
	sf::RenderWindow window(sf::VideoMode(windowWidth, windowHeight), windowTitle, sf::Style::Close);

	// Create and open movie
	sfe::Movie movie;
	if (!movie.OpenFromFile(MOVIE_FILE))
		return 1;

	// Scale movie to the window drawing area and enable VSync
	movie.ResizeToFrame(0, 0, window.GetWidth(), window.GetHeight());
	window.EnableVerticalSync(true);

	// Start movie playback
	movie.Play();

	while (window.IsOpened())
	{
		sf::Event ev;
		while (window.PollEvent(ev))
		{
			// Window closure
			if (ev.Type == sf::Event::Closed ||
				(ev.Type == sf::Event::KeyPressed &&
				 ev.Key.Code == sf::Keyboard::Escape))
			{
				window.Close();
			}

			// Handle basic controls
			else if (ev.Type == sf::Event::KeyPressed)
			{
				// Play/Pause
				if (ev.Key.Code == sf::Keyboard::Space)
				{
					if (movie.GetStatus() != sfe::Movie::Playing)
						movie.Play();
					else
						movie.Pause();
				}

				// Stop
				if (ev.Key.Code == sf::Keyboard::S)
					movie.Stop();

				// Restart playback
				if (ev.Key.Code == sf::Keyboard::R)
				{
					movie.Stop();
					movie.Play();
				}

				// Toggle fullscreen mode
				if (ev.Key.Code == sf::Keyboard::F)
				{
					fullscreen = !fullscreen;

					// We want to switch to the full screen mode
					if (fullscreen)
					{
						window.Create(sf::VideoMode::GetDesktopMode(), windowTitle, sf::Style::Fullscreen);
						window.EnableVerticalSync(true);
						movie.ResizeToFrame(0, 0, window.GetWidth(), window.GetHeight());
					}

					// We want to switch back to the windowed mode
					else
					{
						window.Create(sf::VideoMode(windowWidth, windowHeight), windowTitle, sf::Style::Close);
						window.EnableVerticalSync(true);
						movie.ResizeToFrame(0, 0, window.GetWidth(), window.GetHeight());
					}
				}
			}
		}

		// Render movie
		window.Clear();
		window.Draw(movie);
		window.Display();
	}

	return 0;
}

<|endoftext|>