<commit_before>/* Copyright 2015 Google Inc. 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 "tensorflow/examples/android/jni/tensorflow_jni.h"

#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/bitmap.h>

#include <jni.h>
#include <pthread.h>
#include <unistd.h>
#include <queue>
#include <sstream>
#include <string>

#include "tensorflow/core/framework/types.pb.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/platform/port.h"
#include "tensorflow/core/public/env.h"
#include "tensorflow/core/public/session.h"
#include "tensorflow/core/public/tensor.h"
#include "tensorflow/examples/android/jni/jni_utils.h"

// Global variables that holds the Tensorflow classifier.
static std::unique_ptr<tensorflow::Session> session;

static std::vector<std::string> g_label_strings;
static bool g_compute_graph_initialized = false;
//static mutex g_compute_graph_mutex(base::LINKER_INITIALIZED);

static int g_tensorflow_input_size;  // The image size for the mognet input.
static int g_image_mean;  // The image mean.

using namespace tensorflow;

JNIEXPORT jint JNICALL
TENSORFLOW_METHOD(initializeTensorflow)(
    JNIEnv* env, jobject thiz, jobject java_asset_manager,
    jstring model, jstring labels,
    jint num_classes, jint mognet_input_size, jint image_mean) {
  //MutexLock input_lock(&g_compute_graph_mutex);
  if (g_compute_graph_initialized) {
    LOG(INFO) << "Compute graph already loaded. skipping.";
    return 0;
  }

  const char* const model_cstr = env->GetStringUTFChars(model, NULL);
  const char* const labels_cstr = env->GetStringUTFChars(labels, NULL);

  g_tensorflow_input_size = mognet_input_size;
  g_image_mean = image_mean;

  LOG(INFO) << "Loading Tensorflow.";

  LOG(INFO) << "Making new SessionOptions.";
  tensorflow::SessionOptions options;
  tensorflow::ConfigProto& config = options.config;
  LOG(INFO) << "Got config, " << config.device_count_size() << " devices";

  session.reset(tensorflow::NewSession(options));
  LOG(INFO) << "Session created.";

  tensorflow::GraphDef tensorflow_graph;
  LOG(INFO) << "Graph created.";

  AAssetManager* const asset_manager =
      AAssetManager_fromJava(env, java_asset_manager);
  LOG(INFO) << "Acquired AssetManager.";

  LOG(INFO) << "Reading file to proto: " << model_cstr;
  ReadFileToProto(asset_manager, model_cstr, &tensorflow_graph);

  LOG(INFO) << "Creating session.";
  tensorflow::Status s = session->Create(tensorflow_graph);
  if (!s.ok()) {
    LOG(ERROR) << "Could not create Tensorflow Graph: " << s;
    return -1;
  }

  // Clear the proto to save memory space.
  tensorflow_graph.Clear();
  LOG(INFO) << "Tensorflow graph loaded from: " << model_cstr;

  // Read the label list
  ReadFileToVector(asset_manager, labels_cstr, &g_label_strings);
  LOG(INFO) << g_label_strings.size() << " label strings loaded from: "
            << labels_cstr;
  g_compute_graph_initialized = true;

  return 0;
}

namespace {
typedef struct {
  uint8 red;
  uint8 green;
  uint8 blue;
  uint8 alpha;
} RGBA;
}  // namespace

// Returns the top N confidence values over threshold in the provided vector,
// sorted by confidence in descending order.
static void GetTopN(
    const Eigen::TensorMap<Eigen::Tensor<float, 1, Eigen::RowMajor>,
                           Eigen::Aligned>& prediction,
    const int num_results, const float threshold,
    std::vector<std::pair<float, int> >* top_results) {
  // Will contain top N results in ascending order.
  std::priority_queue<std::pair<float, int>,
      std::vector<std::pair<float, int> >,
      std::greater<std::pair<float, int> > > top_result_pq;

  const int count = prediction.size();
  for (int i = 0; i < count; ++i) {
    const float value = prediction(i);

    // Only add it if it beats the threshold and has a chance at being in
    // the top N.
    if (value < threshold) {
      continue;
    }

    top_result_pq.push(std::pair<float, int>(value, i));

    // If at capacity, kick the smallest value out.
    if (top_result_pq.size() > num_results) {
      top_result_pq.pop();
    }
  }

  // Copy to output vector and reverse into descending order.
  while (!top_result_pq.empty()) {
    top_results->push_back(top_result_pq.top());
    top_result_pq.pop();
  }
  std::reverse(top_results->begin(), top_results->end());
}

static std::string ClassifyImage(const RGBA* const bitmap_src,
                            const int in_stride,
                            const int width, const int height) {
  // Create input tensor
  tensorflow::Tensor input_tensor(
      tensorflow::DT_FLOAT,
      tensorflow::TensorShape({
          1, g_tensorflow_input_size, g_tensorflow_input_size, 3}));

  auto input_tensor_mapped = input_tensor.tensor<float, 4>();

  LOG(INFO) << "Tensorflow: Copying Data.";
  for (int i = 0; i < g_tensorflow_input_size; ++i) {
    const RGBA* src = bitmap_src + i * g_tensorflow_input_size;
    for (int j = 0; j < g_tensorflow_input_size; ++j) {
       // Copy 3 values
      input_tensor_mapped(0, i, j, 0) =
          static_cast<float>(src->red) - g_image_mean;
      input_tensor_mapped(0, i, j, 1) =
          static_cast<float>(src->green) - g_image_mean;
      input_tensor_mapped(0, i, j, 2) =
          static_cast<float>(src->blue) - g_image_mean;
      ++src;
    }
  }

  std::vector<std::pair<std::string, tensorflow::Tensor> > input_tensors(
      {{"input:0", input_tensor}});

  VLOG(0) << "Start computing.";
  std::vector<tensorflow::Tensor> output_tensors;
  std::vector<std::string> output_names({"output:0"});

  tensorflow::Status s =
      session->Run(input_tensors, output_names, {}, &output_tensors);
  VLOG(0) << "End computing.";

  if (!s.ok()) {
    LOG(ERROR) << "Error during inference: " << s;
    return "";
  }

  VLOG(0) << "Reading from layer " << output_names[0];
  tensorflow::Tensor* output = &output_tensors[0];
  const int kNumResults = 5;
  const float kThreshold = 0.1f;
  std::vector<std::pair<float, int> > top_results;
  GetTopN(output->flat<float>(), kNumResults, kThreshold, &top_results);

  std::stringstream ss;
  ss.precision(3);
  for (const auto& result : top_results) {
    const float confidence = result.first;
    const int index = result.second;

    ss << index << " " << confidence << " ";

    // Write out the result as a string
    if (index < g_label_strings.size()) {
      // just for safety: theoretically, the output is under 1000 unless there
      // is some numerical issues leading to a wrong prediction.
      ss << g_label_strings[index];
    } else {
      ss << "Prediction: " << index;
    }

    ss << "\n";
  }

  LOG(INFO) << "Predictions: " << ss.str();
  return ss.str();
}

JNIEXPORT jstring JNICALL
TENSORFLOW_METHOD(classifyImageRgb)(
    JNIEnv* env, jobject thiz, jintArray image, jint width, jint height) {
  // Copy image into currFrame.
  jboolean iCopied = JNI_FALSE;
  jint* pixels = env->GetIntArrayElements(image, &iCopied);

  std::string result = ClassifyImage(
      reinterpret_cast<const RGBA*>(pixels), width * 4, width, height);

  env->ReleaseIntArrayElements(image, pixels, JNI_ABORT);

  return env->NewStringUTF(result.c_str());
}

JNIEXPORT jstring JNICALL
TENSORFLOW_METHOD(classifyImageBmp)(
    JNIEnv* env, jobject thiz, jobject bitmap) {
  // Obtains the bitmap information.
  AndroidBitmapInfo info;
  CHECK_EQ(AndroidBitmap_getInfo(env, bitmap, &info),
           ANDROID_BITMAP_RESULT_SUCCESS);
  void* pixels;
  CHECK_EQ(AndroidBitmap_lockPixels(env, bitmap, &pixels),
           ANDROID_BITMAP_RESULT_SUCCESS);
  LOG(INFO) << "Height: " << info.height;
  LOG(INFO) << "Width: " << info.width;
  LOG(INFO) << "Stride: " << info.stride;
  // TODO(jiayq): deal with other formats if necessary.
  if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
    return env->NewStringUTF(
        "Error: Android system is not using RGBA_8888 in default.");
  }

  std::string result = ClassifyImage(
      static_cast<const RGBA*>(pixels), info.stride, info.width, info.height);

  // Finally, unlock the pixels
  CHECK_EQ(AndroidBitmap_unlockPixels(env, bitmap),
           ANDROID_BITMAP_RESULT_SUCCESS);

  return env->NewStringUTF(result.c_str());
}
<commit_msg>Add basic benchmarking to inference call in Tensorflow Android demo. Change: 112968173<commit_after>/* Copyright 2015 Google Inc. 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 "tensorflow/examples/android/jni/tensorflow_jni.h"

#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/bitmap.h>

#include <jni.h>
#include <pthread.h>
#include <unistd.h>
#include <queue>
#include <sstream>
#include <string>

#include "tensorflow/core/framework/types.pb.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/platform/port.h"
#include "tensorflow/core/public/env.h"
#include "tensorflow/core/public/session.h"
#include "tensorflow/core/public/tensor.h"
#include "tensorflow/examples/android/jni/jni_utils.h"

// Global variables that holds the Tensorflow classifier.
static std::unique_ptr<tensorflow::Session> session;

static std::vector<std::string> g_label_strings;
static bool g_compute_graph_initialized = false;
//static mutex g_compute_graph_mutex(base::LINKER_INITIALIZED);

static int g_tensorflow_input_size;  // The image size for the mognet input.
static int g_image_mean;  // The image mean.

using namespace tensorflow;

inline static int64 CurrentThreadTimeUs() {
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return tv.tv_sec * 1000000 + tv.tv_usec;
}

JNIEXPORT jint JNICALL
TENSORFLOW_METHOD(initializeTensorflow)(
    JNIEnv* env, jobject thiz, jobject java_asset_manager,
    jstring model, jstring labels,
    jint num_classes, jint mognet_input_size, jint image_mean) {
  //MutexLock input_lock(&g_compute_graph_mutex);
  if (g_compute_graph_initialized) {
    LOG(INFO) << "Compute graph already loaded. skipping.";
    return 0;
  }

  const char* const model_cstr = env->GetStringUTFChars(model, NULL);
  const char* const labels_cstr = env->GetStringUTFChars(labels, NULL);

  g_tensorflow_input_size = mognet_input_size;
  g_image_mean = image_mean;

  LOG(INFO) << "Loading Tensorflow.";

  LOG(INFO) << "Making new SessionOptions.";
  tensorflow::SessionOptions options;
  tensorflow::ConfigProto& config = options.config;
  LOG(INFO) << "Got config, " << config.device_count_size() << " devices";

  session.reset(tensorflow::NewSession(options));
  LOG(INFO) << "Session created.";

  tensorflow::GraphDef tensorflow_graph;
  LOG(INFO) << "Graph created.";

  AAssetManager* const asset_manager =
      AAssetManager_fromJava(env, java_asset_manager);
  LOG(INFO) << "Acquired AssetManager.";

  LOG(INFO) << "Reading file to proto: " << model_cstr;
  ReadFileToProto(asset_manager, model_cstr, &tensorflow_graph);

  LOG(INFO) << "Creating session.";
  tensorflow::Status s = session->Create(tensorflow_graph);
  if (!s.ok()) {
    LOG(ERROR) << "Could not create Tensorflow Graph: " << s;
    return -1;
  }

  // Clear the proto to save memory space.
  tensorflow_graph.Clear();
  LOG(INFO) << "Tensorflow graph loaded from: " << model_cstr;

  // Read the label list
  ReadFileToVector(asset_manager, labels_cstr, &g_label_strings);
  LOG(INFO) << g_label_strings.size() << " label strings loaded from: "
            << labels_cstr;
  g_compute_graph_initialized = true;

  return 0;
}

namespace {
typedef struct {
  uint8 red;
  uint8 green;
  uint8 blue;
  uint8 alpha;
} RGBA;
}  // namespace

// Returns the top N confidence values over threshold in the provided vector,
// sorted by confidence in descending order.
static void GetTopN(
    const Eigen::TensorMap<Eigen::Tensor<float, 1, Eigen::RowMajor>,
                           Eigen::Aligned>& prediction,
    const int num_results, const float threshold,
    std::vector<std::pair<float, int> >* top_results) {
  // Will contain top N results in ascending order.
  std::priority_queue<std::pair<float, int>,
      std::vector<std::pair<float, int> >,
      std::greater<std::pair<float, int> > > top_result_pq;

  const int count = prediction.size();
  for (int i = 0; i < count; ++i) {
    const float value = prediction(i);

    // Only add it if it beats the threshold and has a chance at being in
    // the top N.
    if (value < threshold) {
      continue;
    }

    top_result_pq.push(std::pair<float, int>(value, i));

    // If at capacity, kick the smallest value out.
    if (top_result_pq.size() > num_results) {
      top_result_pq.pop();
    }
  }

  // Copy to output vector and reverse into descending order.
  while (!top_result_pq.empty()) {
    top_results->push_back(top_result_pq.top());
    top_result_pq.pop();
  }
  std::reverse(top_results->begin(), top_results->end());
}

static std::string ClassifyImage(const RGBA* const bitmap_src,
                                 const int in_stride,
                                 const int width, const int height) {
  // Very basic benchmarking functionality.
  static int num_runs = 0;
  static int64 timing_total_us = 0;
  ++num_runs;

  // Create input tensor
  tensorflow::Tensor input_tensor(
      tensorflow::DT_FLOAT,
      tensorflow::TensorShape({
          1, g_tensorflow_input_size, g_tensorflow_input_size, 3}));

  auto input_tensor_mapped = input_tensor.tensor<float, 4>();

  LOG(INFO) << "Tensorflow: Copying Data.";
  for (int i = 0; i < g_tensorflow_input_size; ++i) {
    const RGBA* src = bitmap_src + i * g_tensorflow_input_size;
    for (int j = 0; j < g_tensorflow_input_size; ++j) {
       // Copy 3 values
      input_tensor_mapped(0, i, j, 0) =
          static_cast<float>(src->red) - g_image_mean;
      input_tensor_mapped(0, i, j, 1) =
          static_cast<float>(src->green) - g_image_mean;
      input_tensor_mapped(0, i, j, 2) =
          static_cast<float>(src->blue) - g_image_mean;
      ++src;
    }
  }

  std::vector<std::pair<std::string, tensorflow::Tensor> > input_tensors(
      {{"input:0", input_tensor}});

  VLOG(0) << "Start computing.";
  std::vector<tensorflow::Tensor> output_tensors;
  std::vector<std::string> output_names({"output:0"});

  const int64 start_time = CurrentThreadTimeUs();
  tensorflow::Status s =
      session->Run(input_tensors, output_names, {}, &output_tensors);
  const int64 end_time = CurrentThreadTimeUs();

  const int64 elapsed_time_inf = end_time - start_time;
  timing_total_us += elapsed_time_inf;
  VLOG(0) << "End computing. Ran in " << elapsed_time_inf / 1000 << "ms ("
          << (timing_total_us / num_runs / 1000) << "ms avg over " << num_runs
          << " runs)";

  if (!s.ok()) {
    LOG(ERROR) << "Error during inference: " << s;
    return "";
  }

  VLOG(0) << "Reading from layer " << output_names[0];
  tensorflow::Tensor* output = &output_tensors[0];
  const int kNumResults = 5;
  const float kThreshold = 0.1f;
  std::vector<std::pair<float, int> > top_results;
  GetTopN(output->flat<float>(), kNumResults, kThreshold, &top_results);

  std::stringstream ss;
  ss.precision(3);
  for (const auto& result : top_results) {
    const float confidence = result.first;
    const int index = result.second;

    ss << index << " " << confidence << " ";

    // Write out the result as a string
    if (index < g_label_strings.size()) {
      // just for safety: theoretically, the output is under 1000 unless there
      // is some numerical issues leading to a wrong prediction.
      ss << g_label_strings[index];
    } else {
      ss << "Prediction: " << index;
    }

    ss << "\n";
  }

  LOG(INFO) << "Predictions: " << ss.str();
  return ss.str();
}

JNIEXPORT jstring JNICALL
TENSORFLOW_METHOD(classifyImageRgb)(
    JNIEnv* env, jobject thiz, jintArray image, jint width, jint height) {
  // Copy image into currFrame.
  jboolean iCopied = JNI_FALSE;
  jint* pixels = env->GetIntArrayElements(image, &iCopied);

  std::string result = ClassifyImage(
      reinterpret_cast<const RGBA*>(pixels), width * 4, width, height);

  env->ReleaseIntArrayElements(image, pixels, JNI_ABORT);

  return env->NewStringUTF(result.c_str());
}

JNIEXPORT jstring JNICALL
TENSORFLOW_METHOD(classifyImageBmp)(
    JNIEnv* env, jobject thiz, jobject bitmap) {
  // Obtains the bitmap information.
  AndroidBitmapInfo info;
  CHECK_EQ(AndroidBitmap_getInfo(env, bitmap, &info),
           ANDROID_BITMAP_RESULT_SUCCESS);
  void* pixels;
  CHECK_EQ(AndroidBitmap_lockPixels(env, bitmap, &pixels),
           ANDROID_BITMAP_RESULT_SUCCESS);
  LOG(INFO) << "Height: " << info.height;
  LOG(INFO) << "Width: " << info.width;
  LOG(INFO) << "Stride: " << info.stride;
  // TODO(jiayq): deal with other formats if necessary.
  if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
    return env->NewStringUTF(
        "Error: Android system is not using RGBA_8888 in default.");
  }

  std::string result = ClassifyImage(
      static_cast<const RGBA*>(pixels), info.stride, info.width, info.height);

  // Finally, unlock the pixels
  CHECK_EQ(AndroidBitmap_unlockPixels(env, bitmap),
           ANDROID_BITMAP_RESULT_SUCCESS);

  return env->NewStringUTF(result.c_str());
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2016 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the author nor the names of other contributors may
//      be used to endorse or promote products derived from this software
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////

#include "NomadDecoder.h"
#include <vector>
#include <cstring>
#include <stdio.h>

using namespace musik::core::sdk;

#define DEFAULT_READ_SAMPLE_SIZE 2304 * 4
#define SAMPLES_PER_FRAME_LAYER_1 1152
#define SAMPLES_PER_FRAME_LAYER_2 576

static ssize_t nomadRead(void *datasource, void *buffer, size_t count) {
    IDataStream *stream = static_cast<IDataStream*>(datasource);
    return (ssize_t) stream->Read(buffer, count);
}

static off_t nomadSeek(void *datasource, off_t offset, int whence) {
    IDataStream *stream = static_cast<IDataStream*>(datasource);

    if (whence == SEEK_END && stream->Length() > 0) {
        stream->SetPosition(stream->Length() - offset);
    }
    else {
        PositionType pos = (whence == SEEK_SET)
            ? offset : stream->Position() + offset;

        stream->SetPosition(pos);
    }

    return (off_t) stream->Position();
}

static int nomadClose(void *datasource) {
    /* no-op, IDataStream will be closed by the app */
    return 1;
}

NomadDecoder::NomadDecoder() {
    this->duration = -1.0f;
    this->nomadContext = nullptr;
    this->callbacks.read = &nomadRead;
    this->callbacks.lseek = &nomadSeek;
    this->callbacks.close = &nomadClose;
}

NomadDecoder::~NomadDecoder() {
}

void NomadDecoder::Destroy() {
    nomad_close(this->nomadContext);
    this->nomadContext = nullptr;
    delete this;
}

double NomadDecoder::SetPosition(double seconds) {
    return !nomad_time_seek(this->nomadContext, seconds) ? seconds : -1;
}

double NomadDecoder::GetDuration() {
    return this->duration;
}

bool NomadDecoder::GetBuffer(IBuffer *buffer) {
    buffer->SetSamples(DEFAULT_READ_SAMPLE_SIZE);

    int read = nomad_read(
        this->nomadContext,
        (char *)buffer->BufferPointer(),
        DEFAULT_READ_SAMPLE_SIZE,
        SAMPLE_FORMAT_32_BIT_FLOAT);

    buffer->SetSamples(read > 0 ? read : 0);

    return (read > 0) ? true : false;
}

bool NomadDecoder::Open(IDataStream *stream) {
    int tagLengthBytes = 0;

    if (stream->Seekable()) {
        tagLengthBytes = this->GetId3v2HeaderLength(stream);
        stream->SetPosition(0);
    }

    const int result = nomad_open_callbacks(&this->nomadContext, stream, &this->callbacks);

    if (!result) {
        /* nomad's time estimation when there is no xing header seems wrong in many
        cases -- so we recalculate it here based on taglib's algorithm, which
        (empirically) seems much more accurate */
        if (!nomad_xing(this->nomadContext) && tagLengthBytes > 0) {
            const int bitrate = nomad_info(this->nomadContext)->avg_bitrate / 1000;
            const int streamLength = stream->Length() - tagLengthBytes;
            this->duration = (streamLength * 8.0 / bitrate) / 1000;
        }
        else {
            this->duration = nomad_info(this->nomadContext)->duration;
        }
    }

    return result ? false : true;
}

/* adapted from http://stackoverflow.com/a/3520427 */

#pragma pack(1)
struct Mp3Header {
    char tag[3];
    unsigned char maj_ver;
    unsigned char min_ver;
    unsigned char flags;
    unsigned int  size;
};
#pragma pack()

static int HEADER_LENGTH = sizeof(Mp3Header);

size_t NomadDecoder::GetId3v2HeaderLength(musik::core::sdk::IDataStream *stream) {
    Mp3Header hdr = { 0 };
    if (stream->Read(&hdr, HEADER_LENGTH) != HEADER_LENGTH) {
        return 0;
    }

    if (memcmp(hdr.tag, "ID3", 3) != 0) {
        return 0;
    }

    // value has 4 bytes (8-bits each)
    //  - discard most significant bit from each byte
    //  - reverse byte order
    //  - concatenate the 4 * 7-bit nibbles into a 24-bit size.
    unsigned char *parts = reinterpret_cast<unsigned char *>(&hdr.size);

    return
        (parts[3] & 0x7F) |
        ((parts[2] & 0x7F) << 7) |
        ((parts[1] & 0x7F) << 14) |
        ((parts[0] & 0x7F) << 21);
}
<commit_msg>Fixed nomad mp3 decoder sample rate calculation issue.<commit_after>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2016 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the author nor the names of other contributors may
//      be used to endorse or promote products derived from this software
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////

#include "NomadDecoder.h"
#include <vector>
#include <cstring>
#include <stdio.h>

using namespace musik::core::sdk;

#define DEFAULT_READ_SAMPLE_SIZE 2304 * 4
#define SAMPLES_PER_FRAME_LAYER_1 1152
#define SAMPLES_PER_FRAME_LAYER_2 576

static ssize_t nomadRead(void *datasource, void *buffer, size_t count) {
    IDataStream *stream = static_cast<IDataStream*>(datasource);
    return (ssize_t) stream->Read(buffer, count);
}

static off_t nomadSeek(void *datasource, off_t offset, int whence) {
    IDataStream *stream = static_cast<IDataStream*>(datasource);

    if (whence == SEEK_END && stream->Length() > 0) {
        stream->SetPosition(stream->Length() - offset);
    }
    else {
        PositionType pos = (whence == SEEK_SET)
            ? offset : stream->Position() + offset;

        stream->SetPosition(pos);
    }

    return (off_t) stream->Position();
}

static int nomadClose(void *datasource) {
    /* no-op, IDataStream will be closed by the app */
    return 1;
}

NomadDecoder::NomadDecoder() {
    this->duration = -1.0f;
    this->nomadContext = nullptr;
    this->callbacks.read = &nomadRead;
    this->callbacks.lseek = &nomadSeek;
    this->callbacks.close = &nomadClose;
}

NomadDecoder::~NomadDecoder() {
}

void NomadDecoder::Destroy() {
    nomad_close(this->nomadContext);
    this->nomadContext = nullptr;
    delete this;
}

double NomadDecoder::SetPosition(double seconds) {
    return !nomad_time_seek(this->nomadContext, seconds) ? seconds : -1;
}

double NomadDecoder::GetDuration() {
    return this->duration;
}

bool NomadDecoder::GetBuffer(IBuffer *buffer) {
    buffer->SetSamples(DEFAULT_READ_SAMPLE_SIZE);

    int read = nomad_read(
        this->nomadContext,
        (char *)buffer->BufferPointer(),
        DEFAULT_READ_SAMPLE_SIZE,
        SAMPLE_FORMAT_32_BIT_FLOAT);

    buffer->SetSamples(read > 0 ? read : 0);
    buffer->SetSampleRate(nomad_info(this->nomadContext)->sample_rate);

    return (read > 0) ? true : false;
}

bool NomadDecoder::Open(IDataStream *stream) {
    int tagLengthBytes = 0;

    if (stream->Seekable()) {
        tagLengthBytes = this->GetId3v2HeaderLength(stream);
        stream->SetPosition(0);
    }

    const int result = nomad_open_callbacks(&this->nomadContext, stream, &this->callbacks);

    if (!result) {
        /* nomad's time estimation when there is no xing header seems wrong in many
        cases -- so we recalculate it here based on taglib's algorithm, which
        (empirically) seems much more accurate */
        if (!nomad_xing(this->nomadContext) && tagLengthBytes > 0) {
            const int bitrate = nomad_info(this->nomadContext)->avg_bitrate / 1000;
            const int streamLength = stream->Length() - tagLengthBytes;
            this->duration = (streamLength * 8.0 / bitrate) / 1000;
        }
        else {
            this->duration = nomad_info(this->nomadContext)->duration;
        }
    }

    return result ? false : true;
}

/* adapted from http://stackoverflow.com/a/3520427 */

#pragma pack(1)
struct Mp3Header {
    char tag[3];
    unsigned char maj_ver;
    unsigned char min_ver;
    unsigned char flags;
    unsigned int  size;
};
#pragma pack()

static int HEADER_LENGTH = sizeof(Mp3Header);

size_t NomadDecoder::GetId3v2HeaderLength(musik::core::sdk::IDataStream *stream) {
    Mp3Header hdr = { 0 };
    if (stream->Read(&hdr, HEADER_LENGTH) != HEADER_LENGTH) {
        return 0;
    }

    if (memcmp(hdr.tag, "ID3", 3) != 0) {
        return 0;
    }

    // value has 4 bytes (8-bits each)
    //  - discard most significant bit from each byte
    //  - reverse byte order
    //  - concatenate the 4 * 7-bit nibbles into a 24-bit size.
    unsigned char *parts = reinterpret_cast<unsigned char *>(&hdr.size);

    return
        (parts[3] & 0x7F) |
        ((parts[2] & 0x7F) << 7) |
        ((parts[1] & 0x7F) << 14) |
        ((parts[0] & 0x7F) << 21);
}
<|endoftext|>


<commit_before>#include <KnowledgeBase.h>
#include <TypeRegistry.h>

#include <Singleton.h>

#include <vector>
#include <algorithm>
#include <numeric>

using namespace std;

class KBImpl {
  public:
    using TransStorage = std::vector<const Transformation*>;
    using TypeStorage  = AbstractRegistry<EventType>;
    using Transformations = KnowledgeBase::Transformations;
    using EventIDs = TypeStorage::EventIDs;
    using EventTypes = Transformation::EventTypes;

  private:
    using OutIt = back_insert_iterator<Transformations>;
    using TypeOutIt = back_insert_iterator<EventTypes>;
    TransStorage mHetTrans;
    TransStorage mAttrTrans;
    TypeStorage  mTypes;

    EventIDs extractIDs(EventID goal, const EventIDs& ids) const {
      EventIDs result;
      auto start = lower_bound(ids.begin(), ids.end(), goal);
      copy_if(start, ids.end(), back_inserter(result), [&goal](EventID id){ return id>=goal; });

      return result;
    }

    void addValidTypes(EventID id, TypeOutIt it) const {
      transform(mTypes.find(id).first, mTypes.find(id).second, it, [](const EventType& eT){ return &eT;});
    }

    vector<EventTypes> generateTypeLists(const EventIDs& in, const EventIDs& ids) const{
      vector<EventTypes> result(in.size());
      for(unsigned int i=0; i < in.size(); i++) {
        addValidTypes(in[i], back_inserter(result[i]));
        if(!result[i].size())
          break;
      }
      return result;
    }

    vector<EventTypes> generateCombinations(const vector<EventTypes>& typeLists) const {
      if(typeLists.empty())
        return vector<EventTypes>();

      size_t size = accumulate(typeLists.begin(), typeLists.end(), 1UL, [](size_t size, const EventTypes& tL){ return size*tL.size(); });

      if(!size)
        return vector<EventTypes>();

      vector<EventTypes> result(size);
      for(size_t i=0; i<size; i++)
        result[i].resize(typeLists.size());

      size_t currSize=size;
      size_t oldSize = 1;
      for(size_t i=0; i < typeLists.size(); i++) {
        for(size_t m=0; m < oldSize; m++)
          for(size_t j=0; j < typeLists[i].size(); j++) {
            currSize /= typeLists[i].size();
            for(size_t k=0; k < currSize; k++)
              result[i][j*currSize+k] = typeLists[j][i];
          }
        oldSize = typeLists[i].size();
      }
      return result;
    }

    void generateAll(const ConfiguredTransformation& trans, const EventIDs& ids, OutIt it) const {
      vector<EventTypes> usableEventTypes = generateTypeLists(trans.inIDs(), ids);
      vector<EventTypes> typeCombinations = generateCombinations(usableEventTypes);
      auto create = [trans](const EventTypes& in){
        ConfiguredTransformation t(trans);
        t.in(in);
        return t;
      };
      transform(typeCombinations.begin(), typeCombinations.end(), it, create);
    }

    /** \brief create fitting composite transformation for goal EventID
     * \param trans all existing heterogeneus transformations
     * \param goal the EventID of the goal
     * \param all existing published EventIDs
     * \return a list of fitting heterogeneus (composite) transformations
     * \todo filter on input eventids
     * \todo generate composite transformations
     **/
    void findHetTrans(const EventType& goal, const EventIDs& ids, OutIt it) const {
      auto checkAndConvert = [&goal, &ids](OutIt it, const Transformation* t){
        if (t && EventID(goal) <= t->out() )
          return *it++ = ConfiguredTransformation(*t, goal);// || !includes(tIn.begin(), tIn.end(), ids.begin(), ids.end());
        else
          return it;
      };

      accumulate(mHetTrans.begin(), mHetTrans.end(), it, checkAndConvert);
    }

    /** \brief find attribute transforms leading directly to goal
     *  \param goal the goal EventType
     *  \param ids available EventIDs
     *  \return a list of fully configured transformations leading to the goal EventType
     *  \todo enable composite transforms
     **/
    void findAttrTrans(const EventType& goal, const EventIDs& ids, OutIt it) const {

      EventIDs comp = extractIDs(EventID(goal), ids);
      if(!comp.size())
        return;

      for( EventID id : comp)
        for( const EventType& type : mTypes.find(id)) {
          auto toConfTrans = [&type](const Transformation* t){ return ConfiguredTransformation(*t, type); };
          transform(mAttrTrans.begin(), mAttrTrans.end(), it, toConfTrans);
      }
    }

  public:
    void regTrans(const Transformation& trans) {
      if(trans==Transformation::invalid)
        return;
      TransStorage& storage = (trans.out() == EventID::any)?mAttrTrans:mHetTrans;
      if(count(storage.begin(), storage.end(), &trans))
        return;
      storage.push_back(&trans);
    }

    void unregTrans(const Transformation& trans) {
      TransStorage& storage = (trans.out() == EventID::any)?mAttrTrans:mHetTrans;
      auto it = remove(storage.begin(), storage.end(), &trans);
      storage.erase(it, storage.end());
    }

    void regType(const EventType& eT) {
      mTypes.registerType(eT, eT);
    }

    void unregType(const EventType& eT) {
      mTypes.unregisterType(eT);
    }

    /** \brief Find Composite Transformations for EventType
     *  \param goal the output of the Transformations
     *  \return a list of ConfigureTransformation
     *  \todo Add homogeneus transforms
     *  \todo enable composite transforms
     **/
    Transformations find(const EventType& goal) {
      EventIDs ids = mTypes.ids();
      sort(ids.begin(), ids.end()); //<< Sort EventIDs ascending

      Transformations temp;
      Transformations result;

      findHetTrans(goal, ids, back_inserter(temp));
      findAttrTrans(goal, ids, back_inserter(temp));

      for(const ConfiguredTransformation& confTrans : temp)
        generateAll(confTrans, ids, back_inserter(result));

      auto it = remove_if(result.begin(), result.end(),
                          [](const ConfiguredTransformation& t){ return !t.check(); }
                );
      result.erase(it, result.end());

      return result;
    }

    void clear() {
      mTypes.clear();
    }
};

using KB = Singleton<KBImpl>;

void KnowledgeBase::registerTransformation(const Transformation& trans) {
  KB::instance().regTrans(trans);
}

void KnowledgeBase::unregisterTransformation(const Transformation& trans) {
  KB::instance().unregTrans(trans);
}

void KnowledgeBase::registerEventType(const EventType& trans) {
  KB::instance().regType(trans);
}

void KnowledgeBase::unregisterEventType(const EventType& trans) {
  KB::instance().unregType(trans);
}

KnowledgeBase::Transformations KnowledgeBase::findTransforms(const EventType& goal) {
  return KB::instance().find(goal);
}

void KnowledgeBase::clear() {
  KB::instance().clear();
}
<commit_msg>KnowledgeBase: fix search algorithm<commit_after>#include <KnowledgeBase.h>
#include <TypeRegistry.h>

#include <Singleton.h>

#include <vector>
#include <algorithm>
#include <numeric>

using namespace std;

class KBImpl {
  public:
    using TransStorage = std::vector<const Transformation*>;
    using TypeStorage  = AbstractRegistry<EventType>;
    using Transformations = KnowledgeBase::Transformations;
    using EventIDs = TypeStorage::EventIDs;
    using EventTypes = Transformation::EventTypes;

  private:
    using OutIt = back_insert_iterator<Transformations>;
    using TypeOutIt = back_insert_iterator<EventTypes>;
    TransStorage mHetTrans;
    TransStorage mAttrTrans;
    TypeStorage  mTypes;

    EventIDs extractIDs(EventID goal, const EventIDs& ids) const {
      EventIDs result;
      auto start = lower_bound(ids.begin(), ids.end(), goal);
      copy_if(start, ids.end(), back_inserter(result), [&goal](EventID id){ return id>=goal; });

      return result;
    }

    void addValidTypes(EventID id, TypeOutIt it) const {
      transform(mTypes.find(id).first, mTypes.find(id).second, it, [](const EventType& eT){ return &eT;});
    }

    vector<EventTypes> generateTypeLists(const EventIDs& in, const EventIDs& ids) const{
      //Extract IDs
      vector<EventTypes> result(in.size());
      for(unsigned int i=0; i < in.size(); i++) {
        addValidTypes(in[i], back_inserter(result[i]));
        if(!result[i].size())
          break;
      }
      return result;
    }

    vector<EventTypes> generateCombinations(const vector<EventTypes>& typeLists) const {
      if(typeLists.empty())
        return vector<EventTypes>();

      size_t size = accumulate(typeLists.begin(), typeLists.end(), 1UL, [](size_t size, const EventTypes& tL){ return size*tL.size(); });

      if(!size)
        return vector<EventTypes>();

      vector<EventTypes> result(size);
      for(size_t i=0; i<size; i++)
        result[i].resize(typeLists.size());

      size_t currSize=size;
      size_t oldSize = 1;
      for(size_t i=0; i < typeLists.size(); i++) {
        for(size_t m=0; m < oldSize; m++)
          for(size_t j=0; j < typeLists[i].size(); j++) {
            currSize /= typeLists[i].size();
            for(size_t k=0; k < currSize; k++)
              result[j*currSize+k][i] = typeLists[i][j];
          }
        oldSize = typeLists[i].size();
      }
      return result;
    }

    void generateAll(const ConfiguredTransformation& trans, const EventIDs& ids, OutIt it) const {
      vector<EventTypes> usableEventTypes = generateTypeLists(trans.inIDs(), ids);
      vector<EventTypes> typeCombinations = generateCombinations(usableEventTypes);
      auto create = [trans](const EventTypes& in){
        ConfiguredTransformation t(trans);
        t.in(in);
        return t;
      };
      transform(typeCombinations.begin(), typeCombinations.end(), it, create);
    }

    /** \brief create fitting composite transformation for goal EventID
     * \param trans all existing heterogeneus transformations
     * \param goal the EventID of the goal
     * \param all existing published EventIDs
     * \return a list of fitting heterogeneus (composite) transformations
     * \todo filter on input eventids
     * \todo generate composite transformations
     **/
    void findHetTrans(const EventType& goal, const EventIDs& ids, OutIt it) const {
      auto checkAndConvert = [&goal, &ids](OutIt it, const Transformation* t){
        if (t && EventID(goal) <= t->out() )
          return *it++ = ConfiguredTransformation(*t, goal);// || !includes(tIn.begin(), tIn.end(), ids.begin(), ids.end());
        else
          return it;
      };

      accumulate(mHetTrans.begin(), mHetTrans.end(), it, checkAndConvert);
    }

    /** \brief find attribute transforms leading directly to goal
     *  \param goal the goal EventType
     *  \param ids available EventIDs
     *  \return a list of fully configured transformations leading to the goal EventType
     *  \todo enable composite transforms
     **/
    void findAttrTrans(const EventType& goal, const EventIDs& ids, OutIt it) const {

      EventIDs comp = extractIDs(EventID(goal), ids);
      if(!comp.size())
        return;

      auto toConfTrans = [&goal](const Transformation* t){ return ConfiguredTransformation(*t, goal); };
      transform(mAttrTrans.begin(), mAttrTrans.end(), it, toConfTrans);
    }

  public:
    void regTrans(const Transformation& trans) {
      if(trans==Transformation::invalid)
        return;
      TransStorage& storage = (trans.out() == EventID::any)?mAttrTrans:mHetTrans;
      if(count(storage.begin(), storage.end(), &trans))
        return;
      storage.push_back(&trans);
    }

    void unregTrans(const Transformation& trans) {
      TransStorage& storage = (trans.out() == EventID::any)?mAttrTrans:mHetTrans;
      auto it = remove(storage.begin(), storage.end(), &trans);
      storage.erase(it, storage.end());
    }

    void regType(const EventType& eT) {
      mTypes.registerType(eT, eT);
    }

    void unregType(const EventType& eT) {
      mTypes.unregisterType(eT);
    }

    /** \brief Find Composite Transformations for EventType
     *  \param goal the output of the Transformations
     *  \return a list of ConfigureTransformation
     *  \todo Add homogeneus transforms
     *  \todo enable composite transforms
     **/
    Transformations find(const EventType& goal) {
      EventIDs ids = mTypes.ids();
      sort(ids.begin(), ids.end()); //<< Sort EventIDs ascending

      Transformations temp;
      Transformations result;

      findHetTrans(goal, ids, back_inserter(temp));
      findAttrTrans(goal, ids, back_inserter(temp));

      for(const ConfiguredTransformation& confTrans : temp)
        generateAll(confTrans, ids, back_inserter(result));

      auto it = remove_if(result.begin(), result.end(),
                          [](const ConfiguredTransformation& t){ return !t.check(); }
                );
      result.erase(it, result.end());

      return result;
    }

    void clear() {
      mTypes.clear();
    }
};

using KB = Singleton<KBImpl>;

void KnowledgeBase::registerTransformation(const Transformation& trans) {
  KB::instance().regTrans(trans);
}

void KnowledgeBase::unregisterTransformation(const Transformation& trans) {
  KB::instance().unregTrans(trans);
}

void KnowledgeBase::registerEventType(const EventType& trans) {
  KB::instance().regType(trans);
}

void KnowledgeBase::unregisterEventType(const EventType& trans) {
  KB::instance().unregType(trans);
}

KnowledgeBase::Transformations KnowledgeBase::findTransforms(const EventType& goal) {
  return KB::instance().find(goal);
}

void KnowledgeBase::clear() {
  KB::instance().clear();
}
<|endoftext|>


<commit_before>// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t
// RUN: rm -rf %T/coverage-fork-direct
// RUN: mkdir -p %T/coverage-fork-direct && cd %T/coverage-fork-direct
// RUN: %env_asan_opts=coverage=1:coverage_direct=1:verbosity=1 %run %t > %t.log 2>&1
// RUN: %sancov rawunpack *.sancov.raw
// RUN: %sancov print *.sancov >> %t.log 2>&1
// RUN: FileCheck %s < %t.log
//
// XFAIL: android

#include <stdio.h>
#include <string.h>
#include <unistd.h>

__attribute__((noinline))
void foo() { printf("foo\n"); }

__attribute__((noinline))
void bar() { printf("bar\n"); }

__attribute__((noinline))
void baz() { printf("baz\n"); }

int main(int argc, char **argv) {
  pid_t child_pid = fork();
  if (child_pid == 0) {
    fprintf(stderr, "Child PID: %d\n", getpid());
    baz();
  } else {
    fprintf(stderr, "Parent PID: %d\n", getpid());
    foo();
    bar();
  }
  return 0;
}

// CHECK-DAG: Child PID: [[ChildPID:[0-9]+]]
// CHECK-DAG: Parent PID: [[ParentPID:[0-9]+]]
// CHECK-DAG: read 3 64-bit PCs from {{.*}}.[[ParentPID]].sancov

// FIXME: this is missing
// XCHECK-DAG: read 1 64-bit PCs from {{.*}}.[[ChildPID]].sancov
<commit_msg>Also match the output on 32 bit systems.<commit_after>// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t
// RUN: rm -rf %T/coverage-fork-direct
// RUN: mkdir -p %T/coverage-fork-direct && cd %T/coverage-fork-direct
// RUN: %env_asan_opts=coverage=1:coverage_direct=1:verbosity=1 %run %t > %t.log 2>&1
// RUN: %sancov rawunpack *.sancov.raw
// RUN: %sancov print *.sancov >> %t.log 2>&1
// RUN: FileCheck %s < %t.log
//
// XFAIL: android

#include <stdio.h>
#include <string.h>
#include <unistd.h>

__attribute__((noinline))
void foo() { printf("foo\n"); }

__attribute__((noinline))
void bar() { printf("bar\n"); }

__attribute__((noinline))
void baz() { printf("baz\n"); }

int main(int argc, char **argv) {
  pid_t child_pid = fork();
  if (child_pid == 0) {
    fprintf(stderr, "Child PID: %d\n", getpid());
    baz();
  } else {
    fprintf(stderr, "Parent PID: %d\n", getpid());
    foo();
    bar();
  }
  return 0;
}

// CHECK-DAG: Child PID: [[ChildPID:[0-9]+]]
// CHECK-DAG: Parent PID: [[ParentPID:[0-9]+]]
// CHECK-DAG: read 3 {{64|32}}-bit PCs from {{.*}}.[[ParentPID]].sancov

// FIXME: this is missing
// XCHECK-DAG: read 1 {{64|32}}-bit PCs from {{.*}}.[[ChildPID]].sancov
<|endoftext|>


<commit_before>/*
 E. Defining Macros
 time limit per test3 seconds
 memory limit per test256 megabytes
 inputstandard input
 outputstandard output
 Most C/C++ programmers know about excellent opportunities that preprocessor #define directives give; but many know as well about the problems that can arise because of their careless use.

 In this problem we consider the following model of #define constructions (also called macros). Each macro has its name and value. The generic syntax for declaring a macro is the following:

#define macro_name macro_value

 After the macro has been declared, "macro_name" is replaced with "macro_value" each time it is met in the program (only the whole tokens can be replaced; i.e. "macro_name" is replaced only when it is surrounded by spaces or other non-alphabetic symbol). A "macro_value" within our model can only be an arithmetic expression consisting of variables, four arithmetic operations, brackets, and also the names of previously declared macros (in this case replacement is performed sequentially). The process of replacing macros with their values is called substitution.

 One of the main problems arising while using macros — the situation when as a result of substitution we get an arithmetic expression with the changed order of calculation because of different priorities of the operations.

 Let's consider the following example. Say, we declared such a #define construction:

#define sum x + y

 and further in the program the expression "2 * sum" is calculated. After macro substitution is performed we get "2 * x + y", instead of intuitively expected "2 * (x + y)".

 Let's call the situation "suspicious", if after the macro substitution the order of calculation changes, falling outside the bounds of some macro. Thus, your task is to find out by the given set of #define definitions and the given expression if this expression is suspicious or not.

 Let's speak more formally. We should perform an ordinary macros substitution in the given expression. Moreover, we should perform a "safe" macros substitution in the expression, putting in brackets each macro value; after this, guided by arithmetic rules of brackets expansion, we can omit some of the brackets. If there exist a way to get an expression, absolutely coinciding with the expression that is the result of an ordinary substitution (character-by-character, but ignoring spaces), then this expression and the macros system are called correct, otherwise — suspicious.

 Note that we consider the "/" operation as the usual mathematical division, not the integer division like in C/C++. That's why, for example, in the expression "a*(b/c)" we can omit brackets to get the expression "a*b/c".

 Input
 The first line contains the only number n (0 ≤ n ≤ 100) — the amount of #define constructions in the given program.

 Then there follow n lines, each of them contains just one #define construction. Each construction has the following syntax:

#define name expression

 where

 name — the macro name,
 expression — the expression with which the given macro will be replaced. An expression is a non-empty string, containing digits,names of variables, names of previously declared macros, round brackets and operational signs +- * /. It is guaranteed that the expression (before and after macros substitution) is a correct arithmetic expression, having no unary operations. The expression contains only non-negative integers, not exceeding 109.
All the names (#define constructions' names and names of their arguments) are strings of case-sensitive Latin characters. It is guaranteed that the name of any variable is different from any #define construction.

Then, the last line contains an expression that you are to check. This expression is non-empty and satisfies the same limitations as the expressions in #define constructions.

The input lines may contain any number of spaces anywhere, providing these spaces do not break the word "define" or the names of constructions and variables. In particular, there can be any number of spaces before and after the "#" symbol.

The length of any line from the input file does not exceed 100 characters.

Output
Output "OK", if the expression is correct according to the above given criterion, otherwise output "Suspicious".

Examples
input
#define sum x + y
1 * sum
output
Suspicious

input
1
#define sum  (x + y)
sum - sum
output
OK

input
4
#define sum  x + y
#define mul  a * b
#define div  a / b
#define expr sum + mul * div * mul
expr

output
OK

input
3
#define SumSafe   (a+b)
#define DivUnsafe  a/b
#define DenominatorUnsafe  a*b
((SumSafe) + DivUnsafe/DivUnsafe + x/DenominatorUnsafe)
output
Suspicious

 * */

/*
 * state value description
 *
 *  s1     0     invalid
 *  s2     1     invalid when connected by * / or be second op of -
 *  s3     2     invalid when be second op of /
 *  s4     3     valid
 *
 * State transition rules
 *
 * let t be (t1)
 *  t1 != s1 -> t = s4
 *  otherwise -> t = s1
 *
 *let t be t1 op t2
 *
 * t1 || t2 = s1, -> t = s1
 *
 * op = +
 *    t -> s2
 * op = -
 *    t2 = s2 ->t = s1
 *    otherwise t -> s2
 * op = *
 *   t1 = s2 || t2 = s2 || t2 = s3 t-> s1
 *   otherwise t-> s3
 * op = /
 *   t2 = s3 t-> s1
 *   otherwise t-> s3
 *
 * */

#include <stdio.h>

#include <iostream>
#include <string>
#include <map>

using namespace std;
string s;
map<string, int> res;

int eval(int l, int r) {
    for (int i = l, w = 0; i < r; i++) {
        if (s[i] == '(') w++;
        else if (s[i] == ')') w--;
        if (w == 0 && (s[i] == '+' || s[i] == '-')) {
            int L = eval(l, i), R = eval(i+1, r);
            return L && R && (s[i] != '-' || R > 1);
        }
        if (w == 0 && (s[i] == '*' || s[i] == '/')) {
            int L = eval(l, i), R = eval(i+1, r);
            return (L>1) && (R > 1) && (s[i] != '/' || R > 2) ? 2 : 0;
        }
    }
    if (s[0] == '(') {
        return eval(l+1, r-1) ? 3 : 0;
    }
    string u(s.substr(l, r-l));
    return res[u] ? res[u] : 3;
}

int G() {
    string tmp;
    getline(cin, tmp);
    s = "";
    int m = 0;
    for (int i = 0; i < tmp.size(); i++) {
        if (tmp[i] != ' ') {
            s += tmp[i];
        }
    }
    return eval(0, s.size());
}

int main() {
    int n;
    cin >> n;
    string dummy;
    string name;
    for (int i = 0; i < n; i++) {
        cin >> dummy;
        cin >> name;
        res[name] = G();
    }

    cout << (G() ? "OK" : "Suspicious");

    return 0;
}

<commit_msg>fix cf 7e<commit_after>/*
 E. Defining Macros
 time limit per test3 seconds
 memory limit per test256 megabytes
 inputstandard input
 outputstandard output
 Most C/C++ programmers know about excellent opportunities that preprocessor #define directives give; but many know as well about the problems that can arise because of their careless use.

 In this problem we consider the following model of #define constructions (also called macros). Each macro has its name and value. The generic syntax for declaring a macro is the following:

#define macro_name macro_value

 After the macro has been declared, "macro_name" is replaced with "macro_value" each time it is met in the program (only the whole tokens can be replaced; i.e. "macro_name" is replaced only when it is surrounded by spaces or other non-alphabetic symbol). A "macro_value" within our model can only be an arithmetic expression consisting of variables, four arithmetic operations, brackets, and also the names of previously declared macros (in this case replacement is performed sequentially). The process of replacing macros with their values is called substitution.

 One of the main problems arising while using macros — the situation when as a result of substitution we get an arithmetic expression with the changed order of calculation because of different priorities of the operations.

 Let's consider the following example. Say, we declared such a #define construction:

#define sum x + y

 and further in the program the expression "2 * sum" is calculated. After macro substitution is performed we get "2 * x + y", instead of intuitively expected "2 * (x + y)".

 Let's call the situation "suspicious", if after the macro substitution the order of calculation changes, falling outside the bounds of some macro. Thus, your task is to find out by the given set of #define definitions and the given expression if this expression is suspicious or not.

 Let's speak more formally. We should perform an ordinary macros substitution in the given expression. Moreover, we should perform a "safe" macros substitution in the expression, putting in brackets each macro value; after this, guided by arithmetic rules of brackets expansion, we can omit some of the brackets. If there exist a way to get an expression, absolutely coinciding with the expression that is the result of an ordinary substitution (character-by-character, but ignoring spaces), then this expression and the macros system are called correct, otherwise — suspicious.

 Note that we consider the "/" operation as the usual mathematical division, not the integer division like in C/C++. That's why, for example, in the expression "a*(b/c)" we can omit brackets to get the expression "a*b/c".

 Input
 The first line contains the only number n (0 ≤ n ≤ 100) — the amount of #define constructions in the given program.

 Then there follow n lines, each of them contains just one #define construction. Each construction has the following syntax:

#define name expression

 where

 name — the macro name,
 expression — the expression with which the given macro will be replaced. An expression is a non-empty string, containing digits,names of variables, names of previously declared macros, round brackets and operational signs +- * /. It is guaranteed that the expression (before and after macros substitution) is a correct arithmetic expression, having no unary operations. The expression contains only non-negative integers, not exceeding 109.
All the names (#define constructions' names and names of their arguments) are strings of case-sensitive Latin characters. It is guaranteed that the name of any variable is different from any #define construction.

Then, the last line contains an expression that you are to check. This expression is non-empty and satisfies the same limitations as the expressions in #define constructions.

The input lines may contain any number of spaces anywhere, providing these spaces do not break the word "define" or the names of constructions and variables. In particular, there can be any number of spaces before and after the "#" symbol.

The length of any line from the input file does not exceed 100 characters.

Output
Output "OK", if the expression is correct according to the above given criterion, otherwise output "Suspicious".

Examples
input
#define sum x + y
1 * sum
output
Suspicious

input
1
#define sum  (x + y)
sum - sum
output
OK

input
4
#define sum  x + y
#define mul  a * b
#define div  a / b
#define expr sum + mul * div * mul
expr

output
OK

input
3
#define SumSafe   (a+b)
#define DivUnsafe  a/b
#define DenominatorUnsafe  a*b
((SumSafe) + DivUnsafe/DivUnsafe + x/DenominatorUnsafe)
output
Suspicious

 * */

/*
 * state value description
 *
 *  s1     0     invalid
 *  s2     1     invalid when connected by * / or be second op of -
 *  s3     2     invalid when be second op of /
 *  s4     3     valid
 *
 * State transition rules
 *
 * let t be (t1)
 *  t1 != s1 -> t = s4
 *  otherwise -> t = s1
 *
 *let t be t1 op t2
 *
 * t1 || t2 = s1, -> t = s1
 *
 * op = +
 *    t -> s2
 * op = -
 *    t2 = s2 ->t = s1
 *    otherwise t -> s2
 * op = *
 *   t1 = s2 || t2 = s2 || t2 = s3 t-> s1
 *   otherwise t-> s3
 * op = /
 *   t2 = s3 t-> s1
 *   otherwise t-> s3
 *
 * */

#include <stdio.h>

#include <iostream>
#include <string>
#include <map>

using namespace std;
string s;
map<string, int> res;

int eval(int l, int r) {
    int w = 0;
    for (int i = l; i < r; i++) {
        //printf("i = %d, s[%d]=%c w=%d\n", i, i, s[i], w);
        if (s[i] == '(') w++;
        else if (s[i] == ')') w--;
        if (w == 0 && (s[i] == '+' || s[i] == '-')) {
            int L = eval(l, i), R = eval(i+1, r);
            return L && R && (s[i] != '-' || R > 1);
        }
        if (w == 0 && (s[i] == '*' || s[i] == '/')) {
            int L = eval(l, i), R = eval(i+1, r);
            return (L>1) && (R > 1) && (s[i] != '/' || R > 2) ? 2 : 0;
        }
    }
    if (s[l] == '(') {
        return eval(l+1, r-1) ? 3 : 0;
    }
    string u(s.substr(l, r-l));
    return res[u] ? res[u] : 3;
}

int G() {
    string tmp;
    getline(cin, tmp);
    s = "";
    int m = 0;
    for (int i = 0; i < tmp.size(); i++) {
        if (tmp[i] != ' ') {
            s += tmp[i];
        }
    }
    return eval(0, s.size());
}

int main() {
    int n;
    cin >> n;
    string dummy;
    string name;
    for (int i = 0; i < n; i++) {
        cin >> dummy;
        cin >> name;
        res[name] = G();
    }

    cout << (G() ? "OK" : "Suspicious");

    return 0;
}

<|endoftext|>


<commit_before>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/Interpreter/InvocationOptions.h"
#include "cling/Interpreter/ClingOptions.h"

#include "clang/Driver/Options.h"

#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/raw_ostream.h"

#include <memory>

using namespace clang;
using namespace clang::driver;

using namespace llvm;
using namespace llvm::opt;

using namespace cling;
using namespace cling::driver::clingoptions;

namespace {

#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
               HELPTEXT, METAVAR)
#include "cling/Interpreter/ClingOptions.inc"
#undef OPTION
#undef PREFIX

  static const OptTable::Info ClingInfoTable[] = {
#define PREFIX(NAME, VALUE)
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
               HELPTEXT, METAVAR)   \
  { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
    FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
#include "cling/Interpreter/ClingOptions.inc"
#undef OPTION
#undef PREFIX
  };

  class ClingOptTable : public OptTable {
  public:
    ClingOptTable()
      : OptTable(ClingInfoTable) {}
  };

  static OptTable* CreateClingOptTable() {
    return new ClingOptTable();
  }

  static void ParseStartupOpts(cling::InvocationOptions& Opts,
                               InputArgList& Args) {
    Opts.ErrorOut = Args.hasArg(OPT__errorout);
    Opts.NoLogo = Args.hasArg(OPT__nologo);
    Opts.ShowVersion = Args.hasArg(OPT_version);
    Opts.Help = Args.hasArg(OPT_help);
    if (Args.hasArg(OPT__metastr, OPT__metastr_EQ)) {
      Arg* MetaStringArg = Args.getLastArg(OPT__metastr, OPT__metastr_EQ);
      Opts.MetaString = MetaStringArg->getValue();
      if (Opts.MetaString.length() == 0) {
        llvm::errs() << "ERROR: meta string must be non-empty! Defaulting to '.'.\n";
        Opts.MetaString = ".";
      }
    }
  }

  static void Extend(std::vector<std::string>& A, std::vector<std::string> B) {
    A.reserve(A.size()+B.size());
    for (std::string& Val: B)
      A.push_back(std::move(Val));
  }

  static void ParseLinkerOpts(cling::InvocationOptions& Opts,
                              InputArgList& Args /* , Diags */) {
    Extend(Opts.LibsToLoad, Args.getAllArgValues(OPT_l));
    Extend(Opts.LibSearchPath, Args.getAllArgValues(OPT_L));
  }
}

CompilerOptions::CompilerOptions(int argc, const char* const* argv) :
  Language(false), ResourceDir(false), SysRoot(false), NoBuiltinInc(false),
  NoCXXInc(false), StdVersion(false), StdLib(false), Verbose(false) {
  if (argc && argv) {
    // Preserve what's already in Remaining, the user might want to push args
    // to clang while still using main's argc, argv
    // insert should/usually does call reserve, but its not part of the standard
    Remaining.reserve(Remaining.size() + argc);
    Remaining.insert(Remaining.end(), argv, argv+argc);
    Parse(argc, argv);
  }
}

void CompilerOptions::Parse(int argc, const char* const argv[],
                            std::vector<std::string>* Inputs) {
  unsigned MissingArgIndex, MissingArgCount;
  std::unique_ptr<OptTable> OptsC1(createDriverOptTable());
  ArrayRef<const char *> ArgStrings(argv+1, argv + argc);

  InputArgList Args(OptsC1->ParseArgs(ArgStrings, MissingArgIndex,
                    MissingArgCount, 0,
                    options::NoDriverOption | options::CLOption));

  for (const Arg* arg : Args) {
    switch (arg->getOption().getID()) {
      // case options::OPT_d_Flag:
      // case options::OPT_E:
      // case options::OPT_o: HasOuptut = true; break;
      case options::OPT_x: Language = true; break;
      case options::OPT_resource_dir: ResourceDir = true; break;
      case options::OPT_isysroot: SysRoot = true; break;
      case options::OPT_std_EQ: StdVersion = true; break;
      case options::OPT_stdlib_EQ: StdLib = true; break;
      // case options::OPT_nostdlib:
      case options::OPT_nobuiltininc: NoBuiltinInc = true; break;
      // case options::OPT_nostdinc:
      case options::OPT_nostdincxx: NoCXXInc = true; break;
      case options::OPT_v: Verbose = true; break;

      default:
        if (Inputs && arg->getOption().getKind() == Option::InputClass)
          Inputs->push_back(arg->getValue());
        break;
    }
  }
}

InvocationOptions::InvocationOptions(int argc, const char* const* argv) :
  MetaString("."), ErrorOut(false), NoLogo(false), ShowVersion(false),
  Help(false) {

  ArrayRef<const char *> ArgStrings(argv, argv + argc);
  unsigned MissingArgIndex, MissingArgCount;
  std::unique_ptr<OptTable> Opts(CreateClingOptTable());

  InputArgList Args(Opts->ParseArgs(ArgStrings, MissingArgIndex,
                    MissingArgCount, 0,
                    options::NoDriverOption | options::CLOption));

  // Forward unknown arguments.
  for (const Arg* arg : Args) {
    switch (arg->getOption().getKind()) {
      case Option::FlagClass:
        // pass -v to clang as well
        if (arg->getOption().getID() != OPT_v)
          break;
      case Option::UnknownClass:
      case Option::InputClass:
        // prune "-" we need to control where it appears when invoking clang
        if (!arg->getSpelling().equals("-"))
          CompilerOpts.Remaining.push_back(argv[arg->getIndex()]);
      default:
        break;
    }
  }

  // Get Input list and any compiler specific flags we're interested in
  CompilerOpts.Parse(argc, argv, &Inputs);

  ParseStartupOpts(*this, Args);
  ParseLinkerOpts(*this, Args);
}

void InvocationOptions::PrintHelp() {
  std::unique_ptr<OptTable> Opts(CreateClingOptTable());

  Opts->PrintHelp(llvm::outs(), "cling",
                  "cling: LLVM/clang C++ Interpreter: http://cern.ch/cling");

  llvm::outs() << "\n\n";

  std::unique_ptr<OptTable> OptsC1(createDriverOptTable());
  OptsC1->PrintHelp(llvm::outs(), "clang -cc1",
                    "LLVM 'Clang' Compiler: http://clang.llvm.org");
}
<commit_msg>Fix Coverity CID68726 - potential null deref.<commit_after>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/Interpreter/InvocationOptions.h"
#include "cling/Interpreter/ClingOptions.h"

#include "clang/Driver/Options.h"

#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/raw_ostream.h"

#include <memory>

using namespace clang;
using namespace clang::driver;

using namespace llvm;
using namespace llvm::opt;

using namespace cling;
using namespace cling::driver::clingoptions;

namespace {

#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
               HELPTEXT, METAVAR)
#include "cling/Interpreter/ClingOptions.inc"
#undef OPTION
#undef PREFIX

  static const OptTable::Info ClingInfoTable[] = {
#define PREFIX(NAME, VALUE)
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
               HELPTEXT, METAVAR)   \
  { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
    FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
#include "cling/Interpreter/ClingOptions.inc"
#undef OPTION
#undef PREFIX
  };

  class ClingOptTable : public OptTable {
  public:
    ClingOptTable()
      : OptTable(ClingInfoTable) {}
  };

  static OptTable* CreateClingOptTable() {
    return new ClingOptTable();
  }

  static void ParseStartupOpts(cling::InvocationOptions& Opts,
                               InputArgList& Args) {
    Opts.ErrorOut = Args.hasArg(OPT__errorout);
    Opts.NoLogo = Args.hasArg(OPT__nologo);
    Opts.ShowVersion = Args.hasArg(OPT_version);
    Opts.Help = Args.hasArg(OPT_help);
    if (Args.hasArg(OPT__metastr, OPT__metastr_EQ)) {
      if (Arg* MetaStringArg = Args.getLastArg(OPT__metastr, OPT__metastr_EQ))
        Opts.MetaString = MetaStringArg->getValue();
      else
        Opts.MetaString.clear();
      if (Opts.MetaString.empty()) {
        llvm::errs() << "ERROR: meta string must be non-empty! Defaulting to '.'.\n";
        Opts.MetaString = ".";
      }
    }
  }

  static void Extend(std::vector<std::string>& A, std::vector<std::string> B) {
    A.reserve(A.size()+B.size());
    for (std::string& Val: B)
      A.push_back(std::move(Val));
  }

  static void ParseLinkerOpts(cling::InvocationOptions& Opts,
                              InputArgList& Args /* , Diags */) {
    Extend(Opts.LibsToLoad, Args.getAllArgValues(OPT_l));
    Extend(Opts.LibSearchPath, Args.getAllArgValues(OPT_L));
  }
}

CompilerOptions::CompilerOptions(int argc, const char* const* argv) :
  Language(false), ResourceDir(false), SysRoot(false), NoBuiltinInc(false),
  NoCXXInc(false), StdVersion(false), StdLib(false), Verbose(false) {
  if (argc && argv) {
    // Preserve what's already in Remaining, the user might want to push args
    // to clang while still using main's argc, argv
    // insert should/usually does call reserve, but its not part of the standard
    Remaining.reserve(Remaining.size() + argc);
    Remaining.insert(Remaining.end(), argv, argv+argc);
    Parse(argc, argv);
  }
}

void CompilerOptions::Parse(int argc, const char* const argv[],
                            std::vector<std::string>* Inputs) {
  unsigned MissingArgIndex, MissingArgCount;
  std::unique_ptr<OptTable> OptsC1(createDriverOptTable());
  ArrayRef<const char *> ArgStrings(argv+1, argv + argc);

  InputArgList Args(OptsC1->ParseArgs(ArgStrings, MissingArgIndex,
                    MissingArgCount, 0,
                    options::NoDriverOption | options::CLOption));

  for (const Arg* arg : Args) {
    switch (arg->getOption().getID()) {
      // case options::OPT_d_Flag:
      // case options::OPT_E:
      // case options::OPT_o: HasOuptut = true; break;
      case options::OPT_x: Language = true; break;
      case options::OPT_resource_dir: ResourceDir = true; break;
      case options::OPT_isysroot: SysRoot = true; break;
      case options::OPT_std_EQ: StdVersion = true; break;
      case options::OPT_stdlib_EQ: StdLib = true; break;
      // case options::OPT_nostdlib:
      case options::OPT_nobuiltininc: NoBuiltinInc = true; break;
      // case options::OPT_nostdinc:
      case options::OPT_nostdincxx: NoCXXInc = true; break;
      case options::OPT_v: Verbose = true; break;

      default:
        if (Inputs && arg->getOption().getKind() == Option::InputClass)
          Inputs->push_back(arg->getValue());
        break;
    }
  }
}

InvocationOptions::InvocationOptions(int argc, const char* const* argv) :
  MetaString("."), ErrorOut(false), NoLogo(false), ShowVersion(false),
  Help(false) {

  ArrayRef<const char *> ArgStrings(argv, argv + argc);
  unsigned MissingArgIndex, MissingArgCount;
  std::unique_ptr<OptTable> Opts(CreateClingOptTable());

  InputArgList Args(Opts->ParseArgs(ArgStrings, MissingArgIndex,
                    MissingArgCount, 0,
                    options::NoDriverOption | options::CLOption));

  // Forward unknown arguments.
  for (const Arg* arg : Args) {
    switch (arg->getOption().getKind()) {
      case Option::FlagClass:
        // pass -v to clang as well
        if (arg->getOption().getID() != OPT_v)
          break;
      case Option::UnknownClass:
      case Option::InputClass:
        // prune "-" we need to control where it appears when invoking clang
        if (!arg->getSpelling().equals("-"))
          CompilerOpts.Remaining.push_back(argv[arg->getIndex()]);
      default:
        break;
    }
  }

  // Get Input list and any compiler specific flags we're interested in
  CompilerOpts.Parse(argc, argv, &Inputs);

  ParseStartupOpts(*this, Args);
  ParseLinkerOpts(*this, Args);
}

void InvocationOptions::PrintHelp() {
  std::unique_ptr<OptTable> Opts(CreateClingOptTable());

  Opts->PrintHelp(llvm::outs(), "cling",
                  "cling: LLVM/clang C++ Interpreter: http://cern.ch/cling");

  llvm::outs() << "\n\n";

  std::unique_ptr<OptTable> OptsC1(createDriverOptTable());
  OptsC1->PrintHelp(llvm::outs(), "clang -cc1",
                    "LLVM 'Clang' Compiler: http://clang.llvm.org");
}
<|endoftext|>


<commit_before>//===--- ParentMap.cpp - Mappings from Stmts to their Parents ---*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the ParentMap class.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/ParentMap.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "llvm/ADT/DenseMap.h"

using namespace clang;

typedef llvm::DenseMap<Stmt*, Stmt*> MapTy;

static void BuildParentMap(MapTy& M, Stmt* S) {
  for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
    if (*I) {
      M[*I] = S;
      BuildParentMap(M, *I);
    }
}

ParentMap::ParentMap(Stmt* S) : Impl(0) {
  if (S) {
    MapTy *M = new MapTy();
    BuildParentMap(*M, S);
    Impl = M;
  }
}

ParentMap::~ParentMap() {
  delete (MapTy*) Impl;
}

Stmt* ParentMap::getParent(Stmt* S) const {
  MapTy* M = (MapTy*) Impl;
  MapTy::iterator I = M->find(S);
  return I == M->end() ? 0 : I->second;
}

bool ParentMap::isConsumedExpr(Expr* E) const {
  Stmt *P = getParent(E);
  Stmt *DirectChild = E;

  // Ignore parents that are parentheses or casts.
  while (P && (isa<ParenExpr>(E) || isa<CastExpr>(E))) {
    DirectChild = P;
    P = getParent(P);
  }

  if (!P)
    return false;

  switch (P->getStmtClass()) {
    default:
      return isa<Expr>(P);
    case Stmt::DeclStmtClass:
      return true;
    case Stmt::BinaryOperatorClass: {
      BinaryOperator *BE = cast<BinaryOperator>(P);
      // If it is a comma, only the left side is consumed.
      // If it isn't a comma, both sides are consumed.
      return BE->getOpcode()!=BinaryOperator::Comma || DirectChild==BE->getLHS();
    }
    case Stmt::ForStmtClass:
      return DirectChild == cast<ForStmt>(P)->getCond();
    case Stmt::WhileStmtClass:
      return DirectChild == cast<WhileStmt>(P)->getCond();
    case Stmt::DoStmtClass:
      return DirectChild == cast<DoStmt>(P)->getCond();
    case Stmt::IfStmtClass:
      return DirectChild == cast<IfStmt>(P)->getCond();
    case Stmt::IndirectGotoStmtClass:
      return DirectChild == cast<IndirectGotoStmt>(P)->getTarget();
    case Stmt::SwitchStmtClass:
      return DirectChild == cast<SwitchStmt>(P)->getCond();
    case Stmt::ReturnStmtClass:
      return true;
  }
}

<commit_msg>Another ParentMap bug: only the right side of a comma expression is consumed.<commit_after>//===--- ParentMap.cpp - Mappings from Stmts to their Parents ---*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines the ParentMap class.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/ParentMap.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "llvm/ADT/DenseMap.h"

using namespace clang;

typedef llvm::DenseMap<Stmt*, Stmt*> MapTy;

static void BuildParentMap(MapTy& M, Stmt* S) {
  for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
    if (*I) {
      M[*I] = S;
      BuildParentMap(M, *I);
    }
}

ParentMap::ParentMap(Stmt* S) : Impl(0) {
  if (S) {
    MapTy *M = new MapTy();
    BuildParentMap(*M, S);
    Impl = M;
  }
}

ParentMap::~ParentMap() {
  delete (MapTy*) Impl;
}

Stmt* ParentMap::getParent(Stmt* S) const {
  MapTy* M = (MapTy*) Impl;
  MapTy::iterator I = M->find(S);
  return I == M->end() ? 0 : I->second;
}

bool ParentMap::isConsumedExpr(Expr* E) const {
  Stmt *P = getParent(E);
  Stmt *DirectChild = E;

  // Ignore parents that are parentheses or casts.
  while (P && (isa<ParenExpr>(E) || isa<CastExpr>(E))) {
    DirectChild = P;
    P = getParent(P);
  }

  if (!P)
    return false;

  switch (P->getStmtClass()) {
    default:
      return isa<Expr>(P);
    case Stmt::DeclStmtClass:
      return true;
    case Stmt::BinaryOperatorClass: {
      BinaryOperator *BE = cast<BinaryOperator>(P);
      // If it is a comma, only the right side is consumed.
      // If it isn't a comma, both sides are consumed.
      return BE->getOpcode()!=BinaryOperator::Comma ||DirectChild==BE->getRHS();
    }
    case Stmt::ForStmtClass:
      return DirectChild == cast<ForStmt>(P)->getCond();
    case Stmt::WhileStmtClass:
      return DirectChild == cast<WhileStmt>(P)->getCond();
    case Stmt::DoStmtClass:
      return DirectChild == cast<DoStmt>(P)->getCond();
    case Stmt::IfStmtClass:
      return DirectChild == cast<IfStmt>(P)->getCond();
    case Stmt::IndirectGotoStmtClass:
      return DirectChild == cast<IndirectGotoStmt>(P)->getTarget();
    case Stmt::SwitchStmtClass:
      return DirectChild == cast<SwitchStmt>(P)->getCond();
    case Stmt::ReturnStmtClass:
      return true;
  }
}

<|endoftext|>


<commit_before>/*
TidyEngine
Copyright (C) 2016 Jakob Sinclair

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 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 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, see <http://www.gnu.org/licenses/>.
Contact the author at: jakob.sinclair99@gmail.com
*/

#include "sprite.hpp"
#include <glm/vec2.hpp>
#include "renderable.hpp"
#include "vertex.hpp"
#include "sheet.hpp"

Sprite::Sprite(Sheet *sheet, uint32_t w, uint32_t h,
                const std::vector<uint32_t> &frames)
{
        Initialise(sheet, w, h, frames);
}

Sprite::~Sprite()
{
        ;
}

/* frames must contain an even number of elements, else it returns false */
bool Sprite::Initialise(Sheet *sheet, uint32_t w, uint32_t h,
                const std::vector<uint32_t> &frames)
{
        if (frames.size() % 2 != 0 || sheet == nullptr)
                return false;

        m_Tex = sheet->GetTex();
        m_Frames.clear();
        for (size_t i = 1; i < frames.size(); i += 2)
                m_Frames.push_back(sheet->GetTexCoords(frames[i - 1],
                                frames[i]));

        if (w == 0)
                m_Width = sheet->GetWidth();
        else
                m_Width = w;
        if (h == 0)
                m_Height = sheet->GetHeight();
        else
                m_Height = h;

        m_Update = true;

        return true;
}

const std::vector<Vertex> &Sprite::GetVertices()
{
        if (m_Update == true) {
                if (m_Vertices.size() != 6) {
                        m_Vertices.clear();
                        Vertex temp;
                        for (uint8_t i = 0; i < 6; i++)
                                AddVertex(temp);
                }
                if (m_Frames.size() != 0) {
                        for (; m_ImageIndex >= m_Frames.size(); m_ImageIndex -=
                                        m_ImageIndex)
                                ;
                }
                glm::vec4 tex_coords = m_Frames[m_ImageIndex];
                /* OpenGL starts counting the texture coordinates from the
                 * bottom left corner which makes the textures appear upside
                 * down if we don't reverse the y coordinates here
                 */
                m_Vertices[0].TexUV = glm::vec2(tex_coords.x, tex_coords.w);
                m_Vertices[0].Color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
                m_Vertices[0].Position = m_Position;

                m_Vertices[1].TexUV = glm::vec2(tex_coords.z, tex_coords.w);
                m_Vertices[1].Color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
                m_Vertices[1].Position = m_Position + glm::vec3((float)m_Width,
                        0.0f, 0.0f);

                m_Vertices[2].TexUV = glm::vec2(tex_coords.x, tex_coords.y);
                m_Vertices[2].Color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
                m_Vertices[2].Position = m_Position + glm::vec3(0.0f,
                        (float)m_Height, 0.0f);

                m_Vertices[3].TexUV = glm::vec2(tex_coords.x, tex_coords.y);
                m_Vertices[3].Color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
                m_Vertices[3].Position = m_Position + glm::vec3(0.0f,
                        (float)m_Height, 0.0f);

                m_Vertices[4].TexUV = glm::vec2(tex_coords.z, tex_coords.w);
                m_Vertices[4].Color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
                m_Vertices[4].Position = m_Position + glm::vec3((float)m_Width,
                        0.0f, 0.0f);

                m_Vertices[5].TexUV = glm::vec2(tex_coords.z, tex_coords.y);
                m_Vertices[5].Color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
                m_Vertices[5].Position = m_Position + glm::vec3((float)m_Width,
                        (float)m_Height, 0.0f);
                m_Update = false;
        }

        return m_Vertices;
}

void Sprite::SetPos(const glm::vec3 &pos)
{
        m_Position = pos;
        m_Update = true;
}

const glm::vec3 &Sprite::GetPos() const
{
        return m_Position;
}

const uint32_t &Sprite::GetWidth()
{
        return m_Width;
}

const uint32_t &Sprite::GetHeight()
{
        return m_Height;
}

void Sprite::SetWidth(uint32_t w)
{
        m_Width = w;
        m_Update = true;
}

void Sprite::SetHeight(uint32_t h)
{
        m_Height = h;
        m_Update = true;
}
<commit_msg>libTidyEngine: Fixed const functions for sprites<commit_after>/*
TidyEngine
Copyright (C) 2016 Jakob Sinclair

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 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 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, see <http://www.gnu.org/licenses/>.
Contact the author at: jakob.sinclair99@gmail.com
*/

#include "sprite.hpp"
#include <glm/vec2.hpp>
#include "renderable.hpp"
#include "vertex.hpp"
#include "sheet.hpp"

Sprite::Sprite(Sheet *sheet, uint32_t w, uint32_t h,
                const std::vector<uint32_t> &frames)
{
        Initialise(sheet, w, h, frames);
}

Sprite::~Sprite()
{
        ;
}

/* frames must contain an even number of elements, else it returns false */
bool Sprite::Initialise(Sheet *sheet, uint32_t w, uint32_t h,
                const std::vector<uint32_t> &frames)
{
        if (frames.size() % 2 != 0 || sheet == nullptr)
                return false;

        m_Tex = sheet->GetTex();
        m_Frames.clear();
        for (size_t i = 1; i < frames.size(); i += 2)
                m_Frames.push_back(sheet->GetTexCoords(frames[i - 1],
                                frames[i]));

        if (w == 0)
                m_Width = sheet->GetWidth();
        else
                m_Width = w;
        if (h == 0)
                m_Height = sheet->GetHeight();
        else
                m_Height = h;

        m_Update = true;

        return true;
}

const std::vector<Vertex> &Sprite::GetVertices()
{
        if (m_Update == true) {
                if (m_Vertices.size() != 6) {
                        m_Vertices.clear();
                        Vertex temp;
                        for (uint8_t i = 0; i < 6; i++)
                                AddVertex(temp);
                }
                if (m_Frames.size() != 0) {
                        for (; m_ImageIndex >= m_Frames.size(); m_ImageIndex -=
                                        m_ImageIndex)
                                ;
                }
                glm::vec4 tex_coords = m_Frames[m_ImageIndex];
                /* OpenGL starts counting the texture coordinates from the
                 * bottom left corner which makes the textures appear upside
                 * down if we don't reverse the y coordinates here
                 */
                m_Vertices[0].TexUV = glm::vec2(tex_coords.x, tex_coords.w);
                m_Vertices[0].Color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
                m_Vertices[0].Position = m_Position;

                m_Vertices[1].TexUV = glm::vec2(tex_coords.z, tex_coords.w);
                m_Vertices[1].Color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
                m_Vertices[1].Position = m_Position + glm::vec3((float)m_Width,
                        0.0f, 0.0f);

                m_Vertices[2].TexUV = glm::vec2(tex_coords.x, tex_coords.y);
                m_Vertices[2].Color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
                m_Vertices[2].Position = m_Position + glm::vec3(0.0f,
                        (float)m_Height, 0.0f);

                m_Vertices[3].TexUV = glm::vec2(tex_coords.x, tex_coords.y);
                m_Vertices[3].Color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
                m_Vertices[3].Position = m_Position + glm::vec3(0.0f,
                        (float)m_Height, 0.0f);

                m_Vertices[4].TexUV = glm::vec2(tex_coords.z, tex_coords.w);
                m_Vertices[4].Color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
                m_Vertices[4].Position = m_Position + glm::vec3((float)m_Width,
                        0.0f, 0.0f);

                m_Vertices[5].TexUV = glm::vec2(tex_coords.z, tex_coords.y);
                m_Vertices[5].Color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
                m_Vertices[5].Position = m_Position + glm::vec3((float)m_Width,
                        (float)m_Height, 0.0f);
                m_Update = false;
        }

        return m_Vertices;
}

void Sprite::SetPos(const glm::vec3 &pos)
{
        m_Position = pos;
        m_Update = true;
}

const glm::vec3 &Sprite::GetPos() const
{
        return m_Position;
}

const uint32_t &Sprite::GetWidth() const
{
        return m_Width;
}

const uint32_t &Sprite::GetHeight() const
{
        return m_Height;
}

void Sprite::SetWidth(uint32_t w)
{
        m_Width = w;
        m_Update = true;
}

void Sprite::SetHeight(uint32_t h)
{
        m_Height = h;
        m_Update = true;
}
<|endoftext|>