<commit_before>// Copyright (c) 2012 Plenluno All rights reserved.

#include <libj/collection.h>
#include <libj/console.h>
#include <libj/json.h>
#include <libj/map.h>
#include <libj/string.h>
#include <libj/detail/mutex.h>

#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <string>

#pragma GCC diagnostic ignored "-Wformat-security"

namespace libj {
namespace console {

static Level logLevel = DEBUG;

static Boolean isPrintable(Level level) {
    return level != OFF && logLevel <= level;
}

#ifdef LIBJ_USE_THREAD
    static detail::Mutex mutex;

    static Boolean lock() {
        return mutex.lock();
    }

    static Boolean unlock() {
        return mutex.unlock();
    }
#else
    static Boolean lock() {
        return true;
    }

    static Boolean unlock() {
        return true;
    }
#endif  // LIBJ_USE_THREAD

void setLevel(Level level) {
    lock();
    logLevel = level;
    unlock();
}

static Color foreDebug   = DEFAULT;
static Color backDebug   = DEFAULT;
static Color foreInfo    = DEFAULT;
static Color backInfo    = DEFAULT;
static Color foreNormal  = DEFAULT;
static Color backNormal  = DEFAULT;
static Color foreWarning = DEFAULT;
static Color backWarning = DEFAULT;
static Color foreError   = DEFAULT;
static Color backError   = DEFAULT;

static const char* fore(Color color) {
    switch (color) {
    case DEFAULT:
        return "";
    case BLACK:
        return "\033[30m";
    case RED:
        return "\033[31m";
    case GREEN:
        return "\033[32m";
    case YELLOW:
        return "\033[33m";
    case BLUE:
        return "\033[34m";
    case MAGENTA:
        return "\033[35m";
    case CYAN:
        return "\033[36m";
    case WHITE:
        return "\033[37m";
    default:
        assert(false);
        return "";
    }
}

static const char* back(Color color) {
    switch (color) {
    case DEFAULT:
        return "";
    case BLACK:
        return "\033[40m";
    case RED:
        return "\033[41m";
    case GREEN:
        return "\033[42m";
    case YELLOW:
        return "\033[43m";
    case BLUE:
        return "\033[44m";
    case MAGENTA:
        return "\033[45m";
    case CYAN:
        return "\033[46m";
    case WHITE:
        return "\033[47m";
    default:
        assert(false);
        return "";
    }
}

static const char* fore(Level level) {
    Color color;
    switch (level) {
    case DEBUG:
        color = foreDebug;
        break;
    case INFO:
        color = foreInfo;
        break;
    case NORMAL:
        color = foreNormal;
        break;
    case WARNING:
        color = foreWarning;
        break;
    case ERROR:
        color = foreError;
        break;
    case OFF:
        color = DEFAULT;
        break;
    }
    return fore(color);
}

static const char* back(Level level) {
    Color color;
    switch (level) {
    case DEBUG:
        color = backDebug;
        break;
    case INFO:
        color = backInfo;
        break;
    case NORMAL:
        color = backNormal;
        break;
    case WARNING:
        color = backWarning;
        break;
    case ERROR:
        color = backError;
        break;
    case OFF:
        color = DEFAULT;
        break;
    }
    return back(color);
}

void setForegroundColor(Level level, Color color) {
    lock();
    switch (level) {
    case DEBUG:
        foreDebug = color;
        break;
    case INFO:
        foreInfo = color;
        break;
    case NORMAL:
        foreNormal = color;
        break;
    case WARNING:
        foreWarning = color;
        break;
    case ERROR:
        foreError = color;
        break;
    case OFF:
        break;
    }
    unlock();
}

void setBackgroundColor(Level level, Color color) {
    lock();
    switch (level) {
    case DEBUG:
        backDebug = color;
        break;
    case INFO:
        backInfo = color;
        break;
    case NORMAL:
        backNormal = color;
        break;
    case WARNING:
        backWarning = color;
        break;
    case ERROR:
        backError = color;
        break;
    case OFF:
        break;
    }
    unlock();
}

#define LIBJ_VFPRINTF(LEVEL, OUT, FMT) \
    va_list argp; \
    va_start(argp, FMT); \
    fprintf(OUT, fore(LEVEL)); \
    fprintf(OUT, back(LEVEL)); \
    vfprintf(OUT, FMT, argp); \
    fprintf(OUT, "\033[0m"); \
    fprintf(OUT, "\033[0m");

void printf(Level level, const char* fmt, ...) {
    if (!isPrintable(level)) return;

    FILE* out = 0;
    switch (level) {
    case DEBUG:
    case INFO:
    case NORMAL:
        out = stdout;
        break;
    case WARNING:
    case ERROR:
        out = stderr;
        break;
    case OFF:
        assert(false);
    }

    lock();
    LIBJ_VFPRINTF(level, out, fmt);
    unlock();
}

static String::CPtr toString(const Value& val) {
    String::CPtr s = String::null();
    if (val.instanceof(Type<Map>::id()) ||
        val.instanceof(Type<Collection>::id())) {
        s = json::stringify(val);
    } else {
        s = String::valueOf(val);
    }
    return s;
}

void printv(
    Level level, const char* fmt,
    const Value& v0, const Value& v1,
    const Value& v2, const Value& v3,
    const Value& v4, const Value& v5,
    const Value& v6, const Value& v7,
    const Value& v8, const Value& v9) {
    if (!isPrintable(level)) return;

    const Size kMax = 10;
    std::string format(fmt);
    Size count = 0;
    size_t pos = 0;
    while (1) {
        pos = format.find("%v", pos);
        if (pos == std::string::npos) {
            break;
        } else {
            format.replace(pos, 2, "%s");
            count++;
        }
    }

    String::CPtr s[kMax];
    s[0] = toString(v0);
    s[1] = toString(v1);
    s[2] = toString(v2);
    s[3] = toString(v3);
    s[4] = toString(v4);
    s[5] = toString(v5);
    s[6] = toString(v6);
    s[7] = toString(v7);
    s[8] = toString(v8);
    s[9] = toString(v9);
    for (Size i = count; i < kMax; i++) {
        format += "%s";
        s[i] = String::null();
    }

    printf(level, format.c_str(),
        s[0] ? s[0]->toStdString().c_str() : "",
        s[1] ? s[1]->toStdString().c_str() : "",
        s[2] ? s[2]->toStdString().c_str() : "",
        s[3] ? s[3]->toStdString().c_str() : "",
        s[4] ? s[4]->toStdString().c_str() : "",
        s[5] ? s[5]->toStdString().c_str() : "",
        s[6] ? s[6]->toStdString().c_str() : "",
        s[7] ? s[7]->toStdString().c_str() : "",
        s[8] ? s[8]->toStdString().c_str() : "",
        s[9] ? s[9]->toStdString().c_str() : "");
}

#define LIBJ_PRINTLN(LEVEL, OUT, FMT) \
    if (!isPrintable(LEVEL)) return; \
    if (FMT) { \
        lock(); \
        LIBJ_VFPRINTF(LEVEL, OUT, FMT) \
        fprintf(OUT, "\n"); \
        unlock(); \
        return; \
    }

void log(const char* fmt, ...) {
    LIBJ_PRINTLN(NORMAL, stdout, fmt);
    if (!fmt) { log(static_cast<Value>(0)); }
}

void debug(const char* fmt, ...) {
    LIBJ_PRINTLN(DEBUG, stdout, fmt);
    if (!fmt) { debug(static_cast<Value>(0)); }
}

void info(const char* fmt, ...) {
    LIBJ_PRINTLN(INFO, stdout, fmt);
    if (!fmt) { info(static_cast<Value>(0)); }
}

void warn(const char* fmt, ...) {
    LIBJ_PRINTLN(WARNING, stderr, fmt);
    if (!fmt) { warn(static_cast<Value>(0)); }
}

void error(const char* fmt, ...) {
    LIBJ_PRINTLN(ERROR, stderr, fmt);
    if (!fmt) { error(static_cast<Value>(0)); }
}

Boolean log(const Value& val) {
    if (val.isUndefined() || !isPrintable(NORMAL))
        return false;

    String::CPtr s = toString(val);
    if (s) {
        log(s->toStdString().c_str());
        return true;
    } else {
        return false;
    }
}

Boolean debug(const Value& val) {
    if (val.isUndefined() || !isPrintable(DEBUG))
        return false;

    String::CPtr s = toString(val);
    if (s) {
        debug(s->toStdString().c_str());
        return true;
    } else {
        return false;
    }
}

Boolean info(const Value& val) {
    if (val.isUndefined() || !isPrintable(INFO))
        return false;

    String::CPtr s = toString(val);
    if (s) {
        info(s->toStdString().c_str());
        return true;
    } else {
        return false;
    }
}

Boolean warn(const Value& val) {
    if (val.isUndefined() || !isPrintable(WARNING))
        return false;

    String::CPtr s = toString(val);
    if (s) {
        warn(s->toStdString().c_str());
        return true;
    } else {
        return false;
    }
}

Boolean error(const Value& val) {
    if (val.isUndefined() || !isPrintable(ERROR))
        return false;

    String::CPtr s = toString(val);
    if (s) {
        error(s->toStdString().c_str());
        return true;
    } else {
        return false;
    }
}

}  // namespace console
}  // namespace libj
<commit_msg>refactor libj::console<commit_after>// Copyright (c) 2012 Plenluno All rights reserved.

#include <libj/collection.h>
#include <libj/console.h>
#include <libj/json.h>
#include <libj/map.h>
#include <libj/string.h>
#include <libj/detail/mutex.h>

#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <string>

#pragma GCC diagnostic ignored "-Wformat-security"

namespace libj {
namespace console {

static Level logLevel = DEBUG;

static inline Boolean isPrintable(Level level) {
    return level != OFF && logLevel <= level;
}

#ifdef LIBJ_USE_THREAD
    static detail::Mutex mutex;

    static inline Boolean lock() {
        return mutex.lock();
    }

    static inline Boolean unlock() {
        return mutex.unlock();
    }
#else
    static inline Boolean lock() {
        return true;
    }

    static inline Boolean unlock() {
        return true;
    }
#endif  // LIBJ_USE_THREAD

void setLevel(Level level) {
    lock();
    logLevel = level;
    unlock();
}

static Color foreDebug   = DEFAULT;
static Color backDebug   = DEFAULT;
static Color foreInfo    = DEFAULT;
static Color backInfo    = DEFAULT;
static Color foreNormal  = DEFAULT;
static Color backNormal  = DEFAULT;
static Color foreWarning = DEFAULT;
static Color backWarning = DEFAULT;
static Color foreError   = DEFAULT;
static Color backError   = DEFAULT;

static inline const char* fore(Color color) {
    switch (color) {
    case DEFAULT:
        return "";
    case BLACK:
        return "\033[30m";
    case RED:
        return "\033[31m";
    case GREEN:
        return "\033[32m";
    case YELLOW:
        return "\033[33m";
    case BLUE:
        return "\033[34m";
    case MAGENTA:
        return "\033[35m";
    case CYAN:
        return "\033[36m";
    case WHITE:
        return "\033[37m";
    default:
        assert(false);
        return "";
    }
}

static inline const char* back(Color color) {
    switch (color) {
    case DEFAULT:
        return "";
    case BLACK:
        return "\033[40m";
    case RED:
        return "\033[41m";
    case GREEN:
        return "\033[42m";
    case YELLOW:
        return "\033[43m";
    case BLUE:
        return "\033[44m";
    case MAGENTA:
        return "\033[45m";
    case CYAN:
        return "\033[46m";
    case WHITE:
        return "\033[47m";
    default:
        assert(false);
        return "";
    }
}

static inline const char* fore(Level level) {
    Color color;
    switch (level) {
    case DEBUG:
        color = foreDebug;
        break;
    case INFO:
        color = foreInfo;
        break;
    case NORMAL:
        color = foreNormal;
        break;
    case WARNING:
        color = foreWarning;
        break;
    case ERROR:
        color = foreError;
        break;
    case OFF:
        color = DEFAULT;
        break;
    }
    return fore(color);
}

static inline const char* back(Level level) {
    Color color;
    switch (level) {
    case DEBUG:
        color = backDebug;
        break;
    case INFO:
        color = backInfo;
        break;
    case NORMAL:
        color = backNormal;
        break;
    case WARNING:
        color = backWarning;
        break;
    case ERROR:
        color = backError;
        break;
    case OFF:
        color = DEFAULT;
        break;
    }
    return back(color);
}

static inline Color getForegroundColor(Level level) {
    switch (level) {
    case DEBUG:
        return foreDebug;
    case INFO:
        return foreInfo;
    case NORMAL:
        return foreNormal;
    case WARNING:
        return foreWarning;
    case ERROR:
        return foreError;
    case OFF:
        return DEFAULT;
    }
}

static inline Color getBackgroundColor(Level level) {
    switch (level) {
    case DEBUG:
        return backDebug;
    case INFO:
        return backInfo;
    case NORMAL:
        return backNormal;
    case WARNING:
        return backWarning;
    case ERROR:
        return backError;
    case OFF:
        return DEFAULT;
    }
}

void setForegroundColor(Level level, Color color) {
    lock();
    switch (level) {
    case DEBUG:
        foreDebug = color;
        break;
    case INFO:
        foreInfo = color;
        break;
    case NORMAL:
        foreNormal = color;
        break;
    case WARNING:
        foreWarning = color;
        break;
    case ERROR:
        foreError = color;
        break;
    case OFF:
        break;
    }
    unlock();
}

void setBackgroundColor(Level level, Color color) {
    lock();
    switch (level) {
    case DEBUG:
        backDebug = color;
        break;
    case INFO:
        backInfo = color;
        break;
    case NORMAL:
        backNormal = color;
        break;
    case WARNING:
        backWarning = color;
        break;
    case ERROR:
        backError = color;
        break;
    case OFF:
        break;
    }
    unlock();
}

#define LIBJ_VFPRINTF(LEVEL, OUT, FMT) \
    va_list argp; \
    va_start(argp, FMT); \
    fprintf(OUT, fore(LEVEL)); \
    fprintf(OUT, back(LEVEL)); \
    vfprintf(OUT, FMT, argp); \
    if (getForegroundColor(LEVEL) != DEFAULT) fprintf(OUT, "\033[0m"); \
    if (getBackgroundColor(LEVEL) != DEFAULT) fprintf(OUT, "\033[0m");

void printf(Level level, const char* fmt, ...) {
    if (!isPrintable(level)) return;

    FILE* out = 0;
    switch (level) {
    case DEBUG:
    case INFO:
    case NORMAL:
        out = stdout;
        break;
    case WARNING:
    case ERROR:
        out = stderr;
        break;
    case OFF:
        assert(false);
    }

    lock();
    LIBJ_VFPRINTF(level, out, fmt);
    unlock();
}

static String::CPtr toString(const Value& val) {
    String::CPtr s = String::null();
    if (val.instanceof(Type<Map>::id()) ||
        val.instanceof(Type<Collection>::id())) {
        s = json::stringify(val);
    } else {
        s = String::valueOf(val);
    }
    return s;
}

void printv(
    Level level, const char* fmt,
    const Value& v0, const Value& v1,
    const Value& v2, const Value& v3,
    const Value& v4, const Value& v5,
    const Value& v6, const Value& v7,
    const Value& v8, const Value& v9) {
    if (!isPrintable(level)) return;

    const Size kMax = 10;
    std::string format(fmt);
    Size count = 0;
    size_t pos = 0;
    while (1) {
        pos = format.find("%v", pos);
        if (pos == std::string::npos) {
            break;
        } else {
            format.replace(pos, 2, "%s");
            count++;
        }
    }

    String::CPtr s[kMax];
    s[0] = toString(v0);
    s[1] = toString(v1);
    s[2] = toString(v2);
    s[3] = toString(v3);
    s[4] = toString(v4);
    s[5] = toString(v5);
    s[6] = toString(v6);
    s[7] = toString(v7);
    s[8] = toString(v8);
    s[9] = toString(v9);
    for (Size i = count; i < kMax; i++) {
        format += "%s";
        s[i] = String::null();
    }

    printf(level, format.c_str(),
        s[0] ? s[0]->toStdString().c_str() : "",
        s[1] ? s[1]->toStdString().c_str() : "",
        s[2] ? s[2]->toStdString().c_str() : "",
        s[3] ? s[3]->toStdString().c_str() : "",
        s[4] ? s[4]->toStdString().c_str() : "",
        s[5] ? s[5]->toStdString().c_str() : "",
        s[6] ? s[6]->toStdString().c_str() : "",
        s[7] ? s[7]->toStdString().c_str() : "",
        s[8] ? s[8]->toStdString().c_str() : "",
        s[9] ? s[9]->toStdString().c_str() : "");
}

#define LIBJ_PRINTLN(LEVEL, OUT, FMT) \
    if (!isPrintable(LEVEL)) return; \
    if (FMT) { \
        lock(); \
        LIBJ_VFPRINTF(LEVEL, OUT, FMT) \
        fprintf(OUT, "\n"); \
        unlock(); \
        return; \
    }

void log(const char* fmt, ...) {
    LIBJ_PRINTLN(NORMAL, stdout, fmt);
    if (!fmt) { log(static_cast<Value>(0)); }
}

void debug(const char* fmt, ...) {
    LIBJ_PRINTLN(DEBUG, stdout, fmt);
    if (!fmt) { debug(static_cast<Value>(0)); }
}

void info(const char* fmt, ...) {
    LIBJ_PRINTLN(INFO, stdout, fmt);
    if (!fmt) { info(static_cast<Value>(0)); }
}

void warn(const char* fmt, ...) {
    LIBJ_PRINTLN(WARNING, stderr, fmt);
    if (!fmt) { warn(static_cast<Value>(0)); }
}

void error(const char* fmt, ...) {
    LIBJ_PRINTLN(ERROR, stderr, fmt);
    if (!fmt) { error(static_cast<Value>(0)); }
}

Boolean log(const Value& val) {
    if (val.isUndefined() || !isPrintable(NORMAL))
        return false;

    String::CPtr s = toString(val);
    if (s) {
        log(s->toStdString().c_str());
        return true;
    } else {
        return false;
    }
}

Boolean debug(const Value& val) {
    if (val.isUndefined() || !isPrintable(DEBUG))
        return false;

    String::CPtr s = toString(val);
    if (s) {
        debug(s->toStdString().c_str());
        return true;
    } else {
        return false;
    }
}

Boolean info(const Value& val) {
    if (val.isUndefined() || !isPrintable(INFO))
        return false;

    String::CPtr s = toString(val);
    if (s) {
        info(s->toStdString().c_str());
        return true;
    } else {
        return false;
    }
}

Boolean warn(const Value& val) {
    if (val.isUndefined() || !isPrintable(WARNING))
        return false;

    String::CPtr s = toString(val);
    if (s) {
        warn(s->toStdString().c_str());
        return true;
    } else {
        return false;
    }
}

Boolean error(const Value& val) {
    if (val.isUndefined() || !isPrintable(ERROR))
        return false;

    String::CPtr s = toString(val);
    if (s) {
        error(s->toStdString().c_str());
        return true;
    } else {
        return false;
    }
}

}  // namespace console
}  // namespace libj
<|endoftext|>


<commit_before>#include "MSL.h"

#define BOOST_RESULT_OF_USE_DECLTYPE
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/qi_char_class.hpp>
#include <boost/make_shared.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/spirit/repository/include/qi_confix.hpp>

namespace msl
{
	template<typename T, Value::Type type>
	class TemplatedValue : public Value
	{
	public:
		using base_type = TemplatedValue<T, type>;

		TemplatedValue() : { _type = type; }
		TemplatedValue(const T& t) : _value(t) { _type = type; }
		TemplatedValue(T&& t) : _value(std::move(t)) { _type = type; }

	protected:
		T _value;
	};

	template<typename T, Value::Type type>
	class NamedTemplatedValue : public Value
	{
	public:
		using base_type = NamedTemplatedValue<T, type>;

		NamedTemplatedValue() : { _type = type; }
		NamedTemplatedValue(const std::string& name, const MapType& attr, const T& t) : _attributes(attr), _value(t), _name(name) { _type = type; }
		NamedTemplatedValue(const std::string& name, MapType&& attr, T&& t) : _attributes(std::move(attr)), _value(std::move(t)), _name(name) { _type = type; }

		const std::string& name() override { return _name; };
		const MapType& attributes() override { return _attributes; }
	protected:
		MapType _attributes;
		T _value;
		std::string _name;
	};

	class BoolValue : public TemplatedValue<bool, Value::Type::Boolean>
	{
	public:
		using base_type::TemplatedValue;
		bool asBool() override { return _value; }
	};

	class StringValue : public TemplatedValue<std::string, Value::Type::String>
	{
	public:
		using base_type::TemplatedValue;
		const std::string& asString() override { return _value; }
	};

	class FloatValue : public TemplatedValue<float, Value::Type::Float>
	{
	public:
		using base_type::TemplatedValue;
		float asFloat() override { return _value; }
	};

	class ArrayValue : public TemplatedValue<Value::ArrayType, Value::Type::Array>
	{
	public:
		using base_type::TemplatedValue;
		const ArrayType& asArray() override { return _value; }
	};

	class MapValue : public TemplatedValue<Value::MapType, Value::Type::Map>
	{
	public:
		using base_type::TemplatedValue;
		const MapType& asMap() override { return _value; }
	};

	class NamedArrayValue : public NamedTemplatedValue<Value::ArrayType, Value::Type::Array>
	{
	public:
		using base_type::NamedTemplatedValue;
		const ArrayType& asArray() override { return _value; }
	};

	class NamedMapValue : public NamedTemplatedValue<Value::MapType, Value::Type::Map>
	{
	public:
		using base_type::NamedTemplatedValue;
		const MapType& asMap() override { return _value; }
	};
}

namespace client
{
	namespace qi = boost::spirit::qi;
	namespace ascii = boost::spirit::ascii;

	///////////////////////////////////////////////////////////////////////////////
	//  The skipper grammar
	///////////////////////////////////////////////////////////////////////////////
	template <typename Iterator>
	struct skipper : qi::grammar<Iterator>
	{
		skipper() : skipper::base_type(start)
		{
			qi::char_type char_;
			ascii::space_type space;

			start =
				space                               // tab/space/cr/lf
				| "/*" >> *(char_ - "*/") >> "*/"   // C-style comments
				| "//" >> *(char_ - eol) >> eol     // C++-style comments
				;
		}

		qi::rule<Iterator> start;
	};

	using namespace boost::spirit;

	template <typename Iterator>
	struct msl_grammar : qi::grammar<Iterator, msl::Value::pointer(), skipper<Iterator>>
	{
		using standard_rule = qi::rule<Iterator, msl::Value::pointer(), skipper<Iterator>>;

		template<typename Type>
		auto createAttrSynthesizer()
		{
			return [](auto&& f, auto &c)
			{
				using namespace boost::fusion;
				at_c<0>(c.attributes) = std::make_shared<Type>(std::move(f));
			};
		}

		template<typename Type>
		auto createAttrSynthesizerForNamed()
		{
			return [](auto&& f, auto &c)
			{
				using namespace boost::fusion;
				at_c<0>(c.attributes) = std::make_shared<Type>(at_c<0>(f), at_c<1>(f), at_c<2>(f));
			};
		}

		msl_grammar() : msl_grammar::base_type(msl)
		{
			using namespace msl;
			using qi::lit;
			using qi::rule;
			using qi::float_;
			using qi::_1;
			using qi::phrase_parse;
			using ascii::space;
			using ascii::char_;
			using ascii::alpha;
			using ascii::string;
			using namespace qi::labels;
			using namespace boost::fusion;

			//null
			{
				auto rule_null_f = [](auto&& f, auto &c) { at_c<0>(c.attributes) = std::make_shared<Value>(); };
				rule_null = lit("null")[rule_null_f];
			}

			//bool
			{
				auto rule_true_f = [](auto&& f, auto &c) {at_c<0>(c.attributes) = std::make_shared<BoolValue>(true);	};
				auto rule_false_f = [](auto&& f, auto &c) {at_c<0>(c.attributes) = std::make_shared<BoolValue>(false);	};
				rule_bool = lit("true")[rule_true_f] | lit("false")[rule_false_f];
			}

			//float
			{
				auto percent = [](auto&& f, auto &c)
				{
					at_c<0>(c.attributes) = std::make_shared<FloatValue>(f / 100.0f);
				};

				rule_float = (float_ >> '%')[percent] | float_[createAttrSynthesizer<FloatValue>()];
			}

			//string
			{
				quoted_string %= lexeme['"' >> *(char_ - '"') >> '"'];
				simple_string %= alpha >> *(char_("a-zA-Z0-9\\.\\-"));

				rule_string = (quoted_string | simple_string)[createAttrSynthesizer<StringValue>()];
			}

			//array
			{
				rule_varray %= '[' >> *rule_value >> ']';
				rule_array = rule_varray[createAttrSynthesizer<ArrayValue>()];
			}

			//map
			{
				rule_vmap %= qi::lit("{") >> *(rule_value >> qi::lit(":") >> rule_value) >> qi::lit("}");
				rule_map = rule_vmap[createAttrSynthesizer<MapValue>()];
			}

			rule_vattr %= "(" >> *(rule_value >> qi::lit(":") >> rule_value) >> ")";

			//named array
			{
				rule_named_array = (simple_string >> rule_vattr >> rule_varray)[createAttrSynthesizerForNamed<NamedArrayValue>()];
			}

			//named map
			{
				rule_named_map = (simple_string >> rule_vattr >> rule_vmap)[createAttrSynthesizerForNamed<NamedMapValue>()];
			}

			rule_value = rule_float | rule_array | rule_map | rule_named_array | rule_named_map | rule_bool | rule_null | rule_string;
			msl = rule_value;
		}

		standard_rule msl;

		standard_rule rule_value;
		standard_rule rule_float;
		standard_rule rule_bool;
		standard_rule rule_null;
		standard_rule rule_string;
		standard_rule rule_array;
		standard_rule rule_map;

		standard_rule rule_named_array;
		standard_rule rule_named_map;

		qi::rule<Iterator, msl::Value::MapType(), skipper<Iterator>> rule_vattr;
		qi::rule<Iterator, msl::Value::MapType(), skipper<Iterator>> rule_vmap;
		qi::rule<Iterator, msl::Value::ArrayType(), skipper<Iterator>> rule_varray;
		qi::rule<Iterator, std::string()> quoted_string;

		qi::rule<Iterator, std::string()> simple_string;
	};

	template <typename Iterator>
	msl::Value::pointer parse_msl(Iterator first, Iterator last)
	{
		msl_grammar<Iterator> msl; // Our grammar
		msl::Value::pointer ast; // Our tree

		using boost::spirit::ascii::space;
		using boost::spirit::repository::confix;
		using ascii::char_;

		//qi::rule<Iterator>
		skipper<Iterator> skipper;

		bool r = phrase_parse(first, last, msl, skipper, ast);

		return ast;
	}

}

msl::Value::pointer msl::Value::fromString(const std::string &str)
{
	return client::parse_msl(str.begin(), str.end());
}<commit_msg>added optional commas<commit_after>#include "MSL.h"

#define BOOST_RESULT_OF_USE_DECLTYPE
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/qi_char_class.hpp>
#include <boost/make_shared.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/spirit/repository/include/qi_confix.hpp>

namespace msl
{
	template<typename T, Value::Type type>
	class TemplatedValue : public Value
	{
	public:
		using base_type = TemplatedValue<T, type>;

		TemplatedValue() : { _type = type; }
		TemplatedValue(const T& t) : _value(t) { _type = type; }
		TemplatedValue(T&& t) : _value(std::move(t)) { _type = type; }

	protected:
		T _value;
	};

	template<typename T, Value::Type type>
	class NamedTemplatedValue : public Value
	{
	public:
		using base_type = NamedTemplatedValue<T, type>;

		NamedTemplatedValue() : { _type = type; }
		NamedTemplatedValue(const std::string& name, const MapType& attr, const T& t) : _attributes(attr), _value(t), _name(name) { _type = type; }
		NamedTemplatedValue(const std::string& name, MapType&& attr, T&& t) : _attributes(std::move(attr)), _value(std::move(t)), _name(name) { _type = type; }

		const std::string& name() override { return _name; };
		const MapType& attributes() override { return _attributes; }
	protected:
		MapType _attributes;
		T _value;
		std::string _name;
	};

	class BoolValue : public TemplatedValue<bool, Value::Type::Boolean>
	{
	public:
		using base_type::TemplatedValue;
		bool asBool() override { return _value; }
	};

	class StringValue : public TemplatedValue<std::string, Value::Type::String>
	{
	public:
		using base_type::TemplatedValue;
		const std::string& asString() override { return _value; }
	};

	class FloatValue : public TemplatedValue<float, Value::Type::Float>
	{
	public:
		using base_type::TemplatedValue;
		float asFloat() override { return _value; }
	};

	class ArrayValue : public TemplatedValue<Value::ArrayType, Value::Type::Array>
	{
	public:
		using base_type::TemplatedValue;
		const ArrayType& asArray() override { return _value; }
	};

	class MapValue : public TemplatedValue<Value::MapType, Value::Type::Map>
	{
	public:
		using base_type::TemplatedValue;
		const MapType& asMap() override { return _value; }
	};

	class NamedArrayValue : public NamedTemplatedValue<Value::ArrayType, Value::Type::Array>
	{
	public:
		using base_type::NamedTemplatedValue;
		const ArrayType& asArray() override { return _value; }
	};

	class NamedMapValue : public NamedTemplatedValue<Value::MapType, Value::Type::Map>
	{
	public:
		using base_type::NamedTemplatedValue;
		const MapType& asMap() override { return _value; }
	};
}

namespace client
{
	namespace qi = boost::spirit::qi;
	namespace ascii = boost::spirit::ascii;

	///////////////////////////////////////////////////////////////////////////////
	//  The skipper grammar
	///////////////////////////////////////////////////////////////////////////////
	template <typename Iterator>
	struct skipper : qi::grammar<Iterator>
	{
		skipper() : skipper::base_type(start)
		{
			qi::char_type char_;
			ascii::space_type space;

			start =
				space                               // tab/space/cr/lf
				| "/*" >> *(char_ - "*/") >> "*/"   // C-style comments
				| "//" >> *(char_ - eol) >> eol     // C++-style comments
				;
		}

		qi::rule<Iterator> start;
	};

	using namespace boost::spirit;

	template <typename Iterator>
	struct msl_grammar : qi::grammar<Iterator, msl::Value::pointer(), skipper<Iterator>>
	{
		using standard_rule = qi::rule<Iterator, msl::Value::pointer(), skipper<Iterator>>;

		template<typename Type>
		auto createAttrSynthesizer()
		{
			return [](auto&& f, auto &c)
			{
				using namespace boost::fusion;
				at_c<0>(c.attributes) = std::make_shared<Type>(std::move(f));
			};
		}

		template<typename Type>
		auto createAttrSynthesizerForNamed()
		{
			return [](auto&& f, auto &c)
			{
				using namespace boost::fusion;
				at_c<0>(c.attributes) = std::make_shared<Type>(at_c<0>(f), at_c<1>(f), at_c<2>(f));
			};
		}

		msl_grammar() : msl_grammar::base_type(msl)
		{
			using namespace msl;
			using qi::lit;
			using qi::rule;
			using qi::float_;
			using qi::_1;
			using qi::phrase_parse;
			using ascii::space;
			using ascii::char_;
			using ascii::alpha;
			using ascii::string;
			using namespace qi::labels;
			using namespace boost::fusion;

			//null
			{
				auto rule_null_f = [](auto&& f, auto &c) { at_c<0>(c.attributes) = std::make_shared<Value>(); };
				rule_null = lit("null")[rule_null_f];
			}

			//bool
			{
				auto rule_true_f = [](auto&& f, auto &c) {at_c<0>(c.attributes) = std::make_shared<BoolValue>(true);	};
				auto rule_false_f = [](auto&& f, auto &c) {at_c<0>(c.attributes) = std::make_shared<BoolValue>(false);	};
				rule_bool = lit("true")[rule_true_f] | lit("false")[rule_false_f];
			}

			//float
			{
				auto percent = [](auto&& f, auto &c)
				{
					at_c<0>(c.attributes) = std::make_shared<FloatValue>(f / 100.0f);
				};

				rule_float = (float_ >> '%')[percent] | float_[createAttrSynthesizer<FloatValue>()];
			}

			//string
			{
				quoted_string %= lexeme['"' >> *(char_ - '"') >> '"'];
				simple_string %= alpha >> *(char_("a-zA-Z0-9\\.\\-"));

				rule_string = (quoted_string | simple_string)[createAttrSynthesizer<StringValue>()];
			}

			//array
			{
				rule_varray %= '[' >> *rule_value >> -lit(',') >> ']';
				rule_array = rule_varray[createAttrSynthesizer<ArrayValue>()];
			}

			//map
			{
				rule_vmap %= qi::lit("{") >> *(rule_value >> qi::lit(":") >> rule_value >> -lit(',')) >> qi::lit("}");
				rule_map = rule_vmap[createAttrSynthesizer<MapValue>()];
			}

			rule_vattr %= "(" >> *(rule_value >> qi::lit(":") >> rule_value >> -lit(',')) >> ")";

			//named array
			{
				rule_named_array = (simple_string >> rule_vattr >> rule_varray)[createAttrSynthesizerForNamed<NamedArrayValue>()];
			}

			//named map
			{
				rule_named_map = (simple_string >> rule_vattr >> rule_vmap)[createAttrSynthesizerForNamed<NamedMapValue>()];
			}

			rule_value = rule_float | rule_array | rule_map | rule_named_array | rule_named_map | rule_bool | rule_null | rule_string;
			msl = rule_value;
		}

		standard_rule msl;

		standard_rule rule_value;
		standard_rule rule_float;
		standard_rule rule_bool;
		standard_rule rule_null;
		standard_rule rule_string;
		standard_rule rule_array;
		standard_rule rule_map;

		standard_rule rule_named_array;
		standard_rule rule_named_map;

		qi::rule<Iterator, msl::Value::MapType(), skipper<Iterator>> rule_vattr;
		qi::rule<Iterator, msl::Value::MapType(), skipper<Iterator>> rule_vmap;
		qi::rule<Iterator, msl::Value::ArrayType(), skipper<Iterator>> rule_varray;
		qi::rule<Iterator, std::string()> quoted_string;

		qi::rule<Iterator, std::string()> simple_string;
	};

	template <typename Iterator>
	msl::Value::pointer parse_msl(Iterator first, Iterator last)
	{
		msl_grammar<Iterator> msl; // Our grammar
		msl::Value::pointer ast; // Our tree

		using boost::spirit::ascii::space;
		using boost::spirit::repository::confix;
		using ascii::char_;

		//qi::rule<Iterator>
		skipper<Iterator> skipper;

		bool r = phrase_parse(first, last, msl, skipper, ast);

		return ast;
	}

}

msl::Value::pointer msl::Value::fromString(const std::string &str)
{
	return client::parse_msl(str.begin(), str.end());
}<|endoftext|>


<commit_before>#pragma once

#include "byte.hpp"
#include "magic_number.hpp"
#include "string_helpers.hpp"
#include "type_pun.hpp"

#include <gsl/gsl>

#include <cstddef>
#include <optional>
#include <string>
#include <type_traits>

template<Magic_number type_mn>
class Ucfb_reader_strict;

class Ucfb_reader {
public:
   Ucfb_reader() = delete;
   Ucfb_reader(const gsl::span<const Byte> bytes);

   template<Magic_number type_mn>
   Ucfb_reader(const Ucfb_reader_strict<type_mn>&) = delete;
   template<Magic_number type_mn>
   Ucfb_reader& operator=(const Ucfb_reader_strict<type_mn>&) = delete;

   template<Magic_number type_mn>
   Ucfb_reader(Ucfb_reader_strict<type_mn>&&) = delete;
   template<Magic_number type_mn>
   Ucfb_reader& operator=(Ucfb_reader_strict<type_mn>&&) = delete;

   template<typename Type>
   const Type& read_trivial(const bool unaligned = false)
   {
      static_assert(std::is_trivially_copyable_v<Type>,
                    "Type must be trivially copyable.");
      static_assert(!std::is_reference_v<Type>, "Type can not be a reference.");
      static_assert(!std::is_pointer_v<Type>, "Type can not be a pointer.");

      const auto cur_pos = _head;
      _head += sizeof(Type);

      check_head();

      if (!unaligned) align_head();

      return view_type_as<Type>(_data[cur_pos]);
   }

   template<typename Type>
   const Type& read_trivial_unaligned()
   {
      return read_trivial<Type>(true);
   }

   template<typename Type>
   auto read_array(typename const gsl::span<const Type>::index_type size,
                   const bool unaligned = false) -> gsl::span<const Type>
   {
      static_assert(std::is_trivially_copyable_v<Type>,
                    "Type must be trivially copyable.");
      static_assert(!std::is_reference_v<Type>, "Type can not be a reference.");
      static_assert(!std::is_pointer_v<Type>, "Type can not be a pointer.");

      const auto cur_pos = _head;
      _head += sizeof(Type) * size;

      check_head();

      if (!unaligned) align_head();

      return {&view_type_as<Type>(_data[cur_pos]), size};
   }

   template<typename Type>
   auto read_array_unaligned(typename const gsl::span<const Type>::index_type size)
      -> gsl::span<const Type>
   {
      return read_array<Type>(size, true);
   }

   template<typename Char_type = char>
   auto read_string(const bool unaligned = false) -> std::basic_string_view<Char_type>
   {
      const Char_type* const string = reinterpret_cast<const Char_type*>(_data + _head);
      const auto string_length = cstring_length(string, _size - _head);

      _head += (string_length + 1) * sizeof(Char_type);

      check_head();

      if (!unaligned) align_head();

      return {string, string_length};
   }

   template<typename Char_type = char>
   auto read_string_unaligned() -> std::basic_string_view<Char_type>
   {
      return read_string<Char_type>(true);
   }

   Ucfb_reader read_child(const bool unaligned = false);

   Ucfb_reader read_child_unaligned()
   {
      return read_child(true);
   }

   template<Magic_number type_mn>
   auto read_child_strict(const bool unaligned = false) -> Ucfb_reader_strict<type_mn>
   {
      return {read_child_strict(type_mn, unaligned),
              Ucfb_reader_strict<type_mn>::Unchecked_tag{}};
   }

   template<Magic_number type_mn>
   auto read_child_strict_unaligned() -> Ucfb_reader_strict<type_mn>
   {
      return read_child_strict<type_mn>(true);
   }

   template<Magic_number type_mn>
   auto read_child_strict_optional(const bool unaligned = false)
      -> std::optional<Ucfb_reader_strict<type_mn>>
   {
      const auto child = read_child_strict_optional(type_mn, unaligned);

      if (child) {
         return {{*child, Ucfb_reader_strict<type_mn>::Unchecked_tag{}}};
      }

      return {};
   }

   template<Magic_number type_mn>
   auto read_child_strict_optional_unaligned()
      -> std::optional<Ucfb_reader_strict<type_mn>>
   {
      return read_child_strict_optional<type_mn>(true);
   }

   void consume(const std::size_t amount, const bool unaligned = false);

   void consume_unaligned(const std::size_t amount)
   {
      consume(amount, true);
   }

   explicit operator bool() const noexcept;

   void reset_head() noexcept;

   Magic_number magic_number() const noexcept;

   std::size_t size() const noexcept;

private:
   // Special constructor for use by read_child, performs no error checking.
   Ucfb_reader(const Magic_number mn, const std::uint32_t size, const Byte* const data);

   Ucfb_reader read_child_strict(const Magic_number child_mn, const bool unaligned);

   auto read_child_strict_optional(const Magic_number child_mn, const bool unaligned)
      -> std::optional<Ucfb_reader>;

   void check_head();

   void align_head() noexcept
   {
      const auto remainder = _head % 4;

      if (remainder != 0) _head += (4 - remainder);
   }

   const Magic_number _mn;
   const std::size_t _size;
   const Byte* const _data;

   std::size_t _head = 0;
};

template<Magic_number type_mn>
class Ucfb_reader_strict : public Ucfb_reader {
public:
   Ucfb_reader_strict() = delete;

   explicit Ucfb_reader_strict(Ucfb_reader ucfb_reader) noexcept
      : Ucfb_reader{ucfb_reader}
   {
      Expects(type_mn == ucfb_reader.magic_number());
   }

private:
   friend class Ucfb_reader;

   struct Unchecked_tag {
   };

   Ucfb_reader_strict(Ucfb_reader ucfb_reader, Unchecked_tag) : Ucfb_reader{ucfb_reader}
   {
   }
};<commit_msg>Documented Ucfb_reader<commit_after>#pragma once

#include "byte.hpp"
#include "magic_number.hpp"
#include "string_helpers.hpp"
#include "type_pun.hpp"

#include <gsl/gsl>

#include <cstddef>
#include <optional>
#include <string>
#include <type_traits>

template<Magic_number type_mn>
class Ucfb_reader_strict;

//! \brief The class used for reading SWBF's game files.
//!
//! Each reader represents a non-owning view at a chunk from a "ucfb" file.
//! A reader holds only one piece of mutable state and that is the offset to the next
//! unread byte. When a reader is copied, this offset is also copied. It can however
//! be reset at anytime by calling Ucfb_reader::reset_head.
//!
//! The various `read_*` all advance the read head by the size of the value
//! they read. The read can be aligned or unaligned. When it is aligned the
//! read head is advanced to the next four byte margin after the read, else
//! it is only advanced by the size of the value.
//!
//! An inidividual instance of this class is not threadsafe, however because it
//! only represents an immutable view the multiple threads can safely hold different
//! readers all reading the same chunk.
class Ucfb_reader {
public:
   Ucfb_reader() = delete;

   //! \brief Creates a Ucfb_reader from a span of memory.
   //!
   //! \param bytes The span of memory holding the ucfb chunk. The size of the span must
   //! be at least 8.
   //!
   //! \exception std::runtime_error Thrown when the size of the chunk does not match the
   //! size of the span.
   Ucfb_reader(const gsl::span<const Byte> bytes);

   template<Magic_number type_mn>
   Ucfb_reader(const Ucfb_reader_strict<type_mn>&) = delete;
   template<Magic_number type_mn>
   Ucfb_reader& operator=(const Ucfb_reader_strict<type_mn>&) = delete;

   template<Magic_number type_mn>
   Ucfb_reader(Ucfb_reader_strict<type_mn>&&) = delete;
   template<Magic_number type_mn>
   Ucfb_reader& operator=(Ucfb_reader_strict<type_mn>&&) = delete;

   //! \brief Reads a trivial value from the chunk.
   //!
   //! \tparam Type The type of the value to read. The type must be trivially copyable.
   //!
   //! \param unaligned If the read is unaligned or not.
   //!
   //! \return A const reference to the value.
   //!
   //! \exception std::runtime_error Thrown when reading the value would go past the end
   //! of the chunk.
   template<typename Type>
   const Type& read_trivial(const bool unaligned = false)
   {
      static_assert(std::is_trivially_copyable_v<Type>,
                    "Type must be trivially copyable.");
      static_assert(!std::is_reference_v<Type>, "Type can not be a reference.");
      static_assert(!std::is_pointer_v<Type>, "Type can not be a pointer.");

      const auto cur_pos = _head;
      _head += sizeof(Type);

      check_head();

      if (!unaligned) align_head();

      return view_type_as<Type>(_data[cur_pos]);
   }

   //! \brief Reads a trivial unaligned value from the chunk.
   //!
   //! \tparam Type The type of the value to read. The type must be trivially copyable.
   //!
   //! \return A const reference to the value.
   //!
   //! \exception std::runtime_error Thrown when reading the value would go past the end
   //! of the chunk.
   template<typename Type>
   const Type& read_trivial_unaligned()
   {
      return read_trivial<Type>(true);
   }

   //! \brief Reads a variable-length array of trivial values from the chunk.
   //!
   //! \tparam Type The type of the values to read. The type must be trivially copyable.
   //!
   //! \param size The size of the array to read.
   //! \param unaligned If the read is unaligned or not.
   //!
   //! \return A span of const Type.
   //!
   //! \exception std::runtime_error Thrown when reading the array would go past the end
   //! of the chunk.
   template<typename Type>
   auto read_array(typename const gsl::span<const Type>::index_type size,
                   const bool unaligned = false) -> gsl::span<const Type>
   {
      static_assert(std::is_trivially_copyable_v<Type>,
                    "Type must be trivially copyable.");
      static_assert(!std::is_reference_v<Type>, "Type can not be a reference.");
      static_assert(!std::is_pointer_v<Type>, "Type can not be a pointer.");

      const auto cur_pos = _head;
      _head += sizeof(Type) * size;

      check_head();

      if (!unaligned) align_head();

      return {&view_type_as<Type>(_data[cur_pos]), size};
   }

   //! \brief Reads an unaligned variable-length array of trivial values from the chunk.
   //!
   //! \tparam Type The type of the values to read. The type must be trivially copyable.
   //!
   //! \param size The size of the array to read.
   //!
   //! \return A span of const Type.
   //!
   //! \exception std::runtime_error Thrown when reading the array would go past the end
   //! of the chunk.
   template<typename Type>
   auto read_array_unaligned(typename const gsl::span<const Type>::index_type size)
      -> gsl::span<const Type>
   {
      return read_array<Type>(size, true);
   }

   //! \brief Reads a null-terminated string from a chunk.
   //!
   //! \tparam Char_type The char type of the values to read. Defaults to `char`.
   //!
   //! \param unaligned If the read is unaligned or not.
   //!
   //! \return A string_view to the string.
   //!
   //! \exception std::runtime_error Thrown when reading the string would go past the end
   //! of the chunk.
   template<typename Char_type = char>
   auto read_string(const bool unaligned = false) -> std::basic_string_view<Char_type>
   {
      const Char_type* const string = reinterpret_cast<const Char_type*>(_data + _head);
      const auto string_length = cstring_length(string, _size - _head);

      _head += (string_length + 1) * sizeof(Char_type);

      check_head();

      if (!unaligned) align_head();

      return {string, string_length};
   }

   //! \brief Reads an unaligned null-terminated string from a chunk.
   //!
   //! \tparam Char_type The char type of the values to read. Defaults to `char`.
   //!
   //! \return A string_view to the string.
   //!
   //! \exception std::runtime_error Thrown when reading the string would go past the end
   //! of the chunk.
   template<typename Char_type = char>
   auto read_string_unaligned() -> std::basic_string_view<Char_type>
   {
      return read_string<Char_type>(true);
   }

   //! \brief Reads a child chunk.
   //!
   //! \param unaligned If the read is unaligned or not.
   //!
   //! \return A new Ucfb_reader for the child chunk.
   //!
   //! \exception std::runtime_error Thrown when reading the child would go past the end
   //! of the current chunk.
   Ucfb_reader read_child(const bool unaligned = false);

   //! \brief Reads an unaligned child chunk.
   //!
   //! \return A new Ucfb_reader for the child chunk.
   //!
   //! \exception std::runtime_error Thrown when reading the child would go past the end
   //! of the current chunk.
   Ucfb_reader read_child_unaligned()
   {
      return read_child(true);
   }

   //! \brief Reads a child if it's magic number matches an expected
   //! magic number.
   //!
   //! \tparam type_mn The expected Magic_number of the child chunk.
   //!
   //! \param unaligned If the read is unaligned or not.
   //!
   //! \return A new Ucfb_reader_strict<type_mn> for the child chunk.
   //!
   //! \exception std::runtime_error Thrown when the magic number of the child and the
   //! expected magic number do not match. If this happens the read head is not moved.
   //! \exception std::runtime_error Thrown when reading the child would go past the end
   //! of the current chunk.
   template<Magic_number type_mn>
   auto read_child_strict(const bool unaligned = false) -> Ucfb_reader_strict<type_mn>
   {
      return {read_child_strict(type_mn, unaligned),
              Ucfb_reader_strict<type_mn>::Unchecked_tag{}};
   }

   //! \brief Reads an unaligned child if it's magic number matches an expected
   //! magic number.
   //!
   //! \tparam type_mn The expected Magic_number of the child chunk.
   //!
   //! \return A new Ucfb_reader_strict<type_mn> for the child chunk.
   //!
   //! \exception std::runtime_error Thrown when the magic number of the child and the
   //! expected magic number do not match. If this happens the read head is not moved.
   //! \exception std::runtime_error Thrown when reading the child would go past the end
   //! of the current chunk.
   template<Magic_number type_mn>
   auto read_child_strict_unaligned() -> Ucfb_reader_strict<type_mn>
   {
      return read_child_strict<type_mn>(true);
   }

   //! \brief Reads a child if it's magic number matches an expected
   //! magic number.
   //!
   //! \tparam type_mn The expected Magic_number of the child chunk.
   //!
   //! \param unaligned If the read is unaligned or not.
   //!
   //! \return A std::optional<Ucfb_reader_strict<type_mn>> for the child chunk.
   //! If the magic number does not match std::nullopt is returned.
   //!
   //! \exception std::runtime_error Thrown when reading the child would go past the end
   //! of the current chunk.
   template<Magic_number type_mn>
   auto read_child_strict_optional(const bool unaligned = false)
      -> std::optional<Ucfb_reader_strict<type_mn>>
   {
      const auto child = read_child_strict_optional(type_mn, unaligned);

      if (child) {
         return {{*child, Ucfb_reader_strict<type_mn>::Unchecked_tag{}}};
      }

      return {};
   }

   //! \brief Reads an unaligned child if it's magic number matches an expected
   //! magic number.
   //!
   //! \tparam type_mn The expected Magic_number of the child chunk.
   //!
   //! \return A std::optional<Ucfb_reader_strict<type_mn>> for the child chunk.
   //! If the magic number does not match std::nullopt is returned.
   //!
   //! \exception std::runtime_error Thrown when reading the child would go past the end
   //! of the current chunk.
   template<Magic_number type_mn>
   auto read_child_strict_optional_unaligned()
      -> std::optional<Ucfb_reader_strict<type_mn>>
   {
      return read_child_strict_optional<type_mn>(true);
   }

   //! \brief Shifts the read head forward an amount of bytes.
   //!
   //! \param amount The amount to shift the head forward by.
   //! \param unaligned If the consume is unaligned or not.
   //!
   //! \exception std::runtime_error Thrown when the consume operation would go
   //! past the end of the chunk
   void consume(const std::size_t amount, const bool unaligned = false);

   //! \brief Shifts the read head forward an unaligned amount of bytes.
   //!
   //! \param amount The amount to shift the head forward by.
   //!
   //! \exception std::runtime_error Thrown when the consume operation would go
   //! past the end of the chunk
   void consume_unaligned(const std::size_t amount)
   {
      consume(amount, true);
   }

   //! \brief Tests if the end of the chunk has been reached or not.
   //!
   //! \return True if the end of the chunk has not been reached, false if it has.
   explicit operator bool() const noexcept;

   //! \brief Reset the read head.
   void reset_head() noexcept;

   //! \brief Gets the magic number of the chunk.
   //!
   //! \return The magic number of the chunk.
   Magic_number magic_number() const noexcept;

   //! \brief Gets size (in bytes) of the chunk.
   //!
   //! \return The size the chunk.
   std::size_t size() const noexcept;

private:
   // Special constructor for use by read_child, performs no error checking.
   Ucfb_reader(const Magic_number mn, const std::uint32_t size, const Byte* const data);

   Ucfb_reader read_child_strict(const Magic_number child_mn, const bool unaligned);

   auto read_child_strict_optional(const Magic_number child_mn, const bool unaligned)
      -> std::optional<Ucfb_reader>;

   void check_head();

   void align_head() noexcept
   {
      const auto remainder = _head % 4;

      if (remainder != 0) _head += (4 - remainder);
   }

   const Magic_number _mn;
   const std::size_t _size;
   const Byte* const _data;

   std::size_t _head = 0;
};

//! \brief A class used to restrict a reader to a specific magic number.
//!
//! \tparam type_mn The magic number to restrict the reader to.
template<Magic_number type_mn>
class Ucfb_reader_strict : public Ucfb_reader {
public:
   Ucfb_reader_strict() = delete;

   //! \brief Construct a strict reader.
   //!
   //! \param ucfb_reader The reader to construct the strict reader from.
   //! The magic number of the reader must match type_mn.
   explicit Ucfb_reader_strict(Ucfb_reader ucfb_reader) noexcept
      : Ucfb_reader{ucfb_reader}
   {
      Expects(type_mn == ucfb_reader.magic_number());
   }

private:
   friend class Ucfb_reader;

   struct Unchecked_tag {
   };

   Ucfb_reader_strict(Ucfb_reader ucfb_reader, Unchecked_tag) : Ucfb_reader{ucfb_reader}
   {
   }
};<|endoftext|>


<commit_before>//g++-5 --std=c++11 -Wall -g -o ds_tree_is_symmetric_bt ds_tree_is_symmetric_bt.cc

/**
 * @file  is BT symmetric
 * @brief Given BT check if it is symmetric around its center
 */

// https://leetcode.com/problems/symmetric-tree/

#include <iostream>          /* std::cout                    */
#include <algorithm>         /* std::max                     */
using namespace std;

/**
 * Given a binary tree, check whether it is a mirror of itself
 * (ie, symmetric around its center).
 * For example, this binary tree [1,2,2,3,4,4,3] is symmetric:
 *      1
 *     / \
 *    2   2
 *   / \ / \
 *  3  4 4  3
 * But the following [1,2,2,null,3,null,3] is not:
 *      1
 *     / \
 *    2   2
 *     \   \
 *     3    3
 */

struct TreeNode {
   int val;
   TreeNode *left;
   TreeNode *right;
   TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

/**
 * @brief Recursive DFS based approach to check tree symmetry*
 * @param root node of the BT                                *
 * @ret   true if tree is symmetrical around center          *
 */
bool isSymmetric(TreeNode* left, TreeNode* right) {
   if     (left == NULL && right == NULL)                  return true;
   else if(left == NULL || right == NULL)                  return false;
   else if(left->val != right->val)                        return false;
   else if(isSymmetric(left->left, right->right) == false) return false;
   else                    return isSymmetric(left->right, right->left);
}
bool isSymmetric(TreeNode* root) {
   return isSymmetric(root, root);
}

bool manual_test()
{
   /* First test the empty tree test-case                    */
   struct TreeNode *x = NULL;
   struct TreeNode one = TreeNode(1), two = TreeNode(2);
   if(isSymmetric(x) != true)
      {	cout << "Error: Empty test failed" << endl; return false; }

   /* Create a tree with a single node (only root node)     */
   x = &one;    /* Add first node into the BT               */
   if(isSymmetric(x) != true)
      {	cout << "Error: Single node test failed" << endl; return false; }

   /* Create a tree with 2 nodes. 1 parent and 1 child.     */
   x->left = &two;   /* Add second node to BT               */
   if(isSymmetric(x) != false)
      {	cout << "Error: Two node test failed" << endl; return false; }

   /* Create a tree with 3 nodes. 1 parent and 2 children.  */
   x->right = &two;   /* Add second node to BT              */
   if(isSymmetric(x) != true)
      {	cout << "Error: Three node test failed" << endl; return false; }

   return true;
}

int main()
{
   if(manual_test())
      cout << "Info: All manual test-cases passed" << endl;
   return 0;
}
<commit_msg>Remove an extra check<commit_after>//g++-5 --std=c++11 -Wall -g -o ds_tree_is_symmetric_bt ds_tree_is_symmetric_bt.cc

/**
 * @file  is BT symmetric
 * @brief Given BT check if it is symmetric around its center
 */

// https://leetcode.com/problems/symmetric-tree/

#include <iostream>          /* std::cout                    */
#include <algorithm>         /* std::max                     */
using namespace std;

/**
 * Given a binary tree, check whether it is a mirror of itself
 * (ie, symmetric around its center).
 * For example, this binary tree [1,2,2,3,4,4,3] is symmetric:
 *      1
 *     / \
 *    2   2
 *   / \ / \
 *  3  4 4  3
 * But the following [1,2,2,null,3,null,3] is not:
 *      1
 *     / \
 *    2   2
 *     \   \
 *     3    3
 */

struct TreeNode {
   int val;
   TreeNode *left;
   TreeNode *right;
   TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

/**
 * @brief Recursive DFS based approach to check tree symmetry*
 * @param root node of the BT                                *
 * @ret   true if tree is symmetrical around center          *
 */
bool isSymmetric(TreeNode* left, TreeNode* right) {
   if(left == NULL || right == NULL)             return (left == right);
   else if(left->val != right->val)                        return false;
   else if(isSymmetric(left->left, right->right) == false) return false;
   else                    return isSymmetric(left->right, right->left);
}
bool isSymmetric(TreeNode* root) {
   return isSymmetric(root, root);
}

bool manual_test()
{
   /* First test the empty tree test-case                    */
   struct TreeNode *x = NULL;
   struct TreeNode one = TreeNode(1), two = TreeNode(2);
   if(isSymmetric(x) != true)
      {	cout << "Error: Empty test failed" << endl; return false; }

   /* Create a tree with a single node (only root node)     */
   x = &one;    /* Add first node into the BT               */
   if(isSymmetric(x) != true)
      {	cout << "Error: Single node test failed" << endl; return false; }

   /* Create a tree with 2 nodes. 1 parent and 1 child.     */
   x->left = &two;   /* Add second node to BT               */
   if(isSymmetric(x) != false)
      {	cout << "Error: Two node test failed" << endl; return false; }

   /* Create a tree with 3 nodes. 1 parent and 2 children.  */
   x->right = &two;   /* Add second node to BT              */
   if(isSymmetric(x) != true)
      {	cout << "Error: Three node test failed" << endl; return false; }

   return true;
}

int main()
{
   if(manual_test())
      cout << "Info: All manual test-cases passed" << endl;
   return 0;
}
<|endoftext|>


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

#include "config.h"

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include <string>

#include "pcrepp.hh"

int main(int argc, char *argv[])
{
    pcre_context_static<30> context;
    int retval = EXIT_SUCCESS;

    {
        pcrepp nomatch("nothing-to-match");
        pcre_input pi("dummy");

        assert(!nomatch.match(context, pi));
    }

    {
        pcrepp match1("(\\w*)=(\\d+)");
        pcre_input pi("a=1  b=2");
        pcre_context::capture_t *cap;

        assert(match1.match(context, pi));

        cap = context.all();
        assert(cap->c_begin == 0);
        assert(cap->c_end == 3);

        assert((context.end() - context.begin()) == 2);
        assert(pi.get_substr(context.begin()) == "a");
        assert(pi.get_substr(context.begin() + 1) == "1");
        assert(pi.get_substr(context[1]) == "1");

        assert(match1.match(context, pi));
        assert((context.end() - context.begin()) == 2);
        assert(pi.get_substr(context.begin()) == "b");
        assert(pi.get_substr(context.begin() + 1) == "2");
    }

    {
        pcrepp match2("");
    }

    {
        pcrepp match3("(?<var1>\\d+)(?<var2>\\w+)");
        pcre_named_capture::iterator iter;
        const char *expected_names[] = {
            "var1",
            "var2",
        };
        int index = 0;

        for (iter = match3.named_begin();
             iter != match3.named_end();
             ++iter, index++) {
            assert(strcmp(iter->pnc_name, expected_names[index]) == 0);
        }

        assert(match3.name_index("var2") == 1);

        pcre_input pi("123foo");

        match3.match(context, pi);
        assert(pi.get_substr(context["var1"]) == "123");
    }

    {
        pcre_context::capture cap(1, 4);
        pcre_input pi("\0foo", 0, 4);

        assert("foo" == pi.get_substr(&cap));
    }

    const char *empty_cap_regexes[] = {
            "foo (?:bar)",
            "foo [(]",
            "foo \\Q(bar)\\E",
            "(*LIMIT_MATCH=3)",
            "(?i)",

            NULL
    };

    for (int lpc = 0; empty_cap_regexes[lpc]; lpc++) {
        pcrepp re(empty_cap_regexes[lpc]);

        assert(re.captures().empty());
    }

    {
        pcrepp re("foo (bar (?:baz)?)");

        assert(re.captures().size() == 1);
        assert(re.captures()[0].c_begin == 4);
        assert(re.captures()[0].c_end == 18);
        assert(re.captures()[0].length() == 14);
    }

    {
        pcrepp re("(a)(b)(c)");

        assert(re.captures().size() == 3);
        assert(re.captures()[0].c_begin == 0);
        assert(re.captures()[0].c_end == 3);
        assert(re.captures()[1].c_begin == 3);
        assert(re.captures()[1].c_end == 6);
        assert(re.captures()[2].c_begin == 6);
        assert(re.captures()[2].c_end == 9);
    }

    {
        pcrepp re("\\(a\\)(b)");

        assert(re.captures().size() == 1);
        assert(re.captures()[0].c_begin == 5);
        assert(re.captures()[0].c_end == 8);
    }

    {
        pcrepp re("(?<named>b)");

        assert(re.captures().size() == 1);
        assert(re.captures()[0].c_begin == 0);
        assert(re.captures()[0].c_end == 11);
    }

    {
        pcrepp re("(?P<named>b)");

        assert(re.captures().size() == 1);
        assert(re.captures()[0].c_begin == 0);
        assert(re.captures()[0].c_end == 12);
    }

    {
        pcrepp re("(?'named'b)");

        assert(re.captures().size() == 1);
        assert(re.captures()[0].c_begin == 0);
        assert(re.captures()[0].c_end == 11);
    }

    return retval;
}
<commit_msg>try to fix the pcrepp test<commit_after>/**
 * Copyright (c) 2007-2012, Timothy Stack
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * * Neither the name of Timothy Stack nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include <string>

#include "pcrepp.hh"

int main(int argc, char *argv[])
{
    pcre_context_static<30> context;
    int retval = EXIT_SUCCESS;

    {
        pcrepp nomatch("nothing-to-match");
        pcre_input pi("dummy");

        assert(!nomatch.match(context, pi));
    }

    {
        pcrepp match1("(\\w*)=(\\d+)");
        pcre_input pi("a=1  b=2");
        pcre_context::capture_t *cap;

        assert(match1.match(context, pi));

        cap = context.all();
        assert(cap->c_begin == 0);
        assert(cap->c_end == 3);

        assert((context.end() - context.begin()) == 2);
        assert(pi.get_substr(context.begin()) == "a");
        assert(pi.get_substr(context.begin() + 1) == "1");
        assert(pi.get_substr(context[1]) == "1");

        assert(match1.match(context, pi));
        assert((context.end() - context.begin()) == 2);
        assert(pi.get_substr(context.begin()) == "b");
        assert(pi.get_substr(context.begin() + 1) == "2");
    }

    {
        pcrepp match2("");
    }

    {
        pcrepp match3("(?<var1>\\d+)(?<var2>\\w+)");
        pcre_named_capture::iterator iter;
        const char *expected_names[] = {
            "var1",
            "var2",
        };
        int index = 0;

        for (iter = match3.named_begin();
             iter != match3.named_end();
             ++iter, index++) {
            assert(strcmp(iter->pnc_name, expected_names[index]) == 0);
        }

        assert(match3.name_index("var2") == 1);

        pcre_input pi("123foo");

        match3.match(context, pi);
        assert(pi.get_substr(context["var1"]) == "123");
    }

    {
        pcre_context::capture cap(1, 4);
        pcre_input pi("\0foo", 0, 4);

        assert("foo" == pi.get_substr(&cap));
    }

    const char *empty_cap_regexes[] = {
            "foo (?:bar)",
            "foo [(]",
            "foo \\Q(bar)\\E",
            "(*UTF)",
            "(?i)",

            NULL
    };

    for (int lpc = 0; empty_cap_regexes[lpc]; lpc++) {
        pcrepp re(empty_cap_regexes[lpc]);

        assert(re.captures().empty());
    }

    {
        pcrepp re("foo (bar (?:baz)?)");

        assert(re.captures().size() == 1);
        assert(re.captures()[0].c_begin == 4);
        assert(re.captures()[0].c_end == 18);
        assert(re.captures()[0].length() == 14);
    }

    {
        pcrepp re("(a)(b)(c)");

        assert(re.captures().size() == 3);
        assert(re.captures()[0].c_begin == 0);
        assert(re.captures()[0].c_end == 3);
        assert(re.captures()[1].c_begin == 3);
        assert(re.captures()[1].c_end == 6);
        assert(re.captures()[2].c_begin == 6);
        assert(re.captures()[2].c_end == 9);
    }

    {
        pcrepp re("\\(a\\)(b)");

        assert(re.captures().size() == 1);
        assert(re.captures()[0].c_begin == 5);
        assert(re.captures()[0].c_end == 8);
    }

    {
        pcrepp re("(?<named>b)");

        assert(re.captures().size() == 1);
        assert(re.captures()[0].c_begin == 0);
        assert(re.captures()[0].c_end == 11);
    }

    {
        pcrepp re("(?P<named>b)");

        assert(re.captures().size() == 1);
        assert(re.captures()[0].c_begin == 0);
        assert(re.captures()[0].c_end == 12);
    }

    {
        pcrepp re("(?'named'b)");

        assert(re.captures().size() == 1);
        assert(re.captures()[0].c_begin == 0);
        assert(re.captures()[0].c_end == 11);
    }

    return retval;
}
<|endoftext|>


<commit_before>//===- llvm/Analysis/BasicAliasAnalysis.h - Alias Analysis Impl -*- C++ -*-===//
//
// This file defines the default implementation of the Alias Analysis interface
// that simply implements a few identities (two different globals cannot alias,
// etc), but otherwise does no analysis.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Pass.h"
#include "llvm/iMemory.h"
#include "llvm/iOther.h"
#include "llvm/ConstantHandling.h"
#include "llvm/GlobalValue.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Target/TargetData.h"

// Make sure that anything that uses AliasAnalysis pulls in this file...
void BasicAAStub() {}

namespace {
  struct BasicAliasAnalysis : public ImmutablePass, public AliasAnalysis {

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AliasAnalysis::getAnalysisUsage(AU);
    }

    virtual void initializePass();

    // alias - This is the only method here that does anything interesting...
    //
    AliasResult alias(const Value *V1, unsigned V1Size,
                      const Value *V2, unsigned V2Size);
  private:
    // CheckGEPInstructions - Check two GEP instructions of compatible types and
    // equal number of arguments.  This checks to see if the index expressions
    // preclude the pointers from aliasing...
    AliasResult CheckGEPInstructions(GetElementPtrInst *GEP1, unsigned G1Size,
                                     GetElementPtrInst *GEP2, unsigned G2Size);
  };

  // Register this pass...
  RegisterOpt<BasicAliasAnalysis>
  X("basicaa", "Basic Alias Analysis (default AA impl)");

  // Declare that we implement the AliasAnalysis interface
  RegisterAnalysisGroup<AliasAnalysis, BasicAliasAnalysis, true> Y;
}  // End of anonymous namespace

void BasicAliasAnalysis::initializePass() {
  InitializeAliasAnalysis(this);
}

// hasUniqueAddress - Return true if the
static inline bool hasUniqueAddress(const Value *V) {
  return isa<GlobalValue>(V) || isa<MallocInst>(V) || isa<AllocaInst>(V);
}

static const Value *getUnderlyingObject(const Value *V) {
  if (!isa<PointerType>(V->getType())) return 0;

  // If we are at some type of object... return it.
  if (hasUniqueAddress(V)) return V;

  // Traverse through different addressing mechanisms...
  if (const Instruction *I = dyn_cast<Instruction>(V)) {
    if (isa<CastInst>(I) || isa<GetElementPtrInst>(I))
      return getUnderlyingObject(I->getOperand(0));
  }
  return 0;
}

// alias - Provide a bunch of ad-hoc rules to disambiguate in common cases, such
// as array references.  Note that this function is heavily tail recursive.
// Hopefully we have a smart C++ compiler.  :)
//
AliasAnalysis::AliasResult
BasicAliasAnalysis::alias(const Value *V1, unsigned V1Size,
                          const Value *V2, unsigned V2Size) {
  // Strip off constant pointer refs if they exist
  if (const ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(V1))
    V1 = CPR->getValue();
  if (const ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(V2))
    V2 = CPR->getValue();

  // Are we checking for alias of the same value?
  if (V1 == V2) return MustAlias;

  if ((!isa<PointerType>(V1->getType()) || !isa<PointerType>(V2->getType())) &&
      V1->getType() != Type::LongTy && V2->getType() != Type::LongTy)
    return NoAlias;  // Scalars cannot alias each other

  // Strip off cast instructions...
  if (const Instruction *I = dyn_cast<CastInst>(V1))
    return alias(I->getOperand(0), V1Size, V2, V2Size);
  if (const Instruction *I = dyn_cast<CastInst>(V2))
    return alias(V1, V1Size, I->getOperand(0), V2Size);

  // Figure out what objects these things are pointing to if we can...
  const Value *O1 = getUnderlyingObject(V1);
  const Value *O2 = getUnderlyingObject(V2);

  // Pointing at a discernable object?
  if (O1 && O2) {
    // If they are two different objects, we know that we have no alias...
    if (O1 != O2) return NoAlias;

    // If they are the same object, they we can look at the indexes.  If they
    // index off of the object is the same for both pointers, they must alias.
    // If they are provably different, they must not alias.  Otherwise, we can't
    // tell anything.
  } else if (O1 && isa<ConstantPointerNull>(V2)) {
    return NoAlias;                    // Unique values don't alias null
  } else if (O2 && isa<ConstantPointerNull>(V1)) {
    return NoAlias;                    // Unique values don't alias null
  }

  // If we have two gep instructions with identical indices, return an alias
  // result equal to the alias result of the original pointer...
  //
  if (const GetElementPtrInst *GEP1 = dyn_cast<GetElementPtrInst>(V1))
    if (const GetElementPtrInst *GEP2 = dyn_cast<GetElementPtrInst>(V2))
      if (GEP1->getNumOperands() == GEP2->getNumOperands() &&
          GEP1->getOperand(0)->getType() == GEP2->getOperand(0)->getType()) {
        AliasResult GAlias =
          CheckGEPInstructions((GetElementPtrInst*)GEP1, V1Size,
                               (GetElementPtrInst*)GEP2, V2Size);
        if (GAlias != MayAlias)
          return GAlias;
      }

  // Check to see if these two pointers are related by a getelementptr
  // instruction.  If one pointer is a GEP with a non-zero index of the other
  // pointer, we know they cannot alias.
  //
  if (isa<GetElementPtrInst>(V2)) {
    std::swap(V1, V2);
    std::swap(V1Size, V2Size);
  }

  if (V1Size != ~0U && V2Size != ~0U)
    if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V1)) {
      AliasResult R = alias(GEP->getOperand(0), V1Size, V2, V2Size);
      if (R == MustAlias) {
        // If there is at least one non-zero constant index, we know they cannot
        // alias.
        bool ConstantFound = false;
        for (unsigned i = 1, e = GEP->getNumOperands(); i != e; ++i)
          if (const Constant *C = dyn_cast<Constant>(GEP->getOperand(i)))
            if (!C->isNullValue()) {
              ConstantFound = true;
              break;
          }
        if (ConstantFound) {
          if (V2Size <= 1 && V1Size <= 1)  // Just pointer check?
            return NoAlias;

          // Otherwise we have to check to see that the distance is more than
          // the size of the argument... build an index vector that is equal to
          // the arguments provided, except substitute 0's for any variable
          // indexes we find...

          std::vector<Value*> Indices;
          Indices.reserve(GEP->getNumOperands()-1);
          for (unsigned i = 1; i != GEP->getNumOperands(); ++i)
            if (const Constant *C = dyn_cast<Constant>(GEP->getOperand(i)))
              Indices.push_back((Value*)C);
            else
              Indices.push_back(Constant::getNullValue(Type::LongTy));
          const Type *Ty = GEP->getOperand(0)->getType();
          int Offset = getTargetData().getIndexedOffset(Ty, Indices);
          if (Offset >= (int)V2Size || Offset <= -(int)V1Size)
            return NoAlias;
        }
      }
    }

  return MayAlias;
}

// CheckGEPInstructions - Check two GEP instructions of compatible types and
// equal number of arguments.  This checks to see if the index expressions
// preclude the pointers from aliasing...
//
AliasAnalysis::AliasResult
BasicAliasAnalysis::CheckGEPInstructions(GetElementPtrInst *GEP1, unsigned G1S,
                                         GetElementPtrInst *GEP2, unsigned G2S){
  // Do the base pointers alias?
  AliasResult BaseAlias = alias(GEP1->getOperand(0), G1S,
                                GEP2->getOperand(0), G2S);
  if (BaseAlias != MustAlias)   // No or May alias: We cannot add anything...
    return BaseAlias;

  // Find the (possibly empty) initial sequence of equal values...
  unsigned NumGEPOperands = GEP1->getNumOperands();
  unsigned UnequalOper = 1;
  while (UnequalOper != NumGEPOperands &&
         GEP1->getOperand(UnequalOper) == GEP2->getOperand(UnequalOper))
    ++UnequalOper;

  // If all operands equal each other, then the derived pointers must
  // alias each other...
  if (UnequalOper == NumGEPOperands) return MustAlias;

  // So now we know that the indexes derived from the base pointers,
  // which are known to alias, are different.  We can still determine a
  // no-alias result if there are differing constant pairs in the index
  // chain.  For example:
  //        A[i][0] != A[j][1] iff (&A[0][1]-&A[0][0] >= std::max(G1S, G2S))
  //
  unsigned SizeMax = std::max(G1S, G2S);
  if (SizeMax == ~0U) return MayAlias; // Avoid frivolous work...

  // Scan for the first operand that is constant and unequal in the
  // two getelemenptrs...
  unsigned FirstConstantOper = UnequalOper;
  for (; FirstConstantOper != NumGEPOperands; ++FirstConstantOper) {
    const Value *G1Oper = GEP1->getOperand(FirstConstantOper);
    const Value *G2Oper = GEP2->getOperand(FirstConstantOper);
    if (G1Oper != G2Oper &&   // Found non-equal constant indexes...
        isa<Constant>(G1Oper) && isa<Constant>(G2Oper)) {
      // Make sure they are comparable...  and make sure the GEP with
      // the smaller leading constant is GEP1.
      ConstantBool *Compare =
        *cast<Constant>(GEP1->getOperand(FirstConstantOper)) >
        *cast<Constant>(GEP2->getOperand(FirstConstantOper));
      if (Compare) {  // If they are comparable...
        if (Compare->getValue())
          std::swap(GEP1, GEP2);  // Make GEP1 < GEP2
        break;
      }
    }
  }

  // No constant operands, we cannot tell anything...
  if (FirstConstantOper == NumGEPOperands) return MayAlias;

  // If there are non-equal constants arguments, then we can figure
  // out a minimum known delta between the two index expressions... at
  // this point we know that the first constant index of GEP1 is less
  // than the first constant index of GEP2.
  //
  std::vector<Value*> Indices1;
  Indices1.reserve(NumGEPOperands-1);
  for (unsigned i = 1; i != FirstConstantOper; ++i)
    if (GEP1->getOperand(i)->getType() == Type::UByteTy)
      Indices1.push_back(GEP1->getOperand(i));
    else
      Indices1.push_back(Constant::getNullValue(Type::LongTy));
  std::vector<Value*> Indices2;
  Indices2.reserve(NumGEPOperands-1);
  Indices2 = Indices1;           // Copy the zeros prefix...

  // Add the two known constant operands...
  Indices1.push_back((Value*)GEP1->getOperand(FirstConstantOper));
  Indices2.push_back((Value*)GEP2->getOperand(FirstConstantOper));

  const Type *GEPPointerTy = GEP1->getOperand(0)->getType();

  // Loop over the rest of the operands...
  for (unsigned i = FirstConstantOper+1; i!=NumGEPOperands; ++i){
    const Value *Op1 = GEP1->getOperand(i);
    const Value *Op2 = GEP2->getOperand(i);
    if (Op1 == Op2) {   // If they are equal, use a zero index...
      Indices1.push_back(Constant::getNullValue(Op1->getType()));
      Indices2.push_back(Indices1.back());
    } else {
      if (isa<Constant>(Op1))
        Indices1.push_back((Value*)Op1);
      else {
        // GEP1 is known to produce a value less than GEP2.  To be
        // conservatively correct, we must assume the largest possible constant
        // is used in this position.  This cannot be the initial index to the
        // GEP instructions (because we know we have at least one element before
        // this one with the different constant arguments), so we know that the
        // current index must be into either a struct or array.  Because we know
        // it's not constant, this cannot be a structure index.  Because of
        // this, we can calculate the maximum value possible.
        //
        const ArrayType *ElTy =
          cast<ArrayType>(GEP1->getIndexedType(GEPPointerTy, Indices1, true));
        Indices1.push_back(ConstantSInt::get(Type::LongTy,
                                             ElTy->getNumElements()-1));
      }

      if (isa<Constant>(Op2))
        Indices2.push_back((Value*)Op2);
      else // Conservatively assume the minimum value for this index
        Indices2.push_back(Constant::getNullValue(Op1->getType()));
    }
  }

  int64_t Offset1 = getTargetData().getIndexedOffset(GEPPointerTy, Indices1);
  int64_t Offset2 = getTargetData().getIndexedOffset(GEPPointerTy, Indices2);
  assert(Offset1 < Offset2 &&"There is at least one different constant here!");

  if ((uint64_t)(Offset2-Offset1) >= SizeMax) {
    //std::cerr << "Determined that these two GEP's don't alias ["
    //          << SizeMax << " bytes]: \n" << *GEP1 << *GEP2;
    return NoAlias;
  }
  return MayAlias;
}

<commit_msg>Fix Bug: BasicAA/2003-05-21-GEP-Problem.ll<commit_after>//===- llvm/Analysis/BasicAliasAnalysis.h - Alias Analysis Impl -*- C++ -*-===//
//
// This file defines the default implementation of the Alias Analysis interface
// that simply implements a few identities (two different globals cannot alias,
// etc), but otherwise does no analysis.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Pass.h"
#include "llvm/iMemory.h"
#include "llvm/iOther.h"
#include "llvm/ConstantHandling.h"
#include "llvm/GlobalValue.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Target/TargetData.h"

// Make sure that anything that uses AliasAnalysis pulls in this file...
void BasicAAStub() {}

namespace {
  struct BasicAliasAnalysis : public ImmutablePass, public AliasAnalysis {

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AliasAnalysis::getAnalysisUsage(AU);
    }

    virtual void initializePass();

    // alias - This is the only method here that does anything interesting...
    //
    AliasResult alias(const Value *V1, unsigned V1Size,
                      const Value *V2, unsigned V2Size);
  private:
    // CheckGEPInstructions - Check two GEP instructions of compatible types and
    // equal number of arguments.  This checks to see if the index expressions
    // preclude the pointers from aliasing...
    AliasResult CheckGEPInstructions(GetElementPtrInst *GEP1, unsigned G1Size,
                                     GetElementPtrInst *GEP2, unsigned G2Size);
  };

  // Register this pass...
  RegisterOpt<BasicAliasAnalysis>
  X("basicaa", "Basic Alias Analysis (default AA impl)");

  // Declare that we implement the AliasAnalysis interface
  RegisterAnalysisGroup<AliasAnalysis, BasicAliasAnalysis, true> Y;
}  // End of anonymous namespace

void BasicAliasAnalysis::initializePass() {
  InitializeAliasAnalysis(this);
}

// hasUniqueAddress - Return true if the
static inline bool hasUniqueAddress(const Value *V) {
  return isa<GlobalValue>(V) || isa<MallocInst>(V) || isa<AllocaInst>(V);
}

static const Value *getUnderlyingObject(const Value *V) {
  if (!isa<PointerType>(V->getType())) return 0;

  // If we are at some type of object... return it.
  if (hasUniqueAddress(V)) return V;

  // Traverse through different addressing mechanisms...
  if (const Instruction *I = dyn_cast<Instruction>(V)) {
    if (isa<CastInst>(I) || isa<GetElementPtrInst>(I))
      return getUnderlyingObject(I->getOperand(0));
  }
  return 0;
}

// alias - Provide a bunch of ad-hoc rules to disambiguate in common cases, such
// as array references.  Note that this function is heavily tail recursive.
// Hopefully we have a smart C++ compiler.  :)
//
AliasAnalysis::AliasResult
BasicAliasAnalysis::alias(const Value *V1, unsigned V1Size,
                          const Value *V2, unsigned V2Size) {
  // Strip off constant pointer refs if they exist
  if (const ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(V1))
    V1 = CPR->getValue();
  if (const ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(V2))
    V2 = CPR->getValue();

  // Are we checking for alias of the same value?
  if (V1 == V2) return MustAlias;

  if ((!isa<PointerType>(V1->getType()) || !isa<PointerType>(V2->getType())) &&
      V1->getType() != Type::LongTy && V2->getType() != Type::LongTy)
    return NoAlias;  // Scalars cannot alias each other

  // Strip off cast instructions...
  if (const Instruction *I = dyn_cast<CastInst>(V1))
    return alias(I->getOperand(0), V1Size, V2, V2Size);
  if (const Instruction *I = dyn_cast<CastInst>(V2))
    return alias(V1, V1Size, I->getOperand(0), V2Size);

  // Figure out what objects these things are pointing to if we can...
  const Value *O1 = getUnderlyingObject(V1);
  const Value *O2 = getUnderlyingObject(V2);

  // Pointing at a discernable object?
  if (O1 && O2) {
    // If they are two different objects, we know that we have no alias...
    if (O1 != O2) return NoAlias;

    // If they are the same object, they we can look at the indexes.  If they
    // index off of the object is the same for both pointers, they must alias.
    // If they are provably different, they must not alias.  Otherwise, we can't
    // tell anything.
  } else if (O1 && isa<ConstantPointerNull>(V2)) {
    return NoAlias;                    // Unique values don't alias null
  } else if (O2 && isa<ConstantPointerNull>(V1)) {
    return NoAlias;                    // Unique values don't alias null
  }

  // If we have two gep instructions with identical indices, return an alias
  // result equal to the alias result of the original pointer...
  //
  if (const GetElementPtrInst *GEP1 = dyn_cast<GetElementPtrInst>(V1))
    if (const GetElementPtrInst *GEP2 = dyn_cast<GetElementPtrInst>(V2))
      if (GEP1->getNumOperands() == GEP2->getNumOperands() &&
          GEP1->getOperand(0)->getType() == GEP2->getOperand(0)->getType()) {
        AliasResult GAlias =
          CheckGEPInstructions((GetElementPtrInst*)GEP1, V1Size,
                               (GetElementPtrInst*)GEP2, V2Size);
        if (GAlias != MayAlias)
          return GAlias;
      }

  // Check to see if these two pointers are related by a getelementptr
  // instruction.  If one pointer is a GEP with a non-zero index of the other
  // pointer, we know they cannot alias.
  //
  if (isa<GetElementPtrInst>(V2)) {
    std::swap(V1, V2);
    std::swap(V1Size, V2Size);
  }

  if (V1Size != ~0U && V2Size != ~0U)
    if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V1)) {
      AliasResult R = alias(GEP->getOperand(0), V1Size, V2, V2Size);
      if (R == MustAlias) {
        // If there is at least one non-zero constant index, we know they cannot
        // alias.
        bool ConstantFound = false;
        for (unsigned i = 1, e = GEP->getNumOperands(); i != e; ++i)
          if (const Constant *C = dyn_cast<Constant>(GEP->getOperand(i)))
            if (!C->isNullValue()) {
              ConstantFound = true;
              break;
          }
        if (ConstantFound) {
          if (V2Size <= 1 && V1Size <= 1)  // Just pointer check?
            return NoAlias;

          // Otherwise we have to check to see that the distance is more than
          // the size of the argument... build an index vector that is equal to
          // the arguments provided, except substitute 0's for any variable
          // indexes we find...

          std::vector<Value*> Indices;
          Indices.reserve(GEP->getNumOperands()-1);
          for (unsigned i = 1; i != GEP->getNumOperands(); ++i)
            if (const Constant *C = dyn_cast<Constant>(GEP->getOperand(i)))
              Indices.push_back((Value*)C);
            else
              Indices.push_back(Constant::getNullValue(Type::LongTy));
          const Type *Ty = GEP->getOperand(0)->getType();
          int Offset = getTargetData().getIndexedOffset(Ty, Indices);
          if (Offset >= (int)V2Size || Offset <= -(int)V1Size)
            return NoAlias;
        }
      }
    }

  return MayAlias;
}

// CheckGEPInstructions - Check two GEP instructions of compatible types and
// equal number of arguments.  This checks to see if the index expressions
// preclude the pointers from aliasing...
//
AliasAnalysis::AliasResult
BasicAliasAnalysis::CheckGEPInstructions(GetElementPtrInst *GEP1, unsigned G1S,
                                         GetElementPtrInst *GEP2, unsigned G2S){
  // Do the base pointers alias?
  AliasResult BaseAlias = alias(GEP1->getOperand(0), G1S,
                                GEP2->getOperand(0), G2S);
  if (BaseAlias != MustAlias)   // No or May alias: We cannot add anything...
    return BaseAlias;

  // Find the (possibly empty) initial sequence of equal values...
  unsigned NumGEPOperands = GEP1->getNumOperands();
  unsigned UnequalOper = 1;
  while (UnequalOper != NumGEPOperands &&
         GEP1->getOperand(UnequalOper) == GEP2->getOperand(UnequalOper))
    ++UnequalOper;

  // If all operands equal each other, then the derived pointers must
  // alias each other...
  if (UnequalOper == NumGEPOperands) return MustAlias;

  // So now we know that the indexes derived from the base pointers,
  // which are known to alias, are different.  We can still determine a
  // no-alias result if there are differing constant pairs in the index
  // chain.  For example:
  //        A[i][0] != A[j][1] iff (&A[0][1]-&A[0][0] >= std::max(G1S, G2S))
  //
  unsigned SizeMax = std::max(G1S, G2S);
  if (SizeMax == ~0U) return MayAlias; // Avoid frivolous work...

  // Scan for the first operand that is constant and unequal in the
  // two getelemenptrs...
  unsigned FirstConstantOper = UnequalOper;
  for (; FirstConstantOper != NumGEPOperands; ++FirstConstantOper) {
    const Value *G1Oper = GEP1->getOperand(FirstConstantOper);
    const Value *G2Oper = GEP2->getOperand(FirstConstantOper);
    if (G1Oper != G2Oper &&   // Found non-equal constant indexes...
        isa<Constant>(G1Oper) && isa<Constant>(G2Oper)) {
      // Make sure they are comparable...  and make sure the GEP with
      // the smaller leading constant is GEP1.
      ConstantBool *Compare =
        *cast<Constant>(GEP1->getOperand(FirstConstantOper)) >
        *cast<Constant>(GEP2->getOperand(FirstConstantOper));
      if (Compare) {  // If they are comparable...
        if (Compare->getValue())
          std::swap(GEP1, GEP2);  // Make GEP1 < GEP2
        break;
      }
    }
  }

  // No constant operands, we cannot tell anything...
  if (FirstConstantOper == NumGEPOperands) return MayAlias;

  // If there are non-equal constants arguments, then we can figure
  // out a minimum known delta between the two index expressions... at
  // this point we know that the first constant index of GEP1 is less
  // than the first constant index of GEP2.
  //
  std::vector<Value*> Indices1;
  Indices1.reserve(NumGEPOperands-1);
  for (unsigned i = 1; i != FirstConstantOper; ++i)
    if (GEP1->getOperand(i)->getType() == Type::UByteTy)
      Indices1.push_back(GEP1->getOperand(i));
    else
      Indices1.push_back(Constant::getNullValue(Type::LongTy));
  std::vector<Value*> Indices2;
  Indices2.reserve(NumGEPOperands-1);
  Indices2 = Indices1;           // Copy the zeros prefix...

  // Add the two known constant operands...
  Indices1.push_back((Value*)GEP1->getOperand(FirstConstantOper));
  Indices2.push_back((Value*)GEP2->getOperand(FirstConstantOper));

  const Type *GEPPointerTy = GEP1->getOperand(0)->getType();

  // Loop over the rest of the operands...
  for (unsigned i = FirstConstantOper+1; i!=NumGEPOperands; ++i){
    const Value *Op1 = GEP1->getOperand(i);
    const Value *Op2 = GEP2->getOperand(i);
    if (Op1 == Op2) {   // If they are equal, use a zero index...
      Indices1.push_back(Constant::getNullValue(Op1->getType()));
      Indices2.push_back(Indices1.back());
    } else {
      if (isa<Constant>(Op1))
        Indices1.push_back((Value*)Op1);
      else {
        // GEP1 is known to produce a value less than GEP2.  To be
        // conservatively correct, we must assume the largest possible constant
        // is used in this position.  This cannot be the initial index to the
        // GEP instructions (because we know we have at least one element before
        // this one with the different constant arguments), so we know that the
        // current index must be into either a struct or array.  Because we know
        // it's not constant, this cannot be a structure index.  Because of
        // this, we can calculate the maximum value possible.
        //
        const ArrayType *ElTy =
          cast<ArrayType>(GEP1->getIndexedType(GEPPointerTy, Indices1, true));
        Indices1.push_back(ConstantSInt::get(Type::LongTy,
                                             ElTy->getNumElements()-1));
      }

      if (isa<Constant>(Op2))
        Indices2.push_back((Value*)Op2);
      else // Conservatively assume the minimum value for this index
        Indices2.push_back(Constant::getNullValue(Op2->getType()));
    }
  }

  int64_t Offset1 = getTargetData().getIndexedOffset(GEPPointerTy, Indices1);
  int64_t Offset2 = getTargetData().getIndexedOffset(GEPPointerTy, Indices2);
  assert(Offset1 < Offset2 &&"There is at least one different constant here!");

  if ((uint64_t)(Offset2-Offset1) >= SizeMax) {
    //std::cerr << "Determined that these two GEP's don't alias ["
    //          << SizeMax << " bytes]: \n" << *GEP1 << *GEP2;
    return NoAlias;
  }
  return MayAlias;
}

<|endoftext|>