<commit_before>#include "Cache.h"

#ifndef DEBUG_CACHE
#define debug(...)
#else
#define debug(...) do { \
          printf("\033[36m[DEBUG] %s ", __FUNCTION__); \
          printf(__VA_ARGS__); \
          printf("\033[0m\n"); \
      } while (0)
#endif

namespace ramulator
{

Cache::Cache(int size, int assoc, int block_size,
    int mshr_entry_num, Level level,
    std::shared_ptr<CacheSystem> cachesys):
    level(level), cachesys(cachesys), higher_cache(0),
    lower_cache(nullptr), size(size), assoc(assoc),
    block_size(block_size), mshr_entry_num(mshr_entry_num) {

  debug("level %d size %d assoc %d block_size %d\n",
      int(level), size, assoc, block_size);

  if (level == Level::L1) {
    level_string = "L1";
  } else if (level == Level::L2) {
    level_string = "L2";
  } else if (level == Level::L3) {
    level_string = "L3";
  }

  is_first_level = (level == cachesys->first_level);
  is_last_level = (level == cachesys->last_level);

  // Check size, block size and assoc are 2^N
  assert((size & (size - 1)) == 0);
  assert((block_size & (block_size - 1)) == 0);
  assert((assoc & (assoc - 1)) == 0);
  assert(size >= block_size);

  // Initialize cache configuration
  block_num = size / (block_size * assoc);
  index_mask = block_num - 1;
  index_offset = calc_log2(block_size);
  tag_offset = calc_log2(block_num) + index_offset;

  debug("index_offset %d", index_offset);
  debug("index_mask 0x%x", index_mask);
  debug("tag_offset %d", tag_offset);

  // regStats
  cache_read_miss.name(level_string + string("_cache_read_miss"))
                 .desc("cache read miss count")
                 .precision(0);

  cache_write_miss.name(level_string + string("_cache_write_miss"))
                  .desc("cache write miss count")
                  .precision(0);

  cache_total_miss.name(level_string + string("_cache_total_miss"))
                  .desc("cache total miss count")
                  .precision(0);

  cache_eviction.name(level_string + string("_cache_eviction"))
                .desc("number of evict from this level to lower level")
                .precision(0);

  cache_read_access.name(level_string + string("_cache_read_access"))
                  .desc("cache read access count")
                  .precision(0);

  cache_write_access.name(level_string + string("_cache_write_access"))
                    .desc("cache write access count")
                    .precision(0);

  cache_total_access.name(level_string + string("_cache_total_access"))
                    .desc("cache total access count")
                    .precision(0);

  cache_mshr_hit.name(level_string + string("_cache_mshr_hit"))
                .desc("cache mshr hit count")
                .precision(0);
  cache_mshr_unavailable.name(level_string + string("_cache_mshr_unavailable"))
                         .desc("cache mshr not available count")
                         .precision(0);
  cache_set_unavailable.name(level_string + string("_cache_set_unavailable"))
                         .desc("cache set not available")
                         .precision(0);
}

bool Cache::send(Request req) {
  debug("level %d req.addr %lx req.type %d, index %d, tag %ld",
      int(level), req.addr, int(req.type), get_index(req.addr),
      get_tag(req.addr));

  cache_total_access++;
  if (req.type == Request::Type::WRITE) {
    cache_write_access++;
  } else {
    assert(req.type == Request::Type::READ);
    cache_read_access++;
  }
  // If there isn't a set, create it.
  auto& lines = get_lines(req.addr);
  std::list<Line>::iterator line;

  if (is_hit(lines, req.addr, &line)) {
    lines.push_back(Line(req.addr, get_tag(req.addr), false,
        line->dirty || (req.type == Request::Type::WRITE)));
    lines.erase(line);
    cachesys->hit_list.push_back(
        make_pair(cachesys->clk + latency[int(level)], req));

    debug("hit, update timestamp %ld", cachesys->clk);
    debug("hit finish time %ld",
        cachesys->clk + latency[int(level)]);

    return true;

  } else {
    debug("miss @level %d", int(level));
    cache_total_miss++;
    if (req.type == Request::Type::WRITE) {
      cache_write_miss++;
    } else {
      assert(req.type == Request::Type::READ);
      cache_read_miss++;
    }

    // The dirty bit will be set if this is a write request and @L1
    bool dirty = (req.type == Request::Type::WRITE);

    // Modify the type of the request to lower level
    if (req.type == Request::Type::WRITE) {
      req.type = Request::Type::READ;
    }

    // Look it up in MSHR entries
    assert(req.type == Request::Type::READ);
    auto mshr = hit_mshr(req.addr);
    if (mshr != mshr_entries.end()) {
      debug("hit mshr");
      cache_mshr_hit++;
      mshr->second->dirty = dirty || mshr->second->dirty;
      return true;
    }

    // All requests come to this stage will be READ, so they
    // should be recorded in MSHR entries.
    if (mshr_entries.size() == mshr_entry_num) {
      // When no MSHR entries available, the miss request
      // is stalling.
      cache_mshr_unavailable++;
      debug("no mshr entry available");
      return false;
    }

    // Check whether there is a line available
    if (all_sets_locked(lines)) {
      cache_set_unavailable++;
      return false;
    }

    auto newline = allocate_line(lines, req.addr);
    if (newline == lines.end()) {
      return false;
    }

    newline->dirty = dirty;

    // Add to MSHR entries
    mshr_entries.push_back(make_pair(req.addr, newline));

    // Send the request to next level;
    if (!is_last_level) {
      lower_cache->send(req);
    } else {
      cachesys->wait_list.push_back(
          make_pair(cachesys->clk + latency[int(level)], req));
    }
    return true;
  }
}

void Cache::evictline(long addr, bool dirty) {

  auto it = cache_lines.find(get_index(addr));
  assert(it != cache_lines.end()); // check inclusive cache
  auto& lines = it->second;
  auto line = find_if(lines.begin(), lines.end(),
      [addr, this](Line l){return (l.tag == get_tag(addr));});

  assert(line != lines.end());
  // Update LRU queue. The dirty bit will be set if the dirty
  // bit inherited from higher level(s) is set.
  lines.push_back(Line(addr, get_tag(addr), false,
      dirty || line->dirty));
  lines.erase(line);
}

std::pair<long, bool> Cache::invalidate(long addr) {
  long delay = latency_each[int(level)];
  bool dirty = false;

  auto& lines = get_lines(addr);
  if (lines.size() == 0) {
    // The line of this address doesn't exist.
    return make_pair(0, false);
  }
  auto line = find_if(lines.begin(), lines.end(),
      [addr, this](Line l){return (l.tag == get_tag(addr));});

  // If the line is in this level cache, then erase it from
  // the buffer.
  if (line != lines.end()) {
    assert(!line->lock);
    debug("invalidate %lx @ level %d", addr, int(level));
    lines.erase(line);
  } else {
    // If it's not in current level, then no need to go up.
    return make_pair(delay, false);
  }

  if (higher_cache.size()) {
    long max_delay = delay;
    for (auto hc : higher_cache) {
      auto result = hc->invalidate(addr);
      if (result.second) {
        max_delay = max(max_delay, delay + result.first * 2);
      } else {
        max_delay = max(max_delay, delay + result.first);
      }
      dirty = dirty || line->dirty || result.second;
    }
    delay = max_delay;
  } else {
    dirty = line->dirty;
  }
  return make_pair(delay, dirty);
}

void Cache::evict(std::list<Line>* lines,
    std::list<Line>::iterator victim) {
  debug("level %d miss evict victim %lx", int(level), victim->addr);
  cache_eviction++;

  long addr = victim->addr;
  long invalidate_time = 0;
  bool dirty = victim->dirty;

  // First invalidate the victim line in higher level.
  if (higher_cache.size()) {
    for (auto hc : higher_cache) {
      auto result = hc->invalidate(addr);
      invalidate_time = max(invalidate_time,
          result.first + (result.second ? latency_each[int(level)] : 0));
      dirty = dirty || result.second || victim->dirty;
    }
  }

  debug("invalidate delay: %ld, dirty: %s", invalidate_time,
      dirty ? "true" : "false");

  if (!is_last_level) {
    // not LLC eviction
    assert(lower_cache != nullptr);
    lower_cache->evictline(addr, dirty);
  } else {
    // LLC eviction
    if (dirty) {
      Request write_req(addr, Request::Type::WRITE);
      cachesys->wait_list.push_back(make_pair(
          cachesys->clk + invalidate_time + latency[int(level)],
          write_req));

      debug("inject one write request to memory system "
          "addr %lx, invalidate time %ld, issue time %ld",
          write_req.addr, invalidate_time,
          cachesys->clk + invalidate_time + latency[int(level)]);
    }
  }

  lines->erase(victim);
}

std::list<Cache::Line>::iterator Cache::allocate_line(
    std::list<Line>& lines, long addr) {
  // See if an eviction is needed
  if (need_eviction(lines, addr)) {
    // Get victim.
    // The first one might still be locked due to reorder in MC
    auto victim = find_if(lines.begin(), lines.end(),
        [this](Line line) {
          bool check = !line.lock;
          if (!is_first_level) {
            for (auto hc : higher_cache) {
              if(!check) {
                return check;
              }
              check = check && hc->check_unlock(line.addr);
            }
          }
          return check;
        });
    if (victim == lines.end()) {
      return victim;  // doesn't exist a line that's already unlocked in each level
    }
    assert(victim != lines.end());
    evict(&lines, victim);
  }

  // Allocate newline, with lock bit on and dirty bit off
  lines.push_back(Line(addr, get_tag(addr)));
  auto last_element = lines.end();
  --last_element;
  return last_element;
}

bool Cache::is_hit(std::list<Line>& lines, long addr,
    std::list<Line>::iterator* pos_ptr) {
  auto pos = find_if(lines.begin(), lines.end(),
      [addr, this](Line l){return (l.tag == get_tag(addr));});
  *pos_ptr = pos;
  if (pos == lines.end()) {
    return false;
  }
  return !pos->lock;
}

void Cache::concatlower(Cache* lower) {
  lower_cache = lower;
  assert(lower != nullptr);
  lower->higher_cache.push_back(this);
};

bool Cache::need_eviction(const std::list<Line>& lines, long addr) {
  if (find_if(lines.begin(), lines.end(),
      [addr, this](Line l){
        return (get_tag(addr) == l.tag);})
      != lines.end()) {
    // Due to MSHR, the program can't reach here. Just for checking
    assert(false);
  } else {
    if (lines.size() < assoc) {
      return false;
    } else {
      return true;
    }
  }
}

void Cache::callback(Request& req) {
  debug("level %d", int(level));

  auto it = find_if(mshr_entries.begin(), mshr_entries.end(),
      [&req, this](std::pair<long, std::list<Line>::iterator> mshr_entry) {
        return (align(mshr_entry.first) == align(req.addr));
      });

  if (it != mshr_entries.end()) {
    it->second->lock = false;
    mshr_entries.erase(it);
  }

  if (higher_cache.size()) {
    for (auto hc : higher_cache) {
      hc->callback(req);
    }
  }
}

void CacheSystem::tick() {
  debug("clk %ld", clk);

  ++clk;

  // Sends ready waiting request to memory
  auto it = wait_list.begin();
  while (it != wait_list.end() && clk >= it->first) {
    if (!send_memory(it->second)) {
      ++it;
    } else {

      debug("complete req: addr %lx", (it->second).addr);

      it = wait_list.erase(it);
    }
  }

  // hit request callback
  it = hit_list.begin();
  while (it != hit_list.end()) {
    if (clk >= it->first) {
      it->second.callback(it->second);

      debug("finish hit: addr %lx", (it->second).addr);

      it = hit_list.erase(it);
    } else {
      ++it;
    }
  }
}

} // namespace ramulator
<commit_msg>fix stat print: only print non zero cache stat<commit_after>#include "Cache.h"

#ifndef DEBUG_CACHE
#define debug(...)
#else
#define debug(...) do { \
          printf("\033[36m[DEBUG] %s ", __FUNCTION__); \
          printf(__VA_ARGS__); \
          printf("\033[0m\n"); \
      } while (0)
#endif

namespace ramulator
{

Cache::Cache(int size, int assoc, int block_size,
    int mshr_entry_num, Level level,
    std::shared_ptr<CacheSystem> cachesys):
    level(level), cachesys(cachesys), higher_cache(0),
    lower_cache(nullptr), size(size), assoc(assoc),
    block_size(block_size), mshr_entry_num(mshr_entry_num) {

  debug("level %d size %d assoc %d block_size %d\n",
      int(level), size, assoc, block_size);

  if (level == Level::L1) {
    level_string = "L1";
  } else if (level == Level::L2) {
    level_string = "L2";
  } else if (level == Level::L3) {
    level_string = "L3";
  }

  is_first_level = (level == cachesys->first_level);
  is_last_level = (level == cachesys->last_level);

  // Check size, block size and assoc are 2^N
  assert((size & (size - 1)) == 0);
  assert((block_size & (block_size - 1)) == 0);
  assert((assoc & (assoc - 1)) == 0);
  assert(size >= block_size);

  // Initialize cache configuration
  block_num = size / (block_size * assoc);
  index_mask = block_num - 1;
  index_offset = calc_log2(block_size);
  tag_offset = calc_log2(block_num) + index_offset;

  debug("index_offset %d", index_offset);
  debug("index_mask 0x%x", index_mask);
  debug("tag_offset %d", tag_offset);

  // regStats
  cache_read_miss.name(level_string + string("_cache_read_miss"))
                 .desc("cache read miss count")
                 .precision(0)
                 .flags(Stats::nozero)
                 ;

  cache_write_miss.name(level_string + string("_cache_write_miss"))
                  .desc("cache write miss count")
                  .precision(0)
                  .flags(Stats::nozero)
                  ;

  cache_total_miss.name(level_string + string("_cache_total_miss"))
                  .desc("cache total miss count")
                  .precision(0)
                  .flags(Stats::nozero)
                  ;

  cache_eviction.name(level_string + string("_cache_eviction"))
                .desc("number of evict from this level to lower level")
                .precision(0)
                .flags(Stats::nozero)
                ;

  cache_read_access.name(level_string + string("_cache_read_access"))
                  .desc("cache read access count")
                  .precision(0)
                  .flags(Stats::nozero)
                  ;

  cache_write_access.name(level_string + string("_cache_write_access"))
                    .desc("cache write access count")
                    .precision(0)
                    .flags(Stats::nozero)
                    ;

  cache_total_access.name(level_string + string("_cache_total_access"))
                    .desc("cache total access count")
                    .precision(0)
                    .flags(Stats::nozero)
                    ;

  cache_mshr_hit.name(level_string + string("_cache_mshr_hit"))
                .desc("cache mshr hit count")
                .precision(0)
                .flags(Stats::nozero)
                ;
  cache_mshr_unavailable.name(level_string + string("_cache_mshr_unavailable"))
                         .desc("cache mshr not available count")
                         .precision(0)
                         .flags(Stats::nozero)
                         ;
  cache_set_unavailable.name(level_string + string("_cache_set_unavailable"))
                         .desc("cache set not available")
                         .precision(0)
                         .flags(Stats::nozero)
                         ;
}

bool Cache::send(Request req) {
  debug("level %d req.addr %lx req.type %d, index %d, tag %ld",
      int(level), req.addr, int(req.type), get_index(req.addr),
      get_tag(req.addr));

  cache_total_access++;
  if (req.type == Request::Type::WRITE) {
    cache_write_access++;
  } else {
    assert(req.type == Request::Type::READ);
    cache_read_access++;
  }
  // If there isn't a set, create it.
  auto& lines = get_lines(req.addr);
  std::list<Line>::iterator line;

  if (is_hit(lines, req.addr, &line)) {
    lines.push_back(Line(req.addr, get_tag(req.addr), false,
        line->dirty || (req.type == Request::Type::WRITE)));
    lines.erase(line);
    cachesys->hit_list.push_back(
        make_pair(cachesys->clk + latency[int(level)], req));

    debug("hit, update timestamp %ld", cachesys->clk);
    debug("hit finish time %ld",
        cachesys->clk + latency[int(level)]);

    return true;

  } else {
    debug("miss @level %d", int(level));
    cache_total_miss++;
    if (req.type == Request::Type::WRITE) {
      cache_write_miss++;
    } else {
      assert(req.type == Request::Type::READ);
      cache_read_miss++;
    }

    // The dirty bit will be set if this is a write request and @L1
    bool dirty = (req.type == Request::Type::WRITE);

    // Modify the type of the request to lower level
    if (req.type == Request::Type::WRITE) {
      req.type = Request::Type::READ;
    }

    // Look it up in MSHR entries
    assert(req.type == Request::Type::READ);
    auto mshr = hit_mshr(req.addr);
    if (mshr != mshr_entries.end()) {
      debug("hit mshr");
      cache_mshr_hit++;
      mshr->second->dirty = dirty || mshr->second->dirty;
      return true;
    }

    // All requests come to this stage will be READ, so they
    // should be recorded in MSHR entries.
    if (mshr_entries.size() == mshr_entry_num) {
      // When no MSHR entries available, the miss request
      // is stalling.
      cache_mshr_unavailable++;
      debug("no mshr entry available");
      return false;
    }

    // Check whether there is a line available
    if (all_sets_locked(lines)) {
      cache_set_unavailable++;
      return false;
    }

    auto newline = allocate_line(lines, req.addr);
    if (newline == lines.end()) {
      return false;
    }

    newline->dirty = dirty;

    // Add to MSHR entries
    mshr_entries.push_back(make_pair(req.addr, newline));

    // Send the request to next level;
    if (!is_last_level) {
      lower_cache->send(req);
    } else {
      cachesys->wait_list.push_back(
          make_pair(cachesys->clk + latency[int(level)], req));
    }
    return true;
  }
}

void Cache::evictline(long addr, bool dirty) {

  auto it = cache_lines.find(get_index(addr));
  assert(it != cache_lines.end()); // check inclusive cache
  auto& lines = it->second;
  auto line = find_if(lines.begin(), lines.end(),
      [addr, this](Line l){return (l.tag == get_tag(addr));});

  assert(line != lines.end());
  // Update LRU queue. The dirty bit will be set if the dirty
  // bit inherited from higher level(s) is set.
  lines.push_back(Line(addr, get_tag(addr), false,
      dirty || line->dirty));
  lines.erase(line);
}

std::pair<long, bool> Cache::invalidate(long addr) {
  long delay = latency_each[int(level)];
  bool dirty = false;

  auto& lines = get_lines(addr);
  if (lines.size() == 0) {
    // The line of this address doesn't exist.
    return make_pair(0, false);
  }
  auto line = find_if(lines.begin(), lines.end(),
      [addr, this](Line l){return (l.tag == get_tag(addr));});

  // If the line is in this level cache, then erase it from
  // the buffer.
  if (line != lines.end()) {
    assert(!line->lock);
    debug("invalidate %lx @ level %d", addr, int(level));
    lines.erase(line);
  } else {
    // If it's not in current level, then no need to go up.
    return make_pair(delay, false);
  }

  if (higher_cache.size()) {
    long max_delay = delay;
    for (auto hc : higher_cache) {
      auto result = hc->invalidate(addr);
      if (result.second) {
        max_delay = max(max_delay, delay + result.first * 2);
      } else {
        max_delay = max(max_delay, delay + result.first);
      }
      dirty = dirty || line->dirty || result.second;
    }
    delay = max_delay;
  } else {
    dirty = line->dirty;
  }
  return make_pair(delay, dirty);
}

void Cache::evict(std::list<Line>* lines,
    std::list<Line>::iterator victim) {
  debug("level %d miss evict victim %lx", int(level), victim->addr);
  cache_eviction++;

  long addr = victim->addr;
  long invalidate_time = 0;
  bool dirty = victim->dirty;

  // First invalidate the victim line in higher level.
  if (higher_cache.size()) {
    for (auto hc : higher_cache) {
      auto result = hc->invalidate(addr);
      invalidate_time = max(invalidate_time,
          result.first + (result.second ? latency_each[int(level)] : 0));
      dirty = dirty || result.second || victim->dirty;
    }
  }

  debug("invalidate delay: %ld, dirty: %s", invalidate_time,
      dirty ? "true" : "false");

  if (!is_last_level) {
    // not LLC eviction
    assert(lower_cache != nullptr);
    lower_cache->evictline(addr, dirty);
  } else {
    // LLC eviction
    if (dirty) {
      Request write_req(addr, Request::Type::WRITE);
      cachesys->wait_list.push_back(make_pair(
          cachesys->clk + invalidate_time + latency[int(level)],
          write_req));

      debug("inject one write request to memory system "
          "addr %lx, invalidate time %ld, issue time %ld",
          write_req.addr, invalidate_time,
          cachesys->clk + invalidate_time + latency[int(level)]);
    }
  }

  lines->erase(victim);
}

std::list<Cache::Line>::iterator Cache::allocate_line(
    std::list<Line>& lines, long addr) {
  // See if an eviction is needed
  if (need_eviction(lines, addr)) {
    // Get victim.
    // The first one might still be locked due to reorder in MC
    auto victim = find_if(lines.begin(), lines.end(),
        [this](Line line) {
          bool check = !line.lock;
          if (!is_first_level) {
            for (auto hc : higher_cache) {
              if(!check) {
                return check;
              }
              check = check && hc->check_unlock(line.addr);
            }
          }
          return check;
        });
    if (victim == lines.end()) {
      return victim;  // doesn't exist a line that's already unlocked in each level
    }
    assert(victim != lines.end());
    evict(&lines, victim);
  }

  // Allocate newline, with lock bit on and dirty bit off
  lines.push_back(Line(addr, get_tag(addr)));
  auto last_element = lines.end();
  --last_element;
  return last_element;
}

bool Cache::is_hit(std::list<Line>& lines, long addr,
    std::list<Line>::iterator* pos_ptr) {
  auto pos = find_if(lines.begin(), lines.end(),
      [addr, this](Line l){return (l.tag == get_tag(addr));});
  *pos_ptr = pos;
  if (pos == lines.end()) {
    return false;
  }
  return !pos->lock;
}

void Cache::concatlower(Cache* lower) {
  lower_cache = lower;
  assert(lower != nullptr);
  lower->higher_cache.push_back(this);
};

bool Cache::need_eviction(const std::list<Line>& lines, long addr) {
  if (find_if(lines.begin(), lines.end(),
      [addr, this](Line l){
        return (get_tag(addr) == l.tag);})
      != lines.end()) {
    // Due to MSHR, the program can't reach here. Just for checking
    assert(false);
  } else {
    if (lines.size() < assoc) {
      return false;
    } else {
      return true;
    }
  }
}

void Cache::callback(Request& req) {
  debug("level %d", int(level));

  auto it = find_if(mshr_entries.begin(), mshr_entries.end(),
      [&req, this](std::pair<long, std::list<Line>::iterator> mshr_entry) {
        return (align(mshr_entry.first) == align(req.addr));
      });

  if (it != mshr_entries.end()) {
    it->second->lock = false;
    mshr_entries.erase(it);
  }

  if (higher_cache.size()) {
    for (auto hc : higher_cache) {
      hc->callback(req);
    }
  }
}

void CacheSystem::tick() {
  debug("clk %ld", clk);

  ++clk;

  // Sends ready waiting request to memory
  auto it = wait_list.begin();
  while (it != wait_list.end() && clk >= it->first) {
    if (!send_memory(it->second)) {
      ++it;
    } else {

      debug("complete req: addr %lx", (it->second).addr);

      it = wait_list.erase(it);
    }
  }

  // hit request callback
  it = hit_list.begin();
  while (it != hit_list.end()) {
    if (clk >= it->first) {
      it->second.callback(it->second);

      debug("finish hit: addr %lx", (it->second).addr);

      it = hit_list.erase(it);
    } else {
      ++it;
    }
  }
}

} // namespace ramulator
<|endoftext|>


<commit_before>// testLog4CPP.cpp : Derived from testCategory.cpp
//
#include "log4cpp/Portability.hh"
#ifdef LOG4CPP_HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "log4cpp/Category.hh"
#include "log4cpp/Appender.hh"
#include "log4cpp/OstreamAppender.hh"
#include "log4cpp/FileAppender.hh"
#include "log4cpp/Layout.hh"
#include "log4cpp/BasicLayout.hh"
#include "log4cpp/Priority.hh"
#include "log4cpp/NDC.hh"
#include "log4cpp/PatternLayout.hh"

double calcPi()
{
  double denominator = 3.0;
  double retVal = 4.0;
  long i;
  for (i = 0; i < 50000000l; i++)
    {
      retVal = retVal - (4.0 / denominator);
      denominator += 2.0;
      retVal = retVal + (4.0 /denominator);
      denominator += 2.0;
    }
  return retVal;
}

int main(int argc, char* argv[])
{
    log4cpp::Appender* appender =
        new log4cpp::OstreamAppender("default", &std::cout);

    log4cpp::Layout* layout = new log4cpp::PatternLayout();
	bool success = ((log4cpp::PatternLayout *)layout)->setConversionPattern("%% %r %c:%d (%R) [%p] %x %m %% (%u) %n");
	if (!success)
	{
		std::cout << "Problem" << std::endl;
		return -1;
	}
    appender->setLayout(layout);

    log4cpp::Category& root = log4cpp::Category::getRoot();
    root.setAppender(appender);
       root.setPriority(log4cpp::Priority::ERROR);

    log4cpp::Category& sub1 =
        log4cpp::Category::getInstance(std::string("sub1"));

    log4cpp::Category& sub2 =
        log4cpp::Category::getInstance(std::string("sub1.sub2"));

/*    std::cout << " root priority = " << root.getPriority() << std::endl;
    std::cout << " sub1 priority = " << sub1.getPriority() << std::endl;
    std::cout << " sub2 priority = " << sub2.getPriority() << std::endl;*/

    root.error("root error");
    root.warn("root warn");
    sub1.error("sub1 error");
    sub1.warn("sub1 warn");

    calcPi();

    sub2.error("sub2 error");
    sub2.warn("sub2 warn");

       sub1.setPriority(log4cpp::Priority::INFO);
    /*std::cout << " root priority = " << root.getPriority() << std::endl;
    std::cout << " sub1 priority = " << sub1.getPriority() << std::endl;
    std::cout << " sub2 priority = " << sub2.getPriority() << std::endl;*/

//    std::cout << "priority info" << std::endl;
    root.error("root error");
    root.warn("root warn");
    sub1.error("sub1 error");
    sub1.warn("sub1 warn");

#ifdef WIN32
	Sleep(3000);
#else
	sleep(3);
#endif

    sub2.error("sub2 error");
    sub2.warn("sub2 warn");
    sub2.error("%s %s %d", "test", "vform", 123);
    sub2.warnStream() << "streamed warn";

    sub2 << log4cpp::Priority::WARN << "warn2.." << "..warn3..value=" << 0 <<
        log4cpp::CategoryStream::ENDLINE << "..warn4";

    log4cpp::Category::shutdown();

    return 0;
}

<commit_msg>included '%r' in test pattern.<commit_after>// testLog4CPP.cpp : Derived from testCategory.cpp
//
#include "log4cpp/Portability.hh"
#ifdef LOG4CPP_HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "log4cpp/Category.hh"
#include "log4cpp/Appender.hh"
#include "log4cpp/OstreamAppender.hh"
#include "log4cpp/FileAppender.hh"
#include "log4cpp/Layout.hh"
#include "log4cpp/BasicLayout.hh"
#include "log4cpp/Priority.hh"
#include "log4cpp/NDC.hh"
#include "log4cpp/PatternLayout.hh"

double calcPi()
{
  double denominator = 3.0;
  double retVal = 4.0;
  long i;
  for (i = 0; i < 50000000l; i++)
    {
      retVal = retVal - (4.0 / denominator);
      denominator += 2.0;
      retVal = retVal + (4.0 /denominator);
      denominator += 2.0;
    }
  return retVal;
}

int main(int argc, char* argv[])
{
    log4cpp::Appender* appender =
        new log4cpp::OstreamAppender("default", &std::cout);

    log4cpp::Layout* layout = new log4cpp::PatternLayout();
	bool success = ((log4cpp::PatternLayout *)layout)->setConversionPattern("%% %r %c:%d (%R / %r) [%p] %x %m %% (%u) %n");
	if (!success)
	{
		std::cout << "Problem" << std::endl;
		return -1;
	}
    appender->setLayout(layout);

    log4cpp::Category& root = log4cpp::Category::getRoot();
    root.setAppender(appender);
       root.setPriority(log4cpp::Priority::ERROR);

    log4cpp::Category& sub1 =
        log4cpp::Category::getInstance(std::string("sub1"));

    log4cpp::Category& sub2 =
        log4cpp::Category::getInstance(std::string("sub1.sub2"));

/*    std::cout << " root priority = " << root.getPriority() << std::endl;
    std::cout << " sub1 priority = " << sub1.getPriority() << std::endl;
    std::cout << " sub2 priority = " << sub2.getPriority() << std::endl;*/

    root.error("root error");
    root.warn("root warn");
    sub1.error("sub1 error");
    sub1.warn("sub1 warn");

    calcPi();

    sub2.error("sub2 error");
    sub2.warn("sub2 warn");

       sub1.setPriority(log4cpp::Priority::INFO);
    /*std::cout << " root priority = " << root.getPriority() << std::endl;
    std::cout << " sub1 priority = " << sub1.getPriority() << std::endl;
    std::cout << " sub2 priority = " << sub2.getPriority() << std::endl;*/

//    std::cout << "priority info" << std::endl;
    root.error("root error");
    root.warn("root warn");
    sub1.error("sub1 error");
    sub1.warn("sub1 warn");

#ifdef WIN32
	Sleep(3000);
#else
	sleep(3);
#endif

    sub2.error("sub2 error");
    sub2.warn("sub2 warn");
    sub2.error("%s %s %d", "test", "vform", 123);
    sub2.warnStream() << "streamed warn";

    sub2 << log4cpp::Priority::WARN << "warn2.." << "..warn3..value=" << 0 <<
        log4cpp::CategoryStream::ENDLINE << "..warn4";

    log4cpp::Category::shutdown();

    return 0;
}

<|endoftext|>


<commit_before>#include <numpy_eigen/boost_python_headers.hpp>
#include <sm/MatrixArchive.hpp>

// void getMatrix(std::string const & matrixName, Eigen::MatrixXd & outMatrix) const;
Eigen::MatrixXd getMatrix(const sm::MatrixArchive * ma, std::string const & matrixName)
{
  Eigen::MatrixXd M;
  ma->getMatrix(matrixName,M);
  return M;
}

// void getVector(std::string const & vectorName, Eigen::VectorXd & outVector) const;
Eigen::VectorXd getVector(const sm::MatrixArchive * ma, const std::string & vectorName)
{
  Eigen::VectorXd V;
  ma->getVector(vectorName,V);
  return V;
}
// void getScalar(std::string const & scalarName, double & outScalar) const
double getScalar(const sm::MatrixArchive * ma, const std::string & vectorName)
{
  double d;
  ma->getScalar(vectorName,d);
  return d;
}

boost::python::list getNameList(const sm::MatrixArchive * ma)
{
  boost::python::list list;
  sm::MatrixArchive::matrix_map_t::const_iterator it = ma->begin();
  for( ; it != ma->end(); it++)
    {
      list.append(it->first);
    }
  return list;
}

boost::python::dict asDict(const sm::MatrixArchive * ma)
{
  boost::python::dict dict;
  sm::MatrixArchive::matrix_map_t::const_iterator it = ma->begin();
  for( ; it != ma->end(); it++)
    {
      dict[it->first] = it->second;
    }
  return dict;
}

void exportMatrixArchive()
{
  using namespace boost::python;
  using namespace sm;

  //void clear();
  void (MatrixArchive::*clearAll)(void) = &MatrixArchive::clear;
  //void clear(std::string const & entryName);
  void (MatrixArchive::*clearOne)(std::string const &) = &MatrixArchive::clear;

  // void load(std::string const & asaFilePath);
  void (MatrixArchive::*loadArchive)(std::string const &) = &MatrixArchive::load;
  // void save(std::string const & asaFilePath);
  void (MatrixArchive::*saveArchive)(std::string const &)const = &MatrixArchive::save;

  // void append(std::string const & asaFilePath) const;
  void (MatrixArchive::*appendArchive)(std::string const &)const = &MatrixArchive::append;

  // void setScalar(std::string const & scalarName, double scalar);

  // bool isSystemLittleEndian() const;

  // size_t maxNameSize();

  class_<MatrixArchive>("MatrixArchive",init<>())
    .def("clear",clearAll)
    .def("clearOne",clearOne)
    .def("size",&MatrixArchive::size)
    .def("load",loadArchive)
    .def("save",saveArchive)
    .def("append",appendArchive)
    .def("setMatrix",&MatrixArchive::setMatrixXd)
    .def("setVector",&MatrixArchive::setVectorXd)
    .def("setScalar",&MatrixArchive::setScalar)
    .def("isSystemLittleEndian",&MatrixArchive::isSystemLittleEndian)
    .def("maxNameSize",&MatrixArchive::maxNameSize)
    .def("getMatrix",&getMatrix)
    .def("getVector",&getVector)
    .def("getScalar",&getScalar)
    .def("getNameList",&getNameList)
    .def("asDict",&asDict)
    ;

}
<commit_msg>exported the matrix archive strings interface to python<commit_after>#include <numpy_eigen/boost_python_headers.hpp>
#include <sm/MatrixArchive.hpp>

// std::string getString(std::string const & stringName) const;
std::string getString(const sm::MatrixArchive * ma, std::string const & stringName)
{
  return ma->getString(stringName);
}

// void getMatrix(std::string const & matrixName) const;
Eigen::MatrixXd getMatrix(const sm::MatrixArchive * ma, std::string const & matrixName)
{
  Eigen::MatrixXd M;
  ma->getMatrix(matrixName,M);
  return M;
}

// void getVector(std::string const & vectorName, Eigen::VectorXd & outVector) const;
Eigen::VectorXd getVector(const sm::MatrixArchive * ma, const std::string & vectorName)
{
  Eigen::VectorXd V;
  ma->getVector(vectorName,V);
  return V;
}
// void getScalar(std::string const & scalarName, double & outScalar) const
double getScalar(const sm::MatrixArchive * ma, const std::string & vectorName)
{
  double d;
  ma->getScalar(vectorName,d);
  return d;
}

boost::python::list getNameList(const sm::MatrixArchive * ma)
{
  boost::python::list list;
  sm::MatrixArchive::matrix_map_t::const_iterator it = ma->begin();
  for( ; it != ma->end(); it++)
    {
      list.append(it->first);
    }
  return list;
}

boost::python::dict asDict(const sm::MatrixArchive * ma)
{
  boost::python::dict dict;
  sm::MatrixArchive::matrix_map_t::const_iterator it = ma->begin();
  for( ; it != ma->end(); it++)
    {
      dict[it->first] = it->second;
    }
  return dict;
}

boost::python::dict stringsAsDict(const sm::MatrixArchive * ma)
{
  boost::python::dict dict;
  auto & strings = ma->getStrings();
  for(auto it = strings.begin() ; it != strings.end(); it++)
    {
      dict[it->first] = it->second;
    }
  return dict;
}

void exportMatrixArchive()
{
  using namespace boost::python;
  using namespace sm;

  //void clear();
  void (MatrixArchive::*clearAll)(void) = &MatrixArchive::clear;
  //void clear(std::string const & entryName);
  void (MatrixArchive::*clearOne)(std::string const &) = &MatrixArchive::clear;

  // void load(std::string const & asaFilePath);
  void (MatrixArchive::*loadArchive)(std::string const &) = &MatrixArchive::load;
  // void save(std::string const & asaFilePath);
  void (MatrixArchive::*saveArchive)(std::string const &)const = &MatrixArchive::save;

  // void append(std::string const & asaFilePath) const;
  void (MatrixArchive::*appendArchive)(std::string const &)const = &MatrixArchive::append;

  // void setScalar(std::string const & scalarName, double scalar);

  // bool isSystemLittleEndian() const;

  // size_t maxNameSize();

  class_<MatrixArchive>("MatrixArchive",init<>())
    .def("clear",clearAll)
    .def("clearOne",clearOne)
    .def("size",&MatrixArchive::size)
    .def("load",loadArchive)
    .def("save",saveArchive)
    .def("append",appendArchive)
    .def("setMatrix",&MatrixArchive::setMatrixXd)
    .def("setVector",&MatrixArchive::setVectorXd)
    .def("setScalar",&MatrixArchive::setScalar)
    .def("isSystemLittleEndian",&MatrixArchive::isSystemLittleEndian)
    .def("maxNameSize",&MatrixArchive::maxNameSize)
    .def("getMatrix",&getMatrix)
    .def("getVector",&getVector)
    .def("getScalar",&getScalar)
    .def("getString", getString)
    .def("setString", &MatrixArchive::setString)
    .def("getNameList",&getNameList)
    .def("asDict",&asDict)
    .def("stringsAsDict",&stringsAsDict)
    ;

}
<|endoftext|>


<commit_before><commit_msg>test: fix error detection in the test.cpp program of typekit_opaque<commit_after><|endoftext|>


<commit_before>#pragma once

#include <vector>
#include <map>
#include <string>
#include <memory>
#include <functional>

#include <boost/variant.hpp>

namespace mstch {

struct config {
  static std::function<std::string(const std::string&)> escape;
};

namespace internal {

template<class N>
class object_t {
 public:
  const N& at(const std::string& name) const {
    cache[name] = (methods.at(name))();
    return cache[name];
  }

  bool has(const std::string name) const {
    return methods.count(name) != 0;
  }

 protected:
  template<class S>
  void register_methods(S* s, std::map<std::string,N(S::*)()> methods) {
    for(auto& item: methods)
      this->methods.insert({item.first, std::bind(item.second, s)});
  }

  // This is a modification to the original mstch implementation that allows
  // registration of non-member (static or global) functions on mstch::object.
  void register_lambda(std::string name, std::function<N()> func) {
    this->methods[name] = func;
  }

 private:
  std::map<std::string, std::function<N()>> methods;
  mutable std::map<std::string, N> cache;
};

template<class T, class N>
class is_fun {
 private:
  using not_fun = char;
  using fun_without_args = char[2];
  using fun_with_args = char[3];
  template <typename U, U> struct really_has;
  template <typename C> static fun_without_args& test(
      really_has<N(C::*)() const, &C::operator()>*);
  template <typename C> static fun_with_args& test(
      really_has<N(C::*)(const std::string&) const,
      &C::operator()>*);
  template <typename> static not_fun& test(...);

 public:
  static bool const no_args = sizeof(test<T>(0)) == sizeof(fun_without_args);
  static bool const has_args = sizeof(test<T>(0)) == sizeof(fun_with_args);
};

template<class N>
using node_renderer = std::function<std::string(const N& n)>;

template<class N>
class lambda_t {
 public:
  template<class F>
  lambda_t(F f, typename std::enable_if<is_fun<F, N>::no_args>::type* = 0):
      fun([f](node_renderer<N> renderer, const std::string&) {
        return renderer(f());
      })
  {
  }

  template<class F>
  lambda_t(F f, typename std::enable_if<is_fun<F, N>::has_args>::type* = 0):
      fun([f](node_renderer<N> renderer, const std::string& text) {
        return renderer(f(text));
      })
  {
  }

  std::string operator()(node_renderer<N> renderer,
      const std::string& text = "") const
  {
    return fun(renderer, text);
  }

 private:
  std::function<std::string(node_renderer<N> renderer, const std::string&)> fun;
};

}

using node = boost::make_recursive_variant<
    std::nullptr_t, std::string, int, double, bool,
    internal::lambda_t<boost::recursive_variant_>,
    std::shared_ptr<internal::object_t<boost::recursive_variant_>>,
    std::map<const std::string, boost::recursive_variant_>,
    std::vector<boost::recursive_variant_>>::type;
using object = internal::object_t<node>;
using lambda = internal::lambda_t<node>;
using map = std::map<const std::string, node>;
using array = std::vector<node>;

std::string render(
    const std::string& tmplt,
    const node& root,
    const std::map<std::string,std::string>& partials =
        std::map<std::string,std::string>());

}
<commit_msg>Fix inability to override methods (#257)<commit_after>#pragma once

#include <vector>
#include <map>
#include <string>
#include <memory>
#include <functional>

#include <boost/variant.hpp>

namespace mstch {

struct config {
  static std::function<std::string(const std::string&)> escape;
};

namespace internal {

template<class N>
class object_t {
 public:
  const N& at(const std::string& name) const {
    cache[name] = (methods.at(name))();
    return cache[name];
  }

  bool has(const std::string name) const {
    return methods.count(name) != 0;
  }

 protected:
  ////////////////////////////
  // MODIFIED FOR CHIMERA
  ////////////////////////////

  template<class S>
  void register_methods(S* s, std::map<std::string,N(S::*)()> methods) {
    for(auto& item: methods)
      // This is a modification to the original mstch implementation that allows
      // to override methods.
      this->methods[item.first] = std::bind(item.second, s);
  }

  // This is a modification to the original mstch implementation that allows
  // registration of non-member (static or global) functions on mstch::object.
  void register_lambda(std::string name, std::function<N()> func) {
    this->methods[name] = func;
  }

  ////////////////////////////
  // END MODIFIED FOR CHIMERA
  ////////////////////////////

 private:
  std::map<std::string, std::function<N()>> methods;
  mutable std::map<std::string, N> cache;
};

template<class T, class N>
class is_fun {
 private:
  using not_fun = char;
  using fun_without_args = char[2];
  using fun_with_args = char[3];
  template <typename U, U> struct really_has;
  template <typename C> static fun_without_args& test(
      really_has<N(C::*)() const, &C::operator()>*);
  template <typename C> static fun_with_args& test(
      really_has<N(C::*)(const std::string&) const,
      &C::operator()>*);
  template <typename> static not_fun& test(...);

 public:
  static bool const no_args = sizeof(test<T>(0)) == sizeof(fun_without_args);
  static bool const has_args = sizeof(test<T>(0)) == sizeof(fun_with_args);
};

template<class N>
using node_renderer = std::function<std::string(const N& n)>;

template<class N>
class lambda_t {
 public:
  template<class F>
  lambda_t(F f, typename std::enable_if<is_fun<F, N>::no_args>::type* = 0):
      fun([f](node_renderer<N> renderer, const std::string&) {
        return renderer(f());
      })
  {
  }

  template<class F>
  lambda_t(F f, typename std::enable_if<is_fun<F, N>::has_args>::type* = 0):
      fun([f](node_renderer<N> renderer, const std::string& text) {
        return renderer(f(text));
      })
  {
  }

  std::string operator()(node_renderer<N> renderer,
      const std::string& text = "") const
  {
    return fun(renderer, text);
  }

 private:
  std::function<std::string(node_renderer<N> renderer, const std::string&)> fun;
};

}

using node = boost::make_recursive_variant<
    std::nullptr_t, std::string, int, double, bool,
    internal::lambda_t<boost::recursive_variant_>,
    std::shared_ptr<internal::object_t<boost::recursive_variant_>>,
    std::map<const std::string, boost::recursive_variant_>,
    std::vector<boost::recursive_variant_>>::type;
using object = internal::object_t<node>;
using lambda = internal::lambda_t<node>;
using map = std::map<const std::string, node>;
using array = std::vector<node>;

std::string render(
    const std::string& tmplt,
    const node& root,
    const std::map<std::string,std::string>& partials =
        std::map<std::string,std::string>());

}
<|endoftext|>


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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkSimplexMeshGeometry.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

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

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

#include "itkSimplexMeshGeometry.h"
#include "itkNumericTraits.h"

namespace itk
{

SimplexMeshGeometry
::SimplexMeshGeometry()
{
  double c = 1.0/3.0;
  PointType p;
  p.Fill(0.0);

  pos.Fill(0);
  oldPos.Fill(0);
  referenceMetrics.Fill(c);
  eps.Fill(c);
  normal.Fill(0);
  externalForce.Fill(0);
  internalForce.Fill(0);
  circleRadius = 0;
  circleCenter.Fill(0);
  sphereRadius = 0;
  distance = 0;
  phi = 0;

  neighborIndices.Fill((unsigned long) NumericTraits<unsigned long>::max);
  neighbors.Fill(p);
  meanCurvature = c;
}

SimplexMeshGeometry
::~SimplexMeshGeometry()
{
}

void
SimplexMeshGeometry
::ComputeGeometry()
{
  VectorType b,c,cXb, tmp;

  //compute the circum circle (center and radius)
  b = this->neighbors[2] - this->neighbors[0];
  c = this->neighbors[1] - this->neighbors[0];

  cXb.Set_vnl_vector( cross_3d<double>(c.Get_vnl_vector(),b.Get_vnl_vector()) );

  tmp.Set_vnl_vector( b.GetSquaredNorm() *
                        cross_3d<double>( cXb.Get_vnl_vector(), c.Get_vnl_vector() ) +
                      c.GetSquaredNorm() *
                        cross_3d<double>( b.Get_vnl_vector() , cXb.Get_vnl_vector() ) );

  double cXbSquaredNorm = 2 * cXb.GetSquaredNorm();

  circleRadius = tmp.GetNorm()/(cXbSquaredNorm);
  tmp[0] /= (cXbSquaredNorm);
  tmp[1] /= (cXbSquaredNorm);
  tmp[2] /= (cXbSquaredNorm);
  circleCenter = this->neighbors[0] + tmp;

  // Compute the circum sphere (center and radius) of a point
  VectorType d,dXc,bXd,sphereTmp, denom;

  d = pos - this->neighbors[0];
  dXc.Set_vnl_vector( cross_3d<double>(d.Get_vnl_vector(),c.Get_vnl_vector()) );
  bXd.Set_vnl_vector( cross_3d<double>(b.Get_vnl_vector(),d.Get_vnl_vector()) );

  sphereTmp.Set_vnl_vector( d.GetSquaredNorm()* cXb.Get_vnl_vector() +
                            b.GetSquaredNorm()* dXc.Get_vnl_vector() +
                            c.GetSquaredNorm()* bXd.Get_vnl_vector()
                          );

  double val = 2 * (c[0]*(b[1]*d[2]-b[2]*d[1]) -
                    c[1]*( b[0]*d[2]-b[2]*d[0] ) +
                    c[2]*( b[0]*d[1]-b[1]*d[0] ));

  // fix for points which lay on their neighbors plane
  // necessary ??
  if (val == 0)
    {
    val = 1; //  assert (val != 0 );
    }

  sphereRadius = sphereTmp.GetNorm()/val;

  if (sphereRadius < 0) {
    sphereRadius = -1 * sphereRadius;
  }
}

}  // end namespace itk

<commit_msg>ERR: Fix for CVS version of vxl.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkSimplexMeshGeometry.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

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

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

#include "itkSimplexMeshGeometry.h"
#include "itkNumericTraits.h"

#include <vxl_version.h>
#if VXL_VERSION_DATE_FULL > 20040406
# include <vnl/vnl_cross.h>
# define cross_3d vnl_cross_3d
#endif

namespace itk
{

SimplexMeshGeometry
::SimplexMeshGeometry()
{
  double c = 1.0/3.0;
  PointType p;
  p.Fill(0.0);

  pos.Fill(0);
  oldPos.Fill(0);
  referenceMetrics.Fill(c);
  eps.Fill(c);
  normal.Fill(0);
  externalForce.Fill(0);
  internalForce.Fill(0);
  circleRadius = 0;
  circleCenter.Fill(0);
  sphereRadius = 0;
  distance = 0;
  phi = 0;

  neighborIndices.Fill((unsigned long) NumericTraits<unsigned long>::max);
  neighbors.Fill(p);
  meanCurvature = c;
}

SimplexMeshGeometry
::~SimplexMeshGeometry()
{
}

void
SimplexMeshGeometry
::ComputeGeometry()
{
  VectorType b,c,cXb, tmp;

  //compute the circum circle (center and radius)
  b = this->neighbors[2] - this->neighbors[0];
  c = this->neighbors[1] - this->neighbors[0];

  cXb.Set_vnl_vector( cross_3d<double>(c.Get_vnl_vector(),b.Get_vnl_vector()) );

  tmp.Set_vnl_vector( b.GetSquaredNorm() *
                        cross_3d<double>( cXb.Get_vnl_vector(), c.Get_vnl_vector() ) +
                      c.GetSquaredNorm() *
                        cross_3d<double>( b.Get_vnl_vector() , cXb.Get_vnl_vector() ) );

  double cXbSquaredNorm = 2 * cXb.GetSquaredNorm();

  circleRadius = tmp.GetNorm()/(cXbSquaredNorm);
  tmp[0] /= (cXbSquaredNorm);
  tmp[1] /= (cXbSquaredNorm);
  tmp[2] /= (cXbSquaredNorm);
  circleCenter = this->neighbors[0] + tmp;

  // Compute the circum sphere (center and radius) of a point
  VectorType d,dXc,bXd,sphereTmp, denom;

  d = pos - this->neighbors[0];
  dXc.Set_vnl_vector( cross_3d<double>(d.Get_vnl_vector(),c.Get_vnl_vector()) );
  bXd.Set_vnl_vector( cross_3d<double>(b.Get_vnl_vector(),d.Get_vnl_vector()) );

  sphereTmp.Set_vnl_vector( d.GetSquaredNorm()* cXb.Get_vnl_vector() +
                            b.GetSquaredNorm()* dXc.Get_vnl_vector() +
                            c.GetSquaredNorm()* bXd.Get_vnl_vector()
                          );

  double val = 2 * (c[0]*(b[1]*d[2]-b[2]*d[1]) -
                    c[1]*( b[0]*d[2]-b[2]*d[0] ) +
                    c[2]*( b[0]*d[1]-b[1]*d[0] ));

  // fix for points which lay on their neighbors plane
  // necessary ??
  if (val == 0)
    {
    val = 1; //  assert (val != 0 );
    }

  sphereRadius = sphereTmp.GetNorm()/val;

  if (sphereRadius < 0) {
    sphereRadius = -1 * sphereRadius;
  }
}

}  // end namespace itk

<|endoftext|>


<commit_before>/* Chemfiles, an efficient IO library for chemistry file formats
 * Copyright (C) 2015 Guillaume Fraux
 *
 * 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/
*/
#include <algorithm>

#include "chemfiles/Error.hpp"
#include "chemfiles/Frame.hpp"
#include "chemfiles/Logger.hpp"
using namespace chemfiles;

Frame::Frame() : Frame(0) {}
Frame::Frame(size_t natoms) : Frame(dummy_topology(natoms)) {}

Frame::Frame(const Topology& topology, const UnitCell& cell)
    : step_(0), topology_(topology), cell_(cell) {
    resize(topology_.natoms());
}

size_t Frame::natoms() const {
    assert(positions_.size() == topology_.natoms());
    if (velocities_) {
        assert(positions_.size() == velocities_->size());
    }
    return positions_.size();
}

void Frame::resize(size_t size) {
    topology_.resize(size);
    positions_.resize(size, vector3d(0.0, 0.0, 0.0));
    if (velocities_) {
        velocities_->resize(size, vector3d(0.0, 0.0, 0.0));
    }
}

void Frame::add_velocities() {
    if (!velocities_) {
        velocities_ = Array3D(natoms(), vector3d(0.0, 0.0, 0.0));
    }
}

void Frame::guess_topology() {
    topology_.clear_bonds();
    // This bond guessing algorithm comes from VMD
    double cutoff = 0.833;
    for (size_t i = 0; i < natoms(); i++) {
        auto rad = topology_[i].vdw_radius();
        cutoff = fmax(cutoff, rad);
    }
    cutoff = 1.2 * cutoff;

    for (size_t i = 0; i < natoms(); i++) {
        float irad = topology_[i].vdw_radius();
        if (irad == -1) {
            throw Error("Missing Van der Waals radius for the atom " +
                        topology_[i].name());
        }
        for (size_t j = i + 1; j < natoms(); j++) {
            float jrad = topology_[j].vdw_radius();
            if (jrad == -1) {
                throw Error("Missing Van der Waals radius for the atom " +
                            topology_[j].name());
            }
            double d = norm(cell_.wrap(positions_[i] - positions_[j]));
            if (0.03 < d && d < 0.6 * (irad + jrad) && d < cutoff) {
                topology_.add_bond(i, j);
            }
        }
    }

    auto bonds = topology().bonds();
    auto to_remove = std::vector<Bond>();
    // We need to remove bonds between hydrogen atoms which are bonded more than
    // once
    for (auto& bond : bonds) {
        auto i = bond[0], j = bond[1];
        if (topology_[i].name() != "H") {
            continue;
        }
        if (topology_[j].name() != "H") {
            continue;
        }

        auto nbonds = std::count_if(
            std::begin(bonds), std::end(bonds), [=](const Bond& b) {
                return b[0] == i || b[0] == j || b[1] == i || b[1] == j;
            });
        assert(nbonds >= 1);

        if (nbonds != 1) {
            to_remove.push_back(bond);
        }
    }

    for (auto& bond : to_remove) {
        topology_.remove_bond(bond[0], bond[1]);
    }
}

void Frame::set_topology(const Topology& topology) {
    if (topology.natoms() != positions_.size()) {
        throw APIError("Error: the topology contains " +
                       std::to_string(topology.natoms()) +
                       " atoms, but the frame contains " +
                       std::to_string(positions_.size()) + " atoms.");
    }
    topology_ = topology;
}
<commit_msg>Improve the error message<commit_after>/* Chemfiles, an efficient IO library for chemistry file formats
 * Copyright (C) 2015 Guillaume Fraux
 *
 * 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/
*/
#include <algorithm>

#include "chemfiles/Error.hpp"
#include "chemfiles/Frame.hpp"
#include "chemfiles/Logger.hpp"
using namespace chemfiles;

Frame::Frame() : Frame(0) {}
Frame::Frame(size_t natoms) : Frame(dummy_topology(natoms)) {}

Frame::Frame(const Topology& topology, const UnitCell& cell)
    : step_(0), topology_(topology), cell_(cell) {
    resize(topology_.natoms());
}

size_t Frame::natoms() const {
    assert(positions_.size() == topology_.natoms());
    if (velocities_) {
        assert(positions_.size() == velocities_->size());
    }
    return positions_.size();
}

void Frame::resize(size_t size) {
    topology_.resize(size);
    positions_.resize(size, vector3d(0.0, 0.0, 0.0));
    if (velocities_) {
        velocities_->resize(size, vector3d(0.0, 0.0, 0.0));
    }
}

void Frame::add_velocities() {
    if (!velocities_) {
        velocities_ = Array3D(natoms(), vector3d(0.0, 0.0, 0.0));
    }
}

void Frame::guess_topology() {
    topology_.clear_bonds();
    // This bond guessing algorithm comes from VMD
    double cutoff = 0.833;
    for (size_t i = 0; i < natoms(); i++) {
        auto rad = topology_[i].vdw_radius();
        cutoff = fmax(cutoff, rad);
    }
    cutoff = 1.2 * cutoff;

    for (size_t i = 0; i < natoms(); i++) {
        float irad = topology_[i].vdw_radius();
        if (irad == -1) {
            throw Error("Missing Van der Waals radius for the atom " +
                        topology_[i].name());
        }
        for (size_t j = i + 1; j < natoms(); j++) {
            float jrad = topology_[j].vdw_radius();
            if (jrad == -1) {
                throw Error("Missing Van der Waals radius for the atom " +
                            topology_[j].name());
            }
            double d = norm(cell_.wrap(positions_[i] - positions_[j]));
            if (0.03 < d && d < 0.6 * (irad + jrad) && d < cutoff) {
                topology_.add_bond(i, j);
            }
        }
    }

    auto bonds = topology().bonds();
    auto to_remove = std::vector<Bond>();
    // We need to remove bonds between hydrogen atoms which are bonded more than
    // once
    for (auto& bond : bonds) {
        auto i = bond[0], j = bond[1];
        if (topology_[i].name() != "H") {
            continue;
        }
        if (topology_[j].name() != "H") {
            continue;
        }

        auto nbonds = std::count_if(
            std::begin(bonds), std::end(bonds), [=](const Bond& b) {
                return b[0] == i || b[0] == j || b[1] == i || b[1] == j;
            });
        assert(nbonds >= 1);

        if (nbonds != 1) {
            to_remove.push_back(bond);
        }
    }

    for (auto& bond : to_remove) {
        topology_.remove_bond(bond[0], bond[1]);
    }
}

void Frame::set_topology(const Topology& topology) {
    if (topology.natoms() != positions_.size()) {
        throw APIError("the topology contains " +
                       std::to_string(topology.natoms()) +
                       " atoms, but the frame contains " +
                       std::to_string(positions_.size()) + " atoms.");
    }
    topology_ = topology;
}
<|endoftext|>


<commit_before>#include <iostream>

#include <hdf5.h>

#include <pandora/Group.hpp>

namespace pandora {

Group::Group()
    : h5group()
{}

Group::Group(H5::Group h5group)
    : h5group(h5group)
{}

Group::Group(const Group &group)
    : h5group(group.h5group)
{}

void Group::operator=(const Group &group)
{
  h5group = group.h5group;
}

bool Group::hasAttr(std::string name) const {
  return H5Aexists(h5group.getId(), name.c_str());
}

void Group::removeAttr(std::string name) const {
  h5group.removeAttr(name);
}

//Oh the hacks ;-)

struct TypeSpec
{
  H5::DataType fileType;
  H5::DataType memType;
};

template<typename T> TypeSpec type_klassify() {
  TypeSpec e;
  //FIXME throw runtime exception here
  return e;
}

template<> TypeSpec type_klassify<int>() {
  return {H5::PredType::STD_I32LE, H5::PredType::NATIVE_INT};
}

template<> TypeSpec type_klassify<double>() {
  return {H5::PredType::IEEE_F32LE, H5::PredType::NATIVE_DOUBLE};
}

template<> TypeSpec type_klassify<std::string>() {
  return {H5::PredType::C_S1, H5::PredType::C_S1};
}

template<typename T> class Nyx
{

protected:

  T &value;
  TypeSpec m;

public:

  Nyx(T &val)
      : value(val), m(type_klassify<T>())
  {}

  virtual H5::DataSpace getDataSpace() const {
    return H5::DataSpace();
  }

  virtual H5::DataType getFileType() const {
    return m.fileType;
  }

  virtual H5::DataType getMemType() const {
    return m.memType;
  }

  virtual void writeAttribute(H5::Attribute &attr) {
    attr.write(m.memType, &value);
  }

  virtual void readAttribute(H5::Attribute &attr) {
    attr.read(m.memType, &value);
  }

  virtual ~Nyx() {}

};

template<typename T> class Charon: public Nyx<T>
{
public:
  Charon(T &val)
    : Nyx<T>(val)
  {}
};

template<> class Charon<std::string> : public Nyx<std::string>
{

public:
  Charon(std::string &val)
    : Nyx<std::string>(val)
  {}

  virtual H5::DataType getFileType() const {
    H5::AtomType ftype = H5::PredType::C_S1;
    ftype.setSize(value.length());
    return ftype;
  }

  virtual void writeAttribute(H5::Attribute &attr) {
    H5::StrType memtype = attr.getStrType();
    attr.write(memtype, value);
    //attr.write(m.memType, value); //FIXME This is just a quick hack...
  }

  virtual void readAttribute(H5::Attribute &attr) {
    H5::StrType memtype = attr.getStrType();
    //attr.read(m.memType, value);
    attr.read(memtype, value); //FIXME This is just a quick hack...
  }

  virtual ~Charon() {}
};

template<typename T> void Group::setAttr(std::string name, T value) const {
  H5::Attribute attr;
  Charon<T> charon = Charon<T>(value);

  if (hasAttr(name)) {
    attr = h5group.openAttribute(name);
  } else {
    H5::DataType fileType = charon.getFileType();
    H5::DataSpace fileSpace = charon.getDataSpace();
    attr = h5group.createAttribute(name, fileType, fileSpace);
  }

  charon.writeAttribute(attr);
}

template<typename T> bool Group::getAttr(std::string name, T &value) const {

  if (!hasAttr(name)) {
    return false;
  }

  H5::Attribute attr = h5group.openAttribute(name);
  Charon<T> charon = Charon<T>(value);
  charon.readAttribute(attr);

  return true;
}

template void Group::setAttr<int>(std::string name, int value) const;

template void Group::setAttr<double>(std::string name, double value) const;

template void Group::setAttr<std::string>(std::string name, std::string value) const;

template bool Group::getAttr<int>(std::string name, int &value) const;

template bool Group::getAttr<double>(std::string name, double &value) const;

template bool Group::getAttr<std::string>(std::string name, std::string &value) const;

bool Group::hasObject(std::string name) const {
  hsize_t num = h5group.getNumObjs();
  for (hsize_t i = 0; i < num; i++) {
    if (h5group.getObjnameByIdx(i) == name)
      return true;
  }
  return false;
}

size_t Group::objectCount() const {
  return h5group.getNumObjs();
}

std::string Group::objectName(size_t index) const {
  return h5group.getObjnameByIdx(index);
}

bool Group::hasData(std::string name) const {
  if (hasObject(name)) {
    H5G_stat_t info;
    h5group.getObjinfo(name, info);
    if (info.type == H5G_DATASET) {
      return true;
    }
  }
  return false;
}

void Group::removeData(std::string name) {
  if (hasData(name))
    h5group.unlink(name);
}

H5::DataSet Group::openData(std::string name) const {
  H5::DataSet data = h5group.openDataSet(name);
  return data;
}

bool Group::hasGroup(std::string name) const {
  if (hasObject(name)) {
    H5G_stat_t info;
    h5group.getObjinfo(name, info);
    if (info.type == H5G_GROUP) {
      return true;
    }
  }
  return false;
}

Group Group::openGroup(std::string name, bool create) const {
  Group g;
  if (hasGroup(name)) {
    g = Group(h5group.openGroup(name));
  } else if (create) {
    g = Group(h5group.createGroup(name));
  }
  return g;
}

void Group::removeGroup(std::string name) {
  if (hasGroup(name))
    h5group.unlink(name);
}

bool Group::operator==(const Group &group) const {
  return h5group.getLocId() == group.h5group.getLocId();
}

bool Group::operator!=(const Group &group) const {
  return h5group.getLocId() != group.h5group.getLocId();
}

H5::Group Group::h5Group() const {
  return h5group;
}

Group::~Group() {}

}
<commit_msg>[Group+Charon]: Rework to support boost::multiarray<commit_after>#include <iostream>

#include <hdf5.h>

#include <pandora/Group.hpp>
#include <boost/multi_array.hpp>

namespace pandora {

  //

template<typename T>
struct TypeSpec {

  //const bool is_valid = false; //make compiler cry on unspecified types
  const H5::DataType fileType;
  const H5::DataType memType;
};

template<>
struct TypeSpec<int> {

  const bool is_valid = true;
  const H5::DataType fileType = H5::PredType::STD_I32LE;
  const H5::DataType memType = H5::PredType::NATIVE_INT;
};

template<>
struct TypeSpec<double> {

  const bool is_valid = true;
  const H5::DataType fileType = H5::PredType::IEEE_F64LE;
  const H5::DataType memType = H5::PredType::NATIVE_DOUBLE;
};

template<>
struct TypeSpec<std::string> {

  const bool is_valid = true;
  const H5::DataType fileType = H5::StrType(H5::PredType::C_S1, H5T_VARIABLE);
  const H5::DataType memType = H5::StrType(H5::PredType::C_S1, H5T_VARIABLE);
};

  //**

template<typename T, typename U = T>
class Nyx {
public:
  TypeSpec<U>  m;
  T           &value;
  typedef U base_type;

public:

  Nyx(T &val) : m(TypeSpec<U>()), value(val) {
    assert(m.is_valid);
  }

  virtual H5::DataType getFileType() const { return m.fileType; }
  virtual H5::DataType getMemType() const { return m.memType; }
  virtual H5::DataSpace getDataSpace() const { return H5::DataSpace(); }

  virtual void write(H5::Attribute &attr) {
    attr.write(this->m.memType, getData());
  };

  virtual void read(H5::Attribute &attr) {
    attr.read(this->m.memType, getData());
  };

  virtual base_type* getData() { return nullptr; }; //Throw exception?

  virtual ~Nyx() { }
};

template<typename T>
class Charon: public Nyx<T> {
  using typename Nyx<T>::base_type;

public:
  Charon(T &val) : Nyx<T>(val) {}
  base_type* getData() { return &this->value; }
};

template<>
class Charon<std::string> : public Nyx<std::string> {
public:
  Charon(std::string &val) : Nyx<std::string>(val) {}

  virtual void write(H5::Attribute &attr) {
    attr.write(this->m.memType, this->value);
  };

  virtual void read(H5::Attribute &attr) {
    attr.read(this->m.memType, this->value);
  };

};

template<typename T, int N>
class Charon<boost::multi_array<T, N>> : public Nyx<boost::multi_array<T, N>, T> {
public:
  typedef boost::multi_array<T, N> array_type;
  using typename Nyx<array_type, T>::base_type;

  Charon(array_type &value) : Nyx<array_type, T>(value) {}
  //using Nyx<array_type, T>::Nyx;

  virtual H5::DataSpace getDataSpace() const {
    const typename array_type::size_type *shape = this->value.shape();
    hsize_t dims[N];
    std::copy(shape, shape + N, dims);

    return H5::DataSpace(N, dims, NULL);
  }

  base_type* getData() { return this->value.data(); }
};

template<int N>
class Charon<boost::multi_array<std::string, N>> :
  public Nyx<boost::multi_array<std::string, N>, std::string> {
public:
  typedef boost::multi_array<std::string, N> array_type;

  Charon(array_type &value) : Nyx<array_type, std::string>(value) {}

  virtual H5::DataSpace getDataSpace() const {
    const typename array_type::size_type *shape = this->value.shape();
    hsize_t dims[N];
    std::copy(shape, shape + N, dims);

    return H5::DataSpace(N, dims, NULL);
  }

  virtual void write(H5::Attribute &attr) {
    std::string *vptr = this->value.data();
    auto nelms = this->value.num_elements();
    char const* *data = new char const* [nelms];

    for (auto i = 0; i < nelms; i++) {
      data[i] = vptr[i].c_str();
      std::cout << i << " " << data[i] << std::endl;
    }

    attr.write(this->m.memType, data);
    delete[] data;
  }

  virtual void read(H5::Attribute &attr) {
    std::string *vptr = this->value.data();
    auto nelms = this->value.num_elements();
    char **data = new char *[nelms];

    attr.read(this->m.memType, data);
    for (auto i = 0; i < nelms; i++) {

      vptr[i] = data[i];
    }

    H5::DataSet::vlenReclaim(data, this->m.memType, attr.getSpace());
    delete[] data;
  }
};

Group::Group()
    : h5group()
{}

Group::Group(H5::Group h5group)
    : h5group(h5group)
{}

Group::Group(const Group &group)
    : h5group(group.h5group)
{}

void Group::operator=(const Group &group)
{
  h5group = group.h5group;
}

bool Group::hasAttr(std::string name) const {
  return H5Aexists(h5group.getId(), name.c_str());
}

void Group::removeAttr(std::string name) const {
  h5group.removeAttr(name);
}

template<typename T> void Group::setAttr(std::string name, T value) const {
  H5::Attribute attr;
  Charon<T> charon = Charon<T>(value);

  if (hasAttr(name)) {
    attr = h5group.openAttribute(name);
  } else {
    H5::DataType fileType = charon.getFileType();
    H5::DataSpace fileSpace = charon.getDataSpace();
    attr = h5group.createAttribute(name, fileType, fileSpace);
  }

  charon.write(attr);
}

template<typename T> bool Group::getAttr(std::string name, T &value) const {

  if (!hasAttr(name)) {
    return false;
  }

  H5::Attribute attr = h5group.openAttribute(name);
  Charon<T> charon = Charon<T>(value);
  charon.read(attr);
  return true;
}

template void Group::setAttr<int>(std::string name, int value) const;
template void Group::setAttr<double>(std::string name, double value) const;
template void Group::setAttr<std::string>(std::string name, std::string value) const;
template bool Group::getAttr<int>(std::string name, int &value) const;
template bool Group::getAttr<double>(std::string name, double &value) const;
template bool Group::getAttr<std::string>(std::string name, std::string &value) const;

bool Group::hasObject(std::string name) const {
  hsize_t num = h5group.getNumObjs();
  for (hsize_t i = 0; i < num; i++) {
    if (h5group.getObjnameByIdx(i) == name)
      return true;
  }
  return false;
}

size_t Group::objectCount() const {
  return h5group.getNumObjs();
}

std::string Group::objectName(size_t index) const {
  return h5group.getObjnameByIdx(index);
}

bool Group::hasData(std::string name) const {
  if (hasObject(name)) {
    H5G_stat_t info;
    h5group.getObjinfo(name, info);
    if (info.type == H5G_DATASET) {
      return true;
    }
  }
  return false;
}

void Group::removeData(std::string name) {
  if (hasData(name))
    h5group.unlink(name);
}

H5::DataSet Group::openData(std::string name) const {
  H5::DataSet data = h5group.openDataSet(name);
  return data;
}

bool Group::hasGroup(std::string name) const {
  if (hasObject(name)) {
    H5G_stat_t info;
    h5group.getObjinfo(name, info);
    if (info.type == H5G_GROUP) {
      return true;
    }
  }
  return false;
}

Group Group::openGroup(std::string name, bool create) const {
  Group g;
  if (hasGroup(name)) {
    g = Group(h5group.openGroup(name));
  } else if (create) {
    g = Group(h5group.createGroup(name));
  }
  return g;
}

void Group::removeGroup(std::string name) {
  if (hasGroup(name))
    h5group.unlink(name);
}

bool Group::operator==(const Group &group) const {
  return h5group.getLocId() == group.h5group.getLocId();
}

bool Group::operator!=(const Group &group) const {
  return h5group.getLocId() != group.h5group.getLocId();
}

H5::Group Group::h5Group() const {
  return h5group;
}

Group::~Group() {}

}
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2014 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"

#ifdef __BORLANDC__
    #include <stdio.h>
#endif

namespace Ogre {

    Exception::Exception(int num, const String& desc, const String& src) :
        line( 0 ),
        description( desc ),
        source( src )
    {
    }

    Exception::Exception(int num, const String& desc, const String& src,
        const char* typ, const char* fil, long lin) :
        line( lin ),
        typeName(typ),
        description( desc ),
        source( src ),
        file( fil )
    {
        // Log this error, mask it from debug though since it may be caught and ignored
        if(LogManager::getSingletonPtr())
        {
            LogManager::getSingleton().logMessage(
                this->getFullDescription(),
                LML_CRITICAL, true);
        }

    }

    Exception::Exception(const Exception& rhs)
        : line( rhs.line ),
        typeName( rhs.typeName ),
        description( rhs.description ),
        source( rhs.source ),
        file( rhs.file )
    {
    }

    const String& Exception::getFullDescription(void) const
    {
        if (fullDesc.empty())
        {

            StringStream desc;

            desc << typeName << ": "
                << description
                << " in " << source;

            if( line > 0 )
            {
                desc << " at " << file << " (line " << line << ")";
            }

            fullDesc = desc.str();
        }

        return fullDesc;
    }

}

<commit_msg>Main: remove logging from Exception constructor altogether<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2014 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"

#ifdef __BORLANDC__
    #include <stdio.h>
#endif

namespace Ogre {

    Exception::Exception(int num, const String& desc, const String& src) :
        line( 0 ),
        description( desc ),
        source( src )
    {
    }

    Exception::Exception(int num, const String& desc, const String& src,
        const char* typ, const char* fil, long lin) :
        line( lin ),
        typeName(typ),
        description( desc ),
        source( src ),
        file( fil )
    {
    }

    Exception::Exception(const Exception& rhs)
        : line( rhs.line ),
        typeName( rhs.typeName ),
        description( rhs.description ),
        source( rhs.source ),
        file( rhs.file )
    {
    }

    const String& Exception::getFullDescription(void) const
    {
        if (fullDesc.empty())
        {

            StringStream desc;

            desc << typeName << ": "
                << description
                << " in " << source;

            if( line > 0 )
            {
                desc << " at " << file << " (line " << line << ")";
            }

            fullDesc = desc.str();
        }

        return fullDesc;
    }

}

<|endoftext|>


<commit_before>#include "Homie.hpp"

using namespace HomieInternals;

HomieClass::HomieClass()
  : _setupCalled(false)
  , _firmwareSet(false)
  , __HOMIE_SIGNATURE("\x25\x48\x4f\x4d\x49\x45\x5f\x45\x53\x50\x38\x32\x36\x36\x5f\x46\x57\x25") {
  strlcpy(Interface::get().brand, DEFAULT_BRAND, MAX_BRAND_LENGTH);
  Interface::get().bootMode = HomieBootMode::UNDEFINED;
  Interface::get().configurationAp.secured = false;
  #ifdef ESP32
  Interface::get().led.enabled = false;
  #ifdef LED_BUILTIN
  Interface::get().led.pin = LED_BUILTIN;
  #endif // LED_BUILTIN
  Interface::get().led.on = LOW;
  #elif defined(ESP8266)
  Interface::get().led.enabled = true;
  Interface::get().led.pin = LED_BUILTIN;
  Interface::get().led.on = LOW;
  #endif // ESP32
  Interface::get().reset.idle = true;
  Interface::get().reset.enabled = true;
  Interface::get().reset.triggerPin = DEFAULT_RESET_PIN;
  Interface::get().reset.triggerState = DEFAULT_RESET_STATE;
  Interface::get().reset.triggerTime = DEFAULT_RESET_TIME;
  Interface::get().reset.resetFlag = false;
  Interface::get().disable = false;
  Interface::get().flaggedForSleep = false;
  Interface::get().globalInputHandler = [](const HomieNode& node, const HomieRange& range, const String& property, const String& value) { return false; };
  Interface::get().broadcastHandler = [](const String& level, const String& value) { return false; };
  Interface::get().setupFunction = []() {};
  Interface::get().loopFunction = []() {};
  Interface::get().eventHandler = [](const HomieEvent& event) {};
  Interface::get().ready = false;
  Interface::get()._mqttClient = &_mqttClient;
  Interface::get()._sendingPromise = &_sendingPromise;
  Interface::get()._blinker = &_blinker;
  Interface::get()._logger = &_logger;
  Interface::get()._config = &_config;

  DeviceId::generate();
}

HomieClass::~HomieClass() {
}

void HomieClass::_checkBeforeSetup(const __FlashStringHelper* functionName) const {
  if (_setupCalled) {
    String message;
    message.concat(F("✖ "));
    message.concat(functionName);
    message.concat(F("(): has to be called before setup()"));
    Helpers::abort(message);
  }
}

void HomieClass::setup() {
  _setupCalled = true;

  // Check if firmware is set
  if (!_firmwareSet) {
    Helpers::abort(F("✖ Firmware name must be set before calling setup()"));
    return;  // never reached, here for clarity
  }

  // Check the max allowed setting elements
  if (IHomieSetting::settings.size() > MAX_CONFIG_SETTING_SIZE) {
    Helpers::abort(F("✖ Settings exceed set limit of elelement."));
    return;  // never reached, here for clarity
  }

  // Check if default settings values are valid
  bool defaultSettingsValuesValid = true;
  for (IHomieSetting* iSetting : IHomieSetting::settings) {
    if (iSetting->isBool()) {
      HomieSetting<bool>* setting = static_cast<HomieSetting<bool>*>(iSetting);
      if (!setting->isRequired() && !setting->validate(setting->get())) {
        defaultSettingsValuesValid = false;
        break;
      }
    } else if (iSetting->isLong()) {
      HomieSetting<long>* setting = static_cast<HomieSetting<long>*>(iSetting);
      if (!setting->isRequired() && !setting->validate(setting->get())) {
        defaultSettingsValuesValid = false;
        break;
      }
    } else if (iSetting->isDouble()) {
      HomieSetting<double>* setting = static_cast<HomieSetting<double>*>(iSetting);
      if (!setting->isRequired() && !setting->validate(setting->get())) {
        defaultSettingsValuesValid = false;
        break;
      }
    } else if (iSetting->isConstChar()) {
      HomieSetting<const char*>* setting = static_cast<HomieSetting<const char*>*>(iSetting);
      if (!setting->isRequired() && !setting->validate(setting->get())) {
        defaultSettingsValuesValid = false;
        break;
      }
    }
  }

  if (!defaultSettingsValuesValid) {
    Helpers::abort(F("✖ Default setting value does not pass validator test"));
    return;  // never reached, here for clarity
  }

  // boot mode set during this boot by application before Homie.setup()
  HomieBootMode _applicationHomieBootMode = Interface::get().bootMode;

  // boot mode set before resetting the device. If application has defined a boot mode, this will be ignored
  HomieBootMode _nextHomieBootMode = Interface::get().getConfig().getHomieBootModeOnNextBoot();
  if (_nextHomieBootMode != HomieBootMode::UNDEFINED) {
    Interface::get().getConfig().setHomieBootModeOnNextBoot(HomieBootMode::UNDEFINED);
  }

#if HOMIE_CONFIG
  HomieBootMode _selectedHomieBootMode = HomieBootMode::CONFIGURATION;
#else
  HomieBootMode _selectedHomieBootMode = HomieBootMode::NORMAL;
#endif

  // select boot mode source
  if (_applicationHomieBootMode != HomieBootMode::UNDEFINED) {
    _selectedHomieBootMode = _applicationHomieBootMode;
  } else if (_nextHomieBootMode != HomieBootMode::UNDEFINED) {
    _selectedHomieBootMode = _nextHomieBootMode;
  } else {
    _selectedHomieBootMode = HomieBootMode::NORMAL;
  }

  // validate selected mode and fallback as needed
  if (_selectedHomieBootMode == HomieBootMode::NORMAL && !Interface::get().getConfig().load()) {
#if HOMIE_CONFIG
    Interface::get().getLogger() << F("Configuration invalid. Using CONFIG MODE") << endl;
    _selectedHomieBootMode = HomieBootMode::CONFIGURATION;
#else
    Interface::get().getLogger() << F("Configuration invalid. CONFIG MODE is disabled.") << endl;
    ESP.restart();
#endif
  }

  // run selected mode
  if (_selectedHomieBootMode == HomieBootMode::NORMAL) {
    _boot = &_bootNormal;
    Interface::get().event.type = HomieEventType::NORMAL_MODE;
    Interface::get().eventHandler(Interface::get().event);
#if HOMIE_CONFIG
  } else if (_selectedHomieBootMode == HomieBootMode::CONFIGURATION) {
    _boot = &_bootConfig;
    Interface::get().event.type = HomieEventType::CONFIGURATION_MODE;
    Interface::get().eventHandler(Interface::get().event);
#endif
  } else if (_selectedHomieBootMode == HomieBootMode::STANDALONE) {
    _boot = &_bootStandalone;
    Interface::get().event.type = HomieEventType::STANDALONE_MODE;
    Interface::get().eventHandler(Interface::get().event);
  } else {
    Helpers::abort(F("✖ Boot mode invalid"));
    return;  // never reached, here for clarity
  }

  _boot->setup();
}

void HomieClass::loop() {
  _boot->loop();

  if (_flaggedForReboot && Interface::get().reset.idle) {
    Interface::get().getLogger() << F("Device is idle") << endl;
    Interface::get().getLogger() << F("Triggering ABOUT_TO_RESET event...") << endl;
    Interface::get().event.type = HomieEventType::ABOUT_TO_RESET;
    Interface::get().eventHandler(Interface::get().event);

    Interface::get().getLogger() << F("↻ Rebooting device...") << endl;
    Serial.flush();
    ESP.restart();
  }
}

HomieClass& HomieClass::disableLogging() {
  _checkBeforeSetup(F("disableLogging"));

  Interface::get().getLogger().setLogging(false);

  return *this;
}

HomieClass& HomieClass::setLoggingPrinter(Print* printer) {
  _checkBeforeSetup(F("setLoggingPrinter"));

  Interface::get().getLogger().setPrinter(printer);

  return *this;
}

HomieClass& HomieClass::disableLedFeedback() {
  _checkBeforeSetup(F("disableLedFeedback"));

  Interface::get().led.enabled = false;

  return *this;
}

HomieClass& HomieClass::setLedPin(uint8_t pin, uint8_t on) {
  _checkBeforeSetup(F("setLedPin"));

  Interface::get().led.pin = pin;
  Interface::get().led.on = on;

  return *this;
}

HomieClass& HomieClass::setConfigurationApPassword(const char* password) {
  _checkBeforeSetup(F("setConfigurationApPassword"));

  Interface::get().configurationAp.secured = true;
  strlcpy(Interface::get().configurationAp.password, password, MAX_WIFI_PASSWORD_LENGTH);
  return *this;
}

void HomieClass::__setFirmware(const char* name, const char* version) {
  _checkBeforeSetup(F("setFirmware"));
  if (strlen(name) + 1 - 10 > MAX_FIRMWARE_NAME_LENGTH || strlen(version) + 1 - 10 > MAX_FIRMWARE_VERSION_LENGTH) {
    Helpers::abort(F("✖ setFirmware(): either the name or version string is too long"));
    return;  // never reached, here for clarity
  }

  strncpy(Interface::get().firmware.name, name + 5, strlen(name) - 10);
  Interface::get().firmware.name[strlen(name) - 10] = '\0';
  strncpy(Interface::get().firmware.version, version + 5, strlen(version) - 10);
  Interface::get().firmware.version[strlen(version) - 10] = '\0';
  _firmwareSet = true;
}

void HomieClass::__setBrand(const char* brand) const {
  _checkBeforeSetup(F("setBrand"));
  if (strlen(brand) + 1 - 10 > MAX_BRAND_LENGTH) {
    Helpers::abort(F("✖ setBrand(): the brand string is too long"));
    return;  // never reached, here for clarity
  }

  strncpy(Interface::get().brand, brand + 5, strlen(brand) - 10);
  Interface::get().brand[strlen(brand) - 10] = '\0';
}

void HomieClass::reset() {
  Interface::get().getLogger() << F("Flagged for reset by sketch") << endl;
  Interface::get().disable = true;
  Interface::get().reset.resetFlag = true;
}

void HomieClass::reboot() {
  Interface::get().getLogger() << F("Flagged for reboot by sketch") << endl;
  Interface::get().disable = true;
  _flaggedForReboot = true;
}

void HomieClass::setIdle(bool idle) {
  Interface::get().reset.idle = idle;
}

HomieClass& HomieClass::setGlobalInputHandler(const GlobalInputHandler& globalInputHandler) {
  _checkBeforeSetup(F("setGlobalInputHandler"));

  Interface::get().globalInputHandler = globalInputHandler;

  return *this;
}

HomieClass& HomieClass::setBroadcastHandler(const BroadcastHandler& broadcastHandler) {
  _checkBeforeSetup(F("setBroadcastHandler"));

  Interface::get().broadcastHandler = broadcastHandler;

  return *this;
}

HomieClass& HomieClass::setSetupFunction(const OperationFunction& function) {
  _checkBeforeSetup(F("setSetupFunction"));

  Interface::get().setupFunction = function;

  return *this;
}

HomieClass& HomieClass::setLoopFunction(const OperationFunction& function) {
  _checkBeforeSetup(F("setLoopFunction"));

  Interface::get().loopFunction = function;

  return *this;
}

HomieClass& HomieClass::setHomieBootMode(HomieBootMode bootMode) {
  _checkBeforeSetup(F("setHomieBootMode"));
  Interface::get().bootMode = bootMode;
  return *this;
}

HomieClass& HomieClass::setHomieBootModeOnNextBoot(HomieBootMode bootMode) {
  Interface::get().getConfig().setHomieBootModeOnNextBoot(bootMode);
  return *this;
}

bool HomieClass::isConfigured() {
  return Interface::get().getConfig().load();
}

bool HomieClass::isConnected() {
  return Interface::get().ready;
}

HomieClass& HomieClass::onEvent(const EventHandler& handler) {
  _checkBeforeSetup(F("onEvent"));

  Interface::get().eventHandler = handler;

  return *this;
}

HomieClass& HomieClass::setResetTrigger(uint8_t pin, uint8_t state, uint16_t time) {
  _checkBeforeSetup(F("setResetTrigger"));

  Interface::get().reset.enabled = true;
  Interface::get().reset.triggerPin = pin;
  Interface::get().reset.triggerState = state;
  Interface::get().reset.triggerTime = time;

  return *this;
}

HomieClass& HomieClass::disableResetTrigger() {
  _checkBeforeSetup(F("disableResetTrigger"));

  Interface::get().reset.enabled = false;

  return *this;
}

const ConfigStruct& HomieClass::getConfiguration() {
  return Interface::get().getConfig().get();
}

AsyncMqttClient& HomieClass::getMqttClient() {
  return _mqttClient;
}

Logger& HomieClass::getLogger() {
  return _logger;
}

#ifdef ESP32
//FIXME: implement for ESP32
#elif defined(ESP8266)
void HomieClass::prepareToSleep() {
  Interface::get().getLogger() << F("Flagged for sleep by sketch") << endl;
  if (Interface::get().ready) {
    Interface::get().disable = true;
    Interface::get().flaggedForSleep = true;
  } else {
    Interface::get().disable = true;
    Interface::get().getLogger() << F("Triggering READY_TO_SLEEP event...") << endl;
    Interface::get().event.type = HomieEventType::READY_TO_SLEEP;
    Interface::get().eventHandler(Interface::get().event);
  }
}

void HomieClass::doDeepSleep(uint32_t time_us, RFMode mode) {
  Interface::get().getLogger() << F("💤 Device is deep sleeping...") << endl;
  Serial.flush();
  ESP.deepSleep(time_us, mode);
}
#endif // ESP32

HomieClass Homie;
<commit_msg>add workaround for issue #351 (#598)<commit_after>#include "Homie.hpp"

using namespace HomieInternals;

HomieClass::HomieClass()
  : _setupCalled(false)
  , _firmwareSet(false)
  , __HOMIE_SIGNATURE("\x25\x48\x4f\x4d\x49\x45\x5f\x45\x53\x50\x38\x32\x36\x36\x5f\x46\x57\x25") {
  strlcpy(Interface::get().brand, DEFAULT_BRAND, MAX_BRAND_LENGTH);
  Interface::get().bootMode = HomieBootMode::UNDEFINED;
  Interface::get().configurationAp.secured = false;
  #ifdef ESP32
  Interface::get().led.enabled = false;
  #ifdef LED_BUILTIN
  Interface::get().led.pin = LED_BUILTIN;
  #endif // LED_BUILTIN
  Interface::get().led.on = LOW;
  #elif defined(ESP8266)
  Interface::get().led.enabled = true;
  Interface::get().led.pin = LED_BUILTIN;
  Interface::get().led.on = LOW;
  #endif // ESP32
  Interface::get().reset.idle = true;
  Interface::get().reset.enabled = true;
  Interface::get().reset.triggerPin = DEFAULT_RESET_PIN;
  Interface::get().reset.triggerState = DEFAULT_RESET_STATE;
  Interface::get().reset.triggerTime = DEFAULT_RESET_TIME;
  Interface::get().reset.resetFlag = false;
  Interface::get().disable = false;
  Interface::get().flaggedForSleep = false;
  Interface::get().globalInputHandler = [](const HomieNode& node, const HomieRange& range, const String& property, const String& value) { return false; };
  Interface::get().broadcastHandler = [](const String& level, const String& value) { return false; };
  Interface::get().setupFunction = []() {};
  Interface::get().loopFunction = []() {};
  Interface::get().eventHandler = [](const HomieEvent& event) {};
  Interface::get().ready = false;
  Interface::get()._mqttClient = &_mqttClient;
  Interface::get()._sendingPromise = &_sendingPromise;
  Interface::get()._blinker = &_blinker;
  Interface::get()._logger = &_logger;
  Interface::get()._config = &_config;

  DeviceId::generate();
}

HomieClass::~HomieClass() {
}

void HomieClass::_checkBeforeSetup(const __FlashStringHelper* functionName) const {
  if (_setupCalled) {
    String message;
    message.concat(F("✖ "));
    message.concat(functionName);
    message.concat(F("(): has to be called before setup()"));
    Helpers::abort(message);
  }
}

void HomieClass::setup() {
  _setupCalled = true;

  // Check if firmware is set
  if (!_firmwareSet) {
    Helpers::abort(F("✖ Firmware name must be set before calling setup()"));
    return;  // never reached, here for clarity
  }

  // Check the max allowed setting elements
  if (IHomieSetting::settings.size() > MAX_CONFIG_SETTING_SIZE) {
    Helpers::abort(F("✖ Settings exceed set limit of elelement."));
    return;  // never reached, here for clarity
  }

  // Check if default settings values are valid
  bool defaultSettingsValuesValid = true;
  for (IHomieSetting* iSetting : IHomieSetting::settings) {
    if (iSetting->isBool()) {
      HomieSetting<bool>* setting = static_cast<HomieSetting<bool>*>(iSetting);
      if (!setting->isRequired() && !setting->validate(setting->get())) {
        defaultSettingsValuesValid = false;
        break;
      }
    } else if (iSetting->isLong()) {
      HomieSetting<long>* setting = static_cast<HomieSetting<long>*>(iSetting);
      if (!setting->isRequired() && !setting->validate(setting->get())) {
        defaultSettingsValuesValid = false;
        break;
      }
    } else if (iSetting->isDouble()) {
      HomieSetting<double>* setting = static_cast<HomieSetting<double>*>(iSetting);
      if (!setting->isRequired() && !setting->validate(setting->get())) {
        defaultSettingsValuesValid = false;
        break;
      }
    } else if (iSetting->isConstChar()) {
      HomieSetting<const char*>* setting = static_cast<HomieSetting<const char*>*>(iSetting);
      if (!setting->isRequired() && !setting->validate(setting->get())) {
        defaultSettingsValuesValid = false;
        break;
      }
    }
  }

  if (!defaultSettingsValuesValid) {
    Helpers::abort(F("✖ Default setting value does not pass validator test"));
    return;  // never reached, here for clarity
  }

  // boot mode set during this boot by application before Homie.setup()
  HomieBootMode _applicationHomieBootMode = Interface::get().bootMode;

  // boot mode set before resetting the device. If application has defined a boot mode, this will be ignored
  HomieBootMode _nextHomieBootMode = Interface::get().getConfig().getHomieBootModeOnNextBoot();
  if (_nextHomieBootMode != HomieBootMode::UNDEFINED) {
    Interface::get().getConfig().setHomieBootModeOnNextBoot(HomieBootMode::UNDEFINED);
  }

#if HOMIE_CONFIG
  HomieBootMode _selectedHomieBootMode = HomieBootMode::CONFIGURATION;
#else
  HomieBootMode _selectedHomieBootMode = HomieBootMode::NORMAL;
#endif

  // select boot mode source
  if (_applicationHomieBootMode != HomieBootMode::UNDEFINED) {
    _selectedHomieBootMode = _applicationHomieBootMode;
  } else if (_nextHomieBootMode != HomieBootMode::UNDEFINED) {
    _selectedHomieBootMode = _nextHomieBootMode;
  } else {
    _selectedHomieBootMode = HomieBootMode::NORMAL;
  }

  // validate selected mode and fallback as needed
  if (_selectedHomieBootMode == HomieBootMode::NORMAL && !Interface::get().getConfig().load()) {
#if HOMIE_CONFIG
    Interface::get().getLogger() << F("Configuration invalid. Using CONFIG MODE") << endl;
    _selectedHomieBootMode = HomieBootMode::CONFIGURATION;
#else
    Interface::get().getLogger() << F("Configuration invalid. CONFIG MODE is disabled.") << endl;
    ESP.restart();
#endif
  }

  // run selected mode
  if (_selectedHomieBootMode == HomieBootMode::NORMAL) {
    _boot = &_bootNormal;
    Interface::get().event.type = HomieEventType::NORMAL_MODE;
    Interface::get().eventHandler(Interface::get().event);
#if HOMIE_CONFIG
  } else if (_selectedHomieBootMode == HomieBootMode::CONFIGURATION) {
    _boot = &_bootConfig;
    Interface::get().event.type = HomieEventType::CONFIGURATION_MODE;
    Interface::get().eventHandler(Interface::get().event);
#endif
  } else if (_selectedHomieBootMode == HomieBootMode::STANDALONE) {
    _boot = &_bootStandalone;
    Interface::get().event.type = HomieEventType::STANDALONE_MODE;
    Interface::get().eventHandler(Interface::get().event);
  } else {
    Helpers::abort(F("✖ Boot mode invalid"));
    return;  // never reached, here for clarity
  }

  WiFi.disconnect(); // workaround for issue #351

  _boot->setup();
}

void HomieClass::loop() {
  _boot->loop();

  if (_flaggedForReboot && Interface::get().reset.idle) {
    Interface::get().getLogger() << F("Device is idle") << endl;
    Interface::get().getLogger() << F("Triggering ABOUT_TO_RESET event...") << endl;
    Interface::get().event.type = HomieEventType::ABOUT_TO_RESET;
    Interface::get().eventHandler(Interface::get().event);

    Interface::get().getLogger() << F("↻ Rebooting device...") << endl;
    Serial.flush();
    ESP.restart();
  }
}

HomieClass& HomieClass::disableLogging() {
  _checkBeforeSetup(F("disableLogging"));

  Interface::get().getLogger().setLogging(false);

  return *this;
}

HomieClass& HomieClass::setLoggingPrinter(Print* printer) {
  _checkBeforeSetup(F("setLoggingPrinter"));

  Interface::get().getLogger().setPrinter(printer);

  return *this;
}

HomieClass& HomieClass::disableLedFeedback() {
  _checkBeforeSetup(F("disableLedFeedback"));

  Interface::get().led.enabled = false;

  return *this;
}

HomieClass& HomieClass::setLedPin(uint8_t pin, uint8_t on) {
  _checkBeforeSetup(F("setLedPin"));

  Interface::get().led.pin = pin;
  Interface::get().led.on = on;

  return *this;
}

HomieClass& HomieClass::setConfigurationApPassword(const char* password) {
  _checkBeforeSetup(F("setConfigurationApPassword"));

  Interface::get().configurationAp.secured = true;
  strlcpy(Interface::get().configurationAp.password, password, MAX_WIFI_PASSWORD_LENGTH);
  return *this;
}

void HomieClass::__setFirmware(const char* name, const char* version) {
  _checkBeforeSetup(F("setFirmware"));
  if (strlen(name) + 1 - 10 > MAX_FIRMWARE_NAME_LENGTH || strlen(version) + 1 - 10 > MAX_FIRMWARE_VERSION_LENGTH) {
    Helpers::abort(F("✖ setFirmware(): either the name or version string is too long"));
    return;  // never reached, here for clarity
  }

  strncpy(Interface::get().firmware.name, name + 5, strlen(name) - 10);
  Interface::get().firmware.name[strlen(name) - 10] = '\0';
  strncpy(Interface::get().firmware.version, version + 5, strlen(version) - 10);
  Interface::get().firmware.version[strlen(version) - 10] = '\0';
  _firmwareSet = true;
}

void HomieClass::__setBrand(const char* brand) const {
  _checkBeforeSetup(F("setBrand"));
  if (strlen(brand) + 1 - 10 > MAX_BRAND_LENGTH) {
    Helpers::abort(F("✖ setBrand(): the brand string is too long"));
    return;  // never reached, here for clarity
  }

  strncpy(Interface::get().brand, brand + 5, strlen(brand) - 10);
  Interface::get().brand[strlen(brand) - 10] = '\0';
}

void HomieClass::reset() {
  Interface::get().getLogger() << F("Flagged for reset by sketch") << endl;
  Interface::get().disable = true;
  Interface::get().reset.resetFlag = true;
}

void HomieClass::reboot() {
  Interface::get().getLogger() << F("Flagged for reboot by sketch") << endl;
  Interface::get().disable = true;
  _flaggedForReboot = true;
}

void HomieClass::setIdle(bool idle) {
  Interface::get().reset.idle = idle;
}

HomieClass& HomieClass::setGlobalInputHandler(const GlobalInputHandler& globalInputHandler) {
  _checkBeforeSetup(F("setGlobalInputHandler"));

  Interface::get().globalInputHandler = globalInputHandler;

  return *this;
}

HomieClass& HomieClass::setBroadcastHandler(const BroadcastHandler& broadcastHandler) {
  _checkBeforeSetup(F("setBroadcastHandler"));

  Interface::get().broadcastHandler = broadcastHandler;

  return *this;
}

HomieClass& HomieClass::setSetupFunction(const OperationFunction& function) {
  _checkBeforeSetup(F("setSetupFunction"));

  Interface::get().setupFunction = function;

  return *this;
}

HomieClass& HomieClass::setLoopFunction(const OperationFunction& function) {
  _checkBeforeSetup(F("setLoopFunction"));

  Interface::get().loopFunction = function;

  return *this;
}

HomieClass& HomieClass::setHomieBootMode(HomieBootMode bootMode) {
  _checkBeforeSetup(F("setHomieBootMode"));
  Interface::get().bootMode = bootMode;
  return *this;
}

HomieClass& HomieClass::setHomieBootModeOnNextBoot(HomieBootMode bootMode) {
  Interface::get().getConfig().setHomieBootModeOnNextBoot(bootMode);
  return *this;
}

bool HomieClass::isConfigured() {
  return Interface::get().getConfig().load();
}

bool HomieClass::isConnected() {
  return Interface::get().ready;
}

HomieClass& HomieClass::onEvent(const EventHandler& handler) {
  _checkBeforeSetup(F("onEvent"));

  Interface::get().eventHandler = handler;

  return *this;
}

HomieClass& HomieClass::setResetTrigger(uint8_t pin, uint8_t state, uint16_t time) {
  _checkBeforeSetup(F("setResetTrigger"));

  Interface::get().reset.enabled = true;
  Interface::get().reset.triggerPin = pin;
  Interface::get().reset.triggerState = state;
  Interface::get().reset.triggerTime = time;

  return *this;
}

HomieClass& HomieClass::disableResetTrigger() {
  _checkBeforeSetup(F("disableResetTrigger"));

  Interface::get().reset.enabled = false;

  return *this;
}

const ConfigStruct& HomieClass::getConfiguration() {
  return Interface::get().getConfig().get();
}

AsyncMqttClient& HomieClass::getMqttClient() {
  return _mqttClient;
}

Logger& HomieClass::getLogger() {
  return _logger;
}

#ifdef ESP32
//FIXME: implement for ESP32
#elif defined(ESP8266)
void HomieClass::prepareToSleep() {
  Interface::get().getLogger() << F("Flagged for sleep by sketch") << endl;
  if (Interface::get().ready) {
    Interface::get().disable = true;
    Interface::get().flaggedForSleep = true;
  } else {
    Interface::get().disable = true;
    Interface::get().getLogger() << F("Triggering READY_TO_SLEEP event...") << endl;
    Interface::get().event.type = HomieEventType::READY_TO_SLEEP;
    Interface::get().eventHandler(Interface::get().event);
  }
}

void HomieClass::doDeepSleep(uint32_t time_us, RFMode mode) {
  Interface::get().getLogger() << F("💤 Device is deep sleeping...") << endl;
  Serial.flush();
  ESP.deepSleep(time_us, mode);
}
#endif // ESP32

HomieClass Homie;
<|endoftext|>