<commit_before>//===-- ELFHeader.cpp ----------------------------------------- -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include <cstring>

#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/Stream.h"

#include "ELFHeader.h"

using namespace elf;
using namespace lldb;
using namespace llvm::ELF;

//------------------------------------------------------------------------------
// Static utility functions.
//
// GetMaxU64 and GetMaxS64 wrap the similarly named methods from DataExtractor
// with error handling code and provide for parsing a sequence of values.
static bool
GetMaxU64(const lldb_private::DataExtractor &data,
          lldb::offset_t *offset,
          uint64_t *value,
          uint32_t byte_size)
{
    const lldb::offset_t saved_offset = *offset;
    *value = data.GetMaxU64(offset, byte_size);
    return *offset != saved_offset;
}

static bool
GetMaxU64(const lldb_private::DataExtractor &data,
          lldb::offset_t *offset,
          uint64_t *value,
          uint32_t byte_size,
          uint32_t count)
{
    lldb::offset_t saved_offset = *offset;

    for (uint32_t i = 0; i < count; ++i, ++value)
    {
        if (GetMaxU64(data, offset, value, byte_size) == false)
        {
            *offset = saved_offset;
            return false;
        }
    }
    return true;
}

static bool
GetMaxS64(const lldb_private::DataExtractor &data,
          lldb::offset_t *offset,
          int64_t *value,
          uint32_t byte_size)
{
    const lldb::offset_t saved_offset = *offset;
    *value = data.GetMaxS64(offset, byte_size);
    return *offset != saved_offset;
}

static bool
GetMaxS64(const lldb_private::DataExtractor &data,
          lldb::offset_t *offset,
          int64_t *value,
          uint32_t byte_size,
          uint32_t count)
{
    lldb::offset_t saved_offset = *offset;

    for (uint32_t i = 0; i < count; ++i, ++value)
    {
        if (GetMaxS64(data, offset, value, byte_size) == false)
        {
            *offset = saved_offset;
            return false;
        }
    }
    return true;
}

//------------------------------------------------------------------------------
// ELFHeader

ELFHeader::ELFHeader()
{
    memset(this, 0, sizeof(ELFHeader));
}

ByteOrder
ELFHeader::GetByteOrder() const
{
    if (e_ident[EI_DATA] == ELFDATA2MSB)
        return eByteOrderBig;
    if (e_ident[EI_DATA] == ELFDATA2LSB)
        return eByteOrderLittle;
    return eByteOrderInvalid;
}

bool
ELFHeader::Parse(lldb_private::DataExtractor &data, lldb::offset_t *offset)
{
    // Read e_ident.  This provides byte order and address size info.
    if (data.GetU8(offset, &e_ident, EI_NIDENT) == NULL)
        return false;

    const unsigned byte_size = Is32Bit() ? 4 : 8;
    data.SetByteOrder(GetByteOrder());
    data.SetAddressByteSize(byte_size);

    // Read e_type and e_machine.
    if (data.GetU16(offset, &e_type, 2) == NULL)
        return false;

    // Read e_version.
    if (data.GetU32(offset, &e_version, 1) == NULL)
        return false;

    // Read e_entry, e_phoff and e_shoff.
    if (GetMaxU64(data, offset, &e_entry, byte_size, 3) == false)
        return false;

    // Read e_flags.
    if (data.GetU32(offset, &e_flags, 1) == NULL)
        return false;

    // Read e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum and
    // e_shstrndx.
    if (data.GetU16(offset, &e_ehsize, 6) == NULL)
        return false;

    return true;
}

bool
ELFHeader::MagicBytesMatch(const uint8_t *magic)
{
    return memcmp(magic, ElfMagic, strlen(ElfMagic)) == 0;
}

unsigned
ELFHeader::AddressSizeInBytes(const uint8_t *magic)
{
    unsigned address_size = 0;

    switch (magic[EI_CLASS])
    {
    case ELFCLASS32:
        address_size = 4;
        break;

    case ELFCLASS64:
        address_size = 8;
        break;
    }
    return address_size;
}

unsigned
ELFHeader::GetRelocationJumpSlotType() const
{
    unsigned slot = 0;

    switch (e_machine)
    {
    default:
        assert(false && "architecture not supported");
        break;
    case EM_PPC:
        slot = R_PPC_JMP_SLOT;
        break;
    case EM_PPC64:
        slot = R_PPC64_JMP_SLOT;
        break;
    case EM_386:
    case EM_IAMCU: // FIXME: is this correct?
        slot = R_386_JUMP_SLOT;
        break;
    case EM_X86_64:
        slot = R_X86_64_JUMP_SLOT;
        break;
    case EM_ARM:
        slot = R_ARM_JUMP_SLOT;
        break;
    case EM_HEXAGON:
        slot = R_HEX_JMP_SLOT;
        break;
    case EM_AARCH64:
        slot = R_AARCH64_JUMP_SLOT;
        break;
    case EM_MIPS:
        slot = R_MIPS_JUMP_SLOT;
        break;
    }

    return slot;
}

//------------------------------------------------------------------------------
// ELFSectionHeader

ELFSectionHeader::ELFSectionHeader()
{
    memset(this, 0, sizeof(ELFSectionHeader));
}

bool
ELFSectionHeader::Parse(const lldb_private::DataExtractor &data,
                        lldb::offset_t *offset)
{
    const unsigned byte_size = data.GetAddressByteSize();

    // Read sh_name and sh_type.
    if (data.GetU32(offset, &sh_name, 2) == NULL)
        return false;

    // Read sh_flags.
    if (GetMaxU64(data, offset, &sh_flags, byte_size) == false)
        return false;

    // Read sh_addr, sh_off and sh_size.
    if (GetMaxU64(data, offset, &sh_addr, byte_size, 3) == false)
        return false;

    // Read sh_link and sh_info.
    if (data.GetU32(offset, &sh_link, 2) == NULL)
        return false;

    // Read sh_addralign and sh_entsize.
    if (GetMaxU64(data, offset, &sh_addralign, byte_size, 2) == false)
        return false;

    return true;
}

//------------------------------------------------------------------------------
// ELFSymbol

ELFSymbol::ELFSymbol()
{
    memset(this, 0, sizeof(ELFSymbol));
}

#define ENUM_TO_CSTR(e) case e: return #e

const char *
ELFSymbol::bindingToCString(unsigned char binding)
{
    switch (binding)
    {
    ENUM_TO_CSTR(STB_LOCAL);
    ENUM_TO_CSTR(STB_GLOBAL);
    ENUM_TO_CSTR(STB_WEAK);
    ENUM_TO_CSTR(STB_LOOS);
    ENUM_TO_CSTR(STB_HIOS);
    ENUM_TO_CSTR(STB_LOPROC);
    ENUM_TO_CSTR(STB_HIPROC);
    }
    return "";
}

const char *
ELFSymbol::typeToCString(unsigned char type)
{
    switch (type)
    {
    ENUM_TO_CSTR(STT_NOTYPE);
    ENUM_TO_CSTR(STT_OBJECT);
    ENUM_TO_CSTR(STT_FUNC);
    ENUM_TO_CSTR(STT_SECTION);
    ENUM_TO_CSTR(STT_FILE);
    ENUM_TO_CSTR(STT_COMMON);
    ENUM_TO_CSTR(STT_TLS);
    ENUM_TO_CSTR(STT_LOOS);
    ENUM_TO_CSTR(STT_HIOS);
    ENUM_TO_CSTR(STT_GNU_IFUNC);
    ENUM_TO_CSTR(STT_LOPROC);
    ENUM_TO_CSTR(STT_HIPROC);
    }
    return "";
}

const char *
ELFSymbol::sectionIndexToCString (elf_half shndx,
                                  const lldb_private::SectionList *section_list)
{
    switch (shndx)
    {
    ENUM_TO_CSTR(SHN_UNDEF);
    ENUM_TO_CSTR(SHN_LOPROC);
    ENUM_TO_CSTR(SHN_HIPROC);
    ENUM_TO_CSTR(SHN_LOOS);
    ENUM_TO_CSTR(SHN_HIOS);
    ENUM_TO_CSTR(SHN_ABS);
    ENUM_TO_CSTR(SHN_COMMON);
    ENUM_TO_CSTR(SHN_XINDEX);
    default:
        {
            const lldb_private::Section *section = section_list->GetSectionAtIndex(shndx).get();
            if (section)
                return section->GetName().AsCString("");
        }
        break;
    }
    return "";
}

void
ELFSymbol::Dump (lldb_private::Stream *s,
                 uint32_t idx,
                 const lldb_private::DataExtractor *strtab_data,
                 const lldb_private::SectionList *section_list)
{
    s->Printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 " 0x%8.8x 0x%2.2x (%-10s %-13s) 0x%2.2x 0x%4.4x (%-10s) %s\n",
              idx,
              st_value,
              st_size,
              st_name,
              st_info,
              bindingToCString (getBinding()),
              typeToCString (getType()),
              st_other,
              st_shndx,
              sectionIndexToCString (st_shndx, section_list),
              strtab_data ? strtab_data->PeekCStr(st_name) : "");
}

bool
ELFSymbol::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
{
    const unsigned byte_size = data.GetAddressByteSize();
    const bool parsing_32 = byte_size == 4;

    // Read st_name.
    if (data.GetU32(offset, &st_name, 1) == NULL)
        return false;

    if (parsing_32)
    {
        // Read st_value and st_size.
        if (GetMaxU64(data, offset, &st_value, byte_size, 2) == false)
            return false;

        // Read st_info and st_other.
        if (data.GetU8(offset, &st_info, 2) == NULL)
            return false;

        // Read st_shndx.
        if (data.GetU16(offset, &st_shndx, 1) == NULL)
            return false;
    }
    else
    {
        // Read st_info and st_other.
        if (data.GetU8(offset, &st_info, 2) == NULL)
            return false;

        // Read st_shndx.
        if (data.GetU16(offset, &st_shndx, 1) == NULL)
            return false;

        // Read st_value and st_size.
        if (data.GetU64(offset, &st_value, 2) == NULL)
            return false;
    }
    return true;
}

//------------------------------------------------------------------------------
// ELFProgramHeader

ELFProgramHeader::ELFProgramHeader()
{
    memset(this, 0, sizeof(ELFProgramHeader));
}

bool
ELFProgramHeader::Parse(const lldb_private::DataExtractor &data,
                        lldb::offset_t *offset)
{
    const uint32_t byte_size = data.GetAddressByteSize();
    const bool parsing_32 = byte_size == 4;

    // Read p_type;
    if (data.GetU32(offset, &p_type, 1) == NULL)
        return false;

    if (parsing_32) {
        // Read p_offset, p_vaddr, p_paddr, p_filesz and p_memsz.
        if (GetMaxU64(data, offset, &p_offset, byte_size, 5) == false)
            return false;

        // Read p_flags.
        if (data.GetU32(offset, &p_flags, 1) == NULL)
            return false;

        // Read p_align.
        if (GetMaxU64(data, offset, &p_align, byte_size) == false)
            return false;
    }
    else {
        // Read p_flags.
        if (data.GetU32(offset, &p_flags, 1) == NULL)
            return false;

        // Read p_offset, p_vaddr, p_paddr, p_filesz, p_memsz and p_align.
        if (GetMaxU64(data, offset, &p_offset, byte_size, 6) == false)
            return false;
    }

    return true;
}

//------------------------------------------------------------------------------
// ELFDynamic

ELFDynamic::ELFDynamic()
{
    memset(this, 0, sizeof(ELFDynamic));
}

bool
ELFDynamic::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
{
    const unsigned byte_size = data.GetAddressByteSize();
    return GetMaxS64(data, offset, &d_tag, byte_size, 2);
}

//------------------------------------------------------------------------------
// ELFRel

ELFRel::ELFRel()
{
    memset(this, 0, sizeof(ELFRel));
}

bool
ELFRel::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
{
    const unsigned byte_size = data.GetAddressByteSize();

    // Read r_offset and r_info.
    if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false)
        return false;

    return true;
}

//------------------------------------------------------------------------------
// ELFRela

ELFRela::ELFRela()
{
    memset(this, 0, sizeof(ELFRela));
}

bool
ELFRela::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
{
    const unsigned byte_size = data.GetAddressByteSize();

    // Read r_offset and r_info.
    if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false)
        return false;

    // Read r_addend;
    if (GetMaxS64(data, offset, &r_addend, byte_size) == false)
        return false;

    return true;
}

<commit_msg>Fix build breakage after llvm r240426<commit_after>//===-- ELFHeader.cpp ----------------------------------------- -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include <cstring>

#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/Stream.h"

#include "ELFHeader.h"

using namespace elf;
using namespace lldb;
using namespace llvm::ELF;

//------------------------------------------------------------------------------
// Static utility functions.
//
// GetMaxU64 and GetMaxS64 wrap the similarly named methods from DataExtractor
// with error handling code and provide for parsing a sequence of values.
static bool
GetMaxU64(const lldb_private::DataExtractor &data,
          lldb::offset_t *offset,
          uint64_t *value,
          uint32_t byte_size)
{
    const lldb::offset_t saved_offset = *offset;
    *value = data.GetMaxU64(offset, byte_size);
    return *offset != saved_offset;
}

static bool
GetMaxU64(const lldb_private::DataExtractor &data,
          lldb::offset_t *offset,
          uint64_t *value,
          uint32_t byte_size,
          uint32_t count)
{
    lldb::offset_t saved_offset = *offset;

    for (uint32_t i = 0; i < count; ++i, ++value)
    {
        if (GetMaxU64(data, offset, value, byte_size) == false)
        {
            *offset = saved_offset;
            return false;
        }
    }
    return true;
}

static bool
GetMaxS64(const lldb_private::DataExtractor &data,
          lldb::offset_t *offset,
          int64_t *value,
          uint32_t byte_size)
{
    const lldb::offset_t saved_offset = *offset;
    *value = data.GetMaxS64(offset, byte_size);
    return *offset != saved_offset;
}

static bool
GetMaxS64(const lldb_private::DataExtractor &data,
          lldb::offset_t *offset,
          int64_t *value,
          uint32_t byte_size,
          uint32_t count)
{
    lldb::offset_t saved_offset = *offset;

    for (uint32_t i = 0; i < count; ++i, ++value)
    {
        if (GetMaxS64(data, offset, value, byte_size) == false)
        {
            *offset = saved_offset;
            return false;
        }
    }
    return true;
}

//------------------------------------------------------------------------------
// ELFHeader

ELFHeader::ELFHeader()
{
    memset(this, 0, sizeof(ELFHeader));
}

ByteOrder
ELFHeader::GetByteOrder() const
{
    if (e_ident[EI_DATA] == ELFDATA2MSB)
        return eByteOrderBig;
    if (e_ident[EI_DATA] == ELFDATA2LSB)
        return eByteOrderLittle;
    return eByteOrderInvalid;
}

bool
ELFHeader::Parse(lldb_private::DataExtractor &data, lldb::offset_t *offset)
{
    // Read e_ident.  This provides byte order and address size info.
    if (data.GetU8(offset, &e_ident, EI_NIDENT) == NULL)
        return false;

    const unsigned byte_size = Is32Bit() ? 4 : 8;
    data.SetByteOrder(GetByteOrder());
    data.SetAddressByteSize(byte_size);

    // Read e_type and e_machine.
    if (data.GetU16(offset, &e_type, 2) == NULL)
        return false;

    // Read e_version.
    if (data.GetU32(offset, &e_version, 1) == NULL)
        return false;

    // Read e_entry, e_phoff and e_shoff.
    if (GetMaxU64(data, offset, &e_entry, byte_size, 3) == false)
        return false;

    // Read e_flags.
    if (data.GetU32(offset, &e_flags, 1) == NULL)
        return false;

    // Read e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum and
    // e_shstrndx.
    if (data.GetU16(offset, &e_ehsize, 6) == NULL)
        return false;

    return true;
}

bool
ELFHeader::MagicBytesMatch(const uint8_t *magic)
{
    return memcmp(magic, ElfMagic, strlen(ElfMagic)) == 0;
}

unsigned
ELFHeader::AddressSizeInBytes(const uint8_t *magic)
{
    unsigned address_size = 0;

    switch (magic[EI_CLASS])
    {
    case ELFCLASS32:
        address_size = 4;
        break;

    case ELFCLASS64:
        address_size = 8;
        break;
    }
    return address_size;
}

unsigned
ELFHeader::GetRelocationJumpSlotType() const
{
    unsigned slot = 0;

    switch (e_machine)
    {
    default:
        assert(false && "architecture not supported");
        break;
    case EM_PPC:
        slot = R_PPC_JMP_SLOT;
        break;
    case EM_PPC64:
        slot = R_PPC64_JMP_SLOT;
        break;
    case EM_386:
    case EM_IAMCU: // FIXME: is this correct?
        slot = R_386_JUMP_SLOT;
        break;
    case EM_X86_64:
        slot = R_X86_64_JUMP_SLOT;
        break;
    case EM_ARM:
        slot = R_ARM_JUMP_SLOT;
        break;
    case EM_HEXAGON:
        slot = R_HEX_JMP_SLOT;
        break;
    case EM_AARCH64:
        slot = R_AARCH64_JUMP_SLOT;
        break;
    case EM_MIPS:
        slot = R_MIPS_JUMP_SLOT;
        break;
    }

    return slot;
}

//------------------------------------------------------------------------------
// ELFSectionHeader

ELFSectionHeader::ELFSectionHeader()
{
    memset(this, 0, sizeof(ELFSectionHeader));
}

bool
ELFSectionHeader::Parse(const lldb_private::DataExtractor &data,
                        lldb::offset_t *offset)
{
    const unsigned byte_size = data.GetAddressByteSize();

    // Read sh_name and sh_type.
    if (data.GetU32(offset, &sh_name, 2) == NULL)
        return false;

    // Read sh_flags.
    if (GetMaxU64(data, offset, &sh_flags, byte_size) == false)
        return false;

    // Read sh_addr, sh_off and sh_size.
    if (GetMaxU64(data, offset, &sh_addr, byte_size, 3) == false)
        return false;

    // Read sh_link and sh_info.
    if (data.GetU32(offset, &sh_link, 2) == NULL)
        return false;

    // Read sh_addralign and sh_entsize.
    if (GetMaxU64(data, offset, &sh_addralign, byte_size, 2) == false)
        return false;

    return true;
}

//------------------------------------------------------------------------------
// ELFSymbol

ELFSymbol::ELFSymbol()
{
    memset(this, 0, sizeof(ELFSymbol));
}

#define ENUM_TO_CSTR(e) case e: return #e

const char *
ELFSymbol::bindingToCString(unsigned char binding)
{
    switch (binding)
    {
    ENUM_TO_CSTR(STB_LOCAL);
    ENUM_TO_CSTR(STB_GLOBAL);
    ENUM_TO_CSTR(STB_WEAK);
    ENUM_TO_CSTR(STB_LOOS);
    ENUM_TO_CSTR(STB_HIOS);
    ENUM_TO_CSTR(STB_LOPROC);
    ENUM_TO_CSTR(STB_HIPROC);
    }
    return "";
}

const char *
ELFSymbol::typeToCString(unsigned char type)
{
    switch (type)
    {
    ENUM_TO_CSTR(STT_NOTYPE);
    ENUM_TO_CSTR(STT_OBJECT);
    ENUM_TO_CSTR(STT_FUNC);
    ENUM_TO_CSTR(STT_SECTION);
    ENUM_TO_CSTR(STT_FILE);
    ENUM_TO_CSTR(STT_COMMON);
    ENUM_TO_CSTR(STT_TLS);
    ENUM_TO_CSTR(STT_GNU_IFUNC);
    ENUM_TO_CSTR(STT_HIOS);
    ENUM_TO_CSTR(STT_LOPROC);
    ENUM_TO_CSTR(STT_HIPROC);
    }
    return "";
}

const char *
ELFSymbol::sectionIndexToCString (elf_half shndx,
                                  const lldb_private::SectionList *section_list)
{
    switch (shndx)
    {
    ENUM_TO_CSTR(SHN_UNDEF);
    ENUM_TO_CSTR(SHN_LOPROC);
    ENUM_TO_CSTR(SHN_HIPROC);
    ENUM_TO_CSTR(SHN_LOOS);
    ENUM_TO_CSTR(SHN_HIOS);
    ENUM_TO_CSTR(SHN_ABS);
    ENUM_TO_CSTR(SHN_COMMON);
    ENUM_TO_CSTR(SHN_XINDEX);
    default:
        {
            const lldb_private::Section *section = section_list->GetSectionAtIndex(shndx).get();
            if (section)
                return section->GetName().AsCString("");
        }
        break;
    }
    return "";
}

void
ELFSymbol::Dump (lldb_private::Stream *s,
                 uint32_t idx,
                 const lldb_private::DataExtractor *strtab_data,
                 const lldb_private::SectionList *section_list)
{
    s->Printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 " 0x%8.8x 0x%2.2x (%-10s %-13s) 0x%2.2x 0x%4.4x (%-10s) %s\n",
              idx,
              st_value,
              st_size,
              st_name,
              st_info,
              bindingToCString (getBinding()),
              typeToCString (getType()),
              st_other,
              st_shndx,
              sectionIndexToCString (st_shndx, section_list),
              strtab_data ? strtab_data->PeekCStr(st_name) : "");
}

bool
ELFSymbol::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
{
    const unsigned byte_size = data.GetAddressByteSize();
    const bool parsing_32 = byte_size == 4;

    // Read st_name.
    if (data.GetU32(offset, &st_name, 1) == NULL)
        return false;

    if (parsing_32)
    {
        // Read st_value and st_size.
        if (GetMaxU64(data, offset, &st_value, byte_size, 2) == false)
            return false;

        // Read st_info and st_other.
        if (data.GetU8(offset, &st_info, 2) == NULL)
            return false;

        // Read st_shndx.
        if (data.GetU16(offset, &st_shndx, 1) == NULL)
            return false;
    }
    else
    {
        // Read st_info and st_other.
        if (data.GetU8(offset, &st_info, 2) == NULL)
            return false;

        // Read st_shndx.
        if (data.GetU16(offset, &st_shndx, 1) == NULL)
            return false;

        // Read st_value and st_size.
        if (data.GetU64(offset, &st_value, 2) == NULL)
            return false;
    }
    return true;
}

//------------------------------------------------------------------------------
// ELFProgramHeader

ELFProgramHeader::ELFProgramHeader()
{
    memset(this, 0, sizeof(ELFProgramHeader));
}

bool
ELFProgramHeader::Parse(const lldb_private::DataExtractor &data,
                        lldb::offset_t *offset)
{
    const uint32_t byte_size = data.GetAddressByteSize();
    const bool parsing_32 = byte_size == 4;

    // Read p_type;
    if (data.GetU32(offset, &p_type, 1) == NULL)
        return false;

    if (parsing_32) {
        // Read p_offset, p_vaddr, p_paddr, p_filesz and p_memsz.
        if (GetMaxU64(data, offset, &p_offset, byte_size, 5) == false)
            return false;

        // Read p_flags.
        if (data.GetU32(offset, &p_flags, 1) == NULL)
            return false;

        // Read p_align.
        if (GetMaxU64(data, offset, &p_align, byte_size) == false)
            return false;
    }
    else {
        // Read p_flags.
        if (data.GetU32(offset, &p_flags, 1) == NULL)
            return false;

        // Read p_offset, p_vaddr, p_paddr, p_filesz, p_memsz and p_align.
        if (GetMaxU64(data, offset, &p_offset, byte_size, 6) == false)
            return false;
    }

    return true;
}

//------------------------------------------------------------------------------
// ELFDynamic

ELFDynamic::ELFDynamic()
{
    memset(this, 0, sizeof(ELFDynamic));
}

bool
ELFDynamic::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
{
    const unsigned byte_size = data.GetAddressByteSize();
    return GetMaxS64(data, offset, &d_tag, byte_size, 2);
}

//------------------------------------------------------------------------------
// ELFRel

ELFRel::ELFRel()
{
    memset(this, 0, sizeof(ELFRel));
}

bool
ELFRel::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
{
    const unsigned byte_size = data.GetAddressByteSize();

    // Read r_offset and r_info.
    if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false)
        return false;

    return true;
}

//------------------------------------------------------------------------------
// ELFRela

ELFRela::ELFRela()
{
    memset(this, 0, sizeof(ELFRela));
}

bool
ELFRela::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
{
    const unsigned byte_size = data.GetAddressByteSize();

    // Read r_offset and r_info.
    if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false)
        return false;

    // Read r_addend;
    if (GetMaxS64(data, offset, &r_addend, byte_size) == false)
        return false;

    return true;
}

<|endoftext|>


<commit_before>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2012 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#include "coverage_join.hh"
#include "helper.hh"

Coverage_Join::Coverage_Join(Log& l,const std::string& param)
  : Coverage(l), child(NULL)
{
  commalist(param,subs);
  if (subs.size()>1) {
    child=new_coverage(l,subs.back());
  }
  status&=(child!=NULL);
}

void Coverage_Join::handle_sub(const std::string& sub)
{
  std::string mapped_to;
  std::string tmp;
  std::vector<std::string> mapped_from;

  param_cut(sub,mapped_to,tmp);
  commalist(tmp,mapped_from);
  // mapped_to is the _new_ alphabet
  // mapped_from is the alphas found in the current alphabet
  // Let's check that mapped_to doesn't exist in the ActionNames
  if (find(ActionNames,mapped_to)) {
    status=false;
    errormsg=mapped_to+" found twice";
  }

  log.debug("Mapping action %s\n",mapped_to.c_str());

  ActionNames.push_back(mapped_to);
  for(unsigned i=0;i<mapped_from.size();i++) {
    int pos=find(ActionNames_from,mapped_from[i]);
    log.debug("Handling mapping at %i (%s) pos %i\n",i,mapped_from[i].c_str(),pos);
    if (!pos) {
      // No luck? RegExp?
      log.debug("No luck... %s\n",mapped_from[i].c_str());
    } else {
      int m=ActionNames.size()-1;
      action_mapper[pos]=m;
      ActionNames_from[pos]=""; // Only one map....
    }
  }
}

void Coverage_Join::set_model(Model* _model)
{
  Coverage::set_model(_model);
  ActionNames.push_back(""); // TAU

  ActionNames_from=model->getActionNames();

  for(unsigned i=0;i<subs.size()-1;i++) {
    if (!status) {
      return;
    }
    handle_sub(subs[i]);
  }

  log.debug("action_names count %i\n",ActionNames.size());

  // Let's handle not mapped actions

  for(unsigned i=0;i<ActionNames_from.size();i++) {
    if (ActionNames_from[i]!="") {
      int m=ActionNames.size();

      log.debug("Action %i (%s) not mapped. Mapping to %i\n",
	     i,ActionNames_from[i].c_str(),m);

      ActionNames.push_back(ActionNames_from[i]);
      action_mapper[i]=m;
    }
  }

  ActionNames_from.clear();

  alpha=new Alphabet_impl(ActionNames,SPNames);
  submodel=new Model_yes(log,"");
  submodel->set_model(alpha);
  child->set_model(submodel);
}

FACTORY_DEFAULT_CREATOR(Coverage, Coverage_Join, "join")
<commit_msg>coverage join: Better error handling<commit_after>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2012 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#include "coverage_join.hh"
#include "helper.hh"

Coverage_Join::Coverage_Join(Log& l,const std::string& param)
  : Coverage(l), child(NULL)
{
  commalist(param,subs);

  if (subs.size()>1) {
    child=new_coverage(l,subs.back());
  }

  if (child==NULL) {
    status=false;
    errormsg="Can't create coverage:"+subs.back();
    return;
  }

  if (!child->status) {
    status=false;
    errormsg="coverage error at "+subs.back()+ ":"+ child->errormsg;
  }

}

void Coverage_Join::handle_sub(const std::string& sub)
{
  std::string mapped_to;
  std::string tmp;
  std::vector<std::string> mapped_from;

  param_cut(sub,mapped_to,tmp);
  commalist(tmp,mapped_from);
  // mapped_to is the _new_ alphabet
  // mapped_from is the alphas found in the current alphabet
  // Let's check that mapped_to doesn't exist in the ActionNames
  if (find(ActionNames,mapped_to)) {
    status=false;
    errormsg=mapped_to+" found twice";
  }

  log.debug("Mapping action %s\n",mapped_to.c_str());

  ActionNames.push_back(mapped_to);
  for(unsigned i=0;i<mapped_from.size();i++) {
    int pos=find(ActionNames_from,mapped_from[i]);
    log.debug("Handling mapping at %i (%s) pos %i\n",i,mapped_from[i].c_str(),pos);
    if (!pos) {
      // No luck? RegExp?
      log.debug("No luck... %s\n",mapped_from[i].c_str());
    } else {
      int m=ActionNames.size()-1;
      action_mapper[pos]=m;
      ActionNames_from[pos]=""; // Only one map....
    }
  }
}

void Coverage_Join::set_model(Model* _model)
{
  Coverage::set_model(_model);
  ActionNames.push_back(""); // TAU

  ActionNames_from=model->getActionNames();

  for(unsigned i=0;i<subs.size()-1;i++) {
    if (!status) {
      return;
    }
    handle_sub(subs[i]);
  }

  log.debug("action_names count %i\n",ActionNames.size());

  // Let's handle not mapped actions

  for(unsigned i=0;i<ActionNames_from.size();i++) {
    if (ActionNames_from[i]!="") {
      int m=ActionNames.size();

      log.debug("Action %i (%s) not mapped. Mapping to %i\n",
	     i,ActionNames_from[i].c_str(),m);

      ActionNames.push_back(ActionNames_from[i]);
      action_mapper[i]=m;
    }
  }

  ActionNames_from.clear();

  alpha=new Alphabet_impl(ActionNames,SPNames);
  submodel=new Model_yes(log,"");
  submodel->set_model(alpha);
  child->set_model(submodel);
}

FACTORY_DEFAULT_CREATOR(Coverage, Coverage_Join, "join")
<|endoftext|>


<commit_before>#include <istream>

#include "../../hpp/tom/tom.hpp"

#include "../../hpp/ax/ax.hpp"

namespace ax
{
    // A trivial program type to demonstrate the eventable program mixin.
    class eventable_test : public eventable<eventable_test>
    {
    protected:
        enable_cast(eventable_test, eventable<eventable_test>);
    };

    class inspectable_test : public inspectable
    {
    protected:

        enable_cast(inspectable_test, inspectable);

        const std::shared_ptr<type_t> type = register_sub_type<inspectable_test>(typeid(inspectable),
        {
            { "bool_value",             register_field<bool>                        (offsetof(inspectable_test, bool_value)) },
            { "int_value",              register_field<int>                         (offsetof(inspectable_test, int_value)) },
            { "float_value",            register_field<float>                       (offsetof(inspectable_test, float_value)) },
            { "name_value",             register_field<name_t>                      (offsetof(inspectable_test, name_value)) },
            { "address_value",          register_field<address>                     (offsetof(inspectable_test, address_value)) },
            { "vector_int_value",       register_field<std::vector<int>>            (offsetof(inspectable_test, vector_int_value)) },
            { "vector_string_value",    register_field<std::vector<std::string>>    (offsetof(inspectable_test, vector_string_value)) },
            { "unique_int_value",       register_field<std::unique_ptr<int>>        (offsetof(inspectable_test, unique_int_value)) },
            { "shared_int_value",       register_field<std::shared_ptr<int>>        (offsetof(inspectable_test, shared_int_value)) },
            { "pair_value",             register_field<pair<int, int>>              (offsetof(inspectable_test, pair_value)) },
            { "record_value",           register_field<record<int, int, int>>       (offsetof(inspectable_test, record_value)) },
            { "option_some_value",      register_field<option<int>>                 (offsetof(inspectable_test, option_some_value)) },
            { "option_none_value",      register_field<option<int>>                 (offsetof(inspectable_test, option_none_value)) },
            { "either_right_value",     register_field<either<std::string, int>>    (offsetof(inspectable_test, either_right_value)) },
            { "either_left_value",      register_field<either<std::string, int>>    (offsetof(inspectable_test, either_left_value)) },
            { "choice_value",           register_field<choice<int, int, int>>       (offsetof(inspectable_test, choice_value)) }
        });

        std::shared_ptr<type_t> get_type_impl() const override
        {
            return type;
        };

    public:

        int bool_value;
        int int_value;
        float float_value;
        name_t name_value;
        address address_value;
        std::vector<int> vector_int_value;
        std::vector<std::string> vector_string_value;
        std::unique_ptr<int> unique_int_value;
        std::shared_ptr<int> shared_int_value;
        pair<int, int> pair_value;
        record<int, int, int> record_value;
        option<int> option_some_value;
        option<int> option_none_value;
        either<std::string, int> either_right_value;
        either<std::string, int> either_left_value;
        choice<int, int, int> choice_value;

        inspectable_test() :
            bool_value(),
            int_value(),
            float_value(),
            name_value(),
            address_value(),
            vector_int_value(),
            vector_string_value(),
            unique_int_value(std::make_unique<int>()),
            shared_int_value(std::make_shared<int>()),
            pair_value(),
            record_value(),
            option_some_value(),
            option_none_value(),
            either_right_value(),
            either_left_value(),
            choice_value()
        { }

        inspectable_test(
            bool bool_value,
            int int_value,
            float float_value,
            name_t name_value,
            address address_value,
            const std::vector<int>& vector_int_value,
            const std::vector<std::string>& vector_string_value,
            int unique_int_value,
            int shared_int_value,
            pair<int, int> pair_value,
            record<int, int, int> record_value,
            option<int> option_some_value,
            option<int> option_none_value,
            either<std::string, int> either_right_value,
            either<std::string, int> either_left_value,
            choice<int, int, int> choice_value) :
            bool_value(bool_value),
            int_value(int_value),
            float_value(float_value),
            name_value(name_value),
            address_value(address_value),
            vector_int_value(vector_int_value),
            vector_string_value(vector_string_value),
            unique_int_value(std::make_unique<int>(unique_int_value)),
            shared_int_value(std::make_shared<int>(shared_int_value)),
            pair_value(pair_value),
            record_value(record_value),
            option_some_value(option_some_value),
            option_none_value(option_none_value),
            either_right_value(either_right_value),
            either_left_value(either_left_value),
            choice_value(choice_value)
        { }
    };

    TEST("hash works")
    {
        CHECK(ax::get_hash(0) == std::hash<int>()(0));
    }

    TEST("castable works")
    {
        // TODO: implement
    }

    TEST("events work")
    {
        var i = 0;
        ax::eventable_test program{};
        val& event_address = address("event");
        val& participant = std::make_shared<ax::addressable>("participant");
        var handler = [&](val&, val&) { return ++i, true; };
        var unsubscriber = ax::subscribe_event<std::string>(program, event_address, participant, handler);
        ax::publish_event(program, "Event handled!"_s, event_address, participant);
        unsubscriber(program);
        ax::publish_event(program, "Event unhandled."_s, event_address, participant);
        CHECK(i == 1);
    }

    TEST("read and write value works")
    {
        symbol symbol{};
        inspectable_test source(
            true, 5, 10.0f, "jim bob", address("s/compton/la"),
            { 1, 3, 5 }, { "a", "bb", "ccc" }, 666, 777,
            make_pair(50, 100), make_record(150, 200, 250),
            some(2), none<int>(), right<std::string>(4), left<std::string, int>("msg"), third<int, int>(3));
        inspectable_test target{};
        write_value(source, symbol);
        read_value(symbol, target);
        CHECK(target.bool_value);
        CHECK(target.int_value == 5);
        CHECK(target.float_value == 10.0f);
        CHECK(target.name_value == "jim bob");
        CHECK(target.address_value == address("s/compton/la"));
        CHECK(target.vector_int_value == std::vector<int>({ 1, 3, 5 }));
        CHECK(target.vector_string_value == std::vector<std::string>({ "a", "bb", "ccc" }));
        CHECK(*target.unique_int_value == 666);
        CHECK(*target.shared_int_value == 777);
        CHECK(fst(target.pair_value) == 50);
        CHECK(snd(target.pair_value) == 100);
        CHECK(fst(target.record_value) == 150);
        CHECK(snd(target.record_value) == 200);
        CHECK(thd(target.record_value) == 250);
        CHECK(*target.option_some_value == 2);
        CHECK(is_none(target.option_none_value));
        CHECK(*target.either_right_value == 4);
        CHECK(~target.either_left_value == "msg");
        CHECK(get_third(target.choice_value) == 3);
    }

    TEST("parser works")
    {
        val& str =
            "[true 5 10.0 \
              \"jim bob\" \
              \"s/compton/la\" \
              [1 3 5] \
              [\"a\" \"bb\" \"ccc\"] \
              666 \
              777 \
              [50 100] \
              [150 200 250] \
              [some 2] \
              none \
              [right 4] \
              [left \"msg\"] \
              [third 3]]";
        std::stringstream sstr(str);
        sstr << std::noskipws; // apparently avoids skipping whitespace
        std::istream_iterator<char> iter(sstr);
        val& parse = parse_symbol_from_stream(iter, std::istream_iterator<char>());
        val& symbol = get_parse_success(parse);
        inspectable_test target{};
        read_value(symbol, target);
        CHECK(target.bool_value);
        CHECK(target.int_value == 5);
        CHECK(target.float_value == 10.0f);
        CHECK(target.name_value == "jim bob");
        CHECK(target.address_value == address("s/compton/la"));
        CHECK(target.vector_int_value == std::vector<int>({ 1, 3, 5 }));
        CHECK(target.vector_string_value == std::vector<std::string>({ "a", "bb", "ccc" }));
        CHECK(*target.unique_int_value == 666);
        CHECK(*target.shared_int_value == 777);
        CHECK(fst(target.pair_value) == 50);
        CHECK(snd(target.pair_value) == 100);
        CHECK(fst(target.record_value) == 150);
        CHECK(snd(target.record_value) == 200);
        CHECK(thd(target.record_value) == 250);
        CHECK(*target.option_some_value == 2);
        CHECK(is_none(target.option_none_value));
        CHECK(*target.either_right_value == 4);
        CHECK(~target.either_left_value == "msg");
        CHECK(get_third(target.choice_value) == 3);
    }

    TEST("properties work")
    {
        // TODO: implement
    }
}
<commit_msg>Added a little extra whitespace to try to throw off parser.<commit_after>#include <istream>

#include "../../hpp/tom/tom.hpp"

#include "../../hpp/ax/ax.hpp"

namespace ax
{
    // A trivial program type to demonstrate the eventable program mixin.
    class eventable_test : public eventable<eventable_test>
    {
    protected:
        enable_cast(eventable_test, eventable<eventable_test>);
    };

    class inspectable_test : public inspectable
    {
    protected:

        enable_cast(inspectable_test, inspectable);

        const std::shared_ptr<type_t> type = register_sub_type<inspectable_test>(typeid(inspectable),
        {
            { "bool_value",             register_field<bool>                        (offsetof(inspectable_test, bool_value)) },
            { "int_value",              register_field<int>                         (offsetof(inspectable_test, int_value)) },
            { "float_value",            register_field<float>                       (offsetof(inspectable_test, float_value)) },
            { "name_value",             register_field<name_t>                      (offsetof(inspectable_test, name_value)) },
            { "address_value",          register_field<address>                     (offsetof(inspectable_test, address_value)) },
            { "vector_int_value",       register_field<std::vector<int>>            (offsetof(inspectable_test, vector_int_value)) },
            { "vector_string_value",    register_field<std::vector<std::string>>    (offsetof(inspectable_test, vector_string_value)) },
            { "unique_int_value",       register_field<std::unique_ptr<int>>        (offsetof(inspectable_test, unique_int_value)) },
            { "shared_int_value",       register_field<std::shared_ptr<int>>        (offsetof(inspectable_test, shared_int_value)) },
            { "pair_value",             register_field<pair<int, int>>              (offsetof(inspectable_test, pair_value)) },
            { "record_value",           register_field<record<int, int, int>>       (offsetof(inspectable_test, record_value)) },
            { "option_some_value",      register_field<option<int>>                 (offsetof(inspectable_test, option_some_value)) },
            { "option_none_value",      register_field<option<int>>                 (offsetof(inspectable_test, option_none_value)) },
            { "either_right_value",     register_field<either<std::string, int>>    (offsetof(inspectable_test, either_right_value)) },
            { "either_left_value",      register_field<either<std::string, int>>    (offsetof(inspectable_test, either_left_value)) },
            { "choice_value",           register_field<choice<int, int, int>>       (offsetof(inspectable_test, choice_value)) }
        });

        std::shared_ptr<type_t> get_type_impl() const override
        {
            return type;
        };

    public:

        int bool_value;
        int int_value;
        float float_value;
        name_t name_value;
        address address_value;
        std::vector<int> vector_int_value;
        std::vector<std::string> vector_string_value;
        std::unique_ptr<int> unique_int_value;
        std::shared_ptr<int> shared_int_value;
        pair<int, int> pair_value;
        record<int, int, int> record_value;
        option<int> option_some_value;
        option<int> option_none_value;
        either<std::string, int> either_right_value;
        either<std::string, int> either_left_value;
        choice<int, int, int> choice_value;

        inspectable_test() :
            bool_value(),
            int_value(),
            float_value(),
            name_value(),
            address_value(),
            vector_int_value(),
            vector_string_value(),
            unique_int_value(std::make_unique<int>()),
            shared_int_value(std::make_shared<int>()),
            pair_value(),
            record_value(),
            option_some_value(),
            option_none_value(),
            either_right_value(),
            either_left_value(),
            choice_value()
        { }

        inspectable_test(
            bool bool_value,
            int int_value,
            float float_value,
            name_t name_value,
            address address_value,
            const std::vector<int>& vector_int_value,
            const std::vector<std::string>& vector_string_value,
            int unique_int_value,
            int shared_int_value,
            pair<int, int> pair_value,
            record<int, int, int> record_value,
            option<int> option_some_value,
            option<int> option_none_value,
            either<std::string, int> either_right_value,
            either<std::string, int> either_left_value,
            choice<int, int, int> choice_value) :
            bool_value(bool_value),
            int_value(int_value),
            float_value(float_value),
            name_value(name_value),
            address_value(address_value),
            vector_int_value(vector_int_value),
            vector_string_value(vector_string_value),
            unique_int_value(std::make_unique<int>(unique_int_value)),
            shared_int_value(std::make_shared<int>(shared_int_value)),
            pair_value(pair_value),
            record_value(record_value),
            option_some_value(option_some_value),
            option_none_value(option_none_value),
            either_right_value(either_right_value),
            either_left_value(either_left_value),
            choice_value(choice_value)
        { }
    };

    TEST("hash works")
    {
        CHECK(ax::get_hash(0) == std::hash<int>()(0));
    }

    TEST("castable works")
    {
        // TODO: implement
    }

    TEST("events work")
    {
        var i = 0;
        ax::eventable_test program{};
        val& event_address = address("event");
        val& participant = std::make_shared<ax::addressable>("participant");
        var handler = [&](val&, val&) { return ++i, true; };
        var unsubscriber = ax::subscribe_event<std::string>(program, event_address, participant, handler);
        ax::publish_event(program, "Event handled!"_s, event_address, participant);
        unsubscriber(program);
        ax::publish_event(program, "Event unhandled."_s, event_address, participant);
        CHECK(i == 1);
    }

    TEST("read and write value works")
    {
        symbol symbol{};
        inspectable_test source(
            true, 5, 10.0f, "jim bob", address("s/compton/la"),
            { 1, 3, 5 }, { "a", "bb", "ccc" }, 666, 777,
            make_pair(50, 100), make_record(150, 200, 250),
            some(2), none<int>(), right<std::string>(4), left<std::string, int>("msg"), third<int, int>(3));
        inspectable_test target{};
        write_value(source, symbol);
        read_value(symbol, target);
        CHECK(target.bool_value);
        CHECK(target.int_value == 5);
        CHECK(target.float_value == 10.0f);
        CHECK(target.name_value == "jim bob");
        CHECK(target.address_value == address("s/compton/la"));
        CHECK(target.vector_int_value == std::vector<int>({ 1, 3, 5 }));
        CHECK(target.vector_string_value == std::vector<std::string>({ "a", "bb", "ccc" }));
        CHECK(*target.unique_int_value == 666);
        CHECK(*target.shared_int_value == 777);
        CHECK(fst(target.pair_value) == 50);
        CHECK(snd(target.pair_value) == 100);
        CHECK(fst(target.record_value) == 150);
        CHECK(snd(target.record_value) == 200);
        CHECK(thd(target.record_value) == 250);
        CHECK(*target.option_some_value == 2);
        CHECK(is_none(target.option_none_value));
        CHECK(*target.either_right_value == 4);
        CHECK(~target.either_left_value == "msg");
        CHECK(get_third(target.choice_value) == 3);
    }

    TEST("parser works")
    {
        val& str =
            "[true 5 10.0 \
              \"jim bob\" \
              \"s/compton/la\" \
              [1 3 5] \
              [\"a\" \"bb\" \"ccc\"] \
              666 \
              777 \
              [50 100] \
              [150 200 250] \
              [some 2] \
              none \
              [right 4] \
              [left \"msg\"] \
              [  third  3  ]  ]"; // a little extra whitespace to try to throw off parser
        std::stringstream sstr(str);
        sstr << std::noskipws; // apparently avoids skipping whitespace
        std::istream_iterator<char> iter(sstr);
        val& parse = parse_symbol_from_stream(iter, std::istream_iterator<char>());
        val& symbol = get_parse_success(parse);
        inspectable_test target{};
        read_value(symbol, target);
        CHECK(target.bool_value);
        CHECK(target.int_value == 5);
        CHECK(target.float_value == 10.0f);
        CHECK(target.name_value == "jim bob");
        CHECK(target.address_value == address("s/compton/la"));
        CHECK(target.vector_int_value == std::vector<int>({ 1, 3, 5 }));
        CHECK(target.vector_string_value == std::vector<std::string>({ "a", "bb", "ccc" }));
        CHECK(*target.unique_int_value == 666);
        CHECK(*target.shared_int_value == 777);
        CHECK(fst(target.pair_value) == 50);
        CHECK(snd(target.pair_value) == 100);
        CHECK(fst(target.record_value) == 150);
        CHECK(snd(target.record_value) == 200);
        CHECK(thd(target.record_value) == 250);
        CHECK(*target.option_some_value == 2);
        CHECK(is_none(target.option_none_value));
        CHECK(*target.either_right_value == 4);
        CHECK(~target.either_left_value == "msg");
        CHECK(get_third(target.choice_value) == 3);
    }

    TEST("properties work")
    {
        // TODO: implement
    }
}
<|endoftext|>


<commit_before>#include "foo.hpp"

template <typename T>
T foo(T x) {
  return 2 * x;
}

<commit_msg>added header guard to template instantiation demo<commit_after>#ifndef _FOO_DEF_HPP
#define _FOO_DEF_HPP

#include "foo.hpp"

template <typename T>
T foo(T x) {
  return 2 * x;
}

#endif
<|endoftext|>


<commit_before>#include <stan/math/prim/scal/meta/ad_promotable.hpp>
#include <gtest/gtest.h>

TEST(MathMeta, primitive_to_double) {
  EXPECT_TRUE((stan::math::ad_promotable<bool, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<char, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<unsigned char, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<short, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<unsigned short, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<int, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<unsigned int, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<long, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<unsigned long, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<long long, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<unsigned long long, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<float, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<double, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<long double, double>::value));
}

TEST(MathMeta, primitive_to_float) {
  EXPECT_FALSE((stan::math::ad_promotable<bool, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<char, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<unsigned char, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<short, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<unsigned short, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<int, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<unsigned int, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<long, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<unsigned long, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<long long, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<unsigned long long, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<double, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<long double, float>::value));

  EXPECT_TRUE((stan::math::ad_promotable<float, float>::value))
    << "All primitive types should be promotable to the same type";
}
<commit_msg>[Jenkins] auto-formatting by clang-format version 5.0.0-3~16.04.1 (tags/RELEASE_500/final)<commit_after>#include <stan/math/prim/scal/meta/ad_promotable.hpp>
#include <gtest/gtest.h>

TEST(MathMeta, primitive_to_double) {
  EXPECT_TRUE((stan::math::ad_promotable<bool, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<char, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<unsigned char, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<short, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<unsigned short, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<int, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<unsigned int, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<long, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<unsigned long, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<long long, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<unsigned long long, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<float, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<double, double>::value));
  EXPECT_TRUE((stan::math::ad_promotable<long double, double>::value));
}

TEST(MathMeta, primitive_to_float) {
  EXPECT_FALSE((stan::math::ad_promotable<bool, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<char, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<unsigned char, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<short, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<unsigned short, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<int, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<unsigned int, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<long, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<unsigned long, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<long long, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<unsigned long long, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<double, float>::value));
  EXPECT_FALSE((stan::math::ad_promotable<long double, float>::value));

  EXPECT_TRUE((stan::math::ad_promotable<float, float>::value))
      << "All primitive types should be promotable to the same type";
}
<|endoftext|>


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

#include "distortos/devices/communication/SerialPort.hpp"

#include "distortos/internal/devices/UartLowLevel.hpp"

#include "distortos/architecture/InterruptMaskingLock.hpp"

#include "distortos/Semaphore.hpp"

#include "estd/ScopeGuard.hpp"

#include <cerrno>
#include <cstring>

namespace distortos
{

namespace devices
{

namespace
{

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

/**
 * \brief Reads data from ring buffer.
 *
 * \param [in] ringBuffer is a reference to ring buffer from which the data will be read
 * \param [out] buffer is a buffer to which the data will be written
 * \param [in] size is the size of \a buffer, bytes
 *
 * \return number of bytes read from \a ringBuffer and written to \a buffer
 */

size_t readFromRingBuffer(SerialPort::RingBuffer& ringBuffer, uint8_t* const buffer, const size_t size)
{
	decltype(ringBuffer.getReadBlock()) readBlock;
	size_t bytesRead {};
	while (readBlock = ringBuffer.getReadBlock(), readBlock.second != 0 && bytesRead != size)
	{
		const auto copySize = std::min(readBlock.second, size - bytesRead);
		memcpy(buffer + bytesRead, readBlock.first, copySize);
		ringBuffer.increaseReadPosition(copySize);
		bytesRead += copySize;
	}

	return bytesRead;
}

/**
 * \brief Writes data to ring buffer.
 *
 * \param [in] buffer is a buffer from which the data will be read
 * \param [in] size is the size of \a buffer, bytes
 * \param [in] ringBuffer is a reference to ring buffer to which the data will be written
 *
 * \return number of bytes read from \a buffer and written to \a ringBuffer
 */

size_t writeToRingBuffer(const uint8_t* const buffer, const size_t size, SerialPort::RingBuffer& ringBuffer)
{
	decltype(ringBuffer.getWriteBlock()) writeBlock;
	size_t bytesWritten {};
	while (writeBlock = ringBuffer.getWriteBlock(), writeBlock.second != 0 && bytesWritten != size)
	{
		const auto copySize = std::min(writeBlock.second, size - bytesWritten);
		memcpy(writeBlock.first, buffer + bytesWritten, copySize);
		ringBuffer.increaseWritePosition(copySize);
		bytesWritten += copySize;
	}

	return bytesWritten;
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| SerialPort::RingBuffer public functions
+---------------------------------------------------------------------------------------------------------------------*/

std::pair<const uint8_t*, size_t> SerialPort::RingBuffer::getReadBlock() const
{
	const auto readPosition = readPosition_;
	const auto writePosition = writePosition_;
	return {buffer_ + readPosition, (writePosition >= readPosition ? writePosition : size_) - readPosition};
}

std::pair<uint8_t*, size_t> SerialPort::RingBuffer::getWriteBlock() const
{
	const auto readPosition = readPosition_;
	const auto writePosition = writePosition_;
	const auto freeBytes = (readPosition > writePosition ? readPosition - writePosition :
			size_ - writePosition + readPosition) - 2;
	const auto writeBlockSize = (readPosition > writePosition ? readPosition : size_) - writePosition;
	return {buffer_ + writePosition, std::min(freeBytes, writeBlockSize)};
}

/*---------------------------------------------------------------------------------------------------------------------+
| public functions
+---------------------------------------------------------------------------------------------------------------------*/

SerialPort::~SerialPort()
{
	if (openCount_ == 0)
		return;

	readMutex_.lock();
	writeMutex_.lock();
	const auto readWriteMutexScopeGuard = estd::makeScopeGuard(
			[this]()
			{
				writeMutex_.unlock();
				readMutex_.unlock();
			});

	uart_.stopRead();
	uart_.stopWrite();
	uart_.stop();
}

int SerialPort::close()
{
	readMutex_.lock();
	writeMutex_.lock();
	const auto readWriteMutexScopeGuard = estd::makeScopeGuard(
			[this]()
			{
				writeMutex_.unlock();
				readMutex_.unlock();
			});

	if (openCount_ == 0)	// device is not open anymore?
		return EBADF;

	if (openCount_ == 1)	// last close?
	{
		while (transmitInProgress_ == true)	// wait for physical end of write operation
		{
			Semaphore semaphore {0};
			transmitSemaphore_ = &semaphore;
			const auto transmitSemaphoreScopeGuard = estd::makeScopeGuard(
					[this]()
					{
						transmitSemaphore_ = {};
					});

			if (transmitInProgress_ == true)
			{
				const auto ret = semaphore.wait();
				if (ret != 0)
					return ret;
			}
		}

		uart_.stopRead();

		const auto ret = uart_.stop();
		if (ret != 0)
			return ret;

		readBuffer_.clear();
		writeBuffer_.clear();
	}

	--openCount_;
	return 0;
}

int SerialPort::open(const uint32_t baudRate, const uint8_t characterLength, const devices::UartParity parity,
			const bool _2StopBits)
{
	readMutex_.lock();
	writeMutex_.lock();
	const auto readWriteMutexScopeGuard = estd::makeScopeGuard(
			[this]()
			{
				writeMutex_.unlock();
				readMutex_.unlock();
			});

	if (openCount_ == std::numeric_limits<decltype(openCount_)>::max())	// device is already opened too many times?
		return EMFILE;

	if (openCount_ == 0)	// first open?
	{
		if (readBuffer_.getSize() < 4 || writeBuffer_.getSize() < 4)
			return ENOBUFS;

		{
			const auto ret = uart_.start(*this, baudRate, characterLength, parity, _2StopBits);
			if (ret.first != 0)
				return ret.first;
		}
		{
			const auto ret = startReadWrapper(SIZE_MAX);
			if (ret != 0)
				return ret;
		}

		baudRate_ = baudRate;
		characterLength_ = characterLength;
		parity_ = parity;
		_2StopBits_ = _2StopBits;
	}
	else	// if (openCount_ != 0)
	{
		// provided arguments don't match current configuration of already opened device?
		if (baudRate_ != baudRate || characterLength_ != characterLength || parity_ != parity ||
				_2StopBits_ != _2StopBits)
			return EINVAL;
	}

	++openCount_;
	return 0;
}

std::pair<int, size_t> SerialPort::read(void* const buffer, const size_t size)
{
	if (buffer == nullptr || size == 0)
		return {EINVAL, {}};

	readMutex_.lock();
	const auto readMutexScopeGuard = estd::makeScopeGuard(
			[this]()
			{
				readMutex_.unlock();
			});

	if (openCount_ == 0)
		return {EBADF, {}};

	if (characterLength_ > 8 && size % 2 != 0)
		return {EINVAL, {}};

	const size_t minSize = characterLength_ <= 8 ? 1 : 2;
	const auto bufferUint8 = static_cast<uint8_t*>(buffer);
	size_t bytesRead {};
	while (bytesRead < minSize)
	{
		bytesRead += readFromRingBuffer(readBuffer_, bufferUint8 + bytesRead, size - bytesRead);
		if (bytesRead == size)	// buffer already full?
			return {{}, bytesRead};

		Semaphore semaphore {0};
		readSemaphore_ = &semaphore;
		const auto readSemaphoreScopeGuard = estd::makeScopeGuard(
				[this]()
				{
					readSemaphore_ = {};
				});

		{
			// stop and restart the read operation to get the characters that were already received;
			architecture::InterruptMaskingLock interruptMaskingLock;
			const auto bytesReceived = uart_.stopRead();
			readBuffer_.increaseWritePosition(bytesReceived);
			// limit of new read operation is selected to have a notification when requested minimum will be received
			const auto ret = startReadWrapper(minSize > bytesRead + bytesReceived ?
					minSize - bytesRead - bytesReceived : SIZE_MAX);
			if (ret != 0)
				return {ret, bytesRead};
		}

		bytesRead += readFromRingBuffer(readBuffer_, bufferUint8 + bytesRead, size - bytesRead);

		if (bytesRead < minSize)	// wait for data only if requested minimum is not already read
		{
			const auto ret = semaphore.wait();
			if (ret != 0)
				return {ret, bytesRead};
		}
	}

	return {{}, bytesRead};
}

std::pair<int, size_t> SerialPort::write(const void* const buffer, const size_t size)
{
	if (buffer == nullptr || size == 0)
		return {EINVAL, {}};

	writeMutex_.lock();
	const auto writeMutexScopeGuard = estd::makeScopeGuard(
			[this]()
			{
				writeMutex_.unlock();
			});

	if (openCount_ == 0)
		return {EBADF, {}};

	if (characterLength_ > 8 && size % 2 != 0)
		return {EINVAL, {}};

	const auto bufferUint8 = static_cast<const uint8_t*>(buffer);
	size_t bytesWritten {};
	while (bytesWritten < size)
	{
		Semaphore semaphore {0};
		writeSemaphore_ = &semaphore;
		const auto writeSemaphoreScopeGuard = estd::makeScopeGuard(
				[this]()
				{
					writeSemaphore_ = {};
				});

		bytesWritten += writeToRingBuffer(bufferUint8 + bytesWritten, size - bytesWritten, writeBuffer_);

		// restart write operation if it is not currently in progress and the write buffer is not already empty
		if (writeInProgress_ == false && writeBuffer_.isEmpty() == false)
		{
			const auto ret = startWriteWrapper();
			if (ret != 0)
				return {ret, bytesWritten};
		}
		// wait for free space only if write operation is in progress and there is still some data left to write
		else if (bytesWritten != size)
		{
			const auto ret = semaphore.wait();
			if (ret != 0)
				return {ret, bytesWritten};
		}
	}

	return {{}, bytesWritten};
}

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

void SerialPort::readCompleteEvent(const size_t bytesRead)
{
	readBuffer_.increaseWritePosition(bytesRead);

	if (readSemaphore_ != nullptr)
	{
		readSemaphore_->post();
		readSemaphore_ = {};
	}

	if (readBuffer_.isFull() == true)
		return;

	startReadWrapper(SIZE_MAX);
}

void SerialPort::receiveErrorEvent(ErrorSet)
{

}

int SerialPort::startReadWrapper(const size_t limit)
{
	const auto writeBlock = readBuffer_.getWriteBlock();
	return uart_.startRead(writeBlock.first, std::min({writeBlock.second, readBuffer_.getSize() / 2, limit}));
}

int SerialPort::startWriteWrapper()
{
	transmitInProgress_ = true;
	writeInProgress_ = true;
	const auto outBlock = writeBuffer_.getReadBlock();
	return uart_.startWrite(outBlock.first, outBlock.second);
}

void SerialPort::transmitCompleteEvent()
{
	if (transmitSemaphore_ != nullptr)
	{
		transmitSemaphore_->post();
		transmitSemaphore_ = {};
	}

	transmitInProgress_ = false;
}

void SerialPort::writeCompleteEvent(const size_t bytesWritten)
{
	writeBuffer_.increaseReadPosition(bytesWritten);

	if (writeSemaphore_ != nullptr)
	{
		writeSemaphore_->post();
		writeSemaphore_ = {};
	}

	if (writeBuffer_.isEmpty() == true)
	{
		writeInProgress_ = false;
		return;
	}

	startWriteWrapper();
}

}	// namespace devices

}	// namespace distortos
<commit_msg>Rename local variable in SerialPort::startWriteWrapper()<commit_after>/**
 * \file
 * \brief SerialPort class implementation
 *
 * \author Copyright (C) 2016 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "distortos/devices/communication/SerialPort.hpp"

#include "distortos/internal/devices/UartLowLevel.hpp"

#include "distortos/architecture/InterruptMaskingLock.hpp"

#include "distortos/Semaphore.hpp"

#include "estd/ScopeGuard.hpp"

#include <cerrno>
#include <cstring>

namespace distortos
{

namespace devices
{

namespace
{

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

/**
 * \brief Reads data from ring buffer.
 *
 * \param [in] ringBuffer is a reference to ring buffer from which the data will be read
 * \param [out] buffer is a buffer to which the data will be written
 * \param [in] size is the size of \a buffer, bytes
 *
 * \return number of bytes read from \a ringBuffer and written to \a buffer
 */

size_t readFromRingBuffer(SerialPort::RingBuffer& ringBuffer, uint8_t* const buffer, const size_t size)
{
	decltype(ringBuffer.getReadBlock()) readBlock;
	size_t bytesRead {};
	while (readBlock = ringBuffer.getReadBlock(), readBlock.second != 0 && bytesRead != size)
	{
		const auto copySize = std::min(readBlock.second, size - bytesRead);
		memcpy(buffer + bytesRead, readBlock.first, copySize);
		ringBuffer.increaseReadPosition(copySize);
		bytesRead += copySize;
	}

	return bytesRead;
}

/**
 * \brief Writes data to ring buffer.
 *
 * \param [in] buffer is a buffer from which the data will be read
 * \param [in] size is the size of \a buffer, bytes
 * \param [in] ringBuffer is a reference to ring buffer to which the data will be written
 *
 * \return number of bytes read from \a buffer and written to \a ringBuffer
 */

size_t writeToRingBuffer(const uint8_t* const buffer, const size_t size, SerialPort::RingBuffer& ringBuffer)
{
	decltype(ringBuffer.getWriteBlock()) writeBlock;
	size_t bytesWritten {};
	while (writeBlock = ringBuffer.getWriteBlock(), writeBlock.second != 0 && bytesWritten != size)
	{
		const auto copySize = std::min(writeBlock.second, size - bytesWritten);
		memcpy(writeBlock.first, buffer + bytesWritten, copySize);
		ringBuffer.increaseWritePosition(copySize);
		bytesWritten += copySize;
	}

	return bytesWritten;
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| SerialPort::RingBuffer public functions
+---------------------------------------------------------------------------------------------------------------------*/

std::pair<const uint8_t*, size_t> SerialPort::RingBuffer::getReadBlock() const
{
	const auto readPosition = readPosition_;
	const auto writePosition = writePosition_;
	return {buffer_ + readPosition, (writePosition >= readPosition ? writePosition : size_) - readPosition};
}

std::pair<uint8_t*, size_t> SerialPort::RingBuffer::getWriteBlock() const
{
	const auto readPosition = readPosition_;
	const auto writePosition = writePosition_;
	const auto freeBytes = (readPosition > writePosition ? readPosition - writePosition :
			size_ - writePosition + readPosition) - 2;
	const auto writeBlockSize = (readPosition > writePosition ? readPosition : size_) - writePosition;
	return {buffer_ + writePosition, std::min(freeBytes, writeBlockSize)};
}

/*---------------------------------------------------------------------------------------------------------------------+
| public functions
+---------------------------------------------------------------------------------------------------------------------*/

SerialPort::~SerialPort()
{
	if (openCount_ == 0)
		return;

	readMutex_.lock();
	writeMutex_.lock();
	const auto readWriteMutexScopeGuard = estd::makeScopeGuard(
			[this]()
			{
				writeMutex_.unlock();
				readMutex_.unlock();
			});

	uart_.stopRead();
	uart_.stopWrite();
	uart_.stop();
}

int SerialPort::close()
{
	readMutex_.lock();
	writeMutex_.lock();
	const auto readWriteMutexScopeGuard = estd::makeScopeGuard(
			[this]()
			{
				writeMutex_.unlock();
				readMutex_.unlock();
			});

	if (openCount_ == 0)	// device is not open anymore?
		return EBADF;

	if (openCount_ == 1)	// last close?
	{
		while (transmitInProgress_ == true)	// wait for physical end of write operation
		{
			Semaphore semaphore {0};
			transmitSemaphore_ = &semaphore;
			const auto transmitSemaphoreScopeGuard = estd::makeScopeGuard(
					[this]()
					{
						transmitSemaphore_ = {};
					});

			if (transmitInProgress_ == true)
			{
				const auto ret = semaphore.wait();
				if (ret != 0)
					return ret;
			}
		}

		uart_.stopRead();

		const auto ret = uart_.stop();
		if (ret != 0)
			return ret;

		readBuffer_.clear();
		writeBuffer_.clear();
	}

	--openCount_;
	return 0;
}

int SerialPort::open(const uint32_t baudRate, const uint8_t characterLength, const devices::UartParity parity,
			const bool _2StopBits)
{
	readMutex_.lock();
	writeMutex_.lock();
	const auto readWriteMutexScopeGuard = estd::makeScopeGuard(
			[this]()
			{
				writeMutex_.unlock();
				readMutex_.unlock();
			});

	if (openCount_ == std::numeric_limits<decltype(openCount_)>::max())	// device is already opened too many times?
		return EMFILE;

	if (openCount_ == 0)	// first open?
	{
		if (readBuffer_.getSize() < 4 || writeBuffer_.getSize() < 4)
			return ENOBUFS;

		{
			const auto ret = uart_.start(*this, baudRate, characterLength, parity, _2StopBits);
			if (ret.first != 0)
				return ret.first;
		}
		{
			const auto ret = startReadWrapper(SIZE_MAX);
			if (ret != 0)
				return ret;
		}

		baudRate_ = baudRate;
		characterLength_ = characterLength;
		parity_ = parity;
		_2StopBits_ = _2StopBits;
	}
	else	// if (openCount_ != 0)
	{
		// provided arguments don't match current configuration of already opened device?
		if (baudRate_ != baudRate || characterLength_ != characterLength || parity_ != parity ||
				_2StopBits_ != _2StopBits)
			return EINVAL;
	}

	++openCount_;
	return 0;
}

std::pair<int, size_t> SerialPort::read(void* const buffer, const size_t size)
{
	if (buffer == nullptr || size == 0)
		return {EINVAL, {}};

	readMutex_.lock();
	const auto readMutexScopeGuard = estd::makeScopeGuard(
			[this]()
			{
				readMutex_.unlock();
			});

	if (openCount_ == 0)
		return {EBADF, {}};

	if (characterLength_ > 8 && size % 2 != 0)
		return {EINVAL, {}};

	const size_t minSize = characterLength_ <= 8 ? 1 : 2;
	const auto bufferUint8 = static_cast<uint8_t*>(buffer);
	size_t bytesRead {};
	while (bytesRead < minSize)
	{
		bytesRead += readFromRingBuffer(readBuffer_, bufferUint8 + bytesRead, size - bytesRead);
		if (bytesRead == size)	// buffer already full?
			return {{}, bytesRead};

		Semaphore semaphore {0};
		readSemaphore_ = &semaphore;
		const auto readSemaphoreScopeGuard = estd::makeScopeGuard(
				[this]()
				{
					readSemaphore_ = {};
				});

		{
			// stop and restart the read operation to get the characters that were already received;
			architecture::InterruptMaskingLock interruptMaskingLock;
			const auto bytesReceived = uart_.stopRead();
			readBuffer_.increaseWritePosition(bytesReceived);
			// limit of new read operation is selected to have a notification when requested minimum will be received
			const auto ret = startReadWrapper(minSize > bytesRead + bytesReceived ?
					minSize - bytesRead - bytesReceived : SIZE_MAX);
			if (ret != 0)
				return {ret, bytesRead};
		}

		bytesRead += readFromRingBuffer(readBuffer_, bufferUint8 + bytesRead, size - bytesRead);

		if (bytesRead < minSize)	// wait for data only if requested minimum is not already read
		{
			const auto ret = semaphore.wait();
			if (ret != 0)
				return {ret, bytesRead};
		}
	}

	return {{}, bytesRead};
}

std::pair<int, size_t> SerialPort::write(const void* const buffer, const size_t size)
{
	if (buffer == nullptr || size == 0)
		return {EINVAL, {}};

	writeMutex_.lock();
	const auto writeMutexScopeGuard = estd::makeScopeGuard(
			[this]()
			{
				writeMutex_.unlock();
			});

	if (openCount_ == 0)
		return {EBADF, {}};

	if (characterLength_ > 8 && size % 2 != 0)
		return {EINVAL, {}};

	const auto bufferUint8 = static_cast<const uint8_t*>(buffer);
	size_t bytesWritten {};
	while (bytesWritten < size)
	{
		Semaphore semaphore {0};
		writeSemaphore_ = &semaphore;
		const auto writeSemaphoreScopeGuard = estd::makeScopeGuard(
				[this]()
				{
					writeSemaphore_ = {};
				});

		bytesWritten += writeToRingBuffer(bufferUint8 + bytesWritten, size - bytesWritten, writeBuffer_);

		// restart write operation if it is not currently in progress and the write buffer is not already empty
		if (writeInProgress_ == false && writeBuffer_.isEmpty() == false)
		{
			const auto ret = startWriteWrapper();
			if (ret != 0)
				return {ret, bytesWritten};
		}
		// wait for free space only if write operation is in progress and there is still some data left to write
		else if (bytesWritten != size)
		{
			const auto ret = semaphore.wait();
			if (ret != 0)
				return {ret, bytesWritten};
		}
	}

	return {{}, bytesWritten};
}

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

void SerialPort::readCompleteEvent(const size_t bytesRead)
{
	readBuffer_.increaseWritePosition(bytesRead);

	if (readSemaphore_ != nullptr)
	{
		readSemaphore_->post();
		readSemaphore_ = {};
	}

	if (readBuffer_.isFull() == true)
		return;

	startReadWrapper(SIZE_MAX);
}

void SerialPort::receiveErrorEvent(ErrorSet)
{

}

int SerialPort::startReadWrapper(const size_t limit)
{
	const auto writeBlock = readBuffer_.getWriteBlock();
	return uart_.startRead(writeBlock.first, std::min({writeBlock.second, readBuffer_.getSize() / 2, limit}));
}

int SerialPort::startWriteWrapper()
{
	transmitInProgress_ = true;
	writeInProgress_ = true;
	const auto readBlock = writeBuffer_.getReadBlock();
	return uart_.startWrite(readBlock.first, readBlock.second);
}

void SerialPort::transmitCompleteEvent()
{
	if (transmitSemaphore_ != nullptr)
	{
		transmitSemaphore_->post();
		transmitSemaphore_ = {};
	}

	transmitInProgress_ = false;
}

void SerialPort::writeCompleteEvent(const size_t bytesWritten)
{
	writeBuffer_.increaseReadPosition(bytesWritten);

	if (writeSemaphore_ != nullptr)
	{
		writeSemaphore_->post();
		writeSemaphore_ = {};
	}

	if (writeBuffer_.isEmpty() == true)
	{
		writeInProgress_ = false;
		return;
	}

	startWriteWrapper();
}

}	// namespace devices

}	// namespace distortos
<|endoftext|>


<commit_before>/* Copyright © 2001-2014, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

LICENCE: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

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 Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
IRC #navitia on freenode
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "messages_connector.h"
#include <pqxx/pqxx>
#include <boost/make_shared.hpp>
#include "utils/exception.h"
#include "utils/logger.h"
#include "type/data.h"
#include "type/pt_data.h"

namespace ed{ namespace connectors{

namespace pt = boost::posix_time;

std::map<std::string, boost::shared_ptr<navitia::type::Message>> load_messages(
        const RealtimeLoaderConfig& conf,
        const boost::posix_time::ptime& current_time){
    //pour le moment on vire les timezone et on considére que c'est de l'heure local
    std::string request = "SELECT id, uri, start_publication_date::timestamp, "
        "end_publication_date::timestamp, start_application_date::timestamp, "
        "end_application_date::timestamp, start_application_daily_hour::time, "
        "end_application_daily_hour::time, active_days, object_uri, "
        "object_type_id, language, body, title, message_status_id "
        "FROM realtime.message m "
        "JOIN realtime.localized_message l ON l.message_id = m.id "
        "where end_publication_date >= ($1::timestamp - $2::interval) "
        "order by id";
    //on tris par id pour les regrouper ensemble
    pqxx::result result;
    std::unique_ptr<pqxx::connection> conn;
    try{
        conn = std::unique_ptr<pqxx::connection>(new pqxx::connection(conf.connection_string));
        conn->prepare("messages", request);
        std::string st_current_time = boost::posix_time::to_iso_string(current_time);
        std::string st_shift_days =  std::to_string(conf.shift_days) + " days";
        pqxx::work work(*conn, "chargement des messages");
        result = work.prepared("messages")(st_current_time)(st_shift_days).exec();
    }catch(const pqxx::pqxx_exception &e){
        throw navitia::exception(e.base().what());

    }

    std::map<std::string, boost::shared_ptr<navitia::type::Message>> messages;
    boost::shared_ptr<navitia::type::Message> message;
    std::string current_uri = "";

    for(auto cursor = result.begin(); cursor != result.end(); ++cursor){
        if(cursor["uri"].as<std::string>() != current_uri){//on traite un nouveau message
            if(message){//si on a un message précédent, on le rajoute au map de résultat
                messages[message->uri] = message;
            }
            cursor["uri"].to(current_uri);
            //on construit le message
            message = boost::make_shared<navitia::type::Message>();
            message->uri = current_uri;
            cursor["object_uri"].to(message->object_uri);

            message->object_type = static_cast<navitia::type::Type_e>(
                    cursor["object_type_id"].as<int>());

            message->message_status = static_cast<navitia::type::MessageStatus>(
                    cursor["message_status_id"].as<int>());

            message->application_daily_start_hour = pt::duration_from_string(
                    cursor["start_application_daily_hour"].as<std::string>());

            message->application_daily_end_hour = pt::duration_from_string(
                    cursor["end_application_daily_hour"].as<std::string>());

            pt::ptime start = pt::time_from_string(
                    cursor["start_application_date"].as<std::string>());

            pt::ptime end = pt::time_from_string(
                    cursor["end_application_date"].as<std::string>());
            message->application_period = pt::time_period(start, end);

            start = pt::time_from_string(
                    cursor["start_publication_date"].as<std::string>());

            end = pt::time_from_string(
                    cursor["end_publication_date"].as<std::string>());
            message->publication_period = pt::time_period(start, end);

            message->active_days = std::bitset<8>(
                    cursor["active_days"].as<std::string>());
        }
        std::string language = cursor["language"].as<std::string>();
        cursor["body"].to(message->localized_messages[language].body);
        cursor["title"].to(message->localized_messages[language].title);
    }
    if(message){//on ajoute le dernier message traité
        messages[message->uri] = message;
    }

    return messages;
}

void apply_messages(navitia::type::Data& data){
    for(const auto message_pair : data.pt_data->message_holder.messages){
        if(message_pair.second->object_type ==  navitia::type::Type_e::StopArea){
            auto it = data.pt_data->stop_areas_map.find(message_pair.second->object_uri);
            if(it != data.pt_data->stop_areas_map.end()){
                it->second->messages.push_back(message_pair.second);
            }

        }

        if(message_pair.second->object_type ==  navitia::type::Type_e::StopPoint){
            auto it = data.pt_data->stop_points_map.find(message_pair.second->object_uri);
            if(it != data.pt_data->stop_points_map.end()){
                it->second->messages.push_back(message_pair.second);
            }
        }

        if(message_pair.second->object_type ==  navitia::type::Type_e::Route){
            auto it = data.pt_data->routes_map.find(message_pair.second->object_uri);
            if(it != data.pt_data->routes_map.end()){
                it->second->messages.push_back(message_pair.second);
            }
        }

        if(message_pair.second->object_type ==  navitia::type::Type_e::VehicleJourney){
            auto it = data.pt_data->vehicle_journeys_map.find(message_pair.second->object_uri);
            if(it != data.pt_data->vehicle_journeys_map.end()){
                it->second->messages.push_back(message_pair.second);
            }
        }

        if(message_pair.second->object_type ==  navitia::type::Type_e::Line){
            auto it = data.pt_data->lines_map.find(message_pair.second->object_uri);
            if(it != data.pt_data->lines_map.end()){
                it->second->messages.push_back(message_pair.second);
            }
        }

        if(message_pair.second->object_type ==  navitia::type::Type_e::Network){
            auto it = data.pt_data->networks_map.find(message_pair.second->object_uri);
            if(it != data.pt_data->networks_map.end()){
                it->second->messages.push_back(message_pair.second);
            }
        }
    }
}

std::vector<navitia::type::AtPerturbation> load_at_perturbations(
        const RealtimeLoaderConfig& conf,
        const boost::posix_time::ptime& current_time){
    //pour le moment on vire les timezone et on considére que c'est de l'heure local
    std::string request = "SELECT id, uri, start_application_date::timestamp, "
        "end_application_date::timestamp, start_application_daily_hour::time, "
        "end_application_daily_hour::time, active_days, object_uri, "
        "object_type_id "
        "FROM realtime.at_perturbation "
        "where end_application_date >= ($1::timestamp - $2::interval) ";
    pqxx::result result;
    std::unique_ptr<pqxx::connection> conn;
    try{
        conn = std::unique_ptr<pqxx::connection>(new pqxx::connection(conf.connection_string));
        conn->prepare("messages", request);
        std::string st_current_time = boost::posix_time::to_iso_string(current_time);
        std::string st_shift_days =  std::to_string(conf.shift_days) + " days";
        pqxx::work work(*conn, "chargement des perturbations at");
        result = work.prepared("messages")(st_current_time)(st_shift_days).exec();

    }catch(const pqxx::pqxx_exception &e){
        throw navitia::exception(e.base().what());

    }

    std::vector<navitia::type::AtPerturbation> perturbations;
    for(auto cursor = result.begin(); cursor != result.end(); ++cursor){
        navitia::type::AtPerturbation perturbation;
        cursor["uri"].to(perturbation.uri);
        //on construit le message
        cursor["object_uri"].to(perturbation.object_uri);

        perturbation.object_type = static_cast<navitia::type::Type_e>(
                cursor["object_type_id"].as<int>());

        perturbation.application_daily_start_hour = pt::duration_from_string(
                cursor["start_application_daily_hour"].as<std::string>());

        perturbation.application_daily_end_hour = pt::duration_from_string(
                cursor["end_application_daily_hour"].as<std::string>());

        pt::ptime start = pt::time_from_string(
                cursor["start_application_date"].as<std::string>());

        pt::ptime end = pt::time_from_string(
                cursor["end_application_date"].as<std::string>());
        perturbation.application_period = pt::time_period(start, end);

        perturbation.active_days = std::bitset<8>(
                cursor["active_days"].as<std::string>());

        perturbations.push_back(perturbation);
    }

    return perturbations;
}

}}//namespace
<commit_msg>ed: support pqxx v3 and v4<commit_after>/* Copyright © 2001-2014, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

LICENCE: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

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 Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
IRC #navitia on freenode
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "messages_connector.h"
#include <pqxx/pqxx>
#include <boost/make_shared.hpp>
#include "utils/exception.h"
#include "utils/logger.h"
#include "type/data.h"
#include "type/pt_data.h"

namespace ed{ namespace connectors{

namespace pt = boost::posix_time;

std::map<std::string, boost::shared_ptr<navitia::type::Message>> load_messages(
        const RealtimeLoaderConfig& conf,
        const boost::posix_time::ptime& current_time){
    //pour le moment on vire les timezone et on considére que c'est de l'heure local
    std::string request = "SELECT id, uri, start_publication_date::timestamp, "
        "end_publication_date::timestamp, start_application_date::timestamp, "
        "end_application_date::timestamp, start_application_daily_hour::time, "
        "end_application_daily_hour::time, active_days, object_uri, "
        "object_type_id, language, body, title, message_status_id "
        "FROM realtime.message m "
        "JOIN realtime.localized_message l ON l.message_id = m.id "
        "where end_publication_date >= ($1::timestamp - $2::interval) "
        "order by id";
    //on tris par id pour les regrouper ensemble
    pqxx::result result;
    std::unique_ptr<pqxx::connection> conn;
    try{
        conn = std::unique_ptr<pqxx::connection>(new pqxx::connection(conf.connection_string));

#if PQXX_VERSION_MAJOR < 4
        conn->prepare("messages", request)("timestamp")("INTERVAL", pqxx::prepare::treat_string);
#else
        conn->prepare("messages", request);
#endif

        std::string st_current_time = boost::posix_time::to_iso_string(current_time);
        std::string st_shift_days =  std::to_string(conf.shift_days) + " days";
        pqxx::work work(*conn, "chargement des messages");
        result = work.prepared("messages")(st_current_time)(st_shift_days).exec();
    }catch(const pqxx::pqxx_exception &e){
        throw navitia::exception(e.base().what());

    }

    std::map<std::string, boost::shared_ptr<navitia::type::Message>> messages;
    boost::shared_ptr<navitia::type::Message> message;
    std::string current_uri = "";

    for(auto cursor = result.begin(); cursor != result.end(); ++cursor){
        if(cursor["uri"].as<std::string>() != current_uri){//on traite un nouveau message
            if(message){//si on a un message précédent, on le rajoute au map de résultat
                messages[message->uri] = message;
            }
            cursor["uri"].to(current_uri);
            //on construit le message
            message = boost::make_shared<navitia::type::Message>();
            message->uri = current_uri;
            cursor["object_uri"].to(message->object_uri);

            message->object_type = static_cast<navitia::type::Type_e>(
                    cursor["object_type_id"].as<int>());

            message->message_status = static_cast<navitia::type::MessageStatus>(
                    cursor["message_status_id"].as<int>());

            message->application_daily_start_hour = pt::duration_from_string(
                    cursor["start_application_daily_hour"].as<std::string>());

            message->application_daily_end_hour = pt::duration_from_string(
                    cursor["end_application_daily_hour"].as<std::string>());

            pt::ptime start = pt::time_from_string(
                    cursor["start_application_date"].as<std::string>());

            pt::ptime end = pt::time_from_string(
                    cursor["end_application_date"].as<std::string>());
            message->application_period = pt::time_period(start, end);

            start = pt::time_from_string(
                    cursor["start_publication_date"].as<std::string>());

            end = pt::time_from_string(
                    cursor["end_publication_date"].as<std::string>());
            message->publication_period = pt::time_period(start, end);

            message->active_days = std::bitset<8>(
                    cursor["active_days"].as<std::string>());
        }
        std::string language = cursor["language"].as<std::string>();
        cursor["body"].to(message->localized_messages[language].body);
        cursor["title"].to(message->localized_messages[language].title);
    }
    if(message){//on ajoute le dernier message traité
        messages[message->uri] = message;
    }

    return messages;
}

void apply_messages(navitia::type::Data& data){
    for(const auto message_pair : data.pt_data->message_holder.messages){
        if(message_pair.second->object_type ==  navitia::type::Type_e::StopArea){
            auto it = data.pt_data->stop_areas_map.find(message_pair.second->object_uri);
            if(it != data.pt_data->stop_areas_map.end()){
                it->second->messages.push_back(message_pair.second);
            }

        }

        if(message_pair.second->object_type ==  navitia::type::Type_e::StopPoint){
            auto it = data.pt_data->stop_points_map.find(message_pair.second->object_uri);
            if(it != data.pt_data->stop_points_map.end()){
                it->second->messages.push_back(message_pair.second);
            }
        }

        if(message_pair.second->object_type ==  navitia::type::Type_e::Route){
            auto it = data.pt_data->routes_map.find(message_pair.second->object_uri);
            if(it != data.pt_data->routes_map.end()){
                it->second->messages.push_back(message_pair.second);
            }
        }

        if(message_pair.second->object_type ==  navitia::type::Type_e::VehicleJourney){
            auto it = data.pt_data->vehicle_journeys_map.find(message_pair.second->object_uri);
            if(it != data.pt_data->vehicle_journeys_map.end()){
                it->second->messages.push_back(message_pair.second);
            }
        }

        if(message_pair.second->object_type ==  navitia::type::Type_e::Line){
            auto it = data.pt_data->lines_map.find(message_pair.second->object_uri);
            if(it != data.pt_data->lines_map.end()){
                it->second->messages.push_back(message_pair.second);
            }
        }

        if(message_pair.second->object_type ==  navitia::type::Type_e::Network){
            auto it = data.pt_data->networks_map.find(message_pair.second->object_uri);
            if(it != data.pt_data->networks_map.end()){
                it->second->messages.push_back(message_pair.second);
            }
        }
    }
}

std::vector<navitia::type::AtPerturbation> load_at_perturbations(
        const RealtimeLoaderConfig& conf,
        const boost::posix_time::ptime& current_time){
    //pour le moment on vire les timezone et on considére que c'est de l'heure local
    std::string request = "SELECT id, uri, start_application_date::timestamp, "
        "end_application_date::timestamp, start_application_daily_hour::time, "
        "end_application_daily_hour::time, active_days, object_uri, "
        "object_type_id "
        "FROM realtime.at_perturbation "
        "where end_application_date >= ($1::timestamp - $2::interval) ";
    pqxx::result result;
    std::unique_ptr<pqxx::connection> conn;
    try{
        conn = std::unique_ptr<pqxx::connection>(new pqxx::connection(conf.connection_string));

#if PQXX_VERSION_MAJOR < 4
        conn->prepare("messages", request)("timestamp")("INTERVAL", pqxx::prepare::treat_string);
#else
        conn->prepare("messages", request);
#endif

        std::string st_current_time = boost::posix_time::to_iso_string(current_time);
        std::string st_shift_days =  std::to_string(conf.shift_days) + " days";
        pqxx::work work(*conn, "chargement des perturbations at");
        result = work.prepared("messages")(st_current_time)(st_shift_days).exec();

    }catch(const pqxx::pqxx_exception &e){
        throw navitia::exception(e.base().what());

    }

    std::vector<navitia::type::AtPerturbation> perturbations;
    for(auto cursor = result.begin(); cursor != result.end(); ++cursor){
        navitia::type::AtPerturbation perturbation;
        cursor["uri"].to(perturbation.uri);
        //on construit le message
        cursor["object_uri"].to(perturbation.object_uri);

        perturbation.object_type = static_cast<navitia::type::Type_e>(
                cursor["object_type_id"].as<int>());

        perturbation.application_daily_start_hour = pt::duration_from_string(
                cursor["start_application_daily_hour"].as<std::string>());

        perturbation.application_daily_end_hour = pt::duration_from_string(
                cursor["end_application_daily_hour"].as<std::string>());

        pt::ptime start = pt::time_from_string(
                cursor["start_application_date"].as<std::string>());

        pt::ptime end = pt::time_from_string(
                cursor["end_application_date"].as<std::string>());
        perturbation.application_period = pt::time_period(start, end);

        perturbation.active_days = std::bitset<8>(
                cursor["active_days"].as<std::string>());

        perturbations.push_back(perturbation);
    }

    return perturbations;
}

}}//namespace
<|endoftext|>