<commit_before>#pragma ident "$Id$"

#ifndef GPSTK_TIMESYSTEM_HPP
#define GPSTK_TIMESYSTEM_HPP

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk 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
//  any later version.
//
//  The GPSTk 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 GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

//============================================================================
//
//This software developed by Applied Research Laboratories at the University of
//Texas at Austin, under contract to an agency or agencies within the U.S.
//Department of Defense. The U.S. Government retains all rights to use,
//duplicate, distribute, disclose, or release this software.
//
//Pursuant to DoD Directive 523024
//
// DISTRIBUTION STATEMENT A: This software has been approved for public
//                           release, distribution is unlimited.
//
//=============================================================================

namespace TimeSystem
{

   class TimeSystem
   {
   public:
         //Constructor
      TimeSystem()
         throw()
      {}
         //Copy Constructor
      TimeSystem( const TimeSystem& right )
         throw()
      {}

        //Assignment Opperator
      TimeSystem& operator=( const TimeSystem& right )
         throw()
      {}

   private:

   };//class

}//namespace

#endif // GPSTK_TIMESYSTEM_HPP
<commit_msg>Fix operator= to return.  Some compilers don't fix it.<commit_after>#pragma ident "$Id$"

#ifndef GPSTK_TIMESYSTEM_HPP
#define GPSTK_TIMESYSTEM_HPP

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk 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
//  any later version.
//
//  The GPSTk 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 GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

//============================================================================
//
//This software developed by Applied Research Laboratories at the University of
//Texas at Austin, under contract to an agency or agencies within the U.S.
//Department of Defense. The U.S. Government retains all rights to use,
//duplicate, distribute, disclose, or release this software.
//
//Pursuant to DoD Directive 523024
//
// DISTRIBUTION STATEMENT A: This software has been approved for public
//                           release, distribution is unlimited.
//
//=============================================================================

namespace TimeSystem
{

   class TimeSystem
   {
   public:
         //Constructor
      TimeSystem()
         throw()
      {}
         //Copy Constructor
      TimeSystem( const TimeSystem& right )
         throw()
      {}

        //Assignment Opperator
      TimeSystem& operator=( const TimeSystem& right )
         throw()
      {
        return *this;
      }

   private:

   };//class

}//namespace

#endif // GPSTK_TIMESYSTEM_HPP
<|endoftext|>


<commit_before>/**
  MQTT433gateway - MQTT 433.92 MHz radio gateway utilizing ESPiLight
  Project home: https://github.com/puuu/MQTT433gateway/

  The MIT License (MIT)

  Copyright (c) 2017 Jan Losinski

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

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

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

#include "Settings.h"

#include <ArduinoJson.h>
#include <FS.h>

#include <ArduinoSimpleLogging.h>

static inline bool any(std::initializer_list<bool> items) {
  return std::any_of(items.begin(), items.end(),
                     [](bool item) { return item; });
}

std::function<bool(const String &)> notEmpty() {
  return [](const String &str) { return str.length() > 0; };
}

template <typename T>
std::function<bool(const T &)> notZero() {
  return [](const T &val) { return val != 0; };
}

template <typename TVal, typename TKey>
bool setIfPresent(JsonObject &obj, TKey key, TVal &var,
                  const std::function<bool(const TVal &)> &validator =
                      std::function<bool(const TVal &)>()) {
  if (obj.containsKey(key)) {
    TVal tmp = obj.get<TVal>(key);
    if (tmp != var && (!validator || validator(tmp))) {
      var = tmp;
      return true;
    }
  }
  return false;
}

void Settings::registerChangeHandler(SettingType setting,
                                     const SettingCallbackFn &callback) {
  listeners.emplace_front(setting, callback);
}

void Settings::onConfigChange(SettingTypeSet typeSet) const {
  for (const auto &listener : listeners) {
    if (typeSet[listener.type]) {
      listener.callback(*this);
    }
  }
}

void Settings::load() {
  if (SPIFFS.exists(SETTINGS_FILE)) {
    File file = SPIFFS.open(SETTINGS_FILE, "r");
    String settingsContents = file.readStringUntil(SETTINGS_TERMINATOR);
    file.close();
    Logger.debug.println(F("FILE CONTENTS:"));
    Logger.debug.println(settingsContents);

    deserialize(settingsContents, false);
  }
}

void Settings::notifyAll() {
  // Fire for all
  onConfigChange(SettingTypeSet().set());
}

void Settings::save() {
  File file = SPIFFS.open(SETTINGS_FILE, "w");

  if (!file) {
    Logger.error.println(F("Opening settings file failed"));
  } else {
    serialize(file, false, true);
    file.close();
  }
}

Settings::~Settings() = default;

void Settings::serialize(Print &stream, bool pretty, bool sensible) const {
  DynamicJsonBuffer jsonBuffer;
  JsonObject &root = jsonBuffer.createObject();

  root[F("deviceName")] = this->deviceName;
  root[F("mqttReceiveTopic")] = this->mqttReceiveTopic;
  root[F("mqttSendTopic")] = this->mqttSendTopic;
  root[F("mqttBroker")] = this->mqttBroker;
  root[F("mqttBrokerPort")] = this->mqttBrokerPort;
  root[F("mqttUser")] = this->mqttUser;
  root[F("mqttRetain")] = this->mqttRetain;
  root[F("rfReceiverPin")] = this->rfReceiverPin;
  root[F("rfTransmitterPin")] = this->rfTransmitterPin;
  root[F("rfEchoMessages")] = this->rfEchoMessages;

  {
    DynamicJsonBuffer protoBuffer;
    JsonArray &parsedProtocols = protoBuffer.parseArray(this->rfProtocols);
    JsonArray &protos = root.createNestedArray(F("rfProtocols"));
    for (const auto proto : parsedProtocols) {
      protos.add(proto.as<String>());
    }
  }

  root[F("serialLogLevel")] = this->serialLogLevel;
  root[F("webLogLevel")] = this->webLogLevel;
  root[F("syslogLevel")] = this->syslogLevel;
  root[F("syslogHost")] = this->syslogHost;
  root[F("syslogPort")] = this->syslogPort;

  if (sensible) {
    root[F("mqttPassword")] = this->mqttPassword;
    root[F("configPassword")] = this->configPassword;
  }

  if (pretty) {
    root.prettyPrintTo(stream);
  } else {
    root.printTo(stream);
  }
}

void Settings::deserialize(const String &json, const bool fireCallbacks) {
  DynamicJsonBuffer jsonBuffer;
  JsonObject &parsedSettings = jsonBuffer.parseObject(json);

  if (!parsedSettings.success()) {
    Logger.warning.println(F("Config parse failed!"));
    return;
  }

  SettingTypeSet changed;

  changed.set(BASE, setIfPresent(parsedSettings, F("deviceName"), deviceName,
                                 notEmpty()));

  changed.set(
      MQTT,
      any({setIfPresent(parsedSettings, F("mqttReceiveTopic"),
                        mqttReceiveTopic),
           setIfPresent(parsedSettings, F("mqttSendTopic"), mqttSendTopic),
           setIfPresent(parsedSettings, F("mqttBroker"), mqttBroker,
                        notEmpty()),
           setIfPresent(parsedSettings, F("mqttBrokerPort"), mqttBrokerPort,
                        notZero<uint16_t>()),
           setIfPresent(parsedSettings, F("mqttUser"), mqttUser),
           setIfPresent(parsedSettings, F("mqttPassword"), mqttPassword,
                        notEmpty()),
           setIfPresent(parsedSettings, F("mqttRetain"), mqttRetain)}));

  changed.set(
      RF_CONFIG,
      any({setIfPresent(parsedSettings, F("rfReceiverPin"), rfReceiverPin),
           setIfPresent(parsedSettings, F("rfTransmitterPin"),
                        rfTransmitterPin)}));

  changed.set(RF_ECHO, (setIfPresent(parsedSettings, F("rfEchoMessages"),
                                     rfEchoMessages)));

  if (parsedSettings.containsKey(F("rfProtocols"))) {
    String buff;
    parsedSettings[F("rfProtocols")].printTo(buff);
    if (buff != rfProtocols) {
      rfProtocols = buff;
      changed.set(RF_PROTOCOL, true);
    }
  }

  changed.set(
      LOGGING,
      any({setIfPresent(parsedSettings, F("serialLogLevel"), serialLogLevel),
           setIfPresent(parsedSettings, F("webLogLevel"), webLogLevel)}));

  changed.set(WEB_CONFIG, setIfPresent(parsedSettings, F("configPassword"),
                                       configPassword, notEmpty()));

  changed.set(SYSLOG,
              any({setIfPresent(parsedSettings, F("syslogLevel"), syslogLevel),
                   setIfPresent(parsedSettings, F("syslogHost"), syslogHost),
                   setIfPresent(parsedSettings, F("syslogPort"), syslogPort)}));

  if (fireCallbacks) {
    onConfigChange(changed);
  }
}

void Settings::reset() {
  if (SPIFFS.exists(SETTINGS_FILE)) {
    SPIFFS.remove(SETTINGS_FILE);
  }
}
<commit_msg>Settings: define json keys only once.<commit_after>/**
  MQTT433gateway - MQTT 433.92 MHz radio gateway utilizing ESPiLight
  Project home: https://github.com/puuu/MQTT433gateway/

  The MIT License (MIT)

  Copyright (c) 2017 Jan Losinski

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

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

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

#include "Settings.h"

#include <ArduinoJson.h>
#include <FS.h>

#include <ArduinoSimpleLogging.h>

namespace JsonKey {
const char PROGMEM deviceName[] = "deviceName";
const char PROGMEM mqttReceiveTopic[] = "mqttReceiveTopic";
const char PROGMEM mqttSendTopic[] = "mqttSendTopic";
const char PROGMEM mqttBroker[] = "mqttBroker";
const char PROGMEM mqttBrokerPort[] = "mqttBrokerPort";
const char PROGMEM mqttUser[] = "mqttUser";
const char PROGMEM mqttRetain[] = "mqttRetain";
const char PROGMEM rfReceiverPin[] = "rfReceiverPin";
const char PROGMEM rfTransmitterPin[] = "rfTransmitterPin";
const char PROGMEM rfEchoMessages[] = "rfEchoMessages";
const char PROGMEM rfProtocols[] = "rfProtocols";
const char PROGMEM serialLogLevel[] = "serialLogLevel";
const char PROGMEM webLogLevel[] = "webLogLevel";
const char PROGMEM syslogLevel[] = "syslogLevel";
const char PROGMEM syslogHost[] = "syslogHost";
const char PROGMEM syslogPort[] = "syslogPort";
const char PROGMEM mqttPassword[] = "mqttPassword";
const char PROGMEM configPassword[] = "configPassword";
}

static inline bool any(std::initializer_list<bool> items) {
  return std::any_of(items.begin(), items.end(),
                     [](bool item) { return item; });
}

std::function<bool(const String &)> notEmpty() {
  return [](const String &str) { return str.length() > 0; };
}

template <typename T>
std::function<bool(const T &)> notZero() {
  return [](const T &val) { return val != 0; };
}

template <typename TVal, typename TKey>
bool setIfPresent(JsonObject &obj, TKey key, TVal &var,
                  const std::function<bool(const TVal &)> &validator =
                      std::function<bool(const TVal &)>()) {
  if (obj.containsKey(key)) {
    TVal tmp = obj.get<TVal>(key);
    if (tmp != var && (!validator || validator(tmp))) {
      var = tmp;
      return true;
    }
  }
  return false;
}

void Settings::registerChangeHandler(SettingType setting,
                                     const SettingCallbackFn &callback) {
  listeners.emplace_front(setting, callback);
}

void Settings::onConfigChange(SettingTypeSet typeSet) const {
  for (const auto &listener : listeners) {
    if (typeSet[listener.type]) {
      listener.callback(*this);
    }
  }
}

void Settings::load() {
  if (SPIFFS.exists(SETTINGS_FILE)) {
    File file = SPIFFS.open(SETTINGS_FILE, "r");
    if (!file) {
      Logger.error.println(F("Cannot open setings file!"));
      return;
    }
    String settingsContents = file.readStringUntil(SETTINGS_TERMINATOR);
    file.close();
    Logger.debug.println(F("FILE CONTENTS:"));
    Logger.debug.println(settingsContents);

    deserialize(settingsContents, false);
  }
}

void Settings::notifyAll() {
  // Fire for all
  onConfigChange(SettingTypeSet().set());
}

void Settings::save() {
  File file = SPIFFS.open(SETTINGS_FILE, "w");

  if (!file) {
    Logger.error.println(F("Opening settings file failed"));
  } else {
    serialize(file, false, true);
    file.close();
  }
}

Settings::~Settings() = default;

void Settings::serialize(Print &stream, bool pretty, bool sensible) const {
  DynamicJsonBuffer jsonBuffer;
  JsonObject &root = jsonBuffer.createObject();

  root[JsonKey::deviceName] = this->deviceName;
  root[JsonKey::mqttReceiveTopic] = this->mqttReceiveTopic;
  root[JsonKey::mqttSendTopic] = this->mqttSendTopic;
  root[JsonKey::mqttBroker] = this->mqttBroker;
  root[JsonKey::mqttBrokerPort] = this->mqttBrokerPort;
  root[JsonKey::mqttUser] = this->mqttUser;
  root[JsonKey::mqttRetain] = this->mqttRetain;
  root[JsonKey::rfReceiverPin] = this->rfReceiverPin;
  root[JsonKey::rfTransmitterPin] = this->rfTransmitterPin;
  root[JsonKey::rfEchoMessages] = this->rfEchoMessages;

  {
    DynamicJsonBuffer protoBuffer;
    JsonArray &parsedProtocols = protoBuffer.parseArray(this->rfProtocols);
    JsonArray &protos = root.createNestedArray(JsonKey::rfProtocols);
    for (const auto proto : parsedProtocols) {
      protos.add(proto.as<String>());
    }
  }

  root[JsonKey::serialLogLevel] = this->serialLogLevel;
  root[JsonKey::webLogLevel] = this->webLogLevel;
  root[JsonKey::syslogLevel] = this->syslogLevel;
  root[JsonKey::syslogHost] = this->syslogHost;
  root[JsonKey::syslogPort] = this->syslogPort;

  if (sensible) {
    root[JsonKey::mqttPassword] = this->mqttPassword;
    root[JsonKey::configPassword] = this->configPassword;
  }

  if (pretty) {
    root.prettyPrintTo(stream);
  } else {
    root.printTo(stream);
  }
}

void Settings::deserialize(const String &json, const bool fireCallbacks) {
  DynamicJsonBuffer jsonBuffer;
  JsonObject &parsedSettings = jsonBuffer.parseObject(json);

  if (!parsedSettings.success()) {
    Logger.warning.println(F("Config parse failed!"));
    return;
  }

  SettingTypeSet changed;

  changed.set(BASE, setIfPresent(parsedSettings, JsonKey::deviceName, deviceName,
                                 notEmpty()));

  changed.set(
      MQTT,
      any({setIfPresent(parsedSettings, JsonKey::mqttReceiveTopic,
                        mqttReceiveTopic),
           setIfPresent(parsedSettings, JsonKey::mqttSendTopic, mqttSendTopic),
           setIfPresent(parsedSettings, JsonKey::mqttBroker, mqttBroker,
                        notEmpty()),
           setIfPresent(parsedSettings, JsonKey::mqttBrokerPort, mqttBrokerPort,
                        notZero<uint16_t>()),
           setIfPresent(parsedSettings, JsonKey::mqttUser, mqttUser),
           setIfPresent(parsedSettings, JsonKey::mqttPassword, mqttPassword,
                        notEmpty()),
           setIfPresent(parsedSettings, JsonKey::mqttRetain, mqttRetain)}));

  changed.set(
      RF_CONFIG,
      any({setIfPresent(parsedSettings, JsonKey::rfReceiverPin, rfReceiverPin),
           setIfPresent(parsedSettings, JsonKey::rfTransmitterPin,
                        rfTransmitterPin)}));

  changed.set(RF_ECHO, (setIfPresent(parsedSettings, JsonKey::rfEchoMessages,
                                     rfEchoMessages)));

  if (parsedSettings.containsKey(JsonKey::rfProtocols)) {
    String buff;
    parsedSettings[JsonKey::rfProtocols].printTo(buff);
    if (buff != rfProtocols) {
      rfProtocols = buff;
      changed.set(RF_PROTOCOL, true);
    }
  }

  changed.set(
      LOGGING,
      any({setIfPresent(parsedSettings, JsonKey::serialLogLevel, serialLogLevel),
           setIfPresent(parsedSettings, JsonKey::webLogLevel, webLogLevel)}));

  changed.set(WEB_CONFIG, setIfPresent(parsedSettings, JsonKey::configPassword,
                                       configPassword, notEmpty()));

  changed.set(SYSLOG,
              any({setIfPresent(parsedSettings, JsonKey::syslogLevel, syslogLevel),
                   setIfPresent(parsedSettings, JsonKey::syslogHost, syslogHost),
                   setIfPresent(parsedSettings, JsonKey::syslogPort, syslogPort)}));

  if (fireCallbacks) {
    onConfigChange(changed);
  }
}

void Settings::reset() {
  if (SPIFFS.exists(SETTINGS_FILE)) {
    SPIFFS.remove(SETTINGS_FILE);
  }
}
<|endoftext|>


<commit_before>#include "osl/state/numEffectState.h"
#include "osl/effect_util/effectUtil.h"
#include "osl/container/moveVector.h"
#include "osl/record/csa.h"
#include "osl/move_generator/legalMoves.h"
#include <boost/random/mersenne_twister.hpp>
#include <string>
#include <sys/time.h>

namespace osl {
  void
  showState(const NumEffectState& state)
  {
    std::cout << state << std::endl;
  }

  Move
  selectMove(const NumEffectState& state, const MoveVector& moves)
  {
    static boost::mt11213b generator(random());
    return moves[generator() % moves.size()];
  }

  bool
  isMated(const NumEffectState& state)
  {
    return state.inCheck(alt(state.turn()));
  }

  bool
  computerOperate(NumEffectState& state)
  {
    MoveVector moves;
    LegalMoves::generate(state, moves);
    if (moves.empty()) {
      std::cerr << "make masita\n";
      return true;
    }
    const Move my_move = selectMove(state, moves);
    assert(state.isValidMove(my_move));
    state.makeMove(my_move);

    showState(state);
    csaShow(std::cout, my_move);
    std::cout << "\n";

    if (isMated(state)) {
      std::cerr << "checkmate!";
      return true;
    }

    return false;
  }
}

int
main()
{
  using namespace osl;

  srandom(time(0));

  NumEffectState state((SimpleState(HIRATE)));
  std::string line;
  while (true) {
    bool ended = computerOperate(state);
    if (ended) {
      break;
    }

    // 相手の指手を読みこむ
    if (! std::getline(std::cin, line)) {
      break;
    }

    const Move op_move=record::csa::strToMove(line, state);
    if (! state.isValidMove(op_move)) {
      break;
    }

    state.makeMove(op_move);

    showState(state);
    csaShow(std::cout, op_move);
    std::cout << "\n";
  }
}
<commit_msg>Extract code of player operation<commit_after>#include "osl/state/numEffectState.h"
#include "osl/effect_util/effectUtil.h"
#include "osl/container/moveVector.h"
#include "osl/record/csa.h"
#include "osl/move_generator/legalMoves.h"
#include <boost/random/mersenne_twister.hpp>
#include <string>
#include <sys/time.h>

namespace osl {
  void
  showState(const NumEffectState& state)
  {
    std::cout << state << std::endl;
  }

  Move
  selectMove(const NumEffectState& state, const MoveVector& moves)
  {
    static boost::mt11213b generator(random());
    return moves[generator() % moves.size()];
  }

  bool
  isMated(const NumEffectState& state)
  {
    return state.inCheck(alt(state.turn()));
  }

  bool
  computerOperate(NumEffectState& state)
  {
    MoveVector moves;
    LegalMoves::generate(state, moves);
    if (moves.empty()) {
      std::cerr << "make masita\n";
      return true;
    }
    const Move my_move = selectMove(state, moves);
    assert(state.isValidMove(my_move));
    state.makeMove(my_move);

    showState(state);
    csaShow(std::cout, my_move);
    std::cout << "\n";

    if (isMated(state)) {
      std::cerr << "checkmate!";
      return true;
    }

    return false;
  }

  bool
  playerOperate(std::string& line, NumEffectState& state)
  {
    if (! std::getline(std::cin, line)) {
      return true;
    }

    const Move op_move=record::csa::strToMove(line, state);
    if (! state.isValidMove(op_move)) {
      return true;
    }

    state.makeMove(op_move);

    showState(state);
    csaShow(std::cout, op_move);
    std::cout << "\n";

    return false;
  }
}

int
main()
{
  using namespace osl;

  srandom(time(0));

  NumEffectState state((SimpleState(HIRATE)));
  std::string line;
  while (true) {
    bool ended = computerOperate(state);
    if (ended) {
      break;
    }

    bool failed = playerOperate(line, state);
    if (failed) {
      break;
    }
  }
}
<|endoftext|>


<commit_before>#include <iostream>
#include "matrix.h"

using namespace std;

int main(){

	// New matrix, size: 10x10
	matrix<int> m(10, 10);

	// Inserts a value on the specified position and shows its content
	m[0][2] = 95;
	cout << m[0][2] << endl;

	// Makes the matrix bigger
	m.resize(20, 20);

	// Inserts a new value and shows its value
	m[11][8] = 100;
	cout << m[0][2] << ' ' << m[11][8] <<  endl;

	// Copy constructor
	matrix<int> m2(m);
	cout << m[11][8] << endl;

	//
	cin.ignore();

	return 0;
}<commit_msg>Delete Example.cpp<commit_after><|endoftext|>


<commit_before>
/*
 * ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2013, Numenta, Inc.  Unless you have purchased from
 * Numenta, Inc. a separate commercial license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

#include <nta/utils/Log.hpp>
#include <nta/ntypes/Dimensions.hpp>

using namespace nta;

// default dimensions are Unspecified
Dimensions::Dimensions() {};

Dimensions::Dimensions(std::vector<size_t> v) : std::vector<size_t>(v) {};

Dimensions::Dimensions(size_t x)
{
  push_back(x);
}

Dimensions::Dimensions(size_t x, size_t y)
{
  push_back(x);
  push_back(y);
}

Dimensions::Dimensions(size_t x, size_t y, size_t z)
{
  push_back(x);
  push_back(y);
  push_back(z);
}

size_t
Dimensions::getCount() const
{
  if (isUnspecified() || isDontcare())
    NTA_THROW << "Attempt to get count from dimensions " << toString();
  size_t count = 1;
  for (size_t i = 0; i < size(); i++)
    count *= at(i);
  if (count == 0)
    NTA_THROW << "Attempt to get count from invalid dimensions " << toString();
  return count;
}

size_t
Dimensions::getDimensionCount() const
{
  return size();
}

size_t
Dimensions::getDimension(size_t index) const
{
  if (index >= size())
  {
    NTA_THROW << "Bad request for dimension " << index
              << " on " << toString();
  }

  return at(index);
}

bool
Dimensions::isDontcare() const
{
  return (size() == 1 && at(0) == 0);
}

bool
Dimensions::isUnspecified() const
{
  return size() == 0;
}

bool
Dimensions::isOnes() const
{
  if (size() == 0)
    return false;

  for (size_t i = 0; i < size(); i++)
  {
    if (at(i) != 1)
      return false;
  }
  return true;
}

bool
Dimensions::isValid() const
{
  if (isDontcare() || isUnspecified())
    return true;

  for (size_t i = 0; i < size(); i++)
    if (at(i) == 0)
      return false;
  return true;
}

bool
Dimensions::isSpecified() const
{
  return isValid() && !isUnspecified() && !isDontcare();
}

// internal helper method
private static std::string vecToString(std::vector<size_t> vec)
{
  std::stringstream ss;
  for (size_t i = 0; i < vec.size(); i++)
  {
    ss << vec[i];
    if (i != vec.size()-1)
      ss << " ";
  }
  return ss.str();
}

std::string
Dimensions::toString(bool humanReadable) const
{
  if (humanReadable)
  {
    if (isUnspecified())
      return "[unspecified]";
    if (isDontcare())
      return "[dontcare]";
  }

  std::string s = "[";
  s += vecToString(*this);
  s += "]";
  if (humanReadable && !isValid())
    s += " (invalid)";

  return s;
}

size_t
Dimensions::getIndex(const Coordinate& coordinate) const
{
  if(coordinate.size() != size())
  {
    NTA_THROW << "Invalid coordinate [" << vecToString(coordinate)
              << "] for Dimensions " << toString();
  }

  size_t factor = 1;
  size_t index = 0;

  // We need to return an index based on x major ordering. We can't simply use
  // an unsigned or size_t because vector<>::size_type varies between
  // implementations (it is only required to be an unsigned type, not a
  // specific bit-depth).
  for(Coordinate::size_type dim = 0;
      dim != coordinate.size();
      dim++)
  {
    size_t thisdim = at(dim);
    if (coordinate[dim] >= thisdim)
    {
      NTA_THROW << "Invalid coordinate index " << dim
                << " of " << coordinate[dim]
                << " is too large for region dimensions " << toString();
    }
    index += factor * coordinate[dim];
    factor *=  thisdim;
  }
  return index;
}

Coordinate
Dimensions::getCoordinate(const size_t index) const
{
  Coordinate coordinate;
  size_t x = index;

  size_t product = 1;
  for(size_type i = 0; i < size(); i++)
  {
    product *= at(i);
  }

  for(size_type i = size()-1; i != (size_type)-1; i--)
  {
    product/=at(i);
    coordinate.insert(coordinate.begin(), x/product);
    x%=product;
  }

  return coordinate;
}

void
Dimensions::promote(size_t newDimensionality)
{
  if (! isOnes())
  {
    NTA_THROW << "Dimensions::promote -- must be all ones for Dimensions " << toString();
  }
  if (size() == newDimensionality)
    return;
  if (size() > newDimensionality)
    resize(newDimensionality);
  for (size_t i = size(); i < newDimensionality; i++)
    push_back(1);
}

bool
Dimensions::operator==(const Dimensions& dims2) const
{
  if ((std::vector<size_t>)(*this) == (std::vector<size_t>)dims2)
    return true;

  if (isOnes() && dims2.isOnes())
    return true;

  return false;
}

bool
Dimensions::operator!=(const Dimensions& dims2) const
{
  return ! operator==(dims2);
}

namespace nta
{
  std::ostream& operator<<(std::ostream& f, const Dimensions& d)
  {
    // temporary -- this might be hard to de-serialize
    f << d.toString(/* humanReadable: */ false);
    return f;
  }
}
<commit_msg>revert 'private', causing error<commit_after>
/*
 * ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2013, Numenta, Inc.  Unless you have purchased from
 * Numenta, Inc. a separate commercial license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

#include <nta/utils/Log.hpp>
#include <nta/ntypes/Dimensions.hpp>

using namespace nta;

// default dimensions are Unspecified
Dimensions::Dimensions() {};

Dimensions::Dimensions(std::vector<size_t> v) : std::vector<size_t>(v) {};

Dimensions::Dimensions(size_t x)
{
  push_back(x);
}

Dimensions::Dimensions(size_t x, size_t y)
{
  push_back(x);
  push_back(y);
}

Dimensions::Dimensions(size_t x, size_t y, size_t z)
{
  push_back(x);
  push_back(y);
  push_back(z);
}

size_t
Dimensions::getCount() const
{
  if (isUnspecified() || isDontcare())
    NTA_THROW << "Attempt to get count from dimensions " << toString();
  size_t count = 1;
  for (size_t i = 0; i < size(); i++)
    count *= at(i);
  if (count == 0)
    NTA_THROW << "Attempt to get count from invalid dimensions " << toString();
  return count;
}

size_t
Dimensions::getDimensionCount() const
{
  return size();
}

size_t
Dimensions::getDimension(size_t index) const
{
  if (index >= size())
  {
    NTA_THROW << "Bad request for dimension " << index
              << " on " << toString();
  }

  return at(index);
}

bool
Dimensions::isDontcare() const
{
  return (size() == 1 && at(0) == 0);
}

bool
Dimensions::isUnspecified() const
{
  return size() == 0;
}

bool
Dimensions::isOnes() const
{
  if (size() == 0)
    return false;

  for (size_t i = 0; i < size(); i++)
  {
    if (at(i) != 1)
      return false;
  }
  return true;
}

bool
Dimensions::isValid() const
{
  if (isDontcare() || isUnspecified())
    return true;

  for (size_t i = 0; i < size(); i++)
    if (at(i) == 0)
      return false;
  return true;
}

bool
Dimensions::isSpecified() const
{
  return isValid() && !isUnspecified() && !isDontcare();
}

// internal helper method
static std::string vecToString(std::vector<size_t> vec)
{
  std::stringstream ss;
  for (size_t i = 0; i < vec.size(); i++)
  {
    ss << vec[i];
    if (i != vec.size()-1)
      ss << " ";
  }
  return ss.str();
}

std::string
Dimensions::toString(bool humanReadable) const
{
  if (humanReadable)
  {
    if (isUnspecified())
      return "[unspecified]";
    if (isDontcare())
      return "[dontcare]";
  }

  std::string s = "[";
  s += vecToString(*this);
  s += "]";
  if (humanReadable && !isValid())
    s += " (invalid)";

  return s;
}

size_t
Dimensions::getIndex(const Coordinate& coordinate) const
{
  if(coordinate.size() != size())
  {
    NTA_THROW << "Invalid coordinate [" << vecToString(coordinate)
              << "] for Dimensions " << toString();
  }

  size_t factor = 1;
  size_t index = 0;

  // We need to return an index based on x major ordering. We can't simply use
  // an unsigned or size_t because vector<>::size_type varies between
  // implementations (it is only required to be an unsigned type, not a
  // specific bit-depth).
  for(Coordinate::size_type dim = 0;
      dim != coordinate.size();
      dim++)
  {
    size_t thisdim = at(dim);
    if (coordinate[dim] >= thisdim)
    {
      NTA_THROW << "Invalid coordinate index " << dim
                << " of " << coordinate[dim]
                << " is too large for region dimensions " << toString();
    }
    index += factor * coordinate[dim];
    factor *=  thisdim;
  }
  return index;
}

Coordinate
Dimensions::getCoordinate(const size_t index) const
{
  Coordinate coordinate;
  size_t x = index;

  size_t product = 1;
  for(size_type i = 0; i < size(); i++)
  {
    product *= at(i);
  }

  for(size_type i = size()-1; i != (size_type)-1; i--)
  {
    product/=at(i);
    coordinate.insert(coordinate.begin(), x/product);
    x%=product;
  }

  return coordinate;
}

void
Dimensions::promote(size_t newDimensionality)
{
  if (! isOnes())
  {
    NTA_THROW << "Dimensions::promote -- must be all ones for Dimensions " << toString();
  }
  if (size() == newDimensionality)
    return;
  if (size() > newDimensionality)
    resize(newDimensionality);
  for (size_t i = size(); i < newDimensionality; i++)
    push_back(1);
}

bool
Dimensions::operator==(const Dimensions& dims2) const
{
  if ((std::vector<size_t>)(*this) == (std::vector<size_t>)dims2)
    return true;

  if (isOnes() && dims2.isOnes())
    return true;

  return false;
}

bool
Dimensions::operator!=(const Dimensions& dims2) const
{
  return ! operator==(dims2);
}

namespace nta
{
  std::ostream& operator<<(std::ostream& f, const Dimensions& d)
  {
    // temporary -- this might be hard to de-serialize
    f << d.toString(/* humanReadable: */ false);
    return f;
  }
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * c7a/core/hashtable.hpp
 *
 * Hash table with support for reduce and partitions.
 ******************************************************************************/

#ifndef C7A_HASH_TABLE_HPP
#define C7A_HASH_TABLE_HPP

#include <map>
#include <iostream>
#include <c7a/common/logger.hpp>
#include <string>
#include <vector>
#include <stdexcept>
//#include <cstddef>

#include "c7a/api/function_traits.hpp"

//TODO:Remove when we have block manager
#include "c7a/data/data_manager.hpp"

namespace c7a {
namespace core {

struct hash_result {
    std::size_t partition_id; // which partition
    std::size_t partition_offset; // which idx within a partition
    std::size_t global_index;
};

template <typename key_t, typename value_t>
struct node {
    key_t key;
    value_t value;
    node *next;
};

template<typename KeyExtractor, typename ReduceFunction>
class HashTable
{

static const bool debug = true;

using key_t = typename FunctionTraits<KeyExtractor>::result_type;

using value_t = typename FunctionTraits<ReduceFunction>::result_type;

public:

  HashTable(std::size_t partition_size, KeyExtractor key_extractor,
	    ReduceFunction reduce_function, data::BlockEmitter<value_t> emit) :
        num_partitions_(partition_size),
        key_extractor_(key_extractor),
        reduce_function_(reduce_function),
        emit_(emit)
    {
        if (partition_size > num_buckets_) {
            throw std::invalid_argument("num partitions must be less than num buckets");
        }

        //num_buckets_ = num_partitions_*10; // TODO scale initial bucket size based on num of workers
        buckets_per_part_ = num_buckets_/num_partitions_;
        items_in_part_ = new int[num_partitions_];
        for (int i=0; i<num_partitions_; i++) { // TODO: just a tmp fix
            items_in_part_[i] = 0;
        }
    }

    ~HashTable() {
    }

    /*!
     * Inserts a key/value pair.
     *
     * Optionally, this may be reduce using the reduce function
     * in case the key already exists.
     */
    void Insert(value_t &p)
    {
        key_t key = key_extractor_(p);

        hash_result h = hash(std::to_string(key));

        LOG << "key: "
            << key
            << " to idx: "
            << h.global_index;

        // bucket is empty
        if (a[h.global_index] == nullptr) {

            LOG << "bucket empty, inserting...";

            node<key_t, value_t> *n = new node<key_t, value_t>;
            n->key = key;
            n->value = p;
            n->next = nullptr;
            a[h.global_index] = n;

            // increase counter for partition
            items_in_part_[h.partition_id]++;

            // increase total counter
            total_table_size_++;

        // bucket is not empty
        } else {

            LOG << "bucket not empty, checking if key already exists...";

            // check if item with same key
            node<key_t, value_t> *curr_node = a[h.global_index];
            value_t *curr_value;
            do {
                curr_value = &curr_node->value;
                if (key == curr_node->key) {

                    LOG << "match of key: "
                        << key
                        << " and "
                        << curr_node->key
                        << " ... reducing...";

                    (*curr_node).value = reduce_function_(curr_node->value, p);

                    LOG << "...finished reduce!";

                    break;
                }

                curr_node = curr_node->next;
            } while (curr_node != nullptr);

            // no item found with key
            if (curr_node == nullptr) {

                LOG << "key doesn't exists in bucket, appending...";

                // insert at first pos
                node<key_t, value_t> *n = new node<key_t, value_t>;
                n->key = key;
                n->value = p;
                n->next = a[h.global_index];
                a[h.global_index] = n;

                // increase counter for partition
                items_in_part_[h.partition_id]++;
                // increase total counter
                total_table_size_++;

                LOG << "key appendend, metrics updated!";
            }
        }

        // TODO should be externally configureably somehow
        if (total_table_size_ > max_table_size_) {
            LOG << "spilling in progress";
            PopLargestSubtable();
        }
    }

    /*!
     * Returns a vector containing all items belonging to the partition
     * having the most items.
     */
    void PopLargestSubtable() {

        // get partition with max size
        int p_size_max = 0;
        int p_idx = 0;
        for (int i=0; i<num_partitions_; i++) {
            if (items_in_part_[i] > p_size_max) {
                p_size_max = items_in_part_[i];
                p_idx = i;
            }
        }

        LOG << "currMax: "
            << p_size_max
            << " currentIdx: "
            << p_idx
            << " currentIdx*p_size: "
            << p_idx * buckets_per_part_
            << " CurrentIdx*p_size+p_size-1 "
            << p_idx * buckets_per_part_ + buckets_per_part_ - 1;

        // retrieve items
        for (int i=p_idx*buckets_per_part_; i<=p_idx*buckets_per_part_+buckets_per_part_-1; i++) {
            if (a[i] != nullptr) {
                node<key_t, value_t> *curr_node = a[i];
                do {
		            emit_(curr_node->value);
                    curr_node = curr_node->next;
                } while (curr_node != nullptr);
                a[i] = nullptr;
            }
        }

        // reset partition specific counter
        items_in_part_[p_idx] = 0;
        // reset total counter
        total_table_size_ -=p_size_max;
    }

    /*!
     * Returns a map containing all items per partition.
     */
    std::map<int, std::vector<value_t>> Erase() {

        // retrieve items
        std::map<int, std::vector<value_t>> items;
        for (int i=0; i<num_partitions_; i++) {
            std::vector<value_t> curr_items;
            for (int j=i*buckets_per_part_; j<=i*buckets_per_part_+buckets_per_part_-1; j++) {
                if (a[i] != nullptr) {
                    items.insert(std::make_pair<int, std::vector<value_t>>(i, curr_items));
                    node<key_t, value_t> *curr_node = a[i];
                    do {
                        curr_items.push_back(curr_node->value);
                        curr_node = curr_node->next;
                    } while (curr_node != nullptr);
                    a[i] = nullptr;
                }
            }

            // set size of partition to 0
            items_in_part_[i] = 0;
        }

        // reset counters
        total_table_size_ = 0;

        return items;
    }

    /*!
     * Returns the total num of items.
     */
    std::size_t Size() {
        return total_table_size_;
    }

    void Resize() {
        LOG << "to be implemented";
    }

    // prints content of hash table
    void Print() {

        for (int i=0; i<num_buckets_; i++) {
            if (a[i] == nullptr) {

                LOG << "bucket "
                    << i
                    << " empty";

            } else {

                std::string log = "";

                // check if item with same key
                node<key_t, value_t> *curr_node = a[i];
                value_t curr_item;
                do {
                    curr_item = curr_node->value;

                    log += "(";
                    log += curr_item.second;
                    log += ") ";

                    curr_node = curr_node->next;
                } while (curr_node != nullptr);

                LOG << "bucket "
                    << i
                    << ": "
                    << log;
            }
        }

        return;
    }

private:

    int max_table_size_ = 3; //maximum number of elements in whole table, spill largest subtable when full

    int num_partitions_ = 0; // partition size

    int buckets_per_part_ = 0; // num buckets per partition

    int* items_in_part_; // num items per partition

    int total_table_size_ = 0; // total sum of items

    static const int num_buckets_ = 100; // bucket size

    KeyExtractor key_extractor_;

    ReduceFunction reduce_function_;

    //TODO:Network-Emitter when it's there (:
    data::BlockEmitter<value_t> emit_;

    node<key_t, value_t> *a[num_buckets_] = { nullptr }; // TODO: fix this static assignment

    hash_result hash(std::string v) {

        hash_result *h = new hash_result();

        // partition idx
        std::size_t hashed = std::hash<std::string>()(v);
        h->partition_offset = hashed % buckets_per_part_;

        // partition id
        h->partition_id = h->partition_offset % num_partitions_;

        // global idx
        h->global_index = h->partition_offset + h->partition_id * buckets_per_part_;

        return *h;
    }
};

}
}

#endif //C7A_HASH_TABLE_HPP

/******************************************************************************/
<commit_msg>run uncrustify<commit_after>/*******************************************************************************
 * c7a/core/hashtable.hpp
 *
 * Hash table with support for reduce and partitions.
 ******************************************************************************/

#ifndef C7A_HASH_TABLE_HPP
#define C7A_HASH_TABLE_HPP

#include <map>
#include <iostream>
#include <c7a/common/logger.hpp>
#include <string>
#include <vector>
#include <stdexcept>
//#include <cstddef>

#include "c7a/api/function_traits.hpp"

//TODO:Remove when we have block manager
#include "c7a/data/data_manager.hpp"

namespace c7a {
namespace core {
struct hash_result {
    std::size_t partition_id;     // which partition
    std::size_t partition_offset; // which idx within a partition
    std::size_t global_index;
};

template <typename key_t, typename value_t>
struct node {
    key_t   key;
    value_t value;
    node    * next;
};

template <typename KeyExtractor, typename ReduceFunction>
class HashTable
{
    static const bool debug = true;

    using key_t = typename FunctionTraits<KeyExtractor>::result_type;

    using value_t = typename FunctionTraits<ReduceFunction>::result_type;

public:
    HashTable(std::size_t partition_size, KeyExtractor key_extractor,
              ReduceFunction reduce_function, data::BlockEmitter<value_t> emit) :
        num_partitions_(partition_size),
        key_extractor_(key_extractor),
        reduce_function_(reduce_function),
        emit_(emit)
    {
        if (partition_size > num_buckets_) {
            throw std::invalid_argument("num partitions must be less than num buckets");
        }

        //num_buckets_ = num_partitions_*10; // TODO scale initial bucket size based on num of workers
        buckets_per_part_ = num_buckets_ / num_partitions_;
        items_in_part_ = new int[num_partitions_];
        for (int i = 0; i < num_partitions_; i++) { // TODO: just a tmp fix
            items_in_part_[i] = 0;
        }
    }

    ~HashTable() { }

    /*!
     * Inserts a key/value pair.
     *
     * Optionally, this may be reduce using the reduce function
     * in case the key already exists.
     */
    void Insert(value_t& p)
    {
        key_t key = key_extractor_(p);

        hash_result h = hash(std::to_string(key));

        LOG << "key: "
            << key
            << " to idx: "
            << h.global_index;

        // bucket is empty
        if (a[h.global_index] == nullptr) {
            LOG << "bucket empty, inserting...";

            node<key_t, value_t>* n = new node<key_t, value_t>;
            n->key = key;
            n->value = p;
            n->next = nullptr;
            a[h.global_index] = n;

            // increase counter for partition
            items_in_part_[h.partition_id]++;

            // increase total counter
            total_table_size_++;

            // bucket is not empty
        }
        else {
            LOG << "bucket not empty, checking if key already exists...";

            // check if item with same key
            node<key_t, value_t>* curr_node = a[h.global_index];
            value_t* curr_value;
            do {
                curr_value = &curr_node->value;
                if (key == curr_node->key) {
                    LOG << "match of key: "
                        << key
                        << " and "
                        << curr_node->key
                        << " ... reducing...";

                    (*curr_node).value = reduce_function_(curr_node->value, p);

                    LOG << "...finished reduce!";

                    break;
                }

                curr_node = curr_node->next;
            } while (curr_node != nullptr);

            // no item found with key
            if (curr_node == nullptr) {
                LOG << "key doesn't exists in bucket, appending...";

                // insert at first pos
                node<key_t, value_t>* n = new node<key_t, value_t>;
                n->key = key;
                n->value = p;
                n->next = a[h.global_index];
                a[h.global_index] = n;

                // increase counter for partition
                items_in_part_[h.partition_id]++;
                // increase total counter
                total_table_size_++;

                LOG << "key appendend, metrics updated!";
            }
        }

        // TODO should be externally configureably somehow
        if (total_table_size_ > max_table_size_) {
            LOG << "spilling in progress";
            PopLargestSubtable();
        }
    }

    /*!
     * Returns a vector containing all items belonging to the partition
     * having the most items.
     */
    void PopLargestSubtable()
    {
        // get partition with max size
        int p_size_max = 0;
        int p_idx = 0;
        for (int i = 0; i < num_partitions_; i++) {
            if (items_in_part_[i] > p_size_max) {
                p_size_max = items_in_part_[i];
                p_idx = i;
            }
        }

        LOG << "currMax: "
            << p_size_max
            << " currentIdx: "
            << p_idx
            << " currentIdx*p_size: "
            << p_idx * buckets_per_part_
            << " CurrentIdx*p_size+p_size-1 "
            << p_idx * buckets_per_part_ + buckets_per_part_ - 1;

        // retrieve items
        for (int i = p_idx * buckets_per_part_; i <= p_idx * buckets_per_part_ + buckets_per_part_ - 1; i++) {
            if (a[i] != nullptr) {
                node<key_t, value_t>* curr_node = a[i];
                do {
                    emit_(curr_node->value);
                    curr_node = curr_node->next;
                } while (curr_node != nullptr);
                a[i] = nullptr;
            }
        }

        // reset partition specific counter
        items_in_part_[p_idx] = 0;
        // reset total counter
        total_table_size_ -= p_size_max;
    }

    /*!
     * Returns a map containing all items per partition.
     */
    std::map<int, std::vector<value_t> > Erase()
    {
        // retrieve items
        std::map<int, std::vector<value_t> > items;
        for (int i = 0; i < num_partitions_; i++) {
            std::vector<value_t> curr_items;
            for (int j = i * buckets_per_part_; j <= i * buckets_per_part_ + buckets_per_part_ - 1; j++) {
                if (a[i] != nullptr) {
                    items.insert(std::make_pair<int, std::vector<value_t> >(i, curr_items));
                    node<key_t, value_t>* curr_node = a[i];
                    do {
                        curr_items.push_back(curr_node->value);
                        curr_node = curr_node->next;
                    } while (curr_node != nullptr);
                    a[i] = nullptr;
                }
            }

            // set size of partition to 0
            items_in_part_[i] = 0;
        }

        // reset counters
        total_table_size_ = 0;

        return items;
    }

    /*!
     * Returns the total num of items.
     */
    std::size_t Size()
    {
        return total_table_size_;
    }

    void Resize()
    {
        LOG << "to be implemented";
    }

    // prints content of hash table
    void Print()
    {
        for (int i = 0; i < num_buckets_; i++) {
            if (a[i] == nullptr) {
                LOG << "bucket "
                    << i
                    << " empty";
            }
            else {
                std::string log = "";

                // check if item with same key
                node<key_t, value_t>* curr_node = a[i];
                value_t curr_item;
                do {
                    curr_item = curr_node->value;

                    log += "(";
                    log += curr_item.second;
                    log += ") ";

                    curr_node = curr_node->next;
                } while (curr_node != nullptr);

                LOG << "bucket "
                    << i
                    << ": "
                    << log;
            }
        }

        return;
    }

private:
    int max_table_size_ = 3;             //maximum number of elements in whole table, spill largest subtable when full

    int num_partitions_ = 0;             // partition size

    int buckets_per_part_ = 0;           // num buckets per partition

    int* items_in_part_;                 // num items per partition

    int total_table_size_ = 0;           // total sum of items

    static const int num_buckets_ = 100; // bucket size

    KeyExtractor key_extractor_;

    ReduceFunction reduce_function_;

    //TODO:Network-Emitter when it's there (:
    data::BlockEmitter<value_t> emit_;

    node<key_t, value_t>* a[num_buckets_] = { nullptr }; // TODO: fix this static assignment

    hash_result hash(std::string v)
    {
        hash_result* h = new hash_result();

        // partition idx
        std::size_t hashed = std::hash<std::string>()(v);
        h->partition_offset = hashed % buckets_per_part_;

        // partition id
        h->partition_id = h->partition_offset % num_partitions_;

        // global idx
        h->global_index = h->partition_offset + h->partition_id * buckets_per_part_;

        return *h;
    }
};
}
}

#endif //C7A_HASH_TABLE_HPP

/******************************************************************************/
<|endoftext|>


<commit_before>/* Copyright 2014 Andrew Schwartzmeyer
 *
 * Source file for derived genetic algorithm class
 */

#include <algorithm>
#include <iostream>
#include <iterator>

#include "genetic_algorithm.hpp"
#include "random_generator.hpp"

const Individual Genetic::mutate(const Individual & subject) const {
  // unit Gaussian distribution for delta
  Individual mutation = subject;
  normal_dist delta_dist(mean, stddev);
  for (parameter & gene : mutation)
    mutation.mutate(gene, gene * delta_dist(rg.engine));
  mutation.fitness = problem.fitness(mutation);
  return mutation;
}

const Individual Genetic::selection(const Genetic::population & contestants) const {
  // return best Individual from a set of contestants
  return *std::max_element(contestants.begin(), contestants.end());
}

const Genetic::population Genetic::crossover(const Genetic::population & mates) const {
  // return two offspring for two mates
  return mates;
}

const Individual Genetic::solve() const {
  while(true) {
    // create initial population
    population generation;
    for (int i = 0; i < population_size; ++i)
      generation.emplace_back(problem.potential());
    // generations loop
    for (long i = 0; i < problem.iterations; ++i) {
      // find generation's best member (general form of selection)
      const Individual best = selection(generation);
      // terminating condition
      if (best.fitness > problem.goal) return best;
      // std::cout << best.fitness << '\n';
      // selection and mutation stage
      population offspring;
      while(offspring.size() != population_size) {
	// tournament selection of parents
	population parents;
	for (int i = 0; i < crossover_size; ++i) {
	  population contestants;
	  int_dist population_dist(0, population_size-1); // closed interval
	  // create tournament of random members drawn from generation
	  for (int i = 0; i < tournament_size; ++i)
	    contestants.emplace_back(generation[population_dist(rg.engine)]);
	  // select best member from each tournament
	  parents.emplace_back(selection(contestants));
	}
	// crossover
	population children = crossover(parents);
	// add mutated children to offspring
	for (const Individual child : children) offspring.emplace_back(mutate(child));
      }
      // replace generation with offspring
      generation.swap(offspring);
    }
    std::cout << "Exhausted generations!\n";
  }
}
<commit_msg>Adding probability to GA mutation<commit_after>/* Copyright 2014 Andrew Schwartzmeyer
 *
 * Source file for derived genetic algorithm class
 */

#include <algorithm>
#include <iostream>
#include <iterator>

#include "genetic_algorithm.hpp"
#include "random_generator.hpp"

const Individual Genetic::mutate(const Individual & subject) const {
  // unit Gaussian distribution for delta
  Individual mutant = subject;
  int_dist percent(1, 100);
  normal_dist delta_dist(mean, stddev);
  for (parameter & gene : mutant)
    if (problem.chance || percent(rg.engine) < int(100 * problem.chance))
      mutant.mutate(gene, gene * delta_dist(rg.engine));
  // update fitness
  mutant.fitness = problem.fitness(mutant);
  return mutant;
}

const Individual Genetic::selection(const Genetic::population & contestants) const {
  // return best Individual from a set of contestants
  return *std::max_element(contestants.begin(), contestants.end());
}

const Genetic::population Genetic::crossover(const Genetic::population & mates) const {
  // return two offspring for two mates
  return mates;
}

const Individual Genetic::solve() const {
  while(true) {
    // create initial population
    population generation;
    for (int i = 0; i < population_size; ++i)
      generation.emplace_back(problem.potential());
    // generations loop
    for (long i = 0; i < problem.iterations; ++i) {
      // find generation's best member (general form of selection)
      const Individual best = selection(generation);
      // terminating condition
      if (best.fitness > problem.goal) return best;
      // std::cout << best.fitness << '\n';
      // selection and mutation stage
      population offspring;
      while(offspring.size() != population_size) {
	// tournament selection of parents
	population parents;
	for (int i = 0; i < crossover_size; ++i) {
	  population contestants;
	  int_dist population_dist(0, population_size-1); // closed interval
	  // create tournament of random members drawn from generation
	  for (int i = 0; i < tournament_size; ++i)
	    contestants.emplace_back(generation[population_dist(rg.engine)]);
	  // select best member from each tournament
	  parents.emplace_back(selection(contestants));
	}
	// crossover
	population children = crossover(parents);
	// add mutated children to offspring
	for (const Individual child : children) offspring.emplace_back(mutate(child));
      }
      // replace generation with offspring
      generation.swap(offspring);
    }
    std::cout << "Exhausted generations!\n";
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017-present Facebook, 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 <folly/experimental/symbolizer/Elf.h>

#include <fcntl.h>
#include <folly/portability/SysMman.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <string>

#include <glog/logging.h>

#include <folly/Conv.h>
#include <folly/Exception.h>
#include <folly/ScopeGuard.h>

#ifndef STT_GNU_IFUNC
#define STT_GNU_IFUNC 10
#endif

namespace folly {
namespace symbolizer {

ElfFile::ElfFile() noexcept
    : fd_(-1),
      file_(static_cast<char*>(MAP_FAILED)),
      length_(0),
      baseAddress_(0) {}

ElfFile::ElfFile(const char* name, bool readOnly)
    : fd_(-1),
      file_(static_cast<char*>(MAP_FAILED)),
      length_(0),
      baseAddress_(0) {
  open(name, readOnly);
}

void ElfFile::open(const char* name, bool readOnly) {
  const char* msg = "";
  int r = openNoThrow(name, readOnly, &msg);
  if (r == kSystemError) {
    throwSystemError(msg);
  } else {
    CHECK_EQ(r, kSuccess) << msg;
  }
}

int ElfFile::openNoThrow(
    const char* name,
    bool readOnly,
    const char** msg) noexcept {
  FOLLY_SAFE_CHECK(fd_ == -1, "File already open");
  fd_ = ::open(name, readOnly ? O_RDONLY : O_RDWR);
  if (fd_ == -1) {
    if (msg) {
      *msg = "open";
    }
    return kSystemError;
  }
  // Always close fd and unmap in case of failure along the way to avoid
  // check failure above if we leave fd != -1 and the object is recycled
  // like it is inside SignalSafeElfCache
  ScopeGuard guard = makeGuard([&] { reset(); });
  struct stat st;
  int r = fstat(fd_, &st);
  if (r == -1) {
    if (msg) {
      *msg = "fstat";
    }
    return kSystemError;
  }

  length_ = st.st_size;
  int prot = PROT_READ;
  if (!readOnly) {
    prot |= PROT_WRITE;
  }
  file_ = static_cast<char*>(mmap(nullptr, length_, prot, MAP_SHARED, fd_, 0));
  if (file_ == MAP_FAILED) {
    if (msg) {
      *msg = "mmap";
    }
    return kSystemError;
  }
  if (!init(msg)) {
    errno = EINVAL;
    return kInvalidElfFile;
  }
  guard.dismiss();
  return kSuccess;
}

int ElfFile::openAndFollow(
    const char* name,
    bool readOnly,
    const char** msg) noexcept {
  auto result = openNoThrow(name, readOnly, msg);
  if (!readOnly || result != kSuccess) {
    return result;
  }

  /* NOTE .gnu_debuglink specifies only the name of the debugging info file
   * (with no directory components). GDB checks 3 different directories, but
   * ElfFile only supports the first version:
   *     - dirname(name)
   *     - dirname(name) + /.debug/
   *     - X/dirname(name)/ - where X is set in gdb's `debug-file-directory`.
   */
  auto dirend = strrchr(name, '/');
  // include ending '/' if any.
  auto dirlen = dirend != nullptr ? dirend + 1 - name : 0;

  auto debuginfo = getSectionByName(".gnu_debuglink");
  if (!debuginfo) {
    return result;
  }

  // The section starts with the filename, with any leading directory
  // components removed, followed by a zero byte.
  auto debugFileName = getSectionBody(*debuginfo);
  auto debugFileLen = strlen(debugFileName.begin());
  if (dirlen + debugFileLen >= PATH_MAX) {
    return result;
  }

  char linkname[PATH_MAX];
  memcpy(linkname, name, dirlen);
  memcpy(linkname + dirlen, debugFileName.begin(), debugFileLen + 1);
  reset();
  result = openNoThrow(linkname, readOnly, msg);
  if (result == kSuccess) {
    return result;
  }
  return openNoThrow(name, readOnly, msg);
}

ElfFile::~ElfFile() {
  reset();
}

ElfFile::ElfFile(ElfFile&& other) noexcept
    : fd_(other.fd_),
      file_(other.file_),
      length_(other.length_),
      baseAddress_(other.baseAddress_) {
  other.fd_ = -1;
  other.file_ = static_cast<char*>(MAP_FAILED);
  other.length_ = 0;
  other.baseAddress_ = 0;
}

ElfFile& ElfFile::operator=(ElfFile&& other) {
  assert(this != &other);
  reset();

  fd_ = other.fd_;
  file_ = other.file_;
  length_ = other.length_;
  baseAddress_ = other.baseAddress_;

  other.fd_ = -1;
  other.file_ = static_cast<char*>(MAP_FAILED);
  other.length_ = 0;
  other.baseAddress_ = 0;

  return *this;
}

void ElfFile::reset() {
  if (file_ != MAP_FAILED) {
    munmap(file_, length_);
    file_ = static_cast<char*>(MAP_FAILED);
  }

  if (fd_ != -1) {
    close(fd_);
    fd_ = -1;
  }
}

bool ElfFile::init(const char** msg) {
  auto& elfHeader = this->elfHeader();

  // Validate ELF magic numbers
  if (!(elfHeader.e_ident[EI_MAG0] == ELFMAG0 &&
        elfHeader.e_ident[EI_MAG1] == ELFMAG1 &&
        elfHeader.e_ident[EI_MAG2] == ELFMAG2 &&
        elfHeader.e_ident[EI_MAG3] == ELFMAG3)) {
    if (msg) {
      *msg = "invalid ELF magic";
    }
    return false;
  }

#define EXPECTED_CLASS P1(ELFCLASS, __ELF_NATIVE_CLASS)
#define P1(a, b) P2(a, b)
#define P2(a, b) a##b
  // Validate ELF class (32/64 bits)
  if (elfHeader.e_ident[EI_CLASS] != EXPECTED_CLASS) {
    if (msg) {
      *msg = "invalid ELF class";
    }
    return false;
  }
#undef P1
#undef P2
#undef EXPECTED_CLASS

  // Validate ELF data encoding (LSB/MSB)
  static constexpr auto kExpectedEncoding =
      kIsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB;
  if (elfHeader.e_ident[EI_DATA] != kExpectedEncoding) {
    if (msg) {
      *msg = "invalid ELF encoding";
    }
    return false;
  }

  // Validate ELF version (1)
  if (elfHeader.e_ident[EI_VERSION] != EV_CURRENT ||
      elfHeader.e_version != EV_CURRENT) {
    if (msg) {
      *msg = "invalid ELF version";
    }
    return false;
  }

  // We only support executable and shared object files
  if (elfHeader.e_type != ET_EXEC && elfHeader.e_type != ET_DYN) {
    if (msg) {
      *msg = "invalid ELF file type";
    }
    return false;
  }

  if (elfHeader.e_phnum == 0) {
    if (msg) {
      *msg = "no program header!";
    }
    return false;
  }

  if (elfHeader.e_phentsize != sizeof(ElfPhdr)) {
    if (msg) {
      *msg = "invalid program header entry size";
    }
    return false;
  }

  if (elfHeader.e_shentsize != sizeof(ElfShdr)) {
    if (msg) {
      *msg = "invalid section header entry size";
    }
  }

  // Program headers are sorted by load address, so the first PT_LOAD
  // header gives us the base address.
  const ElfPhdr* programHeader =
      iterateProgramHeaders([](auto& h) { return h.p_type == PT_LOAD; });

  if (!programHeader) {
    if (msg) {
      *msg = "could not find base address";
    }
    return false;
  }
  baseAddress_ = programHeader->p_vaddr;

  return true;
}

const ElfShdr* ElfFile::getSectionByIndex(size_t idx) const {
  FOLLY_SAFE_CHECK(idx < elfHeader().e_shnum, "invalid section index");
  return &at<ElfShdr>(elfHeader().e_shoff + idx * sizeof(ElfShdr));
}

folly::StringPiece ElfFile::getSectionBody(const ElfShdr& section) const {
  return folly::StringPiece(file_ + section.sh_offset, section.sh_size);
}

void ElfFile::validateStringTable(const ElfShdr& stringTable) const {
  FOLLY_SAFE_CHECK(
      stringTable.sh_type == SHT_STRTAB, "invalid type for string table");

  const char* start = file_ + stringTable.sh_offset;
  // First and last bytes must be 0
  FOLLY_SAFE_CHECK(
      stringTable.sh_size == 0 ||
          (start[0] == '\0' && start[stringTable.sh_size - 1] == '\0'),
      "invalid string table");
}

const char* ElfFile::getString(const ElfShdr& stringTable, size_t offset)
    const {
  validateStringTable(stringTable);
  FOLLY_SAFE_CHECK(
      offset < stringTable.sh_size, "invalid offset in string table");

  return file_ + stringTable.sh_offset + offset;
}

const char* ElfFile::getSectionName(const ElfShdr& section) const {
  if (elfHeader().e_shstrndx == SHN_UNDEF) {
    return nullptr; // no section name string table
  }

  const ElfShdr& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
  return getString(sectionNames, section.sh_name);
}

const ElfShdr* ElfFile::getSectionByName(const char* name) const {
  if (elfHeader().e_shstrndx == SHN_UNDEF) {
    return nullptr; // no section name string table
  }

  // Find offset in the section name string table of the requested name
  const ElfShdr& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
  const char* foundName = iterateStrings(
      sectionNames, [&](const char* s) { return !strcmp(name, s); });
  if (foundName == nullptr) {
    return nullptr;
  }

  size_t offset = foundName - (file_ + sectionNames.sh_offset);

  // Find section with the appropriate sh_name offset
  const ElfShdr* foundSection = iterateSections([&](const ElfShdr& sh) {
    if (sh.sh_name == offset) {
      return true;
    }
    return false;
  });
  return foundSection;
}

ElfFile::Symbol ElfFile::getDefinitionByAddress(uintptr_t address) const {
  Symbol foundSymbol{nullptr, nullptr};

  auto findSection = [&](const ElfShdr& section) {
    auto findSymbols = [&](const ElfSym& sym) {
      if (sym.st_shndx == SHN_UNDEF) {
        return false; // not a definition
      }
      if (address >= sym.st_value && address < sym.st_value + sym.st_size) {
        foundSymbol.first = &section;
        foundSymbol.second = &sym;
        return true;
      }

      return false;
    };

    return iterateSymbolsWithTypes(
        section, {STT_OBJECT, STT_FUNC, STT_GNU_IFUNC}, findSymbols);
  };

  // Try the .dynsym section first if it exists, it's smaller.
  (iterateSectionsWithType(SHT_DYNSYM, findSection) ||
   iterateSectionsWithType(SHT_SYMTAB, findSection));

  return foundSymbol;
}

ElfFile::Symbol ElfFile::getSymbolByName(const char* name) const {
  Symbol foundSymbol{nullptr, nullptr};

  auto findSection = [&](const ElfShdr& section) -> bool {
    // This section has no string table associated w/ its symbols; hence we
    // can't get names for them
    if (section.sh_link == SHN_UNDEF) {
      return false;
    }

    auto findSymbols = [&](const ElfSym& sym) -> bool {
      if (sym.st_shndx == SHN_UNDEF) {
        return false; // not a definition
      }
      if (sym.st_name == 0) {
        return false; // no name for this symbol
      }
      const char* sym_name =
          getString(*getSectionByIndex(section.sh_link), sym.st_name);
      if (strcmp(sym_name, name) == 0) {
        foundSymbol.first = &section;
        foundSymbol.second = &sym;
        return true;
      }

      return false;
    };

    return iterateSymbolsWithTypes(
        section, {STT_OBJECT, STT_FUNC, STT_GNU_IFUNC}, findSymbols);
  };

  // Try the .dynsym section first if it exists, it's smaller.
  iterateSectionsWithType(SHT_DYNSYM, findSection) ||
      iterateSectionsWithType(SHT_SYMTAB, findSection);

  return foundSymbol;
}

const ElfShdr* ElfFile::getSectionContainingAddress(ElfAddr addr) const {
  return iterateSections([&](const ElfShdr& sh) -> bool {
    return (addr >= sh.sh_addr) && (addr < (sh.sh_addr + sh.sh_size));
  });
}

const char* ElfFile::getSymbolName(Symbol symbol) const {
  if (!symbol.first || !symbol.second) {
    return nullptr;
  }

  if (symbol.second->st_name == 0) {
    return nullptr; // symbol has no name
  }

  if (symbol.first->sh_link == SHN_UNDEF) {
    return nullptr; // symbol table has no strings
  }

  return getString(
      *getSectionByIndex(symbol.first->sh_link), symbol.second->st_name);
}

} // namespace symbolizer
} // namespace folly
<commit_msg>Fix ElfFile crashing when opening short (<64 bytes) files.<commit_after>/*
 * Copyright 2017-present Facebook, 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 <folly/experimental/symbolizer/Elf.h>

#include <fcntl.h>
#include <folly/portability/SysMman.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <string>

#include <glog/logging.h>

#include <folly/Conv.h>
#include <folly/Exception.h>
#include <folly/ScopeGuard.h>

#ifndef STT_GNU_IFUNC
#define STT_GNU_IFUNC 10
#endif

namespace folly {
namespace symbolizer {

ElfFile::ElfFile() noexcept
    : fd_(-1),
      file_(static_cast<char*>(MAP_FAILED)),
      length_(0),
      baseAddress_(0) {}

ElfFile::ElfFile(const char* name, bool readOnly)
    : fd_(-1),
      file_(static_cast<char*>(MAP_FAILED)),
      length_(0),
      baseAddress_(0) {
  open(name, readOnly);
}

void ElfFile::open(const char* name, bool readOnly) {
  const char* msg = "";
  int r = openNoThrow(name, readOnly, &msg);
  if (r == kSystemError) {
    throwSystemError(msg);
  } else {
    CHECK_EQ(r, kSuccess) << msg;
  }
}

int ElfFile::openNoThrow(
    const char* name,
    bool readOnly,
    const char** msg) noexcept {
  FOLLY_SAFE_CHECK(fd_ == -1, "File already open");
  fd_ = ::open(name, readOnly ? O_RDONLY : O_RDWR);
  if (fd_ == -1) {
    if (msg) {
      *msg = "open";
    }
    return kSystemError;
  }
  // Always close fd and unmap in case of failure along the way to avoid
  // check failure above if we leave fd != -1 and the object is recycled
  // like it is inside SignalSafeElfCache
  ScopeGuard guard = makeGuard([&] { reset(); });
  struct stat st;
  int r = fstat(fd_, &st);
  if (r == -1) {
    if (msg) {
      *msg = "fstat";
    }
    return kSystemError;
  }

  length_ = st.st_size;
  int prot = PROT_READ;
  if (!readOnly) {
    prot |= PROT_WRITE;
  }
  file_ = static_cast<char*>(mmap(nullptr, length_, prot, MAP_SHARED, fd_, 0));
  if (file_ == MAP_FAILED) {
    if (msg) {
      *msg = "mmap";
    }
    return kSystemError;
  }
  if (!init(msg)) {
    errno = EINVAL;
    return kInvalidElfFile;
  }
  guard.dismiss();
  return kSuccess;
}

int ElfFile::openAndFollow(
    const char* name,
    bool readOnly,
    const char** msg) noexcept {
  auto result = openNoThrow(name, readOnly, msg);
  if (!readOnly || result != kSuccess) {
    return result;
  }

  /* NOTE .gnu_debuglink specifies only the name of the debugging info file
   * (with no directory components). GDB checks 3 different directories, but
   * ElfFile only supports the first version:
   *     - dirname(name)
   *     - dirname(name) + /.debug/
   *     - X/dirname(name)/ - where X is set in gdb's `debug-file-directory`.
   */
  auto dirend = strrchr(name, '/');
  // include ending '/' if any.
  auto dirlen = dirend != nullptr ? dirend + 1 - name : 0;

  auto debuginfo = getSectionByName(".gnu_debuglink");
  if (!debuginfo) {
    return result;
  }

  // The section starts with the filename, with any leading directory
  // components removed, followed by a zero byte.
  auto debugFileName = getSectionBody(*debuginfo);
  auto debugFileLen = strlen(debugFileName.begin());
  if (dirlen + debugFileLen >= PATH_MAX) {
    return result;
  }

  char linkname[PATH_MAX];
  memcpy(linkname, name, dirlen);
  memcpy(linkname + dirlen, debugFileName.begin(), debugFileLen + 1);
  reset();
  result = openNoThrow(linkname, readOnly, msg);
  if (result == kSuccess) {
    return result;
  }
  return openNoThrow(name, readOnly, msg);
}

ElfFile::~ElfFile() {
  reset();
}

ElfFile::ElfFile(ElfFile&& other) noexcept
    : fd_(other.fd_),
      file_(other.file_),
      length_(other.length_),
      baseAddress_(other.baseAddress_) {
  other.fd_ = -1;
  other.file_ = static_cast<char*>(MAP_FAILED);
  other.length_ = 0;
  other.baseAddress_ = 0;
}

ElfFile& ElfFile::operator=(ElfFile&& other) {
  assert(this != &other);
  reset();

  fd_ = other.fd_;
  file_ = other.file_;
  length_ = other.length_;
  baseAddress_ = other.baseAddress_;

  other.fd_ = -1;
  other.file_ = static_cast<char*>(MAP_FAILED);
  other.length_ = 0;
  other.baseAddress_ = 0;

  return *this;
}

void ElfFile::reset() {
  if (file_ != MAP_FAILED) {
    munmap(file_, length_);
    file_ = static_cast<char*>(MAP_FAILED);
  }

  if (fd_ != -1) {
    close(fd_);
    fd_ = -1;
  }
}

bool ElfFile::init(const char** msg) {
  if (length_ < 4) {
    if (msg) {
      *msg = "not an ELF file (too short)";
    }
    return false;
  }

  // Validate ELF magic numbers
  if (file_[EI_MAG0] != ELFMAG0 || file_[EI_MAG1] != ELFMAG1 ||
      file_[EI_MAG2] != ELFMAG2 || file_[EI_MAG3] != ELFMAG3) {
    if (msg) {
      *msg = "invalid ELF magic";
    }
    return false;
  }

  auto& elfHeader = this->elfHeader();

#define EXPECTED_CLASS P1(ELFCLASS, __ELF_NATIVE_CLASS)
#define P1(a, b) P2(a, b)
#define P2(a, b) a##b
  // Validate ELF class (32/64 bits)
  if (elfHeader.e_ident[EI_CLASS] != EXPECTED_CLASS) {
    if (msg) {
      *msg = "invalid ELF class";
    }
    return false;
  }
#undef P1
#undef P2
#undef EXPECTED_CLASS

  // Validate ELF data encoding (LSB/MSB)
  static constexpr auto kExpectedEncoding =
      kIsLittleEndian ? ELFDATA2LSB : ELFDATA2MSB;
  if (elfHeader.e_ident[EI_DATA] != kExpectedEncoding) {
    if (msg) {
      *msg = "invalid ELF encoding";
    }
    return false;
  }

  // Validate ELF version (1)
  if (elfHeader.e_ident[EI_VERSION] != EV_CURRENT ||
      elfHeader.e_version != EV_CURRENT) {
    if (msg) {
      *msg = "invalid ELF version";
    }
    return false;
  }

  // We only support executable and shared object files
  if (elfHeader.e_type != ET_EXEC && elfHeader.e_type != ET_DYN) {
    if (msg) {
      *msg = "invalid ELF file type";
    }
    return false;
  }

  if (elfHeader.e_phnum == 0) {
    if (msg) {
      *msg = "no program header!";
    }
    return false;
  }

  if (elfHeader.e_phentsize != sizeof(ElfPhdr)) {
    if (msg) {
      *msg = "invalid program header entry size";
    }
    return false;
  }

  if (elfHeader.e_shentsize != sizeof(ElfShdr)) {
    if (msg) {
      *msg = "invalid section header entry size";
    }
  }

  // Program headers are sorted by load address, so the first PT_LOAD
  // header gives us the base address.
  const ElfPhdr* programHeader =
      iterateProgramHeaders([](auto& h) { return h.p_type == PT_LOAD; });

  if (!programHeader) {
    if (msg) {
      *msg = "could not find base address";
    }
    return false;
  }
  baseAddress_ = programHeader->p_vaddr;

  return true;
}

const ElfShdr* ElfFile::getSectionByIndex(size_t idx) const {
  FOLLY_SAFE_CHECK(idx < elfHeader().e_shnum, "invalid section index");
  return &at<ElfShdr>(elfHeader().e_shoff + idx * sizeof(ElfShdr));
}

folly::StringPiece ElfFile::getSectionBody(const ElfShdr& section) const {
  return folly::StringPiece(file_ + section.sh_offset, section.sh_size);
}

void ElfFile::validateStringTable(const ElfShdr& stringTable) const {
  FOLLY_SAFE_CHECK(
      stringTable.sh_type == SHT_STRTAB, "invalid type for string table");

  const char* start = file_ + stringTable.sh_offset;
  // First and last bytes must be 0
  FOLLY_SAFE_CHECK(
      stringTable.sh_size == 0 ||
          (start[0] == '\0' && start[stringTable.sh_size - 1] == '\0'),
      "invalid string table");
}

const char* ElfFile::getString(const ElfShdr& stringTable, size_t offset)
    const {
  validateStringTable(stringTable);
  FOLLY_SAFE_CHECK(
      offset < stringTable.sh_size, "invalid offset in string table");

  return file_ + stringTable.sh_offset + offset;
}

const char* ElfFile::getSectionName(const ElfShdr& section) const {
  if (elfHeader().e_shstrndx == SHN_UNDEF) {
    return nullptr; // no section name string table
  }

  const ElfShdr& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
  return getString(sectionNames, section.sh_name);
}

const ElfShdr* ElfFile::getSectionByName(const char* name) const {
  if (elfHeader().e_shstrndx == SHN_UNDEF) {
    return nullptr; // no section name string table
  }

  // Find offset in the section name string table of the requested name
  const ElfShdr& sectionNames = *getSectionByIndex(elfHeader().e_shstrndx);
  const char* foundName = iterateStrings(
      sectionNames, [&](const char* s) { return !strcmp(name, s); });
  if (foundName == nullptr) {
    return nullptr;
  }

  size_t offset = foundName - (file_ + sectionNames.sh_offset);

  // Find section with the appropriate sh_name offset
  const ElfShdr* foundSection = iterateSections([&](const ElfShdr& sh) {
    if (sh.sh_name == offset) {
      return true;
    }
    return false;
  });
  return foundSection;
}

ElfFile::Symbol ElfFile::getDefinitionByAddress(uintptr_t address) const {
  Symbol foundSymbol{nullptr, nullptr};

  auto findSection = [&](const ElfShdr& section) {
    auto findSymbols = [&](const ElfSym& sym) {
      if (sym.st_shndx == SHN_UNDEF) {
        return false; // not a definition
      }
      if (address >= sym.st_value && address < sym.st_value + sym.st_size) {
        foundSymbol.first = &section;
        foundSymbol.second = &sym;
        return true;
      }

      return false;
    };

    return iterateSymbolsWithTypes(
        section, {STT_OBJECT, STT_FUNC, STT_GNU_IFUNC}, findSymbols);
  };

  // Try the .dynsym section first if it exists, it's smaller.
  (iterateSectionsWithType(SHT_DYNSYM, findSection) ||
   iterateSectionsWithType(SHT_SYMTAB, findSection));

  return foundSymbol;
}

ElfFile::Symbol ElfFile::getSymbolByName(const char* name) const {
  Symbol foundSymbol{nullptr, nullptr};

  auto findSection = [&](const ElfShdr& section) -> bool {
    // This section has no string table associated w/ its symbols; hence we
    // can't get names for them
    if (section.sh_link == SHN_UNDEF) {
      return false;
    }

    auto findSymbols = [&](const ElfSym& sym) -> bool {
      if (sym.st_shndx == SHN_UNDEF) {
        return false; // not a definition
      }
      if (sym.st_name == 0) {
        return false; // no name for this symbol
      }
      const char* sym_name =
          getString(*getSectionByIndex(section.sh_link), sym.st_name);
      if (strcmp(sym_name, name) == 0) {
        foundSymbol.first = &section;
        foundSymbol.second = &sym;
        return true;
      }

      return false;
    };

    return iterateSymbolsWithTypes(
        section, {STT_OBJECT, STT_FUNC, STT_GNU_IFUNC}, findSymbols);
  };

  // Try the .dynsym section first if it exists, it's smaller.
  iterateSectionsWithType(SHT_DYNSYM, findSection) ||
      iterateSectionsWithType(SHT_SYMTAB, findSection);

  return foundSymbol;
}

const ElfShdr* ElfFile::getSectionContainingAddress(ElfAddr addr) const {
  return iterateSections([&](const ElfShdr& sh) -> bool {
    return (addr >= sh.sh_addr) && (addr < (sh.sh_addr + sh.sh_size));
  });
}

const char* ElfFile::getSymbolName(Symbol symbol) const {
  if (!symbol.first || !symbol.second) {
    return nullptr;
  }

  if (symbol.second->st_name == 0) {
    return nullptr; // symbol has no name
  }

  if (symbol.first->sh_link == SHN_UNDEF) {
    return nullptr; // symbol table has no strings
  }

  return getString(
      *getSectionByIndex(symbol.first->sh_link), symbol.second->st_name);
}

} // namespace symbolizer
} // namespace folly
<|endoftext|>