<commit_before>//
//  main.cpp
//  All the Data Structures
//
//  Created by Sophia Nguyen on 2016-06-19.
//  Copyright © 2016 Sophia Nguyen. All rights reserved.
//

#include <iostream>
#include "datastructtypes.h"

int main(int argc, const char * argv[]) {
    std::cout << "Testing out my sparkly, new stack...\n";
    Stack testStack(5);

    testStack.Push(1);
    testStack.Push(5);
    testStack.Push(3);
    testStack.Push(4);
    int* testArray = testStack.get_Arr();

    for (int i = 3; i >= 0; i--) {
        std::cout << testArray[i] << endl;
    }

    return 0;
}
<commit_msg>Add files via upload<commit_after>//
//  main.cpp
//  All the Sorts
//
//  Created by Sophia Nguyen on 2016-06-18.
//  Copyright © 2016 Sophia Nguyen. All rights reserved.
//

#include <iostream>
#include "sorttypes.h"

int main() {
    // Testing Selection Sort
    std::cout << "Here's an unsorted array!" << std::endl;

    int arr[] = {2,7,4,1,5,3};
    for (int i = 0; i < 6; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << "\nRunning selection sort..." << std::endl;
    selectionSort(arr, 6);
    for (int i = 0; i < 6; i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << "\n";

    // Testing Insertion Sort
    std::cout << "Here's another unsorted array!" << std::endl;

    int arr2[] = {6,3,1,0,8,8};
    for (int i = 0; i < 6; i++) {
        std::cout << arr2[i] << " ";
    }
    std::cout << "\nRunning insertion sort..." << std::endl;
    insertionSort(arr2, 6);
    for (int i = 0; i < 6; i++) {
        std::cout << arr2[i] << " ";
    }
    std::cout << "\n";
    return 0;
}<|endoftext|>


<commit_before>#include "main.hpp"
#include "get_input.hpp"
#include "set_asound.hpp"
#include "set_battery.hpp"
#include "set_hwmon.hpp"
#include "set_ipv4.hpp"
#include "set_nvidia.hpp"
#include "set_pause.hpp"
#include "set_time.hpp"
#include "set_wlan.hpp"
#include "string_to.hpp"

#include <fstream>
#include <getopt.h>
#include <jsoncpp/json/json.h>
#include <math.h>
#include <vector>
#include <future>

using namespace std;

Json::Value j_output;
string s_output = "";
bool b_json = true;
bool b_loop = true;
bool b_input = true;
bool b_colored = true;
bool b_tmux = false;
bool b_use_input = false;
int timeout = 5;
string color_normal = "#ffffff", color_urgent = "#ff0000", color_warning = "#00ffff";
vector <bar_config> my_bar_config;

modes string2modes (string input) {
    if (input == "asound") return m_asound;
    if (input == "battery") return m_battery;
    if (input == "hwmon") return m_hwmon;
    if (input == "ipv4") return m_ipv4;
    if (input == "nvidia") return m_nvidia;
    if (input == "time") return m_time;
    if (input == "wlan") return m_wlan;
    return m_null;
}

void add_output (bar_config my_bar_config) {
    Json::Value output;
    if (b_colored) {
        if (my_bar_config.output.color.empty()) {
            if (my_bar_config.output.integer > -1) {
                if (my_bar_config.output.integer > my_bar_config.input.urgent)
                    my_bar_config.output.color = my_bar_config.color.urgent;
                else
                    my_bar_config.output.color = my_bar_config.color.normal;
            } else {
                my_bar_config.output.color = my_bar_config.color.warning;
            }
        }
    }
    switch (b_json) {
    case true:
        output["name"] = my_bar_config.input.name;
        output["full_text"] = my_bar_config.input.label + my_bar_config.output.output;
        output["color"] = my_bar_config.output.color;
        if (!my_bar_config.icon.name.empty()) {
            output["icon_color"] = my_bar_config.output.color;
            if (!my_bar_config.icon.mask.empty()) {
                if (my_bar_config.output.integer > -1) {
                    if (my_bar_config.output.integer < 100) {
                        my_bar_config.output.icon = my_bar_config.icon.mask + to_string((int)ceil((float)my_bar_config.output.integer*(float)my_bar_config.icon.count/(float)100)) + my_bar_config.icon.ext;
                    } else {
                        my_bar_config.output.icon = my_bar_config.icon.mask + to_string(my_bar_config.icon.count) + my_bar_config.icon.ext;
                    }
                } else {
                    my_bar_config.output.icon = my_bar_config.icon.mask + "0" + my_bar_config.icon.ext;
                }
                output["icon"] = my_bar_config.output.icon;
            } else {
                my_bar_config.output.icon = my_bar_config.icon.name;
                output["icon"] = my_bar_config.output.icon;
            }
        }
        j_output.append (output);
        break;
    case false:
        if (!s_output.empty())
            s_output += " | ";
        if (b_colored) {
            if (b_tmux) {
                s_output += "#[fg=" + my_bar_config.output.color + "]" + my_bar_config.input.label + my_bar_config.output.output + "#[fg=" + color_normal + "]";
            } else {
                s_output += "\033[" + my_bar_config.output.color + "m" + my_bar_config.input.label + my_bar_config.output.output + "\033[" + color_normal + "m";
            }
        } else {
            s_output += my_bar_config.input.label + my_bar_config.output.output;
        }
        break;
    }
    my_bar_config.output.output.clear();
    //my_bar_config.max_output.clear();
    my_bar_config.output.icon.clear();
    my_bar_config.output.color.clear();
    my_bar_config.output.integer = -1;
}

void show_output () {
    Json::FastWriter writer;
    switch (b_json) {
    case true:
        if (j_output.empty())
            cout << endl;
        else
            cout << writer.write (j_output) << "," << endl;
        j_output.clear();
        break;
    case false:
        if (s_output.empty())
            cout << endl;
        else
            cout << s_output << endl;
        s_output.clear();
        break;
    }
}

void show_help (string cmd) {
    cout << "usage: " << cmd << " config.json" << endl;
}

int read_config (string config_path) {
    Json::Value config;
    Json::Value element;
    Json::Reader reader;
    ifstream config_file;
    config_file.open (config_path);
    if (config_path.empty()) {
        cerr << "no config file" << endl;
        return -1;
    }
    if (!config_file.is_open()) {
        cerr << config_path << ": can't open" << endl;
        return -1;
    }
    if (!reader.parse (config_file, config, false)) {
        cerr << config_path << ": " << reader.getFormattedErrorMessages() << endl;
        return 1;
    }
    config_file.close();
    b_json = config.get("json", true).asBool();
    b_loop = config.get("loop", true).asBool();
    b_input = config.get("input", true).asBool();
    b_colored = config.get("colored", true).asBool();
    b_tmux = config.get("tmux", false).asBool();
    timeout = config.get("timeout", 5).asInt();
    if (b_colored) {
        if (b_json) {
            color_normal = config.get ("color_normal", "#ffffff").asString();
            color_urgent = config.get ("color_urgent", "#ff0000").asString();
            color_warning = config.get ("color_warning", "#00ffff").asString();
        } else {
            if (b_tmux) {
                color_normal = config.get("color_normal", "white").asString();
                color_urgent = config.get("color_urgent", "red").asString();
                color_warning = config.get("color_warning", "cyan").asString();
            } else {
                color_normal = config.get("color_normal", "37").asString();
                color_urgent = config.get("color_urgent", "31").asString();
                color_warning = config.get("color_warning", "36").asString();
            }
        }
    }
    if (!b_json || !b_loop)
        b_input = false;
    vector <string> names = config.getMemberNames();
    for (unsigned int counter = 0; counter < names.size(); ++counter) {
        if (config[names[counter]].isObject()) {
            my_bar_config.push_back (bar_config());
            element = config[names.at (counter)];
            my_bar_config.back().input.name = names.at (counter);
            my_bar_config.back().mode = string2modes (element.get ("mode", "").asString());
            my_bar_config.back().input.device = element.get ("device", "").asString();
            my_bar_config.back().input.offset = element.get ("offset", 0).asInt();
            my_bar_config.back().input.param = element.get ("param", "").asString();
            my_bar_config.back().input.label = element.get ("label", "").asString();
            if (b_colored) {
                my_bar_config.back().input.urgent = element.get ("urgent", 0).asInt();
                my_bar_config.back().color.normal = element.get ("color_normal", color_normal).asString();
                my_bar_config.back().color.urgent = element.get ("color_urgent", color_urgent).asString();
                my_bar_config.back().color.warning = element.get ("color_warning", color_warning).asString();
            }
            if (b_json) {
                //my_bar_config.back().align = element.get ("align", "center").asString();
                my_bar_config.back().icon.name = element.get ("icon", "").asString();
                //my_bar_config.back().width = element.get ("width", false).asBool();
                if (!my_bar_config.back().icon.name.empty()) {
                    size_t begin = my_bar_config.back().icon.name.find_first_of("%");
                    size_t end = my_bar_config.back().icon.name.find_last_of(".");
                    if ((begin != string::npos) && (end != string::npos)) {
                        my_bar_config.back().icon.mask = (my_bar_config.back().icon.name.substr(0,begin));
                        my_bar_config.back().icon.ext = (my_bar_config.back().icon.name.substr(end));
                        if (!string_to_int (my_bar_config.back().icon.name.substr(begin+1,end-begin-1), my_bar_config.back().icon.count)) {
                            cerr << my_bar_config.back().input.name << ": icon format error" << endl;
                            return 1;
                        }
                    }
                }

                if (b_input) {
                    //my_input_config.push_back (input_config());
                    //my_input_config.back().name = names.at (counter);
                    my_bar_config.back().exec.exec1 = element.get ("exec1", "").asString();
                    my_bar_config.back().exec.exec2 = element.get ("exec2", "").asString();
                    my_bar_config.back().exec.exec3 = element.get ("exec3", "").asString();
                    if ((!my_bar_config.back().exec.exec1.empty()) || (!my_bar_config.back().exec.exec2.empty()) || (!my_bar_config.back().exec.exec3.empty()))
                        b_use_input = true;
                    //if ((my_input_config.back().exec1.size() == 0) && (my_input_config.back().exec2.size() == 0) && (my_input_config.back().exec3.size() == 0))
                        //my_input_config.pop_back();
                }
            }
                    if (my_bar_config.back().mode == m_null)
                        my_bar_config.pop_back();
        }
    }
    return 0;
}

int main (int argc, char *argv[]) {
    int return_value;
    string config_file = "";
    if (argc > 1) {
        int cmd;
        while ((cmd = getopt (argc, argv, "?")) != -1) {
            switch (cmd) {
            case '?':
                show_help(argv[0]);
                return 1;
                break;
            }
        }
    } else {
        show_help(argv[0]);
        return 1;
    }
    if (optind < argc) {
        while (optind < argc) {
            config_file = argv[optind++];
        }
    } else {
        show_help(argv[0]);
        return 1;
    }
    if (read_config (config_file) != 0)
        return 1;
    if (my_bar_config.empty())
        return 1;
    future <void> input = async (launch::async, get_input, my_bar_config, b_use_input);
    if (b_json) {
        if (b_input)
            cout << "{ \"version\": 1, \"click_events\": true }" << endl;
        else
            cout << "{ \"version\": 1 }" << endl;
        cout << "[" << endl;
    }
    do {
        return_value = 0;
        for (unsigned int counter = 0; counter < my_bar_config.size(); ++counter) {
            switch (my_bar_config.at (counter).mode) {
            case m_null:
                break;
            case m_asound:
                return_value = set_asound (my_bar_config.at (counter));
                break;
            case m_battery:
                return_value = set_battery (my_bar_config.at (counter));
                break;
            case m_hwmon:
                return_value = set_hwmon (my_bar_config.at (counter));
                break;
            case m_ipv4:
                return_value = set_ipv4 (my_bar_config.at (counter));
                break;
            case m_nvidia:
                return_value = set_nvidia (my_bar_config.at (counter));
                break;
            case m_time:
                return_value = set_time (my_bar_config.at (counter));
                break;
            case m_wlan:
                return_value = set_wlan (my_bar_config.at (counter));
                break;
            }
            if (return_value == 0) {
                add_output (my_bar_config.at (counter));
                if (b_colored)
                    my_bar_config.at (counter).output.color = my_bar_config.at (counter).color.normal;
            }
            if (return_value > 0) {
                my_bar_config.at (counter).output.output = "ERR" + to_string (return_value);
                if (b_colored)
                    my_bar_config.at (counter).output.color = my_bar_config.at (counter).color.urgent;
                add_output (my_bar_config.at (counter));
            }
        }
        show_output();
        if (b_loop)
            set_pause (timeout);
    } while (b_loop);
    return 0;
}
<commit_msg>better color fix<commit_after>#include "main.hpp"
#include "get_input.hpp"
#include "set_asound.hpp"
#include "set_battery.hpp"
#include "set_hwmon.hpp"
#include "set_ipv4.hpp"
#include "set_nvidia.hpp"
#include "set_pause.hpp"
#include "set_time.hpp"
#include "set_wlan.hpp"
#include "string_to.hpp"

#include <fstream>
#include <getopt.h>
#include <jsoncpp/json/json.h>
#include <math.h>
#include <vector>
#include <future>

using namespace std;

Json::Value j_output;
string s_output = "";
bool b_json = true;
bool b_loop = true;
bool b_input = true;
bool b_colored = true;
bool b_tmux = false;
bool b_use_input = false;
int timeout = 5;
string color_normal = "#ffffff", color_urgent = "#ff0000", color_warning = "#00ffff";
vector <bar_config> my_bar_config;

modes string2modes (string input) {
    if (input == "asound") return m_asound;
    if (input == "battery") return m_battery;
    if (input == "hwmon") return m_hwmon;
    if (input == "ipv4") return m_ipv4;
    if (input == "nvidia") return m_nvidia;
    if (input == "time") return m_time;
    if (input == "wlan") return m_wlan;
    return m_null;
}

void add_output (bar_config my_bar_config) {
    Json::Value output;
    if (b_colored) {
        if (my_bar_config.output.color.empty()) {
            if (my_bar_config.output.integer > -1) {
                if (my_bar_config.output.integer > my_bar_config.input.urgent)
                    my_bar_config.output.color = my_bar_config.color.urgent;
                else
                    my_bar_config.output.color = my_bar_config.color.normal;
            } else {
                my_bar_config.output.color = my_bar_config.color.warning;
            }
        }
    }
    switch (b_json) {
    case true:
        output["name"] = my_bar_config.input.name;
        output["full_text"] = my_bar_config.input.label + my_bar_config.output.output;
        output["color"] = my_bar_config.output.color;
        if (!my_bar_config.icon.name.empty()) {
            output["icon_color"] = my_bar_config.output.color;
            if (!my_bar_config.icon.mask.empty()) {
                if (my_bar_config.output.integer > -1) {
                    if (my_bar_config.output.integer < 100) {
                        my_bar_config.output.icon = my_bar_config.icon.mask + to_string((int)ceil((float)my_bar_config.output.integer*(float)my_bar_config.icon.count/(float)100)) + my_bar_config.icon.ext;
                    } else {
                        my_bar_config.output.icon = my_bar_config.icon.mask + to_string(my_bar_config.icon.count) + my_bar_config.icon.ext;
                    }
                } else {
                    my_bar_config.output.icon = my_bar_config.icon.mask + "0" + my_bar_config.icon.ext;
                }
                output["icon"] = my_bar_config.output.icon;
            } else {
                my_bar_config.output.icon = my_bar_config.icon.name;
                output["icon"] = my_bar_config.output.icon;
            }
        }
        j_output.append (output);
        break;
    case false:
        if (!s_output.empty())
            s_output += " | ";
        if (b_colored) {
            if (b_tmux) {
                s_output += "#[fg=" + my_bar_config.output.color + "]" + my_bar_config.input.label + my_bar_config.output.output + "#[fg=" + color_normal + "]";
            } else {
                s_output += "\033[" + my_bar_config.output.color + "m" + my_bar_config.input.label + my_bar_config.output.output + "\033[" + color_normal + "m";
            }
        } else {
            s_output += my_bar_config.input.label + my_bar_config.output.output;
        }
        break;
    }
    my_bar_config.output.output.clear();
    //my_bar_config.max_output.clear();
    my_bar_config.output.icon.clear();
    my_bar_config.output.color.clear();
    my_bar_config.output.integer = -1;
}

void show_output () {
    Json::FastWriter writer;
    switch (b_json) {
    case true:
        if (j_output.empty())
            cout << endl;
        else
            cout << writer.write (j_output) << "," << endl;
        j_output.clear();
        break;
    case false:
        if (s_output.empty())
            cout << endl;
        else
            cout << s_output << endl;
        s_output.clear();
        break;
    }
}

void show_help (string cmd) {
    cout << "usage: " << cmd << " config.json" << endl;
}

int read_config (string config_path) {
    Json::Value config;
    Json::Value element;
    Json::Reader reader;
    ifstream config_file;
    config_file.open (config_path);
    if (config_path.empty()) {
        cerr << "no config file" << endl;
        return -1;
    }
    if (!config_file.is_open()) {
        cerr << config_path << ": can't open" << endl;
        return -1;
    }
    if (!reader.parse (config_file, config, false)) {
        cerr << config_path << ": " << reader.getFormattedErrorMessages() << endl;
        return 1;
    }
    config_file.close();
    b_json = config.get("json", true).asBool();
    b_loop = config.get("loop", true).asBool();
    b_input = config.get("input", true).asBool();
    b_colored = config.get("colored", true).asBool();
    b_tmux = config.get("tmux", false).asBool();
    timeout = config.get("timeout", 5).asInt();
    if (b_colored) {
        if (b_json) {
            color_normal = config.get ("color_normal", "#ffffff").asString();
            color_urgent = config.get ("color_urgent", "#ff0000").asString();
            color_warning = config.get ("color_warning", "#00ffff").asString();
        } else {
            if (b_tmux) {
                color_normal = config.get("color_normal", "white").asString();
                color_urgent = config.get("color_urgent", "red").asString();
                color_warning = config.get("color_warning", "cyan").asString();
            } else {
                color_normal = config.get("color_normal", "37").asString();
                color_urgent = config.get("color_urgent", "31").asString();
                color_warning = config.get("color_warning", "36").asString();
            }
        }
    }
    if (!b_json || !b_loop)
        b_input = false;
    vector <string> names = config.getMemberNames();
    for (unsigned int counter = 0; counter < names.size(); ++counter) {
        if (config[names[counter]].isObject()) {
            my_bar_config.push_back (bar_config());
            element = config[names.at (counter)];
            my_bar_config.back().input.name = names.at (counter);
            my_bar_config.back().mode = string2modes (element.get ("mode", "").asString());
            my_bar_config.back().input.device = element.get ("device", "").asString();
            my_bar_config.back().input.offset = element.get ("offset", 0).asInt();
            my_bar_config.back().input.param = element.get ("param", "").asString();
            my_bar_config.back().input.label = element.get ("label", "").asString();
            if (b_colored) {
                my_bar_config.back().input.urgent = element.get ("urgent", 0).asInt();
                my_bar_config.back().color.normal = element.get ("color_normal", color_normal).asString();
                my_bar_config.back().color.urgent = element.get ("color_urgent", color_urgent).asString();
                my_bar_config.back().color.warning = element.get ("color_warning", color_warning).asString();
            }
            if (b_json) {
                //my_bar_config.back().align = element.get ("align", "center").asString();
                my_bar_config.back().icon.name = element.get ("icon", "").asString();
                //my_bar_config.back().width = element.get ("width", false).asBool();
                if (!my_bar_config.back().icon.name.empty()) {
                    size_t begin = my_bar_config.back().icon.name.find_first_of("%");
                    size_t end = my_bar_config.back().icon.name.find_last_of(".");
                    if ((begin != string::npos) && (end != string::npos)) {
                        my_bar_config.back().icon.mask = (my_bar_config.back().icon.name.substr(0,begin));
                        my_bar_config.back().icon.ext = (my_bar_config.back().icon.name.substr(end));
                        if (!string_to_int (my_bar_config.back().icon.name.substr(begin+1,end-begin-1), my_bar_config.back().icon.count)) {
                            cerr << my_bar_config.back().input.name << ": icon format error" << endl;
                            return 1;
                        }
                    }
                }

                if (b_input) {
                    //my_input_config.push_back (input_config());
                    //my_input_config.back().name = names.at (counter);
                    my_bar_config.back().exec.exec1 = element.get ("exec1", "").asString();
                    my_bar_config.back().exec.exec2 = element.get ("exec2", "").asString();
                    my_bar_config.back().exec.exec3 = element.get ("exec3", "").asString();
                    if ((!my_bar_config.back().exec.exec1.empty()) || (!my_bar_config.back().exec.exec2.empty()) || (!my_bar_config.back().exec.exec3.empty()))
                        b_use_input = true;
                    //if ((my_input_config.back().exec1.size() == 0) && (my_input_config.back().exec2.size() == 0) && (my_input_config.back().exec3.size() == 0))
                        //my_input_config.pop_back();
                }
            }
                    if (my_bar_config.back().mode == m_null)
                        my_bar_config.pop_back();
        }
    }
    return 0;
}

int main (int argc, char *argv[]) {
    int return_value;
    string config_file = "";
    if (argc > 1) {
        int cmd;
        while ((cmd = getopt (argc, argv, "?")) != -1) {
            switch (cmd) {
            case '?':
                show_help(argv[0]);
                return 1;
                break;
            }
        }
    } else {
        show_help(argv[0]);
        return 1;
    }
    if (optind < argc) {
        while (optind < argc) {
            config_file = argv[optind++];
        }
    } else {
        show_help(argv[0]);
        return 1;
    }
    if (read_config (config_file) != 0)
        return 1;
    if (my_bar_config.empty())
        return 1;
    future <void> input = async (launch::async, get_input, my_bar_config, b_use_input);
    if (b_json) {
        if (b_input)
            cout << "{ \"version\": 1, \"click_events\": true }" << endl;
        else
            cout << "{ \"version\": 1 }" << endl;
        cout << "[" << endl;
    }
    do {
        return_value = 0;
        for (unsigned int counter = 0; counter < my_bar_config.size(); ++counter) {
            switch (my_bar_config.at (counter).mode) {
            case m_null:
                break;
            case m_asound:
                return_value = set_asound (my_bar_config.at (counter));
                break;
            case m_battery:
                return_value = set_battery (my_bar_config.at (counter));
                break;
            case m_hwmon:
                return_value = set_hwmon (my_bar_config.at (counter));
                break;
            case m_ipv4:
                return_value = set_ipv4 (my_bar_config.at (counter));
                break;
            case m_nvidia:
                return_value = set_nvidia (my_bar_config.at (counter));
                break;
            case m_time:
                return_value = set_time (my_bar_config.at (counter));
                break;
            case m_wlan:
                return_value = set_wlan (my_bar_config.at (counter));
                break;
            }
            if (return_value == 0) {
                add_output (my_bar_config.at (counter));
            }
            if (return_value > 0) {
                my_bar_config.at (counter).output.output = "ERR" + to_string (return_value);
                if (b_colored)
                    my_bar_config.at (counter).output.color = my_bar_config.at (counter).color.urgent;
                add_output (my_bar_config.at (counter));
                if (b_colored)
                    my_bar_config.at (counter).output.color.clear();
            }
        }
        show_output();
        if (b_loop)
            set_pause (timeout);
    } while (b_loop);
    return 0;
}
<|endoftext|>


<commit_before>

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>

#include <arpa/inet.h>
#include <string.h>

#include "config.h"
#include "option.h"
#include "error.h"
#include "backend.h"
#include "format.h"
#include "server.h"
#include "udp_socket.h"
#include "packet.h"
#include "handler.h"

////////////////////////////////////////

void print_usage( const std::string &prog )
{
	std::cout << "Usage:\t" << prog << " [<config>] [<command> ...]\n";
	std::cout << "  <config> Configuration file as absolute path (starting with /)\n";
	std::cout << "  <command> Commend to execute (with arguments)\n";
	std::cout << "\nCommands:\n";
	std::cout << "  server [<pidfile>] - start a server (with optional pidfile)\n";
	std::cout << "  show <ip> - show options for <ip>\n";
	std::cout << "  option <ip> [<ip>] <option> - add option for IP range\n";
	std::cout << "  remove-option <ip> [<ip>] <option> - remove option for IP range\n";
	std::cout << "  host <ip> <mac> - add option for IP range\n";
	std::cout << "  remove-host <ip> - remove a host with a IP address\n";
	std::cout << "  list <mac> - list IP addresses for a MAC address\n";
	std::cout << "  available <mac> - list available IP addresses for a MAC address\n";
	std::cout << "  encode <option> - encode the option into a hex string\n";
	std::cout << "  decode <hex> - decode the hex option into something readable\n";
	std::cout << "  discover <ip> <mac> [<option> ...] - send a discover packet to an IP address\n";
	std::cout << "  monitor - listen for DHCP packets and show them\n";
	std::cout << "\nDHCP Options:\n";
	for ( auto opt: dhcp_options )
	{
		std::cout << "  " << opt.first;
		switch ( dhcp_types[opt.second] )
		{
			case TYPE_ADDRESS:
				std::cout << "(1.2.3.4)\n";
				break;
			case TYPE_ADDRESSES:
				std::cout << "(1.2.3.4,...)\n";
				break;
			case TYPE_HWADDR:
				std::cout << "(00:11:22:33:44:55)\n";
				break;
			case TYPE_STRING:
				std::cout << "(name)\n";
				break;
			case TYPE_UINT32:
				std::cout << "(1234)\n";
				break;
			case TYPE_UINT8:
				std::cout << "(12)\n";
				break;
			case TYPE_UINT8S:
				std::cout << "(12,...)\n";
				break;
		}
	}
}

////////////////////////////////////////

int main( int argc, char *argv[] )
{
	std::string config = "/etc/dhcpdb.conf";
	std::vector<std::string> command;

	for ( int i = 1; i < argc; ++i )
	{
		std::string arg( argv[i] );
		if ( arg.empty() )
			continue;

		if ( i == 1 && arg[0] == '/' )
			config = arg;
		else
			command.push_back( arg );
	}

	parse_config( config );

	// No command?
	if ( command.empty() )
	{
		print_usage( argv[0] );
		return 0;
	}

	if ( command[0] == "server" )
	{
		if ( command.size() > 2 )
			error( "Command 'server' has 1 optional argument: server <pidfile>" );

		if ( command.size() < 1 )
			command.push_back( std::string() );

		threadStartBackend();
		int ret = server( command[1] );
		threadStopBackend();
	}

	if ( command[0] == "show" )
	{
		threadStartBackend();
		if ( command.size() != 2 )
			error( "Command 'show' needs 1 arguments: show <ip>" );

		uint32_t ip = dns_lookup( command[1].c_str() );
		std::vector<std::string> options;
		getOptions( ip, options );
		bool addhost = true;
		for ( std::string &o: options )
		{
			if ( o.empty() )
				continue;
			if ( o[0] == DOP_HOSTNAME )
				addhost = false;
		}
		if ( addhost )
		{
			std::string hostname;
			try { hostname = ip_lookup( ip, false, false ); } catch ( ... ) {}
			if ( !hostname.empty() )
				options.push_back( format( "{0}{1}{2}", char(DOP_HOSTNAME), char(hostname.size()), hostname ) );
		}
		std::sort( options.begin(), options.end() );
		for ( const std::string &o: options )
			std::cout << print_options( o ) << '\n';
		if ( options.empty() )
			std::cout << "no options found\n";
		threadStopBackend();
	}
	else if ( command[0] == "option" )
	{
		threadStartBackend();
		if ( command.size() != 3 && command.size() != 4 )
			error( "Command 'option' needs 2 or 3 arguments: option <ip> [<ip>] <option>" );

		uint32_t ip1 = dns_lookup( command[1].c_str() );
		uint32_t ip2 = ip1;
		if ( command.size() == 4 )
			ip2 = dns_lookup( command[2].c_str() );
		std::string opt = parse_option( command.back() );
		addOption( ip1, ip2, opt );
		threadStopBackend();
	}
	else if ( command[0] == "remove-option" )
	{
		threadStartBackend();
		if ( command.size() != 3 && command.size() != 4  )
			error( "Command 'remove-option' needs 2 or 3 arguments: remove-option <ip> [<ip>] <option>" );

		uint32_t ip1 = dns_lookup( command[1].c_str() );
		uint32_t ip2 = ip1;
		if ( command.size() == 4 )
			ip2 = dns_lookup( command[2].c_str() );
		std::string opt = parse_option( command.back() );
		removeOption( ip1, ip2, opt );
		threadStopBackend();
	}
	else if ( command[0] == "host" )
	{
		threadStartBackend();
		if ( command.size() != 3 )
			error( "Command 'host' needs 2 arguments: host <ip> <mac>" );

		uint32_t ip = dns_lookup( command[1].c_str() );
		std::string mac = parse_mac( command[2] );
		addHost( ip, reinterpret_cast<const uint8_t*>( mac.data() ) );
		threadStopBackend();
	}
	else if ( command[0] == "remove-host" )
	{
		threadStartBackend();
		if ( command.size() != 2 )
			error( "Command 'remove-host' needs 1 arguments: remove-host <ip>" );

		uint32_t ip = dns_lookup( command[1].c_str() );
		removeHost( ip );
		threadStopBackend();
	}
	else if ( command[0] == "list" )
	{
		threadStartBackend();
		if ( command.size() != 2 )
			error( "Command 'list' needs 1 argument: list <mac>" );

		std::string mac = parse_mac( command[1] );
		std::vector<uint32_t> ips = getIPAddresses( reinterpret_cast<const uint8_t*>( mac.data() ) );
		for ( size_t i = 0; i < ips.size(); ++i )
			std::cout << as_hex<uint8_t>( reinterpret_cast<uint8_t*>(&ips[i]), 4, '.' ) << std::endl;
		if ( ips.empty() )
			std::cout << format( "no addresses found for {0,B16,w2,f0}", as_hex<char>( mac, ':' ) ) << std::endl;
		threadStopBackend();
	}
	else if ( command[0] == "available" )
	{
		threadStartBackend();
		if ( command.size() != 2 )
			error( "Command 'available' needs 1 argument: available <mac>" );

		std::string mac = parse_mac( command[1] );
		std::vector<uint32_t> ips = getIPAddresses( reinterpret_cast<const uint8_t*>( mac.data() ), true );
		for ( size_t i = 0; i < ips.size(); ++i )
			std::cout << ip_lookup( ips[i] ) << std::endl;
		if ( ips.empty() )
			std::cout << format( "no addresses found for {0,B16,w2,f0}", as_hex<char>( mac, ':' ) ) << std::endl;
		threadStopBackend();
	}
	else if ( command[0] == "decode" )
	{
		if ( command.size() != 2 )
			error( "Command 'decode' needs 1 argument: decode <hex>" );

		std::string o = print_options( from_hex( command[1] ) );
		std::cout << o << std::endl;
	}
	else if ( command[0] == "encode" )
	{
		if ( command.size() != 2 )
			error( "Command 'encode' needs 1 argument: encode <option>" );

		std::string o = parse_option( command[1] );
		std::cout << format( "{0,B16,w2,f0}", as_hex<char>( o ) ) << std::endl;
	}
	else if ( command[0] == "discover" )
	{
		if ( command.size() < 3 )
			error( "Command 'discover' needs 2 or more argument: discover <ip> <mac> [<options> ...]" );

		uint32_t addr = dns_lookup( command[1].c_str() );
		std::string mac = parse_mac( command[2] );

		packet p;
		memset( &p, 0, sizeof(p) );
		p.op = BOOT_REQUEST;
		p.htype = HWADDR_ETHER;
		p.hlen = 6;
		p.xid = 0xCAFEBEEF;
		memcpy( p.chaddr, mac.c_str(), 6 );

		std::vector<std::string> opts;
		opts.push_back( parse_option( "msgtype(1)" ) );
		opts.push_back( parse_option( "param_requested(1,3,6,12,15,54,66,67" ) );
		opts.push_back( parse_option( "vendorid(DHCPDB discover test)" ) );
		for ( size_t i = 3; i < command.size(); ++i )
			opts.push_back( parse_option( command[i] ) );
		fillOptions( &p, opts );

		udp_socket s( INADDR_ANY, 0, true );
		s.send( addr, 67, &p );
		std::cout << "Sent:\n" << &p << std::endl;
	}
	else if ( command[0] == "monitor" )
	{
		if ( command.size() != 1 )
			error( "Command 'monitor' needs no arguments: monitor" );

		udp_socket s( INADDR_ANY, 67, false );
		packet p;

		while ( 1 )
		{
			try
			{
				s.recv( &p );
				std::cout << "Received:\n" << &p << std::endl;
			}
			catch ( std::exception &e )
			{
				std::cout << "Error: " << e.what() << std::endl;
				break;
			}
			catch ( ... )
			{
				std::cout << "Error: unknown" << std::endl;
				break;
			}
		}
	}
	else
	{
		print_usage( argv[0] );
	}

	return 0;
}

<commit_msg>Added ip address to monitor.<commit_after>

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>

#include <arpa/inet.h>
#include <string.h>

#include "config.h"
#include "option.h"
#include "error.h"
#include "backend.h"
#include "format.h"
#include "server.h"
#include "udp_socket.h"
#include "packet.h"
#include "handler.h"

////////////////////////////////////////

void print_usage( const std::string &prog )
{
	std::cout << "Usage:\t" << prog << " [<config>] [<command> ...]\n";
	std::cout << "  <config> Configuration file as absolute path (starting with /)\n";
	std::cout << "  <command> Commend to execute (with arguments)\n";
	std::cout << "\nCommands:\n";
	std::cout << "  server [<pidfile>] - start a server (with optional pidfile)\n";
	std::cout << "  show <ip> - show options for <ip>\n";
	std::cout << "  option <ip> [<ip>] <option> - add option for IP range\n";
	std::cout << "  remove-option <ip> [<ip>] <option> - remove option for IP range\n";
	std::cout << "  host <ip> <mac> - add option for IP range\n";
	std::cout << "  remove-host <ip> - remove a host with a IP address\n";
	std::cout << "  list <mac> - list IP addresses for a MAC address\n";
	std::cout << "  available <mac> - list available IP addresses for a MAC address\n";
	std::cout << "  encode <option> - encode the option into a hex string\n";
	std::cout << "  decode <hex> - decode the hex option into something readable\n";
	std::cout << "  discover <ip> <mac> [<option> ...] - send a discover packet to an IP address\n";
	std::cout << "  monitor - listen for DHCP packets and show them\n";
	std::cout << "\nDHCP Options:\n";
	for ( auto opt: dhcp_options )
	{
		std::cout << "  " << opt.first;
		switch ( dhcp_types[opt.second] )
		{
			case TYPE_ADDRESS:
				std::cout << "(1.2.3.4)\n";
				break;
			case TYPE_ADDRESSES:
				std::cout << "(1.2.3.4,...)\n";
				break;
			case TYPE_HWADDR:
				std::cout << "(00:11:22:33:44:55)\n";
				break;
			case TYPE_STRING:
				std::cout << "(name)\n";
				break;
			case TYPE_UINT32:
				std::cout << "(1234)\n";
				break;
			case TYPE_UINT8:
				std::cout << "(12)\n";
				break;
			case TYPE_UINT8S:
				std::cout << "(12,...)\n";
				break;
		}
	}
}

////////////////////////////////////////

int main( int argc, char *argv[] )
{
	std::string config = "/etc/dhcpdb.conf";
	std::vector<std::string> command;

	for ( int i = 1; i < argc; ++i )
	{
		std::string arg( argv[i] );
		if ( arg.empty() )
			continue;

		if ( i == 1 && arg[0] == '/' )
			config = arg;
		else
			command.push_back( arg );
	}

	parse_config( config );

	// No command?
	if ( command.empty() )
	{
		print_usage( argv[0] );
		return 0;
	}

	if ( command[0] == "server" )
	{
		if ( command.size() > 2 )
			error( "Command 'server' has 1 optional argument: server <pidfile>" );

		if ( command.size() < 1 )
			command.push_back( std::string() );

		threadStartBackend();
		int ret = server( command[1] );
		threadStopBackend();
	}

	if ( command[0] == "show" )
	{
		threadStartBackend();
		if ( command.size() != 2 )
			error( "Command 'show' needs 1 arguments: show <ip>" );

		uint32_t ip = dns_lookup( command[1].c_str() );
		std::vector<std::string> options;
		getOptions( ip, options );
		bool addhost = true;
		for ( std::string &o: options )
		{
			if ( o.empty() )
				continue;
			if ( o[0] == DOP_HOSTNAME )
				addhost = false;
		}
		if ( addhost )
		{
			std::string hostname;
			try { hostname = ip_lookup( ip, false, false ); } catch ( ... ) {}
			if ( !hostname.empty() )
				options.push_back( format( "{0}{1}{2}", char(DOP_HOSTNAME), char(hostname.size()), hostname ) );
		}
		std::sort( options.begin(), options.end() );
		for ( const std::string &o: options )
			std::cout << print_options( o ) << '\n';
		if ( options.empty() )
			std::cout << "no options found\n";
		threadStopBackend();
	}
	else if ( command[0] == "option" )
	{
		threadStartBackend();
		if ( command.size() != 3 && command.size() != 4 )
			error( "Command 'option' needs 2 or 3 arguments: option <ip> [<ip>] <option>" );

		uint32_t ip1 = dns_lookup( command[1].c_str() );
		uint32_t ip2 = ip1;
		if ( command.size() == 4 )
			ip2 = dns_lookup( command[2].c_str() );
		std::string opt = parse_option( command.back() );
		addOption( ip1, ip2, opt );
		threadStopBackend();
	}
	else if ( command[0] == "remove-option" )
	{
		threadStartBackend();
		if ( command.size() != 3 && command.size() != 4  )
			error( "Command 'remove-option' needs 2 or 3 arguments: remove-option <ip> [<ip>] <option>" );

		uint32_t ip1 = dns_lookup( command[1].c_str() );
		uint32_t ip2 = ip1;
		if ( command.size() == 4 )
			ip2 = dns_lookup( command[2].c_str() );
		std::string opt = parse_option( command.back() );
		removeOption( ip1, ip2, opt );
		threadStopBackend();
	}
	else if ( command[0] == "host" )
	{
		threadStartBackend();
		if ( command.size() != 3 )
			error( "Command 'host' needs 2 arguments: host <ip> <mac>" );

		uint32_t ip = dns_lookup( command[1].c_str() );
		std::string mac = parse_mac( command[2] );
		addHost( ip, reinterpret_cast<const uint8_t*>( mac.data() ) );
		threadStopBackend();
	}
	else if ( command[0] == "remove-host" )
	{
		threadStartBackend();
		if ( command.size() != 2 )
			error( "Command 'remove-host' needs 1 arguments: remove-host <ip>" );

		uint32_t ip = dns_lookup( command[1].c_str() );
		removeHost( ip );
		threadStopBackend();
	}
	else if ( command[0] == "list" )
	{
		threadStartBackend();
		if ( command.size() != 2 )
			error( "Command 'list' needs 1 argument: list <mac>" );

		std::string mac = parse_mac( command[1] );
		std::vector<uint32_t> ips = getIPAddresses( reinterpret_cast<const uint8_t*>( mac.data() ) );
		for ( size_t i = 0; i < ips.size(); ++i )
			std::cout << as_hex<uint8_t>( reinterpret_cast<uint8_t*>(&ips[i]), 4, '.' ) << std::endl;
		if ( ips.empty() )
			std::cout << format( "no addresses found for {0,B16,w2,f0}", as_hex<char>( mac, ':' ) ) << std::endl;
		threadStopBackend();
	}
	else if ( command[0] == "available" )
	{
		threadStartBackend();
		if ( command.size() != 2 )
			error( "Command 'available' needs 1 argument: available <mac>" );

		std::string mac = parse_mac( command[1] );
		std::vector<uint32_t> ips = getIPAddresses( reinterpret_cast<const uint8_t*>( mac.data() ), true );
		for ( size_t i = 0; i < ips.size(); ++i )
			std::cout << ip_lookup( ips[i] ) << std::endl;
		if ( ips.empty() )
			std::cout << format( "no addresses found for {0,B16,w2,f0}", as_hex<char>( mac, ':' ) ) << std::endl;
		threadStopBackend();
	}
	else if ( command[0] == "decode" )
	{
		if ( command.size() != 2 )
			error( "Command 'decode' needs 1 argument: decode <hex>" );

		std::string o = print_options( from_hex( command[1] ) );
		std::cout << o << std::endl;
	}
	else if ( command[0] == "encode" )
	{
		if ( command.size() != 2 )
			error( "Command 'encode' needs 1 argument: encode <option>" );

		std::string o = parse_option( command[1] );
		std::cout << format( "{0,B16,w2,f0}", as_hex<char>( o ) ) << std::endl;
	}
	else if ( command[0] == "discover" )
	{
		if ( command.size() < 3 )
			error( "Command 'discover' needs 2 or more argument: discover <ip> <mac> [<options> ...]" );

		uint32_t addr = dns_lookup( command[1].c_str() );
		std::string mac = parse_mac( command[2] );

		packet p;
		memset( &p, 0, sizeof(p) );
		p.op = BOOT_REQUEST;
		p.htype = HWADDR_ETHER;
		p.hlen = 6;
		p.xid = 0xCAFEBEEF;
		memcpy( p.chaddr, mac.c_str(), 6 );

		std::vector<std::string> opts;
		opts.push_back( parse_option( "msgtype(1)" ) );
		opts.push_back( parse_option( "param_requested(1,3,6,12,15,54,66,67" ) );
		opts.push_back( parse_option( "vendorid(DHCPDB discover test)" ) );
		for ( size_t i = 3; i < command.size(); ++i )
			opts.push_back( parse_option( command[i] ) );
		fillOptions( &p, opts );

		udp_socket s( INADDR_ANY, 0, true );
		s.send( addr, 67, &p );
		std::cout << "Sent:\n" << &p << std::endl;
	}
	else if ( command[0] == "monitor" )
	{
		if ( command.size() > 2 )
			error( "Command 'monitor' needs at most 1 argument: monitor [<ip>]" );

		uint32_t ipaddr = INADDR_ANY;
		if ( command.size() > 1 )
			ipaddr = dns_lookup( command[1].c_str() );

		udp_socket s( ipaddr, 67, false );
		packet p;

		while ( 1 )
		{
			try
			{
				s.recv( &p );
				std::cout << "Received:\n" << &p << std::endl;
			}
			catch ( std::exception &e )
			{
				std::cout << "Error: " << e.what() << std::endl;
				break;
			}
			catch ( ... )
			{
				std::cout << "Error: unknown" << std::endl;
				break;
			}
		}
	}
	else
	{
		print_usage( argv[0] );
	}

	return 0;
}

<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include "quadtree.h"
#include "free_quadtree.h"
#include "lock_quadtree.h"
#include <atomic>
#include <memory>
#include <thread>
#include <chrono>

namespace
{
using std::vector;
using std::cout;
using std::endl;
using std::atomic;
using std::thread;
using std::shared_ptr;
using std::srand;
using std::time;
using std::max;
using std::strtoul;
using std::chrono::time_point;
using std::chrono::system_clock;
using std::chrono::duration;
using quadtree::BoundingBox;
using quadtree::Point;
using quadtree::Quadtree;
using quadtree::LockfreeQuadtree;
using quadtree::LockQuadtree;

const unsigned int DEFAULT_CAPACITY = 4;
const unsigned int DEFAULT_THREADS = max(thread::hardware_concurrency(), 1u);
const unsigned int DEFAULT_POINTS = 10000000;

inline double frand()
{
  return (double)rand() / (double)RAND_MAX;
}
}

/// @param q the quadtree to insert into
/// @param points the number of points to insert. Actual points inserted is floor(points/threads)/threads
/// @param threads the number of threads to use to insert in parallel
/// @return the number of points inserted. This will equal floor(points/threads)*threads, not points
int testInsert(Quadtree* q, int points, int numThreads)
{
  const auto tpoints = points / numThreads;
  const auto insertPoint = [tpoints, q] () {
    for(int i = 0, end = tpoints; i != end; ++i)
    {
      const auto p = Point(frand()*100.0 + 50.0, frand() * 100.0 + 50.0);
      const bool ok = q->Insert(p);
      if(!ok)
	cout << "testInsert insert failed" << endl;
    }
  };

  cout << "inserting " << tpoints << " per thread\n";

  vector<shared_ptr<thread>> threads;
  for(int i = 0, end = numThreads; i != end; ++i)
    threads.push_back(shared_ptr<thread>(new thread(insertPoint)));

  for(auto i : threads)
    i->join();

  return tpoints * numThreads;
}

/// @param q the quadtree to insert into
/// @param points the number of points to insert. Actual points inserted is floor(points/threads)/threads
/// @param threads the number of threads to use to insert in parallel
/// @return the number of points inserted. This will equal floor(points/threads)*threads, not points
int testInsertQuery(Quadtree* q, int points, int numThreads)
{
  shared_ptr<std::atomic<bool>> doneInserting = shared_ptr<atomic<bool>>(new std::atomic<bool>());
  shared_ptr<std::atomic<size_t>> numQueries = shared_ptr<atomic<size_t>>(new std::atomic<size_t>());
  doneInserting->store(false);
  numQueries->store(0u);

  const auto tpoints = points / numThreads;
  const auto insertPoint = [tpoints, q] () {
    for(int i = 0, end = tpoints; i != end; ++i)
    {
      const auto p = Point(frand()*100.0 + 50.0, frand() * 100.0 + 50.0);
      const bool ok = q->Insert(p);
      if(!ok)
	cout << "testInsert insert failed" << endl;
    }
    q->Query(q->Boundary());
  };

  // not really forever
  const auto foreverQuery = [q, doneInserting, numQueries] () {
    while(doneInserting->load() == false)
    {
      q->Query(q->Boundary());
      ++(*numQueries.get());
    }
  };

  cout << "query-inserting " << tpoints << " per thread\n";

  vector<shared_ptr<thread>> queryThreads;
  for(int i = 0, end = 1; i != end; ++i)
    queryThreads.push_back(shared_ptr<thread>(new thread(foreverQuery)));

  vector<shared_ptr<thread>> threads;
  for(int i = 0, end = numThreads; i != end; ++i)
    threads.push_back(shared_ptr<thread>(new thread(insertPoint)));

  for(auto i : threads)
    i->join();

  doneInserting->store(true);
  for(auto i : queryThreads)
    i->join();

  cout << "queries: " << std::to_string(numQueries.get()->load()) << endl;
  return tpoints * numThreads;
}

void printTree(Quadtree* q)
{
  const clock_t start = clock();

//  vector<Point> ps = q->Query(q->Boundary());

  const BoundingBox b = {{100.0, 100.0}, {25.0, 25.0}};
  vector<Point> ps = q->Query(b);

  const clock_t end = clock();
  const double seconds_elapsed = ((double)end - start) / CLOCKS_PER_SEC;

  cout << "queried " << ps.size() << " in " << seconds_elapsed << " seconds." << endl;

  if(ps.size() < 1000)
  {
    cout << "found ";
    for(auto i = ps.begin(), end = ps.end(); i != end; ++i)
      cout << "(" << i->X << " " << i->Y << "), ";
    cout << endl;
  }
}

int main(int argc, char** argv)
{
  // @todo cout whether unsigned long is atomic!!

//  cout << sizeof(int*);

  auto points = DEFAULT_POINTS;
  auto threads = DEFAULT_THREADS;
  auto capacity = DEFAULT_CAPACITY;

  if(argc > 1)
  {
    const auto p = static_cast<unsigned int>(strtoul(argv[1], 0, 10));
    if(p == 0)
    {
      cout << "Usage: quadtree points threads lockfree capacity\n";
      return 0;
    }
    if(p > 0)
      points = p;
  }
  if(argc > 2)
  {
    const auto t = static_cast<unsigned int>(strtoul(argv[2], 0, 10));
    if(t > 0)
      threads = t;
  }

  bool lockfree = true;
  if(argc > 3)
  {
    const auto t = static_cast<unsigned int>(strtoul(argv[3], 0, 10));
    lockfree = t > 0;
  }

  if(argc > 4)
  {
    const auto c = static_cast<unsigned int>(strtoul(argv[4], 0, 10));
    if(c > 0)
      capacity = c;
  }

  cout << (lockfree ? "Lock Free\n" : "Lock Based\n");

  srand(time(nullptr));
  cout << std::fixed;

  cout << "threads: " << threads << endl;
  cout << "points: " << points << endl;
  cout << "capacity: " << capacity << endl;

  //#if !__has_feature(cxx_atomic)
  //  cout << "no atomic :(" << endl;
  //#endif

  const BoundingBox b = {{100, 100}, {50, 50}};
  auto q = std::unique_ptr<Quadtree>(lockfree ? (Quadtree*)new LockfreeQuadtree(b, capacity) : (Quadtree*)new LockQuadtree(b, capacity));

  const time_point<system_clock> start = system_clock::now();

  const int inserted = testInsert(q.get(), points, threads);

  const time_point<system_clock> end = system_clock::now();
  const duration<double> elapsed = end - start;
  const int seconds_elapsed = elapsed.count();

  cout << "inserted " << inserted << " in " << seconds_elapsed << " seconds with " << threads << " threads." << endl;

  printTree(q.get());

  return 0;
}
<commit_msg>changed main timers to C++11 high_resolution_clock<commit_after>#include <iostream>
#include <vector>
#include "quadtree.h"
#include "free_quadtree.h"
#include "lock_quadtree.h"
#include <atomic>
#include <memory>
#include <thread>
#include <chrono>

namespace
{
using std::vector;
using std::cout;
using std::endl;
using std::atomic;
using std::thread;
using std::shared_ptr;
using std::srand;
using std::time;
using std::max;
using std::strtoul;
using std::chrono::duration_cast;
using std::chrono::time_point;
using std::chrono::high_resolution_clock;
using std::chrono::duration;
using quadtree::BoundingBox;
using quadtree::Point;
using quadtree::Quadtree;
using quadtree::LockfreeQuadtree;
using quadtree::LockQuadtree;

const unsigned int DEFAULT_CAPACITY = 4;
const unsigned int DEFAULT_THREADS = max(thread::hardware_concurrency(), 1u);
const unsigned int DEFAULT_POINTS = 10000000;

inline double frand()
{
  return (double)rand() / (double)RAND_MAX;
}
}

/// @param q the quadtree to insert into
/// @param points the number of points to insert. Actual points inserted is floor(points/threads)/threads
/// @param threads the number of threads to use to insert in parallel
/// @return the number of points inserted. This will equal floor(points/threads)*threads, not points
int testInsert(Quadtree* q, int points, int numThreads)
{
  const auto tpoints = points / numThreads;
  const auto insertPoint = [tpoints, q] () {
    for(int i = 0, end = tpoints; i != end; ++i)
    {
      const auto p = Point(frand()*100.0 + 50.0, frand() * 100.0 + 50.0);
      const bool ok = q->Insert(p);
      if(!ok)
	cout << "testInsert insert failed" << endl;
    }
  };

  cout << "inserting " << tpoints << " per thread\n";

  vector<shared_ptr<thread>> threads;
  for(int i = 0, end = numThreads; i != end; ++i)
    threads.push_back(shared_ptr<thread>(new thread(insertPoint)));

  for(auto i : threads)
    i->join();

  return tpoints * numThreads;
}

/// @param q the quadtree to insert into
/// @param points the number of points to insert. Actual points inserted is floor(points/threads)/threads
/// @param threads the number of threads to use to insert in parallel
/// @return the number of points inserted. This will equal floor(points/threads)*threads, not points
int testInsertQuery(Quadtree* q, int points, int numThreads)
{
  shared_ptr<std::atomic<bool>> doneInserting = shared_ptr<atomic<bool>>(new std::atomic<bool>());
  shared_ptr<std::atomic<size_t>> numQueries = shared_ptr<atomic<size_t>>(new std::atomic<size_t>());
  doneInserting->store(false);
  numQueries->store(0u);

  const auto tpoints = points / numThreads;
  const auto insertPoint = [tpoints, q] () {
    for(int i = 0, end = tpoints; i != end; ++i)
    {
      const auto p = Point(frand()*100.0 + 50.0, frand() * 100.0 + 50.0);
      const bool ok = q->Insert(p);
      if(!ok)
	cout << "testInsert insert failed" << endl;
    }
    q->Query(q->Boundary());
  };

  // not really forever
  const auto foreverQuery = [q, doneInserting, numQueries] () {
    while(doneInserting->load() == false)
    {
      q->Query(q->Boundary());
      ++(*numQueries.get());
    }
  };

  cout << "query-inserting " << tpoints << " per thread\n";

  vector<shared_ptr<thread>> queryThreads;
  for(int i = 0, end = 1; i != end; ++i)
    queryThreads.push_back(shared_ptr<thread>(new thread(foreverQuery)));

  vector<shared_ptr<thread>> threads;
  for(int i = 0, end = numThreads; i != end; ++i)
    threads.push_back(shared_ptr<thread>(new thread(insertPoint)));

  for(auto i : threads)
    i->join();

  doneInserting->store(true);
  for(auto i : queryThreads)
    i->join();

  cout << "queries: " << std::to_string(numQueries.get()->load()) << endl;
  return tpoints * numThreads;
}

void printTree(Quadtree* q)
{
  const BoundingBox b = {{100.0, 100.0}, {25.0, 25.0}};

  const time_point<high_resolution_clock> start = high_resolution_clock::now();
//  vector<Point> ps = q->Query(q->Boundary());
  vector<Point> ps = q->Query(b);

  const time_point<high_resolution_clock> end = high_resolution_clock::now();
  const duration<double> elapsed = duration_cast<duration<double>>(end - start);

  cout << "queried " << ps.size() << " in " << elapsed.count() << " seconds." << endl;

  if(ps.size() < 1000)
  {
    cout << "found ";
    for(auto i = ps.begin(), end = ps.end(); i != end; ++i)
      cout << "(" << i->X << " " << i->Y << "), ";
    cout << endl;
  }
}

int main(int argc, char** argv)
{
  // @todo cout whether unsigned long is atomic!!

//  cout << sizeof(int*);

  auto points = DEFAULT_POINTS;
  auto threads = DEFAULT_THREADS;
  auto capacity = DEFAULT_CAPACITY;

  if(argc > 1)
  {
    const auto p = static_cast<unsigned int>(strtoul(argv[1], 0, 10));
    if(p == 0)
    {
      cout << "Usage: quadtree points threads lockfree capacity\n";
      return 0;
    }
    if(p > 0)
      points = p;
  }
  if(argc > 2)
  {
    const auto t = static_cast<unsigned int>(strtoul(argv[2], 0, 10));
    if(t > 0)
      threads = t;
  }

  bool lockfree = true;
  if(argc > 3)
  {
    const auto t = static_cast<unsigned int>(strtoul(argv[3], 0, 10));
    lockfree = t > 0;
  }

  if(argc > 4)
  {
    const auto c = static_cast<unsigned int>(strtoul(argv[4], 0, 10));
    if(c > 0)
      capacity = c;
  }

  cout << (lockfree ? "Lock Free\n" : "Lock Based\n");

  srand(time(nullptr));
  cout << std::fixed;

  cout << "threads: " << threads << endl;
  cout << "points: " << points << endl;
  cout << "capacity: " << capacity << endl;

  //#if !__has_feature(cxx_atomic)
  //  cout << "no atomic :(" << endl;
  //#endif

  const BoundingBox b = {{100, 100}, {50, 50}};
  auto q = std::unique_ptr<Quadtree>(lockfree ? (Quadtree*)new LockfreeQuadtree(b, capacity) : (Quadtree*)new LockQuadtree(b, capacity));

  const time_point<high_resolution_clock> start = high_resolution_clock::now();

  const int inserted = testInsert(q.get(), points, threads);

  const time_point<high_resolution_clock> end = high_resolution_clock::now();
  const duration<double> elapsed = duration_cast<duration<double>>(end - start);

  cout << "inserted " << inserted << " in " << elapsed.count() << " seconds with " << threads << " threads." << endl;

  printTree(q.get());

  return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <random>
#include <sstream>
#include <thread>
#include <vector>
#include "geometry.h"
#include "help_text.h"
#include "image.h"
#include "scene.h"
#include "vec2f.h"
#include "vec3f.h"

enum {
  EXIT_OK = 0,
  EXIT_FAIL_SAVE,
  EXIT_FAIL_LOAD,
  EXIT_BAD_ARGS,
};

enum {
  INVALID_ARG = -1,
  HELP_ARG,
  SCENE_FILE_ARG,
  OUTPUT_FILE_ARG,
  THREAD_COUNT_ARG,
};

struct user_inputs {
  user_inputs()
    : scene_file(0)
    , output_file(0)
    , thread_count(1)
    , requests_help(false)
    , requests_help_scene(false)
  {
  }

  const char* scene_file;
  const char* output_file;
  unsigned thread_count;
  bool requests_help;
  bool requests_help_scene;
};

user_inputs parse_inputs(int argc, char** argv) {
  user_inputs in;
  int next_expected_arg = INVALID_ARG;
  for (int i = 1; i < argc; ++i) {
    if (next_expected_arg == SCENE_FILE_ARG) {
      in.scene_file = argv[i];
      next_expected_arg = INVALID_ARG;
    } else if (next_expected_arg == OUTPUT_FILE_ARG) {
      in.output_file = argv[i];
      next_expected_arg = INVALID_ARG;
    } else if (next_expected_arg == THREAD_COUNT_ARG) {
      std::istringstream input(argv[i]);
      input >> in.thread_count;
      if (!input) {
        std::cerr << "Invalid thread count: " << argv[i] << std::endl;
        std::exit(EXIT_BAD_ARGS);
      }
      next_expected_arg = INVALID_ARG;
    } else if (!strcmp(argv[i], "--scene")) {
      next_expected_arg = SCENE_FILE_ARG;
    } else if (!strcmp(argv[i], "--output")) {
      next_expected_arg = OUTPUT_FILE_ARG;
    } else if (!strcmp(argv[i], "--threads") || !strcmp(argv[i], "-j")) {
      next_expected_arg = THREAD_COUNT_ARG;
    } else if (!strcmp(argv[i], "--help")) {
      in.requests_help = true;
      next_expected_arg = HELP_ARG;
    } else if (next_expected_arg == HELP_ARG) {
      if (!strcmp(argv[i], "scene")) {
        in.requests_help_scene = true;
        in.requests_help = false;
      }
      next_expected_arg = INVALID_ARG;
    } else {
      std::cerr << "Unrecognized input: " << argv[i] << std::endl;
      std::exit(EXIT_BAD_ARGS);
    }
  }
  return in;
}

const char* get_with_default(const char* primary, const char* fallback) {
  return primary ? primary : fallback;
}

enum nearest_t {
  NOTHING_NEAREST,
  SPHERE_NEAREST,
  MESH_NEAREST,
};

nearest_t nearest_intersect(
  const ray_sphere_intersect& rsi,
  const std::vector<sphere_t>& spheres,
  const ray_mesh_intersect& rmi,
  const std::vector<mesh_t>& meshes)
{
  if (rsi.intersect_exists(spheres)) {
    if (rmi.intersect_exists(meshes)) {
      return rsi.t < rmi.t ? SPHERE_NEAREST : MESH_NEAREST;
    } else {
      return SPHERE_NEAREST;
    }
  } else {
    if (rmi.intersect_exists(meshes)) {
      return MESH_NEAREST;
    } else {
      return NOTHING_NEAREST;
    }
  }
}

enum cast_policy_t {
  CAST_TO_OBJECT,
  CAST_TO_LIGHT,
};

// The maximum recursive depth
const unsigned MAX_RECURSE = 10u;

// The distance along the ray that the collision is offset by,
// to ensure floating point inaccuracy doesn't result in recollision
// with the same surface upon recasting from the collision point.
// Overall, it's a bit of a hack. A backoff algorithm would be more
// appropriate.
const float BACKOFF = 1e-3f;

/* Casts a ray into the scene and returns a color.

  The default_color is the color returned if no object is hit.

  There are two possible cast_policy values, corresponding with
  two main types of casts:
  - cast-to-object:
    intersection with a solid object results in a search for visible lights
  - cast-to-light:
    intersection with a solid object results in the conclusion that the point
    is shadowed

  Note that these casts do not account for indirect lighting,
  i.e. global illumination
*/
vec3f cast_ray(const ray_t& ray,
  const scene_t& s,
  vec3f default_color,
  cast_policy_t cast_policy,
  float refractive_index,
  unsigned recursion_depth)
{
  vec3f color = default_color;

  ray_sphere_intersect rsi = get_ray_sphere_intersect(ray, s.geometry.spheres);
  ray_mesh_intersect rmi = get_ray_mesh_intersect(ray, s.geometry.meshes);

  nearest_t nearest =
    nearest_intersect(rsi, s.geometry.spheres, rmi, s.geometry.meshes);

  if (nearest == SPHERE_NEAREST) {
    material_t material = s.sphere_materials[rsi.index_in(s.geometry.spheres)];
    float solid_component = material.opacity - material.reflectivity;
    if (cast_policy == CAST_TO_OBJECT) {
      vec3f pos = ray.position_at(rsi.t - BACKOFF);
      vec3f material_color = material.texture ?
        material.texture(pos) : material.color;

      if (solid_component > 0.f) {
        vec3f light_color(0,0,0);
        for (const light_t& light : s.lights) {
          ray_t light_ray = { pos, normalized(light.position - pos) };
          light_color += cast_ray(light_ray, s, light.color,
            CAST_TO_LIGHT, refractive_index, recursion_depth + 1u);
        }
        color += solid_component * material_color * light_color;
        color += solid_component * material_color * s.ambient_light;
      }

      if (material.reflectivity > 0.f) {
        vec3f normal = rsi.near_geometry_it->normal_at(pos);
        ray_t reflected_ray = { pos, reflected(ray.direction, normal) };
        if (recursion_depth < MAX_RECURSE) {
          color += material.reflectivity * material.color *
            cast_ray(reflected_ray, s, default_color, cast_policy,
            refractive_index, recursion_depth + 1u);
        }
      }

      float translucence = 1.f - material.opacity;
      if (translucence > 0.f) {
        vec3f inside_pos = ray.position_at(rsi.t + BACKOFF);
        vec3f normal = rsi.near_geometry_it->normal_at(inside_pos);
        if (dot(ray.direction, normal) > 0.f) {
          normal = -normal;
        }
        ray_t refracted_ray = { inside_pos, refracted(ray.direction, normal,
          refractive_index, material.refractive_index) };
        if (recursion_depth < MAX_RECURSE) {
          color += translucence * material.color * cast_ray(refracted_ray, s,
            default_color, cast_policy, material.refractive_index,
            recursion_depth + 1u);
        } else {
          // todo: handle total internal reflection more nicely
          std::cout << "Max recurse depth!" << std::endl;
        }
      }

    } else { // cast_policy == CAST_TO_LIGHT
      // we hit an object while looking for our light
      // that means we're shadowed...
      // but it still has ambient light...
      color = s.ambient_light * solid_component * material.color;
    }
  } else if (nearest == MESH_NEAREST) {

    // todo: reduce duplication between sphere and mesh color calculations

    material_t material = s.mesh_materials[rmi.index_in(s.geometry.meshes)];
    float solid_component = material.opacity - material.reflectivity;
    if (cast_policy == CAST_TO_OBJECT) {
      vec3f pos = ray.position_at(rmi.t - BACKOFF);
      vec3f material_color = material.texture ?
        material.texture(pos) : material.color;

      if (solid_component > 0.f) {
        vec3f light_color(0,0,0);
        for (const light_t& light : s.lights) {
          ray_t light_ray = { pos, normalized(light.position - pos) };
          light_color += cast_ray(light_ray, s, light.color,
            CAST_TO_LIGHT, refractive_index, recursion_depth + 1u);
        }
        color += solid_component * material_color * light_color;
        color += solid_component * material_color * s.ambient_light;
      }

      if (material.reflectivity > 0.f) {
        vec3f normal = rmi.face_normal();
        ray_t reflected_ray = { pos, reflected(ray.direction, normal) };
        if (recursion_depth < MAX_RECURSE) {
          color += material.reflectivity * material.color *
            cast_ray(reflected_ray, s, default_color, cast_policy,
            refractive_index, recursion_depth + 1u);
        }
      }

      float translucence = 1.f - material.opacity;
      if (translucence > 0.f) {
        vec3f inside_pos = ray.position_at(rsi.t + BACKOFF);
        vec3f normal = rmi.face_normal();
        if (dot(ray.direction, normal) > 0.f) {
          normal = -normal;
        }
        ray_t refracted_ray = { inside_pos, refracted(ray.direction, normal,
          refractive_index, material.refractive_index) };
        if (recursion_depth < MAX_RECURSE) {
          color += translucence * material.color * cast_ray(refracted_ray, s,
            default_color, cast_policy, material.refractive_index,
            recursion_depth + 1u);
        } else {
          // todo: handle total internal reflection more nicely
          std::cout << "Max recurse depth!" << std::endl;
        }
      }

    } else { // cast_policy == CAST_TO_LIGHT
      // shadowed...
      color = s.ambient_light * solid_component * material.color;
    }

  }
  return color;
}

image generate_image(const scene_t& s, unsigned thread_count)
{
  const vec3f observer = s.observer;
  const resolution_t res = s.res;
  const unsigned sample_count = s.sample_count;
  const vec3f screen_top_left = s.screen_top_left;
  const vec3f screen_offset_per_px_x = s.screen_offset_per_px_x();
  const vec3f screen_offset_per_px_y = s.screen_offset_per_px_y();

  image img(res.x, res.y);
  std::vector<std::thread> threads(thread_count);

  for (unsigned thread_id = 0u; thread_id < threads.size(); ++thread_id) {
    threads[thread_id] = std::thread([&,thread_id]() {
      for (unsigned y = thread_id; y < res.y; y += thread_count) {
        std::mt19937 engine(y);
        std::uniform_real_distribution<float> distribution(0.f, 1.f);
        auto rng = std::bind(distribution, engine);
        for (unsigned x = 0u; x < res.x; ++x) {
          vec3f px_color = { 0, 0, 0 };
          for (unsigned sample = 0u; sample < sample_count; ++sample) {
            vec3f background_color = { 0, 0, 0 };
            vec3f pixel_pos = screen_top_left +
              (x + rng()) * screen_offset_per_px_x +
              (y + rng()) * screen_offset_per_px_y;
            ray_t eye_ray = { pixel_pos, normalized(pixel_pos - observer) };
            px_color += cast_ray(eye_ray, s, background_color,
              CAST_TO_OBJECT, 1.f, 0u);
          }
          img.px(x, y) = px_color / sample_count;
        }
      }
    });
  }

  for (auto& thread : threads) {
    thread.join();
  }

  return img;
}

int main(int argc, char** argv) {
  user_inputs user = parse_inputs(argc, argv);
  if (user.requests_help) {
    std::cout << help_text << std::endl;
    std::exit(EXIT_OK);
  } else if (user.requests_help_scene) {
    std::cout << scene_file_help_text << std::endl;
    std::exit(EXIT_OK);
  }

  const scene_t scene = try_load_scene_from_file(
    get_with_default(user.scene_file, "world.yml"), EXIT_FAIL_LOAD);

  image img = generate_image(scene, user.thread_count);
  img.clamp_colors();
  if (!img.save_as_png(get_with_default(user.output_file, "output.png"))) {
    return EXIT_FAIL_SAVE;
  }

  return EXIT_OK;
}
<commit_msg>Removing lambda for compiler compatibility.<commit_after>#include <iostream>
#include <random>
#include <sstream>
#include <thread>
#include <vector>
#include "geometry.h"
#include "help_text.h"
#include "image.h"
#include "scene.h"
#include "vec2f.h"
#include "vec3f.h"

enum {
  EXIT_OK = 0,
  EXIT_FAIL_SAVE,
  EXIT_FAIL_LOAD,
  EXIT_BAD_ARGS,
};

enum {
  INVALID_ARG = -1,
  HELP_ARG,
  SCENE_FILE_ARG,
  OUTPUT_FILE_ARG,
  THREAD_COUNT_ARG,
};

struct user_inputs {
  user_inputs()
    : scene_file(0)
    , output_file(0)
    , thread_count(1)
    , requests_help(false)
    , requests_help_scene(false)
  {
  }

  const char* scene_file;
  const char* output_file;
  unsigned thread_count;
  bool requests_help;
  bool requests_help_scene;
};

user_inputs parse_inputs(int argc, char** argv) {
  user_inputs in;
  int next_expected_arg = INVALID_ARG;
  for (int i = 1; i < argc; ++i) {
    if (next_expected_arg == SCENE_FILE_ARG) {
      in.scene_file = argv[i];
      next_expected_arg = INVALID_ARG;
    } else if (next_expected_arg == OUTPUT_FILE_ARG) {
      in.output_file = argv[i];
      next_expected_arg = INVALID_ARG;
    } else if (next_expected_arg == THREAD_COUNT_ARG) {
      std::istringstream input(argv[i]);
      input >> in.thread_count;
      if (!input) {
        std::cerr << "Invalid thread count: " << argv[i] << std::endl;
        std::exit(EXIT_BAD_ARGS);
      }
      next_expected_arg = INVALID_ARG;
    } else if (!strcmp(argv[i], "--scene")) {
      next_expected_arg = SCENE_FILE_ARG;
    } else if (!strcmp(argv[i], "--output")) {
      next_expected_arg = OUTPUT_FILE_ARG;
    } else if (!strcmp(argv[i], "--threads") || !strcmp(argv[i], "-j")) {
      next_expected_arg = THREAD_COUNT_ARG;
    } else if (!strcmp(argv[i], "--help")) {
      in.requests_help = true;
      next_expected_arg = HELP_ARG;
    } else if (next_expected_arg == HELP_ARG) {
      if (!strcmp(argv[i], "scene")) {
        in.requests_help_scene = true;
        in.requests_help = false;
      }
      next_expected_arg = INVALID_ARG;
    } else {
      std::cerr << "Unrecognized input: " << argv[i] << std::endl;
      std::exit(EXIT_BAD_ARGS);
    }
  }
  return in;
}

const char* get_with_default(const char* primary, const char* fallback) {
  return primary ? primary : fallback;
}

enum nearest_t {
  NOTHING_NEAREST,
  SPHERE_NEAREST,
  MESH_NEAREST,
};

nearest_t nearest_intersect(
  const ray_sphere_intersect& rsi,
  const std::vector<sphere_t>& spheres,
  const ray_mesh_intersect& rmi,
  const std::vector<mesh_t>& meshes)
{
  if (rsi.intersect_exists(spheres)) {
    if (rmi.intersect_exists(meshes)) {
      return rsi.t < rmi.t ? SPHERE_NEAREST : MESH_NEAREST;
    } else {
      return SPHERE_NEAREST;
    }
  } else {
    if (rmi.intersect_exists(meshes)) {
      return MESH_NEAREST;
    } else {
      return NOTHING_NEAREST;
    }
  }
}

enum cast_policy_t {
  CAST_TO_OBJECT,
  CAST_TO_LIGHT,
};

// The maximum recursive depth
const unsigned MAX_RECURSE = 10u;

// The distance along the ray that the collision is offset by,
// to ensure floating point inaccuracy doesn't result in recollision
// with the same surface upon recasting from the collision point.
// Overall, it's a bit of a hack. A backoff algorithm would be more
// appropriate.
const float BACKOFF = 1e-3f;

/* Casts a ray into the scene and returns a color.

  The default_color is the color returned if no object is hit.

  There are two possible cast_policy values, corresponding with
  two main types of casts:
  - cast-to-object:
    intersection with a solid object results in a search for visible lights
  - cast-to-light:
    intersection with a solid object results in the conclusion that the point
    is shadowed

  Note that these casts do not account for indirect lighting,
  i.e. global illumination
*/
vec3f cast_ray(const ray_t& ray,
  const scene_t& s,
  vec3f default_color,
  cast_policy_t cast_policy,
  float refractive_index,
  unsigned recursion_depth)
{
  vec3f color = default_color;

  ray_sphere_intersect rsi = get_ray_sphere_intersect(ray, s.geometry.spheres);
  ray_mesh_intersect rmi = get_ray_mesh_intersect(ray, s.geometry.meshes);

  nearest_t nearest =
    nearest_intersect(rsi, s.geometry.spheres, rmi, s.geometry.meshes);

  if (nearest == SPHERE_NEAREST) {
    material_t material = s.sphere_materials[rsi.index_in(s.geometry.spheres)];
    float solid_component = material.opacity - material.reflectivity;
    if (cast_policy == CAST_TO_OBJECT) {
      vec3f pos = ray.position_at(rsi.t - BACKOFF);
      vec3f material_color = material.texture ?
        material.texture(pos) : material.color;

      if (solid_component > 0.f) {
        vec3f light_color(0,0,0);
        for (const light_t& light : s.lights) {
          ray_t light_ray = { pos, normalized(light.position - pos) };
          light_color += cast_ray(light_ray, s, light.color,
            CAST_TO_LIGHT, refractive_index, recursion_depth + 1u);
        }
        color += solid_component * material_color * light_color;
        color += solid_component * material_color * s.ambient_light;
      }

      if (material.reflectivity > 0.f) {
        vec3f normal = rsi.near_geometry_it->normal_at(pos);
        ray_t reflected_ray = { pos, reflected(ray.direction, normal) };
        if (recursion_depth < MAX_RECURSE) {
          color += material.reflectivity * material.color *
            cast_ray(reflected_ray, s, default_color, cast_policy,
            refractive_index, recursion_depth + 1u);
        }
      }

      float translucence = 1.f - material.opacity;
      if (translucence > 0.f) {
        vec3f inside_pos = ray.position_at(rsi.t + BACKOFF);
        vec3f normal = rsi.near_geometry_it->normal_at(inside_pos);
        if (dot(ray.direction, normal) > 0.f) {
          normal = -normal;
        }
        ray_t refracted_ray = { inside_pos, refracted(ray.direction, normal,
          refractive_index, material.refractive_index) };
        if (recursion_depth < MAX_RECURSE) {
          color += translucence * material.color * cast_ray(refracted_ray, s,
            default_color, cast_policy, material.refractive_index,
            recursion_depth + 1u);
        } else {
          // todo: handle total internal reflection more nicely
          std::cout << "Max recurse depth!" << std::endl;
        }
      }

    } else { // cast_policy == CAST_TO_LIGHT
      // we hit an object while looking for our light
      // that means we're shadowed...
      // but it still has ambient light...
      color = s.ambient_light * solid_component * material.color;
    }
  } else if (nearest == MESH_NEAREST) {

    // todo: reduce duplication between sphere and mesh color calculations

    material_t material = s.mesh_materials[rmi.index_in(s.geometry.meshes)];
    float solid_component = material.opacity - material.reflectivity;
    if (cast_policy == CAST_TO_OBJECT) {
      vec3f pos = ray.position_at(rmi.t - BACKOFF);
      vec3f material_color = material.texture ?
        material.texture(pos) : material.color;

      if (solid_component > 0.f) {
        vec3f light_color(0,0,0);
        for (const light_t& light : s.lights) {
          ray_t light_ray = { pos, normalized(light.position - pos) };
          light_color += cast_ray(light_ray, s, light.color,
            CAST_TO_LIGHT, refractive_index, recursion_depth + 1u);
        }
        color += solid_component * material_color * light_color;
        color += solid_component * material_color * s.ambient_light;
      }

      if (material.reflectivity > 0.f) {
        vec3f normal = rmi.face_normal();
        ray_t reflected_ray = { pos, reflected(ray.direction, normal) };
        if (recursion_depth < MAX_RECURSE) {
          color += material.reflectivity * material.color *
            cast_ray(reflected_ray, s, default_color, cast_policy,
            refractive_index, recursion_depth + 1u);
        }
      }

      float translucence = 1.f - material.opacity;
      if (translucence > 0.f) {
        vec3f inside_pos = ray.position_at(rsi.t + BACKOFF);
        vec3f normal = rmi.face_normal();
        if (dot(ray.direction, normal) > 0.f) {
          normal = -normal;
        }
        ray_t refracted_ray = { inside_pos, refracted(ray.direction, normal,
          refractive_index, material.refractive_index) };
        if (recursion_depth < MAX_RECURSE) {
          color += translucence * material.color * cast_ray(refracted_ray, s,
            default_color, cast_policy, material.refractive_index,
            recursion_depth + 1u);
        } else {
          // todo: handle total internal reflection more nicely
          std::cout << "Max recurse depth!" << std::endl;
        }
      }

    } else { // cast_policy == CAST_TO_LIGHT
      // shadowed...
      color = s.ambient_light * solid_component * material.color;
    }

  }
  return color;
}

void generate_pixels(unsigned thread_id,
  unsigned thread_count,
  const scene_t& s,
  const vec3f& screen_offset_per_px_x,
  const vec3f& screen_offset_per_px_y,
  image& img)
{
  for (unsigned y = thread_id; y < s.res.y; y += thread_count) {
    std::mt19937 engine(y);
    std::uniform_real_distribution<float> distribution(0.f, 1.f);
    auto rng = std::bind(distribution, engine);
    for (unsigned x = 0u; x < s.res.x; ++x) {
      vec3f px_color = { 0, 0, 0 };
      for (unsigned sample = 0u; sample < s.sample_count; ++sample) {
        vec3f background_color = { 0, 0, 0 };
        vec3f pixel_pos = s.screen_top_left +
          (x + rng()) * screen_offset_per_px_x +
          (y + rng()) * screen_offset_per_px_y;
        ray_t eye_ray = { pixel_pos, normalized(pixel_pos - s.observer) };
        px_color += cast_ray(eye_ray, s, background_color,
          CAST_TO_OBJECT, 1.f, 0u);
      }
      img.px(x, y) = px_color / s.sample_count;
    }
  }
}

image generate_image(const scene_t& s, unsigned thread_count)
{
  const vec3f screen_offset_per_px_x = s.screen_offset_per_px_x();
  const vec3f screen_offset_per_px_y = s.screen_offset_per_px_y();

  image img(s.res.x, s.res.y);
  std::vector<std::thread> threads(thread_count);

  for (unsigned thread_id = 0u; thread_id < threads.size(); ++thread_id) {
    threads[thread_id] = std::thread(std::bind(generate_pixels, thread_id,
      std::cref(thread_count),
      std::cref(s),
      std::cref(screen_offset_per_px_x),
      std::cref(screen_offset_per_px_y),
      std::ref(img)));
  }

  for (auto& thread : threads) {
    thread.join();
  }

  return img;
}

int main(int argc, char** argv) {
  user_inputs user = parse_inputs(argc, argv);
  if (user.requests_help) {
    std::cout << help_text << std::endl;
    std::exit(EXIT_OK);
  } else if (user.requests_help_scene) {
    std::cout << scene_file_help_text << std::endl;
    std::exit(EXIT_OK);
  }

  const scene_t scene = try_load_scene_from_file(
    get_with_default(user.scene_file, "world.yml"), EXIT_FAIL_LOAD);

  image img = generate_image(scene, user.thread_count);
  img.clamp_colors();
  if (!img.save_as_png(get_with_default(user.output_file, "output.png"))) {
    return EXIT_FAIL_SAVE;
  }

  return EXIT_OK;
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 <iostream>

#include <process/subprocess.hpp>

#include <stout/os.hpp>
#include <stout/protobuf.hpp>
#include <stout/strings.hpp>

#include <stout/os/raw/argv.hpp>

#include "launcher/posix/executor.hpp"

#ifdef __linux__
#include "linux/fs.hpp"
#endif

#include "slave/containerizer/mesos/constants.hpp"
#include "slave/containerizer/mesos/launch.hpp"

#ifdef __linux__
namespace fs = mesos::internal::fs;
#endif

using process::SETSID;
using process::Subprocess;

using std::cout;
using std::cerr;
using std::endl;
using std::string;
using std::vector;

using mesos::internal::slave::MESOS_CONTAINERIZER;
using mesos::internal::slave::MesosContainerizerLaunch;

namespace mesos {
namespace internal {

pid_t launchTaskPosix(
    const CommandInfo& command,
    const string& launcherDir,
    const Option<string>& user,
    const Option<string>& rootfs,
    const Option<string>& sandboxDirectory,
    const Option<string>& workingDirectory)
{
  if (rootfs.isSome()) {
    // The command executor is responsible for chrooting into the
    // root filesystem and changing the user before exec-ing the
    // user process.
#ifdef __linux__
    Result<string> _user = os::user();
    if (_user.isError()) {
      ABORT("Failed to get current user: " + _user.error());
    } else if (_user.isNone()) {
      ABORT("Current username is not found");
    } else if (_user.get() != "root") {
      ABORT("The command executor requires root with rootfs");
    }
#else
    ABORT("Not expecting root volume with non-linux platform");
#endif // __linux__
  }

  // Prepare the flags to pass to the launch process.
  MesosContainerizerLaunch::Flags launchFlags;

  launchFlags.command = JSON::protobuf(command);

  if (rootfs.isSome()) {
    CHECK_SOME(sandboxDirectory);
    launchFlags.working_directory = workingDirectory.isSome()
      ? workingDirectory
      : sandboxDirectory;
  }

  launchFlags.rootfs = rootfs;
  launchFlags.user = user;

  string commandString = strings::format(
      "%s %s %s",
      path::join(launcherDir, MESOS_CONTAINERIZER),
      MesosContainerizerLaunch::NAME,
      stringify(launchFlags)).get();

  // Fork the child using launcher.
  vector<string> argv(2);
  argv[0] = MESOS_CONTAINERIZER;
  argv[1] = MesosContainerizerLaunch::NAME;

  Try<Subprocess> s = subprocess(
      path::join(launcherDir, MESOS_CONTAINERIZER),
      argv,
      Subprocess::FD(STDIN_FILENO),
      Subprocess::FD(STDOUT_FILENO),
      Subprocess::FD(STDERR_FILENO),
      SETSID,
      &launchFlags);

  if (s.isError()) {
    ABORT("Failed to launch '" + commandString + "': " + s.error());
  }

  cout << commandString << endl;

  return s->pid();
}

} // namespace internal {
} // namespace mesos {
<commit_msg>Unshared the mount namespace when launching mesos-containerizer.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 <iostream>

#include <process/subprocess.hpp>

#include <stout/os.hpp>
#include <stout/protobuf.hpp>
#include <stout/strings.hpp>

#include <stout/os/raw/argv.hpp>

#include "launcher/posix/executor.hpp"

#ifdef __linux__
#include "linux/fs.hpp"
#endif

#include "slave/containerizer/mesos/constants.hpp"
#include "slave/containerizer/mesos/launch.hpp"

#ifdef __linux__
namespace fs = mesos::internal::fs;
#endif

using process::SETSID;
using process::Subprocess;

using std::cout;
using std::cerr;
using std::endl;
using std::string;
using std::vector;

using mesos::internal::slave::MESOS_CONTAINERIZER;
using mesos::internal::slave::MesosContainerizerLaunch;

namespace mesos {
namespace internal {

pid_t launchTaskPosix(
    const CommandInfo& command,
    const string& launcherDir,
    const Option<string>& user,
    const Option<string>& rootfs,
    const Option<string>& sandboxDirectory,
    const Option<string>& workingDirectory)
{
  // Prepare the flags to pass to the launch process.
  MesosContainerizerLaunch::Flags launchFlags;

  if (rootfs.isSome()) {
    // The command executor is responsible for chrooting into the
    // root filesystem and changing the user before exec-ing the
    // user process.
#ifdef __linux__
    Result<string> _user = os::user();
    if (_user.isError()) {
      ABORT("Failed to get current user: " + _user.error());
    } else if (_user.isNone()) {
      ABORT("Current username is not found");
    } else if (_user.get() != "root") {
      ABORT("The command executor requires root with rootfs");
    }

    // Ensure that mount namespace of the executor is not affected by
    // changes in its task's namespace induced by calling `pivot_root`
    // as part of the task setup in mesos-containerizer binary.
    launchFlags.unshare_namespace_mnt = true;
#else
    ABORT("Not expecting root volume with non-linux platform");
#endif // __linux__
  }

  launchFlags.command = JSON::protobuf(command);

  if (rootfs.isSome()) {
    CHECK_SOME(sandboxDirectory);
    launchFlags.working_directory = workingDirectory.isSome()
      ? workingDirectory
      : sandboxDirectory;
  }

  launchFlags.rootfs = rootfs;
  launchFlags.user = user;

  string commandString = strings::format(
      "%s %s %s",
      path::join(launcherDir, MESOS_CONTAINERIZER),
      MesosContainerizerLaunch::NAME,
      stringify(launchFlags)).get();

  // Fork the child using launcher.
  vector<string> argv(2);
  argv[0] = MESOS_CONTAINERIZER;
  argv[1] = MesosContainerizerLaunch::NAME;

  Try<Subprocess> s = subprocess(
      path::join(launcherDir, MESOS_CONTAINERIZER),
      argv,
      Subprocess::FD(STDIN_FILENO),
      Subprocess::FD(STDOUT_FILENO),
      Subprocess::FD(STDERR_FILENO),
      SETSID,
      &launchFlags);

  if (s.isError()) {
    ABORT("Failed to launch '" + commandString + "': " + s.error());
  }

  cout << commandString << endl;

  return s->pid();
}

} // namespace internal {
} // namespace mesos {
<|endoftext|>


<commit_before>/* This code is subject to the terms of the Mozilla Public License, v.2.0. http://mozilla.org/MPL/2.0/. */
#include "MerkleRing.h"

#include "common/MerklePoint.h"
#include "consistent_hashing/IHashRing.h"
#include "consistent_hashing/Hash.h"
#include "membership/IMembership.h"
#include "membership/Peer.h"

#include "util/Random.h"
#include <algorithm>
#include <endian.h>
using std::string;

MerkleRing::MerkleRing(const IHashRing& ring, const IMembership& membership, unsigned mirrors)
	: _ring(ring)
	, _membership(membership)
	, _mirrors(mirrors)
{
}

// addFile
void MerkleRing::add(const std::string& key)
{
	// find appropriate merkle tree based on hash, totalCopies

	/* maintain a list of trees.
	 * map?
	 * needs to reflect HashRing
	 * as hashring grows, index grows
	 * as hashring shrinks, index shrinks
	 * file hashes to hashRing section (first 64 bits?), and totalCopies parameter determines which merkle tree it addresses into.
	 *
	 * merkle sections contain the hashtoken that represents the primary mirror (e.g. "1:1", if it's 1's first hash range). This is true whether we're box 1, or box 2 (mirror 1), or box 3...
	 * merkle sections can be looked up by this hash token
	 **/

	string section = _ring.section(key);
	MerkleTree& tree = _forest[section];
	initTree(tree, section);
	tree.add(key);
}

void MerkleRing::remove(const string& key)
{
	string section = _ring.section(key);
	std::map<string, MerkleTree>::iterator it = _forest.find(section);
	if (it == _forest.end())
		return;

	MerkleTree& tree = it->second;
	tree.remove(key);
	prune(it);
}

void MerkleRing::initTree(MerkleTree& tree, const string& section)
{
	if (tree.empty())
	{
		tree.setId(TreeId(section, _mirrors));

		std::vector<string> locs = _ring.locationsFromHash(section, _mirrors);
		if (std::find(locs.begin(), locs.end(), _membership.self()->uid) == locs.end())
			_unwanted.insert(section);
		else
			_wanted.insert(section);
	}
}

void MerkleRing::prune(const std::map<string, MerkleTree>::iterator& it)
{
	MerkleTree& tree = it->second;
	if (tree.empty())
	{
		_unwanted.erase(tree.id().id);
		_wanted.erase(tree.id().id);
		_forest.erase(it);
	}
}

std::map<string, MerkleTree>::iterator MerkleRing::nextTree(const std::map<string, MerkleTree>::iterator& it)
{
	std::map<string, MerkleTree>::iterator next(it);
	if (++next == _forest.end())
		next = _forest.begin();
	return next;
}

void MerkleRing::splitSection(const string& where)
{
	if (_forest.empty())
		return;

	string section = _ring.section(where);
	std::pair<std::map<string, MerkleTree>::iterator,bool> pear = _forest.emplace(std::make_pair(section, MerkleTree()));
	if (!pear.second)
		return;

	std::map<string, MerkleTree>::iterator next = nextTree(pear.first);
	MerkleTree& sourceTree = next->second;
	MerkleTree& newTree = pear.first->second;
	initTree(newTree, section);

	// range we need to pull out of the sourceTree
	unsigned long long first = 0;
	unsigned long long last = Hash::compute(where).integer();

	// if sourceTree is the first tree and its id is < section, that means it remains the first node -- and that newTree is the last node.
	// So we need to grab its high-end keys instead of the usual low-end.
	if (next == _forest.begin())
	{
		if (sourceTree.id().id < section)
		{
			// would be nice to encapsulate this endianness nonsense somewhere.
			first = htobe64(Hash::fromBase64(sourceTree.id().id).integer());
			first = be64toh(++first);
		}
	}

	auto fun = [&sourceTree, &newTree] (unsigned long long hash, const std::string& file) { newTree.add(file); sourceTree.remove(file); return true; };
	sourceTree.forEachInRange(fun, first, last);

	prune(next);
	prune(pear.first);
}

void MerkleRing::cannibalizeSection(const string& where)
{
	string section = _ring.section(where);
	std::map<string, MerkleTree>::iterator it = _forest.find(section);
	if (it == _forest.end())
		return;

	std::map<string, MerkleTree>::iterator next = nextTree(it);
	MerkleTree& dyingTree = it->second;
	MerkleTree& refugeeTree = next->second;

	auto fun = [&dyingTree, &refugeeTree] (unsigned long long hash, const std::string& file) { refugeeTree.add(file); dyingTree.remove(file); return true; };
	dyingTree.forEachInRange(fun, 0, ~0ULL);
	prune(it);
}

const IMerkleTree& MerkleRing::find(const string& id) const
{
	std::map<string, MerkleTree>::const_iterator it = _forest.find(id);
	if (it == _forest.end())
		return MerkleTree::null();
	return it->second;
}

const IMerkleTree& MerkleRing::randomTree() const
{
	if (_forest.empty())
		return MerkleTree::null();
	std::set<string>::const_iterator it = Random::select(_wanted.begin(), _wanted.end(), _wanted.size());
	if (it == _wanted.end())
		return MerkleTree::null();
	return find(*it);
}

const IMerkleTree& MerkleRing::unwantedTree() const
{
	if (_forest.empty())
		return MerkleTree::null();
	std::set<string>::const_iterator it = Random::select(_unwanted.begin(), _unwanted.end(), _unwanted.size());
	if (it == _unwanted.end())
		return MerkleTree::null();
	return find(*it);
}

std::vector<string> MerkleRing::list() const
{
	std::vector<string> treeIds;
	for (std::map<string, MerkleTree>::const_iterator it = _forest.begin(); it != _forest.end(); ++it)
		treeIds.push_back(it->first);
	return treeIds;
}
<commit_msg>Different split/cannibalize. Maybe a little bit saner for the underlying container.<commit_after>/* This code is subject to the terms of the Mozilla Public License, v.2.0. http://mozilla.org/MPL/2.0/. */
#include "MerkleRing.h"

#include "common/MerklePoint.h"
#include "consistent_hashing/IHashRing.h"
#include "consistent_hashing/Hash.h"
#include "membership/IMembership.h"
#include "membership/Peer.h"

#include "util/Random.h"
#include <algorithm>
#include <endian.h>
using std::string;

MerkleRing::MerkleRing(const IHashRing& ring, const IMembership& membership, unsigned mirrors)
	: _ring(ring)
	, _membership(membership)
	, _mirrors(mirrors)
{
}

// addFile
void MerkleRing::add(const std::string& key)
{
	// find appropriate merkle tree based on hash, totalCopies

	/* maintain a list of trees.
	 * map?
	 * needs to reflect HashRing
	 * as hashring grows, index grows
	 * as hashring shrinks, index shrinks
	 * file hashes to hashRing section (first 64 bits?), and totalCopies parameter determines which merkle tree it addresses into.
	 *
	 * merkle sections contain the hashtoken that represents the primary mirror (e.g. "1:1", if it's 1's first hash range). This is true whether we're box 1, or box 2 (mirror 1), or box 3...
	 * merkle sections can be looked up by this hash token
	 **/

	string section = _ring.section(key);
	MerkleTree& tree = _forest[section];
	initTree(tree, section);
	tree.add(key);
}

void MerkleRing::remove(const string& key)
{
	string section = _ring.section(key);
	std::map<string, MerkleTree>::iterator it = _forest.find(section);
	if (it == _forest.end())
		return;

	MerkleTree& tree = it->second;
	tree.remove(key);
	prune(it);
}

void MerkleRing::initTree(MerkleTree& tree, const string& section)
{
	if (tree.empty())
	{
		tree.setId(TreeId(section, _mirrors));

		std::vector<string> locs = _ring.locationsFromHash(section, _mirrors);
		if (std::find(locs.begin(), locs.end(), _membership.self()->uid) == locs.end())
			_unwanted.insert(section);
		else
			_wanted.insert(section);
	}
}

void MerkleRing::prune(const std::map<string, MerkleTree>::iterator& it)
{
	MerkleTree& tree = it->second;
	if (tree.empty())
	{
		_unwanted.erase(tree.id().id);
		_wanted.erase(tree.id().id);
		_forest.erase(it);
	}
}

std::map<string, MerkleTree>::iterator MerkleRing::nextTree(const std::map<string, MerkleTree>::iterator& it)
{
	std::map<string, MerkleTree>::iterator next(it);
	if (++next == _forest.end())
		next = _forest.begin();
	return next;
}

void MerkleRing::splitSection(const string& where)
{
	if (_forest.empty())
		return;

	string section = _ring.section(where);
	std::pair<std::map<string, MerkleTree>::iterator,bool> pear = _forest.emplace(std::make_pair(section, MerkleTree()));
	if (!pear.second)
		return;

	std::map<string, MerkleTree>::iterator next = nextTree(pear.first);
	MerkleTree& sourceTree = next->second;
	MerkleTree& newTree = pear.first->second;
	initTree(newTree, section);

	// range we need to pull out of the sourceTree
	unsigned long long first = 0;
	unsigned long long last = Hash::compute(where).integer();

	// if sourceTree is the first tree and its id is < section, that means it remains the first node -- and that newTree is the last node.
	// So we need to grab its high-end keys instead of the usual low-end.
	if (next == _forest.begin())
	{
		if (sourceTree.id().id < section)
		{
			// would be nice to encapsulate this endianness nonsense somewhere.
			first = htobe64(Hash::fromBase64(sourceTree.id().id).integer());
			first = be64toh(++first);
		}
	}

	auto adder = [&newTree] (unsigned long long hash, const std::string& file) { newTree.add(file); return true; };
	sourceTree.forEachInRange(adder, first, last);

	auto remover = [&sourceTree] (unsigned long long hash, const std::string& file) { sourceTree.remove(file); return true; };
	newTree.forEachInRange(remover, 0, ~0ULL);

	prune(next);
	prune(pear.first);
}

void MerkleRing::cannibalizeSection(const string& where)
{
	string section = _ring.section(where);
	std::map<string, MerkleTree>::iterator it = _forest.find(section);
	if (it == _forest.end())
		return;

	std::map<string, MerkleTree>::iterator next = nextTree(it);
	MerkleTree& dyingTree = it->second;
	MerkleTree& refugeeTree = next->second;

	auto fun = [&refugeeTree] (unsigned long long hash, const std::string& file) { refugeeTree.add(file); return true; };
	dyingTree.forEachInRange(fun, 0, ~0ULL);

	_unwanted.erase(dyingTree.id().id);
	_wanted.erase(dyingTree.id().id);
	_forest.erase(it);
}

const IMerkleTree& MerkleRing::find(const string& id) const
{
	std::map<string, MerkleTree>::const_iterator it = _forest.find(id);
	if (it == _forest.end())
		return MerkleTree::null();
	return it->second;
}

const IMerkleTree& MerkleRing::randomTree() const
{
	if (_forest.empty())
		return MerkleTree::null();
	std::set<string>::const_iterator it = Random::select(_wanted.begin(), _wanted.end(), _wanted.size());
	if (it == _wanted.end())
		return MerkleTree::null();
	return find(*it);
}

const IMerkleTree& MerkleRing::unwantedTree() const
{
	if (_forest.empty())
		return MerkleTree::null();
	std::set<string>::const_iterator it = Random::select(_unwanted.begin(), _unwanted.end(), _unwanted.size());
	if (it == _unwanted.end())
		return MerkleTree::null();
	return find(*it);
}

std::vector<string> MerkleRing::list() const
{
	std::vector<string> treeIds;
	for (std::map<string, MerkleTree>::const_iterator it = _forest.begin(); it != _forest.end(); ++it)
		treeIds.push_back(it->first);
	return treeIds;
}
<|endoftext|>