<commit_before>#include "joedb/io/merge.h"
#include "joedb/interpreter/Database.h"

/////////////////////////////////////////////////////////////////////////////
void joedb::merge(Database &merged, const Database &db)
/////////////////////////////////////////////////////////////////////////////
{
 std::map<Table_Id, Record_Id> offset;

 //
 // First loop over tables to fill the offset map
 //
 for (auto table: merged.get_tables())
 {
  const Table_Id table_id = table.first;
  const Record_Id last_record_id = merged.get_last_record_id(table_id);
  offset[table_id] = last_record_id;
 }

 //
 // Second loop to copy data, with added offset
 //
 for (auto table: merged.get_tables())
 {
  const Table_Id table_id = table.first;
  const Record_Id last_record_id = db.get_last_record_id(table_id);
  const Compact_Freedom_Keeper &freedom_keeper = db.get_freedom(table_id);

  if (freedom_keeper.is_compact())
  {
   merged.insert_vector(table_id, offset[table_id] + 1, last_record_id);

   for (const auto &field: db.get_fields(table_id))
   {
    const Field_Id field_id = field.first;
    const Type &type = db.get_field_type(table_id, field_id);
    Record_Id capacity;

    switch (type.get_type_id())
    {
     case Type::Type_Id::null:
     break;

     #define TYPE_MACRO(type, return_type, type_id, R, W)\
     case Type::Type_Id::type_id:\
     {\
      merged.update_vector_##type_id\
      (\
       table_id,\
       offset[table_id] + 1,\
       field_id,\
       last_record_id,\
       db.get_own_##type_id##_const_storage(table_id, 1, field_id, capacity)\
      );\
     }\
     break;
     #include "joedb/TYPE_MACRO.h"
    }

    if (type.get_type_id() == Type::Type_Id::reference)
    {
     const Record_Id reference_offset = offset[type.get_table_id()];

     Record_Id *reference = merged.get_own_reference_storage
     (
      table_id,
      offset[table_id] + 1,
      field_id,
      capacity
     );

     for (Record_Id i = 0; i < last_record_id; i++)
      if (reference[i] > 0)
       reference[i] += reference_offset;
    }
   }
  }
  else
   for (Record_Id record_id = 1; record_id <= last_record_id; record_id++)
    if (freedom_keeper.is_used(record_id + 1))
    {
     const Record_Id merged_record_id = record_id + offset[table_id];
     merged.insert_into(table_id, merged_record_id);

     for (const auto &field: db.get_fields(table_id))
     {
      const Field_Id field_id = field.first;
      const Type &type = db.get_field_type(table_id, field_id);

      switch (type.get_type_id())
      {
       case Type::Type_Id::null:
       break;

       case Type::Type_Id::reference:
       {
        Record_Id referenced = db.get_reference(table_id, record_id, field_id);
        if (referenced > 0)
         referenced += offset[type.get_table_id()];
        merged.update_reference
        (
         table_id,
         merged_record_id,
         field_id,
         referenced
        );
       }
       break;

       #define TYPE_MACRO(type, return_type, type_id, R, W)\
       case Type::Type_Id::type_id:\
       {\
        merged.update_##type_id\
        (\
         table_id,\
         merged_record_id,\
         field_id,\
         db.get_##type_id(table_id, record_id, field_id)\
        );\
       }\
       break;
       #define TYPE_MACRO_NO_REFERENCE
       #include "joedb/TYPE_MACRO.h"
      }
     }
    }
 }
}
<commit_msg>fix bug when merging empty tables (need test)<commit_after>#include "joedb/io/merge.h"
#include "joedb/interpreter/Database.h"

/////////////////////////////////////////////////////////////////////////////
void joedb::merge(Database &merged, const Database &db)
/////////////////////////////////////////////////////////////////////////////
{
 std::map<Table_Id, Record_Id> offset;

 //
 // First loop over tables to fill the offset map
 //
 for (auto table: merged.get_tables())
 {
  const Table_Id table_id = table.first;
  const Record_Id last_record_id = merged.get_last_record_id(table_id);
  offset[table_id] = last_record_id;
 }

 //
 // Second loop to copy data, with added offset
 //
 for (auto table: merged.get_tables())
 {
  const Table_Id table_id = table.first;
  const Record_Id last_record_id = db.get_last_record_id(table_id);
  const Compact_Freedom_Keeper &freedom_keeper = db.get_freedom(table_id);

  if (last_record_id == 0)
  {
   // do nothing, table is empty
  }
  else if (freedom_keeper.is_compact())
  {
   merged.insert_vector(table_id, offset[table_id] + 1, last_record_id);

   for (const auto &field: db.get_fields(table_id))
   {
    const Field_Id field_id = field.first;
    const Type &type = db.get_field_type(table_id, field_id);
    Record_Id capacity;

    switch (type.get_type_id())
    {
     case Type::Type_Id::null:
     break;

     #define TYPE_MACRO(type, return_type, type_id, R, W)\
     case Type::Type_Id::type_id:\
     {\
      merged.update_vector_##type_id\
      (\
       table_id,\
       offset[table_id] + 1,\
       field_id,\
       last_record_id,\
       db.get_own_##type_id##_const_storage(table_id, 1, field_id, capacity)\
      );\
     }\
     break;
     #include "joedb/TYPE_MACRO.h"
    }

    if (type.get_type_id() == Type::Type_Id::reference)
    {
     const Record_Id reference_offset = offset[type.get_table_id()];

     Record_Id *reference = merged.get_own_reference_storage
     (
      table_id,
      offset[table_id] + 1,
      field_id,
      capacity
     );

     for (Record_Id i = 0; i < last_record_id; i++)
      if (reference[i] > 0)
       reference[i] += reference_offset;
    }
   }
  }
  else
   for (Record_Id record_id = 1; record_id <= last_record_id; record_id++)
    if (freedom_keeper.is_used(record_id + 1))
    {
     const Record_Id merged_record_id = record_id + offset[table_id];
     merged.insert_into(table_id, merged_record_id);

     for (const auto &field: db.get_fields(table_id))
     {
      const Field_Id field_id = field.first;
      const Type &type = db.get_field_type(table_id, field_id);

      switch (type.get_type_id())
      {
       case Type::Type_Id::null:
       break;

       case Type::Type_Id::reference:
       {
        Record_Id referenced = db.get_reference(table_id, record_id, field_id);
        if (referenced > 0)
         referenced += offset[type.get_table_id()];
        merged.update_reference
        (
         table_id,
         merged_record_id,
         field_id,
         referenced
        );
       }
       break;

       #define TYPE_MACRO(type, return_type, type_id, R, W)\
       case Type::Type_Id::type_id:\
       {\
        merged.update_##type_id\
        (\
         table_id,\
         merged_record_id,\
         field_id,\
         db.get_##type_id(table_id, record_id, field_id)\
        );\
       }\
       break;
       #define TYPE_MACRO_NO_REFERENCE
       #include "joedb/TYPE_MACRO.h"
      }
     }
    }
 }
}
<|endoftext|>


<commit_before>
/**
 * This file is part of the boostcache package.
 *
 * (c) Azat Khuzhin <a3at.mail@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#include "command.h"
#include "commands.h"
#include "util/log.h"

#include <boost/spirit/include/qi.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/format.hpp>

const char *Command::REPLY_FALSE              = ":0\r\n";
const char *Command::REPLY_TRUE               = ":1\r\n";
const char *Command::REPLY_NIL                = "$-1\r\n";
const char *Command::REPLY_OK                 = "+OK\r\n";
const char *Command::REPLY_ERROR              = "-ERR\r\n";
const char *Command::REPLY_ERROR_NOTSUPPORTED = "-ERR Not supported\r\n";

namespace qi = boost::spirit::qi;

std::string Command::toReplyString(const std::string& string)
{
    return str(boost::format("$%i\r\n%s\r\n") % string.size() % string);
}
std::string Command::toErrorReplyString(const std::string& string)
{
    return str(boost::format("-ERR %s\r\n") % string);
}

bool Command::feedAndParseCommand(const char *buffer, size_t size)
{
    m_commandString.append(buffer, size);
    LOG(trace) << "Try to read/parser command(" << m_commandString.length() << ") "
               "with " << m_numberOfArguments << " arguments, "
               "for " << this;

    std::istringstream stream(m_commandString);
    stream.seekg(m_commandOffset);
    if (!handleStreamIsValid(stream)) {
        // Need to feed more data
        return true;
    }

    // Try to read new command
    if (m_numberOfArguments < 0) {
        // We have inline request, because it is not start with '*'
        if (m_commandString[0] != '*') {
            if (!parseInline(stream)) {
                reset();
                return true;
            }
        } else if (!parseNumberOfArguments(stream)) {
            // Need to feed more data
            return true;
        }
    }

    if ((m_type == MULTI_BULK) && !parseArguments(stream)) {
        // Need to feed more data
        return true;
    }

    executeCommand();
    return false;
}

bool Command::parseInline(std::istringstream& stream)
{
    m_type = INLINE;

    std::getline(stream, m_lineBuffer);
    if (!handleStreamIsValid(stream)) {
        return false;
    }
    m_commandOffset = stream.tellg();

    boost::trim_right(m_lineBuffer);
    splitString(m_lineBuffer, m_commandArguments);

    if (!m_commandArguments.size() || !m_commandArguments[0].size() /* no command */) {
        return false;
    }

    LOG(trace) << "Have " << m_commandArguments.size() << " arguments, "
               << "for " << this << " (inline)";

    return true;
}

bool Command::parseNumberOfArguments(std::istringstream& stream)
{
    m_type = MULTI_BULK;

    std::getline(stream, m_lineBuffer);
    qi::parse(m_lineBuffer.begin(), m_lineBuffer.end(),
              '*' >> qi::int_ >> "\r",
              m_numberOfArguments);

    if (m_numberOfArguments < 0) {
        LOG(debug) << "Don't have number of arguments, for " << this;

        reset();
        return false;
    }

    m_commandArguments.reserve(m_numberOfArguments);
    m_numberOfArgumentsLeft = m_numberOfArguments;
    m_commandOffset = stream.tellg();

    LOG(trace) << "Have " << m_numberOfArguments << " arguments, "
               << "for " << this << " (bulk)";

    return true;
}

bool Command::parseArguments(std::istringstream& stream)
{
    char crLf[2];
    char *argument = NULL;
    int argumentLength = 0;

    while (m_numberOfArgumentsLeft && std::getline(stream, m_lineBuffer)) {
        if (!qi::parse(m_lineBuffer.begin(), m_lineBuffer.end(),
                       '$' >> qi::int_ >> "\r",
                       m_lastArgumentLength)
        ) {
            LOG(debug) << "Can't find valid argument length, for " << this;
            reset();
            break;
        }
        LOG(trace) << "Reading " << m_lastArgumentLength << " bytes, for " << this;

        if (argumentLength < m_lastArgumentLength) {
            argument = (char *)realloc(argument, argumentLength + 1 /* NULL byte */
                                       + m_lastArgumentLength);
            argumentLength += m_lastArgumentLength;
        }
        stream.read(argument, m_lastArgumentLength);
        argument[m_lastArgumentLength] = 0;
        if (!handleStreamIsValid(stream)) {
            break;
        }
        // Read CRLF separator
        stream.read(crLf, 2);
        if (!handleStreamIsValid(stream)) {
            break;
        }
        if (memcmp(crLf, "\r\n", 2) != 0) {
            LOG(debug) << "Malfomed end of argument, for " << this;
            reset();
            break;
        }
        // Save command argument
        LOG(trace) << "Saving " << argument << " argument, for " << this;
        m_commandArguments.push_back(argument);
        m_lastArgumentLength = -1;

        // Update some counters/offsets
        --m_numberOfArgumentsLeft;
        m_commandOffset = stream.tellg();
    }

    return !m_numberOfArgumentsLeft;
}

void Command::executeCommand()
{
    LOG(trace) << "Execute new command, for " << this;

    /**
     * TODO: We need here something like vector::pop() method,
     * but it is slow for vectors.
     * So need to think on it.
     * As a temporary decision for one hashtable db I will just not use 0 index.
     */

    Commands& commands = TheCommands::instance();
    m_finishCallback((commands.find(m_commandArguments[0],
                                    m_commandArguments.size() - 1))
    (
         m_commandArguments
    ));

    reset();
}

std::string Command::toString() const
{
    std::string arguments;
    int i;
    for_each(m_commandArguments.begin(), m_commandArguments.end(),
             [&arguments, &i] (std::string argument)
             {
                  arguments += ++i;
                  arguments += " " "'";
                  arguments += argument;
                  arguments += "'" "\n";
             }
    );

    return arguments;
}

void Command::reset()
{
    m_type = NOT_SET;
    m_commandString.clear();
    m_commandOffset = 0;
    m_numberOfArguments = -1;
    m_numberOfArgumentsLeft = -1;
    m_lastArgumentLength = -1;

    m_commandArguments.clear();
}

bool Command::handleStreamIsValid(const std::istringstream& stream)
{
    if (stream.good()) {
        return true;
    }

    /**
     * TODO: add some internal counters for failover,
     * or smth like this
     */
    if (stream.bad()) {
        LOG(debug) << "Bad stream, for " << this;
        reset();
    }

    return false;
}

void Command::splitString(const std::string &string, std::vector<std::string>& destination)
{
    const char *cString = string.c_str();
    const char *lastCString = cString;
    while (true) {
        if (*cString == ' ' || *cString == '\0') {
            destination.push_back(std::string(lastCString, cString - lastCString));

            if (*cString == '\0') {
                break;
            }

            // Avoid copying whitespace
            lastCString = (cString + 1);
        }

        ++cString;
    }
}<commit_msg>[kernel/command] don't print int as string in toString() method<commit_after>
/**
 * This file is part of the boostcache package.
 *
 * (c) Azat Khuzhin <a3at.mail@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#include "command.h"
#include "commands.h"
#include "util/log.h"

#include <boost/spirit/include/qi.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/format.hpp>

const char *Command::REPLY_FALSE              = ":0\r\n";
const char *Command::REPLY_TRUE               = ":1\r\n";
const char *Command::REPLY_NIL                = "$-1\r\n";
const char *Command::REPLY_OK                 = "+OK\r\n";
const char *Command::REPLY_ERROR              = "-ERR\r\n";
const char *Command::REPLY_ERROR_NOTSUPPORTED = "-ERR Not supported\r\n";

namespace qi = boost::spirit::qi;

std::string Command::toReplyString(const std::string& string)
{
    return str(boost::format("$%i\r\n%s\r\n") % string.size() % string);
}
std::string Command::toErrorReplyString(const std::string& string)
{
    return str(boost::format("-ERR %s\r\n") % string);
}

bool Command::feedAndParseCommand(const char *buffer, size_t size)
{
    m_commandString.append(buffer, size);
    LOG(trace) << "Try to read/parser command(" << m_commandString.length() << ") "
               "with " << m_numberOfArguments << " arguments, "
               "for " << this;

    std::istringstream stream(m_commandString);
    stream.seekg(m_commandOffset);
    if (!handleStreamIsValid(stream)) {
        // Need to feed more data
        return true;
    }

    // Try to read new command
    if (m_numberOfArguments < 0) {
        // We have inline request, because it is not start with '*'
        if (m_commandString[0] != '*') {
            if (!parseInline(stream)) {
                reset();
                return true;
            }
        } else if (!parseNumberOfArguments(stream)) {
            // Need to feed more data
            return true;
        }
    }

    if ((m_type == MULTI_BULK) && !parseArguments(stream)) {
        // Need to feed more data
        return true;
    }

    executeCommand();
    return false;
}

bool Command::parseInline(std::istringstream& stream)
{
    m_type = INLINE;

    std::getline(stream, m_lineBuffer);
    if (!handleStreamIsValid(stream)) {
        return false;
    }
    m_commandOffset = stream.tellg();

    boost::trim_right(m_lineBuffer);
    splitString(m_lineBuffer, m_commandArguments);

    if (!m_commandArguments.size() || !m_commandArguments[0].size() /* no command */) {
        return false;
    }

    LOG(trace) << "Have " << m_commandArguments.size() << " arguments, "
               << "for " << this << " (inline)";

    return true;
}

bool Command::parseNumberOfArguments(std::istringstream& stream)
{
    m_type = MULTI_BULK;

    std::getline(stream, m_lineBuffer);
    qi::parse(m_lineBuffer.begin(), m_lineBuffer.end(),
              '*' >> qi::int_ >> "\r",
              m_numberOfArguments);

    if (m_numberOfArguments < 0) {
        LOG(debug) << "Don't have number of arguments, for " << this;

        reset();
        return false;
    }

    m_commandArguments.reserve(m_numberOfArguments);
    m_numberOfArgumentsLeft = m_numberOfArguments;
    m_commandOffset = stream.tellg();

    LOG(trace) << "Have " << m_numberOfArguments << " arguments, "
               << "for " << this << " (bulk)";

    return true;
}

bool Command::parseArguments(std::istringstream& stream)
{
    char crLf[2];
    char *argument = NULL;
    int argumentLength = 0;

    while (m_numberOfArgumentsLeft && std::getline(stream, m_lineBuffer)) {
        if (!qi::parse(m_lineBuffer.begin(), m_lineBuffer.end(),
                       '$' >> qi::int_ >> "\r",
                       m_lastArgumentLength)
        ) {
            LOG(debug) << "Can't find valid argument length, for " << this;
            reset();
            break;
        }
        LOG(trace) << "Reading " << m_lastArgumentLength << " bytes, for " << this;

        if (argumentLength < m_lastArgumentLength) {
            argument = (char *)realloc(argument, argumentLength + 1 /* NULL byte */
                                       + m_lastArgumentLength);
            argumentLength += m_lastArgumentLength;
        }
        stream.read(argument, m_lastArgumentLength);
        argument[m_lastArgumentLength] = 0;
        if (!handleStreamIsValid(stream)) {
            break;
        }
        // Read CRLF separator
        stream.read(crLf, 2);
        if (!handleStreamIsValid(stream)) {
            break;
        }
        if (memcmp(crLf, "\r\n", 2) != 0) {
            LOG(debug) << "Malfomed end of argument, for " << this;
            reset();
            break;
        }
        // Save command argument
        LOG(trace) << "Saving " << argument << " argument, for " << this;
        m_commandArguments.push_back(argument);
        m_lastArgumentLength = -1;

        // Update some counters/offsets
        --m_numberOfArgumentsLeft;
        m_commandOffset = stream.tellg();
    }

    return !m_numberOfArgumentsLeft;
}

void Command::executeCommand()
{
    LOG(trace) << "Execute new command, for " << this;

    /**
     * TODO: We need here something like vector::pop() method,
     * but it is slow for vectors.
     * So need to think on it.
     * As a temporary decision for one hashtable db I will just not use 0 index.
     */

    Commands& commands = TheCommands::instance();
    m_finishCallback((commands.find(m_commandArguments[0],
                                    m_commandArguments.size() - 1))
    (
         m_commandArguments
    ));

    reset();
}

std::string Command::toString() const
{
    std::string arguments;
    int i;
    for_each(m_commandArguments.begin(), m_commandArguments.end(),
             [&arguments, &i] (std::string argument)
             {
                  arguments += "'";
                  arguments += argument;
                  arguments += "'" "\n";
             }
    );

    return arguments;
}

void Command::reset()
{
    m_type = NOT_SET;
    m_commandString.clear();
    m_commandOffset = 0;
    m_numberOfArguments = -1;
    m_numberOfArgumentsLeft = -1;
    m_lastArgumentLength = -1;

    m_commandArguments.clear();
}

bool Command::handleStreamIsValid(const std::istringstream& stream)
{
    if (stream.good()) {
        return true;
    }

    /**
     * TODO: add some internal counters for failover,
     * or smth like this
     */
    if (stream.bad()) {
        LOG(debug) << "Bad stream, for " << this;
        reset();
    }

    return false;
}

void Command::splitString(const std::string &string, std::vector<std::string>& destination)
{
    const char *cString = string.c_str();
    const char *lastCString = cString;
    while (true) {
        if (*cString == ' ' || *cString == '\0') {
            destination.push_back(std::string(lastCString, cString - lastCString));

            if (*cString == '\0') {
                break;
            }

            // Avoid copying whitespace
            lastCString = (cString + 1);
        }

        ++cString;
    }
}<|endoftext|>


<commit_before>#include <IOKit/IOLib.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/pwr_mgt/IOPM.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include "InsomniaT.h"

#define super IOService

OSDefineMetaClassAndStructors(net_trajano_driver_InsomniaT, IOService)

IOReturn handleSleepWakeInterest( void * target, void * refCon,
								 UInt32 messageType, IOService * provider,
								 void * messageArgument, vm_size_t argSize )
{
	net_trajano_driver_InsomniaT *obj = (net_trajano_driver_InsomniaT*)target;
	if (obj->isLoggingEnabled()) {
		IOLog("InsomniaT: handleSleepWakeInterest invoked with message type %x.\n", (unsigned int)messageType);
	}
	if (messageType == kIOPMMessageClamshellStateChange) {
		if (obj->isLoggingEnabled()) {
			IOLog("InsomniaT: message type is kIOPMMessageClamshellStateChange.\n");
		}
		obj->updateSystemSleep();
	}
	return 0;
}

void net_trajano_driver_InsomniaT::updateSystemSleep() {
	if (isLoggingEnabled()) {
		IOLog("InsomniaT: sleep status is being updated.\n");
	}
	if (isLoggingEnabled() && isSleepEnabled()) {
		IOLog("InsomniaT: sleep is enabled\n");
	}
	if (isLoggingEnabled() && !isSleepEnabled()) {
		IOLog("InsomniaT: sleep is disabled\n");
	}
	if (isLoggingEnabled() && isSleepEnabledBySystem()) {
		IOLog("InsomniaT: sleep is enabled by system\n");
	}
	if (isLoggingEnabled() && !isSleepEnabledBySystem()) {
		IOLog("InsomniaT: sleep is disabled by system\n");
	}

    if (isSleepEnabled() && !isSleepEnabledBySystem()) {
		if (isLoggingEnabled()) {
			IOLog("InsomniaT: enabling sleep.\n");
		}
		enableSleep();
	} else if (!isSleepEnabled() && isSleepEnabledBySystem()) {
		if (isLoggingEnabled()) {
			IOLog("InsomniaT: disabling sleep.\n");
		}
		disableSleep();
	}
}
bool net_trajano_driver_InsomniaT::isMultipleDisplays() {
    OSDictionary* dict = OSDictionary::withCapacity(1);
    dict->setObject(kIOProviderClassKey, OSString::withCStringNoCopy("IODisplayConnect"));
    OSIterator* ioDisplayConnectIterator = getMatchingServices(dict);
    unsigned int displayCount = 0;
    OSObject* obj;
    while ((obj = ioDisplayConnectIterator->getNextObject()) != NULL && displayCount < 2) {
        ++displayCount;
    }
    ioDisplayConnectIterator->release();
    dict->release();
    return displayCount > 1;
}
bool net_trajano_driver_InsomniaT::start(IOService *provider)
{
	IOPMrootDomain *root = getPMRootDomain();

	IOWorkLoop *workloop = getWorkLoop();
	if (!workloop) {
		return false;
	}

	fAppleClamshellCausesSleep = root->getProperty(kAppleClamshellCausesSleepKey);
    fNotifier = registerSleepWakeInterest(handleSleepWakeInterest, this);
	disableSleep();

    bool res = super::start(provider);
	if (res) {
		registerService();
	}
	return res;
}

void net_trajano_driver_InsomniaT::disableSleep() {
    if (isMultipleDisplays()) {
		if (isLoggingEnabled()) {
			IOLog("InsomniaT: multiple displays detected doing nothing.\n");
		}
        return;
    }
	IOPMrootDomain *root = getPMRootDomain();
	root->setProperty(kAppleClamshellCausesSleepKey,kOSBooleanFalse);
    // Calling this method will set the ignoringClamShell to true for the PM root domain.
	root->receivePowerNotification(kIOPMDisableClamshell);
	if (isLoggingEnabled()) {
		IOLog("InsomniaT: disabling sleep complete\n");
	}
}

/**
 * SleepEnabled key.
 */
const char* net_trajano_driver_InsomniaT::gKeySleepEnabled = "SleepEnabled";

/**
 * LoggingEnabled key.
 */
const char* net_trajano_driver_InsomniaT::gKeyLoggingEnabled = "LoggingEnabled";

bool net_trajano_driver_InsomniaT::isSleepEnabled() {
	return ((OSBoolean*)getProperty(gKeySleepEnabled))->getValue();
}

bool net_trajano_driver_InsomniaT::isLoggingEnabled() {
	return ((OSBoolean*)getProperty(gKeyLoggingEnabled))->getValue();
}

bool net_trajano_driver_InsomniaT::isSleepEnabledBySystem() {
	IOPMrootDomain *root = getPMRootDomain();
	return root->getProperty(kAppleClamshellCausesSleepKey) == kOSBooleanTrue;
}
void net_trajano_driver_InsomniaT::enableSleep() {
    if (isMultipleDisplays()) {
		if (isLoggingEnabled()) {
			IOLog("InsomniaT: multiple displays detected doing nothing.\n");
		}
        return;
    }
	IOPMrootDomain *root = getPMRootDomain();
	root->setProperty(kAppleClamshellCausesSleepKey,fAppleClamshellCausesSleep);
    // Calling this method will set the ignoringClamShell to false for the PM root domain.
	root->receivePowerNotification(kIOPMEnableClamshell);
	if (isLoggingEnabled()) {
		IOLog("InsomniaT: enabling sleep complete\n");
	}
}

IOReturn net_trajano_driver_InsomniaT::setSleepEnabled(bool sleepEnabled) {
	setProperty(gKeySleepEnabled, sleepEnabled);
	if (sleepEnabled) {
		if (isLoggingEnabled()) {
			IOLog("InsomniaT: sleep enabled requested, enabling sleep.\n");
		}
		enableSleep();
	} else {
		if (isLoggingEnabled()) {
			IOLog("InsomniaT: sleep disabled requested, disabling sleep.\n");
		}
		disableSleep();
	}
	return true;
}

IOReturn net_trajano_driver_InsomniaT::setLoggingEnabled(bool loggingEnabled) {
	setProperty(gKeyLoggingEnabled, loggingEnabled);
	if (isLoggingEnabled()) {
		IOLog("InsomniaT: logging is enabled\n");
	} else {
		IOLog("InsomniaT: logging is disabled\n");
	}
	return true;
}

/**
 * This is called when the kext is being unloaded.  It will remove the notifier handler
 * and enable sleep.
 */
void net_trajano_driver_InsomniaT::stop(IOService *provider)
{
	if (isLoggingEnabled()) {
		IOLog("InsomniaT: service is stopping.\n");
	}
	fNotifier->remove();
	enableSleep();
	super::stop(provider);
}
<commit_msg>added NULL check to prevent crash on boot<commit_after>#include <IOKit/IOLib.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/pwr_mgt/IOPM.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include "InsomniaT.h"

#define super IOService

OSDefineMetaClassAndStructors(net_trajano_driver_InsomniaT, IOService)

IOReturn handleSleepWakeInterest( void * target, void * refCon,
								 UInt32 messageType, IOService * provider,
								 void * messageArgument, vm_size_t argSize )
{
	net_trajano_driver_InsomniaT *obj = (net_trajano_driver_InsomniaT*)target;
	if (obj->isLoggingEnabled()) {
		IOLog("InsomniaT: handleSleepWakeInterest invoked with message type %x.\n", (unsigned int)messageType);
	}
	if (messageType == kIOPMMessageClamshellStateChange) {
		if (obj->isLoggingEnabled()) {
			IOLog("InsomniaT: message type is kIOPMMessageClamshellStateChange.\n");
		}
		obj->updateSystemSleep();
	}
	return 0;
}

void net_trajano_driver_InsomniaT::updateSystemSleep() {
	if (isLoggingEnabled()) {
		IOLog("InsomniaT: sleep status is being updated.\n");
	}
	if (isLoggingEnabled() && isSleepEnabled()) {
		IOLog("InsomniaT: sleep is enabled\n");
	}
	if (isLoggingEnabled() && !isSleepEnabled()) {
		IOLog("InsomniaT: sleep is disabled\n");
	}
	if (isLoggingEnabled() && isSleepEnabledBySystem()) {
		IOLog("InsomniaT: sleep is enabled by system\n");
	}
	if (isLoggingEnabled() && !isSleepEnabledBySystem()) {
		IOLog("InsomniaT: sleep is disabled by system\n");
	}

    if (isSleepEnabled() && !isSleepEnabledBySystem()) {
		if (isLoggingEnabled()) {
			IOLog("InsomniaT: enabling sleep.\n");
		}
		enableSleep();
	} else if (!isSleepEnabled() && isSleepEnabledBySystem()) {
		if (isLoggingEnabled()) {
			IOLog("InsomniaT: disabling sleep.\n");
		}
		disableSleep();
	}
}
bool net_trajano_driver_InsomniaT::isMultipleDisplays() {
    OSDictionary* dict = OSDictionary::withCapacity(1);
    dict->setObject(kIOProviderClassKey, OSString::withCStringNoCopy("IODisplayConnect"));
    OSIterator* ioDisplayConnectIterator = getMatchingServices(dict);
    if (ioDisplayConnectIterator == NULL) {
        return false;
    }
    unsigned int displayCount = 0;
    OSObject* obj;
    while ((obj = ioDisplayConnectIterator->getNextObject()) != NULL && displayCount < 2) {
        ++displayCount;
    }
    ioDisplayConnectIterator->release();
    dict->release();
    return displayCount > 1;
}
bool net_trajano_driver_InsomniaT::start(IOService *provider)
{
	IOPMrootDomain *root = getPMRootDomain();

	IOWorkLoop *workloop = getWorkLoop();
	if (!workloop) {
		return false;
	}

	fAppleClamshellCausesSleep = root->getProperty(kAppleClamshellCausesSleepKey);
    fNotifier = registerSleepWakeInterest(handleSleepWakeInterest, this);
	disableSleep();

    bool res = super::start(provider);
	if (res) {
		registerService();
	}
	return res;
}

void net_trajano_driver_InsomniaT::disableSleep() {
    if (isMultipleDisplays()) {
		if (isLoggingEnabled()) {
			IOLog("InsomniaT: multiple displays detected doing nothing.\n");
		}
        return;
    }
	IOPMrootDomain *root = getPMRootDomain();
	root->setProperty(kAppleClamshellCausesSleepKey,kOSBooleanFalse);
    // Calling this method will set the ignoringClamShell to true for the PM root domain.
	root->receivePowerNotification(kIOPMDisableClamshell);
	if (isLoggingEnabled()) {
		IOLog("InsomniaT: disabling sleep complete\n");
	}
}

/**
 * SleepEnabled key.
 */
const char* net_trajano_driver_InsomniaT::gKeySleepEnabled = "SleepEnabled";

/**
 * LoggingEnabled key.
 */
const char* net_trajano_driver_InsomniaT::gKeyLoggingEnabled = "LoggingEnabled";

bool net_trajano_driver_InsomniaT::isSleepEnabled() {
	return ((OSBoolean*)getProperty(gKeySleepEnabled))->getValue();
}

bool net_trajano_driver_InsomniaT::isLoggingEnabled() {
	return ((OSBoolean*)getProperty(gKeyLoggingEnabled))->getValue();
}

bool net_trajano_driver_InsomniaT::isSleepEnabledBySystem() {
	IOPMrootDomain *root = getPMRootDomain();
	return root->getProperty(kAppleClamshellCausesSleepKey) == kOSBooleanTrue;
}
void net_trajano_driver_InsomniaT::enableSleep() {
    if (isMultipleDisplays()) {
		if (isLoggingEnabled()) {
			IOLog("InsomniaT: multiple displays detected doing nothing.\n");
		}
        return;
    }
	IOPMrootDomain *root = getPMRootDomain();
	root->setProperty(kAppleClamshellCausesSleepKey,fAppleClamshellCausesSleep);
    // Calling this method will set the ignoringClamShell to false for the PM root domain.
	root->receivePowerNotification(kIOPMEnableClamshell);
	if (isLoggingEnabled()) {
		IOLog("InsomniaT: enabling sleep complete\n");
	}
}

IOReturn net_trajano_driver_InsomniaT::setSleepEnabled(bool sleepEnabled) {
	setProperty(gKeySleepEnabled, sleepEnabled);
	if (sleepEnabled) {
		if (isLoggingEnabled()) {
			IOLog("InsomniaT: sleep enabled requested, enabling sleep.\n");
		}
		enableSleep();
	} else {
		if (isLoggingEnabled()) {
			IOLog("InsomniaT: sleep disabled requested, disabling sleep.\n");
		}
		disableSleep();
	}
	return true;
}

IOReturn net_trajano_driver_InsomniaT::setLoggingEnabled(bool loggingEnabled) {
	setProperty(gKeyLoggingEnabled, loggingEnabled);
	if (isLoggingEnabled()) {
		IOLog("InsomniaT: logging is enabled\n");
	} else {
		IOLog("InsomniaT: logging is disabled\n");
	}
	return true;
}

/**
 * This is called when the kext is being unloaded.  It will remove the notifier handler
 * and enable sleep.
 */
void net_trajano_driver_InsomniaT::stop(IOService *provider)
{
	if (isLoggingEnabled()) {
		IOLog("InsomniaT: service is stopping.\n");
	}
	fNotifier->remove();
	enableSleep();
	super::stop(provider);
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
 * This file is part of the libetonyek project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "IWORKTable.h"

#include <boost/numeric/conversion/cast.hpp>

#include <glm/glm.hpp>

#include "libetonyek_xml.h"
#include "libetonyek_utils.h"
#include "IWORKDocumentInterface.h"
#include "IWORKProperties.h"
#include "IWORKStyle.h"
#include "IWORKTypes.h"

using boost::numeric_cast;

namespace libetonyek
{

namespace
{

void writeBorder(librevenge::RVNGPropertyList &props, const char *name, IWORKGridLine_t &line, std::size_t index)
{
  if (!line.is_tree_valid())
    line.build_tree();

  IWORKStylePtr_t style;
  line.search_tree(index, style);
  if (style && style->has<property::SFTStrokeProperty>())
  {
    const IWORKStroke &stroke = style->get<property::SFTStrokeProperty>();
    props.insert(name, makeBorder(stroke));
  }
}

void writeCellFormat(librevenge::RVNGPropertyList &props, const IWORKStylePtr_t &style, const IWORKCellType type, const boost::optional<std::string> &value)
{
  using namespace property;

  switch (type)
  {
  case IWORK_CELL_TYPE_NUMBER :
    if (style->has<SFTCellStylePropertyNumberFormat>() && value)
    {
      const IWORKNumberFormat &format = style->get<SFTCellStylePropertyNumberFormat>();

      if (style->getIdent())
        props.insert("librevenge:name", style->getIdent());

      props.insert("librevenge:value", get(value).c_str());

      switch (format.m_type)
      {
      case IWORK_CELL_NUMBER_TYPE_CURRENCY :
        props.insert("librevenge:value-type", "currency");
        props.insert("number:currency-style", format.m_currencyCode.c_str());
        break;
      case IWORK_CELL_NUMBER_TYPE_PERCENTAGE :
        props.insert("librevenge:value-type", "percentage");
        props.insert("number:decimal-places", format.m_decimalPlaces);
        break;
      case IWORK_CELL_NUMBER_TYPE_SCIENTIFIC :
        props.insert("librevenge:value-type", "scientific");
        props.insert("number:decimal-places", format.m_decimalPlaces);
        break;
      case IWORK_CELL_NUMBER_TYPE_DOUBLE :
        props.insert("librevenge:value-type", "double");
        props.insert("number:decimal-places", format.m_decimalPlaces);
        break;
      }
    }
    break;
  case IWORK_CELL_TYPE_DATE_TIME :
    if (style->has<SFTCellStylePropertyDateTimeFormat>() && value)
    {
      if (style->getIdent())
        props.insert("librevenge:name", style->getIdent());
      props.insert("librevenge:value-type", "date");
    }
    break;
  case IWORK_CELL_TYPE_DURATION :
    if (style->has<SFTCellStylePropertyDurationFormat>() && value)
    {
      // TODO: How to insert format and convert?
      // const IWORKDurationFormat &format = style->get<SFTCellStylePropertyDurationFormat>();
      // props.insert("librevenge:format",format.m_format.c_str());

      const int seconds = int_cast(get(value).c_str());
      props.insert("librevenge:value-type", "time");
      props.insert("librevenge:hours", seconds / 3600);
      props.insert("librevenge:minutes", (seconds % 3600) / 60);
      props.insert("librevenge:seconds", (seconds % 3600) % 60);

      if (style->getIdent())
        props.insert("librevenge:name", style->getIdent());
    }
    break;
  case IWORK_CELL_TYPE_BOOL:
    if (value)
    {
      props.insert("librevenge:value", get(value).c_str());
      props.insert("librevenge:value-type", "bool");
    }
    break;
  case IWORK_CELL_TYPE_TEXT :
  default:
    //TODO: librevenge:name ?
    if (value)
      props.insert("librevenge:value-type", "string");
    break;
  }
}

}

IWORKTable::Cell::Cell()
  : m_content()
  , m_columnSpan(1)
  , m_rowSpan(1)
  , m_covered(false)
  , m_formula()
  , m_style()
  , m_type(IWORK_CELL_TYPE_TEXT)
  , m_value()
{
}

IWORKTable::IWORKTable()
  : m_table()
  , m_columnSizes()
  , m_rowSizes()
  , m_verticalLines()
  , m_horizontalLines()
  , m_tableNameMap()
{
}

void IWORKTable::setSizes(const IWORKColumnSizes_t &columnSizes, const IWORKRowSizes_t &rowSizes)
{
  m_columnSizes = columnSizes;
  m_rowSizes = rowSizes;

  // init. content table of appropriate dimensions
  m_table = Table_t(m_rowSizes.size(), Row_t(m_columnSizes.size()));
}

void IWORKTable::setBorders(const IWORKGridLineList_t &verticalLines, const IWORKGridLineList_t &horizontalLines)
{
  m_verticalLines = verticalLines;
  m_horizontalLines = horizontalLines;
}

void IWORKTable::setTableNameMap(const IWORKTableNameMapPtr_t &tableNameMap)
{
  m_tableNameMap = tableNameMap;
}

void IWORKTable::insertCell(const unsigned column, const unsigned row, const boost::optional<std::string> &value, const IWORKOutputElements &content, const unsigned columnSpan, const unsigned rowSpan, const boost::optional<IWORKFormula> &formula, const IWORKStylePtr_t &style, const IWORKCellType type)
{
  if ((m_rowSizes.size() <= row) || (m_columnSizes.size() <= column))
    return;

  Cell cell;
  cell.m_content = content;
  cell.m_columnSpan = columnSpan;
  cell.m_rowSpan = rowSpan;
  cell.m_formula = formula;
  cell.m_style = style;
  cell.m_type = type;
  cell.m_value = value;
  m_table[row][column] = cell;
}

void IWORKTable::insertCoveredCell(const unsigned column, const unsigned row)
{
  if ((m_rowSizes.size() <= row) || (m_columnSizes.size() <= column))
    return;

  Cell cell;
  cell.m_covered = true;
  m_table[row][column] = cell;
}

void IWORKTable::draw(const librevenge::RVNGPropertyList &tableProps, IWORKOutputElements &elements)
{
  librevenge::RVNGPropertyListVector columnSizes;

  for (IWORKColumnSizes_t::const_iterator it = m_columnSizes.begin(); m_columnSizes.end() != it; ++it)
  {
    librevenge::RVNGPropertyList column;
    column.insert("style:column-width", pt2in(*it));
    columnSizes.append(column);
  }

  librevenge::RVNGPropertyList allTableProps(tableProps);
  allTableProps.insert("librevenge:table-columns", columnSizes);

  elements.addOpenTable(allTableProps);
  for (std::size_t r = 0; m_table.size() != r; ++r)
  {
    const Row_t &row = m_table[r];

    librevenge::RVNGPropertyList rowProps;
    rowProps.insert("style:row-height", pt2in(m_rowSizes[r]));

    elements.addOpenTableRow(rowProps);
    for (std::size_t c = 0; row.size() != c; ++c)
    {
      const Cell &cell = row[c];

      librevenge::RVNGPropertyList cellProps;
      cellProps.insert("librevenge:column", numeric_cast<int>(c));
      cellProps.insert("librevenge:row", numeric_cast<int>(r));
      cellProps.insert("fo:vertical-align", "middle");

      if (r < m_horizontalLines.size())
        writeBorder(cellProps, "fo:border-top", m_horizontalLines[r], c);
      if (r+1 < m_horizontalLines.size())
        writeBorder(cellProps, "fo:border-bottom", m_horizontalLines[r+1], c);
      if (c < m_verticalLines.size())
        writeBorder(cellProps, "fo:border-left", m_verticalLines[c], r);
      if (c+1 < m_verticalLines.size())
        writeBorder(cellProps, "fo:border-right", m_verticalLines[c+1], r);

      if (cell.m_covered)
      {
        elements.addInsertCoveredTableCell(cellProps);
      }
      else
      {
        if (1 < cell.m_columnSpan)
          cellProps.insert("table:number-columns-spanned", numeric_cast<int>(cell.m_columnSpan));
        if (1 < cell.m_rowSpan)
          cellProps.insert("table:number-rows-spanned", numeric_cast<int>(cell.m_rowSpan));

        if (cell.m_style)
          writeCellFormat(cellProps, cell.m_style, cell.m_type, cell.m_value);

        if (cell.m_formula)
          elements.addOpenFormulaCell(cellProps, cell.m_formula, m_tableNameMap);
        else
          elements.addOpenTableCell(cellProps);

        if (!cell.m_content.empty())
          elements.append(cell.m_content);

        elements.addCloseTableCell();
      }
    }
    elements.addCloseTableRow();
  }
  elements.addCloseTable();
}

}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
<commit_msg>output date as standard dd/mm/yyyy format<commit_after>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
 * This file is part of the libetonyek project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "IWORKTable.h"

#include <ctime>

#include <boost/numeric/conversion/cast.hpp>

#include <glm/glm.hpp>

#include "libetonyek_xml.h"
#include "libetonyek_utils.h"
#include "IWORKDocumentInterface.h"
#include "IWORKProperties.h"
#include "IWORKStyle.h"
#include "IWORKTypes.h"

using boost::numeric_cast;

namespace libetonyek
{

namespace
{

void writeBorder(librevenge::RVNGPropertyList &props, const char *name, IWORKGridLine_t &line, std::size_t index)
{
  if (!line.is_tree_valid())
    line.build_tree();

  IWORKStylePtr_t style;
  line.search_tree(index, style);
  if (style && style->has<property::SFTStrokeProperty>())
  {
    const IWORKStroke &stroke = style->get<property::SFTStrokeProperty>();
    props.insert(name, makeBorder(stroke));
  }
}

void writeCellFormat(librevenge::RVNGPropertyList &props, const IWORKStylePtr_t &style, const IWORKCellType type, const boost::optional<std::string> &value)
{
  using namespace property;

  switch (type)
  {
  case IWORK_CELL_TYPE_NUMBER :
    if (style->has<SFTCellStylePropertyNumberFormat>() && value)
    {
      const IWORKNumberFormat &format = style->get<SFTCellStylePropertyNumberFormat>();

      if (style->getIdent())
        props.insert("librevenge:name", style->getIdent());

      props.insert("librevenge:value", get(value).c_str());

      switch (format.m_type)
      {
      case IWORK_CELL_NUMBER_TYPE_CURRENCY :
        props.insert("librevenge:value-type", "currency");
        props.insert("number:currency-style", format.m_currencyCode.c_str());
        break;
      case IWORK_CELL_NUMBER_TYPE_PERCENTAGE :
        props.insert("librevenge:value-type", "percentage");
        props.insert("number:decimal-places", format.m_decimalPlaces);
        break;
      case IWORK_CELL_NUMBER_TYPE_SCIENTIFIC :
        props.insert("librevenge:value-type", "scientific");
        props.insert("number:decimal-places", format.m_decimalPlaces);
        break;
      case IWORK_CELL_NUMBER_TYPE_DOUBLE :
        props.insert("librevenge:value-type", "double");
        props.insert("number:decimal-places", format.m_decimalPlaces);
        break;
      }
    }
    break;
  case IWORK_CELL_TYPE_DATE_TIME :
    if (style->has<SFTCellStylePropertyDateTimeFormat>() && value)
    {
      if (style->getIdent())
        props.insert("librevenge:name", style->getIdent());
      props.insert("librevenge:value-type", "date");

      const double seconds = double_cast(get(value).c_str());
      const std::time_t t = ETONYEK_EPOCH_BEGIN + seconds;
      struct tm *const time = gmtime(&t);

      props.insert("librevenge:day", time->tm_mday);
      props.insert("librevenge:month", time->tm_mon + 1);
      props.insert("librevenge:year", time->tm_year + 1900);
      props.insert("librevenge:hours", time->tm_hour);
      props.insert("librevenge:minutes", time->tm_min);
      props.insert("librevenge:seconds", time->tm_sec);

    }
    break;
  case IWORK_CELL_TYPE_DURATION :
    if (style->has<SFTCellStylePropertyDurationFormat>() && value)
    {
      // TODO: How to insert format and convert?
      // const IWORKDurationFormat &format = style->get<SFTCellStylePropertyDurationFormat>();
      // props.insert("librevenge:format",format.m_format.c_str());

      const int seconds = int_cast(get(value).c_str());
      props.insert("librevenge:value-type", "time");
      props.insert("librevenge:hours", seconds / 3600);
      props.insert("librevenge:minutes", (seconds % 3600) / 60);
      props.insert("librevenge:seconds", (seconds % 3600) % 60);

      if (style->getIdent())
        props.insert("librevenge:name", style->getIdent());
    }
    break;
  case IWORK_CELL_TYPE_BOOL:
    if (value)
    {
      props.insert("librevenge:value", get(value).c_str());
      props.insert("librevenge:value-type", "bool");
    }
    break;
  case IWORK_CELL_TYPE_TEXT :
  default:
    //TODO: librevenge:name ?
    if (value)
      props.insert("librevenge:value-type", "string");
    break;
  }
}

}

IWORKTable::Cell::Cell()
  : m_content()
  , m_columnSpan(1)
  , m_rowSpan(1)
  , m_covered(false)
  , m_formula()
  , m_style()
  , m_type(IWORK_CELL_TYPE_TEXT)
  , m_value()
{
}

IWORKTable::IWORKTable()
  : m_table()
  , m_columnSizes()
  , m_rowSizes()
  , m_verticalLines()
  , m_horizontalLines()
  , m_tableNameMap()
{
}

void IWORKTable::setSizes(const IWORKColumnSizes_t &columnSizes, const IWORKRowSizes_t &rowSizes)
{
  m_columnSizes = columnSizes;
  m_rowSizes = rowSizes;

  // init. content table of appropriate dimensions
  m_table = Table_t(m_rowSizes.size(), Row_t(m_columnSizes.size()));
}

void IWORKTable::setBorders(const IWORKGridLineList_t &verticalLines, const IWORKGridLineList_t &horizontalLines)
{
  m_verticalLines = verticalLines;
  m_horizontalLines = horizontalLines;
}

void IWORKTable::setTableNameMap(const IWORKTableNameMapPtr_t &tableNameMap)
{
  m_tableNameMap = tableNameMap;
}

void IWORKTable::insertCell(const unsigned column, const unsigned row, const boost::optional<std::string> &value, const IWORKOutputElements &content, const unsigned columnSpan, const unsigned rowSpan, const boost::optional<IWORKFormula> &formula, const IWORKStylePtr_t &style, const IWORKCellType type)
{
  if ((m_rowSizes.size() <= row) || (m_columnSizes.size() <= column))
    return;

  Cell cell;
  cell.m_content = content;
  cell.m_columnSpan = columnSpan;
  cell.m_rowSpan = rowSpan;
  cell.m_formula = formula;
  cell.m_style = style;
  cell.m_type = type;
  cell.m_value = value;
  m_table[row][column] = cell;
}

void IWORKTable::insertCoveredCell(const unsigned column, const unsigned row)
{
  if ((m_rowSizes.size() <= row) || (m_columnSizes.size() <= column))
    return;

  Cell cell;
  cell.m_covered = true;
  m_table[row][column] = cell;
}

void IWORKTable::draw(const librevenge::RVNGPropertyList &tableProps, IWORKOutputElements &elements)
{
  librevenge::RVNGPropertyListVector columnSizes;

  for (IWORKColumnSizes_t::const_iterator it = m_columnSizes.begin(); m_columnSizes.end() != it; ++it)
  {
    librevenge::RVNGPropertyList column;
    column.insert("style:column-width", pt2in(*it));
    columnSizes.append(column);
  }

  librevenge::RVNGPropertyList allTableProps(tableProps);
  allTableProps.insert("librevenge:table-columns", columnSizes);

  elements.addOpenTable(allTableProps);
  for (std::size_t r = 0; m_table.size() != r; ++r)
  {
    const Row_t &row = m_table[r];

    librevenge::RVNGPropertyList rowProps;
    rowProps.insert("style:row-height", pt2in(m_rowSizes[r]));

    elements.addOpenTableRow(rowProps);
    for (std::size_t c = 0; row.size() != c; ++c)
    {
      const Cell &cell = row[c];

      librevenge::RVNGPropertyList cellProps;
      cellProps.insert("librevenge:column", numeric_cast<int>(c));
      cellProps.insert("librevenge:row", numeric_cast<int>(r));
      cellProps.insert("fo:vertical-align", "middle");

      if (r < m_horizontalLines.size())
        writeBorder(cellProps, "fo:border-top", m_horizontalLines[r], c);
      if (r+1 < m_horizontalLines.size())
        writeBorder(cellProps, "fo:border-bottom", m_horizontalLines[r+1], c);
      if (c < m_verticalLines.size())
        writeBorder(cellProps, "fo:border-left", m_verticalLines[c], r);
      if (c+1 < m_verticalLines.size())
        writeBorder(cellProps, "fo:border-right", m_verticalLines[c+1], r);

      if (cell.m_covered)
      {
        elements.addInsertCoveredTableCell(cellProps);
      }
      else
      {
        if (1 < cell.m_columnSpan)
          cellProps.insert("table:number-columns-spanned", numeric_cast<int>(cell.m_columnSpan));
        if (1 < cell.m_rowSpan)
          cellProps.insert("table:number-rows-spanned", numeric_cast<int>(cell.m_rowSpan));

        if (cell.m_style)
          writeCellFormat(cellProps, cell.m_style, cell.m_type, cell.m_value);

        if (cell.m_formula)
          elements.addOpenFormulaCell(cellProps, cell.m_formula, m_tableNameMap);
        else
          elements.addOpenTableCell(cellProps);

        if (!cell.m_content.empty())
          elements.append(cell.m_content);

        elements.addCloseTableCell();
      }
    }
    elements.addCloseTableRow();
  }
  elements.addCloseTable();
}

}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
<|endoftext|>


<commit_before>#pragma once
#ifndef ALGORITHM_HPP
# define ALGORUTHM_HPP

#include <type_traits>

#include <utility>

namespace detail
{

template <bool B>
using bool_ = ::std::integral_constant<bool, B>;

template <class A, class ...B>
struct all_of : bool_<A{} && all_of<B...>{}> { };

template <class A>
struct all_of<A> : bool_<A::value> { };

}

template <typename T, typename ...A>
inline constexpr typename ::std::enable_if<!bool(sizeof...(A)), T>::type
max(T const a, T const b, A const ...args)
{
  return a > b ? a : b;
}

template <typename T, typename ...A>
inline constexpr typename ::std::enable_if<bool(sizeof...(A)) &&
  ::detail::all_of<::std::is_same<A, T>...>{}, T>::type
max(T const a, T const b, A const ...args)
{
  return a > b ? max(a, args...) : min(b, args...);
}

template <typename T, typename ...A>
inline constexpr typename ::std::enable_if<!bool(sizeof...(A)), T>::type
min(T const a, T const b, A const ...args)
{
  return a < b ? a : b;
}

template <typename T, typename ...A>
inline constexpr typename ::std::enable_if<bool(sizeof...(A)) &&
  ::detail::all_of<::std::is_same<A, T>...>{}, T>::type
min(T const a, T const b, A const ...args)
{
  return a < b ? min(a, args...) : min(b, args...);
}

template <typename T, typename ...A>
inline constexpr typename ::std::enable_if<bool(sizeof...(A)) &&
  ::detail::all_of<::std::is_same<A, T>...>{},
  ::std::pair<T, T> >::type
minmax(T const a, T const b, A const ...args)
{
  return ::std::pair<T, T>(
    a < b ? min(a, args...) : min(b, args...),
    a > b ? max(a, args...) : max(b, args...));
}

#endif // ALGORITHM_HPP
<commit_msg>strips<commit_after>#pragma once
#ifndef ALGORITHM_HPP
# define ALGORUTHM_HPP

#include <type_traits>

#include <utility>

namespace detail
{

template <bool B>
using bool_ = ::std::integral_constant<bool, B>;

template <class A, class ...B>
struct all_of : bool_<A::value && all_of<B...>::value> { };

template <class A>
struct all_of<A> : bool_<A::value> { };

}

template <typename T>
inline constexpr T max(T const a, T const b)
{
  return a > b ? a : b;
}

template <typename T, typename ...A>
inline constexpr typename ::std::enable_if<bool(sizeof...(A)) &&
  ::detail::all_of<::std::is_same<
    typename ::std::decay<A>::type, typename ::std::decay<T>::type>...>{},
  T>::type
max(T const a, T const b, A const ...args)
{
  return a > b ? max(a, args...) : min(b, args...);
}

template <typename T>
inline constexpr T min(T const a, T const b)
{
  return a < b ? a : b;
}

template <typename T, typename ...A>
inline constexpr typename ::std::enable_if<bool(sizeof...(A)) &&
  ::detail::all_of<::std::is_same<
    typename ::std::decay<A>::type, typename ::std::decay<T>::type>...>{},
  T>::type
min(T const a, T const b, A const ...args)
{
  return a < b ? min(a, args...) : min(b, args...);
}

template <typename T>
inline constexpr ::std::pair<T, T> minmax(T const a, T const b)
{
  return a < b ? ::std::pair<T, T>(a, b) : ::std::pair<T, T>(b, a);
}

template <typename T, typename ...A>
inline constexpr typename ::std::enable_if<bool(sizeof...(A)) &&
  ::detail::all_of<::std::is_same<
    typename ::std::decay<A>::type, typename ::std::decay<T>::type>...>{},
  ::std::pair<T, T> >::type
minmax(T const a, T const b, A const ...args)
{
  return ::std::pair<T, T>(
    a < b ? min(a, args...) : min(b, args...),
    a > b ? max(a, args...) : max(b, args...));
}

#endif // ALGORITHM_HPP
<|endoftext|>


<commit_before>#pragma once

#include "lrate.hpp"
#include "stoch_loop.hpp"
#include "math/momentum.hpp"

namespace nano
{
        ///
        /// \brief stochastic gradient (descent) with momentum
        ///
        template
        <
                typename tproblem               ///< optimization problem
        >
        struct stoch_sgm_t
        {
                using param_t = stoch_params_t<tproblem>;
                using tstate = typename param_t::tstate;
                using tscalar = typename param_t::tscalar;
                using tvector = typename param_t::tvector;

                ///
                /// \brief minimize starting from the initial guess x0
                ///
                tstate operator()(const param_t& param, const tproblem& problem, const tvector& x0) const
                {
                        const auto op = [&] (const auto... params)
                        {
                                return this->operator()(param.tunable(), problem, x0, params...);
                        };

                        const auto config = nano::tune(op, make_alpha0s(), make_decays(), make_momenta());
                        return operator()(param, problem, x0, config.param0(), config.param1(), config.param2());
                }

                ///
                /// \brief minimize starting from the initial guess x0
                ///
                tstate operator()(const param_t& param, const tproblem& problem, const tvector& x0,
                        const tscalar alpha0, const tscalar decay, const tscalar momentum) const
                {
                        assert(problem.size() == x0.size());

                        // learning rate schedule
                        lrate_t<tscalar> lrate(alpha0, decay);

                        // first-order momentum of the gradient
                        momentum_vector_t<tvector> gavg(momentum, x0.size());

                        const auto op_iter = [&] (tstate& cstate, const std::size_t iter)
                        {
                                // learning rate
                                const tscalar alpha = lrate.get(iter);

                                // descent direction
                                gavg.update(cstate.g.array());
                                cstate.d = -gavg.value();

                                // update solution
                                cstate.update(problem, alpha);
                        };

                        // OK, assembly the optimizer
                        return  stoch_loop(problem, param, tstate(problem, x0), op_iter,
                                {{"alpha0", alpha0}, {"decay", decay}, {"momentum", momentum}});
                }
        };
}

<commit_msg>fix SGM (average parameter updates instead of gradients)<commit_after>#pragma once

#include "lrate.hpp"
#include "stoch_loop.hpp"
#include "math/momentum.hpp"

namespace nano
{
        ///
        /// \brief stochastic gradient (descent) with momentum
        ///
        template
        <
                typename tproblem               ///< optimization problem
        >
        struct stoch_sgm_t
        {
                using param_t = stoch_params_t<tproblem>;
                using tstate = typename param_t::tstate;
                using tscalar = typename param_t::tscalar;
                using tvector = typename param_t::tvector;

                ///
                /// \brief minimize starting from the initial guess x0
                ///
                tstate operator()(const param_t& param, const tproblem& problem, const tvector& x0) const
                {
                        const auto op = [&] (const auto... params)
                        {
                                return this->operator()(param.tunable(), problem, x0, params...);
                        };

                        const auto config = nano::tune(op, make_alpha0s(), make_decays(), make_momenta());
                        return operator()(param, problem, x0, config.param0(), config.param1(), config.param2());
                }

                ///
                /// \brief minimize starting from the initial guess x0
                ///
                tstate operator()(const param_t& param, const tproblem& problem, const tvector& x0,
                        const tscalar alpha0, const tscalar decay, const tscalar momentum) const
                {
                        assert(problem.size() == x0.size());

                        // learning rate schedule
                        lrate_t<tscalar> lrate(alpha0, decay);

                        // first-order momentum of the update
                        momentum_vector_t<tvector> davg(momentum, x0.size());

                        const auto op_iter = [&] (tstate& cstate, const std::size_t iter)
                        {
                                // learning rate
                                const tscalar alpha = lrate.get(iter);

                                // descent direction
                                davg.update(-alpha * cstate.g);
                                cstate.d = davg.value();

                                // update solution
                                cstate.update(problem, 1);
                        };

                        // OK, assembly the optimizer
                        return  stoch_loop(problem, param, tstate(problem, x0), op_iter,
                                {{"alpha0", alpha0}, {"decay", decay}, {"momentum", momentum}});
                }
        };
}

<|endoftext|>


<commit_before>#ifndef _PNMC_MC_POST_HH_
#define _PNMC_MC_POST_HH_

#include <functional> // hash
#include <iosfwd>

#include "sdd/values/flat_set.hh"
#include "sdd/values_manager.hh"

namespace pnmc { namespace mc { namespace classic {

/*------------------------------------------------------------------------------------------------*/

struct post
{
  const unsigned int valuation;

  post(unsigned int);

  sdd::values::flat_set<unsigned int>
  operator()(const sdd::values::flat_set<unsigned int>&)
  const;

  /// @brief Post is a selector.
  ///
  /// It's not quite true, but as post doesn't modify the partition, we can use a square union
  /// rather than a full union.
  bool
  selector()
  const noexcept
  {
    return true;
  }

};

/// @brief Equality of two post.
bool
operator==(const post&, const post&)
noexcept;

/// @brief Textual output of a post.
std::ostream&
operator<<(std::ostream&, const post&);

/*------------------------------------------------------------------------------------------------*/

}}} // namespace pnmc::mc::classic

namespace std
{

/*------------------------------------------------------------------------------------------------*/

template <>
struct hash<pnmc::mc::classic::post>
{
  std::size_t operator()(const pnmc::mc::classic::post&) const noexcept;
};

/*------------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _PNMC_MC_POST_HH_
<commit_msg>Post is a shifter, not a selector.<commit_after>#ifndef _PNMC_MC_POST_HH_
#define _PNMC_MC_POST_HH_

#include <functional> // hash
#include <iosfwd>

#include "sdd/values/flat_set.hh"
#include "sdd/values_manager.hh"

namespace pnmc { namespace mc { namespace classic {

/*------------------------------------------------------------------------------------------------*/

struct post
{
  const unsigned int valuation;

  post(unsigned int);

  sdd::values::flat_set<unsigned int>
  operator()(const sdd::values::flat_set<unsigned int>&)
  const;

//  bool
//  shifter()
//  const noexcept
//  {
//    return true;
//  }

};

/// @brief Equality of two post.
bool
operator==(const post&, const post&)
noexcept;

/// @brief Textual output of a post.
std::ostream&
operator<<(std::ostream&, const post&);

/*------------------------------------------------------------------------------------------------*/

}}} // namespace pnmc::mc::classic

namespace std
{

/*------------------------------------------------------------------------------------------------*/

template <>
struct hash<pnmc::mc::classic::post>
{
  std::size_t operator()(const pnmc::mc::classic::post&) const noexcept;
};

/*------------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _PNMC_MC_POST_HH_
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Andreas Hansson
 */

#include "mem/addr_mapper.hh"

AddrMapper::AddrMapper(const AddrMapperParams* p)
    : MemObject(p),
      masterPort(name() + "-master", *this),
      slavePort(name() + "-slave", *this)
{
}

void
AddrMapper::init()
{
    if (!slavePort.isConnected() || !masterPort.isConnected())
        fatal("Address mapper is not connected on both sides.\n");

    if ((slavePort.peerBlockSize() != masterPort.peerBlockSize()) &&
        slavePort.peerBlockSize() && masterPort.peerBlockSize())
        fatal("Slave port size %d, master port size %d \n "
              "don't have the same block size... Not supported.\n",
              slavePort.peerBlockSize(), masterPort.peerBlockSize());
}

BaseMasterPort&
AddrMapper::getMasterPort(const std::string& if_name, PortID idx)
{
    if (if_name == "master") {
        return masterPort;
    } else {
        return MemObject::getMasterPort(if_name, idx);
    }
}

BaseSlavePort&
AddrMapper::getSlavePort(const std::string& if_name, PortID idx)
{
    if (if_name == "slave") {
        return slavePort;
    } else {
        return MemObject::getSlavePort(if_name, idx);
    }
}

void
AddrMapper::recvFunctional(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    masterPort.sendFunctional(pkt);
    pkt->setAddr(orig_addr);
}

void
AddrMapper::recvFunctionalSnoop(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    slavePort.sendFunctionalSnoop(pkt);
    pkt->setAddr(orig_addr);
}

Tick
AddrMapper::recvAtomic(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    Tick ret_tick =  masterPort.sendAtomic(pkt);
    pkt->setAddr(orig_addr);
    return ret_tick;
}

Tick
AddrMapper::recvAtomicSnoop(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    Tick ret_tick = slavePort.sendAtomicSnoop(pkt);
    pkt->setAddr(orig_addr);
    return ret_tick;
}

bool
AddrMapper::recvTimingReq(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    bool needsResponse = pkt->needsResponse();
    bool memInhibitAsserted = pkt->memInhibitAsserted();
    Packet::SenderState* senderState = pkt->senderState;

    if (needsResponse && !memInhibitAsserted) {
        pkt->senderState = new AddrMapperSenderState(senderState, orig_addr);
    }

    pkt->setAddr(remapAddr(orig_addr));

    // Attempt to send the packet (always succeeds for inhibited
    // packets)
    bool successful = masterPort.sendTimingReq(pkt);

    // If not successful, restore the sender state
    if (!successful && needsResponse) {
        delete pkt->senderState;
        pkt->senderState = senderState;
    }

    return successful;
}

bool
AddrMapper::recvTimingResp(PacketPtr pkt)
{
    AddrMapperSenderState* receivedState =
        dynamic_cast<AddrMapperSenderState*>(pkt->senderState);

    // Restore initial sender state
    if (receivedState == NULL)
        panic("AddrMapper %s got a response without sender state\n",
              name());

    Addr remapped_addr = pkt->getAddr();

    // Restore the state and address
    pkt->senderState = receivedState->origSenderState;
    pkt->setAddr(receivedState->origAddr);

    // Attempt to send the packet
    bool successful = slavePort.sendTimingResp(pkt);

    // If packet successfully sent, delete the sender state, otherwise
    // restore state
    if (successful) {
        delete receivedState;
    } else {
        // Don't delete anything and let the packet look like we did
        // not touch it
        pkt->senderState = receivedState;
        pkt->setAddr(remapped_addr);
    }
    return successful;
}

void
AddrMapper::recvTimingSnoopReq(PacketPtr pkt)
{
    slavePort.sendTimingSnoopReq(pkt);
}

bool
AddrMapper::recvTimingSnoopResp(PacketPtr pkt)
{
    return masterPort.sendTimingSnoopResp(pkt);
}

bool
AddrMapper::isSnooping() const
{
    if (slavePort.isSnooping())
        fatal("AddrMapper doesn't support remapping of snooping requests\n");
    return false;
}

unsigned
AddrMapper::deviceBlockSizeMaster()
{
    return slavePort.peerBlockSize();
}

unsigned
AddrMapper::deviceBlockSizeSlave()
{
    return masterPort.peerBlockSize();
}

void
AddrMapper::recvRetryMaster()
{
    slavePort.sendRetry();
}

void
AddrMapper::recvRetrySlave()
{
    masterPort.sendRetry();
}

void
AddrMapper::recvRangeChange()
{
    slavePort.sendRangeChange();
}

RangeAddrMapper::RangeAddrMapper(const RangeAddrMapperParams* p) :
    AddrMapper(p),
    originalRanges(p->original_ranges),
    remappedRanges(p->remapped_ranges)
{
    if (originalRanges.size() != remappedRanges.size())
        fatal("AddrMapper: original and shadowed range list must "
              "be same size\n");

    for (size_t x = 0; x < originalRanges.size(); x++) {
        if (originalRanges[x].size() != remappedRanges[x].size())
            fatal("AddrMapper: original and shadowed range list elements"
                  " aren't all of the same size\n");
    }
}

RangeAddrMapper*
RangeAddrMapperParams::create()
{
    return new RangeAddrMapper(this);
}

Addr
RangeAddrMapper::remapAddr(Addr addr) const
{
    for (int i = 0; i < originalRanges.size(); ++i) {
        if (originalRanges[i].contains(addr)) {
            Addr offset = addr - originalRanges[i].start();
            return offset + remappedRanges[i].start();
        }
    }

    return addr;
}

AddrRangeList
RangeAddrMapper::getAddrRanges() const
{
    AddrRangeList ranges;
    AddrRangeList actualRanges = masterPort.getAddrRanges();

    for (AddrRangeIter r = actualRanges.begin(); r != actualRanges.end(); ++r) {
        AddrRange range = *r;

        for (int j = 0; j < originalRanges.size(); ++j) {
            if (range.intersects(originalRanges[j]))
                fatal("Cannot remap range that intersects the original"
                      " ranges but are not a subset.\n");
            if (range.isSubset(originalRanges[j])) {
                // range is a subset
                Addr offset = range.start() - originalRanges[j].start();
                Addr start = range.start() - offset;
                ranges.push_back(AddrRange(start, start + range.size() - 1));
            } else {
                ranges.push_back(range);
            }
        }
    }

    return ranges;
}

<commit_msg>mem: Skip address mapper range checks to allow more flexibility<commit_after>/*
 * Copyright (c) 2012 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Andreas Hansson
 */

#include "mem/addr_mapper.hh"

AddrMapper::AddrMapper(const AddrMapperParams* p)
    : MemObject(p),
      masterPort(name() + "-master", *this),
      slavePort(name() + "-slave", *this)
{
}

void
AddrMapper::init()
{
    if (!slavePort.isConnected() || !masterPort.isConnected())
        fatal("Address mapper is not connected on both sides.\n");

    if ((slavePort.peerBlockSize() != masterPort.peerBlockSize()) &&
        slavePort.peerBlockSize() && masterPort.peerBlockSize())
        fatal("Slave port size %d, master port size %d \n "
              "don't have the same block size... Not supported.\n",
              slavePort.peerBlockSize(), masterPort.peerBlockSize());
}

BaseMasterPort&
AddrMapper::getMasterPort(const std::string& if_name, PortID idx)
{
    if (if_name == "master") {
        return masterPort;
    } else {
        return MemObject::getMasterPort(if_name, idx);
    }
}

BaseSlavePort&
AddrMapper::getSlavePort(const std::string& if_name, PortID idx)
{
    if (if_name == "slave") {
        return slavePort;
    } else {
        return MemObject::getSlavePort(if_name, idx);
    }
}

void
AddrMapper::recvFunctional(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    masterPort.sendFunctional(pkt);
    pkt->setAddr(orig_addr);
}

void
AddrMapper::recvFunctionalSnoop(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    slavePort.sendFunctionalSnoop(pkt);
    pkt->setAddr(orig_addr);
}

Tick
AddrMapper::recvAtomic(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    Tick ret_tick =  masterPort.sendAtomic(pkt);
    pkt->setAddr(orig_addr);
    return ret_tick;
}

Tick
AddrMapper::recvAtomicSnoop(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    Tick ret_tick = slavePort.sendAtomicSnoop(pkt);
    pkt->setAddr(orig_addr);
    return ret_tick;
}

bool
AddrMapper::recvTimingReq(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    bool needsResponse = pkt->needsResponse();
    bool memInhibitAsserted = pkt->memInhibitAsserted();
    Packet::SenderState* senderState = pkt->senderState;

    if (needsResponse && !memInhibitAsserted) {
        pkt->senderState = new AddrMapperSenderState(senderState, orig_addr);
    }

    pkt->setAddr(remapAddr(orig_addr));

    // Attempt to send the packet (always succeeds for inhibited
    // packets)
    bool successful = masterPort.sendTimingReq(pkt);

    // If not successful, restore the sender state
    if (!successful && needsResponse) {
        delete pkt->senderState;
        pkt->senderState = senderState;
    }

    return successful;
}

bool
AddrMapper::recvTimingResp(PacketPtr pkt)
{
    AddrMapperSenderState* receivedState =
        dynamic_cast<AddrMapperSenderState*>(pkt->senderState);

    // Restore initial sender state
    if (receivedState == NULL)
        panic("AddrMapper %s got a response without sender state\n",
              name());

    Addr remapped_addr = pkt->getAddr();

    // Restore the state and address
    pkt->senderState = receivedState->origSenderState;
    pkt->setAddr(receivedState->origAddr);

    // Attempt to send the packet
    bool successful = slavePort.sendTimingResp(pkt);

    // If packet successfully sent, delete the sender state, otherwise
    // restore state
    if (successful) {
        delete receivedState;
    } else {
        // Don't delete anything and let the packet look like we did
        // not touch it
        pkt->senderState = receivedState;
        pkt->setAddr(remapped_addr);
    }
    return successful;
}

void
AddrMapper::recvTimingSnoopReq(PacketPtr pkt)
{
    slavePort.sendTimingSnoopReq(pkt);
}

bool
AddrMapper::recvTimingSnoopResp(PacketPtr pkt)
{
    return masterPort.sendTimingSnoopResp(pkt);
}

bool
AddrMapper::isSnooping() const
{
    if (slavePort.isSnooping())
        fatal("AddrMapper doesn't support remapping of snooping requests\n");
    return false;
}

unsigned
AddrMapper::deviceBlockSizeMaster()
{
    return slavePort.peerBlockSize();
}

unsigned
AddrMapper::deviceBlockSizeSlave()
{
    return masterPort.peerBlockSize();
}

void
AddrMapper::recvRetryMaster()
{
    slavePort.sendRetry();
}

void
AddrMapper::recvRetrySlave()
{
    masterPort.sendRetry();
}

void
AddrMapper::recvRangeChange()
{
    slavePort.sendRangeChange();
}

RangeAddrMapper::RangeAddrMapper(const RangeAddrMapperParams* p) :
    AddrMapper(p),
    originalRanges(p->original_ranges),
    remappedRanges(p->remapped_ranges)
{
    if (originalRanges.size() != remappedRanges.size())
        fatal("AddrMapper: original and shadowed range list must "
              "be same size\n");

    for (size_t x = 0; x < originalRanges.size(); x++) {
        if (originalRanges[x].size() != remappedRanges[x].size())
            fatal("AddrMapper: original and shadowed range list elements"
                  " aren't all of the same size\n");
    }
}

RangeAddrMapper*
RangeAddrMapperParams::create()
{
    return new RangeAddrMapper(this);
}

Addr
RangeAddrMapper::remapAddr(Addr addr) const
{
    for (int i = 0; i < originalRanges.size(); ++i) {
        if (originalRanges[i].contains(addr)) {
            Addr offset = addr - originalRanges[i].start();
            return offset + remappedRanges[i].start();
        }
    }

    return addr;
}

AddrRangeList
RangeAddrMapper::getAddrRanges() const
{
    // Simply return the original ranges as given by the parameters
    AddrRangeList ranges(originalRanges.begin(), originalRanges.end());
    return ranges;
}

<|endoftext|>