<commit_before>#include <iostream>

extern "C" {
#include "md5.h"
#include "sha1.h"
#include "sha256.h"
}

#include "hash.hh"
#include "archive.hh"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

Hash::Hash()
{
    type = htUnknown;
    hashSize = 0;
    memset(hash, 0, maxHashSize);
}

Hash::Hash(HashType type)
{
    this->type = type;
    if (type == htMD5) hashSize = md5HashSize;
    else if (type == htSHA1) hashSize = sha1HashSize;
    else if (type == htSHA256) hashSize = sha256HashSize;
    else throw Error("unknown hash type");
    assert(hashSize <= maxHashSize);
    memset(hash, 0, maxHashSize);
}

bool Hash::operator == (const Hash & h2) const
{
    if (hashSize != h2.hashSize) return false;
    for (unsigned int i = 0; i < hashSize; i++)
        if (hash[i] != h2.hash[i]) return false;
    return true;
}

bool Hash::operator != (const Hash & h2) const
{
    return !(*this == h2);
}

bool Hash::operator < (const Hash & h) const
{
    for (unsigned int i = 0; i < hashSize; i++) {
        if (hash[i] < h.hash[i]) return true;
        if (hash[i] > h.hash[i]) return false;
    }
    return false;
}

string printHash(const Hash & hash)
{
    ostringstream str;
    for (unsigned int i = 0; i < hash.hashSize; i++) {
        str.fill('0');
        str.width(2);
        str << hex << (int) hash.hash[i];
    }
    return str.str();
}

Hash parseHash(HashType ht, const string & s)
{
    Hash hash(ht);
    if (s.length() != hash.hashSize * 2)
        throw Error(format("invalid hash `%1%'") % s);
    for (unsigned int i = 0; i < hash.hashSize; i++) {
        string s2(s, i * 2, 2);
        if (!isxdigit(s2[0]) || !isxdigit(s2[1]))
            throw Error(format("invalid hash `%1%'") % s);
        istringstream str(s2);
        int n;
        str >> hex >> n;
        hash.hash[i] = n;
    }
    return hash;
}

static unsigned short divMod(uint16_t * words, unsigned short y)
{
    unsigned int borrow = 0;

    int pos = (Hash::maxHashSize / 2) - 1;
    while (pos >= 0 && !words[pos]) --pos;

    for ( ; pos >= 0; --pos) {
        unsigned int s = words[pos] + (borrow << 16);
        unsigned int d = s / y;
        borrow = s % y;
        words[pos] = d;
    }

    return borrow;
}

// omitted: E O U T
char chars[] = "0123456789abcdfghijklmnpqrsvwxyz";

string printHash32(const Hash & hash)
{
    Hash hash2(hash);
    unsigned int len = (hash.hashSize * 8 - 1) / 5 + 1;

    string s(len, '0');

    int pos = len - 1;
    while (pos >= 0) {
        unsigned short digit = divMod((uint16_t *) hash2.hash, 32);
        s[pos--] = chars[digit];
    }

    for (unsigned int i = 0; i < hash2.maxHashSize; ++i)
        assert(hash2.hash[i] == 0);

    return s;
}

static bool mul(uint16_t * words, unsigned short y, int maxSize)
{
    unsigned short carry = 0;

    for (int pos = 0; pos < maxSize; ++pos) {
        unsigned int m = words[pos] * y + carry;
        words[pos] = m & 0xffff;
        carry = m >> 16;
    }

    return carry;
}

static bool add(uint16_t * words, unsigned short y, int maxSize)
{
    unsigned short carry = y;

    for (int pos = 0; pos < maxSize; ++pos) {
        unsigned int m = words[pos] + carry;
        words[pos] = m & 0xffff;
        carry = m >> 16;
        if (carry == 0) break;
    }

    return carry;
}

Hash parseHash32(HashType ht, const string & s)
{
    Hash hash(ht);

    for (unsigned int i = 0; i < s.length(); ++i) {
        char c = s[i];
        unsigned char digit;
        for (digit = 0; digit < sizeof(chars); ++digit) /* !!! slow */
            if (chars[digit] == c) break;
        if (digit >= 32)
            throw Error(format("invalid base-32 hash `%1%'") % s);
        if (mul((uint16_t *) hash.hash, 32, hash.hashSize / 2) ||
            add((uint16_t *) hash.hash, digit, hash.hashSize / 2))
            throw Error(format("base-32 hash `%1%' is too large") % s);
    }

    return hash;
}

bool isHash(const string & s)
{
    if (s.length() != 32) return false;
    for (int i = 0; i < 32; i++) {
        char c = s[i];
        if (!((c >= '0' && c <= '9') ||
              (c >= 'a' && c <= 'f')))
            return false;
    }
    return true;
}

struct Ctx
{
    md5_ctx md5;
    sha_ctx sha1;
    SHA256_CTX sha256;
};

static void start(HashType ht, Ctx & ctx)
{
    if (ht == htMD5) md5_init_ctx(&ctx.md5);
    else if (ht == htSHA1) sha_init(&ctx.sha1);
    else if (ht == htSHA256) SHA256_Init(&ctx.sha256);
}

static void update(HashType ht, Ctx & ctx,
    const unsigned char * bytes, unsigned int len)
{
    if (ht == htMD5) md5_process_bytes(bytes, len, &ctx.md5);
    else if (ht == htSHA1) sha_update(&ctx.sha1, bytes, len);
    else if (ht == htSHA256) SHA256_Update(&ctx.sha256, bytes, len);
}

static void finish(HashType ht, Ctx & ctx, unsigned char * hash)
{
    if (ht == htMD5) md5_finish_ctx(&ctx.md5, hash);
    else if (ht == htSHA1) {
        sha_final(&ctx.sha1);
        sha_digest(&ctx.sha1, hash);
    }
    else if (ht == htSHA256) SHA256_Final(hash, &ctx.sha256);
}

Hash hashString(HashType ht, const string & s)
{
    Ctx ctx;
    Hash hash(ht);
    start(ht, ctx);
    update(ht, ctx, (const unsigned char *) s.c_str(), s.length());
    finish(ht, ctx, hash.hash);
    return hash;
}

Hash hashFile(HashType ht, const Path & path)
{
    Ctx ctx;
    Hash hash(ht);
    start(ht, ctx);

    AutoCloseFD fd = open(path.c_str(), O_RDONLY);
    if (fd == -1) throw SysError(format("opening file `%1%'") % path);

    unsigned char buf[8192];
    ssize_t n;
    while ((n = read(fd, buf, sizeof(buf)))) {
        checkInterrupt();
        if (n == -1) throw SysError(format("reading file `%1%'") % path);
        update(ht, ctx, buf, n);
    }

    finish(ht, ctx, hash.hash);
    return hash;
}

struct HashSink : DumpSink
{
    HashType ht;
    Ctx ctx;
    virtual void operator ()
        (const unsigned char * data, unsigned int len)
    {
        update(ht, ctx, data, len);
    }
};

Hash hashPath(HashType ht, const Path & path)
{
    HashSink sink;
    sink.ht = ht;
    Hash hash(ht);
    start(ht, sink.ctx);
    dumpPath(path, sink);
    finish(ht, sink.ctx, hash.hash);
    return hash;
}

Hash compressHash(const Hash & hash, unsigned int newSize)
{
    Hash h;
    h.hashSize = newSize;
    for (unsigned int i = 0; i < hash.hashSize; ++i)
        h.hash[i % newSize] ^= hash.hash[i];
    return h;
}

HashType parseHashType(const string & s)
{
    if (s == "md5") return htMD5;
    else if (s == "sha1") return htSHA1;
    else if (s == "sha256") return htSHA256;
    else return htUnknown;
}
<commit_msg>* Fix endianness bug.<commit_after>#include <iostream>

extern "C" {
#include "md5.h"
#include "sha1.h"
#include "sha256.h"
}

#include "hash.hh"
#include "archive.hh"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

Hash::Hash()
{
    type = htUnknown;
    hashSize = 0;
    memset(hash, 0, maxHashSize);
}

Hash::Hash(HashType type)
{
    this->type = type;
    if (type == htMD5) hashSize = md5HashSize;
    else if (type == htSHA1) hashSize = sha1HashSize;
    else if (type == htSHA256) hashSize = sha256HashSize;
    else throw Error("unknown hash type");
    assert(hashSize <= maxHashSize);
    memset(hash, 0, maxHashSize);
}

bool Hash::operator == (const Hash & h2) const
{
    if (hashSize != h2.hashSize) return false;
    for (unsigned int i = 0; i < hashSize; i++)
        if (hash[i] != h2.hash[i]) return false;
    return true;
}

bool Hash::operator != (const Hash & h2) const
{
    return !(*this == h2);
}

bool Hash::operator < (const Hash & h) const
{
    for (unsigned int i = 0; i < hashSize; i++) {
        if (hash[i] < h.hash[i]) return true;
        if (hash[i] > h.hash[i]) return false;
    }
    return false;
}

string printHash(const Hash & hash)
{
    ostringstream str;
    for (unsigned int i = 0; i < hash.hashSize; i++) {
        str.fill('0');
        str.width(2);
        str << hex << (int) hash.hash[i];
    }
    return str.str();
}

Hash parseHash(HashType ht, const string & s)
{
    Hash hash(ht);
    if (s.length() != hash.hashSize * 2)
        throw Error(format("invalid hash `%1%'") % s);
    for (unsigned int i = 0; i < hash.hashSize; i++) {
        string s2(s, i * 2, 2);
        if (!isxdigit(s2[0]) || !isxdigit(s2[1]))
            throw Error(format("invalid hash `%1%'") % s);
        istringstream str(s2);
        int n;
        str >> hex >> n;
        hash.hash[i] = n;
    }
    return hash;
}

static unsigned char divMod(unsigned char * bytes, unsigned char y)
{
    unsigned int borrow = 0;

    int pos = Hash::maxHashSize - 1;
    while (pos >= 0 && !bytes[pos]) --pos;

    for ( ; pos >= 0; --pos) {
        unsigned int s = bytes[pos] + (borrow << 8);
        unsigned int d = s / y;
        borrow = s % y;
        bytes[pos] = d;
    }

    return borrow;
}

// omitted: E O U T
char chars[] = "0123456789abcdfghijklmnpqrsvwxyz";

string printHash32(const Hash & hash)
{
    Hash hash2(hash);
    unsigned int len = (hash.hashSize * 8 - 1) / 5 + 1;

    string s(len, '0');

    int pos = len - 1;
    while (pos >= 0) {
        unsigned char digit = divMod(hash2.hash, 32);
        s[pos--] = chars[digit];
    }

    for (unsigned int i = 0; i < hash2.maxHashSize; ++i)
        assert(hash2.hash[i] == 0);

    return s;
}

static bool mul(unsigned char * bytes, unsigned char y, int maxSize)
{
    unsigned char carry = 0;

    for (int pos = 0; pos < maxSize; ++pos) {
        unsigned int m = bytes[pos] * y + carry;
        bytes[pos] = m & 0xff;
        carry = m >> 8;
    }

    return carry;
}

static bool add(unsigned char * bytes, unsigned char y, int maxSize)
{
    unsigned char carry = y;

    for (int pos = 0; pos < maxSize; ++pos) {
        unsigned int m = bytes[pos] + carry;
        bytes[pos] = m & 0xff;
        carry = m >> 8;
        if (carry == 0) break;
    }

    return carry;
}

Hash parseHash32(HashType ht, const string & s)
{
    Hash hash(ht);

    for (unsigned int i = 0; i < s.length(); ++i) {
        char c = s[i];
        unsigned char digit;
        for (digit = 0; digit < sizeof(chars); ++digit) /* !!! slow */
            if (chars[digit] == c) break;
        if (digit >= 32)
            throw Error(format("invalid base-32 hash `%1%'") % s);
        if (mul(hash.hash, 32, hash.hashSize) ||
            add(hash.hash, digit, hash.hashSize))
            throw Error(format("base-32 hash `%1%' is too large") % s);
    }

    return hash;
}

bool isHash(const string & s)
{
    if (s.length() != 32) return false;
    for (int i = 0; i < 32; i++) {
        char c = s[i];
        if (!((c >= '0' && c <= '9') ||
              (c >= 'a' && c <= 'f')))
            return false;
    }
    return true;
}

struct Ctx
{
    md5_ctx md5;
    sha_ctx sha1;
    SHA256_CTX sha256;
};

static void start(HashType ht, Ctx & ctx)
{
    if (ht == htMD5) md5_init_ctx(&ctx.md5);
    else if (ht == htSHA1) sha_init(&ctx.sha1);
    else if (ht == htSHA256) SHA256_Init(&ctx.sha256);
}

static void update(HashType ht, Ctx & ctx,
    const unsigned char * bytes, unsigned int len)
{
    if (ht == htMD5) md5_process_bytes(bytes, len, &ctx.md5);
    else if (ht == htSHA1) sha_update(&ctx.sha1, bytes, len);
    else if (ht == htSHA256) SHA256_Update(&ctx.sha256, bytes, len);
}

static void finish(HashType ht, Ctx & ctx, unsigned char * hash)
{
    if (ht == htMD5) md5_finish_ctx(&ctx.md5, hash);
    else if (ht == htSHA1) {
        sha_final(&ctx.sha1);
        sha_digest(&ctx.sha1, hash);
    }
    else if (ht == htSHA256) SHA256_Final(hash, &ctx.sha256);
}

Hash hashString(HashType ht, const string & s)
{
    Ctx ctx;
    Hash hash(ht);
    start(ht, ctx);
    update(ht, ctx, (const unsigned char *) s.c_str(), s.length());
    finish(ht, ctx, hash.hash);
    return hash;
}

Hash hashFile(HashType ht, const Path & path)
{
    Ctx ctx;
    Hash hash(ht);
    start(ht, ctx);

    AutoCloseFD fd = open(path.c_str(), O_RDONLY);
    if (fd == -1) throw SysError(format("opening file `%1%'") % path);

    unsigned char buf[8192];
    ssize_t n;
    while ((n = read(fd, buf, sizeof(buf)))) {
        checkInterrupt();
        if (n == -1) throw SysError(format("reading file `%1%'") % path);
        update(ht, ctx, buf, n);
    }

    finish(ht, ctx, hash.hash);
    return hash;
}

struct HashSink : DumpSink
{
    HashType ht;
    Ctx ctx;
    virtual void operator ()
        (const unsigned char * data, unsigned int len)
    {
        update(ht, ctx, data, len);
    }
};

Hash hashPath(HashType ht, const Path & path)
{
    HashSink sink;
    sink.ht = ht;
    Hash hash(ht);
    start(ht, sink.ctx);
    dumpPath(path, sink);
    finish(ht, sink.ctx, hash.hash);
    return hash;
}

Hash compressHash(const Hash & hash, unsigned int newSize)
{
    Hash h;
    h.hashSize = newSize;
    for (unsigned int i = 0; i < hash.hashSize; ++i)
        h.hash[i % newSize] ^= hash.hash[i];
    return h;
}

HashType parseHashType(const string & s)
{
    if (s == "md5") return htMD5;
    else if (s == "sha1") return htSHA1;
    else if (s == "sha256") return htSHA256;
    else return htUnknown;
}
<|endoftext|>


<commit_before>/*
 * log_monitor.cpp
 *
 *  Created on: Dec 27, 2014
 *      Author: liao
 */
#include <iostream>
#include <map>
#include <time.h>
#include <vector>
#include <fstream>
#include <sstream>
#include "pthread.h"

#include "simple_config.h"
#include "simple_log.h"
#include "file_agent.h"
#include "flow_handler.h"
#include "reg_utils.h"
#include "json/json.h"
#include "hiredis/hiredis.h"
#include "simple_log.h"
#include "http_server.h"

const char *LINE_REG_NAME = "log_reg";
const char *TIME_FORMAT_NAME = "time_format";
const char *RETAIN_SECONDS_NAME = "retain_seconds";

const int excepted_match_size = 3; // 0: whole, 1: log_time, 2: cost_time
const int index_of_log_time = 1;
const int index_of_cost_time = 2;

class LogMonitorHandler : public LineFlowHandler {

public:
    LogMonitorHandler() {
        line_stat_map = new std::map<time_t, int>();
        cost_time_stat_map = new std::map<time_t, int>();
	last_print_time = 0;
    }

    ~LogMonitorHandler() {
        if (line_stat_map != NULL) {
            delete line_stat_map;
            line_stat_map = NULL;
        }
        if (cost_time_stat_map != NULL) {
            delete cost_time_stat_map;
            cost_time_stat_map = NULL;
        }
    }

    int load_configs(char *config_file) {
        get_config_map(config_file, configs);
        if (configs[LINE_REG_NAME].empty()) {
            LOG_ERROR("log_reg is empty!");
            return -1;
        }
        if (configs[TIME_FORMAT_NAME].empty()) {
            LOG_ERROR("time_format is empty!");
            return -1;
        }
        return 0;
    }

    void remove_expired_keys(std::map<time_t,int> &m, time_t expired_time) {
        std::map<time_t,int>::iterator e_index = m.lower_bound(expired_time);
        if (e_index != m.begin()) {
            m.erase(m.begin(), e_index);
            LOG_DEBUG("has expired record is remove!");
        }
    }

    int handle_lines(std::vector<std::string> lines)
    {
        pthread_mutex_lock(&_mutex);

        for (unsigned i = 0; i < lines.size(); i++) {
            int matched_size = 0;
            std::string match_str_array[excepted_match_size];
            bool match_ret = is_match_reg(lines[i], configs[LINE_REG_NAME], excepted_match_size, match_str_array, matched_size);

            if (!match_ret || matched_size < excepted_match_size - 1) {
                LOG_DEBUG("can not match line for reg:%s, match_ret:%d, matched_size:%d", configs[LINE_REG_NAME].c_str(), match_ret, matched_size);
                continue;
            }

            const char *time_details = match_str_array[index_of_log_time].c_str();
            struct tm tm;
	    if (configs["set_year"] == "true") {
	    	time_t now = time(NULL);
		tm = *localtime(&now);
	    }
            strptime(time_details, configs[TIME_FORMAT_NAME].c_str(), &tm);
            time_t log_time = mktime(&tm);

            bool has_cost_time = false;
            if (matched_size == excepted_match_size) { // no cost time
                has_cost_time = true;
            }
            LOG_DEBUG("get time_details:%s, log_time:%d, has_cost_time:%d", time_details, log_time, has_cost_time);

           // time_t now = time(NULL);
            time_t expired_time = log_time - atoi(configs[RETAIN_SECONDS_NAME].c_str());

            //remove_expired_keys(*line_stat_map, expired_time);
            //remove_expired_keys(*cost_time_stat_map, expired_time);

            if (line_stat_map->find(log_time) == line_stat_map->end()) {
                (*line_stat_map)[log_time] = 1;
            } else {
                (*line_stat_map)[log_time]++;
            }

            if (has_cost_time) {
                int cost_time = atoi(match_str_array[index_of_cost_time].c_str());
                if (cost_time_stat_map->find(log_time) == cost_time_stat_map->end()) {
                    (*cost_time_stat_map)[log_time] = cost_time;
                } else {
                    (*cost_time_stat_map)[log_time] += cost_time;
                }
            }

	    if (last_print_time == 0) {
	   	last_print_time = log_time;
	    } else if (last_print_time != log_time) {
	    	std::stringstream monitor_log;
		char time_buff[20];
		bzero(time_buff, 20);
		struct tm *timeinfo = localtime(&last_print_time);
		strftime(time_buff, 20, "%Y-%m-%d %H:%M:%S", timeinfo);

		monitor_log << " log_time: " << time_buff;
		int qps = (*line_stat_map)[last_print_time];
		monitor_log << ", QPS:";
		monitor_log << qps;
		if (has_cost_time) {
			int ct = (*cost_time_stat_map)[last_print_time];
			monitor_log << ", avg_cost_time:" << ct / qps;
		}
		last_print_time = log_time;
		LOG_INFO("[log_monitor] %s", monitor_log.str().c_str());
	    }

        }

        pthread_mutex_unlock(&_mutex);
        return 0;
    }

    void get_range_map(std::map<time_t,int> & origin_map, std::map<time_t,int> & stat_map, time_t start, time_t end)
    {
        std::map<time_t,int>::iterator start_iter = origin_map.lower_bound(start);
        while(start_iter != origin_map.end()){
            if (start_iter->first >= end) {
                break;
            }
            stat_map[start_iter->first] = start_iter->second;
            start_iter++;
        }
    }

    void get_stat(time_t start, time_t end, std::map<time_t,int> & line_stat, std::map<time_t,int> & cost_stat)
    {
        pthread_mutex_lock(&_mutex);
        get_range_map(*line_stat_map, line_stat, start, end);
        get_range_map(*cost_time_stat_map, cost_stat, start, end);
        pthread_mutex_unlock(&_mutex);
        LOG_INFO("line_stat_map size:%d, cost_time_stat_map size:%d, line_stat size:%d, cost_stat:%d", line_stat_map->size(), cost_time_stat_map->size(), line_stat.size(), cost_stat.size());
    }

private:
    std::map<std::string, std::string> configs;
    std::map<time_t, int> *line_stat_map;
    std::map<time_t, int> *cost_time_stat_map;
    pthread_mutex_t _mutex;
    time_t last_print_time;
};

LogMonitorHandler handler;

void get_count_statist_info(Request& request, Response &response) {
    std::vector<std::string> times;
    Json::Value root;
    Json::Value json_data;

    time_t now = time(NULL);
    time_t start = now - 10;
    std::map<time_t,int> line_stat, cost_stat;
    handler.get_stat(start, now, line_stat, cost_stat);

    int max_value = 0;
    for (size_t i = 0; i < 5; i++) {
        Json::ArrayIndex index = (Json::ArrayIndex) i;

        time_t stat_time = start + i;
        struct tm *time_info = localtime(&stat_time);
        char day_str[80];
        bzero(day_str, 80);
        strftime(day_str, 80, "%Y-%m-%d_%H:%M:%S", time_info);

        json_data[index]["unit"] = day_str;
        int pv_value = line_stat.find(start + i) == line_stat.end() ? 0 : line_stat[start + i];
        if (pv_value == 0) {
            LOG_WARN("PV VALUE IS ZERO which stat_time:%d", stat_time);
        }
        if (max_value < pv_value) {
            max_value = pv_value;
        }
        json_data[index]["value"] = pv_value;
        LOG_DEBUG("start_time:%s, pv:%d", day_str, pv_value);
    }

    Json::ArrayIndex index = 0;
    root["JSChart"]["datasets"][index]["type"] = "line";
    root["JSChart"]["datasets"][index]["data"] = json_data;

    response.set_body(root);
};

void get_time_statist_info(Request& request, Response &response) {
    std::vector<std::string> times;
    Json::Value root;
    Json::Value json_data;

    time_t now = time(NULL);
    time_t start = now - 5;
    std::map<time_t,int> line_stat, cost_stat;
    handler.get_stat(start, now, line_stat, cost_stat);

    for (size_t i = 0; i < 5; i++) {
        Json::ArrayIndex index = (Json::ArrayIndex) i;

        time_t stat_time = start + i;
        struct tm *time_info = localtime(&stat_time);
        char day_str[80];
        bzero(day_str, 80);
        strftime(day_str, 80, "%Y-%m-%d_%H:%M:%S", time_info);

        json_data[index]["unit"] = day_str;
        int pv_value = line_stat.find(start + i) == line_stat.end() ? 0 : line_stat[start + i];
        int avg_cost_time = 0;
        if (pv_value != 0) {
            avg_cost_time = cost_stat[start + i] / pv_value;
        }
        json_data[index]["value"] = avg_cost_time;
        LOG_DEBUG("start_time:%s, avg_cost_time:%d", day_str, avg_cost_time);
    }

    Json::ArrayIndex index = 0;
    root["JSChart"]["datasets"][index]["type"] = "line";
    root["JSChart"]["datasets"][index]["data"] = json_data;

    response.set_body(root);
};

void static_source_handler(Request& request, Response &res) {
    Json::Value root;
    std::string uri = request.get_request_uri();
    uri.replace(0, 1, "");

    LOG_DEBUG("GET replaced uri:%s", uri.c_str());

    std::string file_path = "resources/";
    file_path += uri;
    std::fstream fs(file_path.c_str());
    std::stringstream ss;
    if(fs) {
        int file_max_size = 500 * 1024;
        char buffer[file_max_size];
        bzero(buffer, file_max_size);
        fs.read(buffer, file_max_size);
        ss << std::string(buffer);
    }
    res.body = ss.str();
    std::string content_type = "text/html";
    if (uri.find(".js") != uri.npos) {
        content_type = "text/javascript;charset=UTF-8";
    }
    res.set_head("Content-Type", content_type);

}

void *start_http_server(void *ptr) {
    // start a http server
    std::map<std::string, std::string> *configs = (std::map<std::string, std::string> *) ptr;
    HttpServer http_server;
    http_server.add_mapping("/get_count", get_count_statist_info);
    http_server.add_mapping("/get_time", get_time_statist_info);
    http_server.add_mapping("/show.html", static_source_handler);
    http_server.add_mapping("/jscharts.js", static_source_handler);
    http_server.start(atoi((*configs)["http_port"].c_str()));
}

int main(int argc, char** argv) {
    if(argc < 2) {
        std::cout << "usage: ./log_monitor [config_file]" << std::endl;
        std::cout << "example: ./log_monitor log_monitor.conf" << std::endl;
        exit(-1);
        return -1;
    }

    char *config_file = argv[1];

    std::map<std::string, std::string> configs;
    get_config_map(config_file, configs);

    set_log_level(configs["log_level"].c_str());

    int ret = handler.load_configs(config_file);
    if (ret != 0) {
        LOG_ERROR("load configs error!");
        return -1;
    }

    pthread_t id;
    ret = pthread_create(&id, NULL, start_http_server, &configs);
    if(ret) {
        LOG_ERROR("Create pthread error( for start_http_server)!");
        return 1;
    }

    FileAgent fa;
    fa.set_flow_handler(handler);
    std::string log_file = configs["log_file"];
    char log_file_path[log_file.size() + 1];
    bzero(log_file_path, log_file.size() + 1);
    log_file.copy(log_file_path, log_file.size());

    LOG_INFO("START FILEAGENT for file:%s", log_file_path);
    fa.start(log_file_path);
    return 0;
}
<commit_msg>fix expire bug<commit_after>/*
 * log_monitor.cpp
 *
 *  Created on: Dec 27, 2014
 *      Author: liao
 */
#include <iostream>
#include <map>
#include <time.h>
#include <vector>
#include <fstream>
#include <sstream>
#include "pthread.h"

#include "simple_config.h"
#include "simple_log.h"
#include "file_agent.h"
#include "flow_handler.h"
#include "reg_utils.h"
#include "json/json.h"
#include "hiredis/hiredis.h"
#include "simple_log.h"
#include "http_server.h"

const char *LINE_REG_NAME = "log_reg";
const char *TIME_FORMAT_NAME = "time_format";
const char *RETAIN_SECONDS_NAME = "retain_seconds";

const int excepted_match_size = 3; // 0: whole, 1: log_time, 2: cost_time
const int index_of_log_time = 1;
const int index_of_cost_time = 2;

class LogMonitorHandler : public LineFlowHandler {

public:
    LogMonitorHandler() {
        line_stat_map = new std::map<time_t, int>();
        cost_time_stat_map = new std::map<time_t, int>();
	last_print_time = 0;
    }

    ~LogMonitorHandler() {
        if (line_stat_map != NULL) {
            delete line_stat_map;
            line_stat_map = NULL;
        }
        if (cost_time_stat_map != NULL) {
            delete cost_time_stat_map;
            cost_time_stat_map = NULL;
        }
    }

    int load_configs(char *config_file) {
        get_config_map(config_file, configs);
        if (configs[LINE_REG_NAME].empty()) {
            LOG_ERROR("log_reg is empty!");
            return -1;
        }
        if (configs[TIME_FORMAT_NAME].empty()) {
            LOG_ERROR("time_format is empty!");
            return -1;
        }
        return 0;
    }

    void remove_expired_keys(std::map<time_t,int> &m, time_t expired_time) {
        std::map<time_t,int>::iterator e_index = m.lower_bound(expired_time);
        if (e_index != m.begin()) {
            m.erase(m.begin(), e_index);
            LOG_DEBUG("has expired record is remove!");
        }
    }

    int handle_lines(std::vector<std::string> lines)
    {
        pthread_mutex_lock(&_mutex);

        for (unsigned i = 0; i < lines.size(); i++) {
            int matched_size = 0;
            std::string match_str_array[excepted_match_size];
            bool match_ret = is_match_reg(lines[i], configs[LINE_REG_NAME], excepted_match_size, match_str_array, matched_size);

            if (!match_ret || matched_size < excepted_match_size - 1) {
                LOG_DEBUG("can not match line for reg:%s, match_ret:%d, matched_size:%d", configs[LINE_REG_NAME].c_str(), match_ret, matched_size);
                continue;
            }

            const char *time_details = match_str_array[index_of_log_time].c_str();
            struct tm tm;
	    if (configs["set_year"] == "true") {
	    	time_t now = time(NULL);
		tm = *localtime(&now);
	    }
            strptime(time_details, configs[TIME_FORMAT_NAME].c_str(), &tm);
            time_t log_time = mktime(&tm);

            bool has_cost_time = false;
            if (matched_size == excepted_match_size) { // no cost time
                has_cost_time = true;
            }
            LOG_DEBUG("get time_details:%s, log_time:%d, has_cost_time:%d", time_details, log_time, has_cost_time);

           // time_t now = time(NULL);
            time_t expired_time = log_time - atoi(configs[RETAIN_SECONDS_NAME].c_str());

            remove_expired_keys(*line_stat_map, expired_time);
            remove_expired_keys(*cost_time_stat_map, expired_time);

            if (line_stat_map->find(log_time) == line_stat_map->end()) {
                (*line_stat_map)[log_time] = 1;
            } else {
                (*line_stat_map)[log_time]++;
            }

            if (has_cost_time) {
                int cost_time = atoi(match_str_array[index_of_cost_time].c_str());
                if (cost_time_stat_map->find(log_time) == cost_time_stat_map->end()) {
                    (*cost_time_stat_map)[log_time] = cost_time;
                } else {
                    (*cost_time_stat_map)[log_time] += cost_time;
                }
            }

	    if (last_print_time == 0) {
	   	last_print_time = log_time;
	    } else if (last_print_time != log_time) {
	    	std::stringstream monitor_log;
		char time_buff[20];
		bzero(time_buff, 20);
		struct tm *timeinfo = localtime(&last_print_time);
		strftime(time_buff, 20, "%Y-%m-%d %H:%M:%S", timeinfo);

		monitor_log << " log_time: " << time_buff;
		int qps = (*line_stat_map)[last_print_time];
		monitor_log << ", QPS:";
		monitor_log << qps;
		if (has_cost_time) {
			int ct = (*cost_time_stat_map)[last_print_time];
			monitor_log << ", avg_cost_time:" << ct / qps;
		}
		last_print_time = log_time;
		LOG_INFO("[log_monitor] %s", monitor_log.str().c_str());
	    }

        }

        pthread_mutex_unlock(&_mutex);
        return 0;
    }

    void get_range_map(std::map<time_t,int> & origin_map, std::map<time_t,int> & stat_map, time_t start, time_t end)
    {
        std::map<time_t,int>::iterator start_iter = origin_map.lower_bound(start);
        while(start_iter != origin_map.end()){
            if (start_iter->first >= end) {
                break;
            }
            stat_map[start_iter->first] = start_iter->second;
            start_iter++;
        }
    }

    void get_stat(time_t start, time_t end, std::map<time_t,int> & line_stat, std::map<time_t,int> & cost_stat)
    {
        pthread_mutex_lock(&_mutex);
        get_range_map(*line_stat_map, line_stat, start, end);
        get_range_map(*cost_time_stat_map, cost_stat, start, end);
        pthread_mutex_unlock(&_mutex);
        LOG_INFO("line_stat_map size:%d, cost_time_stat_map size:%d, line_stat size:%d, cost_stat:%d", line_stat_map->size(), cost_time_stat_map->size(), line_stat.size(), cost_stat.size());
    }

private:
    std::map<std::string, std::string> configs;
    std::map<time_t, int> *line_stat_map;
    std::map<time_t, int> *cost_time_stat_map;
    pthread_mutex_t _mutex;
    time_t last_print_time;
};

LogMonitorHandler handler;

void get_count_statist_info(Request& request, Response &response) {
    std::vector<std::string> times;
    Json::Value root;
    Json::Value json_data;

    time_t now = time(NULL);
    time_t start = now - 10;
    std::map<time_t,int> line_stat, cost_stat;
    handler.get_stat(start, now, line_stat, cost_stat);

    int max_value = 0;
    for (size_t i = 0; i < 5; i++) {
        Json::ArrayIndex index = (Json::ArrayIndex) i;

        time_t stat_time = start + i;
        struct tm *time_info = localtime(&stat_time);
        char day_str[80];
        bzero(day_str, 80);
        strftime(day_str, 80, "%Y-%m-%d_%H:%M:%S", time_info);

        json_data[index]["unit"] = day_str;
        int pv_value = line_stat.find(start + i) == line_stat.end() ? 0 : line_stat[start + i];
        if (pv_value == 0) {
            LOG_WARN("PV VALUE IS ZERO which stat_time:%d", stat_time);
        }
        if (max_value < pv_value) {
            max_value = pv_value;
        }
        json_data[index]["value"] = pv_value;
        LOG_DEBUG("start_time:%s, pv:%d", day_str, pv_value);
    }

    Json::ArrayIndex index = 0;
    root["JSChart"]["datasets"][index]["type"] = "line";
    root["JSChart"]["datasets"][index]["data"] = json_data;

    response.set_body(root);
};

void get_time_statist_info(Request& request, Response &response) {
    std::vector<std::string> times;
    Json::Value root;
    Json::Value json_data;

    time_t now = time(NULL);
    time_t start = now - 5;
    std::map<time_t,int> line_stat, cost_stat;
    handler.get_stat(start, now, line_stat, cost_stat);

    for (size_t i = 0; i < 5; i++) {
        Json::ArrayIndex index = (Json::ArrayIndex) i;

        time_t stat_time = start + i;
        struct tm *time_info = localtime(&stat_time);
        char day_str[80];
        bzero(day_str, 80);
        strftime(day_str, 80, "%Y-%m-%d_%H:%M:%S", time_info);

        json_data[index]["unit"] = day_str;
        int pv_value = line_stat.find(start + i) == line_stat.end() ? 0 : line_stat[start + i];
        int avg_cost_time = 0;
        if (pv_value != 0) {
            avg_cost_time = cost_stat[start + i] / pv_value;
        }
        json_data[index]["value"] = avg_cost_time;
        LOG_DEBUG("start_time:%s, avg_cost_time:%d", day_str, avg_cost_time);
    }

    Json::ArrayIndex index = 0;
    root["JSChart"]["datasets"][index]["type"] = "line";
    root["JSChart"]["datasets"][index]["data"] = json_data;

    response.set_body(root);
};

void static_source_handler(Request& request, Response &res) {
    Json::Value root;
    std::string uri = request.get_request_uri();
    uri.replace(0, 1, "");

    LOG_DEBUG("GET replaced uri:%s", uri.c_str());

    std::string file_path = "resources/";
    file_path += uri;
    std::fstream fs(file_path.c_str());
    std::stringstream ss;
    if(fs) {
        int file_max_size = 500 * 1024;
        char buffer[file_max_size];
        bzero(buffer, file_max_size);
        fs.read(buffer, file_max_size);
        ss << std::string(buffer);
    }
    res.body = ss.str();
    std::string content_type = "text/html";
    if (uri.find(".js") != uri.npos) {
        content_type = "text/javascript;charset=UTF-8";
    }
    res.set_head("Content-Type", content_type);

}

void *start_http_server(void *ptr) {
    // start a http server
    std::map<std::string, std::string> *configs = (std::map<std::string, std::string> *) ptr;
    HttpServer http_server;
    http_server.add_mapping("/get_count", get_count_statist_info);
    http_server.add_mapping("/get_time", get_time_statist_info);
    http_server.add_mapping("/show.html", static_source_handler);
    http_server.add_mapping("/jscharts.js", static_source_handler);
    http_server.start(atoi((*configs)["http_port"].c_str()));
}

int main(int argc, char** argv) {
    if(argc < 2) {
        std::cout << "usage: ./log_monitor [config_file]" << std::endl;
        std::cout << "example: ./log_monitor log_monitor.conf" << std::endl;
        exit(-1);
        return -1;
    }

    char *config_file = argv[1];

    std::map<std::string, std::string> configs;
    get_config_map(config_file, configs);

    set_log_level(configs["log_level"].c_str());

    int ret = handler.load_configs(config_file);
    if (ret != 0) {
        LOG_ERROR("load configs error!");
        return -1;
    }

    pthread_t id;
    ret = pthread_create(&id, NULL, start_http_server, &configs);
    if(ret) {
        LOG_ERROR("Create pthread error( for start_http_server)!");
        return 1;
    }

    FileAgent fa;
    fa.set_flow_handler(handler);
    std::string log_file = configs["log_file"];
    char log_file_path[log_file.size() + 1];
    bzero(log_file_path, log_file.size() + 1);
    log_file.copy(log_file_path, log_file.size());

    LOG_INFO("START FILEAGENT for file:%s", log_file_path);
    fa.start(log_file_path);
    return 0;
}
<|endoftext|>


<commit_before>/*-
 * Copyright (c) 2012, Achilleas Margaritis
 * Copyright (c) 2014, David T. Chisnall
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef PEGMATITE_AST_HPP
#define PEGMATITE_AST_HPP

#include <cassert>
#include <list>
#include <unordered_map>
#include <memory>
#include "parser.hh"

namespace pegmatite {

class ASTNode;
template <class T, bool OPT> class ASTPtr;
template <class T> class ASTList;
template <class T> class BindAST;

/** type of AST node stack.
 */
typedef std::vector<std::unique_ptr<ASTNode>> ASTStack;

#ifdef USE_RTTI
#define PEGMATITE_RTTI(thisclass, superclass)
#else
/**
 * Define the methods required for pegmatite's lightweight RTTI replacement to
 * work.  This should be used at the end of the class definition and will
 * provide support for safe downcasting.
 */
#define PEGMATITE_RTTI(thisclass, superclass)            \
	friend ASTNode;                                      \
protected:                                               \
	static char *classKind()                             \
	{                                                    \
		static char thisclass ## id;                     \
		return &thisclass ## id;                         \
	}                                                    \
public:                                                  \
	virtual bool isa(char *x)                            \
	{                                                    \
		return (x == classKind()) ||                     \
				(superclass::isa(x));                    \
	}
#endif

/**
 * Base class for AST nodes.
 */
class ASTNode
{
public:
	/**
	 * Constructs the AST node, with a null parent.
	 */
	ASTNode() : parent_node(0) {}
	/**
	 * Copying AST nodes is not supported.
	 */
	ASTNode(const ASTNode&) = delete;

	/**
	 * Destructor does nothing, virtual for subclasses to use.
	 */
	virtual ~ASTNode() {}

	/**
	 * Returns the parent of this AST node, or `nullptr` if there isn't one
	 * (either if this is the root, or if it is still in the stack waiting to
	 * be added to the tree).
	 */
	ASTNode *parent() const { return parent_node; }

	/**
	 * Interface for constructing the AST node.  The input range `r` is the
	 * range within the source.
	 */
	virtual void construct(const InputRange &r, ASTStack &st) {}

private:
	/**
	 * The parent AST node.
	 */
	ASTNode *parent_node;

	template <class T, bool OPT> friend class ASTPtr;
	template <class T> friend class ASTList;
	template <class T> friend class BindAST;

#ifndef USE_RTTI
protected:
	/**
	 * Returns the kind of object class.  This is a unique pointer that can be
	 * tested against pointers returned by classKind() to determine whether
	 * they can be safely compared.
	 */
	virtual char *kind() { return classKind(); }
	/**
	 * Returns the unique identifier for this class.
	 */
	static char *classKind()
	{
		static char ASTNodeid;
		return &ASTNodeid;
	}
public:
	/**
	 * Root implementation of the RTTI-replacement for builds not wishing to
	 * use RTTI.  This returns true if `x` is the value returned from
	 * `classKind()`, or false otherwise.
	 */
	virtual bool isa(char *x)
	{
		return x == classKind();
	}
	/**
	 * Returns true if this object is an instance of `T`.  Note that this
	 * *only* works with single-inheritance hierarchies.  If you wish to use
	 * multiple inheritance in your AST classes, then you must define
	 * `USE_RTTI` and use the C++ RTTI mechanism.
	 */
	template <class T> bool isa()
	{
		return isa(T::classKind());
	}
	/**
	 * Returns a pointer to this object as a pointer to a child class, or
	 * `nullptr` if the cast would be unsafe.
	 *
	 * Note that AST nodes are intended to be always used as unique pointers
	 * and so the returned object is *only* valid as long as the unique pointer
	 * is valid.
	 */
	template <class T> T* get_as()
	{
		return this ? (isa<T>() ? static_cast<T*>(this) : nullptr) : nullptr;
	}
#else
public:
	template <class T> T* get_as()
	{
		return dynamic_cast<T*>(this);
	}
#endif
};

class ASTMember;

/** type of ast member vector.
 */

/**
 * The base class for non-leaf AST nodes.  Subclasses can have instances of
 * `ASTMember` subclasses as fields and will automatically construct them.
 */
class ASTContainer : public ASTNode
{
public:
	/**
	 * Constructs the container, setting a thread-local value to point to it
	 * allowing constructors in fields of the subclass to register themselves
	 * in the members vector.
	 */
	ASTContainer();

	/**
	 * Asks all members to construct themselves from the stack. The members are
	 * asked to construct themselves in reverse order from a node stack (`st`).
	 *
	 * The input range (`r`) is unused, because the leaf nodes have already
	 * constructed themselves at this point.
	 */
	virtual void construct(const InputRange &r, ASTStack &st);

private:
	/**
	 * The type used for tracking the fields of subclasses.
	 */
	typedef std::vector<ASTMember *> ASTMember_vector;
	/**
	 * References to all of the fields of the subclass that will be
	 * automatically constructed.
	 */
	ASTMember_vector members;

	friend class ASTMember;
	PEGMATITE_RTTI(ASTContainer, ASTNode)
};

/**
 * Base class for children of `ASTContainer`.
 */
class ASTMember
{
public:
	/**
	 * On construction, `ASTMember` sets its `container_node` field to the
	 * `ASTContainer` currently under construction and registers itself with
	 * the container, to be notified during the construction phase.
	 */
	ASTMember();

	/**
	 * Returns the container of which this object is a field.
	 */
	ASTContainer *container() const { return container_node; }

	/**
	 * Interface for constructing references to AST objects from the stack.
	 */
	virtual void construct(ASTStack &st) = 0;
	virtual ~ASTMember();
protected:
	/**
	 * The container that owns this object.
	 */
	ASTContainer *container_node;
};

/**
 * An `ASTPtr` is a wrapper around a pointer to an AST object.  It is intended
 * to be a member of an `ASTContainer` and will automatically pop the top item
 * from the stack and claim it when building the AST..
 */
template <class T, bool OPT = false> class ASTPtr : public ASTMember
{
public:
	/**
	 * Constructs the object in the
	 */
	ASTPtr() : ptr(nullptr) {}

	/** gets the underlying ptr value.
		@return the underlying ptr value.
	 */
	T *get() const
	{
		return ptr.get();
	}

	/** auto conversion to the underlying object ptr.
		@return the underlying ptr value.
	 */
	const std::unique_ptr<T> &operator *() const
	{
		return ptr;
	}

	/** member access.
		@return the underlying ptr value.
	 */
	const std::unique_ptr<T> &operator ->() const
	{
		assert(ptr);
		return ptr;
	}

	/**
	 * Pops the next matching object from the AST stack `st` and claims it.
	 */
	virtual void construct(ASTStack &st)
	{
		assert(!st.empty() && "Stack must not be empty");
		//get the node
		ASTNode *node = st.back().get();

		//get the object
		T *obj = node->get_as<T>();

		assert((obj || OPT) && "Required objects must exist!");
		//if the object is optional, simply return
		if (OPT && !obj)
		{
			return;
		}
		//set the new object
		ptr.reset(obj);
		//pop the node from the stack
		st.back().release();
		st.pop_back();
		ptr->parent_node = container_node;
	}

private:
	/**
	 * The node that we are pointing to.
	 */
	std::unique_ptr<T> ptr;
};

/** A list of objects.
	It pops objects of the given type from the ast stack, until no more objects can be popped.
	It assumes ownership of objects.
	@param T type of object to control.
 */
template <class T> class ASTList : public ASTMember
{
public:
	///list type.
	typedef std::list<std::unique_ptr<T>> container;

	///the default constructor.
	ASTList() {}

	/** duplicates the objects of the given list.
		@param src source object.
	 */
	ASTList(const ASTList<T> &src)
	{
		_dup(src);
	}

	/** returns the container of objects.
		@return the container of objects.
	 */
	const container &objects() const
	{
		return child_objects;
	}

	/**
	 * Pops objects of type T from the stack (`st`) until no more objects can
	 * be popped.
	 */
	virtual void construct(ASTStack &st)
	{
		for(;;)
		{
			//if the stack is empty
			if (st.empty()) break;

			//get the node
			ASTNode *node = st.back().get();

			//get the object
			T *obj = node->get_as<T>();

			//if the object was not not of the appropriate type,
			//end the list parsing
			if (!obj) return;

			//remove the node from the stack
			st.back().release();
			st.pop_back();

			//insert the object in the list, in reverse order
			child_objects.push_front(std::unique_ptr<T>(obj));

			//set the object's parent
			obj->parent_node = ASTMember::container();
		}
	}
	virtual ~ASTList() {}

private:
	//objects
	container child_objects;

	//duplicate the given list.
	void _dup(const ASTList<T> &src)
	{
		for (auto child : src.child_objects)
		{
			T *obj = new T(child.get());
			child_objects.push_back(obj);
			obj->parent_node = ASTMember::container();
		}
	}
};

/** parses the given input.
	@param i input.
	@param g root rule of grammar.
	@param ws whitespace rule.
	@param el list of errors.
	@param d user data, passed to the parse procedures.
	@return pointer to ast node created, or null if there was an error.
		The return object must be deleted by the caller.
 */
std::unique_ptr<ASTNode> parse(Input &i, const Rule &g, const Rule &ws,
                               ErrorList &el, const ParserDelegate &d);

/**
 * A parser delegate that is responsible for creating AST nodes from the input.
 *
 * This class manages a mapping from rules in some grammar to AST nodes.
 * Instances of the `BindAST` class that are fields of a subclass of this will
 * automatically register rules on creation.
 *
 * The recommended use for this class is to only register rules on construction
 * (either explicitly in the constructor or implicitly via `BindAST` members).
 * This will give a completely reentrant delegate, which can be used by
 * multiple threads to parse multiple inputs safely.
 */
class ASTParserDelegate : ParserDelegate
{
	/**
	 * BindAST is a friend so that it can call the `set_parse_proc()` function,
	 * which should never be called from anything else.
	 */
	template <class T> friend class BindAST;
	private:
	/**
	 * The map from rules to parsing handlers.
	 */
	std::unordered_map<const Rule*, parse_proc> handlers;
	/**
	 * Registers a callback in this delegate.  This should only be called from
	 * the `static` version of this function.
	 */
	void set_parse_proc(const Rule &r, parse_proc p);
	/**
	 * Registers a callback for a specific rule in the instance of this class
	 * currently under construction in this thread.  This should only ever be
	 * called by `BindAST` instances.
	 */
	static void bind_parse_proc(const Rule &r, parse_proc p);
	public:
	/**
	 * Default constructor, registers this class in thread-local storage so
	 * that it can be referenced by BindAST fields in subclasses when their
	 * constructors are run.
	 */
	ASTParserDelegate();
	virtual parse_proc get_parse_proc(const Rule &) const;
	/**
	 * Parse an input `i`, starting from rule `g` in the grammar for which
	 * this is a delegate.  The rule `ws` is used as whitespace.  Errors are
	 * returned via the `el` parameter and the root of the AST via the `ast`
	 * parameter.
	 *
	 * This function returns true on a successful parse, or false otherwise.
	 */
	template <class T> bool parse(Input &i, const Rule &g, const Rule &ws,
	                              ErrorList &el, std::unique_ptr<T> &ast) const
	{
		std::unique_ptr<ASTNode> node = pegmatite::parse(i, g, ws, el, *this);
		T *n = node->get_as<T>();
		if (n)
		{
			node.release();
			ast.reset(n);
			return true;
		}
		return false;
	}
};

/**
 * The `BindAST` class is responsible for binding an action to a rule.  The
 * template argument is the `ASTNode` subclass representing the action.  Its
 * `construct()` method will be called when the rule is matched.
 */
template <class T> class BindAST
{
public:
	/**
	 * Bind the AST class described in the grammar to the rule specified.
	 */
	BindAST(const Rule &r)
	{
		ASTParserDelegate::bind_parse_proc(r, [](const ParserPosition &b,
		                                         const ParserPosition &e, void *d)
			{
				ASTStack *st = reinterpret_cast<ASTStack *>(d);
				T *obj = new T();
				obj->construct(InputRange(b, e), *st);
				st->push_back(std::unique_ptr<ASTNode>(obj));
			});
	}
};

} //namespace pegmatite

#endif //PEGMATITE_AST_HPP
<commit_msg>Add a convenience method for checking if an AST pointer is set.<commit_after>/*-
 * Copyright (c) 2012, Achilleas Margaritis
 * Copyright (c) 2014, David T. Chisnall
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef PEGMATITE_AST_HPP
#define PEGMATITE_AST_HPP

#include <cassert>
#include <list>
#include <unordered_map>
#include <memory>
#include "parser.hh"

namespace pegmatite {

class ASTNode;
template <class T, bool OPT> class ASTPtr;
template <class T> class ASTList;
template <class T> class BindAST;

/** type of AST node stack.
 */
typedef std::vector<std::unique_ptr<ASTNode>> ASTStack;

#ifdef USE_RTTI
#define PEGMATITE_RTTI(thisclass, superclass)
#else
/**
 * Define the methods required for pegmatite's lightweight RTTI replacement to
 * work.  This should be used at the end of the class definition and will
 * provide support for safe downcasting.
 */
#define PEGMATITE_RTTI(thisclass, superclass)            \
	friend ASTNode;                                      \
protected:                                               \
	static char *classKind()                             \
	{                                                    \
		static char thisclass ## id;                     \
		return &thisclass ## id;                         \
	}                                                    \
public:                                                  \
	virtual bool isa(char *x)                            \
	{                                                    \
		return (x == classKind()) ||                     \
				(superclass::isa(x));                    \
	}
#endif

/**
 * Base class for AST nodes.
 */
class ASTNode
{
public:
	/**
	 * Constructs the AST node, with a null parent.
	 */
	ASTNode() : parent_node(0) {}
	/**
	 * Copying AST nodes is not supported.
	 */
	ASTNode(const ASTNode&) = delete;

	/**
	 * Destructor does nothing, virtual for subclasses to use.
	 */
	virtual ~ASTNode() {}

	/**
	 * Returns the parent of this AST node, or `nullptr` if there isn't one
	 * (either if this is the root, or if it is still in the stack waiting to
	 * be added to the tree).
	 */
	ASTNode *parent() const { return parent_node; }

	/**
	 * Interface for constructing the AST node.  The input range `r` is the
	 * range within the source.
	 */
	virtual void construct(const InputRange &r, ASTStack &st) {}

private:
	/**
	 * The parent AST node.
	 */
	ASTNode *parent_node;

	template <class T, bool OPT> friend class ASTPtr;
	template <class T> friend class ASTList;
	template <class T> friend class BindAST;

#ifndef USE_RTTI
protected:
	/**
	 * Returns the kind of object class.  This is a unique pointer that can be
	 * tested against pointers returned by classKind() to determine whether
	 * they can be safely compared.
	 */
	virtual char *kind() { return classKind(); }
	/**
	 * Returns the unique identifier for this class.
	 */
	static char *classKind()
	{
		static char ASTNodeid;
		return &ASTNodeid;
	}
public:
	/**
	 * Root implementation of the RTTI-replacement for builds not wishing to
	 * use RTTI.  This returns true if `x` is the value returned from
	 * `classKind()`, or false otherwise.
	 */
	virtual bool isa(char *x)
	{
		return x == classKind();
	}
	/**
	 * Returns true if this object is an instance of `T`.  Note that this
	 * *only* works with single-inheritance hierarchies.  If you wish to use
	 * multiple inheritance in your AST classes, then you must define
	 * `USE_RTTI` and use the C++ RTTI mechanism.
	 */
	template <class T> bool isa()
	{
		return isa(T::classKind());
	}
	/**
	 * Returns a pointer to this object as a pointer to a child class, or
	 * `nullptr` if the cast would be unsafe.
	 *
	 * Note that AST nodes are intended to be always used as unique pointers
	 * and so the returned object is *only* valid as long as the unique pointer
	 * is valid.
	 */
	template <class T> T* get_as()
	{
		return this ? (isa<T>() ? static_cast<T*>(this) : nullptr) : nullptr;
	}
#else
public:
	template <class T> T* get_as()
	{
		return dynamic_cast<T*>(this);
	}
#endif
};

class ASTMember;

/** type of ast member vector.
 */

/**
 * The base class for non-leaf AST nodes.  Subclasses can have instances of
 * `ASTMember` subclasses as fields and will automatically construct them.
 */
class ASTContainer : public ASTNode
{
public:
	/**
	 * Constructs the container, setting a thread-local value to point to it
	 * allowing constructors in fields of the subclass to register themselves
	 * in the members vector.
	 */
	ASTContainer();

	/**
	 * Asks all members to construct themselves from the stack. The members are
	 * asked to construct themselves in reverse order from a node stack (`st`).
	 *
	 * The input range (`r`) is unused, because the leaf nodes have already
	 * constructed themselves at this point.
	 */
	virtual void construct(const InputRange &r, ASTStack &st);

private:
	/**
	 * The type used for tracking the fields of subclasses.
	 */
	typedef std::vector<ASTMember *> ASTMember_vector;
	/**
	 * References to all of the fields of the subclass that will be
	 * automatically constructed.
	 */
	ASTMember_vector members;

	friend class ASTMember;
	PEGMATITE_RTTI(ASTContainer, ASTNode)
};

/**
 * Base class for children of `ASTContainer`.
 */
class ASTMember
{
public:
	/**
	 * On construction, `ASTMember` sets its `container_node` field to the
	 * `ASTContainer` currently under construction and registers itself with
	 * the container, to be notified during the construction phase.
	 */
	ASTMember();

	/**
	 * Returns the container of which this object is a field.
	 */
	ASTContainer *container() const { return container_node; }

	/**
	 * Interface for constructing references to AST objects from the stack.
	 */
	virtual void construct(ASTStack &st) = 0;
	virtual ~ASTMember();
protected:
	/**
	 * The container that owns this object.
	 */
	ASTContainer *container_node;
};

/**
 * An `ASTPtr` is a wrapper around a pointer to an AST object.  It is intended
 * to be a member of an `ASTContainer` and will automatically pop the top item
 * from the stack and claim it when building the AST..
 */
template <class T, bool OPT = false> class ASTPtr : public ASTMember
{
public:
	/**
	 * Constructs the object in the
	 */
	ASTPtr() : ptr(nullptr) {}

	/** gets the underlying ptr value.
		@return the underlying ptr value.
	 */
	T *get() const
	{
		return ptr.get();
	}

	/** auto conversion to the underlying object ptr.
		@return the underlying ptr value.
	 */
	const std::unique_ptr<T> &operator *() const
	{
		return ptr;
	}

	/** member access.
		@return the underlying ptr value.
	 */
	const std::unique_ptr<T> &operator ->() const
	{
		assert(ptr);
		return ptr;
	}

	explicit operator bool() const noexcept
	{
		return (bool)ptr;
	}

	/**
	 * Pops the next matching object from the AST stack `st` and claims it.
	 */
	virtual void construct(ASTStack &st)
	{
		assert(!st.empty() && "Stack must not be empty");
		//get the node
		ASTNode *node = st.back().get();

		//get the object
		T *obj = node->get_as<T>();

		assert((obj || OPT) && "Required objects must exist!");
		//if the object is optional, simply return
		if (OPT && !obj)
		{
			return;
		}
		//set the new object
		ptr.reset(obj);
		//pop the node from the stack
		st.back().release();
		st.pop_back();
		ptr->parent_node = container_node;
	}

private:
	/**
	 * The node that we are pointing to.
	 */
	std::unique_ptr<T> ptr;
};

/** A list of objects.
	It pops objects of the given type from the ast stack, until no more objects can be popped.
	It assumes ownership of objects.
	@param T type of object to control.
 */
template <class T> class ASTList : public ASTMember
{
public:
	///list type.
	typedef std::list<std::unique_ptr<T>> container;

	///the default constructor.
	ASTList() {}

	/** duplicates the objects of the given list.
		@param src source object.
	 */
	ASTList(const ASTList<T> &src)
	{
		_dup(src);
	}

	/** returns the container of objects.
		@return the container of objects.
	 */
	const container &objects() const
	{
		return child_objects;
	}

	/**
	 * Pops objects of type T from the stack (`st`) until no more objects can
	 * be popped.
	 */
	virtual void construct(ASTStack &st)
	{
		for(;;)
		{
			//if the stack is empty
			if (st.empty()) break;

			//get the node
			ASTNode *node = st.back().get();

			//get the object
			T *obj = node->get_as<T>();

			//if the object was not not of the appropriate type,
			//end the list parsing
			if (!obj) return;

			//remove the node from the stack
			st.back().release();
			st.pop_back();

			//insert the object in the list, in reverse order
			child_objects.push_front(std::unique_ptr<T>(obj));

			//set the object's parent
			obj->parent_node = ASTMember::container();
		}
	}
	virtual ~ASTList() {}

private:
	//objects
	container child_objects;

	//duplicate the given list.
	void _dup(const ASTList<T> &src)
	{
		for (auto child : src.child_objects)
		{
			T *obj = new T(child.get());
			child_objects.push_back(obj);
			obj->parent_node = ASTMember::container();
		}
	}
};

/** parses the given input.
	@param i input.
	@param g root rule of grammar.
	@param ws whitespace rule.
	@param el list of errors.
	@param d user data, passed to the parse procedures.
	@return pointer to ast node created, or null if there was an error.
		The return object must be deleted by the caller.
 */
std::unique_ptr<ASTNode> parse(Input &i, const Rule &g, const Rule &ws,
                               ErrorList &el, const ParserDelegate &d);

/**
 * A parser delegate that is responsible for creating AST nodes from the input.
 *
 * This class manages a mapping from rules in some grammar to AST nodes.
 * Instances of the `BindAST` class that are fields of a subclass of this will
 * automatically register rules on creation.
 *
 * The recommended use for this class is to only register rules on construction
 * (either explicitly in the constructor or implicitly via `BindAST` members).
 * This will give a completely reentrant delegate, which can be used by
 * multiple threads to parse multiple inputs safely.
 */
class ASTParserDelegate : ParserDelegate
{
	/**
	 * BindAST is a friend so that it can call the `set_parse_proc()` function,
	 * which should never be called from anything else.
	 */
	template <class T> friend class BindAST;
	private:
	/**
	 * The map from rules to parsing handlers.
	 */
	std::unordered_map<const Rule*, parse_proc> handlers;
	/**
	 * Registers a callback in this delegate.  This should only be called from
	 * the `static` version of this function.
	 */
	void set_parse_proc(const Rule &r, parse_proc p);
	/**
	 * Registers a callback for a specific rule in the instance of this class
	 * currently under construction in this thread.  This should only ever be
	 * called by `BindAST` instances.
	 */
	static void bind_parse_proc(const Rule &r, parse_proc p);
	public:
	/**
	 * Default constructor, registers this class in thread-local storage so
	 * that it can be referenced by BindAST fields in subclasses when their
	 * constructors are run.
	 */
	ASTParserDelegate();
	virtual parse_proc get_parse_proc(const Rule &) const;
	/**
	 * Parse an input `i`, starting from rule `g` in the grammar for which
	 * this is a delegate.  The rule `ws` is used as whitespace.  Errors are
	 * returned via the `el` parameter and the root of the AST via the `ast`
	 * parameter.
	 *
	 * This function returns true on a successful parse, or false otherwise.
	 */
	template <class T> bool parse(Input &i, const Rule &g, const Rule &ws,
	                              ErrorList &el, std::unique_ptr<T> &ast) const
	{
		std::unique_ptr<ASTNode> node = pegmatite::parse(i, g, ws, el, *this);
		T *n = node->get_as<T>();
		if (n)
		{
			node.release();
			ast.reset(n);
			return true;
		}
		return false;
	}
};

/**
 * The `BindAST` class is responsible for binding an action to a rule.  The
 * template argument is the `ASTNode` subclass representing the action.  Its
 * `construct()` method will be called when the rule is matched.
 */
template <class T> class BindAST
{
public:
	/**
	 * Bind the AST class described in the grammar to the rule specified.
	 */
	BindAST(const Rule &r)
	{
		ASTParserDelegate::bind_parse_proc(r, [](const ParserPosition &b,
		                                         const ParserPosition &e, void *d)
			{
				ASTStack *st = reinterpret_cast<ASTStack *>(d);
				T *obj = new T();
				obj->construct(InputRange(b, e), *st);
				st->push_back(std::unique_ptr<ASTNode>(obj));
			});
	}
};

} //namespace pegmatite

#endif //PEGMATITE_AST_HPP
<|endoftext|>


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

#ifndef MISC_LIB_RESULT_HPP
#define MISC_LIB_RESULT_HPP

#include <cassert>
#include <type_traits>

#include "noncopyable.h"

BEGIN_MISC_LIB_NAMESPACE_DECL

template <typename T>
struct TypeHolder {
  using type = T;
};

namespace __detail {

constexpr size_t maxOf(size_t v) { return v; }

template <typename... S>
constexpr size_t maxOf(size_t v, S... rest) {
  return std::max(v, maxOf(rest...));
}

constexpr bool andAll(bool b) { return b; }

template <typename... T>
constexpr bool andAll(bool b, T &&...t) {
  return b && andAll(std::forward<T>(t)...);
}

template <typename T>
constexpr int toTypeIndex(int) {
  return -1;
}

template <typename T, typename F, typename... R>
constexpr int toTypeIndex(int index) {
  return std::is_same<T, F>::value ? index : toTypeIndex<T, R...>(index + 1);
}

template <std::size_t I, std::size_t N, typename F, typename... R>
struct TypeByIndex : TypeByIndex<I + 1, N, R...> {};

template <std::size_t N, typename F, typename... R>
struct TypeByIndex<N, N, F, R...> {
  using type = F;
};

template <typename... T>
struct OverloadResolver;

template <typename F, typename... T>
struct OverloadResolver<F, T...> : OverloadResolver<T...> {
  using OverloadResolver<T...>::operator();

  TypeHolder<F> operator()(F) const;
};

template <>
struct OverloadResolver<> {
  void operator()() const;
};

template <typename F, typename... T>
using resolvedType = typename std::invoke_result_t<OverloadResolver<T...>, F>::type;

} // namespace __detail

template <typename U, typename... T>
struct TypeTag {
  static constexpr int value = __detail::toTypeIndex<U, T...>(0);
};

template <std::size_t N, typename T0, typename... T>
struct TypeByIndex {
  static_assert(N < sizeof...(T) + 1, "out of range");
  using type = typename __detail::TypeByIndex<0, N, T0, T...>::type;
};

// #####################
// ##     Storage     ##
// #####################

template <typename... T>
struct Storage {
  alignas(T...) unsigned char _data[__detail::maxOf(sizeof(T)...)];

  template <typename U, typename F = __detail::resolvedType<U, T...>>
  void obtain(U &&value) {
    static_assert(TypeTag<F, T...>::value > -1, "invalid type");

    using Decayed = typename std::decay<F>::type;
    new (&this->_data) Decayed(std::forward<U>(value));
  }

  template <typename F>
  F *data() {
    static_assert(TypeTag<F, T...>::value > -1, "invalid type");
    return std::launder(reinterpret_cast<F *>(&this->_data));
  }

  template <typename F>
  const F *data() const {
    static_assert(TypeTag<F, T...>::value > -1, "invalid type");
    return std::launder(reinterpret_cast<const F *>(&this->_data));
  }
};

template <typename T, typename... R>
inline T &get(Storage<R...> &storage) {
  static_assert(TypeTag<T, R...>::value > -1, "invalid type");
  return *storage.template data<T>();
}

template <typename T, typename... R>
inline const T &get(const Storage<R...> &storage) {
  static_assert(TypeTag<T, R...>::value > -1, "invalid type");
  return *storage.template data<T>();
}

template <typename T, typename... R>
inline void destroy(Storage<R...> &storage) {
  get<T>(storage).~T();
}

/**
 *
 * @tparam T
 * @tparam R
 * @param src
 * @param dest
 * must be uninitialized
 */
template <typename T, typename... R>
inline void move(Storage<R...> &src, Storage<R...> &dest) {
  dest.obtain(std::move(get<T>(src)));
  destroy<T>(src);
}

template <typename T, typename... R>
inline void copy(const Storage<R...> &src, Storage<R...> &dest) {
  dest.obtain(get<T>(src));
}

namespace __detail_union {

template <int N, typename... R>
struct Destroyer {
  void operator()(Storage<R...> &storage, int tag) const {
    if (tag == N) {
      using T = typename TypeByIndex<N, R...>::type;
      destroy<T>(storage);
    } else {
      Destroyer<N - 1, R...>()(storage, tag);
    }
  }
};

template <typename... R>
struct Destroyer<-1, R...> {
  void operator()(Storage<R...> &, int) const {}
};

template <int N, typename... R>
struct Mover {
  void operator()(Storage<R...> &src, int srcTag, Storage<R...> &dest) const {
    if (srcTag == N) {
      using T = typename TypeByIndex<N, R...>::type;
      move<T>(src, dest);
    } else {
      Mover<N - 1, R...>()(src, srcTag, dest);
    }
  }
};

template <typename... R>
struct Mover<-1, R...> {
  void operator()(Storage<R...> &, int, Storage<R...> &) const {}
};

template <int N, typename... R>
struct Copier {
  void operator()(const Storage<R...> &src, int srcTag, Storage<R...> &dest) const {
    if (srcTag == N) {
      using T = typename TypeByIndex<N, R...>::type;
      copy<T>(src, dest);
    } else {
      Copier<N - 1, R...>()(src, srcTag, dest);
    }
  }
};

template <typename... R>
struct Copier<-1, R...> {
  void operator()(const Storage<R...> &, int, Storage<R...> &) const {}
};

} // namespace __detail_union

template <typename... R>
inline void polyDestroy(Storage<R...> &storage, int tag) {
  __detail_union::Destroyer<sizeof...(R) - 1, R...>()(storage, tag);
}

/**
 *
 * @tparam N
 * @tparam R
 * @param src
 * @param srcTag
 * @param dest
 * must be uninitialized
 */
template <typename... R>
inline void polyMove(Storage<R...> &src, int srcTag, Storage<R...> &dest) {
  __detail_union::Mover<sizeof...(R) - 1, R...>()(src, srcTag, dest);
}

template <typename... R>
inline void polyCopy(const Storage<R...> &src, int srcTag, Storage<R...> &dest) {
  __detail_union::Copier<sizeof...(R) - 1, R...>()(src, srcTag, dest);
}

// ###################
// ##     Union     ##
// ###################

template <typename... T>
class Union {
private:
  static_assert(__detail::andAll(std::is_move_constructible<T>::value...),
                "must be move-constructible");

  using StorageType = Storage<T...>;
  StorageType value_;
  int tag_;

public:
  template <typename R>
  static constexpr int TAG = TypeTag<R, T...>::value;

  Union() noexcept : tag_(-1) {}

  template <typename U, typename F = __detail::resolvedType<U, T...>>
  Union(U &&value) noexcept : tag_(TAG<F>) { // NOLINT
    this->value_.obtain(std::forward<U>(value));
  }

  Union(Union &&value) noexcept : tag_(value.tag()) {
    polyMove(value.value(), this->tag(), this->value());
    value.tag_ = -1;
  }

  Union(const Union &value) : tag_(value.tag()) {
    polyCopy(value.value(), this->tag(), this->value());
  }

  ~Union() { polyDestroy(this->value(), this->tag()); }

  Union &operator=(Union &&value) noexcept {
    if (this != std::addressof(value)) {
      this->moveAssign(value);
    }
    return *this;
  }

  Union &operator=(const Union &value) {
    if (this != std::addressof(value)) {
      this->copyAssign(value);
    }
    return *this;
  }

  StorageType &value() { return this->value_; }

  const StorageType &value() const { return this->value_; }

  int tag() const { return this->tag_; }

  bool hasValue() const { return this->tag() > -1; }

private:
  void moveAssign(Union &value) noexcept {
    polyDestroy(this->value(), this->tag());
    polyMove(value.value(), value.tag(), this->value());
    this->tag_ = value.tag();
    value.tag_ = -1;
  }

  void copyAssign(const Union &value) {
    polyDestroy(this->value(), this->tag());
    polyCopy(value.value(), value.tag(), this->value());
    this->tag_ = value.tag();
  }
};

template <typename T, typename... R>
inline bool is(const Union<R...> &value) {
  using Tag = TypeTag<T, R...>;
  static_assert(Tag::value > -1, "invalid type");
  return value.tag() == Tag::value;
}

template <typename T, typename... R>
inline T &get(Union<R...> &value) {
  assert(is<T>(value));
  return get<T>(value.value());
}

template <typename T, typename... R>
inline const T &get(const Union<R...> &value) {
  assert(is<T>(value));
  return get<T>(value.value());
}

// ######################
// ##     Optional     ##
// ######################

template <typename T>
class OptionalBase : public Union<T> {
public:
  using base_type = Union<T>;

  OptionalBase() noexcept : Union<T>() {}

  OptionalBase(T &&value) noexcept : Union<T>(std::forward<T>(value)) {} // NOLINT

  T &unwrap() noexcept { return get<T>(*this); }

  const T &unwrap() const noexcept { return get<T>(*this); }
};

template <typename... T>
class OptionalBase<Union<T...>> : public Union<T...> {
public:
  using base_type = Union<T...>;

  OptionalBase() noexcept : Union<T...>() {}

  template <typename U>
  OptionalBase(U &&value) noexcept : Union<T...>(std::forward<U>(value)) {} // NOLINT

  Union<T...> &unwrap() noexcept { return static_cast<base_type &>(*this); }

  const Union<T...> &unwrap() const noexcept { return static_cast<const base_type &>(*this); }
};

template <typename T>
struct OptFlattener {
  using type = T;
};

template <typename T>
struct OptFlattener<OptionalBase<T>> : OptFlattener<T> {};

template <typename T>
using Optional = OptionalBase<typename OptFlattener<T>::type>;

// ####################
// ##     Result     ##
// ####################

template <typename T>
struct OkHolder {
  T value;

  explicit OkHolder(T &&value) : value(std::move(value)) {}
  explicit OkHolder(const T &value) : value(value) {}
};

template <typename E>
struct ErrHolder {
  E value;

  explicit ErrHolder(E &&value) : value(std::move(value)) {}
  explicit ErrHolder(const E &value) : value(value) {}
};

template <typename T, typename Decayed = typename std::decay<T>::type>
OkHolder<Decayed> Ok(T &&value) {
  return OkHolder<Decayed>(std::forward<T>(value));
}

template <typename E, typename Decayed = typename std::decay<E>::type>
ErrHolder<Decayed> Err(E &&value) {
  return ErrHolder<Decayed>(std::forward<E>(value));
}

template <typename T, typename E>
class Result : public Union<T, E> {
public:
  NON_COPYABLE(Result);

  Result() = delete;

  template <typename T0>
  Result(OkHolder<T0> &&okHolder) noexcept : Union<T, E>(std::move(okHolder.value)) {} // NOLINT

  Result(ErrHolder<E> &&errHolder) noexcept : Union<T, E>(std::move(errHolder.value)) {} // NOLINT

  Result(Result &&result) noexcept = default;

  ~Result() = default;

  Result &operator=(Result &&result) noexcept = default;

  explicit operator bool() const { return is<T>(*this); }

  T &asOk() { return get<T>(*this); }

  E &asErr() { return get<E>(*this); }

  const T &asOk() const { return get<T>(*this); }

  const E &asErr() const { return get<E>(*this); }

  T &&take() && { return std::move(this->asOk()); }

  E &&takeError() && { return std::move(this->asErr()); }
};

END_MISC_LIB_NAMESPACE_DECL

#endif // MISC_LIB_RESULT_HPP
<commit_msg>revert<commit_after>/*
 * Copyright (C) 2018 Nagisa Sekiguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef MISC_LIB_RESULT_HPP
#define MISC_LIB_RESULT_HPP

#include <cassert>
#include <type_traits>

#include "noncopyable.h"

BEGIN_MISC_LIB_NAMESPACE_DECL

template <typename T>
struct TypeHolder {
  using type = T;
};

namespace __detail {

constexpr size_t maxOf(size_t v) { return v; }

template <typename... S>
constexpr size_t maxOf(size_t v, S... rest) {
  return std::max(v, maxOf(rest...));
}

constexpr bool andAll(bool b) { return b; }

template <typename... T>
constexpr bool andAll(bool b, T &&...t) {
  return b && andAll(std::forward<T>(t)...);
}

template <typename T>
constexpr int toTypeIndex(int) {
  return -1;
}

template <typename T, typename F, typename... R>
constexpr int toTypeIndex(int index) {
  return std::is_same<T, F>::value ? index : toTypeIndex<T, R...>(index + 1);
}

template <std::size_t I, std::size_t N, typename F, typename... R>
struct TypeByIndex : TypeByIndex<I + 1, N, R...> {};

template <std::size_t N, typename F, typename... R>
struct TypeByIndex<N, N, F, R...> {
  using type = F;
};

template <typename... T>
struct OverloadResolver;

template <typename F, typename... T>
struct OverloadResolver<F, T...> : OverloadResolver<T...> {
  using OverloadResolver<T...>::operator();

  TypeHolder<F> operator()(F) const;
};

template <>
struct OverloadResolver<> {
  void operator()() const;
};

template <typename F, typename... T>
using resolvedType = typename std::invoke_result_t<OverloadResolver<T...>, F>::type;

} // namespace __detail

template <typename U, typename... T>
struct TypeTag {
  static constexpr int value = __detail::toTypeIndex<U, T...>(0);
};

template <std::size_t N, typename T0, typename... T>
struct TypeByIndex {
  static_assert(N < sizeof...(T) + 1, "out of range");
  using type = typename __detail::TypeByIndex<0, N, T0, T...>::type;
};

// #####################
// ##     Storage     ##
// #####################

template <typename... T>
struct Storage {
  alignas(T...) unsigned char data[__detail::maxOf(sizeof(T)...)];

  template <typename U, typename F = __detail::resolvedType<U, T...>>
  void obtain(U &&value) {
    static_assert(TypeTag<F, T...>::value > -1, "invalid type");

    using Decayed = typename std::decay<F>::type;
    new (&this->data) Decayed(std::forward<U>(value));
  }
};

template <typename T, typename... R>
inline T &get(Storage<R...> &storage) {
  static_assert(TypeTag<T, R...>::value > -1, "invalid type");

  return *reinterpret_cast<T *>(&storage.data);
}

template <typename T, typename... R>
inline const T &get(const Storage<R...> &storage) {
  static_assert(TypeTag<T, R...>::value > -1, "invalid type");

  return *reinterpret_cast<const T *>(&storage.data);
}

template <typename T, typename... R>
inline void destroy(Storage<R...> &storage) {
  get<T>(storage).~T();
}

/**
 *
 * @tparam T
 * @tparam R
 * @param src
 * @param dest
 * must be uninitialized
 */
template <typename T, typename... R>
inline void move(Storage<R...> &src, Storage<R...> &dest) {
  dest.obtain(std::move(get<T>(src)));
  destroy<T>(src);
}

template <typename T, typename... R>
inline void copy(const Storage<R...> &src, Storage<R...> &dest) {
  dest.obtain(get<T>(src));
}

namespace __detail_union {

template <int N, typename... R>
struct Destroyer {
  void operator()(Storage<R...> &storage, int tag) const {
    if (tag == N) {
      using T = typename TypeByIndex<N, R...>::type;
      destroy<T>(storage);
    } else {
      Destroyer<N - 1, R...>()(storage, tag);
    }
  }
};

template <typename... R>
struct Destroyer<-1, R...> {
  void operator()(Storage<R...> &, int) const {}
};

template <int N, typename... R>
struct Mover {
  void operator()(Storage<R...> &src, int srcTag, Storage<R...> &dest) const {
    if (srcTag == N) {
      using T = typename TypeByIndex<N, R...>::type;
      move<T>(src, dest);
    } else {
      Mover<N - 1, R...>()(src, srcTag, dest);
    }
  }
};

template <typename... R>
struct Mover<-1, R...> {
  void operator()(Storage<R...> &, int, Storage<R...> &) const {}
};

template <int N, typename... R>
struct Copier {
  void operator()(const Storage<R...> &src, int srcTag, Storage<R...> &dest) const {
    if (srcTag == N) {
      using T = typename TypeByIndex<N, R...>::type;
      copy<T>(src, dest);
    } else {
      Copier<N - 1, R...>()(src, srcTag, dest);
    }
  }
};

template <typename... R>
struct Copier<-1, R...> {
  void operator()(const Storage<R...> &, int, Storage<R...> &) const {}
};

} // namespace __detail_union

template <typename... R>
inline void polyDestroy(Storage<R...> &storage, int tag) {
  __detail_union::Destroyer<sizeof...(R) - 1, R...>()(storage, tag);
}

/**
 *
 * @tparam N
 * @tparam R
 * @param src
 * @param srcTag
 * @param dest
 * must be uninitialized
 */
template <typename... R>
inline void polyMove(Storage<R...> &src, int srcTag, Storage<R...> &dest) {
  __detail_union::Mover<sizeof...(R) - 1, R...>()(src, srcTag, dest);
}

template <typename... R>
inline void polyCopy(const Storage<R...> &src, int srcTag, Storage<R...> &dest) {
  __detail_union::Copier<sizeof...(R) - 1, R...>()(src, srcTag, dest);
}

// ###################
// ##     Union     ##
// ###################

template <typename... T>
class Union {
private:
  static_assert(__detail::andAll(std::is_move_constructible<T>::value...),
                "must be move-constructible");

  using StorageType = Storage<T...>;
  StorageType value_;
  int tag_;

public:
  template <typename R>
  static constexpr int TAG = TypeTag<R, T...>::value;

  Union() noexcept : tag_(-1) {}

  template <typename U, typename F = __detail::resolvedType<U, T...>>
  Union(U &&value) noexcept : tag_(TAG<F>) { // NOLINT
    this->value_.obtain(std::forward<U>(value));
  }

  Union(Union &&value) noexcept : tag_(value.tag()) {
    polyMove(value.value(), this->tag(), this->value());
    value.tag_ = -1;
  }

  Union(const Union &value) : tag_(value.tag()) {
    polyCopy(value.value(), this->tag(), this->value());
  }

  ~Union() { polyDestroy(this->value(), this->tag()); }

  Union &operator=(Union &&value) noexcept {
    if (this != std::addressof(value)) {
      this->moveAssign(value);
    }
    return *this;
  }

  Union &operator=(const Union &value) {
    if (this != std::addressof(value)) {
      this->copyAssign(value);
    }
    return *this;
  }

  StorageType &value() { return this->value_; }

  const StorageType &value() const { return this->value_; }

  int tag() const { return this->tag_; }

  bool hasValue() const { return this->tag() > -1; }

private:
  void moveAssign(Union &value) noexcept {
    polyDestroy(this->value(), this->tag());
    polyMove(value.value(), value.tag(), this->value());
    this->tag_ = value.tag();
    value.tag_ = -1;
  }

  void copyAssign(const Union &value) {
    polyDestroy(this->value(), this->tag());
    polyCopy(value.value(), value.tag(), this->value());
    this->tag_ = value.tag();
  }
};

template <typename T, typename... R>
inline bool is(const Union<R...> &value) {
  using Tag = TypeTag<T, R...>;
  static_assert(Tag::value > -1, "invalid type");
  return value.tag() == Tag::value;
}

template <typename T, typename... R>
inline T &get(Union<R...> &value) {
  assert(is<T>(value));
  return get<T>(value.value());
}

template <typename T, typename... R>
inline const T &get(const Union<R...> &value) {
  assert(is<T>(value));
  return get<T>(value.value());
}

// ######################
// ##     Optional     ##
// ######################

template <typename T>
class OptionalBase : public Union<T> {
public:
  using base_type = Union<T>;

  OptionalBase() noexcept : Union<T>() {}

  OptionalBase(T &&value) noexcept : Union<T>(std::forward<T>(value)) {} // NOLINT

  T &unwrap() noexcept { return get<T>(*this); }

  const T &unwrap() const noexcept { return get<T>(*this); }
};

template <typename... T>
class OptionalBase<Union<T...>> : public Union<T...> {
public:
  using base_type = Union<T...>;

  OptionalBase() noexcept : Union<T...>() {}

  template <typename U>
  OptionalBase(U &&value) noexcept : Union<T...>(std::forward<U>(value)) {} // NOLINT

  Union<T...> &unwrap() noexcept { return static_cast<base_type &>(*this); }

  const Union<T...> &unwrap() const noexcept { return static_cast<const base_type &>(*this); }
};

template <typename T>
struct OptFlattener {
  using type = T;
};

template <typename T>
struct OptFlattener<OptionalBase<T>> : OptFlattener<T> {};

template <typename T>
using Optional = OptionalBase<typename OptFlattener<T>::type>;

// ####################
// ##     Result     ##
// ####################

template <typename T>
struct OkHolder {
  T value;

  explicit OkHolder(T &&value) : value(std::move(value)) {}
  explicit OkHolder(const T &value) : value(value) {}
};

template <typename E>
struct ErrHolder {
  E value;

  explicit ErrHolder(E &&value) : value(std::move(value)) {}
  explicit ErrHolder(const E &value) : value(value) {}
};

template <typename T, typename Decayed = typename std::decay<T>::type>
OkHolder<Decayed> Ok(T &&value) {
  return OkHolder<Decayed>(std::forward<T>(value));
}

template <typename E, typename Decayed = typename std::decay<E>::type>
ErrHolder<Decayed> Err(E &&value) {
  return ErrHolder<Decayed>(std::forward<E>(value));
}

template <typename T, typename E>
class Result : public Union<T, E> {
public:
  NON_COPYABLE(Result);

  Result() = delete;

  template <typename T0>
  Result(OkHolder<T0> &&okHolder) noexcept : Union<T, E>(std::move(okHolder.value)) {} // NOLINT

  Result(ErrHolder<E> &&errHolder) noexcept : Union<T, E>(std::move(errHolder.value)) {} // NOLINT

  Result(Result &&result) noexcept = default;

  ~Result() = default;

  Result &operator=(Result &&result) noexcept = default;

  explicit operator bool() const { return is<T>(*this); }

  T &asOk() { return get<T>(*this); }

  E &asErr() { return get<E>(*this); }

  const T &asOk() const { return get<T>(*this); }

  const E &asErr() const { return get<E>(*this); }

  T &&take() && { return std::move(this->asOk()); }

  E &&takeError() && { return std::move(this->asErr()); }
};

END_MISC_LIB_NAMESPACE_DECL

#endif // MISC_LIB_RESULT_HPP
<|endoftext|>


<commit_before>/***
 * @file core.hpp
 *
 * Include all of the base components required to write MLPACK methods, and the
 * main MLPACK Doxygen documentation.
 */
#ifndef __MLPACK_CORE_HPP
#define __MLPACK_CORE_HPP

/**
 * @mainpage MLPACK Documentation
 *
 * @section intro_sec Introduction
 *
 * MLPACK is an intuitive, fast, scalable C++ machine learning library, meant to
 * be a machine learning analog to LAPACK.  It aims to implement a wide array of
 * machine learning methods and function as a "swiss army knife" for machine
 * learning researchers.  The MLPACK development website can be found at
 * http://mlpack.org.
 *
 * MLPACK uses the Armadillo C++ matrix library (http://arma.sourceforge.net)
 * for general matrix, vector, and linear algebra support.  MLPACK also uses the
 * program_options, math_c99, and unit_test_framework components of the Boost
 * library; in addition, LibXml2 is used.
 *
 * @section howto How To Use This Documentation
 *
 * This documentation is API documentation similar to Javadoc.  It isn't
 * necessarily a tutorial, but it does provide detailed documentation on every
 * namespace, method, and class.
 *
 * Each MLPACK namespace generally refers to one machine learning method, so
 * browsing the list of namespaces provides some insight as to the breadth of
 * the methods contained in the library.
 *
 * To generate this documentation in your own local copy of MLPACK, you can
 * simply use Doxygen, from the root directory (@c /mlpack/trunk/ ):
 *
 * @code
 * $ doxygen
 * @endcode
 *
 * @section executables Executables
 *
 * MLPACK provides several executables so that MLPACK methods can be used
 * without any need for knowledge of C++.  These executables are all
 * self-documented, and that documentation can be accessed by running the
 * executables with the '-h' or '--help' flag.
 *
 * A full list of executables is given below:
 *
 * allkfn, allknn, emst, gmm, hmm_train, hmm_loglik, hmm_viterbi, hmm_generate,
 * kernel_pca, kmeans, lars, linear_regression, local_coordinate_coding, mvu,
 * nbc, nca, pca, radical, sparse_coding
 *
 * @section tutorial Tutorials
 *
 * A few short tutorials on how to use MLPACK are given below.
 *
 *  - @ref build
 *  - @ref matrices
 *  - @ref iodoc
 *  - @ref timer
 *  - @ref sample
 *
 * Tutorials on specific methods are also available.
 *
 *  - @ref nstutorial
 *  - @ref lrtutorial
 *  - @ref rstutorial
 *  - @ref dettutorial
 *  - @ref emst_tutorial
 *  - @ref kmtutorial
 *  - @ref fmkstutorial
 *
 * @section methods Methods in MLPACK
 *
 * The following methods are included in MLPACK:
 *
 *  - Density Estimation Trees - mlpack::det::DTree
 *  - Euclidean Minimum Spanning Trees - mlpack::emst::DualTreeBoruvka
 *  - Gaussian Mixture Models (GMMs) - mlpack::gmm::GMM
 *  - Hidden Markov Models (HMMs) - mlpack::hmm::HMM
 *  - Kernel PCA - mlpack::kpca::KernelPCA
 *  - K-Means Clustering - mlpack::kmeans::KMeans
 *  - Least-Angle Regression (LARS/LASSO) - mlpack::regression::LARS
 *  - Local Coordinate Coding - mlpack::lcc::LocalCoordinateCoding
 *  - Locality-Sensitive Hashing - mlpack::neighbor::LSHSearch
 *  - Naive Bayes Classifier - mlpack::naive_bayes::NaiveBayesClassifier
 *  - Neighborhood Components Analysis (NCA) - mlpack::nca::NCA
 *  - Principal Components Analysis (PCA) - mlpack::pca::PCA
 *  - RADICAL (ICA) - mlpack::radical::Radical
 *  - Simple Least-Squares Linear Regression -
 *        mlpack::regression::LinearRegression
 *  - Sparse Coding - mlpack::sparse_coding::SparseCoding
 *  - Tree-based neighbor search (AllkNN, AllkFN) -
 *        mlpack::neighbor::NeighborSearch
 *  - Tree-based range search - mlpack::range::RangeSearch
 *
 * @section remarks Final Remarks
 *
 * This software was written in the FASTLab (http://www.fast-lab.org), which is
 * in the School of Computational Science and Engineering at the Georgia
 * Institute of Technology.
 *
 * MLPACK contributors include:
 *
 *   - Ryan Curtin <gth671b@mail.gatech.edu>
 *   - James Cline <james.cline@gatech.edu>
 *   - Neil Slagle <nslagle3@gatech.edu>
 *   - Matthew Amidon <mamidon@gatech.edu>
 *   - Vlad Grantcharov <vlad321@gatech.edu>
 *   - Ajinkya Kale <kaleajinkya@gmail.com>
 *   - Bill March <march@gatech.edu>
 *   - Dongryeol Lee <dongryel@cc.gatech.edu>
 *   - Nishant Mehta <niche@cc.gatech.edu>
 *   - Parikshit Ram <p.ram@gatech.edu>
 *   - Rajendran Mohan <rmohan88@gatech.edu>
 *   - Trironk Kiatkungwanglai <trironk@gmail.com>
 *   - Patrick Mason <patrick.s.mason@gmail.com>
 *   - Chip Mappus <cmappus@gatech.edu>
 *   - Hua Ouyang <houyang@gatech.edu>
 *   - Long Quoc Tran <tqlong@gmail.com>
 *   - Noah Kauffman <notoriousnoah@gmail.com>
 *   - Guillermo Colon <gcolon7@mail.gatech.edu>
 *   - Wei Guan <wguan@cc.gatech.edu>
 *   - Ryan Riegel <rriegel@cc.gatech.edu>
 *   - Nikolaos Vasiloglou <nvasil@ieee.org>
 *   - Garry Boyer <garryb@gmail.com>
 *   - Andreas Löf <andreas.lof@cs.waikato.ac.nz>
 *   - Marcus Edel <marcus.edel@fu-berlin.de>
 */

// First, standard includes.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <float.h>
#include <stdint.h>
#include <iostream>

// Defining _USE_MATH_DEFINES should set M_PI.
#define _USE_MATH_DEFINES
#include <math.h>

// For tgamma().
#include <boost/math/special_functions/gamma.hpp>

// But if it's not defined, we'll do it.
#ifndef M_PI
  #define M_PI 3.141592653589793238462643383279
#endif

// Clean up unfortunate Windows preprocessor definitions.
// Use std::min and std::max!
#ifdef _WIN32
  #ifdef min
    #undef min
  #endif

  #ifdef max
    #undef max
  #endif
#endif

// Give ourselves a nice way to force functions to be inline if we need.
#define force_inline
#if defined(__GNUG__) && !defined(DEBUG)
  #undef force_inline
  #define force_inline __attribute__((always_inline))
#elif defined(_MSC_VER)
  #undef force_inline && !defined(DEBUG)
  #define force_inline __forceinline
#endif

// Now MLPACK-specific includes.
#include <mlpack/core/arma_extend/arma_extend.hpp> // Includes Armadillo.
#include <mlpack/core/util/log.hpp>
#include <mlpack/core/util/cli.hpp>
#include <mlpack/core/data/load.hpp>
#include <mlpack/core/data/save.hpp>
#include <mlpack/core/math/clamp.hpp>
#include <mlpack/core/math/random.hpp>
#include <mlpack/core/math/lin_alg.hpp>
#include <mlpack/core/math/range.hpp>
#include <mlpack/core/math/round.hpp>
#include <mlpack/core/util/save_restore_utility.hpp>
#include <mlpack/core/dists/discrete_distribution.hpp>
#include <mlpack/core/dists/gaussian_distribution.hpp>

#endif
<commit_msg>Extra cleanup of Windows' ridiculous #define min and #define max.  Seriously guys?<commit_after>/***
 * @file core.hpp
 *
 * Include all of the base components required to write MLPACK methods, and the
 * main MLPACK Doxygen documentation.
 */
#ifndef __MLPACK_CORE_HPP
#define __MLPACK_CORE_HPP

/**
 * @mainpage MLPACK Documentation
 *
 * @section intro_sec Introduction
 *
 * MLPACK is an intuitive, fast, scalable C++ machine learning library, meant to
 * be a machine learning analog to LAPACK.  It aims to implement a wide array of
 * machine learning methods and function as a "swiss army knife" for machine
 * learning researchers.  The MLPACK development website can be found at
 * http://mlpack.org.
 *
 * MLPACK uses the Armadillo C++ matrix library (http://arma.sourceforge.net)
 * for general matrix, vector, and linear algebra support.  MLPACK also uses the
 * program_options, math_c99, and unit_test_framework components of the Boost
 * library; in addition, LibXml2 is used.
 *
 * @section howto How To Use This Documentation
 *
 * This documentation is API documentation similar to Javadoc.  It isn't
 * necessarily a tutorial, but it does provide detailed documentation on every
 * namespace, method, and class.
 *
 * Each MLPACK namespace generally refers to one machine learning method, so
 * browsing the list of namespaces provides some insight as to the breadth of
 * the methods contained in the library.
 *
 * To generate this documentation in your own local copy of MLPACK, you can
 * simply use Doxygen, from the root directory (@c /mlpack/trunk/ ):
 *
 * @code
 * $ doxygen
 * @endcode
 *
 * @section executables Executables
 *
 * MLPACK provides several executables so that MLPACK methods can be used
 * without any need for knowledge of C++.  These executables are all
 * self-documented, and that documentation can be accessed by running the
 * executables with the '-h' or '--help' flag.
 *
 * A full list of executables is given below:
 *
 * allkfn, allknn, emst, gmm, hmm_train, hmm_loglik, hmm_viterbi, hmm_generate,
 * kernel_pca, kmeans, lars, linear_regression, local_coordinate_coding, mvu,
 * nbc, nca, pca, radical, sparse_coding
 *
 * @section tutorial Tutorials
 *
 * A few short tutorials on how to use MLPACK are given below.
 *
 *  - @ref build
 *  - @ref matrices
 *  - @ref iodoc
 *  - @ref timer
 *  - @ref sample
 *
 * Tutorials on specific methods are also available.
 *
 *  - @ref nstutorial
 *  - @ref lrtutorial
 *  - @ref rstutorial
 *  - @ref dettutorial
 *  - @ref emst_tutorial
 *  - @ref kmtutorial
 *  - @ref fmkstutorial
 *
 * @section methods Methods in MLPACK
 *
 * The following methods are included in MLPACK:
 *
 *  - Density Estimation Trees - mlpack::det::DTree
 *  - Euclidean Minimum Spanning Trees - mlpack::emst::DualTreeBoruvka
 *  - Gaussian Mixture Models (GMMs) - mlpack::gmm::GMM
 *  - Hidden Markov Models (HMMs) - mlpack::hmm::HMM
 *  - Kernel PCA - mlpack::kpca::KernelPCA
 *  - K-Means Clustering - mlpack::kmeans::KMeans
 *  - Least-Angle Regression (LARS/LASSO) - mlpack::regression::LARS
 *  - Local Coordinate Coding - mlpack::lcc::LocalCoordinateCoding
 *  - Locality-Sensitive Hashing - mlpack::neighbor::LSHSearch
 *  - Naive Bayes Classifier - mlpack::naive_bayes::NaiveBayesClassifier
 *  - Neighborhood Components Analysis (NCA) - mlpack::nca::NCA
 *  - Principal Components Analysis (PCA) - mlpack::pca::PCA
 *  - RADICAL (ICA) - mlpack::radical::Radical
 *  - Simple Least-Squares Linear Regression -
 *        mlpack::regression::LinearRegression
 *  - Sparse Coding - mlpack::sparse_coding::SparseCoding
 *  - Tree-based neighbor search (AllkNN, AllkFN) -
 *        mlpack::neighbor::NeighborSearch
 *  - Tree-based range search - mlpack::range::RangeSearch
 *
 * @section remarks Final Remarks
 *
 * This software was written in the FASTLab (http://www.fast-lab.org), which is
 * in the School of Computational Science and Engineering at the Georgia
 * Institute of Technology.
 *
 * MLPACK contributors include:
 *
 *   - Ryan Curtin <gth671b@mail.gatech.edu>
 *   - James Cline <james.cline@gatech.edu>
 *   - Neil Slagle <nslagle3@gatech.edu>
 *   - Matthew Amidon <mamidon@gatech.edu>
 *   - Vlad Grantcharov <vlad321@gatech.edu>
 *   - Ajinkya Kale <kaleajinkya@gmail.com>
 *   - Bill March <march@gatech.edu>
 *   - Dongryeol Lee <dongryel@cc.gatech.edu>
 *   - Nishant Mehta <niche@cc.gatech.edu>
 *   - Parikshit Ram <p.ram@gatech.edu>
 *   - Rajendran Mohan <rmohan88@gatech.edu>
 *   - Trironk Kiatkungwanglai <trironk@gmail.com>
 *   - Patrick Mason <patrick.s.mason@gmail.com>
 *   - Chip Mappus <cmappus@gatech.edu>
 *   - Hua Ouyang <houyang@gatech.edu>
 *   - Long Quoc Tran <tqlong@gmail.com>
 *   - Noah Kauffman <notoriousnoah@gmail.com>
 *   - Guillermo Colon <gcolon7@mail.gatech.edu>
 *   - Wei Guan <wguan@cc.gatech.edu>
 *   - Ryan Riegel <rriegel@cc.gatech.edu>
 *   - Nikolaos Vasiloglou <nvasil@ieee.org>
 *   - Garry Boyer <garryb@gmail.com>
 *   - Andreas Löf <andreas.lof@cs.waikato.ac.nz>
 *   - Marcus Edel <marcus.edel@fu-berlin.de>
 */

// First, standard includes.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <float.h>
#include <stdint.h>
#include <iostream>

// Defining _USE_MATH_DEFINES should set M_PI.
#define _USE_MATH_DEFINES
#include <math.h>

// For tgamma().
#include <boost/math/special_functions/gamma.hpp>

// But if it's not defined, we'll do it.
#ifndef M_PI
  #define M_PI 3.141592653589793238462643383279
#endif

// Give ourselves a nice way to force functions to be inline if we need.
#define force_inline
#if defined(__GNUG__) && !defined(DEBUG)
  #undef force_inline
  #define force_inline __attribute__((always_inline))
#elif defined(_MSC_VER)
  #undef force_inline && !defined(DEBUG)
  #define force_inline __forceinline
#endif

// Now MLPACK-specific includes.
#include <mlpack/core/arma_extend/arma_extend.hpp> // Includes Armadillo.
#include <mlpack/core/util/log.hpp>
#include <mlpack/core/util/cli.hpp>
#include <mlpack/core/data/load.hpp>
#include <mlpack/core/data/save.hpp>
#include <mlpack/core/math/clamp.hpp>
#include <mlpack/core/math/random.hpp>
#include <mlpack/core/math/lin_alg.hpp>
#include <mlpack/core/math/range.hpp>
#include <mlpack/core/math/round.hpp>
#include <mlpack/core/util/save_restore_utility.hpp>
#include <mlpack/core/dists/discrete_distribution.hpp>
#include <mlpack/core/dists/gaussian_distribution.hpp>

#endif

// Clean up unfortunate Windows preprocessor definitions, even if this file was
// already included.  Use std::min and std::max!
#ifdef _WIN32
  #ifdef min
    #undef min
  #endif

  #ifdef max
    #undef max
  #endif
#endif
<|endoftext|>