<commit_before>#include "renderer.hpp"

#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

#include "addr_space.hpp"
#include "address.hpp"
#include "const.hpp"
#include "cpu.hpp"
#include "cursor.hpp"
#include "drawing2D.hpp"
#include "drawing3D.hpp"
#include "instruction.hpp"
#include "printer.hpp"
#include "ram.hpp"
#include "util.hpp"

using namespace std;

/*
 * Only public method. Also static. It creates new object every time
 * it gets called.
 */
vector<vector<string>> Renderer::renderState(const Printer &printerIn,
                                             const Ram &ramIn,
                                             const Cpu &cpuIn,
                                             const Cursor &cursorIn,
                                             const View &viewIn) {
  Renderer instance(printerIn, ramIn, cpuIn, cursorIn, viewIn);
  vector<vector<string>> out;
  for (vector<string> line : viewIn.lines) {
    out.push_back(instance.insertActualValues(line));
  }
  return out;
}

vector<string> Renderer::insertActualValues(vector<string> lineIn) {
  vector<bool> highlightedChars = getHighlightedLocations(lineIn);
  vector<string> lineOut;
  for (string cIn : lineIn) {
    string sOut;
    bool charIsALightbulb = ALL_INDICATORS.count(cIn);
    if (charIsALightbulb) {
      sOut = getLightbulb(cIn);
    } else {
      sOut = cIn;
    }
    lineOut.push_back(sOut);
  }
  return insertEscSeqences(lineOut, highlightedChars);
}

vector<string> Renderer::insertEscSeqences(
    vector<string> lineWithoutEscapeSeqences, vector<bool> highlightedChars) {
  vector<string> lineOut;
  bool insideHighlightBlock = false;
  for (size_t i = 0; i < lineWithoutEscapeSeqences.size(); i++) {
    bool firstCharInsideBlock = highlightedChars[i] && !insideHighlightBlock;
    if (firstCharInsideBlock) {
      vector<string> highlightEsc = Util::stringToVecOfString(HIGHLIGHT_ESC);
      lineOut.insert(lineOut.end(), highlightEsc.begin(), highlightEsc.end());
      insideHighlightBlock = true;
    }
    bool firstCharOutsideBlock = !highlightedChars[i] && insideHighlightBlock;
    if (firstCharOutsideBlock) {
      vector<string> highlightEscEnd =
          Util::stringToVecOfString(HIGHLIGHT_END_ESC);
      lineOut.insert(lineOut.end(), highlightEscEnd.begin(),
                     highlightEscEnd.end());
      insideHighlightBlock = false;
    }
    lineOut.push_back(lineWithoutEscapeSeqences[i]);
  }
  return lineOut;
}

/////////////////////////////////
/// GET HIGHLIGHTED LOCATIONS ///
/////////////////////////////////

vector<bool> Renderer::getHighlightedLocations(vector<string> lineIn) {
  vector<bool> highlightedLocations (lineIn.size(), false);
  highlightPc(highlightedLocations, lineIn);
  highlightCursor(highlightedLocations, lineIn);
  Instruction *inst = getInstruction();
  if (inst == NULL) {
    highlightPointingInstructions(highlightedLocations, lineIn);
    return highlightedLocations;
  }
  highlightOperator(highlightedLocations, lineIn, inst);
  if (inst->adr.space == CODE) {
    highlightCodeWord(highlightedLocations, lineIn, inst);
  } else if (inst->adr.space == DATA) {
    highlightDataWord(highlightedLocations, lineIn, inst);
  }
  return highlightedLocations;
}

void Renderer::highlightPc(vector<bool> &highlightedLocations,
                                   vector<string> &lineIn) {
  if (!machineActive() || pcHighlighted) {
    return;
  }
  for (size_t i = 0; i < lineIn.size(); i++) {
    if (lineIn[i] == CODE_ADR_INDICATOR) {
      int index = switchIndex[CODE_ADR_INDICATOR];
      if (pcPointingToAddress(index)) {
        highlightedLocations[i] = true;
        pcHighlighted = true;
        return;
      }
    }
  }
}

void Renderer::highlightCursor(vector<bool> &highlightedLocations,
                                       vector<string> &lineIn) {
  if (machineActive() || cursorHighlighted) {
    return;
  }
  if (cursor.getAddressSpace() == CODE) {
    findCursor(highlightedLocations, lineIn, CODE_INDICATOR);
  } else if (cursor.getAddressSpace() == DATA) {
    findCursor(highlightedLocations, lineIn, DATA_INDICATOR);
  }
}

void Renderer::findCursor(vector<bool> &highlightedLocations,
                                  vector<string> &lineIn, string c) {
  int indexDelta = 0;
  for (size_t i = 0; i < lineIn.size(); i++) {
    if (lineIn[i] == c) {
      int lightbulbIndex = switchIndex[c] + indexDelta++;
      if (cursor.getAbsoluteBitIndex() == lightbulbIndex) {
        highlightedLocations[i] = true;
        cursorHighlighted = true;
        return;
      }
    }
  }
}

void Renderer::highlightPointingInstructions(vector<bool> &highlightedLocations,
                                             vector<string> &lineIn) {
  set<int> *pointingInstructions = getIndexesOfPointingInstructions();
  for (size_t i = 0; i < lineIn.size(); i++) {
    if (lineIn[i] == CODE_INDICATOR) {
      int addressValue = switchIndex[CODE_INDICATOR] / WORD_SIZE;
      if (pointingInstructions->count(addressValue)) {
        highlightedLocations[i] = true;
      }
    }
  }
}

void Renderer::highlightOperator(vector<bool> &highlightedLocations,
                                         vector<string> &lineIn,
                                         Instruction *inst) {
  string exclude;
  if (inst->isLogic()) {
    exclude = LOGIC_OPS_INDICATOR[min(inst->logicIndex, 8)];
  }
  if (inst->index == INC_DEC_OPS_INDEX) {
    if (inst->logicIndex <= 7) {
      exclude = "INC";
    } else {
      exclude = "DEC";
    }
  }
  string label = " " + inst->label;
  label.append(11 - inst->label.length(), ' ');
  highlightLabel(highlightedLocations, lineIn, Util::stringToVecOfString(label),
                 Util::stringToVecOfString(exclude));
}

void Renderer::highlightCodeWord(vector<bool> &highlightedLocations,
                                        vector<string> &lineIn,
                                        Instruction *inst) {
  if (inst->adr.val == LAST_ADDRESS) {
    vector<string> stopLabel = Util::stringToVecOfString(LAST_CODE_ADDR_LABEL);
    highlightLabel(highlightedLocations, lineIn, stopLabel, {});
    return;
  }
  highlightWord(highlightedLocations, lineIn, CODE_INDICATOR, CODE);
}

void Renderer::highlightDataWord(vector<bool> &highlightedLocations,
                                         vector<string> &lineIn,
                                         Instruction *inst) {
  if (inst->adr.val == LAST_ADDRESS) {
    vector<string> inOutLabel = Util::stringToVecOfString(LAST_DATA_ADDR_LABEL);
    highlightLabel(highlightedLocations, lineIn, inOutLabel, {});
    return;
  }
  highlightWord(highlightedLocations, lineIn, DATA_INDICATOR, DATA);
}

void Renderer::highlightWord(vector<bool> &highlightedLocations,
                                     vector<string> &lineIn, string indicator,
                                     AddrSpace addrSpace) {
  for (size_t i = 0; i < lineIn.size(); i++) {
    if (lineIn[i] == indicator) {
      int addressValue = switchIndex[indicator] / WORD_SIZE;
      Address adr = Address(addrSpace, Util::getBoolNibb(addressValue));
      if (instructionPointingToAddress(adr)) {
        highlightedLocations[i] = true;
      }
    }
  }
}

void Renderer::highlightLabel(vector<bool> &highlightedLocations,
                                     vector<string> &lineIn,
                                     vector<string> label,
                                     vector<string> exclude) {
  auto it = search(begin(lineIn), end(lineIn), begin(label), end(label));
  int labelPosition = it - lineIn.begin();
  bool notFound = it == end(lineIn);
  if (notFound) {
    return;
  }
  size_t excludePosition = numeric_limits<size_t>::max();
  if (!exclude.empty()) {
    it = search(begin(label), end(label), begin(exclude), end(exclude));
    excludePosition = it - label.begin();
  }
  for (size_t i = labelPosition; i < labelPosition + label.size(); i++) {
    bool highlight = (i < labelPosition + excludePosition ||
                      i >= labelPosition + excludePosition + exclude.size());
    if (highlight) {
      highlightedLocations[i] = true;
    }
  }
}

/////////////////////
/// GET LIGHTBULB ///
/////////////////////

string Renderer::getLightbulb(string cIn) {
  int i = switchIndex[cIn]++;
  if (cIn == CODE_INDICATOR) {
      return getCodeBit(i);
  } else if (cIn == DATA_INDICATOR) {
      return getDataBit(i);
  } else if (cIn == REGISTER_INDICATOR) {
      return view.getLightbulb(cpu.getRegister().at(i));
  } else if (cIn == CODE_ADR_INDICATOR) {
      return getAdrIndicator(CODE, i);
  } else if (cIn == DATA_ADR_INDICATOR) {
      return getAdrIndicator(DATA, i);
  } else if (cIn == OUTPUT_INDICATOR) {
      return getFormattedOutput(i);
  }
  cerr << "There was an error parsing a drawing file.";
  cerr << " Problem with char" << cIn << ". Will ignore it.";
  return " ";
}

string Renderer::getCodeBit(int i) {
  return getCharAt(i, &ram.state[CODE]);
}

string Renderer::getDataBit(int i) {
  return getCharAt(i, &ram.state[DATA]);
}

string Renderer::getCharAt(int i, vector<vector<bool>>* matrix) {
  int j = i / WORD_SIZE;
  i = i % WORD_SIZE;
  return view.getLightbulb((*matrix).at(j).at(i));
}

bool Renderer::pcPointingToAddress(int adr) {
  bool executionHasntStarted = cpu.getCycle() == 0;
  if (executionHasntStarted) {
    return false;
  }
  return Util::getInt(cpu.getPc()) == adr;
}

string Renderer::getAdrIndicator(AddrSpace addrSpace, int index) {
  Address indicatorsAddress = Address(addrSpace, Util::getBoolNibb(index));
  bool addressReferenced = isAddressReferenced(indicatorsAddress);
  return view.getLightbulb(addressReferenced);
}

string Renderer::getFormattedOutput(int i) {
  if (printer.getPrinterOutput().length() <= (unsigned) i) {
    return " ";
  } else {
    return string(1, printer.getPrinterOutput().at(i));
  }
}

///////////////////////
/// GET INSTRUCTION ///
///////////////////////

Instruction* Renderer::getInstruction() {
  bool noActiveInstruction = !machineActive() &&
                             cursor.getAddressSpace() == DATA;
  if (noActiveInstruction) {
    return NULL;
  }
  if (instruction.size() == 0) {
    instruction.push_back(initializeInstruction());
  }
  return &instruction[0];
}

bool Renderer::machineActive() {
  bool executionHasntStarted = cpu.getCycle() == 0;
  bool executionEnded = Util::getInt(cpu.getPc()) == RAM_SIZE;
  return !(executionHasntStarted || executionEnded);
}

Instruction Renderer::initializeInstruction() {
  if (machineActive()) {
    return cpu.getInstruction();
  } else {
    return Instruction(cursor.getWord(), EMPTY_WORD, ram);
  }
}

bool Renderer::instructionHasId(int id) {
  Instruction *inst = getInstruction();
  if (inst == NULL) {
    return false;
  }
  return inst->index == id;
}

/*
 * Is instruction pointing to passed address in passed address space.
 */
bool Renderer::instructionPointingToAddress(Address adr) {
  Instruction *inst = getInstruction();
  if (inst == NULL) {
    return false;
  }
  return inst->adr == adr;
}

set<int>* Renderer::getIndexesOfPointingInstructions() {
  if (pointingInstructions.empty()) {
    pointingInstructions = generatePointingInstructions();
    if (pointingInstructions.empty()) {
      pointingInstructions.insert(-1);
    }
  }
  return &pointingInstructions;
}

set<int> Renderer::generatePointingInstructions() {
  vector<Instruction> *allInstructions = getAllInstructions();
  set<int> out;
  int i = 0;
  for (Instruction inst : *allInstructions) {
    if (inst.adr == cursor.getAddress()) {
      out.insert(i);
    }
    i++;
  }
  return out;
}

vector<Instruction>* Renderer::getAllInstructions() {
  if (allInstructions.empty()) {
    for (vector<bool> word : ram.state.at(CODE)) {
      Instruction inst = Instruction(word, cpu.getRegister(), ram);
      allInstructions.push_back(inst);
    }
  }
  return &allInstructions;
}

bool Renderer::isAddressReferenced(Address adr) {
  vector<Instruction> *instructions = getAllInstructions();
  for (Instruction inst : *instructions) {
    if (inst.adr == adr) {
      return true;
    }
  }
  return false;
}<commit_msg>If word with cursor is highlighted, cursor gets inverted<commit_after>#include "renderer.hpp"

#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

#include "addr_space.hpp"
#include "address.hpp"
#include "const.hpp"
#include "cpu.hpp"
#include "cursor.hpp"
#include "drawing2D.hpp"
#include "drawing3D.hpp"
#include "instruction.hpp"
#include "printer.hpp"
#include "ram.hpp"
#include "util.hpp"

using namespace std;

/*
 * Only public method. Also static. It creates new object every time
 * it gets called.
 */
vector<vector<string>> Renderer::renderState(const Printer &printerIn,
                                             const Ram &ramIn,
                                             const Cpu &cpuIn,
                                             const Cursor &cursorIn,
                                             const View &viewIn) {
  Renderer instance(printerIn, ramIn, cpuIn, cursorIn, viewIn);
  vector<vector<string>> out;
  for (vector<string> line : viewIn.lines) {
    out.push_back(instance.insertActualValues(line));
  }
  return out;
}

vector<string> Renderer::insertActualValues(vector<string> lineIn) {
  vector<bool> highlightedChars = getHighlightedLocations(lineIn);
  vector<string> lineOut;
  for (string cIn : lineIn) {
    string sOut;
    bool charIsALightbulb = ALL_INDICATORS.count(cIn);
    if (charIsALightbulb) {
      sOut = getLightbulb(cIn);
    } else {
      sOut = cIn;
    }
    lineOut.push_back(sOut);
  }
  return insertEscSeqences(lineOut, highlightedChars);
}

vector<string> Renderer::insertEscSeqences(
    vector<string> lineWithoutEscapeSeqences, vector<bool> highlightedChars) {
  vector<string> lineOut;
  bool insideHighlightBlock = false;
  for (size_t i = 0; i < lineWithoutEscapeSeqences.size(); i++) {
    bool firstCharInsideBlock = highlightedChars[i] && !insideHighlightBlock;
    if (firstCharInsideBlock) {
      vector<string> highlightEsc = Util::stringToVecOfString(HIGHLIGHT_ESC);
      lineOut.insert(lineOut.end(), highlightEsc.begin(), highlightEsc.end());
      insideHighlightBlock = true;
    }
    bool firstCharOutsideBlock = !highlightedChars[i] && insideHighlightBlock;
    if (firstCharOutsideBlock) {
      vector<string> highlightEscEnd =
          Util::stringToVecOfString(HIGHLIGHT_END_ESC);
      lineOut.insert(lineOut.end(), highlightEscEnd.begin(),
                     highlightEscEnd.end());
      insideHighlightBlock = false;
    }
    lineOut.push_back(lineWithoutEscapeSeqences[i]);
  }
  return lineOut;
}

/////////////////////////////////
/// GET HIGHLIGHTED LOCATIONS ///
/////////////////////////////////

vector<bool> Renderer::getHighlightedLocations(vector<string> lineIn) {
  vector<bool> highlightedLocations (lineIn.size(), false);
  highlightPc(highlightedLocations, lineIn);
  highlightCursor(highlightedLocations, lineIn);
  Instruction *inst = getInstruction();
  if (inst == NULL) {
    highlightPointingInstructions(highlightedLocations, lineIn);
    return highlightedLocations;
  }
  highlightOperator(highlightedLocations, lineIn, inst);
  if (inst->adr.space == CODE) {
    highlightCodeWord(highlightedLocations, lineIn, inst);
  } else if (inst->adr.space == DATA) {
    highlightDataWord(highlightedLocations, lineIn, inst);
  }
  return highlightedLocations;
}

void Renderer::highlightPc(vector<bool> &highlightedLocations,
                                   vector<string> &lineIn) {
  if (!machineActive() || pcHighlighted) {
    return;
  }
  for (size_t i = 0; i < lineIn.size(); i++) {
    if (lineIn[i] == CODE_ADR_INDICATOR) {
      int index = switchIndex[CODE_ADR_INDICATOR];
      if (pcPointingToAddress(index)) {
        highlightedLocations[i] = true;
        pcHighlighted = true;
        return;
      }
    }
  }
}

void Renderer::highlightCursor(vector<bool> &highlightedLocations,
                                       vector<string> &lineIn) {
  if (machineActive() || cursorHighlighted) {
    return;
  }
  if (cursor.getAddressSpace() == CODE) {
    findCursor(highlightedLocations, lineIn, CODE_INDICATOR);
  } else if (cursor.getAddressSpace() == DATA) {
    findCursor(highlightedLocations, lineIn, DATA_INDICATOR);
  }
}

void Renderer::findCursor(vector<bool> &highlightedLocations,
                                  vector<string> &lineIn, string c) {
  int indexDelta = 0;
  for (size_t i = 0; i < lineIn.size(); i++) {
    if (lineIn[i] == c) {
      int lightbulbIndex = switchIndex[c] + indexDelta++;
      if (cursor.getAbsoluteBitIndex() == lightbulbIndex) {
        highlightedLocations[i] = true;
        cursorHighlighted = true;
        return;
      }
    }
  }
}

void Renderer::highlightPointingInstructions(vector<bool> &highlightedLocations,
                                             vector<string> &lineIn) {
  set<int> *pointingInstructions = getIndexesOfPointingInstructions();
  for (size_t i = 0; i < lineIn.size(); i++) {
    if (lineIn[i] == CODE_INDICATOR) {
      int addressValue = switchIndex[CODE_INDICATOR] / WORD_SIZE;
      if (pointingInstructions->count(addressValue)) {
        highlightedLocations[i] = true;
      }
    }
  }
}

void Renderer::highlightOperator(vector<bool> &highlightedLocations,
                                         vector<string> &lineIn,
                                         Instruction *inst) {
  string exclude;
  if (inst->isLogic()) {
    exclude = LOGIC_OPS_INDICATOR[min(inst->logicIndex, 8)];
  }
  if (inst->index == INC_DEC_OPS_INDEX) {
    if (inst->logicIndex <= 7) {
      exclude = "INC";
    } else {
      exclude = "DEC";
    }
  }
  string label = " " + inst->label;
  label.append(11 - inst->label.length(), ' ');
  highlightLabel(highlightedLocations, lineIn, Util::stringToVecOfString(label),
                 Util::stringToVecOfString(exclude));
}

void Renderer::highlightCodeWord(vector<bool> &highlightedLocations,
                                        vector<string> &lineIn,
                                        Instruction *inst) {
  if (inst->adr.val == LAST_ADDRESS) {
    vector<string> stopLabel = Util::stringToVecOfString(LAST_CODE_ADDR_LABEL);
    highlightLabel(highlightedLocations, lineIn, stopLabel, {});
    return;
  }
  highlightWord(highlightedLocations, lineIn, CODE_INDICATOR, CODE);
}

void Renderer::highlightDataWord(vector<bool> &highlightedLocations,
                                         vector<string> &lineIn,
                                         Instruction *inst) {
  if (inst->adr.val == LAST_ADDRESS) {
    vector<string> inOutLabel = Util::stringToVecOfString(LAST_DATA_ADDR_LABEL);
    highlightLabel(highlightedLocations, lineIn, inOutLabel, {});
    return;
  }
  highlightWord(highlightedLocations, lineIn, DATA_INDICATOR, DATA);
}

void Renderer::highlightWord(vector<bool> &highlightedLocations,
                                     vector<string> &lineIn, string indicator,
                                     AddrSpace addrSpace) {
  for (size_t i = 0; i < lineIn.size(); i++) {
    if (lineIn[i] == indicator) {
      int addressValue = switchIndex[indicator] / WORD_SIZE;
      Address adr = Address(addrSpace, Util::getBoolNibb(addressValue));
      if (instructionPointingToAddress(adr)) {
        highlightedLocations[i] = !highlightedLocations[i];
      }
    }
  }
}

void Renderer::highlightLabel(vector<bool> &highlightedLocations,
                                     vector<string> &lineIn,
                                     vector<string> label,
                                     vector<string> exclude) {
  auto it = search(begin(lineIn), end(lineIn), begin(label), end(label));
  int labelPosition = it - lineIn.begin();
  bool notFound = it == end(lineIn);
  if (notFound) {
    return;
  }
  size_t excludePosition = numeric_limits<size_t>::max();
  if (!exclude.empty()) {
    it = search(begin(label), end(label), begin(exclude), end(exclude));
    excludePosition = it - label.begin();
  }
  for (size_t i = labelPosition; i < labelPosition + label.size(); i++) {
    bool highlight = (i < labelPosition + excludePosition ||
                      i >= labelPosition + excludePosition + exclude.size());
    if (highlight) {
      highlightedLocations[i] = true;
    }
  }
}

/////////////////////
/// GET LIGHTBULB ///
/////////////////////

string Renderer::getLightbulb(string cIn) {
  int i = switchIndex[cIn]++;
  if (cIn == CODE_INDICATOR) {
      return getCodeBit(i);
  } else if (cIn == DATA_INDICATOR) {
      return getDataBit(i);
  } else if (cIn == REGISTER_INDICATOR) {
      return view.getLightbulb(cpu.getRegister().at(i));
  } else if (cIn == CODE_ADR_INDICATOR) {
      return getAdrIndicator(CODE, i);
  } else if (cIn == DATA_ADR_INDICATOR) {
      return getAdrIndicator(DATA, i);
  } else if (cIn == OUTPUT_INDICATOR) {
      return getFormattedOutput(i);
  }
  cerr << "There was an error parsing a drawing file.";
  cerr << " Problem with char" << cIn << ". Will ignore it.";
  return " ";
}

string Renderer::getCodeBit(int i) {
  return getCharAt(i, &ram.state[CODE]);
}

string Renderer::getDataBit(int i) {
  return getCharAt(i, &ram.state[DATA]);
}

string Renderer::getCharAt(int i, vector<vector<bool>>* matrix) {
  int j = i / WORD_SIZE;
  i = i % WORD_SIZE;
  return view.getLightbulb((*matrix).at(j).at(i));
}

bool Renderer::pcPointingToAddress(int adr) {
  bool executionHasntStarted = cpu.getCycle() == 0;
  if (executionHasntStarted) {
    return false;
  }
  return Util::getInt(cpu.getPc()) == adr;
}

string Renderer::getAdrIndicator(AddrSpace addrSpace, int index) {
  Address indicatorsAddress = Address(addrSpace, Util::getBoolNibb(index));
  bool addressReferenced = isAddressReferenced(indicatorsAddress);
  return view.getLightbulb(addressReferenced);
}

string Renderer::getFormattedOutput(int i) {
  if (printer.getPrinterOutput().length() <= (unsigned) i) {
    return " ";
  } else {
    return string(1, printer.getPrinterOutput().at(i));
  }
}

///////////////////////
/// GET INSTRUCTION ///
///////////////////////

Instruction* Renderer::getInstruction() {
  bool noActiveInstruction = !machineActive() &&
                             cursor.getAddressSpace() == DATA;
  if (noActiveInstruction) {
    return NULL;
  }
  if (instruction.size() == 0) {
    instruction.push_back(initializeInstruction());
  }
  return &instruction[0];
}

bool Renderer::machineActive() {
  bool executionHasntStarted = cpu.getCycle() == 0;
  bool executionEnded = Util::getInt(cpu.getPc()) == RAM_SIZE;
  return !(executionHasntStarted || executionEnded);
}

Instruction Renderer::initializeInstruction() {
  if (machineActive()) {
    return cpu.getInstruction();
  } else {
    return Instruction(cursor.getWord(), EMPTY_WORD, ram);
  }
}

bool Renderer::instructionHasId(int id) {
  Instruction *inst = getInstruction();
  if (inst == NULL) {
    return false;
  }
  return inst->index == id;
}

/*
 * Is instruction pointing to passed address in passed address space.
 */
bool Renderer::instructionPointingToAddress(Address adr) {
  Instruction *inst = getInstruction();
  if (inst == NULL) {
    return false;
  }
  return inst->adr == adr;
}

set<int>* Renderer::getIndexesOfPointingInstructions() {
  if (pointingInstructions.empty()) {
    pointingInstructions = generatePointingInstructions();
    if (pointingInstructions.empty()) {
      pointingInstructions.insert(-1);
    }
  }
  return &pointingInstructions;
}

set<int> Renderer::generatePointingInstructions() {
  vector<Instruction> *allInstructions = getAllInstructions();
  set<int> out;
  int i = 0;
  for (Instruction inst : *allInstructions) {
    if (inst.adr == cursor.getAddress()) {
      out.insert(i);
    }
    i++;
  }
  return out;
}

vector<Instruction>* Renderer::getAllInstructions() {
  if (allInstructions.empty()) {
    for (vector<bool> word : ram.state.at(CODE)) {
      Instruction inst = Instruction(word, cpu.getRegister(), ram);
      allInstructions.push_back(inst);
    }
  }
  return &allInstructions;
}

bool Renderer::isAddressReferenced(Address adr) {
  vector<Instruction> *instructions = getAllInstructions();
  for (Instruction inst : *instructions) {
    if (inst.adr == adr) {
      return true;
    }
  }
  return false;
}<|endoftext|>


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

#include <bsoncxx/oid.hpp>

#include <cstring>

#include <bson.h>

#include <bsoncxx/config/prelude.hpp>

namespace bsoncxx {
BSONCXX_INLINE_NAMESPACE_BEGIN

oid::oid() : _is_valid(false) {
}

oid::oid(init_tag_t) : _is_valid(true) {
    bson_oid_t oid;
    bson_oid_init(&oid, nullptr);

    std::memcpy(_bytes, oid.bytes, sizeof(oid.bytes));
}

oid::oid(stdx::string_view str) : _is_valid(bson_oid_is_valid(str.data(), str.length())) {
    if (_is_valid) {
        bson_oid_t oid;
        bson_oid_init_from_string(&oid, str.data());
        memcpy(_bytes, oid.bytes, sizeof(_bytes));
    }
}

oid::oid(const char* bytes, std::size_t len) : _is_valid(len == 12) {
    if (_is_valid) {
        std::memcpy(_bytes, bytes, sizeof(_bytes));
    }
}

std::string oid::to_string() const {
    bson_oid_t oid;
    std::memcpy(oid.bytes, _bytes, sizeof(oid.bytes));
    char str[25];

    bson_oid_to_string(&oid, str);

    return std::string(str);
}

oid::operator bool() const {
    return _is_valid;
}

std::time_t oid::get_time_t() const {
    bson_oid_t oid;
    std::memcpy(oid.bytes, _bytes, sizeof(oid.bytes));

    return bson_oid_get_time_t(&oid);
}

const char* oid::bytes() const {
    return _bytes;
}

int oid_compare(const oid& lhs, const oid& rhs) {
    if (!lhs._is_valid || !rhs._is_valid) {
        if (lhs._is_valid) {
            return 1;
        } else if (rhs._is_valid) {
            return -1;
        } else {
            return 0;
        }
    }

    bson_oid_t lhs_oid;
    bson_oid_t rhs_oid;

    std::memcpy(lhs_oid.bytes, lhs.bytes(), sizeof(lhs_oid.bytes));
    std::memcpy(rhs_oid.bytes, rhs.bytes(), sizeof(rhs_oid.bytes));

    return bson_oid_compare(&lhs_oid, &rhs_oid);
}

bool operator<(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) < 0;
}

bool operator>(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) > 0;
}

bool operator<=(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) <= 0;
}

bool operator>=(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) >= 0;
}

bool operator==(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) == 0;
}

bool operator!=(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) != 0;
}

std::ostream& operator<<(std::ostream& out, const oid& rhs) {
    bson_oid_t oid;
    std::memcpy(oid.bytes, rhs._bytes, sizeof(oid.bytes));
    char str[25];

    bson_oid_to_string(&oid, str);

    out << str;

    return out;
}

BSONCXX_INLINE_NAMESPACE_END
}  // namespace bsoncxx
<commit_msg>minor: add <ostream> header to bsoncxx/oid.cpp<commit_after>// Copyright 2014 MongoDB Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <bsoncxx/oid.hpp>

#include <cstring>
#include <ostream>

#include <bson.h>

#include <bsoncxx/config/prelude.hpp>

namespace bsoncxx {
BSONCXX_INLINE_NAMESPACE_BEGIN

oid::oid() : _is_valid(false) {
}

oid::oid(init_tag_t) : _is_valid(true) {
    bson_oid_t oid;
    bson_oid_init(&oid, nullptr);

    std::memcpy(_bytes, oid.bytes, sizeof(oid.bytes));
}

oid::oid(stdx::string_view str) : _is_valid(bson_oid_is_valid(str.data(), str.length())) {
    if (_is_valid) {
        bson_oid_t oid;
        bson_oid_init_from_string(&oid, str.data());
        memcpy(_bytes, oid.bytes, sizeof(_bytes));
    }
}

oid::oid(const char* bytes, std::size_t len) : _is_valid(len == 12) {
    if (_is_valid) {
        std::memcpy(_bytes, bytes, sizeof(_bytes));
    }
}

std::string oid::to_string() const {
    bson_oid_t oid;
    std::memcpy(oid.bytes, _bytes, sizeof(oid.bytes));
    char str[25];

    bson_oid_to_string(&oid, str);

    return std::string(str);
}

oid::operator bool() const {
    return _is_valid;
}

std::time_t oid::get_time_t() const {
    bson_oid_t oid;
    std::memcpy(oid.bytes, _bytes, sizeof(oid.bytes));

    return bson_oid_get_time_t(&oid);
}

const char* oid::bytes() const {
    return _bytes;
}

int oid_compare(const oid& lhs, const oid& rhs) {
    if (!lhs._is_valid || !rhs._is_valid) {
        if (lhs._is_valid) {
            return 1;
        } else if (rhs._is_valid) {
            return -1;
        } else {
            return 0;
        }
    }

    bson_oid_t lhs_oid;
    bson_oid_t rhs_oid;

    std::memcpy(lhs_oid.bytes, lhs.bytes(), sizeof(lhs_oid.bytes));
    std::memcpy(rhs_oid.bytes, rhs.bytes(), sizeof(rhs_oid.bytes));

    return bson_oid_compare(&lhs_oid, &rhs_oid);
}

bool operator<(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) < 0;
}

bool operator>(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) > 0;
}

bool operator<=(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) <= 0;
}

bool operator>=(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) >= 0;
}

bool operator==(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) == 0;
}

bool operator!=(const oid& lhs, const oid& rhs) {
    return oid_compare(lhs, rhs) != 0;
}

std::ostream& operator<<(std::ostream& out, const oid& rhs) {
    bson_oid_t oid;
    std::memcpy(oid.bytes, rhs._bytes, sizeof(oid.bytes));
    char str[25];

    bson_oid_to_string(&oid, str);

    out << str;

    return out;
}

BSONCXX_INLINE_NAMESPACE_END
}  // namespace bsoncxx
<|endoftext|>


<commit_before>/*!
 * This file is part of CameraPlus.
 *
 * Copyright (C) 2012-2014 Mohammed Sameer <msameer@foolab.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "settings.h"
#include <QSettings>
#include <QDir>
#include "devicesettings.h"

#ifdef SAILFISH
#define PATH QString("%1%2.config%2harbour-cameraplus%2harbour-cameraplus.conf").arg(QDir::homePath()).arg(QDir::separator())
#else
#define PATH QString("%1%2.config%2cameraplus.conf").arg(QDir::homePath()).arg(QDir::separator())
#endif

#define DEFAULT_MODE                      1
#define DEFAULT_USE_GPS                   true
#define DEFAULT_USE_GEOTAGS               true
#define DEFAULT_SOUND_ENABLED             true
#define DEFAULT_SHOW_TOOL_BAR             false
#define DEFAULT_VIDEO_MUTE                false
#define DEFAULT_GRID_ENABLED              false
#define DEFAULT_FACE_DETECTION_ENABLED    true
#define DEFAULT_ZOOM_AS_SHUTTER           false
#define DEFAULT_PROXIMITY_AS_SHUTTER      false
#define DEFAULT_DEVICE                    0
#define DEFAULT_ENABLE_PREVIEW            true
#define DEFAULT_NIGHT_MODE                false
#define DEFAULT_PLUGIN                    "org.foolab.cameraplus.image"
#define DEFAULT_CAPTURE_TIMER_DELAY       5
#define DEFAULT_LEFT_HANDED_MODE          false
#define DEFAULT_SEQUENTIAL_SHOTS_COUNT    5
#define DEFAULT_SEQUENTIAL_SHOTS_INTERVAL 5
#define DEFAULT_SEQUENTIAL_SHOTS_DELAY    5
#define DEFAULT_SEQUENTIAL_SHOTS_FOCUS    true

Settings::Settings(QObject *parent) :
  QObject(parent),
  m_settings(new QSettings(PATH, QSettings::IniFormat, this)) {

}

Settings::~Settings() {
  delete m_settings; m_settings = 0;
}

int Settings::mode() const {
  return m_settings->value("camera/mode", DEFAULT_MODE).toInt();
}

void Settings::setMode(int mode) {
  if (mode != Settings::mode()) {
    m_settings->setValue("camera/mode", mode);

    emit modeChanged();
  }
}

QString Settings::creatorName() const {
  return m_settings->value("camera/creatorName").toString();
}

void Settings::setCreatorName(const QString& name) {
  if (name != creatorName()) {
    m_settings->setValue("camera/creatorName", name);

    emit creatorNameChanged();
  }
}

bool Settings::useGps() const {
  return m_settings->value("camera/useGps", DEFAULT_USE_GPS).toBool();
}

void Settings::setUseGps(bool enable) {
  if (enable != useGps()) {
    m_settings->setValue("camera/useGps", enable);

    emit useGpsChanged();
  }
}

bool Settings::useGeotags() const {
  return m_settings->value("camera/useGeotags", DEFAULT_USE_GEOTAGS).toBool();
}

void Settings::setUseGeotags(bool enable) {
  if (enable != useGeotags()) {
    m_settings->setValue("camera/useGeotags", enable);

    emit useGeotagsChanged();
  }
}

bool Settings::isSoundEnabled() const {
  return m_settings->value("camera/soundEnabled", DEFAULT_SOUND_ENABLED).toBool();
}

void Settings::setSoundEnabled(bool enabled) {
  if (isSoundEnabled() != enabled) {
    m_settings->setValue("camera/soundEnabled", enabled);
    emit soundEnabledChanged();
  }
}

bool Settings::isToolBarShown() const {
  return m_settings->value("camera/showToolBar", DEFAULT_SHOW_TOOL_BAR).toBool();
}

void Settings::setToolBarShown(bool shown) {
  if (isToolBarShown() != shown) {
    m_settings->setValue("camera/showToolBar", shown);

    emit toolBarShownChanged();
  }
}

bool Settings::isGridEnabled() const {
  return m_settings->value("camera/gridEnabled", DEFAULT_GRID_ENABLED).toBool();
}

void Settings::setGridEnabled(bool enabled) {
  if (enabled != isGridEnabled()) {
    m_settings->setValue("camera/gridEnabled", enabled);
    emit gridEnabledChanged();
  }
}

bool Settings::isFaceDetectionEnabled() const {
  return m_settings->value("image/faceDetectionEnabled", DEFAULT_FACE_DETECTION_ENABLED).toBool();
}

void Settings::setFaceDetectionEnabled(bool enabled) {
  if (isFaceDetectionEnabled() != enabled) {
    m_settings->setValue("image/faceDetectionEnabled", enabled);
    emit faceDetectionEnabledChanged();
  }
}

bool Settings::isZoomAsShutterEnabled() const {
  return m_settings->value("camera/zoomAsShutter", DEFAULT_ZOOM_AS_SHUTTER).toBool();
}

void Settings::setZoomAsShutterEnabled(bool enabled) {
  if (isZoomAsShutterEnabled() != enabled) {
    m_settings->setValue("camera/zoomAsShutter", enabled);

    emit zoomAsShutterChanged();
  }
}

bool Settings::isProximityAsShutterEnabled() const {
  return m_settings->value("camera/proximityAsShutter", DEFAULT_PROXIMITY_AS_SHUTTER).toBool();
}

void Settings::setProximityAsShutterEnabled(bool enabled) {
  if (isProximityAsShutterEnabled() != enabled) {
    m_settings->setValue("camera/proximityAsShutter", enabled);

    emit proximityAsShutterChanged();
  }
}

int Settings::device() const {
  return m_settings->value("camera/device", DEFAULT_DEVICE).toInt();
}

void Settings::setDevice(int device) {
  if (device != Settings::device()) {
    m_settings->setValue("camera/device", device);
    emit deviceChanged();
  }
}

QVariant Settings::value(const QString& key, const QVariant& defaultValue) const {
  return m_settings->value(key, defaultValue);
}

void Settings::setValue(const QString& key, const QVariant& value)  {
  m_settings->setValue(key, value);
}

QString Settings::fileNamingStamp(const QString& id) const {
  QString key = QString("fileNaming/%1").arg(id);
  return m_settings->value(key).toString();
}

void Settings::setFileNamingStamp(const QString& id, const QString& stamp) {
  QString key = QString("fileNaming/%1").arg(id);
  m_settings->setValue(key, stamp);
}

int Settings::fileNamingCounter(const QString& id) const {
  QString key = QString("fileNaming/%1").arg(id);
  return m_settings->value(key).toInt();
}

void Settings::setFileNamingCounter(const QString& id, int counter) {
  QString key = QString("fileNaming/%1").arg(id);
  m_settings->setValue(key, counter);
}

bool Settings::isPreviewEnabled() const {
  return m_settings->value("camera/enablePreview", DEFAULT_ENABLE_PREVIEW).toBool();
}

void Settings::setPreviewEnabled(bool enabled) {
  if (enabled != isPreviewEnabled()) {
    m_settings->setValue("camera/enablePreview", enabled);

    emit previewEnabledChanged();
  }
}

bool Settings::isNightModeEnabled() const {
  return m_settings->value("camera/nightMode", DEFAULT_NIGHT_MODE).toBool();
}

void Settings::setNightModeEnabled(bool enabled) {
  if (isNightModeEnabled() != enabled) {
    m_settings->setValue("camera/nightMode", enabled);
    emit nightModeChanged();
  }
}

QString Settings::plugin() const {
  return m_settings->value("camera/plugin", DEFAULT_PLUGIN).toString();
}

void Settings::setPlugin(const QString& plugin) {
  if (Settings::plugin() != plugin) {
    m_settings->setValue("camera/plugin", plugin);
    emit pluginChanged();
  }
}

int Settings::captureTimerDelay() const {
  return m_settings->value("captureTimer/delay", DEFAULT_CAPTURE_TIMER_DELAY).toInt();
}

void Settings::setCaptureTimerDelay(int delay) {
  if (delay != captureTimerDelay()) {
    m_settings->setValue("captureTimer/delay", delay);
    emit captureTimerDelayChanged();
  }
}

bool Settings::isLeftHandedModeEnabled() {
  return m_settings->value("camera/leftHandedMode", DEFAULT_LEFT_HANDED_MODE).toBool();
}

void Settings::setLeftHandedModeEnabled(bool enabled) {
  if (isLeftHandedModeEnabled() != enabled) {
    m_settings->setValue("camera/leftHandedMode", enabled);

    emit leftHandedModeChanged();
  }
}

int Settings::sequentialShotsCount() const {
  return m_settings->value("sequentialShots/count", DEFAULT_SEQUENTIAL_SHOTS_COUNT).toInt();
}

void Settings::setSequentialShotsCount(int count) {
  if (sequentialShotsCount() != count) {
    m_settings->setValue("sequentialShots/count", count);
    emit sequentialShotsCountChanged();
  }
}

int Settings::sequentialShotsInterval() const {
  return m_settings->value("sequentialShots/interval", DEFAULT_SEQUENTIAL_SHOTS_INTERVAL).toInt();
}

void Settings::setSequentialShotsInterval(int interval) {
  if (sequentialShotsInterval() != interval) {
    m_settings->setValue("sequentialShots/interval", interval);
    emit sequentialShotsIntervalChanged();
  }
}

int Settings::sequentialShotsDelay() const {
  return m_settings->value("sequentialShots/delay", DEFAULT_SEQUENTIAL_SHOTS_DELAY).toInt();
}

void Settings::setSequentialShotsDelay(int delay) {
  if (sequentialShotsDelay() != delay) {
    m_settings->setValue("sequentialShots/delay", delay);
    emit sequentialShotsDelayChanged();
  }
}

bool Settings::isFocusBeforeSequentialShotsEnabled() const {
  return m_settings->value("sequentialShots/focus", DEFAULT_SEQUENTIAL_SHOTS_FOCUS).toBool();
}

void Settings::setFocusBeforeSequentialShotsEnabled(bool enabled) {
  if (isFocusBeforeSequentialShotsEnabled() != enabled) {
    m_settings->setValue("sequentialShots/focus", enabled);
    emit focusBeforeSequentialShotsChanged();
  }
}
<commit_msg>sequential: change DEFAULT_SEQUENTIAL_SHOTS_DELAY to 0<commit_after>/*!
 * This file is part of CameraPlus.
 *
 * Copyright (C) 2012-2014 Mohammed Sameer <msameer@foolab.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "settings.h"
#include <QSettings>
#include <QDir>
#include "devicesettings.h"

#ifdef SAILFISH
#define PATH QString("%1%2.config%2harbour-cameraplus%2harbour-cameraplus.conf").arg(QDir::homePath()).arg(QDir::separator())
#else
#define PATH QString("%1%2.config%2cameraplus.conf").arg(QDir::homePath()).arg(QDir::separator())
#endif

#define DEFAULT_MODE                      1
#define DEFAULT_USE_GPS                   true
#define DEFAULT_USE_GEOTAGS               true
#define DEFAULT_SOUND_ENABLED             true
#define DEFAULT_SHOW_TOOL_BAR             false
#define DEFAULT_VIDEO_MUTE                false
#define DEFAULT_GRID_ENABLED              false
#define DEFAULT_FACE_DETECTION_ENABLED    true
#define DEFAULT_ZOOM_AS_SHUTTER           false
#define DEFAULT_PROXIMITY_AS_SHUTTER      false
#define DEFAULT_DEVICE                    0
#define DEFAULT_ENABLE_PREVIEW            true
#define DEFAULT_NIGHT_MODE                false
#define DEFAULT_PLUGIN                    "org.foolab.cameraplus.image"
#define DEFAULT_CAPTURE_TIMER_DELAY       5
#define DEFAULT_LEFT_HANDED_MODE          false
#define DEFAULT_SEQUENTIAL_SHOTS_COUNT    5
#define DEFAULT_SEQUENTIAL_SHOTS_INTERVAL 5
#define DEFAULT_SEQUENTIAL_SHOTS_DELAY    0
#define DEFAULT_SEQUENTIAL_SHOTS_FOCUS    true

Settings::Settings(QObject *parent) :
  QObject(parent),
  m_settings(new QSettings(PATH, QSettings::IniFormat, this)) {

}

Settings::~Settings() {
  delete m_settings; m_settings = 0;
}

int Settings::mode() const {
  return m_settings->value("camera/mode", DEFAULT_MODE).toInt();
}

void Settings::setMode(int mode) {
  if (mode != Settings::mode()) {
    m_settings->setValue("camera/mode", mode);

    emit modeChanged();
  }
}

QString Settings::creatorName() const {
  return m_settings->value("camera/creatorName").toString();
}

void Settings::setCreatorName(const QString& name) {
  if (name != creatorName()) {
    m_settings->setValue("camera/creatorName", name);

    emit creatorNameChanged();
  }
}

bool Settings::useGps() const {
  return m_settings->value("camera/useGps", DEFAULT_USE_GPS).toBool();
}

void Settings::setUseGps(bool enable) {
  if (enable != useGps()) {
    m_settings->setValue("camera/useGps", enable);

    emit useGpsChanged();
  }
}

bool Settings::useGeotags() const {
  return m_settings->value("camera/useGeotags", DEFAULT_USE_GEOTAGS).toBool();
}

void Settings::setUseGeotags(bool enable) {
  if (enable != useGeotags()) {
    m_settings->setValue("camera/useGeotags", enable);

    emit useGeotagsChanged();
  }
}

bool Settings::isSoundEnabled() const {
  return m_settings->value("camera/soundEnabled", DEFAULT_SOUND_ENABLED).toBool();
}

void Settings::setSoundEnabled(bool enabled) {
  if (isSoundEnabled() != enabled) {
    m_settings->setValue("camera/soundEnabled", enabled);
    emit soundEnabledChanged();
  }
}

bool Settings::isToolBarShown() const {
  return m_settings->value("camera/showToolBar", DEFAULT_SHOW_TOOL_BAR).toBool();
}

void Settings::setToolBarShown(bool shown) {
  if (isToolBarShown() != shown) {
    m_settings->setValue("camera/showToolBar", shown);

    emit toolBarShownChanged();
  }
}

bool Settings::isGridEnabled() const {
  return m_settings->value("camera/gridEnabled", DEFAULT_GRID_ENABLED).toBool();
}

void Settings::setGridEnabled(bool enabled) {
  if (enabled != isGridEnabled()) {
    m_settings->setValue("camera/gridEnabled", enabled);
    emit gridEnabledChanged();
  }
}

bool Settings::isFaceDetectionEnabled() const {
  return m_settings->value("image/faceDetectionEnabled", DEFAULT_FACE_DETECTION_ENABLED).toBool();
}

void Settings::setFaceDetectionEnabled(bool enabled) {
  if (isFaceDetectionEnabled() != enabled) {
    m_settings->setValue("image/faceDetectionEnabled", enabled);
    emit faceDetectionEnabledChanged();
  }
}

bool Settings::isZoomAsShutterEnabled() const {
  return m_settings->value("camera/zoomAsShutter", DEFAULT_ZOOM_AS_SHUTTER).toBool();
}

void Settings::setZoomAsShutterEnabled(bool enabled) {
  if (isZoomAsShutterEnabled() != enabled) {
    m_settings->setValue("camera/zoomAsShutter", enabled);

    emit zoomAsShutterChanged();
  }
}

bool Settings::isProximityAsShutterEnabled() const {
  return m_settings->value("camera/proximityAsShutter", DEFAULT_PROXIMITY_AS_SHUTTER).toBool();
}

void Settings::setProximityAsShutterEnabled(bool enabled) {
  if (isProximityAsShutterEnabled() != enabled) {
    m_settings->setValue("camera/proximityAsShutter", enabled);

    emit proximityAsShutterChanged();
  }
}

int Settings::device() const {
  return m_settings->value("camera/device", DEFAULT_DEVICE).toInt();
}

void Settings::setDevice(int device) {
  if (device != Settings::device()) {
    m_settings->setValue("camera/device", device);
    emit deviceChanged();
  }
}

QVariant Settings::value(const QString& key, const QVariant& defaultValue) const {
  return m_settings->value(key, defaultValue);
}

void Settings::setValue(const QString& key, const QVariant& value)  {
  m_settings->setValue(key, value);
}

QString Settings::fileNamingStamp(const QString& id) const {
  QString key = QString("fileNaming/%1").arg(id);
  return m_settings->value(key).toString();
}

void Settings::setFileNamingStamp(const QString& id, const QString& stamp) {
  QString key = QString("fileNaming/%1").arg(id);
  m_settings->setValue(key, stamp);
}

int Settings::fileNamingCounter(const QString& id) const {
  QString key = QString("fileNaming/%1").arg(id);
  return m_settings->value(key).toInt();
}

void Settings::setFileNamingCounter(const QString& id, int counter) {
  QString key = QString("fileNaming/%1").arg(id);
  m_settings->setValue(key, counter);
}

bool Settings::isPreviewEnabled() const {
  return m_settings->value("camera/enablePreview", DEFAULT_ENABLE_PREVIEW).toBool();
}

void Settings::setPreviewEnabled(bool enabled) {
  if (enabled != isPreviewEnabled()) {
    m_settings->setValue("camera/enablePreview", enabled);

    emit previewEnabledChanged();
  }
}

bool Settings::isNightModeEnabled() const {
  return m_settings->value("camera/nightMode", DEFAULT_NIGHT_MODE).toBool();
}

void Settings::setNightModeEnabled(bool enabled) {
  if (isNightModeEnabled() != enabled) {
    m_settings->setValue("camera/nightMode", enabled);
    emit nightModeChanged();
  }
}

QString Settings::plugin() const {
  return m_settings->value("camera/plugin", DEFAULT_PLUGIN).toString();
}

void Settings::setPlugin(const QString& plugin) {
  if (Settings::plugin() != plugin) {
    m_settings->setValue("camera/plugin", plugin);
    emit pluginChanged();
  }
}

int Settings::captureTimerDelay() const {
  return m_settings->value("captureTimer/delay", DEFAULT_CAPTURE_TIMER_DELAY).toInt();
}

void Settings::setCaptureTimerDelay(int delay) {
  if (delay != captureTimerDelay()) {
    m_settings->setValue("captureTimer/delay", delay);
    emit captureTimerDelayChanged();
  }
}

bool Settings::isLeftHandedModeEnabled() {
  return m_settings->value("camera/leftHandedMode", DEFAULT_LEFT_HANDED_MODE).toBool();
}

void Settings::setLeftHandedModeEnabled(bool enabled) {
  if (isLeftHandedModeEnabled() != enabled) {
    m_settings->setValue("camera/leftHandedMode", enabled);

    emit leftHandedModeChanged();
  }
}

int Settings::sequentialShotsCount() const {
  return m_settings->value("sequentialShots/count", DEFAULT_SEQUENTIAL_SHOTS_COUNT).toInt();
}

void Settings::setSequentialShotsCount(int count) {
  if (sequentialShotsCount() != count) {
    m_settings->setValue("sequentialShots/count", count);
    emit sequentialShotsCountChanged();
  }
}

int Settings::sequentialShotsInterval() const {
  return m_settings->value("sequentialShots/interval", DEFAULT_SEQUENTIAL_SHOTS_INTERVAL).toInt();
}

void Settings::setSequentialShotsInterval(int interval) {
  if (sequentialShotsInterval() != interval) {
    m_settings->setValue("sequentialShots/interval", interval);
    emit sequentialShotsIntervalChanged();
  }
}

int Settings::sequentialShotsDelay() const {
  return m_settings->value("sequentialShots/delay", DEFAULT_SEQUENTIAL_SHOTS_DELAY).toInt();
}

void Settings::setSequentialShotsDelay(int delay) {
  if (sequentialShotsDelay() != delay) {
    m_settings->setValue("sequentialShots/delay", delay);
    emit sequentialShotsDelayChanged();
  }
}

bool Settings::isFocusBeforeSequentialShotsEnabled() const {
  return m_settings->value("sequentialShots/focus", DEFAULT_SEQUENTIAL_SHOTS_FOCUS).toBool();
}

void Settings::setFocusBeforeSequentialShotsEnabled(bool enabled) {
  if (isFocusBeforeSequentialShotsEnabled() != enabled) {
    m_settings->setValue("sequentialShots/focus", enabled);
    emit focusBeforeSequentialShotsChanged();
  }
}
<|endoftext|>


<commit_before>/**
 * @file decision_stump_impl.hpp
 * @author Udit Saxena
 *
 * Implementation of DecisionStump class.
 */

#ifndef __MLPACK_METHODS_DECISION_STUMP_DECISION_STUMP_IMPL_HPP
#define __MLPACK_METHODS_DECISION_STUMP_DECISION_STUMP_IMPL_HPP

// In case it hasn't been included yet.
#include "decision_stump.hpp"

#include <set>
#include <algorithm>

namespace mlpack {
namespace decision_stump {

/**
 * Constructor. Train on the provided data. Generate a decision stump from data.
 *
 * @param data Input, training data.
 * @param labels Labels of data.
 * @param classes Number of distinct classes in labels.
 * @param inpBucketSize Minimum size of bucket when splitting.
 */
template<typename MatType>
DecisionStump<MatType>::DecisionStump(const MatType& data,
                                      const arma::Row<size_t>& labels,
                                      const size_t classes,
                                      size_t inpBucketSize)
{
  arma::Row<size_t> zLabels(labels.n_elem);
  zLabels.fill(0);
  classLabels = labels + zLabels;

  numClass = classes;
  bucketSize = inpBucketSize;

  /* Check whether the input labels are not all identical. */
  if (!isDistinct<size_t>(classLabels))
  {
    // If the classLabels are all identical, the default class is the only
    // class.
    oneClass = true;
    defaultClass = classLabels(0);
  }

  else
  {
    // If classLabels are not all identical, proceed with training.
    oneClass = false;
    int bestAtt = -1;
    double entropy;
    double bestEntropy = DBL_MAX;

    // Set the default class to handle attribute values which are not present in
    // the training data.
    defaultClass = CountMostFreq<size_t>(classLabels);

    for (int i = 0; i < data.n_rows; i++)
    {
      // Go through each attribute of the data.
      if (isDistinct<double>(data.row(i)))
      {
        // For each attribute with non-identical values, treat it as a potential
        // splitting attribute and calculate entropy if split on it.
        entropy = SetupSplitAttribute(data.row(i));

        // Find the attribute with the bestEntropy so that the gain is
        // maximized.
        if (entropy < bestEntropy)
        {
          bestAtt = i;
          bestEntropy = entropy;
        }
      }
    }
    splitCol = bestAtt;

    // Once the splitting column/attribute has been decided, train on it.
    TrainOnAtt<double>(data.row(splitCol));
  }
}

/**
 * Classification function. After training, classify test, and put the predicted
 * classes in predictedLabels.
 *
 * @param test Testing data or data to classify.
 * @param predictedLabels Vector to store the predicted classes after
 *      classifying test
 */
template<typename MatType>
void DecisionStump<MatType>::Classify(const MatType& test,
                                      arma::Row<size_t>& predictedLabels)
{
  bool flag;
  double val;
  if (!oneClass)
  {
    for (int i = 0; i < test.n_cols; i++)
    {
      int j = 0;
      flag = false;

      val = test(splitCol,i);
      while ((j < split.n_rows) && (!flag))
      {
        if (val < split(j, 0) && (!j))
        {
          predictedLabels(i) = split(0, 1);
          flag = true;
        }
        else if (val >= split(j, 0))
        {
          if (j == split.n_rows - 1)
          {
            predictedLabels(i) = split(split.n_rows - 1, 1);
            flag = true;
          }
          else if (val < split(j + 1, 0))
          {
            predictedLabels(i) = split(j, 1);
            flag = true;
          }
        }
        j++;
      }
    }
  }
  else
  {
    for (int i = 0; i < test.n_cols; i++)
      predictedLabels(i) = defaultClass;
  }
}

/**
 * Sets up attribute as if it were splitting on it and finds entropy when
 * splitting on attribute.
 *
 * @param attribute A row from the training data, which might be a candidate for
 *      the splitting attribute.
 */
template <typename MatType>
double DecisionStump<MatType>::SetupSplitAttribute(const arma::rowvec& attribute)
{
  int i, count, begin, end;
  double entropy = 0.0;

  // Sort the attribute in order to calculate splitting ranges.
  arma::rowvec sortedAtt = arma::sort(attribute);

  // Store the indices of the sorted attribute to build a vector of sorted
  // labels.  This sort is stable.
  arma::uvec sortedIndexAtt = arma::stable_sort_index(attribute.t());

  arma::Row<size_t> sortedLabels(attribute.n_elem);
  sortedLabels.fill(0);

  for (i = 0; i < attribute.n_elem; i++)
    sortedLabels(i) = classLabels(sortedIndexAtt(i));

  arma::rowvec subColLabels;
  arma::rowvec subColAtts;

  i = 0;
  count = 0;

  // This splits the sorted into buckets of size greater than or equal to
  // inpBucketSize.
  while (i < sortedLabels.n_elem)
  {
    count++;
    if (i == sortedLabels.n_elem - 1)
    {
      begin = i - count + 1;
      end = i;

      arma::rowvec zSubColLabels((sortedLabels.cols(begin, end)).n_elem);
      zSubColLabels.fill(0.0);

      arma::rowvec zSubColAtts((sortedAtt.cols(begin, end)).n_elem);
      zSubColAtts.fill(0.0);

      subColLabels = sortedLabels.cols(begin, end) + zSubColLabels;

      subColAtts = sortedAtt.cols(begin, end) + zSubColAtts;

      entropy += CalculateEntropy(subColAtts, subColLabels);
      i++;
    }
    else if (sortedLabels(i) != sortedLabels(i + 1))
    {
      if (count < bucketSize)
      {
        begin = i - count + 1;
        end = begin + bucketSize - 1;

        if (end > sortedLabels.n_elem - 1)
          end = sortedLabels.n_elem - 1;
      }
      else
      {
        begin = i - count + 1;
        end = i;
      }

      arma::rowvec zSubColLabels((sortedLabels.cols(begin, end)).n_elem);
      zSubColLabels.fill(0.0);

      arma::rowvec zSubColAtts((sortedAtt.cols(begin, end)).n_elem);
      zSubColAtts.fill(0.0);

      subColLabels = sortedLabels.cols(begin, end) + zSubColLabels;

      subColAtts = sortedAtt.cols(begin, end) + zSubColAtts;

      // Now use subColLabels and subColAtts to calculate entropy.
      entropy += CalculateEntropy(subColAtts, subColLabels);

      i = end + 1;
      count = 0;
    }
    else
      i++;
  }
  return entropy;
}

/**
 * After having decided the attribute on which to split, train on that
 * attribute.
 *
 * @param attribute Attribute is the attribute decided by the constructor on
 *      which we now train the decision stump.
 */
template <typename MatType>
template <typename rType>
void DecisionStump<MatType>::TrainOnAtt(const arma::rowvec& attribute)
{
  int i, count, begin, end;

  arma::rowvec sortedSplitAtt = arma::sort(attribute);
  arma::uvec sortedSplitIndexAtt = arma::stable_sort_index(attribute.t());
  arma::Row<size_t> sortedLabels(attribute.n_elem);
  sortedLabels.fill(0);
  arma::mat tempSplit;

  for (i = 0; i < attribute.n_elem; i++)
    sortedLabels(i) = classLabels(sortedSplitIndexAtt(i));

  arma::rowvec subCols;
  rType mostFreq;
  i = 0;
  count = 0;
  while (i < sortedLabels.n_elem)
  {
    count++;
    if (i == sortedLabels.n_elem - 1)
    {
      begin = i - count + 1;
      end = i;

      arma::rowvec zSubCols((sortedLabels.cols(begin, end)).n_elem);
      zSubCols.fill(0.0);

      subCols = sortedLabels.cols(begin, end) + zSubCols;

      mostFreq = CountMostFreq<double>(subCols);

      tempSplit << sortedSplitAtt(begin)<< mostFreq << arma::endr;
      split = arma::join_cols(split, tempSplit);

      i++;
    }
    else if (sortedLabels(i) != sortedLabels(i + 1))
    {
      if (count < bucketSize)
      {
        // Test for different values of bucketSize, especially extreme cases.
        begin = i - count + 1;
        end = begin + bucketSize - 1;

        if (end > sortedLabels.n_elem - 1)
          end = sortedLabels.n_elem - 1;
      }
      else
      {
        begin = i - count + 1;
        end = i;
      }
      arma::rowvec zSubCols((sortedLabels.cols(begin, end)).n_elem);
      zSubCols.fill(0.0);

      subCols = sortedLabels.cols(begin, end) + zSubCols;

      // Find the most frequent element in subCols so as to assign a label to
      // the bucket of subCols.
      mostFreq = CountMostFreq<double>(subCols);

      tempSplit << sortedSplitAtt(begin) << mostFreq << arma::endr;
      split = arma::join_cols(split, tempSplit);

      i = end + 1;
      count = 0;
    }
    else
      i++;
  }

  // Now trim the split matrix so that buckets one after the after which point
  // to the same classLabel are merged as one big bucket.
  MergeRanges();
}

/**
 * After the "split" matrix has been set up, merge ranges with identical class
 * labels.
 */
template <typename MatType>
void DecisionStump<MatType>::MergeRanges()
{
  for (int i = 1; i < split.n_rows; i++)
  {
    if (split(i, 1) == split(i - 1, 1))
    {
      // Remove this row, as it has the same label as the previous bucket.
      split.shed_row(i);
      // Go back to previous row.
      i--;
    }
  }
}

template <typename MatType>
template <typename rType>
rType DecisionStump<MatType>::CountMostFreq(const arma::Row<rType>& subCols)
{
  // Sort subCols for easier processing.
  arma::Row<rType> sortCounts = arma::sort(subCols);
  rType element;
  int count = 0, localCount = 0;

  // An O(n) loop which counts the most frequent element in sortCounts
  for (int i = 0; i < sortCounts.n_elem; ++i)
  {
    if (i == sortCounts.n_elem - 1)
    {
      if (sortCounts(i - 1) == sortCounts(i))
      {
        // element = sortCounts(i - 1);
        localCount++;
      }
      else if (localCount > count)
        count = localCount;
    }
    else if (sortCounts(i) != sortCounts(i + 1))
    {
      localCount = 0;
      count++;
    }
    else
    {
      localCount++;
      if (localCount > count)
      {
        count = localCount;
        if (localCount == 1)
          element = sortCounts(i);
      }
    }
  }
  return element;
}

/**
 * Returns 1 if all the values of featureRow are not same.
 *
 * @param featureRow The attribute which is checked for identical values.
 */
template <typename MatType>
template <typename rType>
int DecisionStump<MatType>::isDistinct(const arma::Row<rType>& featureRow)
{
  if (featureRow.max() - featureRow.min() > 0)
    return 1;
  else
    return 0;
}

/**
 * Calculating Entropy of attribute.
 *
 * @param attribute The attribute for which we calculate the entropy.
 * @param labels Corresponding labels of the attribute.
 */
template<typename MatType>
double DecisionStump<MatType>::CalculateEntropy(const arma::rowvec& attribute,
                                                const arma::rowvec& labels)
{
  double entropy = 0.0;

  arma::rowvec uniqueAtt = arma::unique(attribute);
  arma::rowvec uniqueLabel = arma::unique(labels);
  arma::Row<size_t> numElem(uniqueAtt.n_elem);
  numElem.fill(0);
  arma::Mat<size_t> entropyArray(uniqueAtt.n_elem,numClass);
  entropyArray.fill(0);

  // Populate entropyArray and numElem; they are used as helpers to calculate
  // entropy.
  for (int j = 0; j < uniqueAtt.n_elem; j++)
  {
    for (int i = 0; i < attribute.n_elem; i++)
    {
      if (uniqueAtt[j] == attribute[i])
      {
        entropyArray(j,labels(i))++;
        numElem(j)++;
      }
    }
  }

  for (int j = 0; j < uniqueAtt.size(); j++)
  {
    const double p1 = ((double) numElem(j) / attribute.n_elem);

    for (int i = 0; i < numClass; i++)
    {
      const double p2 = ((double) entropyArray(j, i) / numElem(j));
      const double p3 = (p2 == 0) ? 0 : p2 * log2(p2);

      entropy += p1 * p3;
    }
  }

  return entropy;
}

}; // namespace decision_stump
}; // namespace mlpack

#endif
<commit_msg>Use const double where possible instead of having a variable used throughout the function.  This is only for clarity and consistency and is not likely to make any runtime difference.<commit_after>/**
 * @file decision_stump_impl.hpp
 * @author Udit Saxena
 *
 * Implementation of DecisionStump class.
 */

#ifndef __MLPACK_METHODS_DECISION_STUMP_DECISION_STUMP_IMPL_HPP
#define __MLPACK_METHODS_DECISION_STUMP_DECISION_STUMP_IMPL_HPP

// In case it hasn't been included yet.
#include "decision_stump.hpp"

#include <set>
#include <algorithm>

namespace mlpack {
namespace decision_stump {

/**
 * Constructor. Train on the provided data. Generate a decision stump from data.
 *
 * @param data Input, training data.
 * @param labels Labels of data.
 * @param classes Number of distinct classes in labels.
 * @param inpBucketSize Minimum size of bucket when splitting.
 */
template<typename MatType>
DecisionStump<MatType>::DecisionStump(const MatType& data,
                                      const arma::Row<size_t>& labels,
                                      const size_t classes,
                                      size_t inpBucketSize)
{
  arma::Row<size_t> zLabels(labels.n_elem);
  zLabels.fill(0);
  classLabels = labels + zLabels;

  numClass = classes;
  bucketSize = inpBucketSize;

  // Check whether the input labels are not all identical.
  if (!isDistinct<size_t>(classLabels))
  {
    // If the classLabels are all identical, the default class is the only
    // class.
    oneClass = true;
    defaultClass = classLabels(0);
  }
  else
  {
    // If classLabels are not all identical, proceed with training.
    oneClass = false;
    int bestAtt = -1;
    double entropy;
    double bestEntropy = DBL_MAX;

    // Set the default class to handle attribute values which are not present in
    // the training data.
    defaultClass = CountMostFreq<size_t>(classLabels);

    for (int i = 0; i < data.n_rows; i++)
    {
      // Go through each attribute of the data.
      if (isDistinct<double>(data.row(i)))
      {
        // For each attribute with non-identical values, treat it as a potential
        // splitting attribute and calculate entropy if split on it.
        entropy = SetupSplitAttribute(data.row(i));

        // Find the attribute with the bestEntropy so that the gain is
        // maximized.
        if (entropy < bestEntropy)
        {
          bestAtt = i;
          bestEntropy = entropy;
        }
      }
    }
    splitCol = bestAtt;

    // Once the splitting column/attribute has been decided, train on it.
    TrainOnAtt<double>(data.row(splitCol));
  }
}

/**
 * Classification function. After training, classify test, and put the predicted
 * classes in predictedLabels.
 *
 * @param test Testing data or data to classify.
 * @param predictedLabels Vector to store the predicted classes after
 *      classifying test
 */
template<typename MatType>
void DecisionStump<MatType>::Classify(const MatType& test,
                                      arma::Row<size_t>& predictedLabels)
{
  if (!oneClass)
  {
    for (int i = 0; i < test.n_cols; i++)
    {
      int j = 0;

      const double val = test(splitCol, i);
      while (j < split.n_rows)
      {
        if (val < split(j, 0) && (!j))
        {
          predictedLabels(i) = split(0, 1);
          break;
        }
        else if (val >= split(j, 0))
        {
          if (j == split.n_rows - 1)
          {
            predictedLabels(i) = split(split.n_rows - 1, 1);
            break;
          }
          else if (val < split(j + 1, 0))
          {
            predictedLabels(i) = split(j, 1);
            break;
          }
        }
        j++;
      }
    }
  }
  else
  {
    for (int i = 0; i < test.n_cols; i++)
      predictedLabels(i) = defaultClass;
  }
}

/**
 * Sets up attribute as if it were splitting on it and finds entropy when
 * splitting on attribute.
 *
 * @param attribute A row from the training data, which might be a candidate for
 *      the splitting attribute.
 */
template <typename MatType>
double DecisionStump<MatType>::SetupSplitAttribute(const arma::rowvec& attribute)
{
  int i, count, begin, end;
  double entropy = 0.0;

  // Sort the attribute in order to calculate splitting ranges.
  arma::rowvec sortedAtt = arma::sort(attribute);

  // Store the indices of the sorted attribute to build a vector of sorted
  // labels.  This sort is stable.
  arma::uvec sortedIndexAtt = arma::stable_sort_index(attribute.t());

  arma::Row<size_t> sortedLabels(attribute.n_elem);
  sortedLabels.fill(0);

  for (i = 0; i < attribute.n_elem; i++)
    sortedLabels(i) = classLabels(sortedIndexAtt(i));

  arma::rowvec subColLabels;
  arma::rowvec subColAtts;

  i = 0;
  count = 0;

  // This splits the sorted into buckets of size greater than or equal to
  // inpBucketSize.
  while (i < sortedLabels.n_elem)
  {
    count++;
    if (i == sortedLabels.n_elem - 1)
    {
      begin = i - count + 1;
      end = i;

      arma::rowvec zSubColLabels((sortedLabels.cols(begin, end)).n_elem);
      zSubColLabels.fill(0.0);

      arma::rowvec zSubColAtts((sortedAtt.cols(begin, end)).n_elem);
      zSubColAtts.fill(0.0);

      subColLabels = sortedLabels.cols(begin, end) + zSubColLabels;

      subColAtts = sortedAtt.cols(begin, end) + zSubColAtts;

      entropy += CalculateEntropy(subColAtts, subColLabels);
      i++;
    }
    else if (sortedLabels(i) != sortedLabels(i + 1))
    {
      if (count < bucketSize)
      {
        begin = i - count + 1;
        end = begin + bucketSize - 1;

        if (end > sortedLabels.n_elem - 1)
          end = sortedLabels.n_elem - 1;
      }
      else
      {
        begin = i - count + 1;
        end = i;
      }

      arma::rowvec zSubColLabels((sortedLabels.cols(begin, end)).n_elem);
      zSubColLabels.fill(0.0);

      arma::rowvec zSubColAtts((sortedAtt.cols(begin, end)).n_elem);
      zSubColAtts.fill(0.0);

      subColLabels = sortedLabels.cols(begin, end) + zSubColLabels;

      subColAtts = sortedAtt.cols(begin, end) + zSubColAtts;

      // Now use subColLabels and subColAtts to calculate entropy.
      entropy += CalculateEntropy(subColAtts, subColLabels);

      i = end + 1;
      count = 0;
    }
    else
      i++;
  }
  return entropy;
}

/**
 * After having decided the attribute on which to split, train on that
 * attribute.
 *
 * @param attribute Attribute is the attribute decided by the constructor on
 *      which we now train the decision stump.
 */
template <typename MatType>
template <typename rType>
void DecisionStump<MatType>::TrainOnAtt(const arma::rowvec& attribute)
{
  int i, count, begin, end;

  arma::rowvec sortedSplitAtt = arma::sort(attribute);
  arma::uvec sortedSplitIndexAtt = arma::stable_sort_index(attribute.t());
  arma::Row<size_t> sortedLabels(attribute.n_elem);
  sortedLabels.fill(0);
  arma::mat tempSplit;

  for (i = 0; i < attribute.n_elem; i++)
    sortedLabels(i) = classLabels(sortedSplitIndexAtt(i));

  arma::rowvec subCols;
  rType mostFreq;
  i = 0;
  count = 0;
  while (i < sortedLabels.n_elem)
  {
    count++;
    if (i == sortedLabels.n_elem - 1)
    {
      begin = i - count + 1;
      end = i;

      arma::rowvec zSubCols((sortedLabels.cols(begin, end)).n_elem);
      zSubCols.fill(0.0);

      subCols = sortedLabels.cols(begin, end) + zSubCols;

      mostFreq = CountMostFreq<double>(subCols);

      tempSplit << sortedSplitAtt(begin)<< mostFreq << arma::endr;
      split = arma::join_cols(split, tempSplit);

      i++;
    }
    else if (sortedLabels(i) != sortedLabels(i + 1))
    {
      if (count < bucketSize)
      {
        // Test for different values of bucketSize, especially extreme cases.
        begin = i - count + 1;
        end = begin + bucketSize - 1;

        if (end > sortedLabels.n_elem - 1)
          end = sortedLabels.n_elem - 1;
      }
      else
      {
        begin = i - count + 1;
        end = i;
      }
      arma::rowvec zSubCols((sortedLabels.cols(begin, end)).n_elem);
      zSubCols.fill(0.0);

      subCols = sortedLabels.cols(begin, end) + zSubCols;

      // Find the most frequent element in subCols so as to assign a label to
      // the bucket of subCols.
      mostFreq = CountMostFreq<double>(subCols);

      tempSplit << sortedSplitAtt(begin) << mostFreq << arma::endr;
      split = arma::join_cols(split, tempSplit);

      i = end + 1;
      count = 0;
    }
    else
      i++;
  }

  // Now trim the split matrix so that buckets one after the after which point
  // to the same classLabel are merged as one big bucket.
  MergeRanges();
}

/**
 * After the "split" matrix has been set up, merge ranges with identical class
 * labels.
 */
template <typename MatType>
void DecisionStump<MatType>::MergeRanges()
{
  for (int i = 1; i < split.n_rows; i++)
  {
    if (split(i, 1) == split(i - 1, 1))
    {
      // Remove this row, as it has the same label as the previous bucket.
      split.shed_row(i);
      // Go back to previous row.
      i--;
    }
  }
}

template <typename MatType>
template <typename rType>
rType DecisionStump<MatType>::CountMostFreq(const arma::Row<rType>& subCols)
{
  // Sort subCols for easier processing.
  arma::Row<rType> sortCounts = arma::sort(subCols);
  rType element;
  int count = 0, localCount = 0;

  // An O(n) loop which counts the most frequent element in sortCounts
  for (int i = 0; i < sortCounts.n_elem; ++i)
  {
    if (i == sortCounts.n_elem - 1)
    {
      if (sortCounts(i - 1) == sortCounts(i))
      {
        // element = sortCounts(i - 1);
        localCount++;
      }
      else if (localCount > count)
        count = localCount;
    }
    else if (sortCounts(i) != sortCounts(i + 1))
    {
      localCount = 0;
      count++;
    }
    else
    {
      localCount++;
      if (localCount > count)
      {
        count = localCount;
        if (localCount == 1)
          element = sortCounts(i);
      }
    }
  }
  return element;
}

/**
 * Returns 1 if all the values of featureRow are not same.
 *
 * @param featureRow The attribute which is checked for identical values.
 */
template <typename MatType>
template <typename rType>
int DecisionStump<MatType>::isDistinct(const arma::Row<rType>& featureRow)
{
  if (featureRow.max() - featureRow.min() > 0)
    return 1;
  else
    return 0;
}

/**
 * Calculate entropy of attribute.
 *
 * @param attribute The attribute for which we calculate the entropy.
 * @param labels Corresponding labels of the attribute.
 */
template<typename MatType>
double DecisionStump<MatType>::CalculateEntropy(const arma::rowvec& attribute,
                                                const arma::rowvec& labels)
{
  double entropy = 0.0;

  arma::rowvec uniqueAtt = arma::unique(attribute);
  arma::rowvec uniqueLabel = arma::unique(labels);
  arma::Row<size_t> numElem(uniqueAtt.n_elem);
  numElem.fill(0);
  arma::Mat<size_t> entropyArray(uniqueAtt.n_elem,numClass);
  entropyArray.fill(0);

  // Populate entropyArray and numElem; they are used as helpers to calculate
  // entropy.
  for (int j = 0; j < uniqueAtt.n_elem; j++)
  {
    for (int i = 0; i < attribute.n_elem; i++)
    {
      if (uniqueAtt[j] == attribute[i])
      {
        entropyArray(j,labels(i))++;
        numElem(j)++;
      }
    }
  }

  for (int j = 0; j < uniqueAtt.size(); j++)
  {
    const double p1 = ((double) numElem(j) / attribute.n_elem);

    for (int i = 0; i < numClass; i++)
    {
      const double p2 = ((double) entropyArray(j, i) / numElem(j));
      const double p3 = (p2 == 0) ? 0 : p2 * log2(p2);

      entropy += p1 * p3;
    }
  }

  return entropy;
}

}; // namespace decision_stump
}; // namespace mlpack

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2016 Alexander Gallego. All rights reserved.
//
#include <experimental/optional>
#include <iostream>
#include <memory>
#include <vector>

#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <flatbuffers/flatbuffers.h>
#include <flatbuffers/util.h>
#include <gflags/gflags.h>
#include <glog/logging.h>

#include "codegen.h"

DEFINE_string(filename, "", "filename to parse");
DEFINE_string(include_dirs, "", "extra include directories");
DEFINE_string(language, "cpp",
              "coma separated list of language to generate: go, cpp");
DEFINE_string(output_path, ".", "output path of the generated files");

std::vector<std::string>
split_coma(const std::string &dirs) {
  std::vector<std::string> retval;
  boost::algorithm::split(retval, dirs, boost::is_any_of(","));
  if (retval.empty() && !dirs.empty()) { retval.push_back(dirs); }
  for (auto &s : retval) {
    boost::algorithm::trim(s);
  }
  return retval;
}

std::vector<smf_gen::language>
split_langs(const std::string &lang) {
  // Note: be sure to add the generator in codegen.cc
  std::vector<smf_gen::language> retval;
  auto str_langs = split_coma(lang);
  for (auto &l : str_langs) {
    if (l == "cpp") {
      retval.push_back(smf_gen::language::cpp);
    } else if (l == "go") {
      retval.push_back(smf_gen::language::go);
    } else {
      LOG(ERROR) << "Skipping unknown language: " << l;
    }
  }
  return retval;
}

int
main(int argc, char **argv, char **env) {
  google::SetUsageMessage("Generate smf services");
  google::ParseCommandLineFlags(&argc, &argv, true);
  google::InstallFailureSignalHandler();
  google::InitGoogleLogging(argv[0]);

  // validate flags
  if (FLAGS_filename.empty()) {
    LOG(ERROR) << "No filename to parse";
    std::exit(1);
  }
  if (!boost::filesystem::exists(FLAGS_filename)) {
    LOG(ERROR) << " ` " << FLAGS_filename
               << " ' - does not exists or could not be found";
    std::exit(1);
  }
  if (FLAGS_output_path.empty()) {
    LOG(ERROR) << " ` " << FLAGS_output_path << " ' - empty output path";
    std::exit(1);
  }
  FLAGS_output_path =
    boost::filesystem::canonical(FLAGS_output_path.c_str()).string();
  if (!flatbuffers::DirExists(FLAGS_output_path.c_str())) {
    LOG(ERROR) << "--output_path specified, but directory: "
               << FLAGS_output_path << " does not exist;";
    std::exit(1);
  }

  auto codegenerator = std::make_unique<smf_gen::codegen>(
    FLAGS_filename, FLAGS_output_path, split_coma(FLAGS_include_dirs),
    split_langs(FLAGS_language));
  // generate code!
  auto status = codegenerator->parse();
  if (status) {
    LOG(ERROR) << "Failed to parse file: " << status.value();
    std::exit(1);
  }
  if (codegenerator->service_count() == 0) {
    LOG(INFO) << "No services need to be generated";
    return 0;
  }
  status = codegenerator->gen();
  if (status) {
    LOG(ERROR) << "Errors generating code: " << *status;
    std::exit(1);
  }
  VLOG(1) << "Success";
  return 0;
}
<commit_msg>smfc: always generate output files<commit_after>// Copyright (c) 2016 Alexander Gallego. All rights reserved.
//
#include <experimental/optional>
#include <iostream>
#include <memory>
#include <vector>

#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <flatbuffers/flatbuffers.h>
#include <flatbuffers/util.h>
#include <gflags/gflags.h>
#include <glog/logging.h>

#include "codegen.h"

DEFINE_string(filename, "", "filename to parse");
DEFINE_string(include_dirs, "", "extra include directories");
DEFINE_string(language, "cpp",
              "coma separated list of language to generate: go, cpp");
DEFINE_string(output_path, ".", "output path of the generated files");

std::vector<std::string>
split_coma(const std::string &dirs) {
  std::vector<std::string> retval;
  boost::algorithm::split(retval, dirs, boost::is_any_of(","));
  if (retval.empty() && !dirs.empty()) { retval.push_back(dirs); }
  for (auto &s : retval) {
    boost::algorithm::trim(s);
  }
  return retval;
}

std::vector<smf_gen::language>
split_langs(const std::string &lang) {
  // Note: be sure to add the generator in codegen.cc
  std::vector<smf_gen::language> retval;
  auto str_langs = split_coma(lang);
  for (auto &l : str_langs) {
    if (l == "cpp") {
      retval.push_back(smf_gen::language::cpp);
    } else if (l == "go") {
      retval.push_back(smf_gen::language::go);
    } else {
      LOG(ERROR) << "Skipping unknown language: " << l;
    }
  }
  return retval;
}

int
main(int argc, char **argv, char **env) {
  google::SetUsageMessage("Generate smf services");
  google::ParseCommandLineFlags(&argc, &argv, true);
  google::InstallFailureSignalHandler();
  google::InitGoogleLogging(argv[0]);

  // validate flags
  if (FLAGS_filename.empty()) {
    LOG(ERROR) << "No filename to parse";
    std::exit(1);
  }
  if (!boost::filesystem::exists(FLAGS_filename)) {
    LOG(ERROR) << " ` " << FLAGS_filename
               << " ' - does not exists or could not be found";
    std::exit(1);
  }
  if (FLAGS_output_path.empty()) {
    LOG(ERROR) << " ` " << FLAGS_output_path << " ' - empty output path";
    std::exit(1);
  }
  FLAGS_output_path =
    boost::filesystem::canonical(FLAGS_output_path.c_str()).string();
  if (!flatbuffers::DirExists(FLAGS_output_path.c_str())) {
    LOG(ERROR) << "--output_path specified, but directory: "
               << FLAGS_output_path << " does not exist;";
    std::exit(1);
  }

  auto codegenerator = std::make_unique<smf_gen::codegen>(
    FLAGS_filename, FLAGS_output_path, split_coma(FLAGS_include_dirs),
    split_langs(FLAGS_language));
  // generate code!
  auto status = codegenerator->parse();
  if (status) {
    LOG(ERROR) << "Failed to parse file: " << status.value();
    std::exit(1);
  }
  if (codegenerator->service_count() == 0) {
    LOG(INFO) << "No services need to be generated";
    // if we return 0, the cmake module cannot detect if we generate a file or not
    // and always calls smfc
    // return 0;
  }
  status = codegenerator->gen();
  if (status) {
    LOG(ERROR) << "Errors generating code: " << *status;
    std::exit(1);
  }
  VLOG(1) << "Success";
  return 0;
}
<|endoftext|>


<commit_before>#include "dsa_common.h"

#include "variant.h"

namespace dsa {
Variant::Variant(int64_t v) : BaseVariant(v) {}

Variant::Variant(double v) : BaseVariant(v) {}

Variant::Variant(bool v) : BaseVariant(v) {}

Variant::Variant(const char* v, size_t size)
    : BaseVariant(std::string(v, size)) {}
Variant::Variant(const std::string& v) : BaseVariant(v) {}
Variant::Variant(const std::string* p)
  : BaseVariant(intrusive_ptr_<VariantString>(new VariantString(*p))) {}

Variant::Variant(const uint8_t* v, size_t size)
    : BaseVariant(std::vector<uint8_t>(v, v + size)) {}
Variant::Variant(const std::vector<uint8_t>& v) : BaseVariant(v) {}
Variant::Variant(const std::vector<uint8_t>* p)
  : BaseVariant(intrusive_ptr_<VariantBinary>(new VariantBinary(*p))) {}

Variant::Variant() : BaseVariant(boost::blank()) {}
Variant::Variant(VariantMap* p) : BaseVariant(intrusive_ptr_<VariantMap>(p)) {}
Variant::Variant(VariantArray* p)
  : BaseVariant(intrusive_ptr_<VariantArray>(new VariantArray(*p))) {}

Variant* Variant::new_map() { return new Variant(new VariantMap()); }
Variant* Variant::new_array() { return new Variant(new VariantArray()); }

Variant* Variant::copy() const {
  switch (which()) {
    case Map: {
      auto new_map = new VariantMap();
      VariantMap& map = get_map();

      for (auto &it : map) {
        (*new_map)[it.first] = Variant(it.second);
      }
      return new Variant(new_map);
    }
    case Array: {
      auto new_array = new VariantArray();
      VariantArray& array = get_array();
      new_array->reserve(array.size());

      for (auto &it : array) {
        new_array->push_back(Variant(it));
      }
      return new Variant(new_array);
    }
    default:
      return new Variant(*this);
  }
}

Variant* Variant::deep_copy() const {
  switch (which()) {
    case Map: {
      auto new_map = new VariantMap();
      VariantMap& map = get_map();

      for (auto &it : map) {
        (*new_map)[it.first] = *(it.second.deep_copy());
      }
      return new Variant(new_map);
    }
    case Array: {
      auto new_array = new VariantArray();
      VariantArray& array = get_array();
      new_array->reserve(array.size());

      for (auto &it : array) {
        new_array->push_back(*(it.deep_copy()));
      }
      return new Variant(new_array);
    }
    default:
      return new Variant(*this);
  }
}

}  // namespace dsa
<commit_msg>Change VariantArray constructor code<commit_after>#include "dsa_common.h"

#include "variant.h"

namespace dsa {
Variant::Variant(int64_t v) : BaseVariant(v) {}

Variant::Variant(double v) : BaseVariant(v) {}

Variant::Variant(bool v) : BaseVariant(v) {}

Variant::Variant(const char* v, size_t size)
    : BaseVariant(std::string(v, size)) {}
Variant::Variant(const std::string& v) : BaseVariant(v) {}
Variant::Variant(const std::string* p)
  : BaseVariant(intrusive_ptr_<VariantString>(new VariantString(*p))) {}

Variant::Variant(const uint8_t* v, size_t size)
    : BaseVariant(std::vector<uint8_t>(v, v + size)) {}
Variant::Variant(const std::vector<uint8_t>& v) : BaseVariant(v) {}
Variant::Variant(const std::vector<uint8_t>* p)
  : BaseVariant(intrusive_ptr_<VariantBinary>(new VariantBinary(*p))) {}

Variant::Variant() : BaseVariant(boost::blank()) {}
Variant::Variant(VariantMap* p) : BaseVariant(intrusive_ptr_<VariantMap>(p)) {}
Variant::Variant(VariantArray* p)
  : BaseVariant(intrusive_ptr_<VariantArray>(p)) {}

Variant* Variant::new_map() { return new Variant(new VariantMap()); }
Variant* Variant::new_array() { return new Variant(new VariantArray()); }

Variant* Variant::copy() const {
  switch (which()) {
    case Map: {
      auto new_map = new VariantMap();
      VariantMap& map = get_map();

      for (auto &it : map) {
        (*new_map)[it.first] = Variant(it.second);
      }
      return new Variant(new_map);
    }
    case Array: {
      auto new_array = new VariantArray();
      VariantArray& array = get_array();
      new_array->reserve(array.size());

      for (auto &it : array) {
        new_array->push_back(Variant(it));
      }
      return new Variant(new_array);
    }
    default:
      return new Variant(*this);
  }
}

Variant* Variant::deep_copy() const {
  switch (which()) {
    case Map: {
      auto new_map = new VariantMap();
      VariantMap& map = get_map();

      for (auto &it : map) {
        (*new_map)[it.first] = *(it.second.deep_copy());
      }
      return new Variant(new_map);
    }
    case Array: {
      auto new_array = new VariantArray();
      VariantArray& array = get_array();
      new_array->reserve(array.size());

      for (auto &it : array) {
        new_array->push_back(*(it.deep_copy()));
      }
      return new Variant(new_array);
    }
    default:
      return new Variant(*this);
  }
}

}  // namespace dsa
<|endoftext|>


<commit_before>/*
   Copyright 2014 Software Reliability Lab, ETH Zurich

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

#include "nice2server.h"

#include "glog/logging.h"
#include "jsoncpp/json/json.h"
#include "jsonrpccpp/server.h"
#include "jsonrpccpp/server/connectors/httpserver.h"
#include "jsonrpccpp/common/exception.h"

#include "stringprintf.h"

#include "graph_inference.h"
#include "server_log.h"
#include "inference.h"

DEFINE_string(model, "model", "Input model files");
DEFINE_string(model_version, "", "Version of the current model");

DEFINE_string(logfile_prefix, "", "File where to log all requests and responses");

namespace {
void DropTrainingNewLine(std::string* s) {
  if (s->empty()) return;
  if ((*s)[s->size() - 1] == '\n') s->erase(s->begin() + s->size() - 1, s->end());
}
}

class Nice2ServerInternal : public jsonrpc::AbstractServer<Nice2ServerInternal> {
public:
  Nice2ServerInternal(jsonrpc::HttpServer* server) : jsonrpc::AbstractServer<Nice2ServerInternal>(*server) {
    bindAndAddMethod(
        jsonrpc::Procedure("infer", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY,
            // Parameters:
            "query", jsonrpc::JSON_ARRAY,
            "assign", jsonrpc::JSON_ARRAY,
            NULL),
        &Nice2ServerInternal::infer);
    bindAndAddMethod(
        jsonrpc::Procedure("nbest", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY,
            // Parameters:
            "n", jsonrpc::JSON_INTEGER,
            "query", jsonrpc::JSON_ARRAY,
            "assign", jsonrpc::JSON_ARRAY,
            NULL),
        &Nice2ServerInternal::nbest);

    bindAndAddMethod(
        jsonrpc::Procedure("showgraph", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT,
            // Parameters:
            "query", jsonrpc::JSON_ARRAY,
            "assign", jsonrpc::JSON_ARRAY,
            NULL),
        &Nice2ServerInternal::showgraph);

    inference_.LoadModel(FLAGS_model);

    if (!FLAGS_logfile_prefix.empty()) {
      logging_.reset(new Nice2ServerLog(FLAGS_logfile_prefix));
    }
  }

  void verifyVersion(const Json::Value& request){
    VLOG(3) << "Current version: " << FLAGS_model_version << ". Request version: " << request["version"];
    if (FLAGS_model_version.empty()){
      return;
    }

    if (!request.isMember("version") ||
        strcmp(request["version"].asCString(), FLAGS_model_version.c_str()) != 0){
      std::ostringstream stringStream;
      stringStream << "The version of client '" << request["version"].asString() <<
          "' does not match the server version '" << FLAGS_model_version << "'. " <<
          "Please update the client to the latest version by running 'npm update -g unuglify-js'.";
      throw jsonrpc::JsonRpcException(-31001, stringStream.str());
    }
  }

  void MaybeLogQuery(const char* method, const Json::Value& request, const Json::Value& response) {
    if (logging_.get() == NULL) {
      return;
    }

    Json::FastWriter writer;
    std::string rs1 = writer.write(request);
    std::string rs2 = writer.write(response);
    DropTrainingNewLine(&rs1);
    DropTrainingNewLine(&rs2);
    logging_->LogRecord(StringPrintf(
        "\"method\":\"%s\", "
        "\"request\":%s, "
        "\"reply\":%s",
        method, rs1.c_str(), rs2.c_str()));
  }

  void infer(const Json::Value& request, Json::Value& response)
  {
    VLOG(3) << request.toStyledString();
    verifyVersion(request);
    std::unique_ptr<Nice2Query> query(inference_.CreateQuery());
    query->FromJSON(request["query"]);
    std::unique_ptr<Nice2Assignment> assignment(inference_.CreateAssignment(query.get()));
    assignment->FromJSON(request["assign"]);
    inference_.MapInference(query.get(), assignment.get());
    assignment->ToJSON(&response);

    MaybeLogQuery("infer", request, response);
  }

  void nbest(const Json::Value& request, Json::Value& response)
  {
    int n = request["n"].asInt();
    int v = request["v"].asInt();

    VLOG(3) << request.toStyledString();
    verifyVersion(request);
    std::unique_ptr<Nice2Query> query(inference_.CreateQuery());
    query->FromJSON(request["query"]);
    std::unique_ptr<Nice2Assignment> assignment(inference_.CreateAssignment(query.get()));
    assignment->FromJSON(request["assign"]);
    inference_.MapInference(query.get(), assignment.get());
    assignment->GetCandidates(inference_, v, n, &response);

    MaybeLogQuery("nbest", request, response);
  }

  void showgraph(const Json::Value& request, Json::Value& response)
  {
    VLOG(3) << request.toStyledString();
    std::unique_ptr<Nice2Query> query(inference_.CreateQuery());
    query->FromJSON(request["query"]);
    std::unique_ptr<Nice2Assignment> assignment(inference_.CreateAssignment(query.get()));
    assignment->FromJSON(request["assign"]);
    if (request.isMember("infer") && request["infer"].asBool() == true) {
      inference_.MapInference(query.get(), assignment.get());
    }
    inference_.DisplayGraph(query.get(), assignment.get(), &response);

    MaybeLogQuery("showgraph", request, response);
  }

private:
  GraphInference inference_;
  std::unique_ptr<Nice2ServerLog> logging_;
};

Nice2Server::Nice2Server(jsonrpc::HttpServer* server)
  : internal_(new Nice2ServerInternal(server)) {
}

Nice2Server::~Nice2Server() {
  delete internal_;
}

void Nice2Server::Listen() {
  internal_->StartListening();
  LOG(INFO) << "Nice2Server started.";
  for (;;) {
    sleep(1);
  }
  internal_->StopListening();
}
<commit_msg>adding "infer" (true/false) parameter to nbest<commit_after>/*
   Copyright 2014 Software Reliability Lab, ETH Zurich

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

#include "nice2server.h"

#include "glog/logging.h"
#include "jsoncpp/json/json.h"
#include "jsonrpccpp/server.h"
#include "jsonrpccpp/server/connectors/httpserver.h"
#include "jsonrpccpp/common/exception.h"

#include "stringprintf.h"

#include "graph_inference.h"
#include "server_log.h"
#include "inference.h"

DEFINE_string(model, "model", "Input model files");
DEFINE_string(model_version, "", "Version of the current model");

DEFINE_string(logfile_prefix, "", "File where to log all requests and responses");

namespace {
void DropTrainingNewLine(std::string* s) {
  if (s->empty()) return;
  if ((*s)[s->size() - 1] == '\n') s->erase(s->begin() + s->size() - 1, s->end());
}
}

class Nice2ServerInternal : public jsonrpc::AbstractServer<Nice2ServerInternal> {
public:
  Nice2ServerInternal(jsonrpc::HttpServer* server) : jsonrpc::AbstractServer<Nice2ServerInternal>(*server) {
    bindAndAddMethod(
        jsonrpc::Procedure("infer", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY,
            // Parameters:
            "query", jsonrpc::JSON_ARRAY,
            "assign", jsonrpc::JSON_ARRAY,
            NULL),
        &Nice2ServerInternal::infer);
    bindAndAddMethod(
        jsonrpc::Procedure("nbest", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY,
            // Parameters:
            "n", jsonrpc::JSON_INTEGER,
            "query", jsonrpc::JSON_ARRAY,
            "assign", jsonrpc::JSON_ARRAY,
            NULL),
        &Nice2ServerInternal::nbest);

    bindAndAddMethod(
        jsonrpc::Procedure("showgraph", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT,
            // Parameters:
            "query", jsonrpc::JSON_ARRAY,
            "assign", jsonrpc::JSON_ARRAY,
            NULL),
        &Nice2ServerInternal::showgraph);

    inference_.LoadModel(FLAGS_model);

    if (!FLAGS_logfile_prefix.empty()) {
      logging_.reset(new Nice2ServerLog(FLAGS_logfile_prefix));
    }
  }

  void verifyVersion(const Json::Value& request){
    VLOG(3) << "Current version: " << FLAGS_model_version << ". Request version: " << request["version"];
    if (FLAGS_model_version.empty()){
      return;
    }

    if (!request.isMember("version") ||
        strcmp(request["version"].asCString(), FLAGS_model_version.c_str()) != 0){
      std::ostringstream stringStream;
      stringStream << "The version of client '" << request["version"].asString() <<
          "' does not match the server version '" << FLAGS_model_version << "'. " <<
          "Please update the client to the latest version by running 'npm update -g unuglify-js'.";
      throw jsonrpc::JsonRpcException(-31001, stringStream.str());
    }
  }

  void MaybeLogQuery(const char* method, const Json::Value& request, const Json::Value& response) {
    if (logging_.get() == NULL) {
      return;
    }

    Json::FastWriter writer;
    std::string rs1 = writer.write(request);
    std::string rs2 = writer.write(response);
    DropTrainingNewLine(&rs1);
    DropTrainingNewLine(&rs2);
    logging_->LogRecord(StringPrintf(
        "\"method\":\"%s\", "
        "\"request\":%s, "
        "\"reply\":%s",
        method, rs1.c_str(), rs2.c_str()));
  }

  void infer(const Json::Value& request, Json::Value& response)
  {
    VLOG(3) << request.toStyledString();
    verifyVersion(request);
    std::unique_ptr<Nice2Query> query(inference_.CreateQuery());
    query->FromJSON(request["query"]);
    std::unique_ptr<Nice2Assignment> assignment(inference_.CreateAssignment(query.get()));
    assignment->FromJSON(request["assign"]);
    inference_.MapInference(query.get(), assignment.get());
    assignment->ToJSON(&response);

    MaybeLogQuery("infer", request, response);
  }

  void nbest(const Json::Value& request, Json::Value& response)
  {
    int n = request["n"].asInt();
    int v = request["v"].asInt();
    bool shouldInfer = request["infer"].asBool();

    VLOG(3) << request.toStyledString();
    verifyVersion(request);
    std::unique_ptr<Nice2Query> query(inference_.CreateQuery());
    query->FromJSON(request["query"]);
    std::unique_ptr<Nice2Assignment> assignment(inference_.CreateAssignment(query.get()));
    assignment->FromJSON(request["assign"]);
    if (shouldInfer) {
      inference_.MapInference(query.get(), assignment.get());
    }
    assignment->GetCandidates(inference_, v, n, &response);

    MaybeLogQuery("nbest", request, response);
  }

  void showgraph(const Json::Value& request, Json::Value& response)
  {
    VLOG(3) << request.toStyledString();
    std::unique_ptr<Nice2Query> query(inference_.CreateQuery());
    query->FromJSON(request["query"]);
    std::unique_ptr<Nice2Assignment> assignment(inference_.CreateAssignment(query.get()));
    assignment->FromJSON(request["assign"]);
    if (request.isMember("infer") && request["infer"].asBool() == true) {
      inference_.MapInference(query.get(), assignment.get());
    }
    inference_.DisplayGraph(query.get(), assignment.get(), &response);

    MaybeLogQuery("showgraph", request, response);
  }

private:
  GraphInference inference_;
  std::unique_ptr<Nice2ServerLog> logging_;
};

Nice2Server::Nice2Server(jsonrpc::HttpServer* server)
  : internal_(new Nice2ServerInternal(server)) {
}

Nice2Server::~Nice2Server() {
  delete internal_;
}

void Nice2Server::Listen() {
  internal_->StartListening();
  LOG(INFO) << "Nice2Server started.";
  for (;;) {
    sleep(1);
  }
  internal_->StopListening();
}
<|endoftext|>