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

#include "chrome/browser/renderer_host/web_cache_manager.h"

#include <algorithm>

#include "base/compiler_specific.h"
#include "base/singleton.h"
#include "base/sys_info.h"
#include "base/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"

using base::Time;
using base::TimeDelta;
using WebKit::WebCache;

static const unsigned int kReviseAllocationDelayMS = 200 /* milliseconds */;

// The default size limit of the in-memory cache is 8 MB
static const int kDefaultMemoryCacheSize = 8 * 1024 * 1024;

namespace {

int GetDefaultCacheSize() {
  // Start off with a modest default
  int default_cache_size = kDefaultMemoryCacheSize;

  // Check how much physical memory the OS has
  int mem_size_mb = base::SysInfo::AmountOfPhysicalMemoryMB();
  if (mem_size_mb >= 1000)  // If we have a GB of memory, set a larger default.
    default_cache_size *= 4;
  else if (mem_size_mb >= 512)  // With 512 MB, set a slightly larger default.
    default_cache_size *= 2;

  return default_cache_size;
}

}  // anonymous namespace

// static
void WebCacheManager::RegisterPrefs(PrefService* prefs) {
  prefs->RegisterIntegerPref(prefs::kMemoryCacheSize, GetDefaultCacheSize());
}

// static
WebCacheManager* WebCacheManager::GetInstance() {
  return Singleton<WebCacheManager>::get();
}

WebCacheManager::WebCacheManager()
    : global_size_limit_(GetDefaultGlobalSizeLimit()),
      ALLOW_THIS_IN_INITIALIZER_LIST(revise_allocation_factory_(this)) {
}

WebCacheManager::~WebCacheManager() {
}

void WebCacheManager::Add(int renderer_id) {
  DCHECK(inactive_renderers_.count(renderer_id) == 0);

  // It is tempting to make the following DCHECK here, but it fails when a new
  // tab is created as we observe activity from that tab because the
  // RenderProcessHost is recreated and adds itself.
  //
  //   DCHECK(active_renderers_.count(renderer_id) == 0);
  //
  // However, there doesn't seem to be much harm in receiving the calls in this
  // order.

  active_renderers_.insert(renderer_id);

  RendererInfo* stats = &(stats_[renderer_id]);
  memset(stats, 0, sizeof(*stats));
  stats->access = Time::Now();

  // Revise our allocation strategy to account for this new renderer.
  ReviseAllocationStrategyLater();
}

void WebCacheManager::Remove(int renderer_id) {
  // Erase all knowledge of this renderer
  active_renderers_.erase(renderer_id);
  inactive_renderers_.erase(renderer_id);
  stats_.erase(renderer_id);

  // Reallocate the resources used by this renderer
  ReviseAllocationStrategyLater();
}

void WebCacheManager::ObserveActivity(int renderer_id) {
  StatsMap::iterator item = stats_.find(renderer_id);
  if (item == stats_.end())
    return;  // We might see stats for a renderer that has been destroyed.

  // Record activity.
  active_renderers_.insert(renderer_id);
  item->second.access = Time::Now();

  std::set<int>::iterator elmt = inactive_renderers_.find(renderer_id);
  if (elmt != inactive_renderers_.end()) {
    inactive_renderers_.erase(elmt);

    // A renderer that was inactive, just became active.  We should make sure
    // it is given a fair cache allocation, but we defer this for a bit in
    // order to make this function call cheap.
    ReviseAllocationStrategyLater();
  }
}

void WebCacheManager::ObserveStats(int renderer_id,
                                   const WebCache::UsageStats& stats) {
  StatsMap::iterator entry = stats_.find(renderer_id);
  if (entry == stats_.end())
    return;  // We might see stats for a renderer that has been destroyed.

  // Record the updated stats.
  entry->second.capacity = stats.capacity;
  entry->second.deadSize = stats.deadSize;
  entry->second.liveSize = stats.liveSize;
  entry->second.maxDeadCapacity = stats.maxDeadCapacity;
  entry->second.minDeadCapacity = stats.minDeadCapacity;

  // trigger notification
  WebCache::UsageStats stats_details(stats);
  // &stats_details is only valid during the notification.
  // See notification_types.h.
  NotificationService::current()->Notify(
      NotificationType::WEB_CACHE_STATS_OBSERVED,
      Source<RenderProcessHost>(RenderProcessHost::FromID(renderer_id)),
      Details<WebCache::UsageStats>(&stats_details));
}

void WebCacheManager::SetGlobalSizeLimit(size_t bytes) {
  global_size_limit_ = bytes;
  ReviseAllocationStrategyLater();
}

// static
size_t WebCacheManager::GetDefaultGlobalSizeLimit() {
  PrefService* perf_service = g_browser_process->local_state();
  if (perf_service)
    return perf_service->GetInteger(prefs::kMemoryCacheSize);

  return GetDefaultCacheSize();
}

void WebCacheManager::GatherStats(const std::set<int>& renderers,
                                  WebCache::UsageStats* stats) {
  DCHECK(stats);

  memset(stats, 0, sizeof(WebCache::UsageStats));

  std::set<int>::const_iterator iter = renderers.begin();
  while (iter != renderers.end()) {
    StatsMap::iterator elmt = stats_.find(*iter);
    if (elmt != stats_.end()) {
      stats->minDeadCapacity += elmt->second.minDeadCapacity;
      stats->maxDeadCapacity += elmt->second.maxDeadCapacity;
      stats->capacity += elmt->second.capacity;
      stats->liveSize += elmt->second.liveSize;
      stats->deadSize += elmt->second.deadSize;
    }
    ++iter;
  }
}

// static
size_t WebCacheManager::GetSize(AllocationTactic tactic,
                                const WebCache::UsageStats& stats) {
  switch (tactic) {
  case DIVIDE_EVENLY:
    // We aren't going to reserve any space for existing objects.
    return 0;
  case KEEP_CURRENT_WITH_HEADROOM:
    // We need enough space for our current objects, plus some headroom.
    return 3 * GetSize(KEEP_CURRENT, stats) / 2;
  case KEEP_CURRENT:
    // We need enough space to keep our current objects.
    return stats.liveSize + stats.deadSize;
  case KEEP_LIVE_WITH_HEADROOM:
    // We need enough space to keep out live resources, plus some headroom.
    return 3 * GetSize(KEEP_LIVE, stats) / 2;
  case KEEP_LIVE:
    // We need enough space to keep our live resources.
    return stats.liveSize;
  default:
    NOTREACHED() << "Unknown cache allocation tactic";
    return 0;
  }
}

bool WebCacheManager::AttemptTactic(
    AllocationTactic active_tactic,
    const WebCache::UsageStats& active_stats,
    AllocationTactic inactive_tactic,
    const WebCache::UsageStats& inactive_stats,
    AllocationStrategy* strategy) {
  DCHECK(strategy);

  size_t active_size = GetSize(active_tactic, active_stats);
  size_t inactive_size = GetSize(inactive_tactic, inactive_stats);

  // Give up if we don't have enough space to use this tactic.
  if (global_size_limit_ < active_size + inactive_size)
    return false;

  // Compute the unreserved space available.
  size_t total_extra = global_size_limit_ - (active_size + inactive_size);

  // The plan for the extra space is to divide it evenly amoung the active
  // renderers.
  size_t shares = active_renderers_.size();

  // The inactive renderers get one share of the extra memory to be divided
  // among themselves.
  size_t inactive_extra = 0;
  if (inactive_renderers_.size() > 0) {
    ++shares;
    inactive_extra = total_extra / shares;
  }

  // The remaining memory is allocated to the active renderers.
  size_t active_extra = total_extra - inactive_extra;

  // Actually compute the allocations for each renderer.
  AddToStrategy(active_renderers_, active_tactic, active_extra, strategy);
  AddToStrategy(inactive_renderers_, inactive_tactic, inactive_extra, strategy);

  // We succeeded in computing an allocation strategy.
  return true;
}

void WebCacheManager::AddToStrategy(std::set<int> renderers,
                                    AllocationTactic tactic,
                                    size_t extra_bytes_to_allocate,
                                    AllocationStrategy* strategy) {
  DCHECK(strategy);

  // Nothing to do if there are no renderers.  It is common for there to be no
  // inactive renderers if there is a single active tab.
  if (renderers.size() == 0)
    return;

  // Divide the extra memory evenly among the renderers.
  size_t extra_each = extra_bytes_to_allocate / renderers.size();

  std::set<int>::const_iterator iter = renderers.begin();
  while (iter != renderers.end()) {
    size_t cache_size = extra_each;

    // Add in the space required to implement |tactic|.
    StatsMap::iterator elmt = stats_.find(*iter);
    if (elmt != stats_.end())
      cache_size += GetSize(tactic, elmt->second);

    // Record the allocation in our strategy.
    strategy->push_back(Allocation(*iter, cache_size));
    ++iter;
  }
}

void WebCacheManager::EnactStrategy(const AllocationStrategy& strategy) {
  // Inform each render process of its cache allocation.
  AllocationStrategy::const_iterator allocation = strategy.begin();
  while (allocation != strategy.end()) {
    RenderProcessHost* host = RenderProcessHost::FromID(allocation->first);
    if (host) {
      // This is the capacity this renderer has been allocated.
      size_t capacity = allocation->second;

      // We don't reserve any space for dead objects in the cache.  Instead, we
      // prefer to keep live objects around.  There is probably some performance
      // tuning to be done here.
      size_t min_dead_capacity = 0;

      // We allow the dead objects to consume all of the cache, if the renderer
      // so desires.  If we wanted this memory, we would have set the total
      // capacity lower.
      size_t max_dead_capacity = capacity;

      host->Send(new ViewMsg_SetCacheCapacities(min_dead_capacity,
                                                max_dead_capacity,
                                                capacity));
    }
    ++allocation;
  }
}

void WebCacheManager::ReviseAllocationStrategy() {
  DCHECK(stats_.size() <=
      active_renderers_.size() + inactive_renderers_.size());

  // Check if renderers have gone inactive.
  FindInactiveRenderers();

  // Gather statistics
  WebCache::UsageStats active;
  WebCache::UsageStats inactive;
  GatherStats(active_renderers_, &active);
  GatherStats(inactive_renderers_, &inactive);

  // Compute an allocation strategy.
  //
  // We attempt various tactics in order of preference.  Our first preference
  // is not to evict any objects.  If we don't have enough resources, we'll
  // first try to evict dead data only.  If that fails, we'll just divide the
  // resources we have evenly.
  //
  // We always try to give the active renderers some head room in their
  // allocations so they can take memory away from an inactive renderer with
  // a large cache allocation.
  //
  // Notice the early exit will prevent attempting less desirable tactics once
  // we've found a workable strategy.
  AllocationStrategy strategy;
  if (  // Ideally, we'd like to give the active renderers some headroom and
        // keep all our current objects.
      AttemptTactic(KEEP_CURRENT_WITH_HEADROOM, active,
                    KEEP_CURRENT, inactive, &strategy) ||
      // If we can't have that, then we first try to evict the dead objects in
      // the caches of inactive renderers.
      AttemptTactic(KEEP_CURRENT_WITH_HEADROOM, active,
                    KEEP_LIVE, inactive, &strategy) ||
      // Next, we try to keep the live objects in the active renders (with some
      // room for new objects) and give whatever is left to the inactive
      // renderers.
      AttemptTactic(KEEP_LIVE_WITH_HEADROOM, active,
                    DIVIDE_EVENLY, inactive, &strategy) ||
      // If we've gotten this far, then we are very tight on memory.  Let's try
      // to at least keep around the live objects for the active renderers.
      AttemptTactic(KEEP_LIVE, active, DIVIDE_EVENLY, inactive, &strategy) ||
      // We're basically out of memory.  The best we can do is just divide up
      // what we have and soldier on.
      AttemptTactic(DIVIDE_EVENLY, active, DIVIDE_EVENLY, inactive,
                    &strategy)) {
    // Having found a workable strategy, we enact it.
    EnactStrategy(strategy);
  } else {
    // DIVIDE_EVENLY / DIVIDE_EVENLY should always succeed.
    NOTREACHED() << "Unable to find a cache allocation";
  }
}

void WebCacheManager::ReviseAllocationStrategyLater() {
  // Ask to be called back in a few milliseconds to actually recompute our
  // allocation.
  MessageLoop::current()->PostDelayedTask(FROM_HERE,
      revise_allocation_factory_.NewRunnableMethod(
          &WebCacheManager::ReviseAllocationStrategy),
      kReviseAllocationDelayMS);
}

void WebCacheManager::FindInactiveRenderers() {
  std::set<int>::const_iterator iter = active_renderers_.begin();
  while (iter != active_renderers_.end()) {
    StatsMap::iterator elmt = stats_.find(*iter);
    DCHECK(elmt != stats_.end());
    TimeDelta idle = Time::Now() - elmt->second.access;
    if (idle >= TimeDelta::FromMinutes(kRendererInactiveThresholdMinutes)) {
      // Moved to inactive status.  This invalidates our iterator.
      inactive_renderers_.insert(*iter);
      active_renderers_.erase(*iter);
      iter = active_renderers_.begin();
      continue;
    }
    ++iter;
  }
}
<commit_msg>Add histograms for web cache manager.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/renderer_host/web_cache_manager.h"

#include <algorithm>

#include "base/compiler_specific.h"
#include "base/histogram.h"
#include "base/singleton.h"
#include "base/sys_info.h"
#include "base/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/render_messages.h"

using base::Time;
using base::TimeDelta;
using WebKit::WebCache;

static const unsigned int kReviseAllocationDelayMS = 200 /* milliseconds */;

// The default size limit of the in-memory cache is 8 MB
static const int kDefaultMemoryCacheSize = 8 * 1024 * 1024;

namespace {

int GetDefaultCacheSize() {
  // Start off with a modest default
  int default_cache_size = kDefaultMemoryCacheSize;

  // Check how much physical memory the OS has
  int mem_size_mb = base::SysInfo::AmountOfPhysicalMemoryMB();
  if (mem_size_mb >= 1000)  // If we have a GB of memory, set a larger default.
    default_cache_size *= 4;
  else if (mem_size_mb >= 512)  // With 512 MB, set a slightly larger default.
    default_cache_size *= 2;

  UMA_HISTOGRAM_MEMORY_MB("Cache.MaxCacheSizeMB",
                          default_cache_size / 1024 / 1024);

  return default_cache_size;
}

}  // anonymous namespace

// static
void WebCacheManager::RegisterPrefs(PrefService* prefs) {
  prefs->RegisterIntegerPref(prefs::kMemoryCacheSize, GetDefaultCacheSize());
}

// static
WebCacheManager* WebCacheManager::GetInstance() {
  return Singleton<WebCacheManager>::get();
}

WebCacheManager::WebCacheManager()
    : global_size_limit_(GetDefaultGlobalSizeLimit()),
      ALLOW_THIS_IN_INITIALIZER_LIST(revise_allocation_factory_(this)) {
}

WebCacheManager::~WebCacheManager() {
}

void WebCacheManager::Add(int renderer_id) {
  DCHECK(inactive_renderers_.count(renderer_id) == 0);

  // It is tempting to make the following DCHECK here, but it fails when a new
  // tab is created as we observe activity from that tab because the
  // RenderProcessHost is recreated and adds itself.
  //
  //   DCHECK(active_renderers_.count(renderer_id) == 0);
  //
  // However, there doesn't seem to be much harm in receiving the calls in this
  // order.

  active_renderers_.insert(renderer_id);

  RendererInfo* stats = &(stats_[renderer_id]);
  memset(stats, 0, sizeof(*stats));
  stats->access = Time::Now();

  // Revise our allocation strategy to account for this new renderer.
  ReviseAllocationStrategyLater();
}

void WebCacheManager::Remove(int renderer_id) {
  // Erase all knowledge of this renderer
  active_renderers_.erase(renderer_id);
  inactive_renderers_.erase(renderer_id);
  stats_.erase(renderer_id);

  // Reallocate the resources used by this renderer
  ReviseAllocationStrategyLater();
}

void WebCacheManager::ObserveActivity(int renderer_id) {
  StatsMap::iterator item = stats_.find(renderer_id);
  if (item == stats_.end())
    return;  // We might see stats for a renderer that has been destroyed.

  // Record activity.
  active_renderers_.insert(renderer_id);
  item->second.access = Time::Now();

  std::set<int>::iterator elmt = inactive_renderers_.find(renderer_id);
  if (elmt != inactive_renderers_.end()) {
    inactive_renderers_.erase(elmt);

    // A renderer that was inactive, just became active.  We should make sure
    // it is given a fair cache allocation, but we defer this for a bit in
    // order to make this function call cheap.
    ReviseAllocationStrategyLater();
  }
}

void WebCacheManager::ObserveStats(int renderer_id,
                                   const WebCache::UsageStats& stats) {
  StatsMap::iterator entry = stats_.find(renderer_id);
  if (entry == stats_.end())
    return;  // We might see stats for a renderer that has been destroyed.

  // Record the updated stats.
  entry->second.capacity = stats.capacity;
  entry->second.deadSize = stats.deadSize;
  entry->second.liveSize = stats.liveSize;
  entry->second.maxDeadCapacity = stats.maxDeadCapacity;
  entry->second.minDeadCapacity = stats.minDeadCapacity;

  // trigger notification
  WebCache::UsageStats stats_details(stats);
  // &stats_details is only valid during the notification.
  // See notification_types.h.
  NotificationService::current()->Notify(
      NotificationType::WEB_CACHE_STATS_OBSERVED,
      Source<RenderProcessHost>(RenderProcessHost::FromID(renderer_id)),
      Details<WebCache::UsageStats>(&stats_details));
}

void WebCacheManager::SetGlobalSizeLimit(size_t bytes) {
  global_size_limit_ = bytes;
  ReviseAllocationStrategyLater();
}

// static
size_t WebCacheManager::GetDefaultGlobalSizeLimit() {
  PrefService* perf_service = g_browser_process->local_state();
  if (perf_service)
    return perf_service->GetInteger(prefs::kMemoryCacheSize);

  return GetDefaultCacheSize();
}

void WebCacheManager::GatherStats(const std::set<int>& renderers,
                                  WebCache::UsageStats* stats) {
  DCHECK(stats);

  memset(stats, 0, sizeof(WebCache::UsageStats));

  std::set<int>::const_iterator iter = renderers.begin();
  while (iter != renderers.end()) {
    StatsMap::iterator elmt = stats_.find(*iter);
    if (elmt != stats_.end()) {
      stats->minDeadCapacity += elmt->second.minDeadCapacity;
      stats->maxDeadCapacity += elmt->second.maxDeadCapacity;
      stats->capacity += elmt->second.capacity;
      stats->liveSize += elmt->second.liveSize;
      stats->deadSize += elmt->second.deadSize;
    }
    ++iter;
  }
}

// static
size_t WebCacheManager::GetSize(AllocationTactic tactic,
                                const WebCache::UsageStats& stats) {
  switch (tactic) {
  case DIVIDE_EVENLY:
    // We aren't going to reserve any space for existing objects.
    return 0;
  case KEEP_CURRENT_WITH_HEADROOM:
    // We need enough space for our current objects, plus some headroom.
    return 3 * GetSize(KEEP_CURRENT, stats) / 2;
  case KEEP_CURRENT:
    // We need enough space to keep our current objects.
    return stats.liveSize + stats.deadSize;
  case KEEP_LIVE_WITH_HEADROOM:
    // We need enough space to keep out live resources, plus some headroom.
    return 3 * GetSize(KEEP_LIVE, stats) / 2;
  case KEEP_LIVE:
    // We need enough space to keep our live resources.
    return stats.liveSize;
  default:
    NOTREACHED() << "Unknown cache allocation tactic";
    return 0;
  }
}

bool WebCacheManager::AttemptTactic(
    AllocationTactic active_tactic,
    const WebCache::UsageStats& active_stats,
    AllocationTactic inactive_tactic,
    const WebCache::UsageStats& inactive_stats,
    AllocationStrategy* strategy) {
  DCHECK(strategy);

  size_t active_size = GetSize(active_tactic, active_stats);
  size_t inactive_size = GetSize(inactive_tactic, inactive_stats);

  // Give up if we don't have enough space to use this tactic.
  if (global_size_limit_ < active_size + inactive_size)
    return false;

  // Compute the unreserved space available.
  size_t total_extra = global_size_limit_ - (active_size + inactive_size);

  // The plan for the extra space is to divide it evenly amoung the active
  // renderers.
  size_t shares = active_renderers_.size();

  // The inactive renderers get one share of the extra memory to be divided
  // among themselves.
  size_t inactive_extra = 0;
  if (inactive_renderers_.size() > 0) {
    ++shares;
    inactive_extra = total_extra / shares;
  }

  // The remaining memory is allocated to the active renderers.
  size_t active_extra = total_extra - inactive_extra;

  // Actually compute the allocations for each renderer.
  AddToStrategy(active_renderers_, active_tactic, active_extra, strategy);
  AddToStrategy(inactive_renderers_, inactive_tactic, inactive_extra, strategy);

  // We succeeded in computing an allocation strategy.
  return true;
}

void WebCacheManager::AddToStrategy(std::set<int> renderers,
                                    AllocationTactic tactic,
                                    size_t extra_bytes_to_allocate,
                                    AllocationStrategy* strategy) {
  DCHECK(strategy);

  // Nothing to do if there are no renderers.  It is common for there to be no
  // inactive renderers if there is a single active tab.
  if (renderers.size() == 0)
    return;

  // Divide the extra memory evenly among the renderers.
  size_t extra_each = extra_bytes_to_allocate / renderers.size();

  std::set<int>::const_iterator iter = renderers.begin();
  while (iter != renderers.end()) {
    size_t cache_size = extra_each;

    // Add in the space required to implement |tactic|.
    StatsMap::iterator elmt = stats_.find(*iter);
    if (elmt != stats_.end())
      cache_size += GetSize(tactic, elmt->second);

    // Record the allocation in our strategy.
    strategy->push_back(Allocation(*iter, cache_size));
    ++iter;
  }
}

void WebCacheManager::EnactStrategy(const AllocationStrategy& strategy) {
  // Inform each render process of its cache allocation.
  AllocationStrategy::const_iterator allocation = strategy.begin();
  while (allocation != strategy.end()) {
    RenderProcessHost* host = RenderProcessHost::FromID(allocation->first);
    if (host) {
      // This is the capacity this renderer has been allocated.
      size_t capacity = allocation->second;

      // We don't reserve any space for dead objects in the cache.  Instead, we
      // prefer to keep live objects around.  There is probably some performance
      // tuning to be done here.
      size_t min_dead_capacity = 0;

      // We allow the dead objects to consume all of the cache, if the renderer
      // so desires.  If we wanted this memory, we would have set the total
      // capacity lower.
      size_t max_dead_capacity = capacity;

      host->Send(new ViewMsg_SetCacheCapacities(min_dead_capacity,
                                                max_dead_capacity,
                                                capacity));
    }
    ++allocation;
  }
}

void WebCacheManager::ReviseAllocationStrategy() {
  DCHECK(stats_.size() <=
      active_renderers_.size() + inactive_renderers_.size());

  // Check if renderers have gone inactive.
  FindInactiveRenderers();

  // Gather statistics
  WebCache::UsageStats active;
  WebCache::UsageStats inactive;
  GatherStats(active_renderers_, &active);
  GatherStats(inactive_renderers_, &inactive);

  UMA_HISTOGRAM_COUNTS_100("Cache.ActiveTabs", active_renderers_.size());
  UMA_HISTOGRAM_COUNTS_100("Cache.InactiveTabs", inactive_renderers_.size());
  UMA_HISTOGRAM_MEMORY_MB("Cache.ActiveCapacityMB",
                          active.capacity / 1024 / 1024);
  UMA_HISTOGRAM_MEMORY_MB("Cache.ActiveDeadSizeMB",
                          active.deadSize / 1024 / 1024);
  UMA_HISTOGRAM_MEMORY_MB("Cache.ActiveLiveSizeMB",
                          active.liveSize / 1024 / 1024);
  UMA_HISTOGRAM_MEMORY_MB("Cache.InactiveCapacityMB",
                          inactive.capacity / 1024 / 1024);
  UMA_HISTOGRAM_MEMORY_MB("Cache.InactiveDeadSizeMB",
                          inactive.deadSize / 1024 / 1024);
  UMA_HISTOGRAM_MEMORY_MB("Cache.InactiveLiveSizeMB",
                          inactive.liveSize / 1024 / 1024);

  // Compute an allocation strategy.
  //
  // We attempt various tactics in order of preference.  Our first preference
  // is not to evict any objects.  If we don't have enough resources, we'll
  // first try to evict dead data only.  If that fails, we'll just divide the
  // resources we have evenly.
  //
  // We always try to give the active renderers some head room in their
  // allocations so they can take memory away from an inactive renderer with
  // a large cache allocation.
  //
  // Notice the early exit will prevent attempting less desirable tactics once
  // we've found a workable strategy.
  AllocationStrategy strategy;
  if (  // Ideally, we'd like to give the active renderers some headroom and
        // keep all our current objects.
      AttemptTactic(KEEP_CURRENT_WITH_HEADROOM, active,
                    KEEP_CURRENT, inactive, &strategy) ||
      // If we can't have that, then we first try to evict the dead objects in
      // the caches of inactive renderers.
      AttemptTactic(KEEP_CURRENT_WITH_HEADROOM, active,
                    KEEP_LIVE, inactive, &strategy) ||
      // Next, we try to keep the live objects in the active renders (with some
      // room for new objects) and give whatever is left to the inactive
      // renderers.
      AttemptTactic(KEEP_LIVE_WITH_HEADROOM, active,
                    DIVIDE_EVENLY, inactive, &strategy) ||
      // If we've gotten this far, then we are very tight on memory.  Let's try
      // to at least keep around the live objects for the active renderers.
      AttemptTactic(KEEP_LIVE, active, DIVIDE_EVENLY, inactive, &strategy) ||
      // We're basically out of memory.  The best we can do is just divide up
      // what we have and soldier on.
      AttemptTactic(DIVIDE_EVENLY, active, DIVIDE_EVENLY, inactive,
                    &strategy)) {
    // Having found a workable strategy, we enact it.
    EnactStrategy(strategy);
  } else {
    // DIVIDE_EVENLY / DIVIDE_EVENLY should always succeed.
    NOTREACHED() << "Unable to find a cache allocation";
  }
}

void WebCacheManager::ReviseAllocationStrategyLater() {
  // Ask to be called back in a few milliseconds to actually recompute our
  // allocation.
  MessageLoop::current()->PostDelayedTask(FROM_HERE,
      revise_allocation_factory_.NewRunnableMethod(
          &WebCacheManager::ReviseAllocationStrategy),
      kReviseAllocationDelayMS);
}

void WebCacheManager::FindInactiveRenderers() {
  std::set<int>::const_iterator iter = active_renderers_.begin();
  while (iter != active_renderers_.end()) {
    StatsMap::iterator elmt = stats_.find(*iter);
    DCHECK(elmt != stats_.end());
    TimeDelta idle = Time::Now() - elmt->second.access;
    if (idle >= TimeDelta::FromMinutes(kRendererInactiveThresholdMinutes)) {
      // Moved to inactive status.  This invalidates our iterator.
      inactive_renderers_.insert(*iter);
      active_renderers_.erase(*iter);
      iter = active_renderers_.begin();
      continue;
    }
    ++iter;
  }
}
<|endoftext|>


<commit_before>//===------------------------ stdexcept.cpp -------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "stdexcept"
#include "new"
#include "string"
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include <cstddef>
#include "system_error"

#ifndef __has_include
#define __has_include(inc) 0
#endif

#ifdef __APPLE__
#include <cxxabi.h>
#elif defined(LIBCXXRT) || __has_include(<cxxabi.h>)
#include <cxxabi.h>
#endif

// Note:  optimize for size

#if ! defined(_LIBCPP_MSVC)
#pragma GCC visibility push(hidden)
#endif

namespace
{

class __libcpp_nmstr
{
private:
    const char* str_;

    typedef std::size_t unused_t;
    typedef std::ptrdiff_t count_t;

    static const std::ptrdiff_t offset = static_cast<std::ptrdiff_t>(2*sizeof(unused_t) +
                                                                       sizeof(count_t));

    count_t& count() const _NOEXCEPT {return *const_cast<count_t *>(reinterpret_cast<const count_t *>(str_ - sizeof(count_t)));}
public:
    explicit __libcpp_nmstr(const char* msg);
    __libcpp_nmstr(const __libcpp_nmstr& s) _NOEXCEPT;
    __libcpp_nmstr& operator=(const __libcpp_nmstr& s) _NOEXCEPT;
    ~__libcpp_nmstr();
    const char* c_str() const _NOEXCEPT {return str_;}
};

__libcpp_nmstr::__libcpp_nmstr(const char* msg)
{
    std::size_t len = strlen(msg);
    str_ = new char[len + 1 + offset];
    unused_t* c = reinterpret_cast<unused_t*>(const_cast<char *>(str_));
    c[0] = c[1] = len;
    str_ += offset;
    count() = 0;
    std::memcpy(const_cast<char*>(c_str()), msg, len + 1);
}

inline
__libcpp_nmstr::__libcpp_nmstr(const __libcpp_nmstr& s) _NOEXCEPT
    : str_(s.str_)
{
    __sync_add_and_fetch(&count(), 1);
}

__libcpp_nmstr&
__libcpp_nmstr::operator=(const __libcpp_nmstr& s) _NOEXCEPT
{
    const char* p = str_;
    str_ = s.str_;
    __sync_add_and_fetch(&count(), 1);
    if (__sync_add_and_fetch(reinterpret_cast<const count_t*>(p-sizeof(count_t)), count_t(-1)) < 0)
        delete [] (p-offset);
    return *this;
}

inline
__libcpp_nmstr::~__libcpp_nmstr()
{
    if (__sync_add_and_fetch(&count(), count_t(-1)) < 0)
        delete [] (str_ - offset);
}

}

#if ! defined(_LIBCPP_MSVC)
#pragma GCC visibility pop
#endif

namespace std  // purposefully not using versioning namespace
{

logic_error::logic_error(const string& msg)
{
    __libcpp_nmstr *s = static_cast<__libcpp_nmstr *>(__imp_);
    ::new(s) __libcpp_nmstr(msg.c_str());
}

logic_error::logic_error(const char* msg)
{
    __libcpp_nmstr *s = static_cast<__libcpp_nmstr *>(__imp_);
    ::new(s) __libcpp_nmstr(msg);
}

logic_error::logic_error(const logic_error& le) _NOEXCEPT
{
    __libcpp_nmstr *s = static_cast<__libcpp_nmstr *>(__imp_);
    const __libcpp_nmstr *s2 = static_cast<const __libcpp_nmstr *>(le.__imp_);
    ::new(s) __libcpp_nmstr(*s2);
}

logic_error&
logic_error::operator=(const logic_error& le) _NOEXCEPT
{
    __libcpp_nmstr *s1 = static_cast<__libcpp_nmstr *>(__imp_);
    const __libcpp_nmstr *s2 = static_cast<const __libcpp_nmstr *>(le.__imp_);
    *s1 = *s2;
    return *this;
}

#if !defined(_LIBCPPABI_VERSION) && !defined(LIBSTDCXX)

logic_error::~logic_error() _NOEXCEPT
{
    __libcpp_nmstr *s = static_cast<__libcpp_nmstr *>(__imp_);
    s->~__libcpp_nmstr();
}

const char*
logic_error::what() const _NOEXCEPT
{
    __libcpp_nmstr *s = static_cast<__libcpp_nmstr *>(__imp_);
    return s->c_str();
}

#endif

runtime_error::runtime_error(const string& msg)
{
    __libcpp_nmstr *s = static_cast<__libcpp_nmstr *>(__imp_);
    ::new(s) __libcpp_nmstr(msg.c_str());
}

runtime_error::runtime_error(const char* msg)
{
    __libcpp_nmstr *s = static_cast<__libcpp_nmstr *>(__imp_);
    ::new(s) __libcpp_nmstr(msg);
}

runtime_error::runtime_error(const runtime_error& le) _NOEXCEPT
{
    __libcpp_nmstr *s = static_cast<__libcpp_nmstr *>(__imp_);
    const __libcpp_nmstr *s2 = static_cast<const __libcpp_nmstr *>(le.__imp_);
    ::new(s) __libcpp_nmstr(*s2);
}

runtime_error&
runtime_error::operator=(const runtime_error& le) _NOEXCEPT
{
    __libcpp_nmstr *s1 = static_cast<__libcpp_nmstr *>(__imp_);
    const __libcpp_nmstr *s2 = static_cast<const __libcpp_nmstr *>(le.__imp_);
    *s1 = *s2;
    return *this;
}

#if !defined(_LIBCPPABI_VERSION) && !defined(LIBSTDCXX)

runtime_error::~runtime_error() _NOEXCEPT
{
    __libcpp_nmstr *s = static_cast<__libcpp_nmstr *>(__imp_);
    s->~__libcpp_nmstr();
}

const char*
runtime_error::what() const _NOEXCEPT
{
    __libcpp_nmstr *s = static_cast<__libcpp_nmstr *>(__imp_);
    return s->c_str();
}

domain_error::~domain_error() _NOEXCEPT {}
invalid_argument::~invalid_argument() _NOEXCEPT {}
length_error::~length_error() _NOEXCEPT {}
out_of_range::~out_of_range() _NOEXCEPT {}

range_error::~range_error() _NOEXCEPT {}
overflow_error::~overflow_error() _NOEXCEPT {}
underflow_error::~underflow_error() _NOEXCEPT {}

#endif

}  // std
<commit_msg>Replace casts of __impl_ with the correct reinterpret_cast of the address. Restores the assembly of before r198504.<commit_after>//===------------------------ stdexcept.cpp -------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "stdexcept"
#include "new"
#include "string"
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include <cstddef>
#include "system_error"

#ifndef __has_include
#define __has_include(inc) 0
#endif

#ifdef __APPLE__
#include <cxxabi.h>
#elif defined(LIBCXXRT) || __has_include(<cxxabi.h>)
#include <cxxabi.h>
#endif

// Note:  optimize for size

#if ! defined(_LIBCPP_MSVC)
#pragma GCC visibility push(hidden)
#endif

namespace
{

class __libcpp_nmstr
{
private:
    const char* str_;

    typedef std::size_t unused_t;
    typedef std::ptrdiff_t count_t;

    static const std::ptrdiff_t offset = static_cast<std::ptrdiff_t>(2*sizeof(unused_t) +
                                                                       sizeof(count_t));

    count_t& count() const _NOEXCEPT {return *const_cast<count_t *>(reinterpret_cast<const count_t *>(str_ - sizeof(count_t)));}
public:
    explicit __libcpp_nmstr(const char* msg);
    __libcpp_nmstr(const __libcpp_nmstr& s) _NOEXCEPT;
    __libcpp_nmstr& operator=(const __libcpp_nmstr& s) _NOEXCEPT;
    ~__libcpp_nmstr();
    const char* c_str() const _NOEXCEPT {return str_;}
};

__libcpp_nmstr::__libcpp_nmstr(const char* msg)
{
    std::size_t len = strlen(msg);
    str_ = new char[len + 1 + offset];
    unused_t* c = reinterpret_cast<unused_t*>(const_cast<char *>(str_));
    c[0] = c[1] = len;
    str_ += offset;
    count() = 0;
    std::memcpy(const_cast<char*>(c_str()), msg, len + 1);
}

inline
__libcpp_nmstr::__libcpp_nmstr(const __libcpp_nmstr& s) _NOEXCEPT
    : str_(s.str_)
{
    __sync_add_and_fetch(&count(), 1);
}

__libcpp_nmstr&
__libcpp_nmstr::operator=(const __libcpp_nmstr& s) _NOEXCEPT
{
    const char* p = str_;
    str_ = s.str_;
    __sync_add_and_fetch(&count(), 1);
    if (__sync_add_and_fetch(reinterpret_cast<const count_t*>(p-sizeof(count_t)), count_t(-1)) < 0)
        delete [] (p-offset);
    return *this;
}

inline
__libcpp_nmstr::~__libcpp_nmstr()
{
    if (__sync_add_and_fetch(&count(), count_t(-1)) < 0)
        delete [] (str_ - offset);
}

}

#if ! defined(_LIBCPP_MSVC)
#pragma GCC visibility pop
#endif

namespace std  // purposefully not using versioning namespace
{

logic_error::logic_error(const string& msg)
{
    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
    ::new(s) __libcpp_nmstr(msg.c_str());
}

logic_error::logic_error(const char* msg)
{
    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
    ::new(s) __libcpp_nmstr(msg);
}

logic_error::logic_error(const logic_error& le) _NOEXCEPT
{
    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
    const __libcpp_nmstr *s2 = reinterpret_cast<const __libcpp_nmstr *>(&le.__imp_);
    ::new(s) __libcpp_nmstr(*s2);
}

logic_error&
logic_error::operator=(const logic_error& le) _NOEXCEPT
{
    __libcpp_nmstr *s1 = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
    const __libcpp_nmstr *s2 = reinterpret_cast<const __libcpp_nmstr *>(&le.__imp_);
    *s1 = *s2;
    return *this;
}

#if !defined(_LIBCPPABI_VERSION) && !defined(LIBSTDCXX)

logic_error::~logic_error() _NOEXCEPT
{
    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
    s->~__libcpp_nmstr();
}

const char*
logic_error::what() const _NOEXCEPT
{
    const __libcpp_nmstr *s = reinterpret_cast<const __libcpp_nmstr *>(&__imp_);
    return s->c_str();
}

#endif

runtime_error::runtime_error(const string& msg)
{
    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
    ::new(s) __libcpp_nmstr(msg.c_str());
}

runtime_error::runtime_error(const char* msg)
{
    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
    ::new(s) __libcpp_nmstr(msg);
}

runtime_error::runtime_error(const runtime_error& le) _NOEXCEPT
{
    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
    const __libcpp_nmstr *s2 = reinterpret_cast<const __libcpp_nmstr *>(&le.__imp_);
    ::new(s) __libcpp_nmstr(*s2);
}

runtime_error&
runtime_error::operator=(const runtime_error& le) _NOEXCEPT
{
    __libcpp_nmstr *s1 = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
    const __libcpp_nmstr *s2 = reinterpret_cast<const __libcpp_nmstr *>(&le.__imp_);
    *s1 = *s2;
    return *this;
}

#if !defined(_LIBCPPABI_VERSION) && !defined(LIBSTDCXX)

runtime_error::~runtime_error() _NOEXCEPT
{
    __libcpp_nmstr *s = reinterpret_cast<__libcpp_nmstr *>(&__imp_);
    s->~__libcpp_nmstr();
}

const char*
runtime_error::what() const _NOEXCEPT
{
    const __libcpp_nmstr *s = reinterpret_cast<const __libcpp_nmstr *>(&__imp_);
    return s->c_str();
}

domain_error::~domain_error() _NOEXCEPT {}
invalid_argument::~invalid_argument() _NOEXCEPT {}
length_error::~length_error() _NOEXCEPT {}
out_of_range::~out_of_range() _NOEXCEPT {}

range_error::~range_error() _NOEXCEPT {}
overflow_error::~overflow_error() _NOEXCEPT {}
underflow_error::~underflow_error() _NOEXCEPT {}

#endif

}  // std
<|endoftext|>


<commit_before>#include <cassert>

#include <cstddef>

#include <cstdint>

#include <type_traits>

#include <utility>

#include <new>

namespace generic
{

template<typename F>
class forwarder;

template<typename R, typename ...A>
class forwarder<R (A...)>
{
public:
  forwarder() = default;

  forwarder(forwarder const&) = default;

  template<typename T>
  forwarder(T&& f) noexcept : stub_(handler<T>::stub)
  {
    static_assert(sizeof(T) <= sizeof(store_), "functor too large");
    static_assert(::std::is_trivially_destructible<T>::value,
      "functor not trivially destructible");
    new (&store_) handler<T>(::std::forward<T>(f));
  }

  forwarder& operator=(forwarder const&) = default;

  template <
    typename T,
    typename = typename ::std::enable_if<
      !::std::is_same<forwarder, typename ::std::decay<T>::type>{}
    >::type
  >
  forwarder& operator=(T&& f) noexcept
  {
    static_assert(sizeof(T) <= sizeof(store_), "functor too large");
    static_assert(::std::is_trivially_destructible<T>::value,
      "functor not trivially destructible");
    new (&store_) handler<T>(::std::forward<T>(f));

    stub_ = handler<T>::stub;

    return *this;
  }

  R operator() (A... args)
  {
    //assert(stub_);
    return stub_(&store_, ::std::forward<A>(args)...);
  }

private:
  template<typename T>
  struct handler
  {
    handler(T&& f) noexcept : f_(::std::forward<T>(f))
    {
    }

    static R stub(void* ptr, A&&... args)
    {
      return static_cast<handler<T>*>(ptr)->f_(::std::forward<A>(args)...);
    }

    T f_;
  };

#if defined(__clang__)
  using max_align_type = long double;
#elif defined(__GNUC__)
  using max_align_type = ::max_align_t;
#else
  using max_align_type = ::std::max_align_t;
#endif

  alignas(max_align_type) ::std::uintptr_t store_;

  R (*stub_)(void*, A&&...){};
};

}
<commit_msg>some fixes<commit_after>#include <cassert>

#include <cstddef>

#include <cstdint>

#include <type_traits>

#include <utility>

#include <new>

namespace generic
{

template<typename F>
class forwarder;

template<typename R, typename ...A>
class forwarder<R (A...)>
{
public:
  forwarder() = default;

  forwarder(forwarder const&) = default;

  template<typename T>
  forwarder(T&& f) : stub_(handler<T>::stub)
  {
    static_assert(sizeof(T) <= sizeof(store_), "functor too large");
    static_assert(::std::is_trivially_destructible<T>::value,
      "functor not trivially destructible");
    new (&store_) handler<T>(::std::forward<T>(f));
  }

  forwarder& operator=(forwarder const&) = default;

  template <
    typename T,
    typename = typename ::std::enable_if<
      !::std::is_same<forwarder, typename ::std::decay<T>::type>{}
    >::type
  >
  forwarder& operator=(T&& f)
  {
    static_assert(sizeof(T) <= sizeof(store_), "functor too large");
    static_assert(::std::is_trivially_destructible<T>::value,
      "functor not trivially destructible");
    new (&store_) handler<T>(::std::forward<T>(f));

    stub_ = handler<T>::stub;

    return *this;
  }

  R operator() (A... args)
  {
    //assert(stub_);
    return stub_(&store_, ::std::forward<A>(args)...);
  }

private:
  template<typename T>
  struct handler
  {
    handler(T&& f) noexcept : f_(::std::forward<T>(f))
    {
    }

    static R stub(void* ptr, A&&... args)
    {
      return static_cast<handler<T>*>(ptr)->f_(::std::forward<A>(args)...);
    }

    T f_;
  };

#if defined(__clang__)
  using max_align_type = long double;
#elif defined(__GNUC__)
  using max_align_type = ::max_align_t;
#else
  using max_align_type = ::std::max_align_t;
#endif

  alignas(max_align_type) ::std::uintptr_t store_;

  R (*stub_)(void*, A&&...){};
};

}
<|endoftext|>


<commit_before>#ifndef ITER_ENUMERATE_H_
#define ITER_ENUMERATE_H_

#include "internal/iterbase.hpp"

#include <utility>
#include <iterator>
#include <functional>
#include <initializer_list>
#include <type_traits>

namespace iter {
  namespace impl {
    template <typename Container, typename Index>
    class Enumerable;

    using EnumerateFn = IterToolFnOptionalBindSecond<Enumerable, std::size_t>;
  }
  constexpr impl::EnumerateFn enumerate{};
}

template <typename Container, typename Index>
class iter::impl::Enumerable {
 private:
  Container container;
  const Index start;

  friend EnumerateFn;

  // for IterYield
  using BasePair = std::pair<Index, iterator_deref<Container>>;

  // Value constructor for use only in the enumerate function
  Enumerable(Container&& in_container, Index in_start)
      : container(std::forward<Container>(in_container)), start{in_start} {}

 public:
  Enumerable(Enumerable&&) = default;

  // "yielded" by the Enumerable::Iterator.  Has a .index, and a
  // .element referencing the value yielded by the subiterator
  class IterYield : public BasePair {
   public:
    using BasePair::BasePair;
    typename BasePair::first_type& index = BasePair::first;
    typename BasePair::second_type& element = BasePair::second;
  };

  //  Holds an iterator of the contained type and an Index for the
  //  index.  Each call to ++ increments both of these data members.
  //  Each dereference returns an IterYield.
  class Iterator : public std::iterator<std::input_iterator_tag, IterYield> {
   private:
    iterator_type<Container> sub_iter;
    Index index;

   public:
    Iterator(iterator_type<Container>&& si, Index start)
        : sub_iter{std::move(si)}, index{start} {}

    IterYield operator*() {
      return {this->index, *this->sub_iter};
    }

    ArrowProxy<IterYield> operator->() {
      return {**this};
    }

    Iterator& operator++() {
      ++this->sub_iter;
      ++this->index;
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return this->sub_iter != other.sub_iter;
    }

    bool operator==(const Iterator& other) const {
      return !(*this != other);
    }
  };

  Iterator begin() {
    return {std::begin(this->container), start};
  }

  Iterator end() {
    return {std::end(this->container), start};
  }
};

#endif
<commit_msg>Supports different begin and end in enumerate<commit_after>#ifndef ITER_ENUMERATE_H_
#define ITER_ENUMERATE_H_

#include "internal/iterbase.hpp"
#include "internal/iterator_wrapper.hpp"

#include <utility>
#include <iterator>
#include <functional>
#include <initializer_list>
#include <type_traits>

namespace iter {
  namespace impl {
    template <typename Container, typename Index>
    class Enumerable;

    using EnumerateFn = IterToolFnOptionalBindSecond<Enumerable, std::size_t>;
  }
  constexpr impl::EnumerateFn enumerate{};
}

template <typename Container, typename Index>
class iter::impl::Enumerable {
 private:
  Container container;
  const Index start;

  friend EnumerateFn;

  // for IterYield
  using BasePair = std::pair<Index, iterator_deref<Container>>;

  // Value constructor for use only in the enumerate function
  Enumerable(Container&& in_container, Index in_start)
      : container(std::forward<Container>(in_container)), start{in_start} {}

 public:
  Enumerable(Enumerable&&) = default;

  // "yielded" by the Enumerable::Iterator.  Has a .index, and a
  // .element referencing the value yielded by the subiterator
  class IterYield : public BasePair {
   public:
    using BasePair::BasePair;
    typename BasePair::first_type& index = BasePair::first;
    typename BasePair::second_type& element = BasePair::second;
  };

  //  Holds an iterator of the contained type and an Index for the
  //  index.  Each call to ++ increments both of these data members.
  //  Each dereference returns an IterYield.
  class Iterator : public std::iterator<std::input_iterator_tag, IterYield> {
   private:
    IteratorWrapper<Container> sub_iter;
    Index index;

   public:
    Iterator(IteratorWrapper<Container>&& si, Index start)
        : sub_iter{std::move(si)}, index{start} {}

    IterYield operator*() {
      return {this->index, *this->sub_iter};
    }

    ArrowProxy<IterYield> operator->() {
      return {**this};
    }

    Iterator& operator++() {
      ++this->sub_iter;
      ++this->index;
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return this->sub_iter != other.sub_iter;
    }

    bool operator==(const Iterator& other) const {
      return !(*this != other);
    }
  };

  Iterator begin() {
    return {std::begin(this->container), start};
  }

  Iterator end() {
    return {std::end(this->container), start};
  }
};

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT,
 * Applied Mathematics, Norway.
 *
 * Contact information: E-mail: tor.dokken@sintef.no
 * SINTEF ICT, Department of Applied Mathematics,
 * P.O. Box 124 Blindern,
 * 0314 Oslo, Norway.
 *
 * This file is part of GoTools.
 *
 * GoTools is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * GoTools is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with GoTools. If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public
 * License, a covered work must retain the producer line in every data
 * file that is created or manipulated using GoTools.
 *
 * Other Usage
 * You can be released from the requirements of the license by purchasing
 * a commercial license. Buying such a license is mandatory as soon as you
 * develop commercial activities involving the GoTools library without
 * disclosing the source code of your own applications.
 *
 * This file may be used in accordance with the terms contained in a
 * written agreement between you and SINTEF ICT.
 */

#include "GoTools/viewlib/DefaultDataHandler.h"

#include "GoTools/viewlib/vol_and_lr/DataHandlerVolAndLR.h"
#include "GoTools/viewlib/vol_and_lr/RectangularVolumePropertySheet.h"
#include "GoTools/viewlib/vol_and_lr/gvRectangularVolumePaintable.h"

#include "GoTools/viewlib/gvRectangularSurfacePaintable.h"
#include "GoTools/viewlib/RectangularSurfacePropertySheet.h"

#include "GoTools/lrsplines2D/LRSplineSurface.h"
#include "GoTools/trivariate/SplineVolume.h"
#include "GoTools/trivariate/RectangularVolumeTesselator.h"
#include "GoTools/tesselator/RectangularSurfaceTesselator.h"

#include <GoTools/geometry/GoTools.h>
#include "GoTools/geometry/Factory.h"

using namespace Go;
using std::vector;
// using std::shared_ptr;
// using dynamic_pointer_cast;

//===========================================================================
DataHandlerVolAndLR::~DataHandlerVolAndLR()
  //===========================================================================
{
}

//===========================================================================
DataHandlerVolAndLR::DataHandlerVolAndLR()
  //===========================================================================
{
    // Create the default factory
    GoTools::init();
    Registrator<SplineVolume> r700;
    Registrator<LRSplineSurface> r293;

    //      cout << "Registering should be processed by now." << endl;
}

//===========================================================================
void DataHandlerVolAndLR::create(shared_ptr<GeomObject> obj,
				const gvColor& col, int id)
  //===========================================================================
{
    //    cout << "DataHandlerVolAndLR::create... " << flush;
    ClassType type = obj->instanceType();

    // Make unbounded elementary objects bounded with "canonical" parameter
    // bounds. This is ugly and arbitrary. We need this hack in order to
    // tesselate.
    switch (type) {
    case Class_LRSplineSurface:
      {
	const ParamSurface& sf
	  = dynamic_cast<const ParamSurface&>(*obj);
	if (sf.dimension() == 1)
	{
	    LRSplineSurface& lr_sf
		= dynamic_cast<LRSplineSurface&>(*obj);
#if 0
	    MESSAGE("Setting parameter domain to the unit square!");
	    lr_sf.setParameterDomain(0.0, 1.0, 0.0, 1.0);
#endif
	    MESSAGE("Lifting lrspline_sf from 1D to 3D.");
	    lr_sf.to3D();
	}

#if 0
	{
	    LRSplineSurface& lr_sf
		= dynamic_cast<LRSplineSurface&>(*obj);
	    MESSAGE("Translating the surface to the origin!");
	    BoundingBox bd_box = lr_sf.boundingBox();
	    Point mid_pt = 0.5*(bd_box.low() + bd_box.high());
	    Point transl_pt = -mid_pt;
	    std::cout << "transl_pt: (" << transl_pt[0] << ", " << transl_pt[1] << ", " << transl_pt[2] << std::endl;
	    lr_sf.translate(transl_pt);
	}
#endif

	shared_ptr<RectangularSurfaceTesselator> te(new RectangularSurfaceTesselator(sf));
	shared_ptr<gvRectangularSurfacePaintable> pa
	  (new gvRectangularSurfacePaintable(*(te->getMesh()), col, id));
	shared_ptr<ParamSurface> psf =
	  dynamic_pointer_cast<ParamSurface, GeomObject>(obj);
	shared_ptr<gvPropertySheet> ps(new RectangularSurfacePropertySheet(te.get(), pa.get(),
									   psf));
	tesselator_ = te;
	paintable_ = pa;
	property_sheet_ = ps;
	break;
      }
    case Class_SplineVolume:
      {
//	MESSAGE("SplineVolume support coming soon!");

	const SplineVolume& sv
	  = dynamic_cast<const SplineVolume&>(*obj);

	shared_ptr<RectangularVolumeTesselator> te(new RectangularVolumeTesselator(sv));
	shared_ptr<gvRectangularVolumePaintable> pa
	  (new gvRectangularVolumePaintable(*(te->getMesh()), col, id));
	shared_ptr<ParamVolume> pvol =
	  dynamic_pointer_cast<ParamVolume, GeomObject>(obj);
	shared_ptr<gvPropertySheet> ps(new RectangularVolumePropertySheet(te.get(), pa.get(),
									  pvol));
	tesselator_ = te;
	paintable_ = pa;
	property_sheet_ = ps;
	break;

      }
    default:
	DefaultDataHandler::create(obj, col, id);
    }
  //    cout << "finished" << endl;
}

<commit_msg>* Lifting 1D trimmed LRSplineSurface to 3D in viewlib data handler.<commit_after>/*
 * Copyright (C) 1998, 2000-2007, 2010, 2011, 2012, 2013 SINTEF ICT,
 * Applied Mathematics, Norway.
 *
 * Contact information: E-mail: tor.dokken@sintef.no
 * SINTEF ICT, Department of Applied Mathematics,
 * P.O. Box 124 Blindern,
 * 0314 Oslo, Norway.
 *
 * This file is part of GoTools.
 *
 * GoTools is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * GoTools is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with GoTools. If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public
 * License, a covered work must retain the producer line in every data
 * file that is created or manipulated using GoTools.
 *
 * Other Usage
 * You can be released from the requirements of the license by purchasing
 * a commercial license. Buying such a license is mandatory as soon as you
 * develop commercial activities involving the GoTools library without
 * disclosing the source code of your own applications.
 *
 * This file may be used in accordance with the terms contained in a
 * written agreement between you and SINTEF ICT.
 */

#include "GoTools/viewlib/DefaultDataHandler.h"

#include "GoTools/viewlib/vol_and_lr/DataHandlerVolAndLR.h"
#include "GoTools/viewlib/vol_and_lr/RectangularVolumePropertySheet.h"
#include "GoTools/viewlib/vol_and_lr/gvRectangularVolumePaintable.h"

#include "GoTools/viewlib/gvRectangularSurfacePaintable.h"
#include "GoTools/viewlib/RectangularSurfacePropertySheet.h"

#include "GoTools/lrsplines2D/LRSplineSurface.h"
#include "GoTools/trivariate/SplineVolume.h"
#include "GoTools/trivariate/RectangularVolumeTesselator.h"
#include "GoTools/tesselator/RectangularSurfaceTesselator.h"

#include <GoTools/geometry/GoTools.h>
#include "GoTools/geometry/Factory.h"

using namespace Go;
using std::vector;
// using std::shared_ptr;
// using dynamic_pointer_cast;

//===========================================================================
DataHandlerVolAndLR::~DataHandlerVolAndLR()
  //===========================================================================
{
}

//===========================================================================
DataHandlerVolAndLR::DataHandlerVolAndLR()
  //===========================================================================
{
    // Create the default factory
    GoTools::init();
    Registrator<SplineVolume> r700;
    Registrator<LRSplineSurface> r293;

    //      cout << "Registering should be processed by now." << endl;
}

//===========================================================================
void DataHandlerVolAndLR::create(shared_ptr<GeomObject> obj,
				const gvColor& col, int id)
  //===========================================================================
{
    //    cout << "DataHandlerVolAndLR::create... " << flush;
    ClassType type = obj->instanceType();

    // Make unbounded elementary objects bounded with "canonical" parameter
    // bounds. This is ugly and arbitrary. We need this hack in order to
    // tesselate.
    switch (type) {
    case Class_LRSplineSurface:
      {
	const ParamSurface& sf
	  = dynamic_cast<const ParamSurface&>(*obj);
	if (sf.dimension() == 1)
	{
	    LRSplineSurface& lr_sf
		= dynamic_cast<LRSplineSurface&>(*obj);
#if 0
	    MESSAGE("Setting parameter domain to the unit square!");
	    lr_sf.setParameterDomain(0.0, 1.0, 0.0, 1.0);
#endif
	    MESSAGE("Lifting lrspline_sf from 1D to 3D.");
	    lr_sf.to3D();
	}

#if 0
	{
	    LRSplineSurface& lr_sf
		= dynamic_cast<LRSplineSurface&>(*obj);
	    MESSAGE("Translating the surface to the origin!");
	    BoundingBox bd_box = lr_sf.boundingBox();
	    Point mid_pt = 0.5*(bd_box.low() + bd_box.high());
	    Point transl_pt = -mid_pt;
	    std::cout << "transl_pt: (" << transl_pt[0] << ", " << transl_pt[1] << ", " << transl_pt[2] << std::endl;
	    lr_sf.translate(transl_pt);
	}
#endif

	shared_ptr<RectangularSurfaceTesselator> te(new RectangularSurfaceTesselator(sf));
	shared_ptr<gvRectangularSurfacePaintable> pa
	  (new gvRectangularSurfacePaintable(*(te->getMesh()), col, id));
	shared_ptr<ParamSurface> psf =
	  dynamic_pointer_cast<ParamSurface, GeomObject>(obj);
	shared_ptr<gvPropertySheet> ps(new RectangularSurfacePropertySheet(te.get(), pa.get(),
									   psf));
	tesselator_ = te;
	paintable_ = pa;
	property_sheet_ = ps;
	break;
      }
    case Class_SplineVolume:
      {
//	MESSAGE("SplineVolume support coming soon!");

	const SplineVolume& sv
	  = dynamic_cast<const SplineVolume&>(*obj);

	shared_ptr<RectangularVolumeTesselator> te(new RectangularVolumeTesselator(sv));
	shared_ptr<gvRectangularVolumePaintable> pa
	  (new gvRectangularVolumePaintable(*(te->getMesh()), col, id));
	shared_ptr<ParamVolume> pvol =
	  dynamic_pointer_cast<ParamVolume, GeomObject>(obj);
	shared_ptr<gvPropertySheet> ps(new RectangularVolumePropertySheet(te.get(), pa.get(),
									  pvol));
	tesselator_ = te;
	paintable_ = pa;
	property_sheet_ = ps;
	break;

      }
    case Class_BoundedSurface:
    {
	BoundedSurface& sf
	  = dynamic_cast<BoundedSurface&>(*obj);
	shared_ptr<ParamSurface> under_sf = sf.underlyingSurface();
	if (under_sf->instanceType() == Class_LRSplineSurface)
	{
	    MESSAGE("Lifting underlying lrspline_sf from 1D to 3D.");
	    shared_ptr<LRSplineSurface> lr_sf = dynamic_pointer_cast<LRSplineSurface>(under_sf);
	    lr_sf->to3D();
	}
    }
    default:
	DefaultDataHandler::create(obj, col, id);
    }
  //    cout << "finished" << endl;
}

<|endoftext|>


<commit_before>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "otbWrapperQtWidgetParameterGroup.h"
#include "otbWrapperQtWidgetChoiceParameter.h"
#include "otbWrapperQtWidgetParameterLabel.h"
#include "otbWrapperQtWidgetParameterFactory.h"

namespace otb
{
namespace Wrapper
{

QtWidgetParameterGroup::QtWidgetParameterGroup(ParameterGroup::Pointer paramList, QtWidgetModel* m)
: QtWidgetParameterBase(paramList, m),
  m_ParamList(paramList)
{
}

QtWidgetParameterGroup::~QtWidgetParameterGroup()
{
}

void QtWidgetParameterGroup::DoUpdateGUI()
{
  WidgetListIteratorType it = m_WidgetList.begin();
  for (it = m_WidgetList.begin(); it != m_WidgetList.end(); ++it)
    {
    (*it)->UpdateGUI();
    }
}

void QtWidgetParameterGroup::DoCreateWidget()
{
  // a GridLayout with two columns : parameter label / parameter widget
  QGridLayout *gridLayout = new QGridLayout;
  gridLayout->setSpacing(1);
  gridLayout->setContentsMargins(0, 0, 0, 0);

  unsigned int nbParams = m_ParamList->GetNumberOfParameters();
  for (unsigned int i = 0; i < nbParams; ++i)
    {
    Parameter* param = m_ParamList->GetParameterByIndex(i);

    if (param != 0)
      {
      ParameterGroup* paramAsGroup = dynamic_cast<ParameterGroup*>(param);
      ChoiceParameter* paramAsChoice = dynamic_cast<ChoiceParameter*>(param);

      if (paramAsGroup == 0 && paramAsChoice == 0)
        {
        // Label (col 1)
        QWidget* label = new QtWidgetParameterLabel( param );
        gridLayout->addWidget(label, i, 1);

        // Parameter Widget (col 2)
        QtWidgetParameterBase* specificWidget = QtWidgetParameterFactory::CreateQtWidget( param, GetModel() );
        gridLayout->addWidget(specificWidget, i, 2 );

        // CheckBox (col 0)
        QCheckBox * checkBox = new QCheckBox;
        connect( checkBox, SIGNAL(clicked(bool)), specificWidget, SLOT(SetActivationState(bool)));
        connect( checkBox, SIGNAL(clicked(bool)), GetModel(), SLOT(NotifyUpdate()) );
        connect( specificWidget, SIGNAL(ParameterActiveStatus(bool)), checkBox, SLOT(setChecked(bool)));
        connect( specificWidget, SIGNAL(ParameterActiveStatus(bool)), specificWidget, SLOT(SetActivationState(bool)));

        // if Mandatory make the checkbox checked and deactivated
        if (param->GetMandatory())
          {
          checkBox->setCheckState(Qt::Checked);
          checkBox->setEnabled(false);
          specificWidget->setEnabled(true);
          }
        else
          {
          checkBox->setCheckState(Qt::Unchecked);
          checkBox->setEnabled(true);
          specificWidget->setEnabled(false);
          }
        gridLayout->addWidget(checkBox, i, 0);

        // Reset Button
        // Make sense only for NumericalParameter
        if (dynamic_cast<IntParameter*>(param)
            || dynamic_cast<FloatParameter*>(param)
            || dynamic_cast<RadiusParameter*>(param)
            /*|| dynamic_cast<RAMParameter*>(param)*/)
          {
          QPushButton* resetButton = new QPushButton;
          resetButton->setText("Reset");
          resetButton->setToolTip("Reset the value of this parameter");
          gridLayout->addWidget(resetButton, i, 3);

          // Slots to connect to the reset button
          connect( resetButton, SIGNAL(clicked()), specificWidget, SLOT(Reset()) );
          connect( resetButton, SIGNAL(clicked()), GetModel(), SLOT(NotifyUpdate()) );
          }

        m_WidgetList.push_back(specificWidget);
        }
      else
        {
        QtWidgetParameterBase* specificWidget = QtWidgetParameterFactory::CreateQtWidget( param, GetModel() );

        QVBoxLayout* vboxLayout = new QVBoxLayout;
        vboxLayout->addWidget(specificWidget);
        QGroupBox* group = new QGroupBox;
        group->setLayout(vboxLayout);

        // Make the paramter Group checkable when it is not mandatory
        if (!param->GetMandatory() )
          {
          group->setCheckable(true);
          group->setChecked(false);

          // Update iteratively the children status
          for (unsigned int idx = 0; idx < param->GetChildrenList().size(); ++idx)
            {
            // deactivate the children tree
            this->ProcessChild(param->GetChildrenList()[idx], false);
            }
          }
        else
          {
          param->SetActive(true);
          }
        connect(group, SIGNAL(clicked(bool)), specificWidget, SLOT(SetActivationState(bool)));

        group->setTitle(param->GetName());
        gridLayout->addWidget(group, i, 0, 1, -1);

        m_WidgetList.push_back(specificWidget);
        }
      }
    }

  this->setLayout(gridLayout);
}

// Slot connected to the signal emitted the checkBox relative to
// current widget
void QtWidgetParameterGroup::SetActivationState( bool value )
{
  // First call the superclass implementation
  this->QtWidgetParameterBase::SetActivationState(value);

  // Update the Group status
  this->setEnabled(value);

  // Update iteratively the children status
  for (unsigned int idx = 0; idx < m_ParamList->GetChildrenList().size(); ++idx)
    {
    this->ProcessChild(m_ParamList->GetChildrenList()[idx], value);
    }
}

// Activate iteratively  the children
void QtWidgetParameterGroup::ProcessChild(Parameter* currentNode, bool status)
{
  // Activate the current node if it was checked
  if ( currentNode->IsChecked() && status)
    {
    currentNode->SetActive(status);
    }

  // If the status is false (deactivating) deactivate all the children
  // tree
  if (!status)
    {
    currentNode->SetActive(status);
    }

  unsigned int counter = 0;
  while(counter < currentNode->GetChildrenList().size())
    {
    this->ProcessChild(currentNode->GetChildrenList()[counter], status);
    ++counter;
    }
}

}
}
<commit_msg>ENH: don't use Reset button for Role_Output param<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "otbWrapperQtWidgetParameterGroup.h"
#include "otbWrapperQtWidgetChoiceParameter.h"
#include "otbWrapperQtWidgetParameterLabel.h"
#include "otbWrapperQtWidgetParameterFactory.h"

namespace otb
{
namespace Wrapper
{

QtWidgetParameterGroup::QtWidgetParameterGroup(ParameterGroup::Pointer paramList, QtWidgetModel* m)
: QtWidgetParameterBase(paramList, m),
  m_ParamList(paramList)
{
}

QtWidgetParameterGroup::~QtWidgetParameterGroup()
{
}

void QtWidgetParameterGroup::DoUpdateGUI()
{
  WidgetListIteratorType it = m_WidgetList.begin();
  for (it = m_WidgetList.begin(); it != m_WidgetList.end(); ++it)
    {
    (*it)->UpdateGUI();
    }
}

void QtWidgetParameterGroup::DoCreateWidget()
{
  // a GridLayout with two columns : parameter label / parameter widget
  QGridLayout *gridLayout = new QGridLayout;
  gridLayout->setSpacing(1);
  gridLayout->setContentsMargins(0, 0, 0, 0);

  unsigned int nbParams = m_ParamList->GetNumberOfParameters();
  for (unsigned int i = 0; i < nbParams; ++i)
    {
    Parameter* param = m_ParamList->GetParameterByIndex(i);

    if (param != 0)
      {
      ParameterGroup* paramAsGroup = dynamic_cast<ParameterGroup*>(param);
      ChoiceParameter* paramAsChoice = dynamic_cast<ChoiceParameter*>(param);

      if (paramAsGroup == 0 && paramAsChoice == 0)
        {
        // Label (col 1)
        QWidget* label = new QtWidgetParameterLabel( param );
        gridLayout->addWidget(label, i, 1);

        // Parameter Widget (col 2)
        QtWidgetParameterBase* specificWidget = QtWidgetParameterFactory::CreateQtWidget( param, GetModel() );
        gridLayout->addWidget(specificWidget, i, 2 );

        // CheckBox (col 0)
        QCheckBox * checkBox = new QCheckBox;
        connect( checkBox, SIGNAL(clicked(bool)), specificWidget, SLOT(SetActivationState(bool)));
        connect( checkBox, SIGNAL(clicked(bool)), GetModel(), SLOT(NotifyUpdate()) );
        connect( specificWidget, SIGNAL(ParameterActiveStatus(bool)), checkBox, SLOT(setChecked(bool)));
        connect( specificWidget, SIGNAL(ParameterActiveStatus(bool)), specificWidget, SLOT(SetActivationState(bool)));

        // if Mandatory make the checkbox checked and deactivated
        if (param->GetMandatory())
          {
          checkBox->setCheckState(Qt::Checked);
          checkBox->setEnabled(false);
          specificWidget->setEnabled(true);
          }
        else
          {
          checkBox->setCheckState(Qt::Unchecked);
          checkBox->setEnabled(true);
          specificWidget->setEnabled(false);
          }
        gridLayout->addWidget(checkBox, i, 0);

        // Reset Button
        // Make sense only for NumericalParameter
        if (dynamic_cast<IntParameter*>(param)
            || dynamic_cast<FloatParameter*>(param)
            || dynamic_cast<RadiusParameter*>(param)
            /*|| dynamic_cast<RAMParameter*>(param)*/)
          {
          if( param->GetRole() != Role_Output )
            {
            QPushButton* resetButton = new QPushButton;
            resetButton->setText("Reset");
            resetButton->setToolTip("Reset the value of this parameter");
            gridLayout->addWidget(resetButton, i, 3);

            // Slots to connect to the reset button
            connect( resetButton, SIGNAL(clicked()), specificWidget, SLOT(Reset()) );
            connect( resetButton, SIGNAL(clicked()), GetModel(), SLOT(NotifyUpdate()) );
            }
          }

        m_WidgetList.push_back(specificWidget);
        }
      else
        {
        QtWidgetParameterBase* specificWidget = QtWidgetParameterFactory::CreateQtWidget( param, GetModel() );

        QVBoxLayout* vboxLayout = new QVBoxLayout;
        vboxLayout->addWidget(specificWidget);
        QGroupBox* group = new QGroupBox;
        group->setLayout(vboxLayout);

        // Make the paramter Group checkable when it is not mandatory
        if (!param->GetMandatory() )
          {
          group->setCheckable(true);
          group->setChecked(false);

          // Update iteratively the children status
          for (unsigned int idx = 0; idx < param->GetChildrenList().size(); ++idx)
            {
            // deactivate the children tree
            this->ProcessChild(param->GetChildrenList()[idx], false);
            }
          }
        else
          {
          param->SetActive(true);
          }
        connect(group, SIGNAL(clicked(bool)), specificWidget, SLOT(SetActivationState(bool)));

        group->setTitle(param->GetName());
        gridLayout->addWidget(group, i, 0, 1, -1);

        m_WidgetList.push_back(specificWidget);
        }
      }
    }

  this->setLayout(gridLayout);
}

// Slot connected to the signal emitted the checkBox relative to
// current widget
void QtWidgetParameterGroup::SetActivationState( bool value )
{
  // First call the superclass implementation
  this->QtWidgetParameterBase::SetActivationState(value);

  // Update the Group status
  this->setEnabled(value);

  // Update iteratively the children status
  for (unsigned int idx = 0; idx < m_ParamList->GetChildrenList().size(); ++idx)
    {
    this->ProcessChild(m_ParamList->GetChildrenList()[idx], value);
    }
}

// Activate iteratively  the children
void QtWidgetParameterGroup::ProcessChild(Parameter* currentNode, bool status)
{
  // Activate the current node if it was checked
  if ( currentNode->IsChecked() && status)
    {
    currentNode->SetActive(status);
    }

  // If the status is false (deactivating) deactivate all the children
  // tree
  if (!status)
    {
    currentNode->SetActive(status);
    }

  unsigned int counter = 0;
  while(counter < currentNode->GetChildrenList().size())
    {
    this->ProcessChild(currentNode->GetChildrenList()[counter], status);
    ++counter;
    }
}

}
}
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  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 and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER 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.
 *
 * Author: Nico Blodow (blodow@cs.tum.edu)
 */

#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/kinect_grabber.h>
#include <pcl/io/kinect_grabber.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/octree/octree.h>
#include <pcl/filters/extract_indices.h>

class KinectChangeViewer
{
  public:
    KinectChangeViewer (double resolution)
      : viewer ("PCL Kinect Viewer")
    {
      octree = new pcl::octree::OctreePointCloudChangeDetector<pcl::PointXYZ>(resolution);
    }

    void cloud_cb_ (const pcl::PointCloud<pcl::PointXYZ>::ConstPtr &cloud)
    {
      pcl::PointCloud<pcl::PointXYZ> filtered_cloud;
      pcl::ExtractIndices<pcl::PointXYZ> ei;
      ei.setInputCloud (cloud);
      ei.filter (filtered_cloud);
//      // assign point cloud to octree
//      octree->setInputCloud (cloud);
//
//      // add points from cloud to octree
//      octree->addPointsFromInputCloud ();
//
      std::vector<int> newPointIdxVector;
//
//      // get a vector of new points, which did not exist in previous buffer
//      octree->getPointIndicesFromNewVoxels (newPointIdxVector);
//
      std::cerr << newPointIdxVector.size() << std::endl;
      if (!viewer.wasStopped())
        viewer.showCloud (filtered_cloud);
//      // switch buffers - reset tree
//      octree->switchBuffers ();

    }

    void run ()
    {
      pcl::Grabber* interface = new pcl::OpenNIGrabber();

      boost::function<void (const pcl::PointCloud<pcl::PointXYZ>::ConstPtr&)> f =
        boost::bind (&KinectChangeViewer::cloud_cb_, this, _1);

      boost::signals2::connection c = interface->registerCallback (f);

      interface->start ();

      while (!viewer.wasStopped())
      {
        sleep (1);
      }

      interface->stop ();
    }

    pcl::octree::OctreePointCloudChangeDetector<pcl::PointXYZ> *octree;
    pcl_visualization::CloudViewer viewer;
};

int main (int argc, char* argv[])
{
  double resolution = 0.05;
  if (argc > 1)
    resolution = atof (argv[1]);

  KinectChangeViewer v (resolution);
  v.run ();
  return 0;
}

<commit_msg>thank you julius<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  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 and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER 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.
 *
 * Author: Nico Blodow (blodow@cs.tum.edu)
 */

#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/kinect_grabber.h>
#include <pcl/io/kinect_grabber.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/octree/octree.h>
#include <pcl/filters/extract_indices.h>

class KinectChangeViewer
{
  public:
    KinectChangeViewer (double resolution)
      : viewer ("PCL Kinect Viewer")
    {
      octree = new pcl::octree::OctreePointCloudChangeDetector<pcl::PointXYZRGB>(resolution);
    }

    void cloud_cb_ (const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &cloud)
    {
      std::cerr << cloud->points.size() << " -- ";

      // assign point cloud to octree
      octree->setInputCloud (cloud);

      // add points from cloud to octree
      octree->addPointsFromInputCloud ();

      std::cerr << octree->getLeafCount() << " -- ";
      boost::shared_ptr<std::vector<int> > newPointIdxVector (new std::vector<int>);

      // get a vector of new points, which did not exist in previous buffer
      octree->getPointIndicesFromNewVoxels (*newPointIdxVector);

      std::cerr << newPointIdxVector->size() << std::endl;

      //// extract points from pointcloud
      pcl::PointCloud<pcl::PointXYZRGB> filtered_cloud (*cloud);
      //pcl::ExtractIndices<pcl::PointXYZRGB> ei;
      //ei.setInputCloud (cloud);
      //ei.setIndices (newPointIdxVector);
      //ei.filter (filtered_cloud);

      for (std::vector<int>::iterator it = newPointIdxVector->begin(); it != newPointIdxVector->end(); it++)
        filtered_cloud.points[*it].rgb = 255<<16;

      if (!viewer.wasStopped())
        viewer.showCloud (filtered_cloud);

      // switch buffers - reset tree
      octree->switchBuffers ();
    }

    void run ()
    {
      pcl::Grabber* interface = new pcl::OpenNIGrabber();

      boost::function<void (const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr&)> f =
        boost::bind (&KinectChangeViewer::cloud_cb_, this, _1);

      boost::signals2::connection c = interface->registerCallback (f);

      interface->start ();

      while (!viewer.wasStopped())
      {
        sleep (1);
      }

      interface->stop ();
    }

    pcl::octree::OctreePointCloudChangeDetector<pcl::PointXYZRGB> *octree;
    pcl_visualization::CloudViewer viewer;
};

int main (int argc, char* argv[])
{
  double resolution = 0.05;
  if (argc > 1)
    resolution = atof (argv[1]);

  KinectChangeViewer v (resolution);
  v.run ();
  return 0;
}

<|endoftext|>