<commit_before>/*
 * C++ Mandelbrot.
 *
 * Usage: mandelbrot_cpp <image_width> <image_height> <max_iterations> <repetitions (1+)> <center x> <center y> <section height> <gradient filename> <output filename>
 * Example: mandelbrot_cpp 320 200 20 1 -0.5 0.0 2.0 blue.gradient mandelbrot.raw
 *
 * Gradient file example:
 *   0.0: 0.0, 0.0, 0.0
 *   0.5: 0.0, 0.0, 1.0
 *   1.0: 1.0, 1.0, 1.0
 *
 * Tobias Brückner, 2019
 */

#include <algorithm>
#include <chrono>
#include <cmath>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <limits>
#include <numeric>
#include <regex>
#include <string>
#include <tuple>
#include <vector>

enum class Error {
    AllocMemory = 1,
    EvalArgs,
    LoadGradient,
    SaveImage,
    GetTime
};

// Compare two float values for "enough" equality.
bool equal_enough(float a, float b)
{
    constexpr float epsilon = std::numeric_limits<float>::epsilon();

    a = std::abs(a);
    b = std::abs(b);

    return std::abs(a - b) <= std::max(a, b) * epsilon;
}

struct PixelColor {
    unsigned char r, g, b;
};

struct GradientColor {
    float pos;
    float r, g, b;
    bool operator==(const float p) const { return equal_enough(p, pos); }
    bool operator<(const GradientColor& col) const { return pos < col.pos; }
};

struct Gradient {
    std::vector<GradientColor> colors;
};

void die(Error error)
{
    std::cerr << "Error: " << static_cast<int>(error) << std::endl;
    std::exit(static_cast<int>(error));
}

Gradient load_gradient(const std::string& filename)
{
    Gradient gradient;
    gradient.colors.push_back(GradientColor{0.0f, 0.0f, 0.0f, 0.0f});
    gradient.colors.push_back(GradientColor{1.0f, 1.0f, 1.0f, 1.0f});

    std::ifstream in{filename};
    std::string line;

    if (!in.is_open())
        die(Error::LoadGradient);

    const std::regex re{R"(([0-9]*\.?[0-9]+):\s*([0-9]*\.?[0-9]+),\s*([0-9]*\.?[0-9]+),\s*([0-9]*\.?[0-9]+))"};
    std::smatch m;

    while (std::getline(in, line)) {
        if (std::regex_match(line, m, re)) {
            if (m.size() == 4+1) {
                float pos = std::stof(m[1]);
                auto col = std::find(gradient.colors.begin(), gradient.colors.end(), pos);

                if (col != gradient.colors.end())
                    *col = GradientColor{pos, std::stof(m[2]), std::stof(m[3]), std::stof(m[4])};
                else
                    gradient.colors.push_back({pos, std::stof(m[2]), std::stof(m[3]), std::stof(m[4])});
            }
        }
    }

    std::sort(gradient.colors.begin(), gradient.colors.end());
    return gradient;
}

void color_from_gradient_range(const GradientColor& left, const GradientColor& right, const double pos, PixelColor& pixel_color)
{
    const double pos2 = (pos - left.pos) / (right.pos - left.pos);

    pixel_color.r = static_cast<unsigned char>(255.0 * (((right.r - left.r) * pos2) + left.r));
    pixel_color.g = static_cast<unsigned char>(255.0 * (((right.g - left.g) * pos2) + left.g));
    pixel_color.b = static_cast<unsigned char>(255.0 * (((right.b - left.b) * pos2) + left.b));
}

void color_from_gradient(const Gradient& gradient, double pos, PixelColor& pixel_color)
{
    for (std::size_t i = 1; i < gradient.colors.size(); ++i) {
        const GradientColor& left = gradient.colors[i - 1];
        const GradientColor& right = gradient.colors[i];

        if (pos >= left.pos && pos <= right.pos) {
            color_from_gradient_range(left, right, pos, pixel_color);
            break;
        }
    }
}

void mandelbrot_calc(const int image_width, const int image_height, const int max_iterations, const double center_x, const double center_y, const double height,
                     std::vector<int>& histogram, std::vector<int>& iterations_per_pixel, std::vector<double>& smoothed_distances_to_next_iteration_per_pixel)
{
    const double width = height * (static_cast<double>(image_width) / static_cast<double>(image_height));

    const double x_left   = center_x - width / 2.0;
 // const double x_right  = center_x + width / 2.0;
    const double y_top    = center_y + height / 2.0;
 // const double y_bottom = center_y - height / 2.0;

    constexpr double bailout = 20.0;
    constexpr double bailout_squared = bailout * bailout;
    const double log_log_bailout = std::log(std::log(bailout));
    const double log_2 = std::log(2.0);

    double final_magnitude = 0.0;

    std::fill(histogram.begin(), histogram.end(), 0);

    for (int pixel_y = 0; pixel_y < image_height; ++pixel_y) {
        for (int pixel_x = 0; pixel_x < image_width; ++pixel_x) {
            const double x0 = x_left + width * (static_cast<double>(pixel_x) / static_cast<double>(image_width));
            const double y0 = y_top - height * (static_cast<double>(pixel_y) / static_cast<double>(image_height));

            double x = 0.0;
            double y = 0.0;

            // iteration, will be from 1 to max_iterations once the loop is done
            int iter = 0;

            while (iter < max_iterations) {
                const double x_squared = x*x;
                const double y_squared = y*y;

                if (x_squared + y_squared >= bailout_squared) {
                    final_magnitude = std::sqrt(x_squared + y_squared);
                    break;
                }

                const double xtemp = x_squared - y_squared + x0;
                y = 2.0*x*y + y0;
                x = xtemp;

                ++iter;
            }

            const int pixel = pixel_y * image_width + pixel_x;

            if (iter < max_iterations) {
                smoothed_distances_to_next_iteration_per_pixel[static_cast<std::size_t>(pixel)] = 1.0 - std::min(1.0, (std::log(std::log(final_magnitude)) - log_log_bailout) / log_2);
                ++histogram[static_cast<std::size_t>(iter)];  // no need to count histogram[max_iterations]
            }

            iterations_per_pixel[static_cast<std::size_t>(pixel)] = iter;  // 1 .. max_iterations
        }
    }
}

void mandelbrot_colorize(const int max_iterations, const Gradient& gradient,
                         std::vector<PixelColor>& image_data, const std::vector<int>& histogram, const std::vector<int>& iterations_per_pixel, const std::vector<double>& smoothed_distances_to_next_iteration_per_pixel, std::vector<double>& normalized_colors)
{
    // Sum all iterations, not counting the last one at position histogram[max_iterations] (which
    // are points in the Mandelbrot Set).
    const double total_iterations = std::accumulate(std::next(histogram.cbegin()), std::prev(histogram.cend()), 0);

    // Normalize the colors (0.0 .. 1.0) based on how often they are used in the image, not counting
    // histogram[max_iterations] (which are points in the Mandelbrot Set).
    int running_total = 0;

    for (std::size_t i = 1; i < static_cast<std::size_t>(max_iterations); ++i) {
        running_total += histogram[i];
        normalized_colors[i] = running_total / total_iterations;
    }

    auto iter = iterations_per_pixel.cbegin();  // in range of 1 .. max_iterations
    auto smoothed_distance_to_next_iteration = smoothed_distances_to_next_iteration_per_pixel.cbegin();  // in range of 0 .. <1.0

    for (auto& pixel : image_data) {
        if (*iter == max_iterations) {
            // pixels with max. iterations (aka. inside the Mandelbrot Set) are always black
            pixel.r = 0;
            pixel.g = 0;
            pixel.b = 0;
        } else {
            // we use the color of the previous iteration in order to cover the full gradient range
            const double color_of_previous_iter = normalized_colors[static_cast<std::size_t>(*iter - 1)];
            const double color_of_current_iter  = normalized_colors[static_cast<std::size_t>(*iter)];
            const double pos_in_gradient = color_of_previous_iter + *smoothed_distance_to_next_iteration * (color_of_current_iter - color_of_previous_iter);

            color_from_gradient(gradient, pos_in_gradient, pixel);
        }

        ++iter;
        ++smoothed_distance_to_next_iteration;
    }
}

bool save_image(const std::string& filename, const std::vector<PixelColor>& image_data)
{
    std::ofstream out{filename};

    if (!out.is_open())
        return false;

    for (auto p : image_data)
        out << p.r << p.g << p.b;

    return true;
}

double mean(const std::vector<double>& values)
{
    return std::accumulate(values.begin(), values.end(), 0.0) / values.size();
}

double median(const std::vector<double>& values)
{
    std::vector<double> sorted_values{values};
    std::sort(sorted_values.begin(), sorted_values.end());

    if (sorted_values.size() % 2)
        return sorted_values[(sorted_values.size() - 1) / 2];
    else
        return (sorted_values[sorted_values.size() / 2 - 1] + sorted_values[sorted_values.size() / 2]) / 2.0;
}

void show_summary(const std::vector<double>& durations)
{
    if (durations.size() == 1) {
        std::cout << durations[0] << " s" << std::endl;
    } else {
        std::vector<double> sorted_values{durations};
        std::sort(sorted_values.begin(), sorted_values.end());

        std::cout << "mean: " << mean(sorted_values) << " s, median: " << median(sorted_values) << " s (repetitions=" << sorted_values.size() << ") ["
                  << sorted_values[0];

        for (auto p = std::next(sorted_values.cbegin()); p != sorted_values.cend(); ++p)
            std::cout << ", " << *p;

        std::cout << "]" << std::endl;
    }
}

int eval_int_arg(const char* s, int min, int max)
{
    int value;

    try {
        value = std::stoi(s);

        if (value < min || value > max)
            die(Error::EvalArgs);

        return value;
    } catch (...) {
        die(Error::EvalArgs);
    }

    return value;
}

double eval_double_arg(const char* s, double min, double max)
{
    double value;

    try {
        value = std::stod(s);

        if (value < min || value > max || std::isnan(value) || std::isinf(value))
            die(Error::EvalArgs);

        return value;
    } catch (...) {
        die(Error::EvalArgs);
    }

    return value;
}

std::tuple<int, int, int, int, double, double, double, std::string, std::string> eval_args(const int argc, char const* argv[])
{
    if (argc < 10)
        die(Error::EvalArgs);

    auto image_width    = eval_int_arg(argv[1], 1, 100000);
    auto image_height   = eval_int_arg(argv[2], 1, 100000);
    auto max_iterations = eval_int_arg(argv[3], 1, 1000000000);
    auto repetitions    = eval_int_arg(argv[4], 1, 1000000);
    auto center_x       = eval_double_arg(argv[5], -100.0, 100.0);
    auto center_y       = eval_double_arg(argv[6], -100.0, 100.0);
    auto height         = eval_double_arg(argv[7], -100.0, 100.0);
    auto colors         = std::string{argv[8]};
    auto filename       = std::string{argv[9]};

    return std::make_tuple(image_width, image_height, max_iterations, repetitions, center_x, center_y, height, colors, filename);
}

void go(const int image_width, const int image_height, const int max_iterations, const double center_x, const double center_y, const double height, const Gradient& gradient, std::vector<PixelColor>& image_data, std::vector<double>& durations, const int repetitions)
{
    // histogram & normalized_colors: for simplicity we only use indices [1] .. [max_iterations], [0] is unused
    std::vector<int> histogram(static_cast<std::size_t>(max_iterations + 1));
    std::vector<double> normalized_colors(static_cast<std::size_t>(max_iterations + 1));
    std::vector<int> iterations_per_pixel(static_cast<std::size_t>(image_width * image_height));
    std::vector<double> smoothed_distances_to_next_iteration_per_pixel(static_cast<std::size_t>(image_width * image_height));

    for (int i = 0; i < repetitions; ++i) {
        const auto t1 = std::chrono::high_resolution_clock::now();
        mandelbrot_calc(image_width, image_height, max_iterations, center_x, center_y, height, histogram, iterations_per_pixel, smoothed_distances_to_next_iteration_per_pixel);
        mandelbrot_colorize(max_iterations, gradient, image_data, histogram, iterations_per_pixel, smoothed_distances_to_next_iteration_per_pixel, normalized_colors);
        const auto t2 = std::chrono::high_resolution_clock::now();

        durations.push_back(std::chrono::duration<double>{t2 - t1}.count());
    }
}

int main(int argc, char const* argv[])
{
    auto [image_width, image_height, max_iterations, repetitions, center_x, center_y, height, gradient_filename, filename] = eval_args(argc, argv);
    auto gradient = load_gradient(gradient_filename);

    std::vector<PixelColor> image_data(static_cast<unsigned long>(image_width * image_height));
    std::vector<double> durations;

    go(image_width, image_height, max_iterations, center_x, center_y, height, gradient, image_data, durations, repetitions);

    if (!save_image(filename, image_data))
        die(Error::SaveImage);

    show_summary(durations);
}
<commit_msg>Change all color calculations from doule to float, which is accurate enough<commit_after>/*
 * C++ Mandelbrot.
 *
 * Usage: mandelbrot_cpp <image_width> <image_height> <max_iterations> <repetitions (1+)> <center x> <center y> <section height> <gradient filename> <output filename>
 * Example: mandelbrot_cpp 320 200 20 1 -0.5 0.0 2.0 blue.gradient mandelbrot.raw
 *
 * Gradient file example:
 *   0.0: 0.0, 0.0, 0.0
 *   0.5: 0.0, 0.0, 1.0
 *   1.0: 1.0, 1.0, 1.0
 *
 * Tobias Brückner, 2019
 */

#include <algorithm>
#include <chrono>
#include <cmath>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <limits>
#include <numeric>
#include <regex>
#include <string>
#include <tuple>
#include <vector>

enum class Error {
    AllocMemory = 1,
    EvalArgs,
    LoadGradient,
    SaveImage,
    GetTime
};

// Compare two float values for "enough" equality.
bool equal_enough(float a, float b)
{
    constexpr float epsilon = std::numeric_limits<float>::epsilon();

    a = std::abs(a);
    b = std::abs(b);

    return std::abs(a - b) <= std::max(a, b) * epsilon;
}

struct PixelColor {
    unsigned char r, g, b;
};

struct GradientColor {
    float pos;
    float r, g, b;
    bool operator==(const float p) const { return equal_enough(p, pos); }
    bool operator<(const GradientColor& col) const { return pos < col.pos; }
};

struct Gradient {
    std::vector<GradientColor> colors;
};

void die(Error error)
{
    std::cerr << "Error: " << static_cast<int>(error) << std::endl;
    std::exit(static_cast<int>(error));
}

Gradient load_gradient(const std::string& filename)
{
    Gradient gradient;
    gradient.colors.push_back(GradientColor{0.0f, 0.0f, 0.0f, 0.0f});
    gradient.colors.push_back(GradientColor{1.0f, 1.0f, 1.0f, 1.0f});

    std::ifstream in{filename};
    std::string line;

    if (!in.is_open())
        die(Error::LoadGradient);

    const std::regex re{R"(([0-9]*\.?[0-9]+):\s*([0-9]*\.?[0-9]+),\s*([0-9]*\.?[0-9]+),\s*([0-9]*\.?[0-9]+))"};
    std::smatch m;

    while (std::getline(in, line)) {
        if (std::regex_match(line, m, re)) {
            if (m.size() == 4+1) {
                float pos = std::stof(m[1]);
                auto col = std::find(gradient.colors.begin(), gradient.colors.end(), pos);

                if (col != gradient.colors.end())
                    *col = GradientColor{pos, std::stof(m[2]), std::stof(m[3]), std::stof(m[4])};
                else
                    gradient.colors.push_back({pos, std::stof(m[2]), std::stof(m[3]), std::stof(m[4])});
            }
        }
    }

    std::sort(gradient.colors.begin(), gradient.colors.end());
    return gradient;
}

void color_from_gradient_range(const GradientColor& left, const GradientColor& right, const float pos, PixelColor& pixel_color)
{
    const float pos2 = (pos - left.pos) / (right.pos - left.pos);

    pixel_color.r = static_cast<unsigned char>(255.0f * (((right.r - left.r) * pos2) + left.r));
    pixel_color.g = static_cast<unsigned char>(255.0f * (((right.g - left.g) * pos2) + left.g));
    pixel_color.b = static_cast<unsigned char>(255.0f * (((right.b - left.b) * pos2) + left.b));
}

void color_from_gradient(const Gradient& gradient, float pos, PixelColor& pixel_color)
{
    for (std::size_t i = 1; i < gradient.colors.size(); ++i) {
        const GradientColor& left = gradient.colors[i - 1];
        const GradientColor& right = gradient.colors[i];

        if (pos >= left.pos && pos <= right.pos) {
            color_from_gradient_range(left, right, pos, pixel_color);
            break;
        }
    }
}

void mandelbrot_calc(const int image_width, const int image_height, const int max_iterations, const double center_x, const double center_y, const double height,
                     std::vector<int>& histogram, std::vector<int>& iterations_per_pixel, std::vector<float>& smoothed_distances_to_next_iteration_per_pixel)
{
    const double width = height * (static_cast<double>(image_width) / static_cast<double>(image_height));

    const double x_left   = center_x - width / 2.0;
 // const double x_right  = center_x + width / 2.0;
    const double y_top    = center_y + height / 2.0;
 // const double y_bottom = center_y - height / 2.0;

    constexpr double bailout = 20.0;
    constexpr double bailout_squared = bailout * bailout;
    const double log_log_bailout = std::log(std::log(bailout));
    const double log_2 = std::log(2.0);

    double final_magnitude = 0.0;

    std::fill(histogram.begin(), histogram.end(), 0);

    for (int pixel_y = 0; pixel_y < image_height; ++pixel_y) {
        for (int pixel_x = 0; pixel_x < image_width; ++pixel_x) {
            const double x0 = x_left + width * (static_cast<double>(pixel_x) / static_cast<double>(image_width));
            const double y0 = y_top - height * (static_cast<double>(pixel_y) / static_cast<double>(image_height));

            double x = 0.0;
            double y = 0.0;

            // iteration, will be from 1 to max_iterations once the loop is done
            int iter = 0;

            while (iter < max_iterations) {
                const double x_squared = x*x;
                const double y_squared = y*y;

                if (x_squared + y_squared >= bailout_squared) {
                    final_magnitude = std::sqrt(x_squared + y_squared);
                    break;
                }

                const double xtemp = x_squared - y_squared + x0;
                y = 2.0*x*y + y0;
                x = xtemp;

                ++iter;
            }

            const int pixel = pixel_y * image_width + pixel_x;

            if (iter < max_iterations) {
                smoothed_distances_to_next_iteration_per_pixel[static_cast<std::size_t>(pixel)] = 1.0f - std::min(1.0f, static_cast<float>((std::log(std::log(final_magnitude)) - log_log_bailout) / log_2));
                ++histogram[static_cast<std::size_t>(iter)];  // no need to count histogram[max_iterations]
            }

            iterations_per_pixel[static_cast<std::size_t>(pixel)] = iter;  // 1 .. max_iterations
        }
    }
}

void mandelbrot_colorize(const int max_iterations, const Gradient& gradient,
                         std::vector<PixelColor>& image_data, const std::vector<int>& histogram, const std::vector<int>& iterations_per_pixel, const std::vector<float>& smoothed_distances_to_next_iteration_per_pixel, std::vector<float>& normalized_colors)
{
    // Sum all iterations, not counting the last one at position histogram[max_iterations] (which
    // are points in the Mandelbrot Set).
    const float total_iterations = std::accumulate(std::next(histogram.cbegin()), std::prev(histogram.cend()), 0);

    // Normalize the colors (0.0 .. 1.0) based on how often they are used in the image, not counting
    // histogram[max_iterations] (which are points in the Mandelbrot Set).
    int running_total = 0;

    for (std::size_t i = 1; i < static_cast<std::size_t>(max_iterations); ++i) {
        running_total += histogram[i];
        normalized_colors[i] = running_total / total_iterations;
    }

    auto iter = iterations_per_pixel.cbegin();  // in range of 1 .. max_iterations
    auto smoothed_distance_to_next_iteration = smoothed_distances_to_next_iteration_per_pixel.cbegin();  // in range of 0 .. <1.0

    for (auto& pixel : image_data) {
        if (*iter == max_iterations) {
            // pixels with max. iterations (aka. inside the Mandelbrot Set) are always black
            pixel.r = 0;
            pixel.g = 0;
            pixel.b = 0;
        } else {
            // we use the color of the previous iteration in order to cover the full gradient range
            const float color_of_previous_iter = normalized_colors[static_cast<std::size_t>(*iter - 1)];
            const float color_of_current_iter  = normalized_colors[static_cast<std::size_t>(*iter)];
            const float pos_in_gradient = color_of_previous_iter + *smoothed_distance_to_next_iteration * (color_of_current_iter - color_of_previous_iter);

            color_from_gradient(gradient, pos_in_gradient, pixel);
        }

        ++iter;
        ++smoothed_distance_to_next_iteration;
    }
}

bool save_image(const std::string& filename, const std::vector<PixelColor>& image_data)
{
    std::ofstream out{filename};

    if (!out.is_open())
        return false;

    for (auto p : image_data)
        out << p.r << p.g << p.b;

    return true;
}

double mean(const std::vector<double>& values)
{
    return std::accumulate(values.begin(), values.end(), 0.0) / values.size();
}

double median(const std::vector<double>& values)
{
    std::vector<double> sorted_values{values};
    std::sort(sorted_values.begin(), sorted_values.end());

    if (sorted_values.size() % 2)
        return sorted_values[(sorted_values.size() - 1) / 2];
    else
        return (sorted_values[sorted_values.size() / 2 - 1] + sorted_values[sorted_values.size() / 2]) / 2.0;
}

void show_summary(const std::vector<double>& durations)
{
    if (durations.size() == 1) {
        std::cout << durations[0] << " s" << std::endl;
    } else {
        std::vector<double> sorted_values{durations};
        std::sort(sorted_values.begin(), sorted_values.end());

        std::cout << "mean: " << mean(sorted_values) << " s, median: " << median(sorted_values) << " s (repetitions=" << sorted_values.size() << ") ["
                  << sorted_values[0];

        for (auto p = std::next(sorted_values.cbegin()); p != sorted_values.cend(); ++p)
            std::cout << ", " << *p;

        std::cout << "]" << std::endl;
    }
}

int eval_int_arg(const char* s, int min, int max)
{
    int value;

    try {
        value = std::stoi(s);

        if (value < min || value > max)
            die(Error::EvalArgs);

        return value;
    } catch (...) {
        die(Error::EvalArgs);
    }

    return value;
}

double eval_double_arg(const char* s, double min, double max)
{
    double value;

    try {
        value = std::stod(s);

        if (value < min || value > max || std::isnan(value) || std::isinf(value))
            die(Error::EvalArgs);

        return value;
    } catch (...) {
        die(Error::EvalArgs);
    }

    return value;
}

std::tuple<int, int, int, int, double, double, double, std::string, std::string> eval_args(const int argc, char const* argv[])
{
    if (argc < 10)
        die(Error::EvalArgs);

    auto image_width    = eval_int_arg(argv[1], 1, 100000);
    auto image_height   = eval_int_arg(argv[2], 1, 100000);
    auto max_iterations = eval_int_arg(argv[3], 1, 1000000000);
    auto repetitions    = eval_int_arg(argv[4], 1, 1000000);
    auto center_x       = eval_double_arg(argv[5], -100.0, 100.0);
    auto center_y       = eval_double_arg(argv[6], -100.0, 100.0);
    auto height         = eval_double_arg(argv[7], -100.0, 100.0);
    auto colors         = std::string{argv[8]};
    auto filename       = std::string{argv[9]};

    return std::make_tuple(image_width, image_height, max_iterations, repetitions, center_x, center_y, height, colors, filename);
}

void go(const int image_width, const int image_height, const int max_iterations, const double center_x, const double center_y, const double height, const Gradient& gradient, std::vector<PixelColor>& image_data, std::vector<double>& durations, const int repetitions)
{
    // histogram & normalized_colors: for simplicity we only use indices [1] .. [max_iterations], [0] is unused
    std::vector<int> histogram(static_cast<std::size_t>(max_iterations + 1));
    std::vector<float> normalized_colors(static_cast<std::size_t>(max_iterations + 1));
    std::vector<int> iterations_per_pixel(static_cast<std::size_t>(image_width * image_height));
    std::vector<float> smoothed_distances_to_next_iteration_per_pixel(static_cast<std::size_t>(image_width * image_height));

    for (int i = 0; i < repetitions; ++i) {
        const auto t1 = std::chrono::high_resolution_clock::now();
        mandelbrot_calc(image_width, image_height, max_iterations, center_x, center_y, height, histogram, iterations_per_pixel, smoothed_distances_to_next_iteration_per_pixel);
        mandelbrot_colorize(max_iterations, gradient, image_data, histogram, iterations_per_pixel, smoothed_distances_to_next_iteration_per_pixel, normalized_colors);
        const auto t2 = std::chrono::high_resolution_clock::now();

        durations.push_back(std::chrono::duration<double>{t2 - t1}.count());
    }
}

int main(int argc, char const* argv[])
{
    auto [image_width, image_height, max_iterations, repetitions, center_x, center_y, height, gradient_filename, filename] = eval_args(argc, argv);
    auto gradient = load_gradient(gradient_filename);

    std::vector<PixelColor> image_data(static_cast<unsigned long>(image_width * image_height));
    std::vector<double> durations;

    go(image_width, image_height, max_iterations, center_x, center_y, height, gradient, image_data, durations, repetitions);

    if (!save_image(filename, image_data))
        die(Error::SaveImage);

    show_summary(durations);
}
<|endoftext|>


<commit_before>
// INCLUDES
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/select.h>
#include "atTCPNetworkInterface.h++"

atTCPNetworkInterface::atTCPNetworkInterface(char * address, short port)
{
   char               hostname[MAXHOSTNAMELEN];
   struct hostent *   host;

   // Open the socket
   if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
      notify(AT_ERROR, "Unable to open socket for communication.\n");

   // Get information about this host and initialize the read name field
   gethostname(hostname, sizeof(hostname));
   host = gethostbyname(hostname);
   read_name.sin_family = AF_INET;
   memcpy(&read_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   read_name.sin_port = htons(port);

   // Get information about remote host and initialize the write name field
   host = gethostbyname(address);
   write_name.sin_family = AF_INET;
   memcpy(&write_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   write_name.sin_port = htons(port);

   // Initialize remaining instance variables
   num_client_sockets = 0;
}

atTCPNetworkInterface::atTCPNetworkInterface(short port)
{
   char               hostname[MAXHOSTNAMELEN];
   struct hostent *   host;

   // Open the socket
   if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
      notify(AT_ERROR, "Unable to open socket for communication.\n");

   // Get information about this host and initialize the read name field
   gethostname(hostname, sizeof(hostname));
   host = gethostbyname(hostname);
   read_name.sin_family = AF_INET;
   memcpy(&read_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   read_name.sin_port = htons(port);

   // Get information about remote host and initialize the write name field
   write_name.sin_family = AF_INET;
   memcpy(&write_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   write_name.sin_port = htons(port);

   // Initialize remaining instance variables
   num_client_sockets = 0;
}

atTCPNetworkInterface::~atTCPNetworkInterface()
{
   // Close the socket
   close(socket_value);
}

void atTCPNetworkInterface::allowConnections(int backlog)
{
   // Bind to the port
   if (bind(socket_value, (struct sockaddr *) &read_name,
            sizeof(read_name)) < 0)
   {
      notify(AT_ERROR, "Unable to bind to the port.\n");
   }

   // Notify our willingness to accept connections and give a backlog limit
   listen(socket_value, backlog);
}

int atTCPNetworkInterface::acceptConnection()
{
   int                  newSocket;
   struct sockaddr_in   connectingName;
   socklen_t            connectingNameLength;

   // Try to accept a connection
   connectingNameLength = sizeof(connectingName);
   newSocket = accept(socket_value, (struct sockaddr *) &connectingName,
                      &connectingNameLength);

   // If we had an error and it wasn't that we would block on a non-blocking
   // socket (a blocking socket shouldn't generate an EWOULDBLOCK error), then
   // notify the user; otherwise, store the socket and return an ID to the user
   if (newSocket == -1)
   {
      if (errno != EWOULDBLOCK)
         notify(AT_ERROR, "Could not accept a connection.\n");
      return -1;
   }
   else
   {
      client_sockets[num_client_sockets] = newSocket;
      num_client_sockets++;
      return num_client_sockets - 1;
   }
}

void atTCPNetworkInterface::enableBlockingOnClient(int clientID)
{
   int   statusFlags;

   // Get the current flags on the socket (return an error if we fail)
   if ( (statusFlags = fcntl(client_sockets[clientID], F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");
   else
   {
      // Now set the flags back while removing the non-blocking bit
      if (fcntl(client_sockets[clientID], F_SETFL,
                statusFlags & (~FNONBLOCK)) < 0)
      {
         // Report an error if we fail
         notify(AT_ERROR, "Unable to disable blocking on socket.\n");
      }
   }
}

void atTCPNetworkInterface::disableBlockingOnClient(int clientID)
{
   int   statusFlags;

   // Get the current flags on the socket (return an error if we fail)
   if ( (statusFlags = fcntl(client_sockets[clientID], F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");
   else
   {
      // Now set the flags back while adding the non-blocking bit (report any
      // errors we get if we fail)
      if (fcntl(client_sockets[clientID], F_SETFL, statusFlags | FNONBLOCK) < 0)
         notify(AT_ERROR, "Unable to disable blocking on socket.\n");
   }
}

int atTCPNetworkInterface::makeConnection()
{
   int                  statusFlags;
   int                  keepTrying;
   struct sockaddr_in   connectingName;
   fd_set               fds;
   struct timeval       timeout;

   // Get flags on our current socket (so we can put them on new sockets if
   // needed)
   if ( (statusFlags = fcntl(socket_value, F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");

   keepTrying = 1;
   while (keepTrying == 1)
   {
      // Try to connect
      connectingName = write_name;
      if (connect(socket_value, (struct sockaddr *) &connectingName,
                  sizeof(connectingName)) != -1)
      {
         // We connected so signal the loop to end
         keepTrying = 0;
      }
      else
      {
         // If we are not in blocking mode, tell the loop to stop (we give up);
         // Otherwise, tell the user the info that we failed this time and
         // re-open the socket
         if ( (fcntl(socket_value, F_GETFL) & FNONBLOCK) != 0 )
         {
            // We are non-blocking so we could be failing to connect
            // or we could just need more time (EINPROGRESS) so
            // use select() to give it some time and then check again
            FD_ZERO(&fds);
            FD_SET(socket_value, &fds);
            timeout.tv_sec = 1;
            timeout.tv_usec = 0;
            if (select(socket_value+1, NULL, &fds, NULL, &timeout) > 0)
            {
               // We actually did connect!
               keepTrying = 0;
            }
            else
            {
               // We didn't connect so close the socket
               keepTrying = 0;
               close(socket_value);
               socket_value = -1;
            }
         }
         else
         {
            // We didn't connect so close the socket
            close(socket_value);
            socket_value = -1;

            notify(AT_INFO, "Failed to connect to server.  Trying again.\n");

            // Re-open the socket
            if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
               notify(AT_ERROR, "Unable to open socket for communication.\n");

            // Put flags from previous socket on this new socket
            if (fcntl(socket_value, F_SETFL, statusFlags) < 0)
               notify(AT_ERROR, "Unable to disable blocking on socket.\n");
         }
      }
   }

   // Tell the user whether or not we succeeded to connect
   if (socket_value == -1)
      return -1;
   else
      return 0;
}

int atTCPNetworkInterface::read(u_char * buffer, u_long len)
{
   struct sockaddr_in   fromAddress;
   socklen_t            fromAddressLength;
   int                  packetLength;

   // Get a packet
   fromAddressLength = sizeof(fromAddress);
   packetLength = recvfrom(socket_value, buffer, len, MSG_WAITALL,
                           (struct sockaddr *) &fromAddress,
                           &fromAddressLength);

   // Tell user how many bytes we read (-1 means an error)
   return packetLength;
}

int atTCPNetworkInterface::read(int clientID, u_char * buffer, u_long len)
{
   struct sockaddr_in   fromAddress;
   socklen_t            fromAddressLength;
   int                  packetLength;

   // Get a packet
   fromAddressLength = sizeof(fromAddress);
   packetLength = recvfrom(client_sockets[clientID], buffer, len, MSG_WAITALL,
                           (struct sockaddr *) &fromAddress,
                           &fromAddressLength);

   // Tell user how many bytes we read (-1 means an error)
   return packetLength;
}

int atTCPNetworkInterface::write(u_char * buffer, u_long len)
{
   int   lengthWritten;

   // Write the packet
   lengthWritten = sendto(socket_value, buffer, len, 0,
                          (struct sockaddr *) &write_name, write_name_length);

   // Tell user how many bytes we wrote (-1 if error)
   return lengthWritten;
}

int atTCPNetworkInterface::write(int clientID, u_char * buffer, u_long len)
{
   int   lengthWritten;

   // Write the packet
   lengthWritten = sendto(client_sockets[clientID], buffer, len, 0,
                          (struct sockaddr *) &write_name, write_name_length);

   // Tell user how many bytes we wrote (-1 if error)
   return lengthWritten;
}

<commit_msg>Only double check non-blocking case when we get an EINPROGRESS.<commit_after>
// INCLUDES
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/select.h>
#include "atTCPNetworkInterface.h++"

atTCPNetworkInterface::atTCPNetworkInterface(char * address, short port)
{
   char               hostname[MAXHOSTNAMELEN];
   struct hostent *   host;

   // Open the socket
   if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
      notify(AT_ERROR, "Unable to open socket for communication.\n");

   // Get information about this host and initialize the read name field
   gethostname(hostname, sizeof(hostname));
   host = gethostbyname(hostname);
   read_name.sin_family = AF_INET;
   memcpy(&read_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   read_name.sin_port = htons(port);

   // Get information about remote host and initialize the write name field
   host = gethostbyname(address);
   write_name.sin_family = AF_INET;
   memcpy(&write_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   write_name.sin_port = htons(port);

   // Initialize remaining instance variables
   num_client_sockets = 0;
}

atTCPNetworkInterface::atTCPNetworkInterface(short port)
{
   char               hostname[MAXHOSTNAMELEN];
   struct hostent *   host;

   // Open the socket
   if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
      notify(AT_ERROR, "Unable to open socket for communication.\n");

   // Get information about this host and initialize the read name field
   gethostname(hostname, sizeof(hostname));
   host = gethostbyname(hostname);
   read_name.sin_family = AF_INET;
   memcpy(&read_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   read_name.sin_port = htons(port);

   // Get information about remote host and initialize the write name field
   write_name.sin_family = AF_INET;
   memcpy(&write_name.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
   write_name.sin_port = htons(port);

   // Initialize remaining instance variables
   num_client_sockets = 0;
}

atTCPNetworkInterface::~atTCPNetworkInterface()
{
   // Close the socket
   close(socket_value);
}

void atTCPNetworkInterface::allowConnections(int backlog)
{
   // Bind to the port
   if (bind(socket_value, (struct sockaddr *) &read_name,
            sizeof(read_name)) < 0)
   {
      notify(AT_ERROR, "Unable to bind to the port.\n");
   }

   // Notify our willingness to accept connections and give a backlog limit
   listen(socket_value, backlog);
}

int atTCPNetworkInterface::acceptConnection()
{
   int                  newSocket;
   struct sockaddr_in   connectingName;
   socklen_t            connectingNameLength;

   // Try to accept a connection
   connectingNameLength = sizeof(connectingName);
   newSocket = accept(socket_value, (struct sockaddr *) &connectingName,
                      &connectingNameLength);

   // If we had an error and it wasn't that we would block on a non-blocking
   // socket (a blocking socket shouldn't generate an EWOULDBLOCK error), then
   // notify the user; otherwise, store the socket and return an ID to the user
   if (newSocket == -1)
   {
      if (errno != EWOULDBLOCK)
         notify(AT_ERROR, "Could not accept a connection.\n");
      return -1;
   }
   else
   {
      client_sockets[num_client_sockets] = newSocket;
      num_client_sockets++;
      return num_client_sockets - 1;
   }
}

void atTCPNetworkInterface::enableBlockingOnClient(int clientID)
{
   int   statusFlags;

   // Get the current flags on the socket (return an error if we fail)
   if ( (statusFlags = fcntl(client_sockets[clientID], F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");
   else
   {
      // Now set the flags back while removing the non-blocking bit
      if (fcntl(client_sockets[clientID], F_SETFL,
                statusFlags & (~FNONBLOCK)) < 0)
      {
         // Report an error if we fail
         notify(AT_ERROR, "Unable to disable blocking on socket.\n");
      }
   }
}

void atTCPNetworkInterface::disableBlockingOnClient(int clientID)
{
   int   statusFlags;

   // Get the current flags on the socket (return an error if we fail)
   if ( (statusFlags = fcntl(client_sockets[clientID], F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");
   else
   {
      // Now set the flags back while adding the non-blocking bit (report any
      // errors we get if we fail)
      if (fcntl(client_sockets[clientID], F_SETFL, statusFlags | FNONBLOCK) < 0)
         notify(AT_ERROR, "Unable to disable blocking on socket.\n");
   }
}

int atTCPNetworkInterface::makeConnection()
{
   int                  statusFlags;
   int                  keepTrying;
   struct sockaddr_in   connectingName;
   fd_set               readFds;
   fd_set               writeFds;
   struct timeval       timeout;

   // Get flags on our current socket (so we can put them on new sockets if
   // needed)
   if ( (statusFlags = fcntl(socket_value, F_GETFL)) < 0 )
      notify(AT_ERROR, "Unable to get status of socket.\n");

   keepTrying = 1;
   while (keepTrying == 1)
   {
      // Try to connect
      connectingName = write_name;
      if (connect(socket_value, (struct sockaddr *) &connectingName,
                  sizeof(connectingName)) != -1)
      {
         // We connected so signal the loop to end
         keepTrying = 0;
      }
      else
      {
         // If we are not in blocking mode, tell the loop to stop (we give up);
         // Otherwise, tell the user the info that we failed this time and
         // re-open the socket
         if ( (fcntl(socket_value, F_GETFL) & FNONBLOCK) != 0 )
         {
            // We are non-blocking so we could be failing to connect
            // or we could just need more time (EINPROGRESS) so
            // use select() to give it some time and then check again
            if (errno == EINPROGRESS)
            {
               notify(AT_INFO, "Waiting for connection.\n");
               FD_ZERO(&readFds);
               FD_SET(socket_value, &readFds);
               FD_ZERO(&writeFds);
               FD_SET(socket_value, &writeFds);
               timeout.tv_sec = 1;
               timeout.tv_usec = 0;
               if (select(socket_value+1, &readFds,
                          &writeFds, NULL, &timeout) < 1)
               {
                  // We didn't connect so close the socket
                  keepTrying = 0;
                  close(socket_value);
                  socket_value = -1;
               }
               else
               {
                  // We actually did connect!
                  keepTrying = 0;
               }
            }
            else
            {
               // Just give up
               notify(AT_INFO, "Failed to connect to server.  Giving up.\n");
               keepTrying = 0;
               close(socket_value);
               socket_value = -1;
            }
         }
         else
         {
            // We didn't connect so close the socket
            close(socket_value);
            socket_value = -1;

            notify(AT_INFO, "Failed to connect to server.  Trying again.\n");

            // Re-open the socket
            if ( (socket_value = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
               notify(AT_ERROR, "Unable to open socket for communication.\n");

            // Put flags from previous socket on this new socket
            if (fcntl(socket_value, F_SETFL, statusFlags) < 0)
               notify(AT_ERROR, "Unable to disable blocking on socket.\n");
         }
      }
   }

   // Tell the user whether or not we succeeded to connect
   if (socket_value == -1)
      return -1;
   else
      return 0;
}

int atTCPNetworkInterface::read(u_char * buffer, u_long len)
{
   struct sockaddr_in   fromAddress;
   socklen_t            fromAddressLength;
   int                  packetLength;

   // Get a packet
   fromAddressLength = sizeof(fromAddress);
   packetLength = recvfrom(socket_value, buffer, len, MSG_WAITALL,
                           (struct sockaddr *) &fromAddress,
                           &fromAddressLength);

   // Tell user how many bytes we read (-1 means an error)
   return packetLength;
}

int atTCPNetworkInterface::read(int clientID, u_char * buffer, u_long len)
{
   struct sockaddr_in   fromAddress;
   socklen_t            fromAddressLength;
   int                  packetLength;

   // Get a packet
   fromAddressLength = sizeof(fromAddress);
   packetLength = recvfrom(client_sockets[clientID], buffer, len, MSG_WAITALL,
                           (struct sockaddr *) &fromAddress,
                           &fromAddressLength);

   // Tell user how many bytes we read (-1 means an error)
   return packetLength;
}

int atTCPNetworkInterface::write(u_char * buffer, u_long len)
{
   int   lengthWritten;

   // Write the packet
   lengthWritten = sendto(socket_value, buffer, len, 0,
                          (struct sockaddr *) &write_name, write_name_length);

   // Tell user how many bytes we wrote (-1 if error)
   return lengthWritten;
}

int atTCPNetworkInterface::write(int clientID, u_char * buffer, u_long len)
{
   int   lengthWritten;

   // Write the packet
   lengthWritten = sendto(client_sockets[clientID], buffer, len, 0,
                          (struct sockaddr *) &write_name, write_name_length);

   // Tell user how many bytes we wrote (-1 if error)
   return lengthWritten;
}

<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/launcher/launcher.h"

#include "ash/launcher/launcher_delegate.h"
#include "ash/launcher/launcher_model.h"
#include "ash/launcher/launcher_view.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "ash/shell_window_ids.h"
#include "grit/ui_resources.h"
#include "ui/aura/window.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/compositor/layer.h"
#include "ui/gfx/image/image.h"
#include "ui/views/accessible_pane_view.h"
#include "ui/views/painter.h"
#include "ui/views/widget/widget.h"

namespace ash {

namespace {

// Used to draw the background of the shelf.
class ShelfPainter : public views::Painter {
 public:
  ShelfPainter() {
    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    image_ = *rb.GetImageNamed(IDR_AURA_LAUNCHER_BACKGROUND).ToSkBitmap();
  }

  // Overridden from views::Painter:
  virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE {
    canvas->TileImageInt(image_, 0, 0, size.width(), size.height());
  }

 private:
  SkBitmap image_;

  DISALLOW_COPY_AND_ASSIGN(ShelfPainter);
};

}  // namespace

// The contents view of the Widget. This view contains LauncherView and
// sizes it to the width of the widget minus the size of the status area.
class Launcher::DelegateView : public views::WidgetDelegate,
                               public views::AccessiblePaneView {
 public:
  explicit DelegateView();
  virtual ~DelegateView();

  void SetStatusWidth(int width);
  int status_width() const { return status_width_; }

  // views::View overrides
  virtual gfx::Size GetPreferredSize() OVERRIDE;
  virtual void Layout() OVERRIDE;

  virtual views::Widget* GetWidget() OVERRIDE {
    return View::GetWidget();
  }

  virtual const views::Widget* GetWidget() const OVERRIDE {
    return View::GetWidget();
  }

 private:
  int status_width_;

  DISALLOW_COPY_AND_ASSIGN(DelegateView);
};

Launcher::DelegateView::DelegateView()
    : status_width_(0) {
  set_background(
      views::Background::CreateBackgroundPainter(true, new ShelfPainter()));
}

Launcher::DelegateView::~DelegateView() {
}

void Launcher::DelegateView::SetStatusWidth(int width) {
  if (status_width_ == width)
    return;

  status_width_ = width;
  Layout();
}

gfx::Size Launcher::DelegateView::GetPreferredSize() {
  return child_count() > 0 ? child_at(0)->GetPreferredSize() : gfx::Size();
}

void Launcher::DelegateView::Layout() {
  if (child_count() == 0)
    return;
  child_at(0)->SetBounds(0, 0, std::max(0, width() - status_width_), height());
}

Launcher::Launcher(aura::Window* window_container)
    : widget_(NULL),
      window_container_(window_container),
      delegate_view_(NULL) {
  model_.reset(new LauncherModel);
  delegate_.reset(Shell::GetInstance()->delegate()->CreateLauncherDelegate());

  widget_.reset(new views::Widget);
  views::Widget::InitParams params(
      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
  params.create_texture_for_layer = true;
  params.transparent = true;
  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  params.parent = Shell::GetInstance()->GetContainer(
      ash::internal::kShellWindowId_LauncherContainer);
  internal::LauncherView* launcher_view =
      new internal::LauncherView(model_.get(), delegate_.get());
  launcher_view->Init();
  delegate_view_ = new DelegateView;
  delegate_view_->AddChildView(launcher_view);
  params.delegate = delegate_view_;
  widget_->Init(params);
  widget_->GetNativeWindow()->SetName("LauncherWindow");
  gfx::Size pref = static_cast<views::View*>(launcher_view)->GetPreferredSize();
  widget_->SetBounds(gfx::Rect(0, 0, pref.width(), pref.height()));
  // The launcher should not take focus when it is initially shown.
  widget_->set_focus_on_creation(false);
  widget_->SetContentsView(delegate_view_);
  widget_->Show();
  widget_->GetNativeView()->SetName("LauncherView");
}

Launcher::~Launcher() {
}

void Launcher::SetStatusWidth(int width) {
  delegate_view_->SetStatusWidth(width);
}

int Launcher::GetStatusWidth() {
  return delegate_view_->status_width();
}

}  // namespace ash
<commit_msg>Fix ui test related crash.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/launcher/launcher.h"

#include "ash/launcher/launcher_delegate.h"
#include "ash/launcher/launcher_model.h"
#include "ash/launcher/launcher_view.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "ash/shell_window_ids.h"
#include "grit/ui_resources.h"
#include "ui/aura/window.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/compositor/layer.h"
#include "ui/gfx/image/image.h"
#include "ui/views/accessible_pane_view.h"
#include "ui/views/painter.h"
#include "ui/views/widget/widget.h"

namespace ash {

namespace {

// Used to draw the background of the shelf.
class ShelfPainter : public views::Painter {
 public:
  ShelfPainter() {
    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    image_ = *rb.GetImageNamed(IDR_AURA_LAUNCHER_BACKGROUND).ToSkBitmap();
  }

  // Overridden from views::Painter:
  virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE {
    canvas->TileImageInt(image_, 0, 0, size.width(), size.height());
  }

 private:
  SkBitmap image_;

  DISALLOW_COPY_AND_ASSIGN(ShelfPainter);
};

}  // namespace

// The contents view of the Widget. This view contains LauncherView and
// sizes it to the width of the widget minus the size of the status area.
class Launcher::DelegateView : public views::WidgetDelegate,
                               public views::AccessiblePaneView {
 public:
  explicit DelegateView();
  virtual ~DelegateView();

  void SetStatusWidth(int width);
  int status_width() const { return status_width_; }

  // views::View overrides
  virtual gfx::Size GetPreferredSize() OVERRIDE;
  virtual void Layout() OVERRIDE;

  virtual views::Widget* GetWidget() OVERRIDE {
    return View::GetWidget();
  }

  virtual const views::Widget* GetWidget() const OVERRIDE {
    return View::GetWidget();
  }

 private:
  int status_width_;

  DISALLOW_COPY_AND_ASSIGN(DelegateView);
};

Launcher::DelegateView::DelegateView()
    : status_width_(0) {
  set_background(
      views::Background::CreateBackgroundPainter(true, new ShelfPainter()));
}

Launcher::DelegateView::~DelegateView() {
}

void Launcher::DelegateView::SetStatusWidth(int width) {
  if (status_width_ == width)
    return;

  status_width_ = width;
  Layout();
}

gfx::Size Launcher::DelegateView::GetPreferredSize() {
  return child_count() > 0 ? child_at(0)->GetPreferredSize() : gfx::Size();
}

void Launcher::DelegateView::Layout() {
  if (child_count() == 0)
    return;
  child_at(0)->SetBounds(0, 0, std::max(0, width() - status_width_), height());
}

Launcher::Launcher(aura::Window* window_container)
    : widget_(NULL),
      window_container_(window_container),
      delegate_view_(NULL) {
  model_.reset(new LauncherModel);
  if (Shell::GetInstance()->delegate())
    delegate_.reset(Shell::GetInstance()->delegate()->CreateLauncherDelegate());

  widget_.reset(new views::Widget);
  views::Widget::InitParams params(
      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
  params.create_texture_for_layer = true;
  params.transparent = true;
  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  params.parent = Shell::GetInstance()->GetContainer(
      ash::internal::kShellWindowId_LauncherContainer);
  internal::LauncherView* launcher_view =
      new internal::LauncherView(model_.get(), delegate_.get());
  launcher_view->Init();
  delegate_view_ = new DelegateView;
  delegate_view_->AddChildView(launcher_view);
  params.delegate = delegate_view_;
  widget_->Init(params);
  widget_->GetNativeWindow()->SetName("LauncherWindow");
  gfx::Size pref = static_cast<views::View*>(launcher_view)->GetPreferredSize();
  widget_->SetBounds(gfx::Rect(0, 0, pref.width(), pref.height()));
  // The launcher should not take focus when it is initially shown.
  widget_->set_focus_on_creation(false);
  widget_->SetContentsView(delegate_view_);
  widget_->Show();
  widget_->GetNativeView()->SetName("LauncherView");
}

Launcher::~Launcher() {
}

void Launcher::SetStatusWidth(int width) {
  delegate_view_->SetStatusWidth(width);
}

int Launcher::GetStatusWidth() {
  return delegate_view_->status_width();
}

}  // namespace ash
<|endoftext|>


<commit_before>/*******************************
Copyright (c) 2016-2020 Gr�goire Angerand

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

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

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

#include "ShadowMapPass.h"

#include <yave/framegraph/FrameGraph.h>

#include <yave/ecs/EntityWorld.h>
#include <yave/components/SpotLightComponent.h>
#include <yave/entities/entities.h>

#include <y/utils/log.h>

namespace yave {

struct SubAtlas {
	math::Vec2ui pos;
	u32 subs = 4;
};

static std::pair<math::Vec2ui, u32> alloc_sub_atlas(u32 level, usize& first_level_index, core::MutableSpan<SubAtlas> levels, usize first_level_size) {
	y_always_assert(level < levels.size(), "Invalid atlas level");
	const u32 size = first_level_size >> level;
	const u32 index = levels[level].subs;
	if(index != 4) {
		++levels[level].subs;
		return {math::Vec2ui(index >> 1, index & 1) * size + levels[level].pos, size};
	}

	if(level == 0) {
		if(first_level_index < levels.size()) {
			return {math::Vec2ui(0, first_level_index++) * first_level_size, first_level_size};
		}
		log_msg("Unable to allocate shadow altas: too many shadow casters", Log::Warning);
		return {math::Vec2ui(), 0};
	}

	const math::Vec2ui pos = alloc_sub_atlas(level - 1, first_level_index, levels, first_level_size).first;
	levels[level] = {pos, 0};
	return alloc_sub_atlas(level, first_level_index, levels, first_level_size);
}

static Camera spotlight_camera(const TransformableComponent& tr, const SpotLightComponent& sp) {
	Camera cam;
	cam.set_proj(math::perspective(sp.half_angle() * 2.0f, 1.0f, 0.1f));
	cam.set_view(math::look_at(tr.position(), tr.position() + tr.forward(), tr.up()));
	return cam;
}

ShadowMapPass ShadowMapPass::create(FrameGraph& framegraph, const SceneView& scene, const ShadowMapPassSettings& settings) {
	static constexpr ImageFormat shadow_format = VK_FORMAT_D32_SFLOAT;
	const ecs::EntityWorld& world = scene.world();

	FrameGraphPassBuilder builder = framegraph.add_pass("Shadow pass");

	const usize shadow_map_log_size = log2ui(settings.shadow_map_size);
	const usize first_level_size = 1 << shadow_map_log_size;
	if(first_level_size != settings.shadow_map_size) {
		log_msg("Shadow map size is not a power of two", Log::Warning);
	}

	usize first_level_index = 0;
	std::array<SubAtlas, 32> levels;
	auto alloc = [&](u32 level) { return alloc_sub_atlas(level, first_level_index, core::MutableSpan(levels), first_level_size); };

	const math::Vec2ui shadow_map_size = math::Vec2ui(1, settings.shadow_atlas_size) * first_level_size;
	const auto shadow_map = builder.declare_image(shadow_format, shadow_map_size);

	ShadowMapPass pass;
	pass.shadow_map = shadow_map;
	pass.sub_passes = std::make_shared<SubPassData>();

	{
		const math::Vec2 uv_mul = 1.0f / math::Vec2(shadow_map_size);
		for(auto spot : world.view(SpotLightArchetype())) {
			auto [t, l] = spot.components();
			if(!l.cast_shadow()) {
				continue;
			}

			const u32 level = l.shadow_lod();
			const auto [offset, size] = alloc(level);

			const SceneView spot_view(&world, spotlight_camera(t, l));
			pass.sub_passes->passes.push_back(SubPass{
				SceneRenderSubPass::create(builder, spot_view),
				offset, size
			});
			pass.sub_passes->lights[spot.id().as_u64()] = {
				spot_view.camera().viewproj_matrix(),
				math::Vec2(offset) * uv_mul,
				math::Vec2(size) * uv_mul
			};
		}
	}

	builder.add_depth_output(shadow_map);
	builder.set_render_func([=](CmdBufferRecorder& recorder, const FrameGraphPass* self) {
		auto render_pass = recorder.bind_framebuffer(self->framebuffer());

		for(const auto& sub_pass : pass.sub_passes->passes) {
			render_pass.set_viewport(Viewport(math::Vec2(sub_pass.viewport_size), sub_pass.viewport_offset));
			sub_pass.scene_pass.render(render_pass, self);
		}
	});

	return pass;
}

}
<commit_msg>Fixed shadow generation when too many lights are present<commit_after>/*******************************
Copyright (c) 2016-2020 Gr�goire Angerand

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

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

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

#include "ShadowMapPass.h"

#include <yave/framegraph/FrameGraph.h>

#include <yave/ecs/EntityWorld.h>
#include <yave/components/SpotLightComponent.h>
#include <yave/entities/entities.h>

#include <y/utils/log.h>

namespace yave {

struct SubAtlas {
	math::Vec2ui pos;
	u32 subs = 4;
};

static std::pair<math::Vec2ui, u32> alloc_sub_atlas(u32 level, usize& first_level_index, core::MutableSpan<SubAtlas> levels, usize first_level_size) {
	y_always_assert(level < levels.size(), "Invalid atlas level");
	const u32 size = first_level_size >> level;
	const u32 index = levels[level].subs;
	if(index != 4) {
		++levels[level].subs;
		return {math::Vec2ui(index >> 1, index & 1) * size + levels[level].pos, size};
	}

	if(level == 0) {
		if(first_level_index < levels.size()) {
			return {math::Vec2ui(0, first_level_index++) * first_level_size, first_level_size};
		}
		return {math::Vec2ui(), 0};
	}

	const math::Vec2ui pos = alloc_sub_atlas(level - 1, first_level_index, levels, first_level_size).first;
	levels[level] = {pos, 0};
	return alloc_sub_atlas(level, first_level_index, levels, first_level_size);
}

static Camera spotlight_camera(const TransformableComponent& tr, const SpotLightComponent& sp) {
	Camera cam;
	cam.set_proj(math::perspective(sp.half_angle() * 2.0f, 1.0f, 0.1f));
	cam.set_view(math::look_at(tr.position(), tr.position() + tr.forward(), tr.up()));
	return cam;
}

ShadowMapPass ShadowMapPass::create(FrameGraph& framegraph, const SceneView& scene, const ShadowMapPassSettings& settings) {
	static constexpr ImageFormat shadow_format = VK_FORMAT_D32_SFLOAT;
	const ecs::EntityWorld& world = scene.world();

	FrameGraphPassBuilder builder = framegraph.add_pass("Shadow pass");

	const usize shadow_map_log_size = log2ui(settings.shadow_map_size);
	const usize first_level_size = 1 << shadow_map_log_size;
	if(first_level_size != settings.shadow_map_size) {
		log_msg("Shadow map size is not a power of two", Log::Warning);
	}

	usize first_level_index = 0;
	std::array<SubAtlas, 32> levels;
	auto alloc = [&](u32 level) { return alloc_sub_atlas(level, first_level_index, core::MutableSpan(levels), first_level_size); };

	const math::Vec2ui shadow_map_size = math::Vec2ui(1, settings.shadow_atlas_size) * first_level_size;
	const auto shadow_map = builder.declare_image(shadow_format, shadow_map_size);

	ShadowMapPass pass;
	pass.shadow_map = shadow_map;
	pass.sub_passes = std::make_shared<SubPassData>();

	{
		const math::Vec2 uv_mul = 1.0f / math::Vec2(shadow_map_size);
		for(auto spot : world.view(SpotLightArchetype())) {
			auto [t, l] = spot.components();
			if(!l.cast_shadow()) {
				continue;
			}

			const u32 level = l.shadow_lod();
			const auto [offset, size] = alloc(level);

			if(!size) {
				log_msg("Unable to allocate shadow altas: too many shadow casters", Log::Warning);
				continue;
			}

			const SceneView spot_view(&world, spotlight_camera(t, l));
			pass.sub_passes->passes.push_back(SubPass{
				SceneRenderSubPass::create(builder, spot_view),
				offset, size
			});
			pass.sub_passes->lights[spot.id().as_u64()] = {
				spot_view.camera().viewproj_matrix(),
				math::Vec2(offset) * uv_mul,
				math::Vec2(size) * uv_mul
			};
		}
	}

	builder.add_depth_output(shadow_map);
	builder.set_render_func([=](CmdBufferRecorder& recorder, const FrameGraphPass* self) {
		auto render_pass = recorder.bind_framebuffer(self->framebuffer());

		for(const auto& sub_pass : pass.sub_passes->passes) {
			render_pass.set_viewport(Viewport(math::Vec2(sub_pass.viewport_size), sub_pass.viewport_offset));
			sub_pass.scene_pass.render(render_pass, self);
		}
	});

	return pass;
}

}
<|endoftext|>


<commit_before><commit_msg>bug fix<commit_after><|endoftext|>


<commit_before>#include <iostream>
//#include <vector>
#include <queue>
#include <math.h>

using namespace std;

double x0,x1,x2,s2,c2;

/////////////////////////////
struct engine;
struct proc;
struct chan;

struct engine{
	//std::vector<chan*> ready;
	std::queue<chan*> ready;
};

struct proc{
	void(*recv)(chan*, proc*);
};

struct chan{
	proc*p;
 	bool sending;
};

inline void send(engine*e, chan*c, proc*p)
{
	if (c->sending) return;
 	c->sending = true;	c->p = p;
 	e->ready.push(c);

//	if (c->sending) return;
// 	c->sending = true;
// 	c->p = p;
// 	e->ready.push_back(c);
}

inline bool access(chan*c, proc*p)
{
	return c->p == p && !c->sending;
}

inline void run(engine*e, int n = 1)
{
 	while (!e->ready.empty()){
 		chan*c = e->ready.front(); e->ready.pop();
 		c->sending = false;
 		c->p->recv(c, c->p);
 	}
/*
	size_t rsize;
	while (rsize = e->ready.size()){
 		int n = rand() % rsize;
		std::vector<chan*>::const_iterator it = e->ready.begin() + n;
 		chan*c = *it;	e->ready.erase(it); c->sending = false;
 		c->p->recv(c, c->p);
	}
*/
}

/////////////////////////////
/*
~Link=
 	+Begin ? argSin2 -> Calc | argCos2 -> Calc;
 	 Calc  ! result  -> End;
 	 End.
*Parent=
 	 p1 : Link ! result -> join;
 	 p2 : Link ! result -> join;
 	+fork(p1!argCos2,p2!argSin2);
 	 join(p1?result,p2?result).
*Child=
 	p : Link ? argCos2 -> calcCos2 | argSin2 -> calcSin2;
 	calcCos2(p?argCos2,p!result);
 	calcSin2(p?argSin2,p!result).
*/
/////////////////////////////

engine e;
proc  parent,child1,child2;
chan  link0,link1,link2;

void  Parent(chan*c, proc*p)
{
	if(c==&link0){
		cin >> x0; x1=x2=x0;
		send(&e,&link1,&child1);
		send(&e,&link2,&child2);
	}
	if(access(&link1,p) && access(&link2,p))
		cout << endl << "sin2(x)+cos2(x)=" << s2+c2;
}

void Child(chan*c, proc*)
{
	if(c==&link1) s2=sin(x1)*sin(x1);
	else if(c==&link2)c2=cos(x2)*cos(x2);
	else cout << "something wrong";
	send(&e,c,&parent);
}

void main()
{
	//cin >> x;
	//s2=sin(x)*sin(x); /*//*/ c2=cos(x)*cos(x);
	//cout << endl << "sin2(x)+cos2(x)=" << s2+c2;

	parent.recv=&Parent;
	child1.recv=child2.recv=&Child;

	send(&e,&link0,&parent);
	run(&e);
}
<commit_msg>IDs databases added<commit_after>#include <iostream>
//#include <vector>
#include <queue>
#include <map>
#include <math.h>

using namespace std;

double x0,x1,x2,s2,c2;

/////////////////////////////
struct engine;
struct proc;
struct chan;

struct engine{
	//std::vector<chan*> ready;
	std::queue<chan*> ready;
	////////////////////////////////////////////////
 	std::map<int,chan*> chans;// channel id --> channel ref
 	std::map<int,proc*> procs;// process id --> process ref
 	std::map<int,int> pmap;   // process id --> rank in MPI_COMM_WORLD
};

struct proc{
	void(*recv)(chan*, proc*);
	////////////////////////////////////////
 	int id; // process ref in MPI message
 	void(*in) (proc*, std::istream&);
 	void(*out)(proc*, std::ostream&);
};

struct chan{
	proc*p;
 	bool sending;
	////////////////////////////////
	int id; // channel ref in MPI message
	void(*in) (chan*, std::istream&);
	void(*out)(chan*, std::ostream&);
};

inline void send(engine*e, chan*c, proc*p)
{
	if (c->sending) return;
 	c->sending = true;	c->p = p;
 	e->ready.push(c);

//	if (c->sending) return;
// 	c->sending = true;
// 	c->p = p;
// 	e->ready.push_back(c);
}

inline bool access(chan*c, proc*p)
{
	return c->p == p && !c->sending;
}

inline void run(engine*e, int n = 1)
{
 	while (!e->ready.empty()){
 		chan*c = e->ready.front(); e->ready.pop();
 		c->sending = false;
 		c->p->recv(c, c->p);
 	}
/*
	size_t rsize;
	while (rsize = e->ready.size()){
 		int n = rand() % rsize;
		std::vector<chan*>::const_iterator it = e->ready.begin() + n;
 		chan*c = *it;	e->ready.erase(it); c->sending = false;
 		c->p->recv(c, c->p);
	}
*/
}

/////////////////////////////
/*
~Link=
 	+Begin ? argSin2 -> Calc | argCos2 -> Calc;
 	 Calc  ! result  -> End;
 	 End.
*Parent=
 	 p1 : Link ! result -> join;
 	 p2 : Link ! result -> join;
 	+fork(p1!argCos2,p2!argSin2);
 	 join(p1?result,p2?result).
*Child=
 	p : Link ? argCos2 -> calcCos2 | argSin2 -> calcSin2;
 	calcCos2(p?argCos2,p!result);
 	calcSin2(p?argSin2,p!result).
*/
/////////////////////////////

engine e;
proc  parent,child1,child2;
chan  link0,link1,link2;

void  Parent(chan*c, proc*p)
{
	if(c==&link0){
		cin >> x0; x1=x2=x0;
		send(&e,&link1,&child1);
		send(&e,&link2,&child2);
	}
	if(access(&link1,p) && access(&link2,p))
		cout << endl << "sin2(x)+cos2(x)=" << s2+c2;
}

void Child(chan*c, proc*)
{
	if(c==&link1) s2=sin(x1)*sin(x1);
	else if(c==&link2)c2=cos(x2)*cos(x2);
	else cout << "something wrong";
	send(&e,c,&parent);
}

void main()
{
	//cin >> x;
	//s2=sin(x)*sin(x); /*//*/ c2=cos(x)*cos(x);
	//cout << endl << "sin2(x)+cos2(x)=" << s2+c2;

	parent.recv=&Parent;
	child1.recv=child2.recv=&Child;

	send(&e,&link0,&parent);
	run(&e);
}
<|endoftext|>


<commit_before>// Time:  O(4^n)
// Space: O(n)

class Solution {
public:
    vector<string> addOperators(string num, int target) {
        vector<string> result;
        vector<string> expr;
        addOperatorsDFS(num, target, 0, 0, 0, &expr, &result);
        return result;
    }

    void addOperatorsDFS(const string& s, const int& target, const int& pos,
                         const int& operand1, const int& operand2, vector<string> *expr,
                         vector<string> *result) {
        if (pos == s.length()) {
            if (operand1 + operand2 == target) {
                result->emplace_back(move(join(*expr)));
            }
            return;
        }

        int num = 0;
        string num_str;
        for (int i = pos; i < s.length(); ++i) {
            num = num * 10 + s[i] - '0';
            num_str.push_back(s[i]);
            // Avoid overflow and "00...".
            if (to_string(num) != num_str) {
                break;
            }

            // Case '+':
            expr->emplace_back("+"), expr->emplace_back(num_str);
            addOperatorsDFS(s, target, i + 1, operand1 + operand2, num, expr, result);
            expr->pop_back(), expr->pop_back();

            // '-' and '*' could be used only if the expression is not empty.
            if (!expr->empty()) {
                // Case '-':
                expr->emplace_back("-"), expr->emplace_back(num_str);
                addOperatorsDFS(s, target, i + 1, operand1 + operand2, -num, expr, result);
                expr->pop_back(), expr->pop_back();

                // Case '*':
                expr->emplace_back("*"), expr->emplace_back(num_str);
                addOperatorsDFS(s, target, i + 1, operand1, operand2 * num, expr, result);
                expr->pop_back(), expr->pop_back();
            }
        }
    }

    string join(const vector<string>& expr) {
        string e;
        for (int i = 0; i < expr.size(); ++i) {
            if (i == 0 && expr[i] == "+") {  // Skip '+' at the beginning of the string.
                continue;
            }
            e.append(expr[i]);
        }
        return e;
    }
};
<commit_msg>Update expression-add-operators.cpp<commit_after>// Time:  O(4^n)
// Space: O(n)

class Solution {
public:
    vector<string> addOperators(string num, int target) {
        vector<string> result;
        vector<string> expr;
        int val = 0;
        string val_str;
        for (int i = 0; i < num.length(); ++i) {
            val = val * 10 + num[i] - '0';
            val_str.push_back(num[i]);
            // Avoid overflow and "00...".
            if (to_string(val) != val_str) {
                break;
            }
            expr.emplace_back(val_str);
            addOperatorsDFS(num, target, i + 1, 0, val, &expr, &result);
            expr.pop_back();
        }
        return result;
    }

    void addOperatorsDFS(const string& num, const int& target, const int& pos,
                         const int& operand1, const int& operand2, vector<string> *expr,
                         vector<string> *result) {
        if (pos == num.length()) {
            if (operand1 + operand2 == target) {
                result->emplace_back(move(join(*expr)));
            }
            return;
        }

        int val = 0;
        string val_str;
        for (int i = pos; i < num.length(); ++i) {
            val = val * 10 + num[i] - '0';
            val_str.push_back(num[i]);
            // Avoid overflow and "00...".
            if (to_string(val) != val_str) {
                break;
            }

            // Case '+':
            expr->emplace_back("+" + val_str);
            addOperatorsDFS(num, target, i + 1, operand1 + operand2, val, expr, result);
            expr->pop_back();

            // Case '-':
            expr->emplace_back("-" + val_str);
            addOperatorsDFS(num, target, i + 1, operand1 + operand2, -val, expr, result);
            expr->pop_back();

            // Case '*':
            expr->emplace_back("*" + val_str);
            addOperatorsDFS(num, target, i + 1, operand1, operand2 * val, expr, result);
            expr->pop_back();
        }
    }

    string join(const vector<string>& expr) {
        ostringstream stream;
        copy(expr.cbegin(), expr.cend(), ostream_iterator<string>(stream));
        return stream.str();
    }
};
<|endoftext|>


<commit_before>// Time:  O(n)
// Space: O(k), k is size of the alphabet

// vector solution, need to know size of the alphabet in advance (4ms)
class Solution {
public:
    string removeDuplicateLetters(string s) {
        const int k = 26;
        vector<int> cnts(k);
        for (const auto& c : s) {
            ++cnts[c - 'a'];
        }

        vector<bool> visited(k);
        string stk;
        for (const auto& c : s) {
            if (!visited[c - 'a']) {
                while (!stk.empty() && stk.back() > c && cnts[stk.back() - 'a']) {
                    visited[stk.back() - 'a'] = false;
                    stk.pop_back();
                }
                stk.push_back(c);
                visited[c - 'a'] = true;
            }
            --cnts[c - 'a'];
        }
        return stk;
    }
};

// Time:  O(n)
// Space: O(k), k is size of the alphabet
// hash solution, no need to know size of the alphabet in advance (16ms)
class Solution2 {
public:
    string removeDuplicateLetters(string s) {
        unordered_map<char, int> cnts;
        for (const auto& c : s) {
            ++cnts[c];
        }

        unordered_set<char> visited;
        string stk;
        for (const auto& c : s) {
            if (!visited.count(c)) {
                while (!stk.empty() && stk.back() > c && cnts[stk.back()]) {
                    visited.erase(stk.back());
                    stk.pop_back();
                }
                stk.push_back(c);
                visited.emplace(c);
            }
            --cnts[c];
        }
        return stk;
    }
};
<commit_msg>Update remove-duplicate-letters.cpp<commit_after>// Time:  O(n)
// Space: O(k), k is size of the alphabet

// vector solution, need to know size of the alphabet in advance (4ms)
class Solution {
public:
    string removeDuplicateLetters(string s) {
        const int k = 26;
        vector<int> cnts(k);
        for (const auto& c : s) {
            ++cnts[c - 'a'];
        }

        vector<bool> in_stack(k);
        string stk;
        for (const auto& c : s) {
            if (!in_stack[c - 'a']) {
                while (!stk.empty() && stk.back() > c && cnts[stk.back() - 'a']) {
                    in_stack[stk.back() - 'a'] = false;
                    stk.pop_back();
                }
                stk.push_back(c);
                in_stack[c - 'a'] = true;
            }
            --cnts[c - 'a'];
        }
        return stk;
    }
};

// Time:  O(n)
// Space: O(k), k is size of the alphabet
// hash solution, no need to know size of the alphabet in advance (16ms)
class Solution2 {
public:
    string removeDuplicateLetters(string s) {
        unordered_map<char, int> cnts;
        for (const auto& c : s) {
            ++cnts[c];
        }

        unordered_set<char> in_stack;
        string stk;
        for (const auto& c : s) {
            if (!in_stack.count(c)) {
                while (!stk.empty() && stk.back() > c && cnts[stk.back()]) {
                    in_stack.erase(stk.back());
                    stk.pop_back();
                }
                stk.push_back(c);
                in_stack.emplace(c);
            }
            --cnts[c];
        }
        return stk;
    }
};
<|endoftext|>


<commit_before><commit_msg>Delete scientific - original.hpp<commit_after><|endoftext|>