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

#include "src/trace_processor/importers/common/clock_tracker.h"

#include <inttypes.h>

#include <algorithm>
#include <queue>

#include "perfetto/base/logging.h"
#include "perfetto/ext/base/hash.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"

#include "protos/perfetto/common/builtin_clock.pbzero.h"
#include "protos/perfetto/trace/clock_snapshot.pbzero.h"

namespace perfetto {
namespace trace_processor {

using Clock = protos::pbzero::ClockSnapshot::Clock;

ClockTracker::ClockTracker(TraceProcessorContext* ctx)
    : context_(ctx),
      trace_time_clock_id_(protos::pbzero::BUILTIN_CLOCK_BOOTTIME) {}

ClockTracker::~ClockTracker() = default;

void ClockTracker::AddSnapshot(const std::vector<ClockValue>& clocks) {
  const auto snapshot_id = cur_snapshot_id_++;

  // Clear the cache
  cache_.fill({});

  // Compute the fingerprint of the snapshot by hashing all clock ids. This is
  // used by the clock pathfinding logic.
  base::Hash hasher;
  for (const auto& clock : clocks)
    hasher.Update(clock.clock_id);
  const auto snapshot_hash = static_cast<SnapshotHash>(hasher.digest());

  // Add a new entry in each clock's snapshot vector.
  for (const auto& clock : clocks) {
    ClockId clock_id = clock.clock_id;
    ClockDomain& domain = clocks_[clock_id];
    if (domain.snapshots.empty()) {
      if (clock.is_incremental && !ClockIsSeqScoped(clock_id)) {
        PERFETTO_ELOG("Clock sync error: the global clock with id=%" PRIu64
                      " cannot use incremental encoding; this is only "
                      "supported for sequence-scoped clocks.",
                      clock_id);
        context_->storage->IncrementStats(stats::invalid_clock_snapshots);
        return;
      }
      domain.unit_multiplier_ns = clock.unit_multiplier_ns;
      domain.is_incremental = clock.is_incremental;
    } else if (PERFETTO_UNLIKELY(
                   domain.unit_multiplier_ns != clock.unit_multiplier_ns ||
                   domain.is_incremental != clock.is_incremental)) {
      PERFETTO_ELOG("Clock sync error: the clock domain with id=%" PRIu64
                    " (unit=%" PRIu64
                    ", incremental=%d), was previously registered with "
                    "different properties (unit=%" PRIu64 ", incremental=%d).",
                    clock_id, clock.unit_multiplier_ns, clock.is_incremental,
                    domain.unit_multiplier_ns, domain.is_incremental);
      context_->storage->IncrementStats(stats::invalid_clock_snapshots);
      return;
    }
    const int64_t timestamp_ns =
        clock.absolute_timestamp * domain.unit_multiplier_ns;
    domain.last_timestamp_ns = timestamp_ns;

    ClockSnapshots& vect = domain.snapshots[snapshot_hash];
    if (!vect.snapshot_ids.empty() &&
        PERFETTO_UNLIKELY(vect.snapshot_ids.back() == snapshot_id)) {
      PERFETTO_ELOG("Clock sync error: duplicate clock domain with id=%" PRIu64
                    " at snapshot %" PRIu32 ".",
                    clock_id, snapshot_id);
      context_->storage->IncrementStats(stats::invalid_clock_snapshots);
      return;
    }

    // Clock ids in the range [64, 128) are sequence-scoped and must be
    // translated to global ids via SeqScopedClockIdToGlobal() before calling
    // this function.
    PERFETTO_DCHECK(!IsReservedSeqScopedClockId(clock_id));

    // Snapshot IDs must be always monotonic.
    PERFETTO_DCHECK(vect.snapshot_ids.empty() ||
                    vect.snapshot_ids.back() < snapshot_id);

    if (!vect.timestamps_ns.empty() &&
        timestamp_ns < vect.timestamps_ns.back()) {
      // Clock is not monotonic.

      if (clock_id == trace_time_clock_id_) {
        // The trace clock cannot be non-monotonic.
        PERFETTO_ELOG("Clock sync error: the trace clock (id=%" PRIu64
                      ") is not monotonic at snapshot %" PRIu32 ". %" PRId64
                      " not >= %" PRId64 ".",
                      clock_id, snapshot_id, timestamp_ns,
                      vect.timestamps_ns.back());
        context_->storage->IncrementStats(stats::invalid_clock_snapshots);
        return;
      }

      PERFETTO_DLOG("Detected non-monotonic clock with ID %" PRIu64, clock_id);

      // For the other clocks the best thing we can do is mark it as
      // non-monotonic and refuse to use it as a source clock in the resolution
      // graph. We can still use it as a target clock, but not viceversa.
      // The concrete example is the CLOCK_REALTIME going 1h backwards during
      // daylight saving. We can still answer the question "what was the
      // REALTIME timestamp when BOOTTIME was X?" but we can't answer the
      // opposite question because there can be two valid BOOTTIME(s) for the
      // same REALTIME instant because of the 1:many relationship.
      non_monotonic_clocks_.insert(clock_id);

      // Erase all edges from the graph that start from this clock (but keep the
      // ones that end on this clock).
      auto begin = graph_.lower_bound(ClockGraphEdge{clock_id, 0, 0});
      auto end = graph_.lower_bound(ClockGraphEdge{clock_id + 1, 0, 0});
      graph_.erase(begin, end);
    }
    vect.snapshot_ids.emplace_back(snapshot_id);
    vect.timestamps_ns.emplace_back(timestamp_ns);
  }

  // Create graph edges for all the possible tuples of clocks in this snapshot.
  // If the snapshot contains clock a, b, c, d create edges [ab, ac, ad, bc, bd,
  // cd] and the symmetrical ones [ba, ca, da, bc, db, dc].
  // This is to store the information: Clock A is syncable to Clock B via the
  // snapshots of type (hash).
  // Clocks that were previously marked as non-monotonic won't be added as
  // valid sources.
  for (auto it1 = clocks.begin(); it1 != clocks.end(); ++it1) {
    auto it2 = it1;
    ++it2;
    for (; it2 != clocks.end(); ++it2) {
      if (!non_monotonic_clocks_.count(it1->clock_id))
        graph_.emplace(it1->clock_id, it2->clock_id, snapshot_hash);

      if (!non_monotonic_clocks_.count(it2->clock_id))
        graph_.emplace(it2->clock_id, it1->clock_id, snapshot_hash);
    }
  }
}

// Finds the shortest clock resolution path in the graph that allows to
// translate a timestamp from |src| to |target| clocks.
// The return value looks like the following: "If you want to convert a
// timestamp from clock C1 to C2 you need to first convert C1 -> C3 using the
// snapshot hash A, then convert C3 -> C2 via snapshot hash B".
ClockTracker::ClockPath ClockTracker::FindPath(ClockId src, ClockId target) {
  // This is a classic breadth-first search. Each node in the queue holds also
  // the full path to reach that node.
  // We assume the graph is acyclic, if it isn't the ClockPath::kMaxLen will
  // stop the search anyways.
  PERFETTO_CHECK(src != target);
  std::queue<ClockPath> queue;
  queue.emplace(src);

  while (!queue.empty()) {
    ClockPath cur_path = queue.front();
    queue.pop();

    const ClockId cur_clock_id = cur_path.last;
    if (cur_clock_id == target)
      return cur_path;

    if (cur_path.len >= ClockPath::kMaxLen)
      continue;

    // Expore all the adjacent clocks.
    // The lower_bound() below returns an iterator to the first edge that starts
    // on |cur_clock_id|. The edges are sorted by (src, target, hash).
    for (auto it = std::lower_bound(graph_.begin(), graph_.end(),
                                    ClockGraphEdge(cur_clock_id, 0, 0));
         it != graph_.end() && std::get<0>(*it) == cur_clock_id; ++it) {
      ClockId next_clock_id = std::get<1>(*it);
      SnapshotHash hash = std::get<2>(*it);
      queue.push(ClockPath(cur_path, next_clock_id, hash));
    }
  }
  return ClockPath();  // invalid path.
}

base::Optional<int64_t> ClockTracker::ConvertSlowpath(ClockId src_clock_id,
                                                      int64_t src_timestamp,
                                                      ClockId target_clock_id) {
  PERFETTO_DCHECK(!IsReservedSeqScopedClockId(src_clock_id));
  PERFETTO_DCHECK(!IsReservedSeqScopedClockId(target_clock_id));

  context_->storage->IncrementStats(stats::clock_sync_cache_miss);

  ClockPath path = FindPath(src_clock_id, target_clock_id);
  if (!path.valid()) {
    // Too many logs maybe emitted when path is invalid.
    static uint64_t dlog_count = 0;
    if (dlog_count++ < 10) {
      PERFETTO_DLOG("No path from clock %" PRIu64 " to %" PRIu64
                    " at timestamp %" PRId64,
                    src_clock_id, target_clock_id, src_timestamp);
    }
    context_->storage->IncrementStats(stats::clock_sync_failure);
    return base::nullopt;
  }

  // We can cache only single-path resolutions between two clocks.
  // Caching multi-path resolutions is harder because the (src,target) tuple
  // is not enough as a cache key: at any step the |ns| value can yield to a
  // different choice of the next snapshot. Multi-path resolutions don't seem
  // too frequent these days, so we focus only on caching the more frequent
  // one-step resolutions (typically from any clock to the trace clock).
  const bool cacheable = path.len == 1;
  CachedClockPath cache_entry{};

  // Iterate trough the path found and translate timestamps onto the new clock
  // domain on each step, until the target domain is reached.
  ClockDomain* src_domain = GetClock(src_clock_id);
  int64_t ns = src_domain->ToNs(src_timestamp);
  for (uint32_t i = 0; i < path.len; ++i) {
    const ClockGraphEdge edge = path.at(i);
    ClockDomain* cur_clock = GetClock(std::get<0>(edge));
    ClockDomain* next_clock = GetClock(std::get<1>(edge));
    const SnapshotHash hash = std::get<2>(edge);

    // Find the closest timestamp within the snapshots of the source clock.
    const ClockSnapshots& cur_snap = cur_clock->GetSnapshot(hash);
    const auto& ts_vec = cur_snap.timestamps_ns;
    auto it = std::upper_bound(ts_vec.begin(), ts_vec.end(), ns);
    if (it != ts_vec.begin())
      --it;

    // Now lookup the snapshot id that matches the closest timestamp.
    size_t index = static_cast<size_t>(std::distance(ts_vec.begin(), it));
    PERFETTO_DCHECK(index < ts_vec.size());
    PERFETTO_DCHECK(cur_snap.snapshot_ids.size() == ts_vec.size());
    uint32_t snapshot_id = cur_snap.snapshot_ids[index];

    // And use that to retrieve the corresponding time in the next clock domain.
    // The snapshot id must exist in the target clock domain. If it doesn't
    // either the hash logic or the pathfinding logic are bugged.
    // This can also happen if the checks in AddSnapshot fail and we skip part
    // of the snapshot.
    const ClockSnapshots& next_snap = next_clock->GetSnapshot(hash);

    // Using std::lower_bound because snapshot_ids is sorted, so we can do
    // a binary search. std::find would do a linear scan.
    auto next_it = std::lower_bound(next_snap.snapshot_ids.begin(),
                                    next_snap.snapshot_ids.end(), snapshot_id);
    if (next_it == next_snap.snapshot_ids.end() || *next_it != snapshot_id) {
      PERFETTO_DFATAL("Snapshot does not exist in clock domain.");
      continue;
    }
    size_t next_index = static_cast<size_t>(
        std::distance(next_snap.snapshot_ids.begin(), next_it));
    PERFETTO_DCHECK(next_index < next_snap.snapshot_ids.size());
    int64_t next_timestamp_ns = next_snap.timestamps_ns[next_index];

    // The translated timestamp is the relative delta of the source timestamp
    // from the closest snapshot found (ns - *it), plus the timestamp in
    // the new clock domain for the same snapshot id.
    const int64_t adj = next_timestamp_ns - *it;
    ns += adj;

    // On the first iteration, keep track of the bounds for the cache entry.
    // This will allow future Convert() calls to skip the pathfinder logic
    // as long as the query stays within the bound.
    if (cacheable) {
      PERFETTO_DCHECK(i == 0);
      const int64_t kInt64Min = std::numeric_limits<int64_t>::min();
      const int64_t kInt64Max = std::numeric_limits<int64_t>::max();
      cache_entry.min_ts_ns = it == ts_vec.begin() ? kInt64Min : *it;
      auto ubound = it + 1;
      cache_entry.max_ts_ns = ubound == ts_vec.end() ? kInt64Max : *ubound;
      cache_entry.translation_ns = adj;
    }

    // The last clock in the path must be the target clock.
    PERFETTO_DCHECK(i < path.len - 1 || std::get<1>(edge) == target_clock_id);
  }

  if (cacheable) {
    cache_entry.src = src_clock_id;
    cache_entry.src_domain = src_domain;
    cache_entry.target = target_clock_id;
    cache_[rnd_() % cache_.size()] = cache_entry;
  }

  return ns;
}

}  // namespace trace_processor
}  // namespace perfetto
<commit_msg>Avoid race in accessing log count<commit_after>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/trace_processor/importers/common/clock_tracker.h"

#include <inttypes.h>

#include <algorithm>
#include <atomic>
#include <queue>

#include "perfetto/base/logging.h"
#include "perfetto/ext/base/hash.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"

#include "protos/perfetto/common/builtin_clock.pbzero.h"
#include "protos/perfetto/trace/clock_snapshot.pbzero.h"

namespace perfetto {
namespace trace_processor {

using Clock = protos::pbzero::ClockSnapshot::Clock;

ClockTracker::ClockTracker(TraceProcessorContext* ctx)
    : context_(ctx),
      trace_time_clock_id_(protos::pbzero::BUILTIN_CLOCK_BOOTTIME) {}

ClockTracker::~ClockTracker() = default;

void ClockTracker::AddSnapshot(const std::vector<ClockValue>& clocks) {
  const auto snapshot_id = cur_snapshot_id_++;

  // Clear the cache
  cache_.fill({});

  // Compute the fingerprint of the snapshot by hashing all clock ids. This is
  // used by the clock pathfinding logic.
  base::Hash hasher;
  for (const auto& clock : clocks)
    hasher.Update(clock.clock_id);
  const auto snapshot_hash = static_cast<SnapshotHash>(hasher.digest());

  // Add a new entry in each clock's snapshot vector.
  for (const auto& clock : clocks) {
    ClockId clock_id = clock.clock_id;
    ClockDomain& domain = clocks_[clock_id];
    if (domain.snapshots.empty()) {
      if (clock.is_incremental && !ClockIsSeqScoped(clock_id)) {
        PERFETTO_ELOG("Clock sync error: the global clock with id=%" PRIu64
                      " cannot use incremental encoding; this is only "
                      "supported for sequence-scoped clocks.",
                      clock_id);
        context_->storage->IncrementStats(stats::invalid_clock_snapshots);
        return;
      }
      domain.unit_multiplier_ns = clock.unit_multiplier_ns;
      domain.is_incremental = clock.is_incremental;
    } else if (PERFETTO_UNLIKELY(
                   domain.unit_multiplier_ns != clock.unit_multiplier_ns ||
                   domain.is_incremental != clock.is_incremental)) {
      PERFETTO_ELOG("Clock sync error: the clock domain with id=%" PRIu64
                    " (unit=%" PRIu64
                    ", incremental=%d), was previously registered with "
                    "different properties (unit=%" PRIu64 ", incremental=%d).",
                    clock_id, clock.unit_multiplier_ns, clock.is_incremental,
                    domain.unit_multiplier_ns, domain.is_incremental);
      context_->storage->IncrementStats(stats::invalid_clock_snapshots);
      return;
    }
    const int64_t timestamp_ns =
        clock.absolute_timestamp * domain.unit_multiplier_ns;
    domain.last_timestamp_ns = timestamp_ns;

    ClockSnapshots& vect = domain.snapshots[snapshot_hash];
    if (!vect.snapshot_ids.empty() &&
        PERFETTO_UNLIKELY(vect.snapshot_ids.back() == snapshot_id)) {
      PERFETTO_ELOG("Clock sync error: duplicate clock domain with id=%" PRIu64
                    " at snapshot %" PRIu32 ".",
                    clock_id, snapshot_id);
      context_->storage->IncrementStats(stats::invalid_clock_snapshots);
      return;
    }

    // Clock ids in the range [64, 128) are sequence-scoped and must be
    // translated to global ids via SeqScopedClockIdToGlobal() before calling
    // this function.
    PERFETTO_DCHECK(!IsReservedSeqScopedClockId(clock_id));

    // Snapshot IDs must be always monotonic.
    PERFETTO_DCHECK(vect.snapshot_ids.empty() ||
                    vect.snapshot_ids.back() < snapshot_id);

    if (!vect.timestamps_ns.empty() &&
        timestamp_ns < vect.timestamps_ns.back()) {
      // Clock is not monotonic.

      if (clock_id == trace_time_clock_id_) {
        // The trace clock cannot be non-monotonic.
        PERFETTO_ELOG("Clock sync error: the trace clock (id=%" PRIu64
                      ") is not monotonic at snapshot %" PRIu32 ". %" PRId64
                      " not >= %" PRId64 ".",
                      clock_id, snapshot_id, timestamp_ns,
                      vect.timestamps_ns.back());
        context_->storage->IncrementStats(stats::invalid_clock_snapshots);
        return;
      }

      PERFETTO_DLOG("Detected non-monotonic clock with ID %" PRIu64, clock_id);

      // For the other clocks the best thing we can do is mark it as
      // non-monotonic and refuse to use it as a source clock in the resolution
      // graph. We can still use it as a target clock, but not viceversa.
      // The concrete example is the CLOCK_REALTIME going 1h backwards during
      // daylight saving. We can still answer the question "what was the
      // REALTIME timestamp when BOOTTIME was X?" but we can't answer the
      // opposite question because there can be two valid BOOTTIME(s) for the
      // same REALTIME instant because of the 1:many relationship.
      non_monotonic_clocks_.insert(clock_id);

      // Erase all edges from the graph that start from this clock (but keep the
      // ones that end on this clock).
      auto begin = graph_.lower_bound(ClockGraphEdge{clock_id, 0, 0});
      auto end = graph_.lower_bound(ClockGraphEdge{clock_id + 1, 0, 0});
      graph_.erase(begin, end);
    }
    vect.snapshot_ids.emplace_back(snapshot_id);
    vect.timestamps_ns.emplace_back(timestamp_ns);
  }

  // Create graph edges for all the possible tuples of clocks in this snapshot.
  // If the snapshot contains clock a, b, c, d create edges [ab, ac, ad, bc, bd,
  // cd] and the symmetrical ones [ba, ca, da, bc, db, dc].
  // This is to store the information: Clock A is syncable to Clock B via the
  // snapshots of type (hash).
  // Clocks that were previously marked as non-monotonic won't be added as
  // valid sources.
  for (auto it1 = clocks.begin(); it1 != clocks.end(); ++it1) {
    auto it2 = it1;
    ++it2;
    for (; it2 != clocks.end(); ++it2) {
      if (!non_monotonic_clocks_.count(it1->clock_id))
        graph_.emplace(it1->clock_id, it2->clock_id, snapshot_hash);

      if (!non_monotonic_clocks_.count(it2->clock_id))
        graph_.emplace(it2->clock_id, it1->clock_id, snapshot_hash);
    }
  }
}

// Finds the shortest clock resolution path in the graph that allows to
// translate a timestamp from |src| to |target| clocks.
// The return value looks like the following: "If you want to convert a
// timestamp from clock C1 to C2 you need to first convert C1 -> C3 using the
// snapshot hash A, then convert C3 -> C2 via snapshot hash B".
ClockTracker::ClockPath ClockTracker::FindPath(ClockId src, ClockId target) {
  // This is a classic breadth-first search. Each node in the queue holds also
  // the full path to reach that node.
  // We assume the graph is acyclic, if it isn't the ClockPath::kMaxLen will
  // stop the search anyways.
  PERFETTO_CHECK(src != target);
  std::queue<ClockPath> queue;
  queue.emplace(src);

  while (!queue.empty()) {
    ClockPath cur_path = queue.front();
    queue.pop();

    const ClockId cur_clock_id = cur_path.last;
    if (cur_clock_id == target)
      return cur_path;

    if (cur_path.len >= ClockPath::kMaxLen)
      continue;

    // Expore all the adjacent clocks.
    // The lower_bound() below returns an iterator to the first edge that starts
    // on |cur_clock_id|. The edges are sorted by (src, target, hash).
    for (auto it = std::lower_bound(graph_.begin(), graph_.end(),
                                    ClockGraphEdge(cur_clock_id, 0, 0));
         it != graph_.end() && std::get<0>(*it) == cur_clock_id; ++it) {
      ClockId next_clock_id = std::get<1>(*it);
      SnapshotHash hash = std::get<2>(*it);
      queue.push(ClockPath(cur_path, next_clock_id, hash));
    }
  }
  return ClockPath();  // invalid path.
}

base::Optional<int64_t> ClockTracker::ConvertSlowpath(ClockId src_clock_id,
                                                      int64_t src_timestamp,
                                                      ClockId target_clock_id) {
  PERFETTO_DCHECK(!IsReservedSeqScopedClockId(src_clock_id));
  PERFETTO_DCHECK(!IsReservedSeqScopedClockId(target_clock_id));

  context_->storage->IncrementStats(stats::clock_sync_cache_miss);

  ClockPath path = FindPath(src_clock_id, target_clock_id);
  if (!path.valid()) {
    // Too many logs maybe emitted when path is invalid.
    static std::atomic<uint32_t> dlog_count = 0;
    if (dlog_count++ < 10) {
      PERFETTO_DLOG("No path from clock %" PRIu64 " to %" PRIu64
                    " at timestamp %" PRId64,
                    src_clock_id, target_clock_id, src_timestamp);
    }
    context_->storage->IncrementStats(stats::clock_sync_failure);
    return base::nullopt;
  }

  // We can cache only single-path resolutions between two clocks.
  // Caching multi-path resolutions is harder because the (src,target) tuple
  // is not enough as a cache key: at any step the |ns| value can yield to a
  // different choice of the next snapshot. Multi-path resolutions don't seem
  // too frequent these days, so we focus only on caching the more frequent
  // one-step resolutions (typically from any clock to the trace clock).
  const bool cacheable = path.len == 1;
  CachedClockPath cache_entry{};

  // Iterate trough the path found and translate timestamps onto the new clock
  // domain on each step, until the target domain is reached.
  ClockDomain* src_domain = GetClock(src_clock_id);
  int64_t ns = src_domain->ToNs(src_timestamp);
  for (uint32_t i = 0; i < path.len; ++i) {
    const ClockGraphEdge edge = path.at(i);
    ClockDomain* cur_clock = GetClock(std::get<0>(edge));
    ClockDomain* next_clock = GetClock(std::get<1>(edge));
    const SnapshotHash hash = std::get<2>(edge);

    // Find the closest timestamp within the snapshots of the source clock.
    const ClockSnapshots& cur_snap = cur_clock->GetSnapshot(hash);
    const auto& ts_vec = cur_snap.timestamps_ns;
    auto it = std::upper_bound(ts_vec.begin(), ts_vec.end(), ns);
    if (it != ts_vec.begin())
      --it;

    // Now lookup the snapshot id that matches the closest timestamp.
    size_t index = static_cast<size_t>(std::distance(ts_vec.begin(), it));
    PERFETTO_DCHECK(index < ts_vec.size());
    PERFETTO_DCHECK(cur_snap.snapshot_ids.size() == ts_vec.size());
    uint32_t snapshot_id = cur_snap.snapshot_ids[index];

    // And use that to retrieve the corresponding time in the next clock domain.
    // The snapshot id must exist in the target clock domain. If it doesn't
    // either the hash logic or the pathfinding logic are bugged.
    // This can also happen if the checks in AddSnapshot fail and we skip part
    // of the snapshot.
    const ClockSnapshots& next_snap = next_clock->GetSnapshot(hash);

    // Using std::lower_bound because snapshot_ids is sorted, so we can do
    // a binary search. std::find would do a linear scan.
    auto next_it = std::lower_bound(next_snap.snapshot_ids.begin(),
                                    next_snap.snapshot_ids.end(), snapshot_id);
    if (next_it == next_snap.snapshot_ids.end() || *next_it != snapshot_id) {
      PERFETTO_DFATAL("Snapshot does not exist in clock domain.");
      continue;
    }
    size_t next_index = static_cast<size_t>(
        std::distance(next_snap.snapshot_ids.begin(), next_it));
    PERFETTO_DCHECK(next_index < next_snap.snapshot_ids.size());
    int64_t next_timestamp_ns = next_snap.timestamps_ns[next_index];

    // The translated timestamp is the relative delta of the source timestamp
    // from the closest snapshot found (ns - *it), plus the timestamp in
    // the new clock domain for the same snapshot id.
    const int64_t adj = next_timestamp_ns - *it;
    ns += adj;

    // On the first iteration, keep track of the bounds for the cache entry.
    // This will allow future Convert() calls to skip the pathfinder logic
    // as long as the query stays within the bound.
    if (cacheable) {
      PERFETTO_DCHECK(i == 0);
      const int64_t kInt64Min = std::numeric_limits<int64_t>::min();
      const int64_t kInt64Max = std::numeric_limits<int64_t>::max();
      cache_entry.min_ts_ns = it == ts_vec.begin() ? kInt64Min : *it;
      auto ubound = it + 1;
      cache_entry.max_ts_ns = ubound == ts_vec.end() ? kInt64Max : *ubound;
      cache_entry.translation_ns = adj;
    }

    // The last clock in the path must be the target clock.
    PERFETTO_DCHECK(i < path.len - 1 || std::get<1>(edge) == target_clock_id);
  }

  if (cacheable) {
    cache_entry.src = src_clock_id;
    cache_entry.src_domain = src_domain;
    cache_entry.target = target_clock_id;
    cache_[rnd_() % cache_.size()] = cache_entry;
  }

  return ns;
}

}  // namespace trace_processor
}  // namespace perfetto
<|endoftext|>


<commit_before><commit_msg>vcldemo: create --popup mode demonstrating Windows GL issue.<commit_after><|endoftext|>


<commit_before>/**
 * \file
 * \brief MutexPriorityProtectOperationsTestCase class implementation
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-11-09
 */

#include "MutexPriorityProtectOperationsTestCase.hpp"

#include "waitForNextTick.hpp"

#include "distortos/Mutex.hpp"
#include "distortos/ThisThread.hpp"

#include <cerrno>

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// single duration used in tests
constexpr auto singleDuration = TickClock::duration{1};

/// priority of current test thread
constexpr uint8_t testThreadPriority {UINT8_MAX};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Runs the test case.
 *
 * \attention this function expects the priority of test thread to be testThreadPriority
 *
 * \return true if the test case succeeded, false otherwise
 */

bool testRunner_()
{
	static const Mutex::Type types[]
	{
			Mutex::Type::Normal,
			Mutex::Type::ErrorChecking,
			Mutex::Type::Recursive,
	};

	for (const auto type : types)
	{
		Mutex mutex {type, Mutex::Protocol::PriorityProtect, testThreadPriority - 1};

		{
			// invalid lock attempt - must fail with EINVAL immediately
			waitForNextTick();
			const auto start = TickClock::now();
			const auto ret = mutex.lock();
			if (ret != EINVAL || start != TickClock::now())
				return false;
		}

		{
			// invalid lock attempt - must fail with EINVAL immediately
			waitForNextTick();
			const auto start = TickClock::now();
			const auto ret = mutex.tryLock();
			if (ret != EINVAL || start != TickClock::now())
				return false;
		}

		{
			// invalid lock attempt - must fail with EINVAL immediately
			waitForNextTick();
			const auto start = TickClock::now();
			const auto ret = mutex.tryLockFor(singleDuration);
			if (ret != EINVAL || start != TickClock::now())
				return false;
		}

		{
			// invalid lock attempt - must fail with EINVAL immediately
			waitForNextTick();
			const auto start = TickClock::now();
			const auto ret = mutex.tryLockUntil(start + singleDuration);
			if (ret != EINVAL || start != TickClock::now())
				return false;
		}
	}

	return true;
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool MutexPriorityProtectOperationsTestCase::run_() const
{
	const auto thisThreadPriority = ThisThread::getPriority();
	ThisThread::setPriority(testThreadPriority);
	const auto ret = testRunner_();
	ThisThread::setPriority(thisThreadPriority);
	return ret;
}

}	// namespace test

}	// namespace distortos
<commit_msg>test: run MutexPriorityProtectOperationsTestCase at priority 1<commit_after>/**
 * \file
 * \brief MutexPriorityProtectOperationsTestCase class implementation
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-11-11
 */

#include "MutexPriorityProtectOperationsTestCase.hpp"

#include "waitForNextTick.hpp"

#include "distortos/Mutex.hpp"
#include "distortos/ThisThread.hpp"

#include <cerrno>

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// single duration used in tests
constexpr auto singleDuration = TickClock::duration{1};

/// priority of current test thread
constexpr uint8_t testThreadPriority {1};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Runs the test case.
 *
 * \attention this function expects the priority of test thread to be testThreadPriority
 *
 * \return true if the test case succeeded, false otherwise
 */

bool testRunner_()
{
	static const Mutex::Type types[]
	{
			Mutex::Type::Normal,
			Mutex::Type::ErrorChecking,
			Mutex::Type::Recursive,
	};

	for (const auto type : types)
	{
		Mutex mutex {type, Mutex::Protocol::PriorityProtect, testThreadPriority - 1};

		{
			// invalid lock attempt - must fail with EINVAL immediately
			waitForNextTick();
			const auto start = TickClock::now();
			const auto ret = mutex.lock();
			if (ret != EINVAL || start != TickClock::now())
				return false;
		}

		{
			// invalid lock attempt - must fail with EINVAL immediately
			waitForNextTick();
			const auto start = TickClock::now();
			const auto ret = mutex.tryLock();
			if (ret != EINVAL || start != TickClock::now())
				return false;
		}

		{
			// invalid lock attempt - must fail with EINVAL immediately
			waitForNextTick();
			const auto start = TickClock::now();
			const auto ret = mutex.tryLockFor(singleDuration);
			if (ret != EINVAL || start != TickClock::now())
				return false;
		}

		{
			// invalid lock attempt - must fail with EINVAL immediately
			waitForNextTick();
			const auto start = TickClock::now();
			const auto ret = mutex.tryLockUntil(start + singleDuration);
			if (ret != EINVAL || start != TickClock::now())
				return false;
		}
	}

	return true;
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool MutexPriorityProtectOperationsTestCase::run_() const
{
	const auto thisThreadPriority = ThisThread::getPriority();
	ThisThread::setPriority(testThreadPriority);
	const auto ret = testRunner_();
	ThisThread::setPriority(thisThreadPriority);
	return ret;
}

}	// namespace test

}	// namespace distortos
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                     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.
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++98, c++03, c++11, c++14

// type_traits

// is_callable

// Most testing of is_callable is done within the [meta.trans.other] result_of
// tests.

#include <type_traits>
#include <functional>

#include "test_macros.h"

struct Tag {};
struct DerFromTag : Tag {};

struct Implicit {
  Implicit(int) {}
};

struct Explicit {
  explicit Explicit(int) {}
};

struct NotCallableWithInt {
  int operator()(int) = delete;
  int operator()(Tag) { return 42; }
};

int main()
{
    {
        using Fn = int(Tag::*)(int);
        using RFn = int(Tag::*)(int) &&;
        // INVOKE bullet 1, 2 and 3
        {
            // Bullet 1
            static_assert(std::is_callable<Fn(Tag&, int)>::value);
            static_assert(std::is_callable<Fn(DerFromTag&, int)>::value);
            static_assert(std::is_callable<RFn(Tag&&, int)>::value);
            static_assert(!std::is_callable<RFn(Tag&, int)>::value);
            static_assert(!std::is_callable<Fn(Tag&)>::value);
            static_assert(!std::is_callable<Fn(Tag const&, int)>::value);
        }
        {
            // Bullet 2
            using T = std::reference_wrapper<Tag>;
            using DT = std::reference_wrapper<DerFromTag>;
            using CT = std::reference_wrapper<const Tag>;
            static_assert(std::is_callable<Fn(T&, int)>::value);
            static_assert(std::is_callable<Fn(DT&, int)>::value);
            static_assert(std::is_callable<Fn(const T&, int)>::value);
            static_assert(std::is_callable<Fn(T&&, int)>::value);
            static_assert(!std::is_callable<Fn(CT&, int)>::value);
            static_assert(!std::is_callable<RFn(T, int)>::value);
        }
        {
            // Bullet 3
            using T = Tag*;
            using DT = DerFromTag*;
            using CT = const Tag*;
            using ST = std::unique_ptr<Tag>;
            static_assert(std::is_callable<Fn(T&, int)>::value);
            static_assert(std::is_callable<Fn(DT&, int)>::value);
            static_assert(std::is_callable<Fn(const T&, int)>::value);
            static_assert(std::is_callable<Fn(T&&, int)>::value);
            static_assert(std::is_callable<Fn(ST, int)>::value);
            static_assert(!std::is_callable<Fn(CT&, int)>::value);
            static_assert(!std::is_callable<RFn(T, int)>::value);
        }
    }
    {
        // Bullets 4, 5 and 6
        using Fn = int (Tag::*);
        static_assert(!std::is_callable<Fn()>::value);
        {
            // Bullet 4
            static_assert(std::is_callable<Fn(Tag&)>::value);
            static_assert(std::is_callable<Fn(DerFromTag&)>::value);
            static_assert(std::is_callable<Fn(Tag&&)>::value);
            static_assert(std::is_callable<Fn(Tag const&)>::value);
        }
        {
            // Bullet 5
            using T = std::reference_wrapper<Tag>;
            using DT = std::reference_wrapper<DerFromTag>;
            using CT = std::reference_wrapper<const Tag>;
            static_assert(std::is_callable<Fn(T&)>::value);
            static_assert(std::is_callable<Fn(DT&)>::value);
            static_assert(std::is_callable<Fn(const T&)>::value);
            static_assert(std::is_callable<Fn(T&&)>::value);
            static_assert(std::is_callable<Fn(CT&)>::value);
        }
        {
            // Bullet 6
            using T = Tag*;
            using DT = DerFromTag*;
            using CT = const Tag*;
            using ST = std::unique_ptr<Tag>;
            static_assert(std::is_callable<Fn(T&)>::value);
            static_assert(std::is_callable<Fn(DT&)>::value);
            static_assert(std::is_callable<Fn(const T&)>::value);
            static_assert(std::is_callable<Fn(T&&)>::value);
            static_assert(std::is_callable<Fn(ST)>::value);
            static_assert(std::is_callable<Fn(CT&)>::value);
        }
    }
    {
        // INVOKE bullet 7
        {
            // Function pointer
            using Fp = void(*)(Tag&, int);
            static_assert(std::is_callable<Fp(Tag&, int)>::value);
            static_assert(std::is_callable<Fp(DerFromTag&, int)>::value);
            static_assert(!std::is_callable<Fp(const Tag&, int)>::value);
            static_assert(!std::is_callable<Fp()>::value);
            static_assert(!std::is_callable<Fp(Tag&)>::value);
        }
        {
            // Function reference
            using Fp = void(&)(Tag&, int);
            static_assert(std::is_callable<Fp(Tag&, int)>::value);
            static_assert(std::is_callable<Fp(DerFromTag&, int)>::value);
            static_assert(!std::is_callable<Fp(const Tag&, int)>::value);
            static_assert(!std::is_callable<Fp()>::value);
            static_assert(!std::is_callable<Fp(Tag&)>::value);
        }
        {
            // Function object
            using Fn = NotCallableWithInt;
            static_assert(std::is_callable<Fn(Tag)>::value, "");
            static_assert(!std::is_callable<Fn(int)>::value, "");
        }
    }
    {
        // Check that the conversion to the return type is properly checked
        using Fn = int(*)();
        static_assert(std::is_callable<Fn(), Implicit>::value);
        static_assert(std::is_callable<Fn(), double>::value);
        static_assert(std::is_callable<Fn(), const volatile void>::value);
        static_assert(!std::is_callable<Fn(), Explicit>::value);
    }
    {
        // Check for is_callable_v
        using Fn = void(*)();
        static_assert(std::is_callable_v<Fn()>);
        static_assert(!std::is_callable_v<Fn(int)>);
    }
}
<commit_msg>Add proper include for unique_ptr. Patch from STL@microsoft.com<commit_after>//===----------------------------------------------------------------------===//
//
//                     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.
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++98, c++03, c++11, c++14

// type_traits

// is_callable

// Most testing of is_callable is done within the [meta.trans.other] result_of
// tests.

#include <type_traits>
#include <functional>
#include <memory>

#include "test_macros.h"

struct Tag {};
struct DerFromTag : Tag {};

struct Implicit {
  Implicit(int) {}
};

struct Explicit {
  explicit Explicit(int) {}
};

struct NotCallableWithInt {
  int operator()(int) = delete;
  int operator()(Tag) { return 42; }
};

int main()
{
    {
        using Fn = int(Tag::*)(int);
        using RFn = int(Tag::*)(int) &&;
        // INVOKE bullet 1, 2 and 3
        {
            // Bullet 1
            static_assert(std::is_callable<Fn(Tag&, int)>::value);
            static_assert(std::is_callable<Fn(DerFromTag&, int)>::value);
            static_assert(std::is_callable<RFn(Tag&&, int)>::value);
            static_assert(!std::is_callable<RFn(Tag&, int)>::value);
            static_assert(!std::is_callable<Fn(Tag&)>::value);
            static_assert(!std::is_callable<Fn(Tag const&, int)>::value);
        }
        {
            // Bullet 2
            using T = std::reference_wrapper<Tag>;
            using DT = std::reference_wrapper<DerFromTag>;
            using CT = std::reference_wrapper<const Tag>;
            static_assert(std::is_callable<Fn(T&, int)>::value);
            static_assert(std::is_callable<Fn(DT&, int)>::value);
            static_assert(std::is_callable<Fn(const T&, int)>::value);
            static_assert(std::is_callable<Fn(T&&, int)>::value);
            static_assert(!std::is_callable<Fn(CT&, int)>::value);
            static_assert(!std::is_callable<RFn(T, int)>::value);
        }
        {
            // Bullet 3
            using T = Tag*;
            using DT = DerFromTag*;
            using CT = const Tag*;
            using ST = std::unique_ptr<Tag>;
            static_assert(std::is_callable<Fn(T&, int)>::value);
            static_assert(std::is_callable<Fn(DT&, int)>::value);
            static_assert(std::is_callable<Fn(const T&, int)>::value);
            static_assert(std::is_callable<Fn(T&&, int)>::value);
            static_assert(std::is_callable<Fn(ST, int)>::value);
            static_assert(!std::is_callable<Fn(CT&, int)>::value);
            static_assert(!std::is_callable<RFn(T, int)>::value);
        }
    }
    {
        // Bullets 4, 5 and 6
        using Fn = int (Tag::*);
        static_assert(!std::is_callable<Fn()>::value);
        {
            // Bullet 4
            static_assert(std::is_callable<Fn(Tag&)>::value);
            static_assert(std::is_callable<Fn(DerFromTag&)>::value);
            static_assert(std::is_callable<Fn(Tag&&)>::value);
            static_assert(std::is_callable<Fn(Tag const&)>::value);
        }
        {
            // Bullet 5
            using T = std::reference_wrapper<Tag>;
            using DT = std::reference_wrapper<DerFromTag>;
            using CT = std::reference_wrapper<const Tag>;
            static_assert(std::is_callable<Fn(T&)>::value);
            static_assert(std::is_callable<Fn(DT&)>::value);
            static_assert(std::is_callable<Fn(const T&)>::value);
            static_assert(std::is_callable<Fn(T&&)>::value);
            static_assert(std::is_callable<Fn(CT&)>::value);
        }
        {
            // Bullet 6
            using T = Tag*;
            using DT = DerFromTag*;
            using CT = const Tag*;
            using ST = std::unique_ptr<Tag>;
            static_assert(std::is_callable<Fn(T&)>::value);
            static_assert(std::is_callable<Fn(DT&)>::value);
            static_assert(std::is_callable<Fn(const T&)>::value);
            static_assert(std::is_callable<Fn(T&&)>::value);
            static_assert(std::is_callable<Fn(ST)>::value);
            static_assert(std::is_callable<Fn(CT&)>::value);
        }
    }
    {
        // INVOKE bullet 7
        {
            // Function pointer
            using Fp = void(*)(Tag&, int);
            static_assert(std::is_callable<Fp(Tag&, int)>::value);
            static_assert(std::is_callable<Fp(DerFromTag&, int)>::value);
            static_assert(!std::is_callable<Fp(const Tag&, int)>::value);
            static_assert(!std::is_callable<Fp()>::value);
            static_assert(!std::is_callable<Fp(Tag&)>::value);
        }
        {
            // Function reference
            using Fp = void(&)(Tag&, int);
            static_assert(std::is_callable<Fp(Tag&, int)>::value);
            static_assert(std::is_callable<Fp(DerFromTag&, int)>::value);
            static_assert(!std::is_callable<Fp(const Tag&, int)>::value);
            static_assert(!std::is_callable<Fp()>::value);
            static_assert(!std::is_callable<Fp(Tag&)>::value);
        }
        {
            // Function object
            using Fn = NotCallableWithInt;
            static_assert(std::is_callable<Fn(Tag)>::value, "");
            static_assert(!std::is_callable<Fn(int)>::value, "");
        }
    }
    {
        // Check that the conversion to the return type is properly checked
        using Fn = int(*)();
        static_assert(std::is_callable<Fn(), Implicit>::value);
        static_assert(std::is_callable<Fn(), double>::value);
        static_assert(std::is_callable<Fn(), const volatile void>::value);
        static_assert(!std::is_callable<Fn(), Explicit>::value);
    }
    {
        // Check for is_callable_v
        using Fn = void(*)();
        static_assert(std::is_callable_v<Fn()>);
        static_assert(!std::is_callable_v<Fn(int)>);
    }
}
<|endoftext|>


<commit_before>/* * This file is part of Maliit framework *
 *
 * Copyright (C) 2012 Openismus GmbH
 * Contact: maliit-discuss@lists.maliit.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * and appearing in the file LICENSE.LGPL included in the packaging
 * of this file.
 */

#include "ut_mimonscreenplugins.h"

#include "config.h"
#include "mimonscreenplugins.h"
#include "mimsettings.h"
#include "mimsettingsqsettings.h"

#include <QtCore>

namespace
{

const QString Organization = "maliit.org";
const QString Application = "server-tests";
const QString DefaultPlugin = MALIIT_DEFAULT_PLUGIN;
const QString DefaultSubview = MALIIT_DEFAULT_SUBVIEW;

}

void Ut_MImOnScreenPlugins::initTestCase()
{
    MImSettings::setImplementationFactory(new MImSettingsQSettingsBackendFactory(Organization, Application));
}

void Ut_MImOnScreenPlugins::cleanupTestCase()
{}

void Ut_MImOnScreenPlugins::init()
{}

void Ut_MImOnScreenPlugins::cleanup()
{
    QSettings settings(Organization, Application);
    settings.clear();
}

void Ut_MImOnScreenPlugins::testActiveAndEnabledSubviews_data()
{
    QTest::addColumn<QString>("active_key");
    QTest::addColumn<QString>("enabled_key");
    QTest::addColumn<QString>("initially_active");
    QTest::addColumn<QStringList>("initially_enabled");
    QTest::addColumn<QString>("expected_active_plugin");
    QTest::addColumn<QString>("expected_active_id");
    QTest::addColumn<int>("expected_enabled_count");
    QTest::addColumn<int>("expected_active_index");

    QTest::newRow("empty user configuration")
        << "maliit/onscreen/active" << "maliit/onscreen/enabled"
        << QString()
        << QStringList()
        << DefaultPlugin << DefaultSubview
        << 1 << 0;

    QTest::newRow("no active subview")
        << "maliit/onscreen/active" << "maliit/onscreen/enabled"
        << QString()
        << (QStringList() << QString(DefaultPlugin + ":cs")
                          << QString(DefaultPlugin + ":fr_ca"))
        << DefaultPlugin << DefaultSubview
        << 3 << 0;

    QTest::newRow("non-default active subview")
        << "maliit/onscreen/active" << "maliit/onscreen/enabled"
        << QString("libmaliit-keyboard-plugin.so:fr_ca")
        << (QStringList() << QString(DefaultPlugin + ":cs")
                          << QString(DefaultPlugin + ":fr_ca"))
        << DefaultPlugin << "fr_ca"
        << 2 << 1;

    QTest::newRow("active but no enabled subview (enabled default subview, too)")
        << "maliit/onscreen/active" << "maliit/onscreen/enabled"
        << QString(DefaultPlugin + ":fr_ca")
        << QStringList()
        << DefaultPlugin << "fr_ca"
        << 2 << 0;
}

void Ut_MImOnScreenPlugins::testActiveAndEnabledSubviews()
{
    QFETCH(QString, active_key);
    QFETCH(QString, enabled_key);
    QFETCH(QString, initially_active);
    QFETCH(QStringList, initially_enabled);
    QFETCH(QString, expected_active_plugin);
    QFETCH(QString, expected_active_id);
    QFETCH(int, expected_enabled_count);
    QFETCH(int, expected_active_index);

    QSettings settings(Organization, Application);

    if (not initially_active.isEmpty()) {
        settings.setValue(active_key, initially_active);
    }

    if (not initially_enabled.isEmpty()) {
        settings.setValue(enabled_key, initially_enabled);
    }

    MImOnScreenPlugins plugins;
    MImOnScreenPlugins::SubView active = plugins.activeSubView();
    QCOMPARE(active.plugin, expected_active_plugin);
    QCOMPARE(active.id, expected_active_id);

    QList<MImOnScreenPlugins::SubView> enabled = plugins.enabledSubViews(active.plugin);
    QCOMPARE(enabled.size(), expected_enabled_count);
    QCOMPARE(enabled.at(expected_active_index), active);
}

QTEST_MAIN(Ut_MImOnScreenPlugins)
<commit_msg>Forgot replace one instance of libmaliit-keyboard-plugin.so with DefaultPlugin<commit_after>/* * This file is part of Maliit framework *
 *
 * Copyright (C) 2012 Openismus GmbH
 * Contact: maliit-discuss@lists.maliit.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * and appearing in the file LICENSE.LGPL included in the packaging
 * of this file.
 */

#include "ut_mimonscreenplugins.h"

#include "config.h"
#include "mimonscreenplugins.h"
#include "mimsettings.h"
#include "mimsettingsqsettings.h"

#include <QtCore>

namespace
{

const QString Organization = "maliit.org";
const QString Application = "server-tests";
const QString DefaultPlugin = MALIIT_DEFAULT_PLUGIN;
const QString DefaultSubview = MALIIT_DEFAULT_SUBVIEW;

}

void Ut_MImOnScreenPlugins::initTestCase()
{
    MImSettings::setImplementationFactory(new MImSettingsQSettingsBackendFactory(Organization, Application));
}

void Ut_MImOnScreenPlugins::cleanupTestCase()
{}

void Ut_MImOnScreenPlugins::init()
{}

void Ut_MImOnScreenPlugins::cleanup()
{
    QSettings settings(Organization, Application);
    settings.clear();
}

void Ut_MImOnScreenPlugins::testActiveAndEnabledSubviews_data()
{
    QTest::addColumn<QString>("active_key");
    QTest::addColumn<QString>("enabled_key");
    QTest::addColumn<QString>("initially_active");
    QTest::addColumn<QStringList>("initially_enabled");
    QTest::addColumn<QString>("expected_active_plugin");
    QTest::addColumn<QString>("expected_active_id");
    QTest::addColumn<int>("expected_enabled_count");
    QTest::addColumn<int>("expected_active_index");

    QTest::newRow("empty user configuration")
        << "maliit/onscreen/active" << "maliit/onscreen/enabled"
        << QString()
        << QStringList()
        << DefaultPlugin << DefaultSubview
        << 1 << 0;

    QTest::newRow("no active subview")
        << "maliit/onscreen/active" << "maliit/onscreen/enabled"
        << QString()
        << (QStringList() << QString(DefaultPlugin + ":cs")
                          << QString(DefaultPlugin + ":fr_ca"))
        << DefaultPlugin << DefaultSubview
        << 3 << 0;

    QTest::newRow("non-default active subview")
        << "maliit/onscreen/active" << "maliit/onscreen/enabled"
        << QString(DefaultPlugin +":fr_ca")
        << (QStringList() << QString(DefaultPlugin + ":cs")
                          << QString(DefaultPlugin + ":fr_ca"))
        << DefaultPlugin << "fr_ca"
        << 2 << 1;

    QTest::newRow("active but no enabled subview (enabled default subview, too)")
        << "maliit/onscreen/active" << "maliit/onscreen/enabled"
        << QString(DefaultPlugin + ":fr_ca")
        << QStringList()
        << DefaultPlugin << "fr_ca"
        << 2 << 0;
}

void Ut_MImOnScreenPlugins::testActiveAndEnabledSubviews()
{
    QFETCH(QString, active_key);
    QFETCH(QString, enabled_key);
    QFETCH(QString, initially_active);
    QFETCH(QStringList, initially_enabled);
    QFETCH(QString, expected_active_plugin);
    QFETCH(QString, expected_active_id);
    QFETCH(int, expected_enabled_count);
    QFETCH(int, expected_active_index);

    QSettings settings(Organization, Application);

    if (not initially_active.isEmpty()) {
        settings.setValue(active_key, initially_active);
    }

    if (not initially_enabled.isEmpty()) {
        settings.setValue(enabled_key, initially_enabled);
    }

    MImOnScreenPlugins plugins;
    MImOnScreenPlugins::SubView active = plugins.activeSubView();
    QCOMPARE(active.plugin, expected_active_plugin);
    QCOMPARE(active.id, expected_active_id);

    QList<MImOnScreenPlugins::SubView> enabled = plugins.enabledSubViews(active.plugin);
    QCOMPARE(enabled.size(), expected_enabled_count);
    QCOMPARE(enabled.at(expected_active_index), active);
}

QTEST_MAIN(Ut_MImOnScreenPlugins)
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright David Doria 2011 daviddoria@gmail.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  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 <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <vtkSphereSource.h>
#include <vtkXMLPolyDataReader.h>

#include "vtkOBJWriter.h"

int main (int argc, char *argv[])
{
  vtkSmartPointer<vtkPolyData> input;
  std::string outputFilename;

  // Verify command line arguments
  if(argc > 1) // Use the command line arguments
    {
    if(argc != 3)
      {
      std::cout << "Required arguments: InputFilename.vtp OutputFilename.obj" << std::endl;
      return EXIT_FAILURE;
      }
    vtkSmartPointer<vtkXMLPolyDataReader> reader =
      vtkSmartPointer<vtkXMLPolyDataReader>::New();
    reader->SetFileName(argv[1]);
    reader->Update();

    input->ShallowCopy(reader->GetOutput());

    outputFilename = argv[2];
    }
  else
    {
    outputFilename = "output.obj";
    vtkSmartPointer<vtkSphereSource> sphereSource =
      vtkSmartPointer<vtkSphereSource>::New();
    sphereSource->Update();
    input->ShallowCopy(sphereSource->GetOutput());
    }

  vtkSmartPointer<vtkOBJWriter> writer =
      vtkSmartPointer<vtkOBJWriter>::New();
  writer->SetInputData(input);
  writer->SetFileName(outputFilename.c_str());
  writer->Update();

  return EXIT_SUCCESS;
}
<commit_msg>fix: vtkPolyData needs to be initialized<commit_after>/*=========================================================================
 *
 *  Copyright David Doria 2011 daviddoria@gmail.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  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 <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <vtkSphereSource.h>
#include <vtkXMLPolyDataReader.h>

#include "vtkOBJWriter.h"

int main (int argc, char *argv[])
{
  vtkSmartPointer<vtkPolyData> input =
    vtkSmartPointer<vtkPolyData>::New();
  std::string outputFilename;

  // Verify command line arguments
  if(argc > 1) // Use the command line arguments
    {
    if(argc != 3)
      {
      std::cout << "Required arguments: InputFilename.vtp OutputFilename.obj" << std::endl;
      return EXIT_FAILURE;
      }
    vtkSmartPointer<vtkXMLPolyDataReader> reader =
      vtkSmartPointer<vtkXMLPolyDataReader>::New();
    reader->SetFileName(argv[1]);
    reader->Update();

    input->ShallowCopy(reader->GetOutput());

    outputFilename = argv[2];
    }
  else
    {
    outputFilename = "output.obj";
    vtkSmartPointer<vtkSphereSource> sphereSource =
      vtkSmartPointer<vtkSphereSource>::New();
    sphereSource->Update();
    input->ShallowCopy(sphereSource->GetOutput());
    }

  vtkSmartPointer<vtkOBJWriter> writer =
    vtkSmartPointer<vtkOBJWriter>::New();
  writer->SetInputData(input);
  writer->SetFileName(outputFilename.c_str());
  writer->Update();

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <cstring>
#include <map>
#include <fstream>
#include "../cppGzip/DecodeGzip.h"
#include "../Include/MBTileReader.h"
#include <math.h>
#include <sstream>
#include <fstream>
#include <stdlib.h>
#include "../Include/VectorTile.h"
using namespace std;

// http://stackoverflow.com/a/236803/4288232
void strsplit(const string &s, char delim, vector<string> &elems) {
    stringstream ss(s);
    string item;
    while (getline(ss, item, delim)) {
        elems.push_back(item);
    }
}

///This class would need to be expanded to store features as needed.
class ExampleDataStore : public DecodeVectorTileResults
{
public:
	ExampleDataStore() : DecodeVectorTileResults()
	{
		cout << "Create custom data store..." << endl;
	}

	void Feature(int typeEnum, bool hasId, unsigned long long id,
		const std::map<std::string, std::string> &tagMap,
		std::vector<Point2D> &pointsOut,
		std::vector<std::vector<Point2D> > &linesOut,
		std::vector<Polygon2D> &polygonsOut)
	{
		//In real use, delete this function call and add your own functionality.
		DecodeVectorTileResults::Feature(typeEnum, hasId, id,
			tagMap, pointsOut, linesOut, polygonsOut);
	}
};

int main(int argc, char **argv)
{
	// Verify that the version of the library that we linked against is
	// compatible with the version of the headers we compiled against.
	GOOGLE_PROTOBUF_VERIFY_VERSION;

	//Grab from http://osm2vectortiles.org/downloads/
	class MBTileReader mbTileReader("cairo_egypt.mbtiles");

	cout << "name:" << mbTileReader.GetMetadata("name") << endl;
	cout << "type:" << mbTileReader.GetMetadata("type") << endl;
	string version = mbTileReader.GetMetadata("version");
	cout << "version:" << version << endl;
	vector<string> versionSplit;
	strsplit(version, '.', versionSplit);
	vector<int> versionInts;
	for (size_t i=0;i<versionSplit.size();i++) versionInts.push_back(atoi(versionSplit[i].c_str()));
	cout << "description:" << mbTileReader.GetMetadata("description") << endl;
	string format = mbTileReader.GetMetadata("format");
	cout << "format:" << format << endl;
	cout << "bounds:" << mbTileReader.GetMetadata("bounds") << endl;

	if(0) //Get metadata fields
	{
		std::vector<std::string> fieldNames;
		mbTileReader.GetMetadataFields(fieldNames);
		for(unsigned i=0;i<fieldNames.size();i++) cout << fieldNames[i] << endl;
	}

	if(0) //Get list of tiles
	{
		TileInfoRows tileInfoRows;
		mbTileReader.ListTiles(tileInfoRows);
		for(unsigned i=0;i < tileInfoRows.size(); i++)
		{
			for(size_t j=0; j < tileInfoRows[i].size(); j++)
				cout << tileInfoRows[i][j] << ",";
			cout << endl;
		}
	}

	string blob;
	int tileZoom = 14;
	int tileColumn = 9613;
	int tileRow = 9626;
	mbTileReader.GetTile(tileZoom, tileColumn, tileRow, blob);

	if(format == "pbf" && versionInts[0] == 2)
	{
		//Ungzip the data
		std::stringbuf buff;
		buff.sputn(blob.c_str(), blob.size());
		DecodeGzip dec(buff);

		string tileData;

		char tmp[1024];
		while(dec.in_avail())
		{
			streamsize bytes = dec.sgetn(tmp, 1024);
			tileData.append(tmp, bytes);
		}

		//Decode vector data
		class ExampleDataStore results;
		class DecodeVectorTile vectorDec(tileZoom, tileColumn, tileRow, results);
		vectorDec.DecodeTileData(tileData);
	}

	if(format == "jpg" || format == "png")
	{
		//Save image to output file
		stringstream filename;
		filename << "out" << "." << format;
		ofstream outFi(filename.str().c_str());
		outFi.write(blob.c_str(), blob.size());
	}

	// Optional:  Delete all global objects allocated by libprotobuf.
	google::protobuf::ShutdownProtobufLibrary();

}

<commit_msg>Update versionInts comparison so the example.cpp runs again.<commit_after>#include <iostream>
#include <cstring>
#include <map>
#include <fstream>
#include "../cppGzip/DecodeGzip.h"
#include "../Include/MBTileReader.h"
#include <math.h>
#include <sstream>
#include <fstream>
#include <stdlib.h>
#include "../Include/VectorTile.h"
using namespace std;

// http://stackoverflow.com/a/236803/4288232
void strsplit(const string &s, char delim, vector<string> &elems) {
    stringstream ss(s);
    string item;
    while (getline(ss, item, delim)) {
        elems.push_back(item);
    }
}

///This class would need to be expanded to store features as needed.
class ExampleDataStore : public DecodeVectorTileResults
{
public:
	ExampleDataStore() : DecodeVectorTileResults()
	{
		cout << "Create custom data store..." << endl;
	}

	void Feature(int typeEnum, bool hasId, unsigned long long id,
		const std::map<std::string, std::string> &tagMap,
		std::vector<Point2D> &pointsOut,
		std::vector<std::vector<Point2D> > &linesOut,
		std::vector<Polygon2D> &polygonsOut)
	{
		//In real use, delete this function call and add your own functionality.
		DecodeVectorTileResults::Feature(typeEnum, hasId, id,
			tagMap, pointsOut, linesOut, polygonsOut);
	}
};

int main(int argc, char **argv)
{
	// Verify that the version of the library that we linked against is
	// compatible with the version of the headers we compiled against.
	GOOGLE_PROTOBUF_VERIFY_VERSION;

	//Grab from http://osm2vectortiles.org/downloads/
	class MBTileReader mbTileReader("cairo_egypt.mbtiles");

	cout << "name:" << mbTileReader.GetMetadata("name") << endl;
	cout << "type:" << mbTileReader.GetMetadata("type") << endl;
	string version = mbTileReader.GetMetadata("version");
	cout << "version:" << version << endl;
	vector<string> versionSplit;
	strsplit(version, '.', versionSplit);
	vector<int> versionInts;
	for (size_t i=0;i<versionSplit.size();i++) versionInts.push_back(atoi(versionSplit[i].c_str()));
	cout << "description:" << mbTileReader.GetMetadata("description") << endl;
	string format = mbTileReader.GetMetadata("format");
	cout << "format:" << format << endl;
	cout << "bounds:" << mbTileReader.GetMetadata("bounds") << endl;

	if(1) //Get metadata fields
	{
		std::vector<std::string> fieldNames;
		mbTileReader.GetMetadataFields(fieldNames);
		for(unsigned i=0;i<fieldNames.size();i++) cout << fieldNames[i] << endl;
	}

	if(0) //Get list of tiles
	{
		TileInfoRows tileInfoRows;
		mbTileReader.ListTiles(tileInfoRows);
		for(unsigned i=0;i < tileInfoRows.size(); i++)
		{
			for(size_t j=0; j < tileInfoRows[i].size(); j++)
				cout << tileInfoRows[i][j] << ",";
			cout << endl;
		}
	}

	string blob;
	int tileZoom = 14;
	int tileColumn = 9613;
	int tileRow = 9626;
	mbTileReader.GetTile(tileZoom, tileColumn, tileRow, blob);

	if(format == "pbf" && versionInts[0] == 3)
	{
		//Ungzip the data
		std::stringbuf buff;
		buff.sputn(blob.c_str(), blob.size());
		DecodeGzip dec(buff);

		string tileData;

		char tmp[1024];
		while(dec.in_avail())
		{
			streamsize bytes = dec.sgetn(tmp, 1024);
			tileData.append(tmp, bytes);
		}

		//Decode vector data
		class ExampleDataStore results;
		class DecodeVectorTile vectorDec(tileZoom, tileColumn, tileRow, results);
		vectorDec.DecodeTileData(tileData);
	}

	if(format == "jpg" || format == "png")
	{
		//Save image to output file
		stringstream filename;
		filename << "out" << "." << format;
		ofstream outFi(filename.str().c_str());
		outFi.write(blob.c_str(), blob.size());
	}

	// Optional:  Delete all global objects allocated by libprotobuf.
	google::protobuf::ShutdownProtobufLibrary();

}

<|endoftext|>


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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include "mitkHistogramGenerator.h"
//#include "mitkImageTimeSelector.h"

mitk::ImageStatisticsHolder::ImageStatisticsHolder( mitk::Image* image)
  : m_Image(image)/*, m_TimeSelectorForExtremaObject(NULL)*/
{
  m_CountOfMinValuedVoxels.resize(1, 0);
  m_CountOfMaxValuedVoxels.resize(1, 0);
  m_ScalarMin.resize(1, itk::NumericTraits<ScalarType>::max());
  m_ScalarMax.resize(1, itk::NumericTraits<ScalarType>::NonpositiveMin());
  m_Scalar2ndMin.resize(1, itk::NumericTraits<ScalarType>::max());
  m_Scalar2ndMax.resize(1, itk::NumericTraits<ScalarType>::NonpositiveMin());

  mitk::HistogramGenerator::Pointer generator = mitk::HistogramGenerator::New();
  m_HistogramGeneratorObject = generator;

  //m_Image = image;

  // create time selector
  //this->GetTimeSelector();
}

mitk::ImageStatisticsHolder::~ImageStatisticsHolder()
{
  m_HistogramGeneratorObject = NULL;
  //m_TimeSelectorForExtremaObject = NULL;
  //m_Image = NULL;
}

const mitk::ImageStatisticsHolder::HistogramType* mitk::ImageStatisticsHolder::GetScalarHistogram(int t)
{
  mitk::ImageTimeSelector* timeSelector = this->GetTimeSelector();
  if(timeSelector!=NULL)
  {
    timeSelector->SetTimeNr(t);
    timeSelector->UpdateLargestPossibleRegion();

    mitk::HistogramGenerator* generator = static_cast<mitk::HistogramGenerator*>(m_HistogramGeneratorObject.GetPointer());
    generator->SetImage(timeSelector->GetOutput());
    generator->ComputeHistogram();
    return static_cast<const mitk::ImageStatisticsHolder::HistogramType*>(generator->GetHistogram());
  }
  return NULL;
}

bool mitk::ImageStatisticsHolder::IsValidTimeStep( int t) const
{
    return m_Image->IsValidTimeStep(t);
}

mitk::ImageTimeSelector::Pointer mitk::ImageStatisticsHolder::GetTimeSelector()
{
  //if(m_TimeSelectorForExtremaObject.IsNull())
  //{
  //  m_TimeSelectorForExtremaObject = ImageTimeSelector::New();

  ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New();//static_cast<mitk::ImageTimeSelector*>( m_TimeSelectorForExtremaObject.GetPointer() );
    timeSelector->SetInput(m_Image);
  //}

  return timeSelector; //static_cast<ImageTimeSelector*>( m_TimeSelectorForExtremaObject.GetPointer() );
}

void mitk::ImageStatisticsHolder::Expand( unsigned int timeSteps )
{
  if(! m_Image->IsValidTimeStep(timeSteps - 1) ) return;

  // The BaseData needs to be expanded, call the mitk::Image::Expand() method
  m_Image->Expand(timeSteps);

  if(timeSteps > m_ScalarMin.size() )
  {
    m_ScalarMin.resize(timeSteps, itk::NumericTraits<ScalarType>::max());
    m_ScalarMax.resize(timeSteps, itk::NumericTraits<ScalarType>::NonpositiveMin());
    m_Scalar2ndMin.resize(timeSteps, itk::NumericTraits<ScalarType>::max());
    m_Scalar2ndMax.resize(timeSteps, itk::NumericTraits<ScalarType>::NonpositiveMin());
    m_CountOfMinValuedVoxels.resize(timeSteps, 0);
    m_CountOfMaxValuedVoxels.resize(timeSteps, 0);
  }
}

void mitk::ImageStatisticsHolder::ResetImageStatistics()
{
  m_ScalarMin.assign(1, itk::NumericTraits<ScalarType>::max());
  m_ScalarMax.assign(1, itk::NumericTraits<ScalarType>::NonpositiveMin());
  m_Scalar2ndMin.assign(1, itk::NumericTraits<ScalarType>::max());
  m_Scalar2ndMax.assign(1, itk::NumericTraits<ScalarType>::NonpositiveMin());
  m_CountOfMinValuedVoxels.assign(1, 0);
  m_CountOfMaxValuedVoxels.assign(1, 0);
}

#include "mitkImageAccessByItk.h"

//#define BOUNDINGOBJECT_IGNORE

template < typename ItkImageType >
void mitk::_ComputeExtremaInItkImage( const ItkImageType* itkImage, mitk::ImageStatisticsHolder* statisticsHolder, int t)
{
  typename ItkImageType::RegionType region;
  region = itkImage->GetBufferedRegion();
  if(region.Crop(itkImage->GetRequestedRegion()) == false) return;
  if(region != itkImage->GetRequestedRegion()) return;

  itk::ImageRegionConstIterator<ItkImageType> it(itkImage, region);
  typedef typename ItkImageType::PixelType TPixel;
  TPixel value = 0;

  if ( statisticsHolder == NULL || !statisticsHolder->IsValidTimeStep( t ) ) return;
  statisticsHolder->Expand(t+1); // make sure we have initialized all arrays
  statisticsHolder->m_CountOfMinValuedVoxels[t] = 0;
  statisticsHolder->m_CountOfMaxValuedVoxels[t] = 0;

  statisticsHolder->m_Scalar2ndMin[t]=
      statisticsHolder->m_ScalarMin[t] = itk::NumericTraits<ScalarType>::max();
  statisticsHolder->m_Scalar2ndMax[t]=
      statisticsHolder->m_ScalarMax[t] = itk::NumericTraits<ScalarType>::NonpositiveMin();

  while( !it.IsAtEnd() )
  {
    value = it.Get();
    //  if ( (value > mitkImage->m_ScalarMin) && (value < mitkImage->m_Scalar2ndMin) )        mitkImage->m_Scalar2ndMin = value;
    //  else if ( (value < mitkImage->m_ScalarMax) && (value > mitkImage->m_Scalar2ndMax) )   mitkImage->m_Scalar2ndMax = value;
    //  else if (value > mitkImage->m_ScalarMax)                                              mitkImage->m_ScalarMax = value;
    //  else if (value < mitkImage->m_ScalarMin)                                              mitkImage->m_ScalarMin = value;

    // if numbers start with 2ndMin or 2ndMax and never have that value again, the previous above logic failed
#ifdef BOUNDINGOBJECT_IGNORE
    if( value > -32765)
    {
#endif
      // update min
      if ( value < statisticsHolder->m_ScalarMin[t] )
      {
        statisticsHolder->m_Scalar2ndMin[t] =
            statisticsHolder->m_ScalarMin[t];    statisticsHolder->m_ScalarMin[t] = value;
        statisticsHolder->m_CountOfMinValuedVoxels[t] = 1;
      }
      else if ( value == statisticsHolder->m_ScalarMin[t] )
      {
        ++statisticsHolder->m_CountOfMinValuedVoxels[t];
      }
      else if ( value < statisticsHolder->m_Scalar2ndMin[t] )
      {
        statisticsHolder->m_Scalar2ndMin[t] = value;
      }

      // update max
      if ( value > statisticsHolder->m_ScalarMax[t] )
      {
        statisticsHolder->m_Scalar2ndMax[t] =
            statisticsHolder->m_ScalarMax[t];    statisticsHolder->m_ScalarMax[t] = value;
        statisticsHolder->m_CountOfMaxValuedVoxels[t] = 1;
      }
      else if ( value == statisticsHolder->m_ScalarMax[t] )
      {
        ++statisticsHolder->m_CountOfMaxValuedVoxels[t];
      }
      else if ( value > statisticsHolder->m_Scalar2ndMax[t] )
      {
        statisticsHolder->m_Scalar2ndMax[t] = value;
      }
#ifdef BOUNDINGOBJECT_IGNORE
    }
#endif

    ++it;
  }

  //// guard for wrong 2dMin/Max on single constant value images
  if (statisticsHolder->m_ScalarMax[t] == statisticsHolder->m_ScalarMin[t])
  {
    statisticsHolder->m_Scalar2ndMax[t] = statisticsHolder->m_Scalar2ndMin[t] = statisticsHolder->m_ScalarMax[t];
  }
  statisticsHolder->m_LastRecomputeTimeStamp.Modified();
  //MITK_DEBUG <<"extrema "<<itk::NumericTraits<TPixel>::NonpositiveMin()<<" "<<mitkImage->m_ScalarMin<<" "<<mitkImage->m_Scalar2ndMin<<" "<<mitkImage->m_Scalar2ndMax<<" "<<mitkImage->m_ScalarMax<<" "<<itk::NumericTraits<TPixel>::max();
}

void mitk::ImageStatisticsHolder::ComputeImageStatistics(int t)
{
  // timestep valid?
  if (!m_Image->IsValidTimeStep(t)) return;

  // image modified?
  if (this->m_Image->GetMTime() > m_LastRecomputeTimeStamp.GetMTime())
    this->ResetImageStatistics();

  Expand(t+1);

  // do we have valid information already?
  if( m_ScalarMin[t] != itk::NumericTraits<ScalarType>::max() ||
      m_Scalar2ndMin[t] != itk::NumericTraits<ScalarType>::max() ) return; // Values already calculated before...

  const mitk::PixelType pType = m_Image->GetPixelType(0);
  if(pType.GetNumberOfComponents() == 1)
  {
    // recompute
    mitk::ImageTimeSelector::Pointer timeSelector = this->GetTimeSelector();
    if(timeSelector.IsNotNull())
    {
      timeSelector->SetTimeNr(t);
      timeSelector->UpdateLargestPossibleRegion();
      mitk::Image* image = timeSelector->GetOutput();
      AccessByItk_2( image, _ComputeExtremaInItkImage, this, t );
    }
  }
  else if(pType.GetNumberOfComponents() > 1)
  {
    m_ScalarMin[t] = 0;
    m_ScalarMax[t] = 255;
    m_Scalar2ndMin[t] = 0;
    m_Scalar2ndMax[t] = 255;
  }
}

mitk::ScalarType mitk::ImageStatisticsHolder::GetScalarValueMin(int t)
{
  ComputeImageStatistics(t);
  return m_ScalarMin[t];
}

mitk::ScalarType mitk::ImageStatisticsHolder::GetScalarValueMax(int t)
{
  ComputeImageStatistics(t);
  return m_ScalarMax[t];
}

mitk::ScalarType mitk::ImageStatisticsHolder::GetScalarValue2ndMin(int t)
{
  ComputeImageStatistics(t);
  return m_Scalar2ndMin[t];
}

mitk::ScalarType mitk::ImageStatisticsHolder::GetScalarValue2ndMax(int t)
{
  ComputeImageStatistics(t);
  return m_Scalar2ndMax[t];
}

mitk::ScalarType mitk::ImageStatisticsHolder::GetCountOfMinValuedVoxels(int t)
{
  ComputeImageStatistics(t);
  return m_CountOfMinValuedVoxels[t];
}

mitk::ScalarType mitk::ImageStatisticsHolder::GetCountOfMaxValuedVoxels(int t)
{
  ComputeImageStatistics(t);
  return m_CountOfMaxValuedVoxels[t];
}

<commit_msg>Disable image statistics for unknown pixel type<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include "mitkHistogramGenerator.h"
//#include "mitkImageTimeSelector.h"

mitk::ImageStatisticsHolder::ImageStatisticsHolder( mitk::Image* image)
  : m_Image(image)/*, m_TimeSelectorForExtremaObject(NULL)*/
{
  m_CountOfMinValuedVoxels.resize(1, 0);
  m_CountOfMaxValuedVoxels.resize(1, 0);
  m_ScalarMin.resize(1, itk::NumericTraits<ScalarType>::max());
  m_ScalarMax.resize(1, itk::NumericTraits<ScalarType>::NonpositiveMin());
  m_Scalar2ndMin.resize(1, itk::NumericTraits<ScalarType>::max());
  m_Scalar2ndMax.resize(1, itk::NumericTraits<ScalarType>::NonpositiveMin());

  mitk::HistogramGenerator::Pointer generator = mitk::HistogramGenerator::New();
  m_HistogramGeneratorObject = generator;

  //m_Image = image;

  // create time selector
  //this->GetTimeSelector();
}

mitk::ImageStatisticsHolder::~ImageStatisticsHolder()
{
  m_HistogramGeneratorObject = NULL;
  //m_TimeSelectorForExtremaObject = NULL;
  //m_Image = NULL;
}

const mitk::ImageStatisticsHolder::HistogramType* mitk::ImageStatisticsHolder::GetScalarHistogram(int t)
{
  mitk::ImageTimeSelector* timeSelector = this->GetTimeSelector();
  if(timeSelector!=NULL)
  {
    timeSelector->SetTimeNr(t);
    timeSelector->UpdateLargestPossibleRegion();

    mitk::HistogramGenerator* generator = static_cast<mitk::HistogramGenerator*>(m_HistogramGeneratorObject.GetPointer());
    generator->SetImage(timeSelector->GetOutput());
    generator->ComputeHistogram();
    return static_cast<const mitk::ImageStatisticsHolder::HistogramType*>(generator->GetHistogram());
  }
  return NULL;
}

bool mitk::ImageStatisticsHolder::IsValidTimeStep( int t) const
{
    return m_Image->IsValidTimeStep(t);
}

mitk::ImageTimeSelector::Pointer mitk::ImageStatisticsHolder::GetTimeSelector()
{
  //if(m_TimeSelectorForExtremaObject.IsNull())
  //{
  //  m_TimeSelectorForExtremaObject = ImageTimeSelector::New();

  ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New();//static_cast<mitk::ImageTimeSelector*>( m_TimeSelectorForExtremaObject.GetPointer() );
    timeSelector->SetInput(m_Image);
  //}

  return timeSelector; //static_cast<ImageTimeSelector*>( m_TimeSelectorForExtremaObject.GetPointer() );
}

void mitk::ImageStatisticsHolder::Expand( unsigned int timeSteps )
{
  if(! m_Image->IsValidTimeStep(timeSteps - 1) ) return;

  // The BaseData needs to be expanded, call the mitk::Image::Expand() method
  m_Image->Expand(timeSteps);

  if(timeSteps > m_ScalarMin.size() )
  {
    m_ScalarMin.resize(timeSteps, itk::NumericTraits<ScalarType>::max());
    m_ScalarMax.resize(timeSteps, itk::NumericTraits<ScalarType>::NonpositiveMin());
    m_Scalar2ndMin.resize(timeSteps, itk::NumericTraits<ScalarType>::max());
    m_Scalar2ndMax.resize(timeSteps, itk::NumericTraits<ScalarType>::NonpositiveMin());
    m_CountOfMinValuedVoxels.resize(timeSteps, 0);
    m_CountOfMaxValuedVoxels.resize(timeSteps, 0);
  }
}

void mitk::ImageStatisticsHolder::ResetImageStatistics()
{
  m_ScalarMin.assign(1, itk::NumericTraits<ScalarType>::max());
  m_ScalarMax.assign(1, itk::NumericTraits<ScalarType>::NonpositiveMin());
  m_Scalar2ndMin.assign(1, itk::NumericTraits<ScalarType>::max());
  m_Scalar2ndMax.assign(1, itk::NumericTraits<ScalarType>::NonpositiveMin());
  m_CountOfMinValuedVoxels.assign(1, 0);
  m_CountOfMaxValuedVoxels.assign(1, 0);
}

#include "mitkImageAccessByItk.h"

//#define BOUNDINGOBJECT_IGNORE

template < typename ItkImageType >
void mitk::_ComputeExtremaInItkImage( const ItkImageType* itkImage, mitk::ImageStatisticsHolder* statisticsHolder, int t)
{
  typename ItkImageType::RegionType region;
  region = itkImage->GetBufferedRegion();
  if(region.Crop(itkImage->GetRequestedRegion()) == false) return;
  if(region != itkImage->GetRequestedRegion()) return;

  itk::ImageRegionConstIterator<ItkImageType> it(itkImage, region);
  typedef typename ItkImageType::PixelType TPixel;
  TPixel value = 0;

  if ( statisticsHolder == NULL || !statisticsHolder->IsValidTimeStep( t ) ) return;
  statisticsHolder->Expand(t+1); // make sure we have initialized all arrays
  statisticsHolder->m_CountOfMinValuedVoxels[t] = 0;
  statisticsHolder->m_CountOfMaxValuedVoxels[t] = 0;

  statisticsHolder->m_Scalar2ndMin[t]=
      statisticsHolder->m_ScalarMin[t] = itk::NumericTraits<ScalarType>::max();
  statisticsHolder->m_Scalar2ndMax[t]=
      statisticsHolder->m_ScalarMax[t] = itk::NumericTraits<ScalarType>::NonpositiveMin();

  while( !it.IsAtEnd() )
  {
    value = it.Get();
    //  if ( (value > mitkImage->m_ScalarMin) && (value < mitkImage->m_Scalar2ndMin) )        mitkImage->m_Scalar2ndMin = value;
    //  else if ( (value < mitkImage->m_ScalarMax) && (value > mitkImage->m_Scalar2ndMax) )   mitkImage->m_Scalar2ndMax = value;
    //  else if (value > mitkImage->m_ScalarMax)                                              mitkImage->m_ScalarMax = value;
    //  else if (value < mitkImage->m_ScalarMin)                                              mitkImage->m_ScalarMin = value;

    // if numbers start with 2ndMin or 2ndMax and never have that value again, the previous above logic failed
#ifdef BOUNDINGOBJECT_IGNORE
    if( value > -32765)
    {
#endif
      // update min
      if ( value < statisticsHolder->m_ScalarMin[t] )
      {
        statisticsHolder->m_Scalar2ndMin[t] =
            statisticsHolder->m_ScalarMin[t];    statisticsHolder->m_ScalarMin[t] = value;
        statisticsHolder->m_CountOfMinValuedVoxels[t] = 1;
      }
      else if ( value == statisticsHolder->m_ScalarMin[t] )
      {
        ++statisticsHolder->m_CountOfMinValuedVoxels[t];
      }
      else if ( value < statisticsHolder->m_Scalar2ndMin[t] )
      {
        statisticsHolder->m_Scalar2ndMin[t] = value;
      }

      // update max
      if ( value > statisticsHolder->m_ScalarMax[t] )
      {
        statisticsHolder->m_Scalar2ndMax[t] =
            statisticsHolder->m_ScalarMax[t];    statisticsHolder->m_ScalarMax[t] = value;
        statisticsHolder->m_CountOfMaxValuedVoxels[t] = 1;
      }
      else if ( value == statisticsHolder->m_ScalarMax[t] )
      {
        ++statisticsHolder->m_CountOfMaxValuedVoxels[t];
      }
      else if ( value > statisticsHolder->m_Scalar2ndMax[t] )
      {
        statisticsHolder->m_Scalar2ndMax[t] = value;
      }
#ifdef BOUNDINGOBJECT_IGNORE
    }
#endif

    ++it;
  }

  //// guard for wrong 2dMin/Max on single constant value images
  if (statisticsHolder->m_ScalarMax[t] == statisticsHolder->m_ScalarMin[t])
  {
    statisticsHolder->m_Scalar2ndMax[t] = statisticsHolder->m_Scalar2ndMin[t] = statisticsHolder->m_ScalarMax[t];
  }
  statisticsHolder->m_LastRecomputeTimeStamp.Modified();
  //MITK_DEBUG <<"extrema "<<itk::NumericTraits<TPixel>::NonpositiveMin()<<" "<<mitkImage->m_ScalarMin<<" "<<mitkImage->m_Scalar2ndMin<<" "<<mitkImage->m_Scalar2ndMax<<" "<<mitkImage->m_ScalarMax<<" "<<itk::NumericTraits<TPixel>::max();
}

void mitk::ImageStatisticsHolder::ComputeImageStatistics(int t)
{
  // timestep valid?
  if (!m_Image->IsValidTimeStep(t)) return;

  // image modified?
  if (this->m_Image->GetMTime() > m_LastRecomputeTimeStamp.GetMTime())
    this->ResetImageStatistics();

  Expand(t+1);

  // do we have valid information already?
  if( m_ScalarMin[t] != itk::NumericTraits<ScalarType>::max() ||
      m_Scalar2ndMin[t] != itk::NumericTraits<ScalarType>::max() ) return; // Values already calculated before...

  const mitk::PixelType pType = m_Image->GetPixelType(0);
  if(pType.GetNumberOfComponents() == 1 && (pType.GetPixelType() != itk::ImageIOBase::UNKNOWNPIXELTYPE) )
  {
    // recompute
    mitk::ImageTimeSelector::Pointer timeSelector = this->GetTimeSelector();
    if(timeSelector.IsNotNull())
    {
      timeSelector->SetTimeNr(t);
      timeSelector->UpdateLargestPossibleRegion();
      mitk::Image* image = timeSelector->GetOutput();
      AccessByItk_2( image, _ComputeExtremaInItkImage, this, t );
    }
  }
  else if(pType.GetNumberOfComponents() > 1)
  {
    m_ScalarMin[t] = 0;
    m_ScalarMax[t] = 255;
    m_Scalar2ndMin[t] = 0;
    m_Scalar2ndMax[t] = 255;
  }
}

mitk::ScalarType mitk::ImageStatisticsHolder::GetScalarValueMin(int t)
{
  ComputeImageStatistics(t);
  return m_ScalarMin[t];
}

mitk::ScalarType mitk::ImageStatisticsHolder::GetScalarValueMax(int t)
{
  ComputeImageStatistics(t);
  return m_ScalarMax[t];
}

mitk::ScalarType mitk::ImageStatisticsHolder::GetScalarValue2ndMin(int t)
{
  ComputeImageStatistics(t);
  return m_Scalar2ndMin[t];
}

mitk::ScalarType mitk::ImageStatisticsHolder::GetScalarValue2ndMax(int t)
{
  ComputeImageStatistics(t);
  return m_Scalar2ndMax[t];
}

mitk::ScalarType mitk::ImageStatisticsHolder::GetCountOfMinValuedVoxels(int t)
{
  ComputeImageStatistics(t);
  return m_CountOfMinValuedVoxels[t];
}

mitk::ScalarType mitk::ImageStatisticsHolder::GetCountOfMaxValuedVoxels(int t)
{
  ComputeImageStatistics(t);
  return m_CountOfMaxValuedVoxels[t];
}

<|endoftext|>


<commit_before>#include "RhoConf.h"
#include "RhoFile.h"
#include "RhoFilePath.h"
#include "StringConverter.h"

static const char* CONF_FILENAME = "apps/rhoconfig.txt";

extern "C" void rho_conf_set_property_by_name(char* name, char* value);

namespace rho{
namespace common{

RhoSettings g_RhoSettings;

void RhoSettings::saveToFile(){
    String strData;
    saveToString(strData);

    common::CRhoFile oFile;
    oFile.open(  getConfFilePath().c_str(), common::CRhoFile::OpenForWrite);

    oFile.write( strData.c_str(), strData.size() );
}

void RhoSettings::loadFromFile(){
    common::CRhoFile oFile;
    if ( oFile.open( getConfFilePath().c_str(), common::CRhoFile::OpenReadOnly) ){
        String strSettings;
        oFile.readString(strSettings);
        loadFromString( strSettings.c_str() );
    }
}

void RhoSettings::loadFromString(const char* szSettings){
    if ( !szSettings && !*szSettings )
        return;

    const char* start = szSettings;

    while(start!=0){
        int len = 0;

        const char* end = end = strchr(start,'\n');
        if (end){
            if ( end > start && *(end-1) == '\r' )
                len = end-start-1;
            else
                len = end-start;
        }else {
            len = (int)strlen(start);
        }

        loadProperty( start, len );

        start = end ? end + 1 : end;
    }
}

void RhoSettings::loadProperty( const char* start, int len ){
    int nNameLen = 0;
    while(*start==' '){ start++; len--;}

    int i = 0;
    for( i = 0; i < len; i++ ){
        if ( start[i] == '=' ){
            if ( i > 0 ){
                int s = i-1;
                for(; s >= 0 && start[s]==' '; s-- );

                nNameLen = s+1;
                break;
            }else
                break;
        }
    }

    if ( nNameLen == 0 )
        return;

    const char* szValue = start + i+1;
    int nValueLen = len - (i+1);

    while(*szValue==' ' || *szValue=='\'' || *szValue=='"' && nValueLen >= 0 ){ szValue++; nValueLen--;}
    while(nValueLen > 0 && (szValue[nValueLen-1]==' ' || szValue[nValueLen-1]=='\'' || szValue[nValueLen-1]=='"')) nValueLen--;

    setPropertyByName(start, nNameLen, szValue, nValueLen );
}

void RhoSettings::setPropertyByName(const char* szName, int nNameLen, const char* szValue, int nValueLen ){
    String name(szName,nNameLen);
    String value(szValue,nValueLen);
	printf("name: %s, value: %s\n", name.c_str(), value.c_str());
    m_mapValues[name] = value;
}

void RhoSettings::saveToString(String& strData){
	for ( std::map<String,String>::iterator it=m_mapValues.begin() ; it != m_mapValues.end(); it++ ) {
        strData += it->first;
        strData += "='";
        strData += it->second;
        strData += "'";
        strData += LOG_NEWLINE;
	}
}

String RhoSettings::getString(const char* szName){
	std::map<String,String>::iterator it = m_mapValues.find(szName);
	if ( it != m_mapValues.end() )
        return it->second;

    return String();
}

int RhoSettings::getInt(const char* szName){
	std::map<String,String>::iterator it = m_mapValues.find(szName);
	if ( it != m_mapValues.end() )
        return atoi(it->second.c_str());

    return 0;
}

bool   RhoSettings::getBool(const char* szName){
    return getInt(szName) == 0 ? false : true;
}

void   RhoSettings::setString(const char* szName, const String& str){
    m_mapValues[szName] = str;
}

void   RhoSettings::setInt(const char* szName, int nVal){
    m_mapValues[szName] = common::convertToStringA(nVal);
}

void   RhoSettings::setBool(const char* szName, bool bVal){
    setInt(szName, bVal?1:0);
}

bool   RhoSettings::isExist(const char* szName){
	std::map<String,String>::iterator it = m_mapValues.find(szName);
	return it != m_mapValues.end();
}

}
}

extern "C" {

void rho_conf_Init(const char* szRootPath){
	rho::common::CFilePath oRhoPath( szRootPath );

    RHOCONF().setConfFilePath(oRhoPath.makeFullPath(CONF_FILENAME).c_str());
}

bool rho_conf_getBool(const char* szName) {
	return RHOCONF().getBool(szName);
}

void rho_conf_setBool(const char* szName, bool value) {
	RHOCONF().setBool(szName,value);
}

char* rho_conf_getString(const char* szName) {
	return strdup(RHOCONF().getString(szName).c_str());
}

void rho_conf_freeString(char* str) {
	free(str);
}

void rho_conf_setString(const char* szName, const char* value){
	RHOCONF().setString(szName,value);
}

void rho_conf_save() {
	RHOCONF().saveToFile();
}

char* str_assign_ex( char* data, int len)
{
	if (data)
	{
		char* a = (char*)malloc(len+1);
		strncpy(a,data,len);
		a[len] = 0;
		return a;
	}
	return 0;
}

char* str_assign(char* data)
{
	if (data)
	{
		int len = strlen(data);
		return str_assign_ex(data,len);
	}
	return 0;
}

}

// RhoConf.set_property_by_name
void rho_conf_set_property_by_name(char* name, char* value)
{
	rho_conf_setString(name, value);
	rho_conf_save();
}<commit_msg>Fix WM rhoconf<commit_after>#include "RhoConf.h"
#include "RhoFile.h"
#include "RhoFilePath.h"
#include "StringConverter.h"

static const char* CONF_FILENAME = "apps/rhoconfig.txt";

extern "C" void rho_conf_set_property_by_name(char* name, char* value);

namespace rho{
namespace common{

RhoSettings g_RhoSettings;

void RhoSettings::saveToFile(){
    String strData;
    saveToString(strData);

    common::CRhoFile oFile;
    oFile.open(  getConfFilePath().c_str(), common::CRhoFile::OpenForWrite);

    oFile.write( strData.c_str(), strData.size() );
}

void RhoSettings::loadFromFile(){
    common::CRhoFile oFile;
    if ( oFile.open( getConfFilePath().c_str(), common::CRhoFile::OpenReadOnly) ){
        String strSettings;
        oFile.readString(strSettings);
        loadFromString( strSettings.c_str() );
    }
}

void RhoSettings::loadFromString(const char* szSettings){
    if ( !szSettings && !*szSettings )
        return;

    const char* start = szSettings;

    while(start!=0){
        int len = 0;

        const char* end = end = strchr(start,'\n');
        if (end){
            if ( end > start && *(end-1) == '\r' )
                len = end-start-1;
            else
                len = end-start;
        }else {
            len = (int)strlen(start);
        }

        loadProperty( start, len );

        start = end ? end + 1 : end;
    }
}

void RhoSettings::loadProperty( const char* start, int len ){
    int nNameLen = 0;
    while(*start==' '){ start++; len--;}

    int i = 0;
    for( i = 0; i < len; i++ ){
        if ( start[i] == '=' ){
            if ( i > 0 ){
                int s = i-1;
                for(; s >= 0 && start[s]==' '; s-- );

                nNameLen = s+1;
                break;
            }else
                break;
        }
    }

    if ( nNameLen == 0 )
        return;

    const char* szValue = start + i+1;
    int nValueLen = len - (i+1);

    while(*szValue==' ' || *szValue=='\'' || *szValue=='"' && nValueLen >= 0 ){ szValue++; nValueLen--;}
    while(nValueLen > 0 && (szValue[nValueLen-1]==' ' || szValue[nValueLen-1]=='\'' || szValue[nValueLen-1]=='"')) nValueLen--;

    setPropertyByName(start, nNameLen, szValue, nValueLen );
}

void RhoSettings::setPropertyByName(const char* szName, int nNameLen, const char* szValue, int nValueLen ){
    String name(szName,nNameLen);
    String value(szValue,nValueLen);
	printf("name: %s, value: %s\n", name.c_str(), value.c_str());
    m_mapValues[name] = value;
}

void RhoSettings::saveToString(String& strData){
	for ( std::map<String,String>::iterator it=m_mapValues.begin() ; it != m_mapValues.end(); it++ ) {
        strData += it->first;
        strData += "='";
        strData += it->second;
        strData += "'";
        strData += LOG_NEWLINE;
	}
}

String RhoSettings::getString(const char* szName){
	std::map<String,String>::iterator it = m_mapValues.find(szName);
	if ( it != m_mapValues.end() )
        return it->second;

    return String();
}

int RhoSettings::getInt(const char* szName){
	std::map<String,String>::iterator it = m_mapValues.find(szName);
	if ( it != m_mapValues.end() )
        return atoi(it->second.c_str());

    return 0;
}

bool   RhoSettings::getBool(const char* szName){
    return getInt(szName) == 0 ? false : true;
}

void   RhoSettings::setString(const char* szName, const String& str){
    m_mapValues[szName] = str;
}

void   RhoSettings::setInt(const char* szName, int nVal){
    m_mapValues[szName] = common::convertToStringA(nVal);
}

void   RhoSettings::setBool(const char* szName, bool bVal){
    setInt(szName, bVal?1:0);
}

bool   RhoSettings::isExist(const char* szName){
	std::map<String,String>::iterator it = m_mapValues.find(szName);
	return it != m_mapValues.end();
}

}
}

extern "C" {

void rho_conf_Init(const char* szRootPath){
	rho::common::CFilePath oRhoPath( szRootPath );

    RHOCONF().setConfFilePath(oRhoPath.makeFullPath(CONF_FILENAME).c_str());
}

bool rho_conf_getBool(const char* szName) {
	return RHOCONF().getBool(szName);
}

void rho_conf_setBool(const char* szName, bool value) {
	RHOCONF().setBool(szName,value);
}

char* rho_conf_getString(const char* szName) {
	return strdup(RHOCONF().getString(szName).c_str());
}

void rho_conf_freeString(char* str) {
	free(str);
}

void rho_conf_setString(const char* szName, const char* value){
    RHOCONF().setString(szName,value ? value : "");
}

void rho_conf_save() {
	RHOCONF().saveToFile();
}

char* str_assign_ex( char* data, int len)
{
	if (data)
	{
		char* a = (char*)malloc(len+1);
		strncpy(a,data,len);
		a[len] = 0;
		return a;
	}
	return 0;
}

char* str_assign(char* data)
{
	if (data)
	{
		int len = strlen(data);
		return str_assign_ex(data,len);
	}
	return 0;
}

}

// RhoConf.set_property_by_name
void rho_conf_set_property_by_name(char* name, char* value)
{
	rho_conf_setString(name, value);
	rho_conf_save();
}<|endoftext|>


<commit_before>// Time:  O(n)
// Space: O(n)

/**
 * Definition for a point.
 * struct Point {
 *     int x;
 *     int y;
 *     Point() : x(0), y(0) {}
 *     Point(int a, int b) : x(a), y(b) {}
 * };
 */

class Solution {
public:
    /**
     * @param n an integer
     * @param m an integer
     * @param operators an array of point
     * @return an integer array
     */
    vector<int> numIslands2(int n, int m, vector<Point>& operators) {
        vector<int> numbers;
        int number = 0;
        const vector<pair<int, int>> directions{{0, -1}, {0, 1},
                                                {-1, 0}, {1, 0}};
        unordered_map<int, int> set;
        for (const auto& oper : operators) {
            const auto& node = make_pair(oper.x, oper.y);
            set[node_id(node, m)] = node_id(node, m);

            // For each direction, count distinct islands.
            unordered_set<int> neighbors;
            for (const auto& d : directions) {
                const auto& neighbor = make_pair(oper.x + d.first,
                                                 oper.y + d.second);
                if (neighbor.first >= 0 && neighbor.first < n &&
                    neighbor.second >= 0 && neighbor.second < m &&
                    set.find(node_id(neighbor, m)) != set.end()) {
                    neighbors.emplace(find_set(node_id(neighbor, m), &set));
                }
            }

            // For each direction, find and union.
            for (const auto& d : directions) {
                const auto& neighbor = make_pair(oper.x + d.first, oper.y + d.second);
                if (neighbor.first >= 0 && neighbor.first < n &&
                    neighbor.second >= 0 && neighbor.second < m &&
                    set.find(node_id(neighbor, m)) != set.end()) {
                    union_set(&set, node_id(node, m), node_id(neighbor, m));
                }
            }

            number += 1 - neighbors.size();
            numbers.emplace_back(number);
        }
        return numbers;
    }

    int node_id(const pair<int, int>& node, const int m) {
        return node.first * m + node.second;
    }

    int find_set(int x, unordered_map<int, int> *set) {
       if ((*set)[x] != x) {
           (*set)[x] = find_set((*set)[x], set);  // path compression.
       }
       return (*set)[x];
    }

    void union_set(unordered_map<int, int> *set, const int x, const int y) {
        int x_root = find_set(x, set), y_root = find_set(y, set);
        (*set)[min(x_root, y_root)] = max(x_root, y_root);
    }
};
<commit_msg>Update number-of-islands-ii.cpp<commit_after>// Time:  O(p), p is number of operators.
// Space: O(p)

/**
 * Definition for a point.
 * struct Point {
 *     int x;
 *     int y;
 *     Point() : x(0), y(0) {}
 *     Point(int a, int b) : x(a), y(b) {}
 * };
 */

class Solution {
public:
    /**
     * @param n an integer
     * @param m an integer
     * @param operators an array of point
     * @return an integer array
     */
    vector<int> numIslands2(int n, int m, vector<Point>& operators) {
        vector<int> numbers;
        int number = 0;
        const vector<pair<int, int>> directions{{0, -1}, {0, 1},
                                                {-1, 0}, {1, 0}};
        unordered_map<int, int> set;
        for (const auto& oper : operators) {
            const auto& node = make_pair(oper.x, oper.y);
            set[node_id(node, m)] = node_id(node, m);

            // For each direction, count distinct islands.
            unordered_set<int> neighbors;
            for (const auto& d : directions) {
                const auto& neighbor = make_pair(oper.x + d.first,
                                                 oper.y + d.second);
                if (neighbor.first >= 0 && neighbor.first < n &&
                    neighbor.second >= 0 && neighbor.second < m &&
                    set.find(node_id(neighbor, m)) != set.end()) {
                    neighbors.emplace(find_set(node_id(neighbor, m), &set));
                }
            }

            // For each direction, find and union.
            for (const auto& d : directions) {
                const auto& neighbor = make_pair(oper.x + d.first, oper.y + d.second);
                if (neighbor.first >= 0 && neighbor.first < n &&
                    neighbor.second >= 0 && neighbor.second < m &&
                    set.find(node_id(neighbor, m)) != set.end()) {
                    union_set(&set, node_id(node, m), node_id(neighbor, m));
                }
            }

            number += 1 - neighbors.size();
            numbers.emplace_back(number);
        }
        return numbers;
    }

    int node_id(const pair<int, int>& node, const int m) {
        return node.first * m + node.second;
    }

    int find_set(int x, unordered_map<int, int> *set) {
       if ((*set)[x] != x) {
           (*set)[x] = find_set((*set)[x], set);  // path compression.
       }
       return (*set)[x];
    }

    void union_set(unordered_map<int, int> *set, const int x, const int y) {
        int x_root = find_set(x, set), y_root = find_set(y, set);
        (*set)[min(x_root, y_root)] = max(x_root, y_root);
    }
};
<|endoftext|>