<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnordmetric/sstable/binaryformat.h>
#include <fnordmetric/sstable/fileheaderwriter.h>
#include <fnordmetric/sstable/fileheaderreader.h>
#include <fnordmetric/sstable/sstablewriter.h>
#include <fnordmetric/util/fnv.h>
#include <fnordmetric/util/runtimeexception.h>
#include <string.h>

namespace fnord {
namespace sstable {

std::unique_ptr<SSTableWriter> SSTableWriter::create(
    const std::string& filename,
    IndexProvider index_provider,
    void const* header,
    size_t header_size) {
  auto file = io::File::openFile(filename, io::File::O_READ);
  auto file_size = file.size();
  if (file_size > 0) {
    RAISE(kIllegalStateError, "file size must be 0");
  }

  auto sstable = new SSTableWriter(
      filename,
      file_size,
      index_provider.popIndexes());

  sstable->writeHeader(header, header_size);
  return std::unique_ptr<SSTableWriter>(sstable);
}

std::unique_ptr<SSTableWriter> SSTableWriter::reopen(
    const std::string& filename,
    IndexProvider index_provider) {
  auto file = io::File::openFile(filename, io::File::O_READ);
  auto file_size = file.size();

  auto sstable = new SSTableWriter(
      filename,
      file_size,
      index_provider.popIndexes());

  sstable->reopen(file_size);
  return std::unique_ptr<SSTableWriter>(sstable);
}

SSTableWriter::SSTableWriter(
    const std::string& filename,
    size_t file_size,
    std::vector<Index::IndexRef>&& indexes) :
    indexes_(std::move(indexes)),
    mmap_(new io::MmapPageManager(filename, file_size)),
    header_size_(0),
    body_size_(0),
    finalized_(false) {}

SSTableWriter::~SSTableWriter() {
}

// FIXPAUL lock
void SSTableWriter::appendRow(
    void const* key,
    size_t key_size,
    void const* data,
    size_t data_size) {
  if (finalized_) {
    RAISE(kIllegalStateError, "table is immutable (alread finalized)");
  }
  // FIXPAUL assert that key is monotonically increasing...

  size_t page_size = sizeof(BinaryFormat::RowHeader) + key_size + data_size;
  auto alloc = mmap_->allocPage(page_size);
  auto page = mmap_->getPage(alloc);

  auto header = page->structAt<BinaryFormat::RowHeader>(0);
  header->key_size = key_size;
  header->data_size = data_size;

  auto key_dst = page->structAt<void>(sizeof(BinaryFormat::RowHeader));
  memcpy(key_dst, key, key_size);

  auto data_dst = page->structAt<void>(
      sizeof(BinaryFormat::RowHeader) + key_size);
  memcpy(data_dst, data, data_size);

  util::FNV<uint32_t> fnv;
  header->checksum = fnv.hash(
      page->structAt<void>(sizeof(uint32_t)),
      page_size - sizeof(uint32_t));

  page->sync();

  auto row_body_offset = body_size_;
  body_size_ += page_size;

  for (const auto& idx : indexes_) {
    idx->addRow(row_body_offset, key, key_size, data, data_size);
  }
}

void SSTableWriter::appendRow(
    const std::string& key,
    const std::string& value) {
  appendRow(key.data(), key.size(), value.data(), value.size());
}

// FIXPAUL lock
void SSTableWriter::writeHeader(void const* userdata, size_t userdata_size) {
  if (header_size_ > 0) {
    RAISE(kIllegalStateError, "header already written");
  }

  header_size_ = FileHeaderWriter::calculateSize(userdata_size);
  auto alloc = mmap_->allocPage(header_size_);
  auto page = mmap_->getPage(alloc);

  if (alloc.offset != 0) {
    RAISE(kIllegalStateError, "header page offset must be 0");
  }

  FileHeaderWriter header(
      page->ptr(),
      page->size(),
      0,
      userdata,
      userdata_size);

  page->sync();
}

void SSTableWriter::writeIndex(uint32_t index_type, void* data, size_t size) {
  if (finalized_) {
    RAISE(kIllegalStateError, "table is immutable (alread finalized)");
  }

  auto alloc = mmap_->allocPage(sizeof(BinaryFormat::FooterHeader) + size);
  auto page = mmap_->getPage(alloc, io::MmapPageManager::kNoPadding{});

  auto header = page->structAt<BinaryFormat::FooterHeader>(0);
  header->magic = BinaryFormat::kMagicBytes;
  header->type = index_type;
  header->footer_size = size;

  util::FNV<uint32_t> fnv;
  header->footer_checksum = fnv.hash(data, size);

  if (size > 0) {
    auto dst = page->structAt<void>(sizeof(BinaryFormat::FooterHeader));
    memcpy(dst, data, size);
  }

  page->sync();
  mmap_->shrinkFile();
}

void SSTableWriter::reopen(size_t file_size) {
  auto page = mmap_->getPage(io::PageManager::Page(0, file_size));

  FileHeaderReader header(page->ptr(), page->size());

  if (!header.verify()) {
    RAISE(kIllegalStateError, "corrupt sstable header");
  }

  if (header.bodySize() != 0) {
    RAISE(kIllegalStateError, "finalized sstable can't be re-opened");
  }

  if (header.headerSize() + header.bodySize() > file_size) {
    RAISE(kIllegalStateError, "file metadata offsets exceed file bounds");
  }

  header_size_ = header.headerSize();
  body_size_ = file_size - header_size_;
}

// FIXPAUL lock
void SSTableWriter::finalize() {
  finalized_ = true;

  auto page = mmap_->getPage(
      io::PageManager::Page(0, FileHeaderWriter::calculateSize(0)));

  FileHeaderWriter header(page->ptr(), page->size());
  header.updateBodySize(body_size_);

  page->sync();
  mmap_->shrinkFile();
}

// FIXPAUL lock
std::unique_ptr<Cursor> SSTableWriter::getCursor() {
  return std::unique_ptr<Cursor>(
      new SSTableWriter::Cursor(this, mmap_.get()));
}

// FIXPAUL lock
size_t SSTableWriter::bodySize() const {
  return body_size_;
}

size_t SSTableWriter::headerSize() const {
  return header_size_;
}

SSTableWriter::Cursor::Cursor(
    SSTableWriter* table,
    io::MmapPageManager* mmap) :
    table_(table),
    mmap_(mmap),
    pos_(0) {}

void SSTableWriter::Cursor::seekTo(size_t body_offset) {
  if (body_offset >= table_->bodySize()) {
    RAISE(kIndexError, "seekTo() out of bounds position");
  }

  pos_ = body_offset;
}

bool SSTableWriter::Cursor::next() {
  auto page = getPage();
  auto header = page->structAt<BinaryFormat::RowHeader>(0);

  size_t page_size = page->page_.size;
  size_t row_size = sizeof(BinaryFormat::RowHeader) + header->key_size +
      header->data_size;

  if (row_size > page_size) {
    RAISE(kIllegalStateError, "row exceeds page boundary");
  }

  if (row_size == page_size) {
    return false;
  } else {
    pos_ += row_size;
    return true;
  }
}

bool SSTableWriter::Cursor::valid() {
  return pos_ < table_->bodySize();
}

void SSTableWriter::Cursor::getKey(void** data, size_t* size) {
  auto page = getPage();
  size_t page_size = page->page_.size;

  auto header = page->structAt<BinaryFormat::RowHeader>(0);
  if (header->key_size == 0) {
    RAISE(kIllegalStateError, "empty key");
  }

  if (sizeof(BinaryFormat::RowHeader) + header->key_size > page_size) {
    RAISE(kIllegalStateError, "key exceeds page boundary");
  }

  *data = page->structAt<void>(sizeof(BinaryFormat::RowHeader));
  *size = header->key_size;
}

size_t SSTableWriter::Cursor::position() const {
  return pos_;
}

void SSTableWriter::Cursor::getData(void** data, size_t* size) {
  auto page = getPage();
  auto header = page->structAt<BinaryFormat::RowHeader>(0);

  size_t page_size = page->page_.size;
  size_t row_size = sizeof(BinaryFormat::RowHeader) + header->key_size +
      header->data_size;
  if (row_size > page_size) {
    RAISE(kIllegalStateError, "row exceeds page boundary");
  }

  *data = page->structAt<void>(
      sizeof(BinaryFormat::RowHeader) + header->key_size);
  *size = header->data_size;
}

std::unique_ptr<io::PageManager::PageRef> SSTableWriter::Cursor::getPage() {
  return mmap_->getPage(io::PageManager::Page(
      table_->headerSize() + pos_,
      table_->bodySize() - pos_));
}

}
}
<commit_msg>fix SSTableWriter#writeIndex<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnordmetric/sstable/binaryformat.h>
#include <fnordmetric/sstable/fileheaderwriter.h>
#include <fnordmetric/sstable/fileheaderreader.h>
#include <fnordmetric/sstable/sstablewriter.h>
#include <fnordmetric/util/fnv.h>
#include <fnordmetric/util/runtimeexception.h>
#include <string.h>

namespace fnord {
namespace sstable {

std::unique_ptr<SSTableWriter> SSTableWriter::create(
    const std::string& filename,
    IndexProvider index_provider,
    void const* header,
    size_t header_size) {
  auto file = io::File::openFile(filename, io::File::O_READ);
  auto file_size = file.size();
  if (file_size > 0) {
    RAISE(kIllegalStateError, "file size must be 0");
  }

  auto sstable = new SSTableWriter(
      filename,
      file_size,
      index_provider.popIndexes());

  sstable->writeHeader(header, header_size);
  return std::unique_ptr<SSTableWriter>(sstable);
}

std::unique_ptr<SSTableWriter> SSTableWriter::reopen(
    const std::string& filename,
    IndexProvider index_provider) {
  auto file = io::File::openFile(filename, io::File::O_READ);
  auto file_size = file.size();

  auto sstable = new SSTableWriter(
      filename,
      file_size,
      index_provider.popIndexes());

  sstable->reopen(file_size);
  return std::unique_ptr<SSTableWriter>(sstable);
}

SSTableWriter::SSTableWriter(
    const std::string& filename,
    size_t file_size,
    std::vector<Index::IndexRef>&& indexes) :
    indexes_(std::move(indexes)),
    mmap_(new io::MmapPageManager(filename, file_size)),
    header_size_(0),
    body_size_(0),
    finalized_(false) {}

SSTableWriter::~SSTableWriter() {
}

// FIXPAUL lock
void SSTableWriter::appendRow(
    void const* key,
    size_t key_size,
    void const* data,
    size_t data_size) {
  if (finalized_) {
    RAISE(kIllegalStateError, "table is immutable (alread finalized)");
  }
  // FIXPAUL assert that key is monotonically increasing...

  size_t page_size = sizeof(BinaryFormat::RowHeader) + key_size + data_size;
  auto alloc = mmap_->allocPage(page_size);
  auto page = mmap_->getPage(alloc);

  auto header = page->structAt<BinaryFormat::RowHeader>(0);
  header->key_size = key_size;
  header->data_size = data_size;

  auto key_dst = page->structAt<void>(sizeof(BinaryFormat::RowHeader));
  memcpy(key_dst, key, key_size);

  auto data_dst = page->structAt<void>(
      sizeof(BinaryFormat::RowHeader) + key_size);
  memcpy(data_dst, data, data_size);

  util::FNV<uint32_t> fnv;
  header->checksum = fnv.hash(
      page->structAt<void>(sizeof(uint32_t)),
      page_size - sizeof(uint32_t));

  page->sync();

  auto row_body_offset = body_size_;
  body_size_ += page_size;

  for (const auto& idx : indexes_) {
    idx->addRow(row_body_offset, key, key_size, data, data_size);
  }
}

void SSTableWriter::appendRow(
    const std::string& key,
    const std::string& value) {
  appendRow(key.data(), key.size(), value.data(), value.size());
}

// FIXPAUL lock
void SSTableWriter::writeHeader(void const* userdata, size_t userdata_size) {
  if (header_size_ > 0) {
    RAISE(kIllegalStateError, "header already written");
  }

  header_size_ = FileHeaderWriter::calculateSize(userdata_size);
  auto alloc = mmap_->allocPage(header_size_);
  auto page = mmap_->getPage(alloc);

  if (alloc.offset != 0) {
    RAISE(kIllegalStateError, "header page offset must be 0");
  }

  FileHeaderWriter header(
      page->ptr(),
      page->size(),
      0,
      userdata,
      userdata_size);

  page->sync();
}

void SSTableWriter::writeIndex(uint32_t index_type, void* data, size_t size) {
  if (finalized_) {
    RAISE(kIllegalStateError, "table is immutable (alread finalized)");
  }

  if (size == 0) {
    return;
  }

  auto alloc = mmap_->allocPage(sizeof(BinaryFormat::FooterHeader) + size);
  auto page = mmap_->getPage(alloc, io::MmapPageManager::kNoPadding{});

  auto header = page->structAt<BinaryFormat::FooterHeader>(0);
  header->magic = BinaryFormat::kMagicBytes;
  header->type = index_type;
  header->footer_size = size;

  util::FNV<uint32_t> fnv;
  header->footer_checksum = fnv.hash(data, size);

  if (size > 0) {
    auto dst = page->structAt<void>(sizeof(BinaryFormat::FooterHeader));
    memcpy(dst, data, size);
  }

  page->sync();
  mmap_->shrinkFile();
}

void SSTableWriter::reopen(size_t file_size) {
  auto page = mmap_->getPage(io::PageManager::Page(0, file_size));

  FileHeaderReader header(page->ptr(), page->size());

  if (!header.verify()) {
    RAISE(kIllegalStateError, "corrupt sstable header");
  }

  if (header.bodySize() != 0) {
    RAISE(kIllegalStateError, "finalized sstable can't be re-opened");
  }

  if (header.headerSize() + header.bodySize() > file_size) {
    RAISE(kIllegalStateError, "file metadata offsets exceed file bounds");
  }

  header_size_ = header.headerSize();
  body_size_ = file_size - header_size_;
}

// FIXPAUL lock
void SSTableWriter::finalize() {
  finalized_ = true;

  auto page = mmap_->getPage(
      io::PageManager::Page(0, FileHeaderWriter::calculateSize(0)));

  FileHeaderWriter header(page->ptr(), page->size());
  header.updateBodySize(body_size_);

  page->sync();
  mmap_->shrinkFile();
}

// FIXPAUL lock
std::unique_ptr<Cursor> SSTableWriter::getCursor() {
  return std::unique_ptr<Cursor>(
      new SSTableWriter::Cursor(this, mmap_.get()));
}

// FIXPAUL lock
size_t SSTableWriter::bodySize() const {
  return body_size_;
}

size_t SSTableWriter::headerSize() const {
  return header_size_;
}

SSTableWriter::Cursor::Cursor(
    SSTableWriter* table,
    io::MmapPageManager* mmap) :
    table_(table),
    mmap_(mmap),
    pos_(0) {}

void SSTableWriter::Cursor::seekTo(size_t body_offset) {
  if (body_offset >= table_->bodySize()) {
    RAISE(kIndexError, "seekTo() out of bounds position");
  }

  pos_ = body_offset;
}

bool SSTableWriter::Cursor::next() {
  auto page = getPage();
  auto header = page->structAt<BinaryFormat::RowHeader>(0);

  size_t page_size = page->page_.size;
  size_t row_size = sizeof(BinaryFormat::RowHeader) + header->key_size +
      header->data_size;

  if (row_size > page_size) {
    RAISE(kIllegalStateError, "row exceeds page boundary");
  }

  if (row_size == page_size) {
    return false;
  } else {
    pos_ += row_size;
    return true;
  }
}

bool SSTableWriter::Cursor::valid() {
  return pos_ < table_->bodySize();
}

void SSTableWriter::Cursor::getKey(void** data, size_t* size) {
  auto page = getPage();
  size_t page_size = page->page_.size;

  auto header = page->structAt<BinaryFormat::RowHeader>(0);
  if (header->key_size == 0) {
    RAISE(kIllegalStateError, "empty key");
  }

  if (sizeof(BinaryFormat::RowHeader) + header->key_size > page_size) {
    RAISE(kIllegalStateError, "key exceeds page boundary");
  }

  *data = page->structAt<void>(sizeof(BinaryFormat::RowHeader));
  *size = header->key_size;
}

size_t SSTableWriter::Cursor::position() const {
  return pos_;
}

void SSTableWriter::Cursor::getData(void** data, size_t* size) {
  auto page = getPage();
  auto header = page->structAt<BinaryFormat::RowHeader>(0);

  size_t page_size = page->page_.size;
  size_t row_size = sizeof(BinaryFormat::RowHeader) + header->key_size +
      header->data_size;
  if (row_size > page_size) {
    RAISE(kIllegalStateError, "row exceeds page boundary");
  }

  *data = page->structAt<void>(
      sizeof(BinaryFormat::RowHeader) + header->key_size);
  *size = header->data_size;
}

std::unique_ptr<io::PageManager::PageRef> SSTableWriter::Cursor::getPage() {
  return mmap_->getPage(io::PageManager::Page(
      table_->headerSize() + pos_,
      table_->bodySize() - pos_));
}

}
}
<|endoftext|>


<commit_before>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#include "../../core/Setup.h"

#if OUZEL_COMPILE_OPENSL

#include <array>
#include <system_error>
#include "OSLAudioDevice.hpp"
#include "OSLErrorCategory.hpp"
#include "../../core/Engine.hpp"
#include "../../utils/Log.hpp"

namespace ouzel::audio::opensl
{
    namespace
    {
        const ErrorCategory errorCategory{};

        std::error_code makeErrorCode(SLresult e)
        {
            return std::error_code(static_cast<int>(e), errorCategory);
        }

        void playerCallback(SLAndroidSimpleBufferQueueItf bufferQueue, void* context)
        {
            try
            {
                auto audioDevice = static_cast<AudioDevice*>(context);

                audioDevice->enqueue(bufferQueue);
            }
            catch (const std::exception& e)
            {
                logger.log(Log::Level::error) << e.what();
            }
        }

        constexpr SLuint32 getChannelMask(std::uint32_t channels)
        {
            switch (channels)
            {
                case 1: return SL_SPEAKER_FRONT_CENTER;
                case 2: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
                case 4: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT;
                case 6: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
                case 7: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_CENTER | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
                case 8: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
                default:
                    throw std::runtime_error("Invalid channel count");
            }
        }
    }

    AudioDevice::AudioDevice(const Settings& settings,
                             const std::function<void(std::uint32_t frames,
                                                      std::uint32_t channels,
                                                      std::uint32_t sampleRate,
                                                      std::vector<float>& samples)>& initDataGetter):
        audio::AudioDevice(Driver::openSL, settings, initDataGetter)
    {
        const std::array engineInterfaces = { SL_IID_ENGINE, SL_IID_ENGINECAPABILITIES };
        constexpr std::array engineRequirements = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE };

        SLObjectItf engineObjectPointer;
        if (const auto result = slCreateEngine(&engineObjectPointer, 0, nullptr,
                                               static_cast<SLuint32>(engineInterfaces.size()),
                                               engineInterfaces.data(),
                                               engineRequirements.data()); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL engine object");

        engineObject = engineObjectPointer;

        if (const auto result = engineObject->Realize(engineObject.get(), SL_BOOLEAN_FALSE); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL engine object");

        SLEngineCapabilitiesItf engineCapabilities;
        if (const auto result = engineObject->GetInterface(engineObject.get(), SL_IID_ENGINECAPABILITIES, &engineCapabilities); result == SL_RESULT_SUCCESS)
        {
            SLint16 major;
            SLint16 minor;
            SLint16 step;
            if (const auto result = (*engineCapabilities)->QueryAPIVersion(engineCapabilities, &major, &minor, &step); result != SL_RESULT_SUCCESS)
                throw std::system_error(makeErrorCode(result), "Failed to get OpenSL version");

            apiMajorVersion = static_cast<std::uint16_t>(major);
            apiMinorVersion = static_cast<std::uint16_t>(minor);
        }
        else
        {
            apiMajorVersion = 1;
            apiMinorVersion = 0;
        }

        if (const auto result = engineObject->GetInterface(engineObject.get(), SL_IID_ENGINE, &engine); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL engine");

        SLObjectItf outputMixObjectPointer;
        if (const auto result = (*engine)->CreateOutputMix(engine, &outputMixObjectPointer, 0, nullptr, nullptr); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL output mix");

        outputMixObject = outputMixObjectPointer;

        if (const auto result = outputMixObject->Realize(outputMixObject.get(), SL_BOOLEAN_FALSE); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL output mix");

        SLDataLocator_AndroidSimpleBufferQueue location = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};

        SLDataFormat_PCM dataFormat;
        dataFormat.formatType = SL_DATAFORMAT_PCM;
        // TODO: get speaker count
        dataFormat.numChannels = channels;
        dataFormat.samplesPerSec = sampleRate * 1000; // mHz
        dataFormat.bitsPerSample = sizeof(std::int16_t) * 8;
        dataFormat.containerSize = dataFormat.bitsPerSample;
        dataFormat.channelMask = getChannelMask(channels);
        dataFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;

        SLDataSource dataSource{&location, &dataFormat};
        SLDataLocator_OutputMix dataLocatorOut{SL_DATALOCATOR_OUTPUTMIX, outputMixObject.get()};
        SLDataSink dataSink{&dataLocatorOut, nullptr};
        constexpr SLuint32 playerIIDCount = 3;
        const SLInterfaceID playerIIDs[] = {SL_IID_BUFFERQUEUE, SL_IID_PLAY, SL_IID_VOLUME};
        constexpr SLboolean playerReqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};

        SLObjectItf playerObjectPointer;
        if (const auto result = (*engine)->CreateAudioPlayer(engine, &playerObjectPointer, &dataSource, &dataSink, playerIIDCount, playerIIDs, playerReqs); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL player object");

        playerObject = playerObjectPointer;

        sampleFormat = SampleFormat::signedInt16;

        if (const auto result = playerObject->Realize(playerObject.get(), SL_BOOLEAN_FALSE); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL player object");

        if (const auto result = playerObject->GetInterface(playerObject.get(), SL_IID_PLAY, &player); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL player interface");

        if (const auto result = playerObject->GetInterface(playerObject.get(), SL_IID_BUFFERQUEUE, &bufferQueue); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL buffer queue interface");

        if (const auto result = playerObject->GetInterface(playerObject.get(), SL_IID_VOLUME, &playerVolume); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL volume interface");

        if (const auto result = (*bufferQueue)->Clear(bufferQueue); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to clear OpenSL buffer");

        if (const auto result = (*bufferQueue)->RegisterCallback(bufferQueue, playerCallback, this); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to register OpenSL buffer queue callback");
    }

    void AudioDevice::start()
    {
        getData(bufferSize / (channels * sizeof(std::int16_t)), data);

        if (const auto result = (*bufferQueue)->Enqueue(bufferQueue, data.data(), data.size()); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to enqueue OpenSL data");

        if (const auto result = (*player)->SetPlayState(player, SL_PLAYSTATE_PLAYING); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to play sound");
    }

    void AudioDevice::stop()
    {
        if (const auto result = (*player)->SetPlayState(player, SL_PLAYSTATE_STOPPED); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to stop sound");
    }

    void AudioDevice::enqueue(SLAndroidSimpleBufferQueueItf bufferQueue)
    {
        getData(bufferSize / (channels * sizeof(std::int16_t)), data);

        if (const auto result = (*bufferQueue)->Enqueue(bufferQueue, data.data(), data.size()); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to enqueue OpenSL data");
    }
}
#endif
<commit_msg>Add comment why the version is set to 1.0<commit_after>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#include "../../core/Setup.h"

#if OUZEL_COMPILE_OPENSL

#include <array>
#include <system_error>
#include "OSLAudioDevice.hpp"
#include "OSLErrorCategory.hpp"
#include "../../core/Engine.hpp"
#include "../../utils/Log.hpp"

namespace ouzel::audio::opensl
{
    namespace
    {
        const ErrorCategory errorCategory{};

        std::error_code makeErrorCode(SLresult e)
        {
            return std::error_code(static_cast<int>(e), errorCategory);
        }

        void playerCallback(SLAndroidSimpleBufferQueueItf bufferQueue, void* context)
        {
            try
            {
                auto audioDevice = static_cast<AudioDevice*>(context);

                audioDevice->enqueue(bufferQueue);
            }
            catch (const std::exception& e)
            {
                logger.log(Log::Level::error) << e.what();
            }
        }

        constexpr SLuint32 getChannelMask(std::uint32_t channels)
        {
            switch (channels)
            {
                case 1: return SL_SPEAKER_FRONT_CENTER;
                case 2: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
                case 4: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT;
                case 6: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
                case 7: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_CENTER | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
                case 8: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
                default:
                    throw std::runtime_error("Invalid channel count");
            }
        }
    }

    AudioDevice::AudioDevice(const Settings& settings,
                             const std::function<void(std::uint32_t frames,
                                                      std::uint32_t channels,
                                                      std::uint32_t sampleRate,
                                                      std::vector<float>& samples)>& initDataGetter):
        audio::AudioDevice(Driver::openSL, settings, initDataGetter)
    {
        const std::array engineInterfaces = { SL_IID_ENGINE, SL_IID_ENGINECAPABILITIES };
        constexpr std::array engineRequirements = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE };

        SLObjectItf engineObjectPointer;
        if (const auto result = slCreateEngine(&engineObjectPointer, 0, nullptr,
                                               static_cast<SLuint32>(engineInterfaces.size()),
                                               engineInterfaces.data(),
                                               engineRequirements.data()); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL engine object");

        engineObject = engineObjectPointer;

        if (const auto result = engineObject->Realize(engineObject.get(), SL_BOOLEAN_FALSE); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL engine object");

        SLEngineCapabilitiesItf engineCapabilities;
        if (const auto result = engineObject->GetInterface(engineObject.get(), SL_IID_ENGINECAPABILITIES, &engineCapabilities); result == SL_RESULT_SUCCESS)
        {
            SLint16 major;
            SLint16 minor;
            SLint16 step;
            if (const auto result = (*engineCapabilities)->QueryAPIVersion(engineCapabilities, &major, &minor, &step); result != SL_RESULT_SUCCESS)
                throw std::system_error(makeErrorCode(result), "Failed to get OpenSL version");

            apiMajorVersion = static_cast<std::uint16_t>(major);
            apiMinorVersion = static_cast<std::uint16_t>(minor);
        }
        else
        {
            // engine capabilities interface is not supported in OpenSL ES 1.0
            apiMajorVersion = 1;
            apiMinorVersion = 0;
        }

        if (const auto result = engineObject->GetInterface(engineObject.get(), SL_IID_ENGINE, &engine); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL engine");

        SLObjectItf outputMixObjectPointer;
        if (const auto result = (*engine)->CreateOutputMix(engine, &outputMixObjectPointer, 0, nullptr, nullptr); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL output mix");

        outputMixObject = outputMixObjectPointer;

        if (const auto result = outputMixObject->Realize(outputMixObject.get(), SL_BOOLEAN_FALSE); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL output mix");

        SLDataLocator_AndroidSimpleBufferQueue location = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};

        SLDataFormat_PCM dataFormat;
        dataFormat.formatType = SL_DATAFORMAT_PCM;
        // TODO: get speaker count
        dataFormat.numChannels = channels;
        dataFormat.samplesPerSec = sampleRate * 1000; // mHz
        dataFormat.bitsPerSample = sizeof(std::int16_t) * 8;
        dataFormat.containerSize = dataFormat.bitsPerSample;
        dataFormat.channelMask = getChannelMask(channels);
        dataFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;

        SLDataSource dataSource{&location, &dataFormat};
        SLDataLocator_OutputMix dataLocatorOut{SL_DATALOCATOR_OUTPUTMIX, outputMixObject.get()};
        SLDataSink dataSink{&dataLocatorOut, nullptr};
        constexpr SLuint32 playerIIDCount = 3;
        const SLInterfaceID playerIIDs[] = {SL_IID_BUFFERQUEUE, SL_IID_PLAY, SL_IID_VOLUME};
        constexpr SLboolean playerReqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};

        SLObjectItf playerObjectPointer;
        if (const auto result = (*engine)->CreateAudioPlayer(engine, &playerObjectPointer, &dataSource, &dataSink, playerIIDCount, playerIIDs, playerReqs); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL player object");

        playerObject = playerObjectPointer;

        sampleFormat = SampleFormat::signedInt16;

        if (const auto result = playerObject->Realize(playerObject.get(), SL_BOOLEAN_FALSE); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL player object");

        if (const auto result = playerObject->GetInterface(playerObject.get(), SL_IID_PLAY, &player); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL player interface");

        if (const auto result = playerObject->GetInterface(playerObject.get(), SL_IID_BUFFERQUEUE, &bufferQueue); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL buffer queue interface");

        if (const auto result = playerObject->GetInterface(playerObject.get(), SL_IID_VOLUME, &playerVolume); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL volume interface");

        if (const auto result = (*bufferQueue)->Clear(bufferQueue); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to clear OpenSL buffer");

        if (const auto result = (*bufferQueue)->RegisterCallback(bufferQueue, playerCallback, this); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to register OpenSL buffer queue callback");
    }

    void AudioDevice::start()
    {
        getData(bufferSize / (channels * sizeof(std::int16_t)), data);

        if (const auto result = (*bufferQueue)->Enqueue(bufferQueue, data.data(), data.size()); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to enqueue OpenSL data");

        if (const auto result = (*player)->SetPlayState(player, SL_PLAYSTATE_PLAYING); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to play sound");
    }

    void AudioDevice::stop()
    {
        if (const auto result = (*player)->SetPlayState(player, SL_PLAYSTATE_STOPPED); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to stop sound");
    }

    void AudioDevice::enqueue(SLAndroidSimpleBufferQueueItf bufferQueue)
    {
        getData(bufferSize / (channels * sizeof(std::int16_t)), data);

        if (const auto result = (*bufferQueue)->Enqueue(bufferQueue, data.data(), data.size()); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to enqueue OpenSL data");
    }
}
#endif
<|endoftext|>


<commit_before>/*	____________________________________________________________________________

	                 Scanner Component for the Micro A Compiler

	                                mscan.h

	                              Version 2007 - 2016

	                           James L. Richards
	                     Last Update: August 28, 2007
	                      	   Nelson A Castillo
	                     Last Update: January 31, 2016

	The routines in this unit are based on those provided in the book
	"Crafting A Compiler" by Charles N. Fischer and Richard J. LeBlanc, Jr.,
	Benjamin Cummings Publishing Co. (1991).

	See Section 2.2, pp. 25-29.
	____________________________________________________________________________
*/

#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;

extern ifstream sourceFile;
extern ofstream outFile, listFile;

#include "mscan.h"

// *******************
// **  Constructor  **
// *******************

Scanner::Scanner()
{
	tokenBuffer = "";
	lineBuffer = "";
	lineNumber = 0;
	cheese_size = 1; /* Null char */
}

// ********************************
// **  Private Member Functions  **
// ********************************

void Scanner::BufferChar(char c)
{
	if (tokenBuffer.length() < ID_STRING_LEN){
		tokenBuffer += c;
	} else {
		cout << endl << " *** Fatal error: token is bigger then "
			<< "the TokenBuffer." << endl;
		cout << " *** Error at line " << this->lineNumber << endl;
		cout << " *** Please consider spliting cheese variables "
			<< "or recompiling the MaccNCheese compiler "
			<< "with a bigger TokenBuffer." << endl;
		exit(1);
	}
}

Token Scanner::CheckReserved()
{
	/*
	 * FIXME this converts variables to lowercase too.
	 * It was not supposed to do so.
	 */
	/* Convert the string to lower case */
	transform(tokenBuffer.begin(), tokenBuffer.end(), \
				tokenBuffer.begin(), ::tolower);
	/* Check the converted words */
	if ((tokenBuffer) == "bool") return BOOL_SYM;
	if ((tokenBuffer) == "break") return BREAK_SYM;
	if ((tokenBuffer) == "case") return CASE_SYM;
	if ((tokenBuffer) == "cheese") return CHEESE_SYM;
	if ((tokenBuffer) == "decs") return DECS_SYM;
	if ((tokenBuffer) == "do") return DO_SYM;
	if ((tokenBuffer) == "else") return ELSE_SYM;
	if ((tokenBuffer) == "end") return END_SYM;
	if ((tokenBuffer) == "false") return FALSE_SYM;
	if ((tokenBuffer) == "float") return FLOAT_SYM;
	if ((tokenBuffer) == "for") return FOR_SYM;
	if ((tokenBuffer) == "hiphip") return HIPHIP_SYM;
	if ((tokenBuffer) == "if") return IF_SYM;
	if ((tokenBuffer) == "int") return INT_SYM;
	if ((tokenBuffer) == "listen") return LISTEN_SYM;
	if ((tokenBuffer) == "otherwise") return OTHERWISE_SYM;
	if ((tokenBuffer) == "until") return UNTIL_SYM;
	if ((tokenBuffer) == "select") return SELECT_SYM;
	if ((tokenBuffer) == "shout") return SHOUT_SYM;
	if ((tokenBuffer) == "then") return THEN_SYM;
	if ((tokenBuffer) == "true") return TRUE_SYM;
	if ((tokenBuffer) == "while") return WHILE_SYM;

	return ID;
}

void Scanner::ClearBuffer()
{
	tokenBuffer = "";
}

void Scanner::LexicalError(char& c)
{
	cout << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << endl;
	listFile << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << endl;

	c = NextChar();
}
void Scanner::LexicalError(char& c, const string& errorExp)
{
	cout << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << '\n'
		<< errorExp << endl;
	listFile << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << '\n'
		<< errorExp << endl;

	c = NextChar();
}

char Scanner::NextChar()
{
	char c;

	sourceFile.get(c);
	if (c == '\n')
	{
		listFile.width(6);
		listFile << ++lineNumber << "  " << lineBuffer << endl;
		lineBuffer = "";
	} else{
		lineBuffer += c;
	}
	return c;
}

// *******************************
// **  Public Member Functions  **
// *******************************

Token Scanner::GetNextToken()
{
	char currentChar, c;

	ClearBuffer();
	currentChar = NextChar();
	while (!sourceFile.eof())
	{
		if (isspace(currentChar)) {
			/* do nothing */
			currentChar = NextChar();
		} else if (isalpha(currentChar)) {
			/* identifier */
			BufferChar(currentChar);
			c = sourceFile.peek();
			while (isalnum(c) || c == '_') {
				currentChar = NextChar();
				BufferChar(currentChar);
				c = sourceFile.peek();
			}
			return CheckReserved();
		} else if (isdigit(currentChar)) {
			/* integer or float literals */
			BufferChar(currentChar);
			c = sourceFile.peek();
			while (isdigit(c)) {
				currentChar = NextChar();
				BufferChar(currentChar);
				c = sourceFile.peek();
			}
			/* check if it is a float */
			if (c == '.') {
				currentChar = NextChar();
				c = sourceFile.peek();
				/* check for a digit after the '.' */
				if (!isdigit(c))
					LexicalError(currentChar, to_string(c) \
						+ " Float needs a digit" \
						" after the '.'");
				BufferChar(currentChar);
				while (isdigit(c)) {
					currentChar = NextChar();
					BufferChar(currentChar);
					c = sourceFile.peek();
				}
				/* check for power of 10 multipliers */
				if (c == 'e' || c == 'E') {
					currentChar = NextChar();
					c = sourceFile.peek();
					if (c != '+' && c!= '-') {
						LexicalError(currentChar, \
							to_string(c) + \
							" Float needs a "
							"'+'/'-' after 'E'");
					}
					BufferChar(currentChar);
					currentChar = NextChar();
					c = sourceFile.peek();
					if (!isdigit(c))
						LexicalError(currentChar, \
							to_string(c) + \
							" Float needs a " \
							"digit after '+'/'-'");
					BufferChar(currentChar);
					while (isdigit(c)) {
						currentChar = NextChar();
						BufferChar(currentChar);
						c = sourceFile.peek();
					}
				}
				return FLOAT_LIT;
			}
			return INT_LIT;
		} else if (currentChar == '"') {
			/* string literal */
			BufferChar(currentChar);
			c = sourceFile.peek();
			cheese_size = 1; /* Null Char */
			/* while not end of string */
			while (c != '"') {
				/* escape sequences */
				if (c == '\\') {
					/*
					 * Replace the '\' for a ':'
					 * which's SAM's escape char
					 */
					currentChar = NextChar();
					c = sourceFile.peek();
					currentChar = ':';
					if (c == '\\') {
						/* '\\' sequence */
						/* Just remove one '\' */
						currentChar = NextChar();
						BufferChar(currentChar);
						c = sourceFile.peek();
						cheese_size += 1;
					} else if (c == '"') {
						/* '\"' sequence */
						/* replace '\' for ':' */
						BufferChar(currentChar);
						currentChar = NextChar();
						BufferChar(currentChar);
						c = sourceFile.peek();
						cheese_size += 1;
					} else if (c == 'n') {
						/* \n sequence */
						/* replace for ascii '\n'(012)*/
						BufferChar(currentChar);
						currentChar = NextChar();
						currentChar = '0';
						BufferChar(currentChar);
						currentChar = '1';
						BufferChar(currentChar);
						currentChar = '2';
						BufferChar(currentChar);
						c = sourceFile.peek();
						cheese_size += 1;
					} else if (isdigit(c)) {
						/* '\ddd' sequence */
						/* replace '\' for ':' */
						BufferChar(currentChar);

						int ind;
						for (ind = 0; ind < 3; ind++) {
							/* check for 3 digits */
							if (!isdigit(c))
								LexicalError(c, to_string(c) + " received. Expected three digits after \\.");
							currentChar = NextChar();
							BufferChar(currentChar);
							c = sourceFile.peek();
						}
						cheese_size += 1;
					} else {
						LexicalError(currentChar, to_string(currentChar) + \
						" was followed by the wrong character -options are \\ or \".");
					}
				} else if (c == ':') {
					/*
					 * ':' is the escape char used
					 * by the SAM assembler. So it
					 * needs to be escaped.
					 */
					currentChar = NextChar();
					BufferChar(currentChar);
					BufferChar(currentChar);
					c = sourceFile.peek();
					cheese_size += 1;
				} else {
					/* regular characters */
					currentChar = NextChar();
					BufferChar(currentChar);
					c = sourceFile.peek();
					cheese_size += 1;
				}
			}
			/* buffer the final '"' */
			currentChar = NextChar();
			BufferChar(currentChar);
			return CHEESE_LIT;
		} else if (currentChar == '(') {
			BufferChar(currentChar);
			return LBANANA;
		} else if (currentChar == ')') {
			BufferChar(currentChar);
			return RBANANA;
		} else if (currentChar == '[') {
			BufferChar(currentChar);
			return LSTAPLE;
		} else if (currentChar == ']') {
			BufferChar(currentChar);
			return RSTAPLE;
		} else if (currentChar == '{') {
			BufferChar(currentChar);
			return LMUSTACHE;
		} else if (currentChar == '}') {
			BufferChar(currentChar);
			return RMUSTACHE;
		} else if (currentChar == ';') {
			BufferChar(currentChar);
			return SEMICOLON;
		} else if (currentChar == ':') {
			BufferChar(currentChar);
			return COLON;
		} else if (currentChar == ',') {
			BufferChar(currentChar);
			return COMMA;
		} else if (currentChar == '+') {
			BufferChar(currentChar);
			return PLUS_OP;
		} else if (currentChar == '*') {
			BufferChar(currentChar);
			return MULT_OP;
		} else if (currentChar == '/') {
			/* check if it is a multiline comment */
			c = sourceFile.peek();
			if (c == ':') {
				do { /* skip comment */
					currentChar = NextChar();
					if (currentChar == ':') {
						currentChar = NextChar();
						if (currentChar == '/') {
							currentChar = NextChar();
							break;
						}
					}
				} while (!sourceFile.eof());
			} else if (c == '/') {
				/* single line commment */
				do { /* skip comment */
					currentChar = NextChar();
				} while (currentChar != '\n');
			} else {
				/* if it is a division operator */
				BufferChar(currentChar);
				return DIV_OP;
			}
		} else if (currentChar == '=') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return EQ_OP1;
			}
			currentChar = NextChar();
			return ASSIGN_OP;
		} else if (currentChar == '!') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '!') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return EQ_OP2;
			} else if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return NE_OP;
			} else {
				LexicalError(currentChar, to_string(c) + \
						" The not operator is not" \
						" supported by MnC");
			}
			currentChar = NextChar();
		} else if (currentChar == '<') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return LE_OP;
			}
			currentChar = NextChar();
			return LT_OP;
		} else if (currentChar == '>') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return GE_OP;
			}
			currentChar = NextChar();
			return GT_OP;
		} else if (currentChar == '-') {
			/* minus operator */
			BufferChar(currentChar);
			currentChar = NextChar();
			return MINUS_OP;
		} else {
			/* Unrecognized character */
			LexicalError(currentChar, to_string(c) + \
					" Unrecognized character");
		}
	} /* end while */

	return EOF_SYM;
}
<commit_msg>Fix a comment.<commit_after>/*	____________________________________________________________________________

	                 Scanner Component for the Micro A Compiler

	                                mscan.h

	                              Version 2007 - 2016

	                           James L. Richards
	                     Last Update: August 28, 2007
	                      	   Nelson A Castillo
	                     Last Update: January 31, 2016

	The routines in this unit are based on those provided in the book
	"Crafting A Compiler" by Charles N. Fischer and Richard J. LeBlanc, Jr.,
	Benjamin Cummings Publishing Co. (1991).

	See Section 2.2, pp. 25-29.
	____________________________________________________________________________
*/

#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;

extern ifstream sourceFile;
extern ofstream outFile, listFile;

#include "mscan.h"

// *******************
// **  Constructor  **
// *******************

Scanner::Scanner()
{
	tokenBuffer = "";
	lineBuffer = "";
	lineNumber = 0;
	cheese_size = 1; /* Null char */
}

// ********************************
// **  Private Member Functions  **
// ********************************

void Scanner::BufferChar(char c)
{
	if (tokenBuffer.length() < ID_STRING_LEN){
		tokenBuffer += c;
	} else {
		cout << endl << " *** Fatal error: token is bigger then "
			<< "the TokenBuffer." << endl;
		cout << " *** Error at line " << this->lineNumber << endl;
		cout << " *** Please consider spliting cheese variables "
			<< "or recompiling the MaccNCheese compiler "
			<< "with a bigger TokenBuffer." << endl;
		exit(1);
	}
}

Token Scanner::CheckReserved()
{
	/*
	 * FIXME this converts variables to lowercase too.
	 * Was it supposed to do so?
	 */
	/* Convert the string to lower case */
	transform(tokenBuffer.begin(), tokenBuffer.end(), \
				tokenBuffer.begin(), ::tolower);
	/* Check the converted words */
	if ((tokenBuffer) == "bool") return BOOL_SYM;
	if ((tokenBuffer) == "break") return BREAK_SYM;
	if ((tokenBuffer) == "case") return CASE_SYM;
	if ((tokenBuffer) == "cheese") return CHEESE_SYM;
	if ((tokenBuffer) == "decs") return DECS_SYM;
	if ((tokenBuffer) == "do") return DO_SYM;
	if ((tokenBuffer) == "else") return ELSE_SYM;
	if ((tokenBuffer) == "end") return END_SYM;
	if ((tokenBuffer) == "false") return FALSE_SYM;
	if ((tokenBuffer) == "float") return FLOAT_SYM;
	if ((tokenBuffer) == "for") return FOR_SYM;
	if ((tokenBuffer) == "hiphip") return HIPHIP_SYM;
	if ((tokenBuffer) == "if") return IF_SYM;
	if ((tokenBuffer) == "int") return INT_SYM;
	if ((tokenBuffer) == "listen") return LISTEN_SYM;
	if ((tokenBuffer) == "otherwise") return OTHERWISE_SYM;
	if ((tokenBuffer) == "until") return UNTIL_SYM;
	if ((tokenBuffer) == "select") return SELECT_SYM;
	if ((tokenBuffer) == "shout") return SHOUT_SYM;
	if ((tokenBuffer) == "then") return THEN_SYM;
	if ((tokenBuffer) == "true") return TRUE_SYM;
	if ((tokenBuffer) == "while") return WHILE_SYM;

	return ID;
}

void Scanner::ClearBuffer()
{
	tokenBuffer = "";
}

void Scanner::LexicalError(char& c)
{
	cout << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << endl;
	listFile << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << endl;

	c = NextChar();
}
void Scanner::LexicalError(char& c, const string& errorExp)
{
	cout << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << '\n'
		<< errorExp << endl;
	listFile << " *** Lexical Error: '" << c
		<< "' ignored at position " << int(lineBuffer.size())
		<< " on line #" << lineNumber + 1 << '.' << '\n'
		<< errorExp << endl;

	c = NextChar();
}

char Scanner::NextChar()
{
	char c;

	sourceFile.get(c);
	if (c == '\n')
	{
		listFile.width(6);
		listFile << ++lineNumber << "  " << lineBuffer << endl;
		lineBuffer = "";
	} else{
		lineBuffer += c;
	}
	return c;
}

// *******************************
// **  Public Member Functions  **
// *******************************

Token Scanner::GetNextToken()
{
	char currentChar, c;

	ClearBuffer();
	currentChar = NextChar();
	while (!sourceFile.eof())
	{
		if (isspace(currentChar)) {
			/* do nothing */
			currentChar = NextChar();
		} else if (isalpha(currentChar)) {
			/* identifier */
			BufferChar(currentChar);
			c = sourceFile.peek();
			while (isalnum(c) || c == '_') {
				currentChar = NextChar();
				BufferChar(currentChar);
				c = sourceFile.peek();
			}
			return CheckReserved();
		} else if (isdigit(currentChar)) {
			/* integer or float literals */
			BufferChar(currentChar);
			c = sourceFile.peek();
			while (isdigit(c)) {
				currentChar = NextChar();
				BufferChar(currentChar);
				c = sourceFile.peek();
			}
			/* check if it is a float */
			if (c == '.') {
				currentChar = NextChar();
				c = sourceFile.peek();
				/* check for a digit after the '.' */
				if (!isdigit(c))
					LexicalError(currentChar, to_string(c) \
						+ " Float needs a digit" \
						" after the '.'");
				BufferChar(currentChar);
				while (isdigit(c)) {
					currentChar = NextChar();
					BufferChar(currentChar);
					c = sourceFile.peek();
				}
				/* check for power of 10 multipliers */
				if (c == 'e' || c == 'E') {
					currentChar = NextChar();
					c = sourceFile.peek();
					if (c != '+' && c!= '-') {
						LexicalError(currentChar, \
							to_string(c) + \
							" Float needs a "
							"'+'/'-' after 'E'");
					}
					BufferChar(currentChar);
					currentChar = NextChar();
					c = sourceFile.peek();
					if (!isdigit(c))
						LexicalError(currentChar, \
							to_string(c) + \
							" Float needs a " \
							"digit after '+'/'-'");
					BufferChar(currentChar);
					while (isdigit(c)) {
						currentChar = NextChar();
						BufferChar(currentChar);
						c = sourceFile.peek();
					}
				}
				return FLOAT_LIT;
			}
			return INT_LIT;
		} else if (currentChar == '"') {
			/* string literal */
			BufferChar(currentChar);
			c = sourceFile.peek();
			cheese_size = 1; /* Null Char */
			/* while not end of string */
			while (c != '"') {
				/* escape sequences */
				if (c == '\\') {
					/*
					 * Replace the '\' for a ':'
					 * which's SAM's escape char
					 */
					currentChar = NextChar();
					c = sourceFile.peek();
					currentChar = ':';
					if (c == '\\') {
						/* '\\' sequence */
						/* Just remove one '\' */
						currentChar = NextChar();
						BufferChar(currentChar);
						c = sourceFile.peek();
						cheese_size += 1;
					} else if (c == '"') {
						/* '\"' sequence */
						/* replace '\' for ':' */
						BufferChar(currentChar);
						currentChar = NextChar();
						BufferChar(currentChar);
						c = sourceFile.peek();
						cheese_size += 1;
					} else if (c == 'n') {
						/* \n sequence */
						/* replace for ascii '\n'(012)*/
						BufferChar(currentChar);
						currentChar = NextChar();
						currentChar = '0';
						BufferChar(currentChar);
						currentChar = '1';
						BufferChar(currentChar);
						currentChar = '2';
						BufferChar(currentChar);
						c = sourceFile.peek();
						cheese_size += 1;
					} else if (isdigit(c)) {
						/* '\ddd' sequence */
						/* replace '\' for ':' */
						BufferChar(currentChar);

						int ind;
						for (ind = 0; ind < 3; ind++) {
							/* check for 3 digits */
							if (!isdigit(c))
								LexicalError(c, to_string(c) + " received. Expected three digits after \\.");
							currentChar = NextChar();
							BufferChar(currentChar);
							c = sourceFile.peek();
						}
						cheese_size += 1;
					} else {
						LexicalError(currentChar, to_string(currentChar) + \
						" was followed by the wrong character -options are \\ or \".");
					}
				} else if (c == ':') {
					/*
					 * ':' is the escape char used
					 * by the SAM assembler. So it
					 * needs to be escaped.
					 */
					currentChar = NextChar();
					BufferChar(currentChar);
					BufferChar(currentChar);
					c = sourceFile.peek();
					cheese_size += 1;
				} else {
					/* regular characters */
					currentChar = NextChar();
					BufferChar(currentChar);
					c = sourceFile.peek();
					cheese_size += 1;
				}
			}
			/* buffer the final '"' */
			currentChar = NextChar();
			BufferChar(currentChar);
			return CHEESE_LIT;
		} else if (currentChar == '(') {
			BufferChar(currentChar);
			return LBANANA;
		} else if (currentChar == ')') {
			BufferChar(currentChar);
			return RBANANA;
		} else if (currentChar == '[') {
			BufferChar(currentChar);
			return LSTAPLE;
		} else if (currentChar == ']') {
			BufferChar(currentChar);
			return RSTAPLE;
		} else if (currentChar == '{') {
			BufferChar(currentChar);
			return LMUSTACHE;
		} else if (currentChar == '}') {
			BufferChar(currentChar);
			return RMUSTACHE;
		} else if (currentChar == ';') {
			BufferChar(currentChar);
			return SEMICOLON;
		} else if (currentChar == ':') {
			BufferChar(currentChar);
			return COLON;
		} else if (currentChar == ',') {
			BufferChar(currentChar);
			return COMMA;
		} else if (currentChar == '+') {
			BufferChar(currentChar);
			return PLUS_OP;
		} else if (currentChar == '*') {
			BufferChar(currentChar);
			return MULT_OP;
		} else if (currentChar == '/') {
			/* check if it is a multiline comment */
			c = sourceFile.peek();
			if (c == ':') {
				do { /* skip comment */
					currentChar = NextChar();
					if (currentChar == ':') {
						currentChar = NextChar();
						if (currentChar == '/') {
							currentChar = NextChar();
							break;
						}
					}
				} while (!sourceFile.eof());
			} else if (c == '/') {
				/* single line commment */
				do { /* skip comment */
					currentChar = NextChar();
				} while (currentChar != '\n');
			} else {
				/* if it is a division operator */
				BufferChar(currentChar);
				return DIV_OP;
			}
		} else if (currentChar == '=') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return EQ_OP1;
			}
			currentChar = NextChar();
			return ASSIGN_OP;
		} else if (currentChar == '!') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '!') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return EQ_OP2;
			} else if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return NE_OP;
			} else {
				LexicalError(currentChar, to_string(c) + \
						" The not operator is not" \
						" supported by MnC");
			}
			currentChar = NextChar();
		} else if (currentChar == '<') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return LE_OP;
			}
			currentChar = NextChar();
			return LT_OP;
		} else if (currentChar == '>') {
			BufferChar(currentChar);
			if (sourceFile.peek() == '=') {
				currentChar = NextChar();
				BufferChar(currentChar);
				return GE_OP;
			}
			currentChar = NextChar();
			return GT_OP;
		} else if (currentChar == '-') {
			/* minus operator */
			BufferChar(currentChar);
			currentChar = NextChar();
			return MINUS_OP;
		} else {
			/* Unrecognized character */
			LexicalError(currentChar, to_string(c) + \
					" Unrecognized character");
		}
	} /* end while */

	return EOF_SYM;
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <limits>

#include "base/all.h"

using namespace base;
using namespace std;

static void print_binary(const void* vbuf, int len) {
    char* buf = (char *) vbuf;
    for (int i = 0; i < len; i++) {
        for (int j = 0; j < 8; j++) {
            uint8_t u = buf[i];
            printf("%d", (u >> (7 - j)) & 0x1);
        }
        printf(" ");
    }
    printf("\n");
}

TEST(sparseint, dump_load_i32) {
    char buf[9];
    const i32 values[] = {0, 1, -1, -64, 63, 64, -65, -8192, 8191, -8193, 8192, -1048576, 1048575,
                    1048576, -1048577, -134217728, 134217727,
                    134217728, -134217729,
                    numeric_limits<i32>::max(), numeric_limits<i32>::min()};
    const i32 bs[] = {1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
                    4, 4, 4, 4,
                    5, 5, 5, 5};
    for (int i = 0; i < arraysize(values); i++) {
        const i32 v = values[i];
        memset(buf, 0, 9);
        int bsize = SparseInt::dump(v, buf);
        //print_binary(buf, bsize);
        //print_binary(&v, 4);
        const i32 u = SparseInt::load_i32(buf);
        Log::debug("%ld -> bsize=%ld -> %ld", (long) v, bsize, (long) u);
        //EXPECT_EQ(v, u);
        EXPECT_EQ(bsize, bs[i]);
    }
}
<commit_msg>add back EXPECT macros<commit_after>#include <stdio.h>
#include <limits>

#include "base/all.h"

using namespace base;
using namespace std;

static void print_binary(const void* vbuf, int len) {
    char* buf = (char *) vbuf;
    for (int i = 0; i < len; i++) {
        for (int j = 0; j < 8; j++) {
            uint8_t u = buf[i];
            printf("%d", (u >> (7 - j)) & 0x1);
        }
        printf(" ");
    }
    printf("\n");
}

TEST(sparseint, dump_load_i32) {
    char buf[9];
    const i32 values[] = {0, 1, -1, -64, 63, 64, -65, -8192, 8191, -8193, 8192, -1048576, 1048575,
                    1048576, -1048577, -134217728, 134217727,
                    134217728, -134217729,
                    numeric_limits<i32>::max(), numeric_limits<i32>::min()};
    const i32 bs[] = {1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
                    4, 4, 4, 4,
                    5, 5, 5, 5};
    for (int i = 0; i < arraysize(values); i++) {
        const i32 v = values[i];
        memset(buf, 0, 9);
        int bsize = SparseInt::dump(v, buf);
        print_binary(buf, bsize);
        print_binary(&v, 4);
        const i32 u = SparseInt::load_i32(buf);
        Log::debug("%ld -> bsize=%ld -> %ld", (long) v, bsize, (long) u);
        EXPECT_EQ(v, u);
        EXPECT_EQ(bsize, bs[i]);
    }
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "kitmanager.h"

#include "kit.h"
#include "kitconfigwidget.h"
#include "kitinformation.h"
#include "kitmanagerconfigwidget.h"
#include "project.h"
#include "projectexplorer.h"

#include <coreplugin/icore.h>

#include <extensionsystem/pluginmanager.h>

#include <utils/persistentsettings.h>
#include <utils/environment.h>
#include <utils/qtcassert.h>

#include <QCoreApplication>
#include <QDir>
#include <QSettings>

#include <QFormLayout>
#include <QLabel>

static const char KIT_DATA_KEY[] = "Profile.";
static const char KIT_COUNT_KEY[] = "Profile.Count";
static const char KIT_FILE_VERSION_KEY[] = "Version";
static const char KIT_DEFAULT_KEY[] = "Profile.Default";
static const char KIT_FILENAME[] = "/qtcreator/profiles.xml";

using Utils::PersistentSettingsWriter;
using Utils::PersistentSettingsReader;

static Utils::FileName settingsFileName()
{
    QFileInfo settingsLocation(ExtensionSystem::PluginManager::settings()->fileName());
    return Utils::FileName::fromString(settingsLocation.absolutePath() + QLatin1String(KIT_FILENAME));
}

namespace ProjectExplorer {

KitManager *KitManager::m_instance = 0;

namespace Internal {

// --------------------------------------------------------------------------
// KitManagerPrivate:
// --------------------------------------------------------------------------

class KitManagerPrivate
{
public:
    KitManagerPrivate();
    ~KitManagerPrivate();

    Kit *m_defaultKit;
    bool m_initialized;
    QList<KitInformation *> m_informationList;
    QList<Kit *> m_kitList;
    Utils::PersistentSettingsWriter *m_writer;
};

KitManagerPrivate::KitManagerPrivate()
    : m_defaultKit(0), m_initialized(false), m_writer(0)
{ }

KitManagerPrivate::~KitManagerPrivate()
{
    qDeleteAll(m_informationList);
    delete m_writer;
}

} // namespace Internal

// --------------------------------------------------------------------------
// KitManager:
// --------------------------------------------------------------------------

KitManager *KitManager::instance()
{
    return m_instance;
}

KitManager::KitManager(QObject *parent) :
    QObject(parent),
    d(new Internal::KitManagerPrivate())
{
    QTC_CHECK(!m_instance);
    m_instance = this;

    connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()),
            this, SLOT(saveKits()));

    connect(this, SIGNAL(kitAdded(ProjectExplorer::Kit*)),
            this, SIGNAL(kitsChanged()));
    connect(this, SIGNAL(kitRemoved(ProjectExplorer::Kit*)),
            this, SIGNAL(kitsChanged()));
    connect(this, SIGNAL(kitUpdated(ProjectExplorer::Kit*)),
            this, SIGNAL(kitsChanged()));
}

void KitManager::restoreKits()
{
    QTC_ASSERT(!d->m_initialized, return);
    static bool initializing = false;

    if (initializing) // kits will call kits() to check their display names, which will trigger another
                      // call to restoreKits, which ...
        return;

    initializing = true;

    QList<Kit *> kitsToRegister;
    QList<Kit *> kitsToValidate;
    QList<Kit *> kitsToCheck;

    // read all kits from SDK
    QFileInfo systemSettingsFile(Core::ICore::settings(QSettings::SystemScope)->fileName());
    QFileInfo kitFile(systemSettingsFile.absolutePath() + QLatin1String(KIT_FILENAME));
    if (kitFile.exists()) {
        KitList system = restoreKits(Utils::FileName(kitFile));
        // make sure we mark these as autodetected and run additional setup logic
        foreach (Kit *k, system.kits) {
            k->setAutoDetected(true);
            k->setSdkProvided(true);
            k->setup();
        }

        // SDK kits are always considered to be up for validation since they might have been
        // extended with additional information by creator in the meantime:
        kitsToValidate = system.kits;
    }

    // read all kits from user file
    KitList userKits = restoreKits(settingsFileName());
    foreach (Kit *k, userKits.kits) {
        if (k->isSdkProvided())
            kitsToCheck.append(k);
        else
            kitsToRegister.append(k);
    }

    Kit *toStore = 0;
    foreach (Kit *current, kitsToValidate) {
        toStore = current;

        // Check whether we had this kit stored and prefer the stored one:
        for (int i = 0; i < kitsToCheck.count(); ++i) {
            if (kitsToCheck.at(i)->id() == current->id()) {
                toStore = kitsToCheck.at(i);
                kitsToCheck.removeAt(i);

                // Overwrite settings that the SDK sets to those values:
                foreach (const KitInformation *ki, kitInformation()) {
                    if (current->hasValue(ki->dataId()))
                        toStore->setValue(ki->dataId(), current->value(ki->dataId()));
                }

                delete current;
                break;
            }
        }
        addKit(toStore);
    }

    // Delete all loaded autodetected kits that were not rediscovered:
    foreach (Kit *k, kitsToCheck)
        delete k;
    kitsToCheck.clear();

    // Store manual kits
    foreach (Kit *k, kitsToRegister)
        addKit(k);

    if (kits().isEmpty()) {
        Kit *defaultKit = new Kit; // One kit using default values
        defaultKit->setDisplayName(tr("Desktop"));
        defaultKit->setSdkProvided(false);
        defaultKit->setAutoDetected(false);
        defaultKit->setIconPath(QLatin1String(":///DESKTOP///"));

        defaultKit->setup();

        addKit(defaultKit);
    }

    Kit *k = find(userKits.defaultKit);
    if (k)
        setDefaultKit(k);

    d->m_writer = new Utils::PersistentSettingsWriter(settingsFileName(), QLatin1String("QtCreatorProfiles"));
    d->m_initialized = true;
    emit kitsLoaded();
    emit kitsChanged();
}

KitManager::~KitManager()
{
    saveKits(); // Make sure we save the current state on exit!

    foreach (Kit *k, d->m_kitList)
        delete k;
    d->m_kitList.clear();
    delete d;
    m_instance = 0;
}

void KitManager::saveKits()
{
    if (!d->m_writer) // ignore save requests while we are not initialized.
        return;

    QVariantMap data;
    data.insert(QLatin1String(KIT_FILE_VERSION_KEY), 1);

    int count = 0;
    foreach (Kit *k, kits()) {
        QVariantMap tmp = k->toMap();
        if (tmp.isEmpty())
            continue;
        data.insert(QString::fromLatin1(KIT_DATA_KEY) + QString::number(count), tmp);
        ++count;
    }
    data.insert(QLatin1String(KIT_COUNT_KEY), count);
    data.insert(QLatin1String(KIT_DEFAULT_KEY),
                d->m_defaultKit ? QString::fromLatin1(d->m_defaultKit->id().name()) : QString());
    d->m_writer->save(data, Core::ICore::mainWindow());
}

bool greaterPriority(KitInformation *a, KitInformation *b)
{
    return a->priority() > b->priority();
}

void KitManager::registerKitInformation(KitInformation *ki)
{
    QTC_CHECK(!isLoaded());

    QList<KitInformation *>::iterator it
            = qLowerBound(d->m_informationList.begin(), d->m_informationList.end(), ki, greaterPriority);
    d->m_informationList.insert(it, ki);

    if (!d->m_initialized)
        return;

    foreach (Kit *k, kits()) {
        if (!k->hasValue(ki->dataId()))
            k->setValue(ki->dataId(), ki->defaultValue(k));
        else
            ki->fix(k);
    }

    return;
}

void KitManager::deregisterKitInformation(KitInformation *ki)
{
    QTC_CHECK(d->m_informationList.contains(ki));
    d->m_informationList.removeAll(ki);
    delete ki;
}

KitManager::KitList KitManager::restoreKits(const Utils::FileName &fileName)
{
    KitList result;

    PersistentSettingsReader reader;
    if (!reader.load(fileName)) {
        qWarning("Warning: Failed to read \"%s\", cannot restore kits!", qPrintable(fileName.toUserOutput()));
        return result;
    }
    QVariantMap data = reader.restoreValues();

    // Check version:
    int version = data.value(QLatin1String(KIT_FILE_VERSION_KEY), 0).toInt();
    if (version < 1) {
        qWarning("Warning: Kit file version %d not supported, cannot restore kits!", version);
        return result;
    }

    const int count = data.value(QLatin1String(KIT_COUNT_KEY), 0).toInt();
    for (int i = 0; i < count; ++i) {
        const QString key = QString::fromLatin1(KIT_DATA_KEY) + QString::number(i);
        if (!data.contains(key))
            break;

        const QVariantMap stMap = data.value(key).toMap();

        Kit *k = new Kit;
        if (k->fromMap(stMap)) {
            result.kits.append(k);
        } else {
            delete k;
            qWarning("Warning: Unable to restore kits stored in %s at position %d.",
                     qPrintable(fileName.toUserOutput()), i);
        }
    }
    const QString defaultId = data.value(QLatin1String(KIT_DEFAULT_KEY)).toString();
    if (defaultId.isEmpty())
        return result;

    const Core::Id id = Core::Id(defaultId);
    foreach (Kit *k, result.kits) {
        if (k->id() == id) {
            result.defaultKit = id;
            break;
        }
    }
    return result;
}

QList<Kit *> KitManager::kits(const KitMatcher *m) const
{
    QList<Kit *> result;
    foreach (Kit *k, d->m_kitList) {
        if (!m || m->matches(k))
            result.append(k);
    }
    return result;
}

Kit *KitManager::find(const Core::Id &id) const
{
    if (!id.isValid())
        return 0;

    foreach (Kit *k, kits()) {
        if (k->id() == id)
            return k;
    }
    return 0;
}

Kit *KitManager::find(const KitMatcher *m) const
{
    QList<Kit *> matched = kits(m);
    return matched.isEmpty() ? 0 : matched.first();
}

Kit *KitManager::defaultKit() const
{
    return d->m_defaultKit;
}

QList<KitInformation *> KitManager::kitInformation() const
{
    return d->m_informationList;
}

Internal::KitManagerConfigWidget *KitManager::createConfigWidget(Kit *k) const
{
    Internal::KitManagerConfigWidget *result = new Internal::KitManagerConfigWidget(k);
    foreach (KitInformation *ki, d->m_informationList)
        result->addConfigWidget(ki->createConfigWidget(result->workingCopy()));

    result->updateVisibility();

    return result;
}

void KitManager::deleteKit(Kit *k)
{
    QTC_ASSERT(!KitManager::instance()->kits().contains(k), return);
    delete k;
}

bool KitManager::isLoaded() const
{
    return d->m_initialized;
}

void KitManager::notifyAboutUpdate(ProjectExplorer::Kit *k)
{
    if (!k)
        return;
    if (kits().contains(k) && d->m_initialized)
        emit kitUpdated(k);
    else
        emit unmanagedKitUpdated(k);
}

bool KitManager::registerKit(ProjectExplorer::Kit *k)
{
    QTC_ASSERT(isLoaded(), return false);
    if (!k)
        return true;
    foreach (Kit *current, kits()) {
        if (k == current)
            return false;
    }

    // make sure we have all the information in our kits:
    addKit(k);
    if (d->m_initialized)
        emit kitAdded(k);
    return true;
}

void KitManager::deregisterKit(Kit *k)
{
    if (!k || !kits().contains(k))
        return;
    d->m_kitList.removeOne(k);
    if (d->m_defaultKit == k) {
        QList<Kit *> stList = kits();
        Kit *newDefault = 0;
        foreach (Kit *cur, stList) {
            if (cur->isValid()) {
                newDefault = cur;
                break;
            }
        }
        setDefaultKit(newDefault);
    }
    if (d->m_initialized)
        emit kitRemoved(k);
    delete k;
}

void KitManager::setDefaultKit(Kit *k)
{
    if (d->m_defaultKit == k)
        return;
    if (k && !kits().contains(k))
        return;
    d->m_defaultKit = k;
    if (d->m_initialized)
        emit defaultkitChanged();
}

void KitManager::addKit(Kit *k)
{
    if (!k)
        return;

    {
        KitGuard g(k);
        foreach (KitInformation *ki, d->m_informationList) {
            if (!k->hasValue(ki->dataId()))
                k->setValue(ki->dataId(), ki->defaultValue(k));
            else
                ki->fix(k);
        }
    }

    d->m_kitList.append(k);
    if (!d->m_defaultKit ||
            (!d->m_defaultKit->isValid() && k->isValid()))
        setDefaultKit(k);
}

void KitInformation::addToEnvironment(const Kit *k, Utils::Environment &env) const
{
    Q_UNUSED(k);
    Q_UNUSED(env);
}

IOutputParser *KitInformation::createOutputParser(const Kit *k) const
{
    Q_UNUSED(k);
    return 0;
}

QString KitInformation::displayNamePostfix(const Kit *k) const
{
    Q_UNUSED(k);
    return QString();
}

void KitInformation::notifyAboutUpdate(Kit *k)
{
    KitManager::instance()->notifyAboutUpdate(k);
}

} // namespace ProjectExplorer
<commit_msg>Kits: Sort kits by displayname<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "kitmanager.h"

#include "kit.h"
#include "kitconfigwidget.h"
#include "kitinformation.h"
#include "kitmanagerconfigwidget.h"
#include "project.h"
#include "projectexplorer.h"

#include <coreplugin/icore.h>

#include <extensionsystem/pluginmanager.h>

#include <utils/persistentsettings.h>
#include <utils/environment.h>
#include <utils/qtcassert.h>

#include <QCoreApplication>
#include <QDir>
#include <QSettings>

#include <QFormLayout>
#include <QLabel>

static const char KIT_DATA_KEY[] = "Profile.";
static const char KIT_COUNT_KEY[] = "Profile.Count";
static const char KIT_FILE_VERSION_KEY[] = "Version";
static const char KIT_DEFAULT_KEY[] = "Profile.Default";
static const char KIT_FILENAME[] = "/qtcreator/profiles.xml";

using Utils::PersistentSettingsWriter;
using Utils::PersistentSettingsReader;

static Utils::FileName settingsFileName()
{
    QFileInfo settingsLocation(ExtensionSystem::PluginManager::settings()->fileName());
    return Utils::FileName::fromString(settingsLocation.absolutePath() + QLatin1String(KIT_FILENAME));
}

namespace ProjectExplorer {

KitManager *KitManager::m_instance = 0;

namespace Internal {

// --------------------------------------------------------------------------
// KitManagerPrivate:
// --------------------------------------------------------------------------

class KitManagerPrivate
{
public:
    KitManagerPrivate();
    ~KitManagerPrivate();

    void insertKit(Kit *k)
    {
        // Keep list of kits sorted by displayname:
        int i =0;
        for (; i < m_kitList.count(); ++i)
            if (m_kitList.at(i)->displayName() > k->displayName())
                break;
        m_kitList.insert(i, k);
    }

    void moveKit(int pos)
    {
        if (pos < 0 || pos >= m_kitList.count())
            return;

        Kit *current = m_kitList.at(pos);
        int prev = pos - 1;
        int next = pos + 1;

        if (prev >= 0
                && m_kitList.at(prev)->displayName() > current->displayName()) {
            std::swap(m_kitList[prev], m_kitList[pos]);
            moveKit(prev);
        } else if (next < m_kitList.count()
                   && m_kitList.at(next)->displayName() < current->displayName()) {
            std::swap(m_kitList[pos], m_kitList[next]);
            moveKit(next);
        }
    }

    Kit *m_defaultKit;
    bool m_initialized;
    QList<KitInformation *> m_informationList;
    QList<Kit *> m_kitList;
    Utils::PersistentSettingsWriter *m_writer;
};

KitManagerPrivate::KitManagerPrivate()
    : m_defaultKit(0), m_initialized(false), m_writer(0)
{ }

KitManagerPrivate::~KitManagerPrivate()
{
    qDeleteAll(m_informationList);
    delete m_writer;
}

} // namespace Internal

// --------------------------------------------------------------------------
// KitManager:
// --------------------------------------------------------------------------

KitManager *KitManager::instance()
{
    return m_instance;
}

KitManager::KitManager(QObject *parent) :
    QObject(parent),
    d(new Internal::KitManagerPrivate())
{
    QTC_CHECK(!m_instance);
    m_instance = this;

    connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()),
            this, SLOT(saveKits()));

    connect(this, SIGNAL(kitAdded(ProjectExplorer::Kit*)),
            this, SIGNAL(kitsChanged()));
    connect(this, SIGNAL(kitRemoved(ProjectExplorer::Kit*)),
            this, SIGNAL(kitsChanged()));
    connect(this, SIGNAL(kitUpdated(ProjectExplorer::Kit*)),
            this, SIGNAL(kitsChanged()));
}

void KitManager::restoreKits()
{
    QTC_ASSERT(!d->m_initialized, return);
    static bool initializing = false;

    if (initializing) // kits will call kits() to check their display names, which will trigger another
                      // call to restoreKits, which ...
        return;

    initializing = true;

    QList<Kit *> kitsToRegister;
    QList<Kit *> kitsToValidate;
    QList<Kit *> kitsToCheck;

    // read all kits from SDK
    QFileInfo systemSettingsFile(Core::ICore::settings(QSettings::SystemScope)->fileName());
    QFileInfo kitFile(systemSettingsFile.absolutePath() + QLatin1String(KIT_FILENAME));
    if (kitFile.exists()) {
        KitList system = restoreKits(Utils::FileName(kitFile));
        // make sure we mark these as autodetected and run additional setup logic
        foreach (Kit *k, system.kits) {
            k->setAutoDetected(true);
            k->setSdkProvided(true);
            k->setup();
        }

        // SDK kits are always considered to be up for validation since they might have been
        // extended with additional information by creator in the meantime:
        kitsToValidate = system.kits;
    }

    // read all kits from user file
    KitList userKits = restoreKits(settingsFileName());
    foreach (Kit *k, userKits.kits) {
        if (k->isSdkProvided())
            kitsToCheck.append(k);
        else
            kitsToRegister.append(k);
    }

    Kit *toStore = 0;
    foreach (Kit *current, kitsToValidate) {
        toStore = current;

        // Check whether we had this kit stored and prefer the stored one:
        for (int i = 0; i < kitsToCheck.count(); ++i) {
            if (kitsToCheck.at(i)->id() == current->id()) {
                toStore = kitsToCheck.at(i);
                kitsToCheck.removeAt(i);

                // Overwrite settings that the SDK sets to those values:
                foreach (const KitInformation *ki, kitInformation()) {
                    if (current->hasValue(ki->dataId()))
                        toStore->setValue(ki->dataId(), current->value(ki->dataId()));
                }

                delete current;
                break;
            }
        }
        addKit(toStore);
    }

    // Delete all loaded autodetected kits that were not rediscovered:
    foreach (Kit *k, kitsToCheck)
        delete k;
    kitsToCheck.clear();

    // Store manual kits
    foreach (Kit *k, kitsToRegister)
        addKit(k);

    if (kits().isEmpty()) {
        Kit *defaultKit = new Kit; // One kit using default values
        defaultKit->setDisplayName(tr("Desktop"));
        defaultKit->setSdkProvided(false);
        defaultKit->setAutoDetected(false);
        defaultKit->setIconPath(QLatin1String(":///DESKTOP///"));

        defaultKit->setup();

        addKit(defaultKit);
    }

    Kit *k = find(userKits.defaultKit);
    if (k)
        setDefaultKit(k);

    d->m_writer = new Utils::PersistentSettingsWriter(settingsFileName(), QLatin1String("QtCreatorProfiles"));
    d->m_initialized = true;
    emit kitsLoaded();
    emit kitsChanged();
}

KitManager::~KitManager()
{
    saveKits(); // Make sure we save the current state on exit!

    foreach (Kit *k, d->m_kitList)
        delete k;
    d->m_kitList.clear();
    delete d;
    m_instance = 0;
}

void KitManager::saveKits()
{
    if (!d->m_writer) // ignore save requests while we are not initialized.
        return;

    QVariantMap data;
    data.insert(QLatin1String(KIT_FILE_VERSION_KEY), 1);

    int count = 0;
    foreach (Kit *k, kits()) {
        QVariantMap tmp = k->toMap();
        if (tmp.isEmpty())
            continue;
        data.insert(QString::fromLatin1(KIT_DATA_KEY) + QString::number(count), tmp);
        ++count;
    }
    data.insert(QLatin1String(KIT_COUNT_KEY), count);
    data.insert(QLatin1String(KIT_DEFAULT_KEY),
                d->m_defaultKit ? QString::fromLatin1(d->m_defaultKit->id().name()) : QString());
    d->m_writer->save(data, Core::ICore::mainWindow());
}

bool greaterPriority(KitInformation *a, KitInformation *b)
{
    return a->priority() > b->priority();
}

void KitManager::registerKitInformation(KitInformation *ki)
{
    QTC_CHECK(!isLoaded());

    QList<KitInformation *>::iterator it
            = qLowerBound(d->m_informationList.begin(), d->m_informationList.end(), ki, greaterPriority);
    d->m_informationList.insert(it, ki);

    if (!d->m_initialized)
        return;

    foreach (Kit *k, kits()) {
        if (!k->hasValue(ki->dataId()))
            k->setValue(ki->dataId(), ki->defaultValue(k));
        else
            ki->fix(k);
    }

    return;
}

void KitManager::deregisterKitInformation(KitInformation *ki)
{
    QTC_CHECK(d->m_informationList.contains(ki));
    d->m_informationList.removeAll(ki);
    delete ki;
}

KitManager::KitList KitManager::restoreKits(const Utils::FileName &fileName)
{
    KitList result;

    PersistentSettingsReader reader;
    if (!reader.load(fileName)) {
        qWarning("Warning: Failed to read \"%s\", cannot restore kits!", qPrintable(fileName.toUserOutput()));
        return result;
    }
    QVariantMap data = reader.restoreValues();

    // Check version:
    int version = data.value(QLatin1String(KIT_FILE_VERSION_KEY), 0).toInt();
    if (version < 1) {
        qWarning("Warning: Kit file version %d not supported, cannot restore kits!", version);
        return result;
    }

    const int count = data.value(QLatin1String(KIT_COUNT_KEY), 0).toInt();
    for (int i = 0; i < count; ++i) {
        const QString key = QString::fromLatin1(KIT_DATA_KEY) + QString::number(i);
        if (!data.contains(key))
            break;

        const QVariantMap stMap = data.value(key).toMap();

        Kit *k = new Kit;
        if (k->fromMap(stMap)) {
            result.kits.append(k);
        } else {
            delete k;
            qWarning("Warning: Unable to restore kits stored in %s at position %d.",
                     qPrintable(fileName.toUserOutput()), i);
        }
    }
    const QString defaultId = data.value(QLatin1String(KIT_DEFAULT_KEY)).toString();
    if (defaultId.isEmpty())
        return result;

    const Core::Id id = Core::Id(defaultId);
    foreach (Kit *k, result.kits) {
        if (k->id() == id) {
            result.defaultKit = id;
            break;
        }
    }
    return result;
}

QList<Kit *> KitManager::kits(const KitMatcher *m) const
{
    QList<Kit *> result;
    foreach (Kit *k, d->m_kitList) {
        if (!m || m->matches(k))
            result.append(k);
    }
    return result;
}

Kit *KitManager::find(const Core::Id &id) const
{
    if (!id.isValid())
        return 0;

    foreach (Kit *k, kits()) {
        if (k->id() == id)
            return k;
    }
    return 0;
}

Kit *KitManager::find(const KitMatcher *m) const
{
    QList<Kit *> matched = kits(m);
    return matched.isEmpty() ? 0 : matched.first();
}

Kit *KitManager::defaultKit() const
{
    return d->m_defaultKit;
}

QList<KitInformation *> KitManager::kitInformation() const
{
    return d->m_informationList;
}

Internal::KitManagerConfigWidget *KitManager::createConfigWidget(Kit *k) const
{
    Internal::KitManagerConfigWidget *result = new Internal::KitManagerConfigWidget(k);
    foreach (KitInformation *ki, d->m_informationList)
        result->addConfigWidget(ki->createConfigWidget(result->workingCopy()));

    result->updateVisibility();

    return result;
}

void KitManager::deleteKit(Kit *k)
{
    QTC_ASSERT(!KitManager::instance()->kits().contains(k), return);
    delete k;
}

bool KitManager::isLoaded() const
{
    return d->m_initialized;
}

void KitManager::notifyAboutUpdate(ProjectExplorer::Kit *k)
{
    if (!k)
        return;
    int pos = d->m_kitList.indexOf(k);
    if (pos >= 0 && d->m_initialized) {
        d->moveKit(pos);
        emit kitUpdated(k);
    } else {
        emit unmanagedKitUpdated(k);
    }
}

bool KitManager::registerKit(ProjectExplorer::Kit *k)
{
    QTC_ASSERT(isLoaded(), return false);
    if (!k)
        return true;
    foreach (Kit *current, kits()) {
        if (k == current)
            return false;
    }

    // make sure we have all the information in our kits:
    addKit(k);
    if (d->m_initialized)
        emit kitAdded(k);
    return true;
}

void KitManager::deregisterKit(Kit *k)
{
    if (!k || !kits().contains(k))
        return;
    d->m_kitList.removeOne(k);
    if (d->m_defaultKit == k) {
        QList<Kit *> stList = kits();
        Kit *newDefault = 0;
        foreach (Kit *cur, stList) {
            if (cur->isValid()) {
                newDefault = cur;
                break;
            }
        }
        setDefaultKit(newDefault);
    }
    if (d->m_initialized)
        emit kitRemoved(k);
    delete k;
}

void KitManager::setDefaultKit(Kit *k)
{
    if (d->m_defaultKit == k)
        return;
    if (k && !kits().contains(k))
        return;
    d->m_defaultKit = k;
    if (d->m_initialized)
        emit defaultkitChanged();
}

void KitManager::addKit(Kit *k)
{
    if (!k)
        return;

    {
        KitGuard g(k);
        foreach (KitInformation *ki, d->m_informationList) {
            if (!k->hasValue(ki->dataId()))
                k->setValue(ki->dataId(), ki->defaultValue(k));
            else
                ki->fix(k);
        }
    }

    d->insertKit(k);

    if (!d->m_defaultKit ||
            (!d->m_defaultKit->isValid() && k->isValid()))
        setDefaultKit(k);
}

void KitInformation::addToEnvironment(const Kit *k, Utils::Environment &env) const
{
    Q_UNUSED(k);
    Q_UNUSED(env);
}

IOutputParser *KitInformation::createOutputParser(const Kit *k) const
{
    Q_UNUSED(k);
    return 0;
}

QString KitInformation::displayNamePostfix(const Kit *k) const
{
    Q_UNUSED(k);
    return QString();
}

void KitInformation::notifyAboutUpdate(Kit *k)
{
    KitManager::instance()->notifyAboutUpdate(k);
}

} // namespace ProjectExplorer
<|endoftext|>


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

#include "modules/drivers/lidar/proto/lidar_parameter.pb.h"

namespace apollo {
namespace drivers {
namespace lidar {

LidarDriverComponent::LidarDriverComponent() {}
bool LidarDriverComponent::Init() {
  if (!GetProtoConfig(&conf_)) {
    AERROR << "load config error, file:" << config_file_path_;
    return false;
  }
  node_ = apollo::cyber::CreateNode("drivers_lidar");
  AINFO << "conf:" << conf_.DebugString();
  LidarDriverFactory::Instance()->RegisterLidarClients();
  driver_ = LidarDriverFactory::Instance()->CreateLidarDriver(node_, conf_);
  if (!driver_->Init()) {
    AERROR << "driver init error";
    return false;
  }
  return true;
}

}  // namespace lidar
}  // namespace drivers
}  // namespace apollo
<commit_msg>Drivers:fix  a potential null pointer problem<commit_after>/******************************************************************************
 * Copyright 2020 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/
#include "modules/drivers/lidar/lidar_driver_component.h"

#include "modules/drivers/lidar/proto/lidar_parameter.pb.h"

namespace apollo {
namespace drivers {
namespace lidar {

LidarDriverComponent::LidarDriverComponent() {}
bool LidarDriverComponent::Init() {
  if (!GetProtoConfig(&conf_)) {
    AERROR << "load config error, file:" << config_file_path_;
    return false;
  }
  node_ = apollo::cyber::CreateNode("drivers_lidar");
  AINFO << "conf:" << conf_.DebugString();
  LidarDriverFactory::Instance()->RegisterLidarClients();
  driver_ = LidarDriverFactory::Instance()->CreateLidarDriver(node_, conf_);
  if (driver_ == nullptr || !driver_->Init()) {
    AERROR << "driver init error";
    return false;
  }
  return true;
}

}  // namespace lidar
}  // namespace drivers
}  // namespace apollo
<|endoftext|>