<commit_before>#include "text_input_line.hpp"

#include "../../context.hpp"
#include "../../util/key.hpp"
#include "../../util/util.hpp"

#if M_OS == M_OS_WINDOWS
#	ifdef DELETE
#		undef DELETE
#	endif
#endif

using namespace morda;

namespace{
const uint32_t cursorBlinkPeriod_c = 500; // milliseconds

const real cursorWidth_c = real(1.0);
}

text_input_line::text_input_line(std::shared_ptr<morda::context> c, const puu::forest& desc) :
		widget(std::move(c), desc),
		single_line_text_widget(this->context, desc),
		character_input_widget(this->context),
		color_widget(this->context, desc)
{
	this->set_clip_enabled(true);
}

void text_input_line::render(const morda::matrix4& matrix) const{
	// render selection
	if(this->cursorIndex != this->selectionStartIndex){
		morda::matrix4 matr(matrix);
		matr.translate(
				this->selectionStartIndex < this->cursorIndex ? this->selectionStartPos : this->cursorPos,
				0
			);
		matr.scale(vector2(std::abs(this->cursorPos - this->selectionStartPos), this->rect().d.y()));

		auto& r = *this->context->renderer;
		r.shader->color_pos->render(matr, *r.pos_quad_01_vao, 0xff804040);
	}

	{
		morda::matrix4 matr(matrix);

		using std::round;

		const auto& font = this->get_font().get();

		matr.translate(-this->get_bounding_box().p.x() + this->xOffset, round((font.get_height() + font.get_ascender() - font.get_descender()) / 2));

		ASSERT(this->firstVisibleCharIndex <= this->get_text().size())
		font.render(
				matr,
				morda::color_to_vec4f(this->get_current_color()),
				this->get_text().substr(this->firstVisibleCharIndex, this->get_text().size() - this->firstVisibleCharIndex)
			);
	}

	if(this->is_focused() && this->cursorBlinkVisible){
		morda::matrix4 matr(matrix);
		matr.translate(this->cursorPos, 0);
		matr.scale(vector2(cursorWidth_c * this->context->units.dots_per_dp, this->rect().d.y()));

		auto& r = *this->context->renderer;
		r.shader->color_pos->render(matr, *r.pos_quad_01_vao, this->get_current_color());
	}
}

bool text_input_line::on_mouse_button(const mouse_button_event& e){
	if(e.button != mouse_button::left){
		return false;
	}

	this->leftMouseButtonDown = e.is_down;

	if(e.is_down){
		this->set_cursor_index(this->posToIndex(e.pos.x()));
	}

	return true;
}

bool text_input_line::on_mouse_move(const mouse_move_event& e){
	if(!this->leftMouseButtonDown){
		return false;
	}

	this->set_cursor_index(this->posToIndex(e.pos.x()), true);
	return true;
}

vector2 text_input_line::measure(const morda::vector2& quotum)const noexcept{
	vector2 ret;

	if(quotum.x() < 0){
		ret.x() = this->single_line_text_widget::measure(vector2(-1)).x() + cursorWidth_c * this->context->units.dots_per_dp;
	}else{
		ret.x() = quotum.x();
	}

	if(quotum.y() < 0){
		ret.y() = this->get_font().get().get_height();
	}else{
		ret.y() = quotum.y();
	}

	return ret;
}

void text_input_line::set_cursor_index(size_t index, bool selection){
	this->cursorIndex = index;

	using std::min;
	this->cursorIndex = min(this->cursorIndex, this->get_text().size()); // clamp top

	if(!selection){
		this->selectionStartIndex = this->cursorIndex;
	}

	utki::scope_exit scopeExit([this](){
		this->selectionStartPos = this->indexToPos(this->selectionStartIndex);

		if(!this->is_focused()){
			this->focus();
		}
		this->startCursorBlinking();
	});

//	TRACE(<< "selectionStartIndex = " << this->selectionStartIndex << std::endl)

	if(this->cursorIndex <= this->firstVisibleCharIndex){
		this->firstVisibleCharIndex = this->cursorIndex;
		this->xOffset = 0;
		this->cursorPos = 0;
		return;
	}

	const auto& font = this->get_font().get();

	ASSERT(this->firstVisibleCharIndex <= this->get_text().size())
	ASSERT(this->cursorIndex > this->firstVisibleCharIndex)
	this->cursorPos = font.get_advance(
			std::u32string(this->get_text(), this->firstVisibleCharIndex, this->cursorIndex - this->firstVisibleCharIndex)
		) + this->xOffset;

	ASSERT(this->cursorPos >= 0)

	if(this->cursorPos > this->rect().d.x() - cursorWidth_c * this->context->units.dots_per_dp){
		this->cursorPos = this->rect().d.x() - cursorWidth_c * this->context->units.dots_per_dp;

		this->xOffset = this->cursorPos; // start from rightmost cursor position
		this->firstVisibleCharIndex = this->cursorIndex;

		// calculate advance backwards
		for(auto i = this->get_text().rbegin() + (this->get_text().size() - this->cursorIndex);
				this->xOffset > 0;
				++i
			)
		{
			ASSERT(i != this->get_text().rend())
			this->xOffset -= font.get_advance(*i);
			ASSERT(this->firstVisibleCharIndex > 0)
			--this->firstVisibleCharIndex;
		}
	}
}

real text_input_line::indexToPos(size_t index){
	ASSERT(this->firstVisibleCharIndex <= this->get_text().size())

	if(index <= this->firstVisibleCharIndex){
		return 0;
	}

	using std::min;
	index = min(index, this->get_text().size()); // clamp top

	real ret = this->xOffset;

	for(auto i = this->get_text().begin() + this->firstVisibleCharIndex;
			i != this->get_text().end() && index != this->firstVisibleCharIndex;
			++i, --index
		)
	{
		ret += this->get_font().get().get_advance(*i);
		if(ret >= this->rect().d.x()){
			ret = this->rect().d.x();
			break;
		}
	}

	return ret;
}

size_t text_input_line::posToIndex(real pos){
	size_t index = this->firstVisibleCharIndex;
	real p = this->xOffset;

	for(auto i = this->get_text().begin() + this->firstVisibleCharIndex; i != this->get_text().end(); ++i){
		real w = this->get_font().get().get_advance(*i);

		if(pos < p + w){
			if(pos < p + w / 2){
				break;
			}
			p += w;
			++index;
			break;
		}

		p += w;
		++index;
	}

	return index;
}

void text_input_line::update(uint32_t dt){
	this->cursorBlinkVisible = !this->cursorBlinkVisible;
}

void text_input_line::on_focus_change(){
	if(this->is_focused()){
		this->ctrlPressed = false;
		this->shiftPressed = false;
		this->startCursorBlinking();
	}else{
		this->context->updater->stop(*this);
	}
}

void text_input_line::on_resize(){
//	TRACE(<< "text_input_line::on_resize(): size = " << this->rect().d << std::endl)
	this->selectionStartPos = this->indexToPos(this->selectionStartIndex);
}

void text_input_line::startCursorBlinking(){
	this->context->updater->stop(*this);
	this->cursorBlinkVisible = true;
	this->context->updater->start(
			utki::make_shared_from(*static_cast<updateable*>(this)),
			cursorBlinkPeriod_c
		);
}

bool text_input_line::on_key(bool isDown, key keyCode){
	switch(keyCode){
		case key::left_control:
		case key::right_control:
			this->ctrlPressed = isDown;
			break;
		case key::left_shift:
		case key::right_shift:
			this->shiftPressed = isDown;
			break;
		default:
			break;
	}
	return false;
}

void text_input_line::on_character_input(const std::u32string& unicode, key keycode){
	switch(keycode){
		case key::enter:
			break;
		case key::right:
			if(this->cursorIndex != this->get_text().size()){
				size_t newIndex;
				if(this->ctrlPressed){
					bool spaceSkipped = false;
					newIndex = this->cursorIndex;
					for(auto i = this->get_text().begin() + this->cursorIndex; i != this->get_text().end(); ++i, ++newIndex){
						if(*i == uint32_t(' ')){
							if(spaceSkipped){
								break;
							}
						}else{
							spaceSkipped = true;
						}
					}

				}else{
					newIndex = this->cursorIndex + 1;
				}
				this->set_cursor_index(newIndex, this->shiftPressed);
			}
			break;
		case key::left:
			if(this->cursorIndex != 0){
				size_t newIndex;
				if(this->ctrlPressed){
					bool spaceSkipped = false;
					newIndex = this->cursorIndex;
					for(auto i = this->get_text().rbegin() + (this->get_text().size() - this->cursorIndex);
							i != this->get_text().rend();
							++i, --newIndex
						)
					{
						if(*i == uint32_t(' ')){
							if(spaceSkipped){
								break;
							}
						}else{
							spaceSkipped = true;
						}
					}
				}else{
					newIndex = this->cursorIndex - 1;
				}
				this->set_cursor_index(newIndex, this->shiftPressed);
			}
			break;
		case key::end:
			this->set_cursor_index(this->get_text().size(), this->shiftPressed);
			break;
		case key::home:
			this->set_cursor_index(0, this->shiftPressed);
			break;
		case key::backspace:
			if(this->thereIsSelection()){
				this->set_cursor_index(this->deleteSelection());
			}else{
				if(this->cursorIndex != 0){
					auto t = this->get_text();
					this->clear();
					t.erase(t.begin() + (this->cursorIndex - 1));
					this->set_text(std::move(t));
					this->set_cursor_index(this->cursorIndex - 1);
				}
			}
			break;
		case key::deletion:
			if(this->thereIsSelection()){
				this->set_cursor_index(this->deleteSelection());
			}else{
				if(this->cursorIndex < this->get_text().size()){
					auto t = this->get_text();
					this->clear();
					t.erase(t.begin() + this->cursorIndex);
					this->set_text(std::move(t));
				}
			}
			this->startCursorBlinking();
			break;
		case key::escape:
			// do nothing
			break;
		case key::a:
			if(this->ctrlPressed){
				this->selectionStartIndex = 0;
				this->set_cursor_index(this->get_text().size(), true);
				break;
			}
			// fall through
		default:
			if(unicode.size() != 0){
				if(this->thereIsSelection()){
					this->cursorIndex = this->deleteSelection();
				}

				auto t = this->get_text();
				this->clear();
				t.insert(t.begin() + this->cursorIndex, unicode.begin(), unicode.end());
				this->set_text(std::move(t));

				this->set_cursor_index(this->cursorIndex + unicode.size());
			}

			break;
	}

}

size_t text_input_line::deleteSelection(){
	ASSERT(this->cursorIndex != this->selectionStartIndex)

	size_t start, end;
	if(this->cursorIndex < this->selectionStartIndex){
		start = this->cursorIndex;
		end = this->selectionStartIndex;
	}else{
		start = this->selectionStartIndex;
		end = this->cursorIndex;
	}

	auto t = this->get_text();
	this->clear();
	t.erase(t.begin() + start, t.begin() + end);
	this->set_text(std::move(t));

	return start;
}
<commit_msg>stuff<commit_after>#include "text_input_line.hpp"

#include "../../context.hpp"
#include "../../util/key.hpp"
#include "../../util/util.hpp"

#if M_OS == M_OS_WINDOWS
#	ifdef DELETE
#		undef DELETE
#	endif
#endif

using namespace morda;

namespace{
const uint32_t cursorBlinkPeriod_c = 500; // milliseconds

const real cursorWidth_c = real(1.0);
}

text_input_line::text_input_line(std::shared_ptr<morda::context> c, const puu::forest& desc) :
		widget(std::move(c), desc),
		single_line_text_widget(this->context, desc),
		character_input_widget(this->context),
		color_widget(this->context, desc)
{
	this->set_clip_enabled(true);
}

void text_input_line::render(const morda::matrix4& matrix) const{
	// render selection
	if(this->cursorIndex != this->selectionStartIndex){
		morda::matrix4 matr(matrix);
		matr.translate(
				this->selectionStartIndex < this->cursorIndex ? this->selectionStartPos : this->cursorPos,
				0
			);
		matr.scale(vector2(std::abs(this->cursorPos - this->selectionStartPos), this->rect().d.y()));

		auto& r = *this->context->renderer;
		r.shader->color_pos->render(matr, *r.pos_quad_01_vao, 0xff804040);
	}

	{
		morda::matrix4 matr(matrix);

		using std::round;

		const auto& font = this->get_font().get();

		matr.translate(-this->get_bounding_box().p.x() + this->xOffset, round((font.get_height() + font.get_ascender() - font.get_descender()) / 2));

		ASSERT(this->firstVisibleCharIndex <= this->get_text().size())
		font.render(
				matr,
				morda::color_to_vec4f(this->get_current_color()),
				this->get_text().substr(this->firstVisibleCharIndex, this->get_text().size() - this->firstVisibleCharIndex)
			);
	}

	if(this->is_focused() && this->cursorBlinkVisible){
		morda::matrix4 matr(matrix);
		matr.translate(this->cursorPos, 0);
		matr.scale(vector2(cursorWidth_c * this->context->units.dots_per_dp, this->rect().d.y()));

		auto& r = *this->context->renderer;
		r.shader->color_pos->render(matr, *r.pos_quad_01_vao, this->get_current_color());
	}
}

bool text_input_line::on_mouse_button(const mouse_button_event& e){
	if(e.button != mouse_button::left){
		return false;
	}

	this->leftMouseButtonDown = e.is_down;

	if(e.is_down){
		this->set_cursor_index(this->posToIndex(e.pos.x()));
	}

	return true;
}

bool text_input_line::on_mouse_move(const mouse_move_event& e){
	if(!this->leftMouseButtonDown){
		return false;
	}

	this->set_cursor_index(this->posToIndex(e.pos.x()), true);
	return true;
}

vector2 text_input_line::measure(const morda::vector2& quotum)const noexcept{
	vector2 ret;

	if(quotum.x() < 0){
		ret.x() = this->single_line_text_widget::measure(vector2(-1)).x() + cursorWidth_c * this->context->units.dots_per_dp;
	}else{
		ret.x() = quotum.x();
	}

	if(quotum.y() < 0){
		ret.y() = this->get_font().get().get_height();
	}else{
		ret.y() = quotum.y();
	}

	return ret;
}

void text_input_line::set_cursor_index(size_t index, bool selection){
	this->cursorIndex = index;

	using std::min;
	this->cursorIndex = min(this->cursorIndex, this->get_text().size()); // clamp top

	if(!selection){
		this->selectionStartIndex = this->cursorIndex;
	}

	utki::scope_exit scopeExit([this](){
		this->selectionStartPos = this->indexToPos(this->selectionStartIndex);

		if(!this->is_focused()){
			this->focus();
		}
		this->startCursorBlinking();
	});

//	TRACE(<< "selectionStartIndex = " << this->selectionStartIndex << std::endl)

	if(this->cursorIndex <= this->firstVisibleCharIndex){
		this->firstVisibleCharIndex = this->cursorIndex;
		this->xOffset = 0;
		this->cursorPos = 0;
		return;
	}

	const auto& font = this->get_font().get();

	ASSERT(this->firstVisibleCharIndex <= this->get_text().size())
	ASSERT(this->cursorIndex > this->firstVisibleCharIndex)
	this->cursorPos = font.get_advance(
			std::u32string(this->get_text(), this->firstVisibleCharIndex, this->cursorIndex - this->firstVisibleCharIndex)
		) + this->xOffset;

	ASSERT(this->cursorPos >= 0)

	if(this->cursorPos > this->rect().d.x() - cursorWidth_c * this->context->units.dots_per_dp){
		this->cursorPos = this->rect().d.x() - cursorWidth_c * this->context->units.dots_per_dp;

		this->xOffset = this->cursorPos; // start from rightmost cursor position
		this->firstVisibleCharIndex = this->cursorIndex;

		// calculate advance backwards
		for(auto i = this->get_text().rbegin() + (this->get_text().size() - this->cursorIndex);
				this->xOffset > 0;
				++i
			)
		{
			ASSERT(i != this->get_text().rend())
			this->xOffset -= font.get_advance(*i);
			ASSERT(this->firstVisibleCharIndex > 0)
			--this->firstVisibleCharIndex;
		}
	}
}

real text_input_line::indexToPos(size_t index){
	ASSERT(this->firstVisibleCharIndex <= this->get_text().size())

	if(index <= this->firstVisibleCharIndex){
		return 0;
	}

	using std::min;
	index = min(index, this->get_text().size()); // clamp top

	real ret = this->xOffset;

	for(auto i = this->get_text().begin() + this->firstVisibleCharIndex;
			i != this->get_text().end() && index != this->firstVisibleCharIndex;
			++i, --index
		)
	{
		ret += this->get_font().get().get_advance(*i);
		if(ret >= this->rect().d.x()){
			ret = this->rect().d.x();
			break;
		}
	}

	return ret;
}

size_t text_input_line::posToIndex(real pos){
	size_t index = this->firstVisibleCharIndex;
	real p = this->xOffset;

	for(auto i = this->get_text().begin() + this->firstVisibleCharIndex; i != this->get_text().end(); ++i){
		real w = this->get_font().get().get_advance(*i);

		if(pos < p + w){
			if(pos < p + w / 2){
				break;
			}
			p += w;
			++index;
			break;
		}

		p += w;
		++index;
	}

	return index;
}

void text_input_line::update(uint32_t dt){
	this->cursorBlinkVisible = !this->cursorBlinkVisible;
}

void text_input_line::on_focus_change(){
	if(this->is_focused()){
		this->ctrlPressed = false;
		this->shiftPressed = false;
		this->startCursorBlinking();
	}else{
		this->context->updater->stop(*this);
	}
}

void text_input_line::on_resize(){
//	TRACE(<< "text_input_line::on_resize(): size = " << this->rect().d << std::endl)
	this->selectionStartPos = this->indexToPos(this->selectionStartIndex);
}

void text_input_line::startCursorBlinking(){
	this->context->updater->stop(*this);
	this->cursorBlinkVisible = true;
	this->context->updater->start(
			utki::make_shared_from(*static_cast<updateable*>(this)),
			cursorBlinkPeriod_c
		);
}

bool text_input_line::on_key(bool isDown, key keyCode){
	switch(keyCode){
		case key::left_control:
		case key::right_control:
			this->ctrlPressed = isDown;
			break;
		case key::left_shift:
		case key::right_shift:
			this->shiftPressed = isDown;
			break;
		default:
			break;
	}
	return false;
}

void text_input_line::on_character_input(const std::u32string& unicode, key keycode){
	switch(keycode){
		case key::enter:
			break;
		case key::right:
			if(this->cursorIndex != this->get_text().size()){
				size_t newIndex;
				if(this->ctrlPressed){
					bool spaceSkipped = false;
					newIndex = this->cursorIndex;
					for(auto i = this->get_text().begin() + this->cursorIndex; i != this->get_text().end(); ++i, ++newIndex){
						if(*i == uint32_t(' ')){
							if(spaceSkipped){
								break;
							}
						}else{
							spaceSkipped = true;
						}
					}

				}else{
					newIndex = this->cursorIndex + 1;
				}
				this->set_cursor_index(newIndex, this->shiftPressed);
			}
			break;
		case key::left:
			if(this->cursorIndex != 0){
				size_t newIndex;
				if(this->ctrlPressed){
					bool spaceSkipped = false;
					newIndex = this->cursorIndex;
					for(auto i = this->get_text().rbegin() + (this->get_text().size() - this->cursorIndex);
							i != this->get_text().rend();
							++i, --newIndex
						)
					{
						if(*i == uint32_t(' ')){
							if(spaceSkipped){
								break;
							}
						}else{
							spaceSkipped = true;
						}
					}
				}else{
					newIndex = this->cursorIndex - 1;
				}
				this->set_cursor_index(newIndex, this->shiftPressed);
			}
			break;
		case key::end:
			this->set_cursor_index(this->get_text().size(), this->shiftPressed);
			break;
		case key::home:
			this->set_cursor_index(0, this->shiftPressed);
			break;
		case key::backspace:
			if(this->thereIsSelection()){
				this->set_cursor_index(this->deleteSelection());
			}else{
				if(this->cursorIndex != 0){
					auto t = this->get_text();
					this->clear();
					t.erase(t.begin() + (this->cursorIndex - 1));
					this->set_text(std::move(t));
					this->set_cursor_index(this->cursorIndex - 1);
				}
			}
			break;
		case key::deletion:
			if(this->thereIsSelection()){
				this->set_cursor_index(this->deleteSelection());
			}else{
				if(this->cursorIndex < this->get_text().size()){
					auto t = this->get_text();
					this->clear();
					t.erase(t.begin() + this->cursorIndex);
					this->set_text(std::move(t));
				}
			}
			this->startCursorBlinking();
			break;
		case key::escape:
			// do nothing
			break;
		case key::a:
			if(this->ctrlPressed){
				this->selectionStartIndex = 0;
				this->set_cursor_index(this->get_text().size(), true);
				break;
			}
			// fall through
		default:
			if(unicode.size() != 0){
				if(this->thereIsSelection()){
					this->cursorIndex = this->deleteSelection();
				}

				auto t = this->get_text();
				this->clear();
				t.insert(t.begin() + this->cursorIndex, unicode.begin(), unicode.end());
				this->set_text(std::move(t));

				this->set_cursor_index(this->cursorIndex + unicode.size());
			}

			break;
	}

}

size_t text_input_line::deleteSelection(){
	ASSERT(this->cursorIndex != this->selectionStartIndex)

	size_t start, end;
	if(this->cursorIndex < this->selectionStartIndex){
		start = this->cursorIndex;
		end = this->selectionStartIndex;
	}else{
		start = this->selectionStartIndex;
		end = this->cursorIndex;
	}

	auto t = this->get_text();
	this->clear();
	t.erase(t.begin() + start, t.begin() + end);
	this->set_text(std::move(t));

	return start;
}
<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <vector>
#include <map>

#include "rapidjson/writer.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/error/en.h"
#include "rapidjson/stringbuffer.h"

#include "acmacs-base/read-file.hh"

// ----------------------------------------------------------------------

template <typename RW> class JsonWriterT : public RW
{
 public:
    inline JsonWriterT(std::string aKeyword) : RW(mBuffer), mKeyword(aKeyword) {}
    inline operator std::string() const { return mBuffer.GetString(); }
    inline std::string keyword() const { return mKeyword; }

 private:
    rapidjson::StringBuffer mBuffer;
    std::string mKeyword;
};

// template <> inline JsonWriterT<rapidjson::PrettyWriter<rapidjson::StringBuffer>>::JsonWriterT(std::string aKeyword)
//     : rapidjson::PrettyWriter<rapidjson::StringBuffer>(mBuffer), mKeyword(aKeyword)
// {
//     SetIndent(' ', 1);
// }

typedef JsonWriterT<rapidjson::Writer<rapidjson::StringBuffer>> JsonWriter;
typedef JsonWriterT<rapidjson::PrettyWriter<rapidjson::StringBuffer>> JsonPrettyWriter;

// ----------------------------------------------------------------------

enum _StartArray { StartArray };
enum _EndArray { EndArray };
enum _StartObject { StartObject };
enum _EndObject { EndObject };

template <typename RW> inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, _StartArray) { writer.StartArray(); return writer; }
template <typename RW> inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, _EndArray) { writer.EndArray(); return writer; }
template <typename RW> inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, _StartObject) { writer.StartObject(); return writer; }
template <typename RW> inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, _EndObject) { writer.EndObject(); return writer; }

template <typename RW> inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, const char* s) { writer.String(s, static_cast<unsigned>(strlen(s))); return writer; }
template <typename RW> inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, std::string s) { writer.String(s.c_str(), static_cast<unsigned>(s.size())); return writer; }
template <typename RW> inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, int value) { writer.Int(value); return writer; }
template <typename RW> inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, size_t value) { writer.Uint64(value); return writer; }
template <typename RW> inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, bool value) { writer.Bool(value); return writer; }
template <typename RW> inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, double value) { writer.Double(value); return writer; }

class JsonObjectKey
{
 public:
    inline JsonObjectKey(const char* v) : value(v) {}
    inline JsonObjectKey(std::string v) : value(v.c_str()) {}
    inline operator const char*() const { return value; }

 private:
    const char* value;
};

template <typename RW> inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, JsonObjectKey value) { writer.Key(value); return writer; }

// ----------------------------------------------------------------------

template <typename RW, typename T> inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, const std::vector<T>& list)
{
    writer << StartArray;
    for (const auto& e: list)
        writer << e;
    return writer << EndArray;
}

// ----------------------------------------------------------------------

template <typename RW> inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, const std::vector<std::vector<std::string>>& list_list_strings)
{
    writer << StartArray;
    for (const auto& e: list_list_strings)
        writer << e;
    return writer << EndArray;
}

// ----------------------------------------------------------------------

template <typename RW> inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, const std::map<std::string, std::vector<std::string>>& map_list_strings)
{
    writer << StartObject;
    for (const auto& e: map_list_strings)
        writer << JsonObjectKey(e.first) << e.second;
    return writer << EndObject;
}

// ----------------------------------------------------------------------

namespace json_writer { namespace _internal
{
      // void_t is a C++17 feature
    template<class ...> using void_t = void; // http://stackoverflow.com/questions/26513095/void-t-can-implement-concepts
    template <typename T, typename = void> struct castable_to_char : public std::false_type {};
    template <typename T> struct castable_to_char<T, void_t<decltype(static_cast<char>(std::declval<T>()))>> : public std::true_type {};
}}

template <typename RW, typename Key, typename std::enable_if<json_writer::_internal::castable_to_char<Key>{}>::type* = nullptr>
                     inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, Key key)
{
    const char k = static_cast<char>(key);
    writer.Key(&k, 1, false);
    return writer;
}

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------

template <typename Key, typename Value> class _if_not_empty
{
 public:
    inline _if_not_empty(Key&& key, Value&& value) : mKey(key), mValue(value) {}

    template <typename RW> friend inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, const _if_not_empty<Key, Value>& data)
        {
            if (!data.mValue.empty())
                writer << data.mKey << data.mValue;
            return writer;
        }

 private:
    Key mKey;
    Value mValue;
};

template <typename Key, typename Value> inline auto if_not_empty(Key&& key, Value&& value) { return _if_not_empty<Key, Value>(std::forward<Key>(key), std::forward<Value>(value)); }
template <typename Value> inline auto if_not_empty(const char* key, Value&& value) { return _if_not_empty<JsonObjectKey, Value>(JsonObjectKey(key), std::forward<Value>(value)); }

// ----------------------------------------------------------------------

template <typename Key, typename Value> class _if_non_negative
{
 public:
    inline _if_non_negative(Key&& key, Value&& value) : mKey(key), mValue(value) {}

    template <typename RW> friend inline JsonWriterT<RW>& operator <<(JsonWriterT<RW>& writer, const _if_non_negative<Key, Value>& data)
        {
            if (data.mValue >= 0.0)
                writer << data.mKey << data.mValue;
            return writer;
        }

 private:
    Key mKey;
    Value mValue;
};

template <typename Key, typename Value> inline auto if_non_negative(Key&& key, Value&& value) { return _if_non_negative<Key, Value>(std::forward<Key>(key), std::forward<Value>(value)); }
template <typename Value> inline auto if_non_negative(const char* key, Value&& value) { return _if_non_negative<JsonObjectKey, Value>(JsonObjectKey(key), std::forward<Value>(value)); }

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------

template <typename V> inline std::string pretty_json(const V& value, std::string keyword, size_t indent, bool insert_emacs_indent_hint)
{
    JsonPrettyWriter writer(keyword);
    writer.SetIndent(' ', static_cast<unsigned int>(indent));
    writer << value;
    std::string result = writer;
    if (insert_emacs_indent_hint && result[0] == '{') {
        const std::string ind(indent - 1, ' ');
        result.insert(1, ind + "\"_\": \"-*- js-indent-level: " + std::to_string(indent) + " -*-\",");
    }
    return result;
}

template <typename V> inline std::string compact_json(const V& value, std::string keyword)
{
    JsonWriter writer(keyword);
    return writer << value;
}

template <typename V> inline std::string json(const V& value, std::string keyword, size_t indent, bool insert_emacs_indent_hint = true)
{
    if (indent)
        return pretty_json(value, keyword, indent, insert_emacs_indent_hint);
    else
        return compact_json(value, keyword);
}

// ----------------------------------------------------------------------

template <typename V> inline void export_to_json(const V& value, std::string keyword, std::string filename, size_t indent, bool insert_emacs_indent_hint = true, bool force_compression = false)
{
    acmacs_base::write_file(filename, json(value, keyword, indent, insert_emacs_indent_hint), force_compression);
}

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>making json_writer namespace<commit_after>#pragma once

#include <string>
#include <vector>
#include <map>

#include "rapidjson/writer.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/error/en.h"
#include "rapidjson/stringbuffer.h"

#include "acmacs-base/read-file.hh"

// ----------------------------------------------------------------------
// Forward declarations
// ----------------------------------------------------------------------

namespace json_writer
{
    template <typename RW> class writer;
    class key;
}

template <typename RW, typename T> json_writer::writer<RW>& operator <<(json_writer::writer<RW>&, const std::vector<T>&);
template <typename RW> json_writer::writer<RW>& operator <<(json_writer::writer<RW>&, const char*);
template <typename RW> json_writer::writer<RW>& operator <<(json_writer::writer<RW>&, std::string);
template <typename RW> json_writer::writer<RW>& operator <<(json_writer::writer<RW>&, double);
template <typename RW> json_writer::writer<RW>& operator <<(json_writer::writer<RW>&, int);
template <typename RW> json_writer::writer<RW>& operator <<(json_writer::writer<RW>&, size_t);
template <typename RW> json_writer::writer<RW>& operator <<(json_writer::writer<RW>&, bool);
template <typename RW> json_writer::writer<RW>& operator <<(json_writer::writer<RW>&, const std::map<std::string, std::vector<std::string>>&);
template <typename RW> json_writer::writer<RW>& operator <<(json_writer::writer<RW>&, json_writer::key);

// ======================================================================

namespace json_writer
{
    template <typename RW> class writer : public RW // JsonWriterT
    {
     public:
        inline writer(std::string aKeyword) : RW(mBuffer), mKeyword(aKeyword) {}
        inline operator std::string() const { return mBuffer.GetString(); }
        inline std::string keyword() const { return mKeyword; }

     private:
        rapidjson::StringBuffer mBuffer;
        std::string mKeyword;
    };

      // template <> inline writer<rapidjson::PrettyWriter<rapidjson::StringBuffer>>::writer(std::string aKeyword)
      //     : rapidjson::PrettyWriter<rapidjson::StringBuffer>(mBuffer), mKeyword(aKeyword)
      // {
      //     SetIndent(' ', 1);
      // }

      // ----------------------------------------------------------------------

    enum _StartArray { start_array };
    enum _EndArray { end_array };
    enum _StartObject { start_object };
    enum _EndObject { end_object };

    class key
    {
     public:
        inline key(const char* v) : value(v) {}
        inline key(std::string v) : value(v) {}
        inline key(char v) : value(1, v) {}
        inline operator const char*() const { return value.c_str(); }

     private:
        std::string value;
    };

// ----------------------------------------------------------------------

// ----------------------------------------------------------------------

    namespace _internal
    {
          // void_t is a C++17 feature
        template<class ...> using void_t = void; // http://stackoverflow.com/questions/26513095/void-t-can-implement-concepts
        template <typename T, typename = void> struct castable_to_char : public std::false_type {};
        template <typename T> struct castable_to_char<T, void_t<decltype(static_cast<char>(std::declval<T>()))>> : public std::true_type {};
    }

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------

    template <typename Key, typename Value> class _if_not_empty
    {
     public:
        inline _if_not_empty(Key&& aKey, Value&& aValue) : mKey(aKey), mValue(aValue) {}

        template <typename RW> friend inline writer<RW>& operator <<(writer<RW>& aWriter, const _if_not_empty<Key, Value>& data)
            {
                if (!data.mValue.empty())
                    aWriter << data.mKey << data.mValue;
                return aWriter;
            }

     private:
        Key mKey;
        Value mValue;
    };

    template <typename Key, typename Value> inline auto if_not_empty(Key&& aKey, Value&& aValue) { return _if_not_empty<Key, Value>(std::forward<Key>(aKey), std::forward<Value>(aValue)); }
    template <typename Value> inline auto if_not_empty(const char* aKey, Value&& aValue) { return _if_not_empty<key, Value>(key(aKey), std::forward<Value>(aValue)); }

// ----------------------------------------------------------------------

    template <typename Key, typename Value> class _if_non_negative
    {
     public:
        inline _if_non_negative(Key&& aKey, Value&& aValue) : mKey(aKey), mValue(aValue) {}

        template <typename RW> friend inline writer<RW>& operator <<(writer<RW>& aWriter, const _if_non_negative<Key, Value>& data)
            {
                if (data.mValue >= 0.0)
                    aWriter << data.mKey << data.mValue;
                return aWriter;
            }

     private:
        Key mKey;
        Value mValue;
    };

    template <typename Key, typename Value> inline auto if_non_negative(Key&& aKey, Value&& aValue) { return _if_non_negative<Key, Value>(std::forward<Key>(aKey), std::forward<Value>(aValue)); }
    template <typename Value> inline auto if_non_negative(const char* aKey, Value&& aValue) { return _if_non_negative<key, Value>(key(aKey), std::forward<Value>(aValue)); }

} // namespace json_writer

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------

template <typename RW> inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, json_writer::_StartArray) { aWriter.StartArray(); return aWriter; }
template <typename RW> inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, json_writer::_EndArray) { aWriter.EndArray(); return aWriter; }
template <typename RW> inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, json_writer::_StartObject) { aWriter.StartObject(); return aWriter; }
template <typename RW> inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, json_writer::_EndObject) { aWriter.EndObject(); return aWriter; }

template <typename RW> inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, const char* s) { aWriter.String(s, static_cast<unsigned>(strlen(s))); return aWriter; }
template <typename RW> inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, std::string s) { aWriter.String(s.c_str(), static_cast<unsigned>(s.size())); return aWriter; }
template <typename RW> inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, int value) { aWriter.Int(value); return aWriter; }
template <typename RW> inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, size_t value) { aWriter.Uint64(value); return aWriter; }
template <typename RW> inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, bool value) { aWriter.Bool(value); return aWriter; }
template <typename RW> inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, double value) { aWriter.Double(value); return aWriter; }

template <typename RW> inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, json_writer::key value) { aWriter.Key(value); return aWriter; }

template <typename RW, typename T> inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, const std::vector<T>& aList)
{
    aWriter << json_writer::start_array;
    for (const auto& e: aList)
        aWriter << e;
    return aWriter << json_writer::end_array;
}

template <typename RW> inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, const std::vector<std::vector<std::string>>& list_list_strings)
{
    aWriter << json_writer::start_array;
    for (const auto& e: list_list_strings)
        aWriter << e;
    return aWriter << json_writer::end_array;
}

template <typename RW> inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, const std::map<std::string, std::vector<std::string>>& map_list_strings)
{
    aWriter << json_writer::start_object;
    for (const auto& e: map_list_strings)
        aWriter << json_writer::key(e.first) << e.second;
    return aWriter << json_writer::end_object;
}

template <typename RW, typename Key, typename std::enable_if<json_writer::_internal::castable_to_char<Key>{}>::type* = nullptr>
                      inline json_writer::writer<RW>& operator <<(json_writer::writer<RW>& aWriter, Key aKey)
{
    const char k = static_cast<char>(aKey);
    aWriter.Key(&k, 1, false);
    return aWriter;
}

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------

namespace json_writer
{
    template <typename V> inline std::string pretty_json(const V& value, std::string keyword, size_t indent, bool insert_emacs_indent_hint)
    {
        writer<rapidjson::PrettyWriter<rapidjson::StringBuffer>> aWriter(keyword);
        aWriter.SetIndent(' ', static_cast<unsigned int>(indent));
        aWriter << value;
        std::string result = aWriter;
        if (insert_emacs_indent_hint && result[0] == '{') {
            const std::string ind(indent - 1, ' ');
            result.insert(1, ind + "\"_\": \"-*- js-indent-level: " + std::to_string(indent) + " -*-\",");
        }
        return result;
    }

    template <typename V> inline std::string compact_json(const V& aValue, std::string keyword)
    {
        writer<rapidjson::Writer<rapidjson::StringBuffer>> aWriter(keyword);
        return aWriter << aValue;
    }

    template <typename V> inline std::string json(const V& value, std::string keyword, size_t indent, bool insert_emacs_indent_hint = true)
    {
        if (indent)
            return pretty_json(value, keyword, indent, insert_emacs_indent_hint);
        else
            return compact_json(value, keyword);
    }

      // ----------------------------------------------------------------------

    template <typename V> inline void export_to_json(const V& value, std::string keyword, std::string filename, size_t indent, bool insert_emacs_indent_hint = true, bool force_compression = false)
    {
        acmacs_base::write_file(filename, json(value, keyword, indent, insert_emacs_indent_hint), force_compression);
    }

} // namespace json_writer

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>


<commit_before>#include <iostream>
#include <utility>

#include "acmacs-base/rjson.hh"
#include "acmacs-base/stream.hh"

// ----------------------------------------------------------------------

#pragma GCC diagnostic push
#ifdef __clang__
#pragma GCC diagnostic ignored "-Wexit-time-destructors"
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#endif

static const std::pair<std::vector<const char*>, std::variant<const char*, rjson::v2::parse_error>> sSource[] = {
    {{R"(
          "Altogether elsewhere, \"vast\""  )"}, R"("Altogether elsewhere, \"vast\"")"},
    {{R"(  2017)"}, R"(2017)"},
    {{R"(  -2017)"}, R"(-2017)"},
    {{R"(  +2001.21)"}, R"(+2001.21)"},
    {{R"(  -2002.22E2)"}, R"(-2002.22E2)"},
    {{R"(  -2003.3E+3)"}, R"(-2003.3E+3)"},
    {{R"(  -2004.4E-4)"}, R"(-2004.4E-4)"},
    {{R"(  .2005)"}, R"(.2005)"},
    {{R"(  -.2006)"}, R"(-.2006)"},
    {{R"( true)"}, R"(true)"},
    {{R"( false)"}, R"(false)"},
    {{R"(null)"}, R"(null)"},
    {{R"( { "a" : "b"}  )"}, R"({"a":"b"})"},
    {{R"({x"a" : "b"}  )"}, rjson::v2::parse_error(1, 2, "unexpected symbol: 'x' (0x78)")},
    {{R"({"a","b"})"}, rjson::v2::parse_error(1, 5, "unexpected comma, colon is expected there")},
    {{R"({"a":,"b"})"}, rjson::v2::parse_error(1, 6, "unexpected symbol: ',' (0x2C)")},
    {{R"({,})"}, rjson::v2::parse_error(1, 2, "unexpected comma right after the beginning of an object")},
    {{R"( { "a" :   1234   }  )"}, R"({"a":1234})"},
    {{R"( { "a" : -1234}  )"}, R"({"a":-1234})"},
    {{R"( { "a" : 12.34}  )"}, R"({"a":12.34})"},
    {{R"( { "a" : true}  )"}, R"({"a":true})"},
    {{R"( { "a" : false}  )"}, R"({"a":false})"},
    {{R"( { "a" : null}  )"}, R"({"a":null})"},
    {{R"( { "a" : null,}  )"}, rjson::v2::parse_error(1, 15, "unexpected } -- did you forget to remove last comma?")},
    {{R"( { "a" : null "b": false}  )"}, rjson::v2::parse_error(1, 15, "unexpected \" -- did you forget comma?")},
    {{R"( { "a" : null  ,  ,  "b": false}  )"}, rjson::v2::parse_error(1, 19, "unexpected comma -- two successive commas?")},
    {{R"( { "a" : {"b" : 1  , "c"  : "c"  , "sub":{"xsub": false},"d": null  }}  )"}, R"({"a":{"b":1,"c":"c","d":null,"sub":{"xsub":false}}})"},
    {{R"([])"}, R"([])"},
    {{R"([  ,  ])"}, rjson::v2::parse_error(1, 4, "unexpected comma right after the beginning of an array")},
    {{R"(["a"])"}, R"(["a"])"},
    {{R"(["a",1])"}, R"(["a",1])"},
    {{R"([true,false,null,"aaa"])"}, R"([true,false,null,"aaa"])"},
    {{R"( [ 1   ,   2   ,  true  , { "a" : null}  ]  )"}, R"([1,2,true,{"a":null}])"},
    {{R"( {"array":[ 1   ,   2   ,  true  , { "a" : null}  ], "another":[]}  )"}, R"({"another":[],"array":[1,2,true,{"a":null}]})"},

      // merge json objects
    {{R"({"a": "a", "b": {"ba": "ba"}})", R"({"b": {"ba": "BAAA"}, "c": "c"})"}, R"({"a":"a","b":{"ba":"BAAA"},"c":"c"})"},
    {{R"({"a": 1, "b": {"ba": 2}})", R"({"b": {"ba": 3.3}, "c": true})"}, R"({"a":1,"b":{"ba":3.3},"c":true})"},
    {{R"({"a": 1, "b": ["ba", "bb"]})", R"({"b": ["BA", 3.3], "c": true})"}, R"({"a":1,"b":["BA",3.3],"c":true})"},
};

static const char* cText = "Zugriff auf alle";
static const std::pair<rjson::v2::value, const char*> sSourceRJ[] = {
    {{}, "null"},
    {rjson::v2::null{}, "null"},
    {{"Bundesstadt"}, R"("Bundesstadt")"},
    {{std::string("Bundesstadt")}, R"("Bundesstadt")"},
    {{std::string_view(cText)}, R"("Zugriff auf alle")"},
    {{2012}, R"(2012)"},
    {{+2012}, R"(2012)"},
    {{-2012}, R"(-2012)"},
    {{2012.25}, R"(2012.25)"},
    {{+2012.5}, R"(2012.5)"},
    {{-2012.125}, R"(-2012.125)"},
    {{2012.33e2}, R"(201233)"},
    {rjson::v2::array{1, 2.5, "three"}, R"([1,2.5,"three"])"},
    {rjson::v2::object{{"first", 1}, {"second", 2.5}, {"third", "three"}}, R"({"first":1,"second":2.5,"third":"three"})"},
    {rjson::v2::object{{"first", rjson::v2::array{1, 2.5, "three"}}, {"second", rjson::v2::object{{"first", 1}, {"second", 2.5}, {"third", "three"}}}, {"third", "three"}},
     R"({"first":[1,2.5,"three"],"second":{"first":1,"second":2.5,"third":"three"},"third":"three"})"},
};

#pragma GCC diagnostic pop

// ----------------------------------------------------------------------

int main()
{
    int exit_code = 0;

    for (auto [to_parse, expected]: sSource) {
        const auto& to_parse_ref = to_parse; // to capture by lambda below, cannot capture to_parse (bug in llvm 4.0.1?)
        try {
            // std::cerr << "DEBUG: " << to_parse << '\n';
            auto val = rjson::v2::parse_string(to_parse[0]);
            for (auto& to_parse_e: to_parse) {
                if (&to_parse_e != &to_parse.front())
                    val.update(rjson::v2::parse_string(to_parse_e));
            }

            const auto result = rjson::v2::to_string(val);
            // std::cerr << "DEBUG: " << to_parse << " --> " << result << '\n';
            std::visit([&](auto&& aExpected) {
                using T = std::decay_t<decltype(aExpected)>;
                if constexpr (std::is_same_v<T, const char*>) {
                    if (result != aExpected) {
                        std::cerr << "ERROR: parsing %" << to_parse_ref << "%\n  --> %" << result << "%\n  expected: %" << aExpected << "%\n\n";
                        exit_code = 1;
                    }
                }
                else {
                    std::cerr << "ERROR: parsing %" << to_parse_ref << "%\n  --> %" << result << "%\n  expected: %" << aExpected.what() << "%\n\n";
                    exit_code = 1;
                }
            }, expected);
        }
        catch (rjson::v2::parse_error& err) {
            std::visit([&](auto&& aExpected) {
                using T = std::decay_t<decltype(aExpected)>;
                if constexpr (std::is_same_v<T, const char*>) {
                    std::cerr << "ERROR: parsing %" << to_parse_ref << "%\n  --> " << err.what() << "\n  expected: %" << aExpected << "%\n\n";
                    exit_code = 2;
                }
                else {
                    if (std::string{err.what()} != aExpected.what()) {
                        std::cerr << "ERROR: parsing %" << to_parse_ref << "%\n  --> %" << err.what() << "%\n  expected: %" << aExpected.what() << "%\n\n";
                        exit_code = 2;
                    }
                }
            }, expected);
        }
    }

    for (const auto& [val, expected]: sSourceRJ) {
        const auto result = rjson::v2::to_string(val);
        // std::cerr << "DEBUG: " << result << " == " << expected << '\n';
        if (result != expected) {
            std::cerr << "ERROR: after initialization %" << result << "%  expected: %" << expected << "%\n";
            exit_code = 1;
        }
    }

    rjson::v2::value v1;
    v1 = rjson::v2::value{};
    assert(v1.is_null());
    v1 = true;
    assert(v1.is_bool());
    v1 = 4;
    assert(v1.is_number());
    v1 = 4U;
    assert(v1.is_number());
    v1 = 4UL;
    assert(v1.is_number());
    v1 = 4.4;
    assert(v1.is_number());
    v1 = 4.4F;
    assert(v1.is_number());
    v1 = "const char*";
    assert(v1.is_string());
    v1 = std::string{"string"};
    assert(v1.is_string());
    v1 = std::string{};
    assert(v1.is_string());
    const char* const_char_ptr = "string";
    std::string_view sv{const_char_ptr};
    v1 = sv;
    assert(v1.is_string());
    v1 = 'C';
    assert(v1.is_string());
    v1 = rjson::v2::object{};
    assert(v1.is_object());
    v1 = rjson::v2::array{};
    assert(v1.is_array());
    v1 = rjson::v2::number{51L};
    assert(v1.is_number());

    return exit_code;
}

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>rjson::v2 development<commit_after>#include <iostream>
#include <utility>

#include "acmacs-base/rjson.hh"
#include "acmacs-base/stream.hh"

// ----------------------------------------------------------------------

#pragma GCC diagnostic push
#ifdef __clang__
#pragma GCC diagnostic ignored "-Wexit-time-destructors"
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#endif

static const std::pair<std::vector<const char*>, std::variant<const char*, rjson::v2::parse_error>> sSource[] = {
    {{R"(
          "Altogether elsewhere, \"vast\""  )"}, R"("Altogether elsewhere, \"vast\"")"},
    {{R"(  2017)"}, R"(2017)"},
    {{R"(  -2017)"}, R"(-2017)"},
    {{R"(  +2001.21)"}, R"(+2001.21)"},
    {{R"(  -2002.22E2)"}, R"(-2002.22E2)"},
    {{R"(  -2003.3E+3)"}, R"(-2003.3E+3)"},
    {{R"(  -2004.4E-4)"}, R"(-2004.4E-4)"},
    {{R"(  .2005)"}, R"(.2005)"},
    {{R"(  -.2006)"}, R"(-.2006)"},
    {{R"( true)"}, R"(true)"},
    {{R"( false)"}, R"(false)"},
    {{R"(null)"}, R"(null)"},
    {{R"( { "a" : "b"}  )"}, R"({"a":"b"})"},
    {{R"({x"a" : "b"}  )"}, rjson::v2::parse_error(1, 2, "unexpected symbol: 'x' (0x78)")},
    {{R"({"a","b"})"}, rjson::v2::parse_error(1, 5, "unexpected comma, colon is expected there")},
    {{R"({"a":,"b"})"}, rjson::v2::parse_error(1, 6, "unexpected symbol: ',' (0x2C)")},
    {{R"({,})"}, rjson::v2::parse_error(1, 2, "unexpected comma right after the beginning of an object")},
    {{R"( { "a" :   1234   }  )"}, R"({"a":1234})"},
    {{R"( { "a" : -1234}  )"}, R"({"a":-1234})"},
    {{R"( { "a" : 12.34}  )"}, R"({"a":12.34})"},
    {{R"( { "a" : true}  )"}, R"({"a":true})"},
    {{R"( { "a" : false}  )"}, R"({"a":false})"},
    {{R"( { "a" : null}  )"}, R"({"a":null})"},
    {{R"( { "a" : null,}  )"}, rjson::v2::parse_error(1, 15, "unexpected } -- did you forget to remove last comma?")},
    {{R"( { "a" : null "b": false}  )"}, rjson::v2::parse_error(1, 15, "unexpected \" -- did you forget comma?")},
    {{R"( { "a" : null  ,  ,  "b": false}  )"}, rjson::v2::parse_error(1, 19, "unexpected comma -- two successive commas?")},
    {{R"( { "a" : {"b" : 1  , "c"  : "c"  , "sub":{"xsub": false},"d": null  }}  )"}, R"({"a":{"b":1,"c":"c","d":null,"sub":{"xsub":false}}})"},
    {{R"([])"}, R"([])"},
    {{R"([  ,  ])"}, rjson::v2::parse_error(1, 4, "unexpected comma right after the beginning of an array")},
    {{R"(["a"])"}, R"(["a"])"},
    {{R"(["a",1])"}, R"(["a",1])"},
    {{R"([true,false,null,"aaa"])"}, R"([true,false,null,"aaa"])"},
    {{R"( [ 1   ,   2   ,  true  , { "a" : null}  ]  )"}, R"([1,2,true,{"a":null}])"},
    {{R"( {"array":[ 1   ,   2   ,  true  , { "a" : null}  ], "another":[]}  )"}, R"({"another":[],"array":[1,2,true,{"a":null}]})"},

      // merge json objects
    {{R"({"a": "a", "b": {"ba": "ba"}})", R"({"b": {"ba": "BAAA"}, "c": "c"})"}, R"({"a":"a","b":{"ba":"BAAA"},"c":"c"})"},
    {{R"({"a": 1, "b": {"ba": 2}})", R"({"b": {"ba": 3.3}, "c": true})"}, R"({"a":1,"b":{"ba":3.3},"c":true})"},
    {{R"({"a": 1, "b": ["ba", "bb"]})", R"({"b": ["BA", 3.3], "c": true})"}, R"({"a":1,"b":["BA",3.3],"c":true})"},
};

static const char* cText = "Zugriff auf alle";
static const std::pair<rjson::v2::value, const char*> sSourceRJ[] = {
    {{}, "null"},
    {rjson::v2::null{}, "null"},
    {{"Bundesstadt"}, R"("Bundesstadt")"},
    {{std::string("Bundesstadt")}, R"("Bundesstadt")"},
    {{std::string_view(cText)}, R"("Zugriff auf alle")"},
    {{2012}, R"(2012)"},
    {{+2012}, R"(2012)"},
    {{-2012}, R"(-2012)"},
    {{2012.25}, R"(2012.25)"},
    {{+2012.5}, R"(2012.5)"},
    {{-2012.125}, R"(-2012.125)"},
    {{2012.33e2}, R"(201233)"},
    {rjson::v2::array{1, 2.5, "three"}, R"([1,2.5,"three"])"},
    {rjson::v2::object{{"first", 1}, {"second", 2.5}, {"third", "three"}}, R"({"first":1,"second":2.5,"third":"three"})"},
    {rjson::v2::object{{"first", rjson::v2::array{1, 2.5, "three"}}, {"second", rjson::v2::object{{"first", 1}, {"second", 2.5}, {"third", "three"}}}, {"third", "three"}},
     R"({"first":[1,2.5,"three"],"second":{"first":1,"second":2.5,"third":"three"},"third":"three"})"},
};

#pragma GCC diagnostic pop

// ----------------------------------------------------------------------

int main()
{
    int exit_code = 0;

    for (auto [to_parse, expected]: sSource) {
        const auto& to_parse_ref = to_parse; // to capture by lambda below, cannot capture to_parse (bug in llvm 4.0.1?)
        try {
            // std::cerr << "DEBUG: " << to_parse << '\n';
            auto val = rjson::v2::parse_string(to_parse[0]);
            for (auto& to_parse_e: to_parse) {
                if (&to_parse_e != &to_parse.front())
                    val.update(rjson::v2::parse_string(to_parse_e));
            }

            const auto result = rjson::v2::to_string(val);
            // std::cerr << "DEBUG: " << to_parse << " --> " << result << '\n';
            std::visit([&](auto&& aExpected) {
                using T = std::decay_t<decltype(aExpected)>;
                if constexpr (std::is_same_v<T, const char*>) {
                    if (result != aExpected) {
                        std::cerr << "ERROR: parsing %" << to_parse_ref << "%\n  --> %" << result << "%\n  expected: %" << aExpected << "%\n\n";
                        exit_code = 1;
                    }
                }
                else {
                    std::cerr << "ERROR: parsing %" << to_parse_ref << "%\n  --> %" << result << "%\n  expected: %" << aExpected.what() << "%\n\n";
                    exit_code = 1;
                }
            }, expected);
        }
        catch (rjson::v2::parse_error& err) {
            std::visit([&](auto&& aExpected) {
                using T = std::decay_t<decltype(aExpected)>;
                if constexpr (std::is_same_v<T, const char*>) {
                    std::cerr << "ERROR: parsing %" << to_parse_ref << "%\n  --> " << err.what() << "\n  expected: %" << aExpected << "%\n\n";
                    exit_code = 2;
                }
                else {
                    if (std::string{err.what()} != aExpected.what()) {
                        std::cerr << "ERROR: parsing %" << to_parse_ref << "%\n  --> %" << err.what() << "%\n  expected: %" << aExpected.what() << "%\n\n";
                        exit_code = 2;
                    }
                }
            }, expected);
        }
    }

    for (const auto& [val, expected]: sSourceRJ) {
        const auto result = rjson::v2::to_string(val);
        // std::cerr << "DEBUG: " << result << " == " << expected << '\n';
        if (result != expected) {
            std::cerr << "ERROR: after initialization %" << result << "%  expected: %" << expected << "%\n";
            exit_code = 1;
        }
    }

    rjson::v2::value v1;
    v1 = rjson::v2::value{};
    assert(v1.is_null());
    v1 = true;
    assert(v1.is_bool());
    v1 = 4;
    assert(v1.is_number());
    v1 = 4U;
    assert(v1.is_number());
    v1 = 4UL;
    assert(v1.is_number());
    v1 = 4.4;
    assert(v1.is_number());
    v1 = 4.4F;
    assert(v1.is_number());
    v1 = "const char*";
    assert(v1.is_string());
    v1 = std::string{"string"};
    assert(v1.is_string());
    v1 = std::string{};
    assert(v1.is_string());
    const char* const_char_ptr = "string";
    std::string_view sv{const_char_ptr};
    v1 = sv;
    assert(v1.is_string());
    v1 = 'C';
    assert(v1.is_string());
    v1 = rjson::v2::object{};
    assert(v1.is_object());
    v1 = rjson::v2::array{};
    assert(v1.is_array());
    v1 = rjson::v2::number{51L};
    assert(v1.is_number());

    rjson::v2::value v2{rjson::v2::object{{"first", 1}, {"second", 2}}};
    assert(v2.is_object());
    assert(!v2.empty());
    v2["third"] = 3;
    assert(v2.get("third").is_number());
    v2["third"] = 33;
    assert(v2.get("third").is_number());
    v2["first"] = rjson::v2::object{};
    assert(v2.get("first").is_object());
    v2["first"]["first"] = 11;
    assert(v2.get("first", "first").is_number());

    rjson::value v3{rjson::object{{"first", rjson::object{}}, {"second", rjson::object{}}}};
    v3["third"] = 3;
    assert(v3.get("third").is_number());
    v3["third"] = 33;
    assert(v3.get("third").is_number());
    v3["first"] = 1111;
    v3["first"] = rjson::v2::object{};
    assert(v3.get("first").is_object());
    v3.set("first", "aaa", "bbb") = 88;
    assert(v3.get("first", "aaa", "bbb").is_number());
    v3.set("first") = 88;
    assert(v3.get("first").is_number());

    return exit_code;
}

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief cap constraint
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "CapConstraint.h"
#include "Utils/transactions.h"
#include "VocBase/document-collection.h"
#include "VocBase/transaction.h"

using namespace triagens::arango;

// -----------------------------------------------------------------------------
// --SECTION--                                               class CapConstraint
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief minimum size
////////////////////////////////////////////////////////////////////////////////

int64_t const CapConstraint::MinSize = 16384;

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

CapConstraint::CapConstraint (TRI_idx_iid_t iid,
                              TRI_document_collection_t* collection,
                              size_t count,
                              int64_t size)
  : Index(iid, collection, std::vector<std::string>()),
    _count(count),
    _size(static_cast<int64_t>(size)) {

  initialize();
}

CapConstraint::~CapConstraint () {
}

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

size_t CapConstraint::memory () const {
  return 0;
}

triagens::basics::Json CapConstraint::toJson (TRI_memory_zone_t* zone) const {
  auto json = Index::toJson(zone);

  json("size",     triagens::basics::Json(zone, static_cast<double>(_count)))
      ("byteSize", triagens::basics::Json(zone, static_cast<double>(_size)));

  return json;
}

int CapConstraint::insert (TRI_doc_mptr_t const* doc,
                           bool) {
  if (_size > 0) {
    // there is a size restriction
    auto marker = static_cast<TRI_df_marker_t const*>(doc->getDataPtr());  // ONLY IN INDEX, PROTECTED by RUNTIME

    // check if the document would be too big
    if (static_cast<int64_t>(marker->_size) > _size) {
      return TRI_ERROR_ARANGO_DOCUMENT_TOO_LARGE;
    }
  }

  return TRI_ERROR_NO_ERROR;
}

int CapConstraint::remove (TRI_doc_mptr_t const*,
                           bool) {
  return TRI_ERROR_NO_ERROR;
}

int CapConstraint::postInsert (TRI_transaction_collection_t* trxCollection,
                               TRI_doc_mptr_t const*) {
  TRI_ASSERT(_count > 0 || _size > 0);

  return apply(trxCollection->_collection->_collection, trxCollection);
}

// -----------------------------------------------------------------------------
// --SECTION--                                                   private methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief initialize the cap constraint
////////////////////////////////////////////////////////////////////////////////

int CapConstraint::initialize () {
  TRI_ASSERT(_count > 0 || _size > 0);

  TRI_headers_t* headers = _collection->_headersPtr;  // ONLY IN INDEX (CAP)
  int64_t currentCount   = static_cast<int64_t>(headers->count());
  int64_t currentSize    = headers->size();

  if ((_count > 0 && currentCount <= _count) &&
      (_size > 0 && currentSize <= _size)) {
    // nothing to do
    return TRI_ERROR_NO_ERROR;
  }
  else {
    TRI_vocbase_t* vocbase = _collection->_vocbase;
    TRI_voc_cid_t cid = _collection->_info._cid;

    triagens::arango::SingleCollectionWriteTransaction<UINT64_MAX> trx(new triagens::arango::StandaloneTransactionContext(), vocbase, cid);
    trx.addHint(TRI_TRANSACTION_HINT_LOCK_NEVER, false);
    trx.addHint(TRI_TRANSACTION_HINT_NO_BEGIN_MARKER, false);
    trx.addHint(TRI_TRANSACTION_HINT_NO_ABORT_MARKER, false);
    trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false); // this is actually not true, but necessary to create trx id 0

    int res = trx.begin();

    if (res != TRI_ERROR_NO_ERROR) {
      return res;
    }

    TRI_transaction_collection_t* trxCollection = trx.trxCollection();
    res = apply(_collection, trxCollection);

    res = trx.finish(res);

    return res;
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief apply the cap constraint for the collection
////////////////////////////////////////////////////////////////////////////////

int CapConstraint::apply (TRI_document_collection_t* document,
                          TRI_transaction_collection_t* trxCollection) {
  TRI_headers_t* headers = document->_headersPtr;  // PROTECTED by trx in trxCollection
  int64_t currentCount   = static_cast<int64_t>(headers->count());
  int64_t currentSize    = headers->size();

  int res = TRI_ERROR_NO_ERROR;

  // delete while at least one of the constraints is still violated
  while ((_count > 0 && currentCount > _count) ||
         (_size > 0 && currentSize > _size)) {
    TRI_doc_mptr_t* oldest = headers->front();

    if (oldest != nullptr) {
      TRI_ASSERT(oldest->getDataPtr() != nullptr);  // ONLY IN INDEX, PROTECTED by RUNTIME
      size_t oldSize = ((TRI_df_marker_t*) (oldest->getDataPtr()))->_size;  // ONLY IN INDEX, PROTECTED by RUNTIME

      TRI_ASSERT(oldSize > 0);

      if (trxCollection != nullptr) {
        res = TRI_DeleteDocumentDocumentCollection(trxCollection, nullptr, oldest);

        if (res != TRI_ERROR_NO_ERROR) {
          LOG_WARNING("cannot cap collection: %s", TRI_errno_string(res));
          break;
        }
      }
      else {
        headers->unlink(oldest);
      }

      currentCount--;
      currentSize -= (int64_t) oldSize;
    }
    else {
      // we should not get here
      LOG_WARNING("logic error in %s", __FUNCTION__);
      break;
    }
  }

  return res;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<commit_msg>fix test<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief cap constraint
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "CapConstraint.h"
#include "Utils/transactions.h"
#include "VocBase/document-collection.h"
#include "VocBase/transaction.h"

using namespace triagens::arango;

// -----------------------------------------------------------------------------
// --SECTION--                                               class CapConstraint
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief minimum size
////////////////////////////////////////////////////////////////////////////////

int64_t const CapConstraint::MinSize = 16384;

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

CapConstraint::CapConstraint (TRI_idx_iid_t iid,
                              TRI_document_collection_t* collection,
                              size_t count,
                              int64_t size)
  : Index(iid, collection, std::vector<std::string>()),
    _count(count),
    _size(static_cast<int64_t>(size)) {

  initialize();
}

CapConstraint::~CapConstraint () {
}

// -----------------------------------------------------------------------------
// --SECTION--                                                    public methods
// -----------------------------------------------------------------------------

size_t CapConstraint::memory () const {
  return 0;
}

triagens::basics::Json CapConstraint::toJson (TRI_memory_zone_t* zone) const {
  auto json = Index::toJson(zone);

  json("size",     triagens::basics::Json(zone, static_cast<double>(_count)))
      ("byteSize", triagens::basics::Json(zone, static_cast<double>(_size)))
      ("unique",   triagens::basics::Json(zone, false));

  return json;
}

int CapConstraint::insert (TRI_doc_mptr_t const* doc,
                           bool) {
  if (_size > 0) {
    // there is a size restriction
    auto marker = static_cast<TRI_df_marker_t const*>(doc->getDataPtr());  // ONLY IN INDEX, PROTECTED by RUNTIME

    // check if the document would be too big
    if (static_cast<int64_t>(marker->_size) > _size) {
      return TRI_ERROR_ARANGO_DOCUMENT_TOO_LARGE;
    }
  }

  return TRI_ERROR_NO_ERROR;
}

int CapConstraint::remove (TRI_doc_mptr_t const*,
                           bool) {
  return TRI_ERROR_NO_ERROR;
}

int CapConstraint::postInsert (TRI_transaction_collection_t* trxCollection,
                               TRI_doc_mptr_t const*) {
  TRI_ASSERT(_count > 0 || _size > 0);

  return apply(trxCollection->_collection->_collection, trxCollection);
}

// -----------------------------------------------------------------------------
// --SECTION--                                                   private methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief initialize the cap constraint
////////////////////////////////////////////////////////////////////////////////

int CapConstraint::initialize () {
  TRI_ASSERT(_count > 0 || _size > 0);

  TRI_headers_t* headers = _collection->_headersPtr;  // ONLY IN INDEX (CAP)
  int64_t currentCount   = static_cast<int64_t>(headers->count());
  int64_t currentSize    = headers->size();

  if ((_count > 0 && currentCount <= _count) &&
      (_size > 0 && currentSize <= _size)) {
    // nothing to do
    return TRI_ERROR_NO_ERROR;
  }
  else {
    TRI_vocbase_t* vocbase = _collection->_vocbase;
    TRI_voc_cid_t cid = _collection->_info._cid;

    triagens::arango::SingleCollectionWriteTransaction<UINT64_MAX> trx(new triagens::arango::StandaloneTransactionContext(), vocbase, cid);
    trx.addHint(TRI_TRANSACTION_HINT_LOCK_NEVER, false);
    trx.addHint(TRI_TRANSACTION_HINT_NO_BEGIN_MARKER, false);
    trx.addHint(TRI_TRANSACTION_HINT_NO_ABORT_MARKER, false);
    trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false); // this is actually not true, but necessary to create trx id 0

    int res = trx.begin();

    if (res != TRI_ERROR_NO_ERROR) {
      return res;
    }

    TRI_transaction_collection_t* trxCollection = trx.trxCollection();
    res = apply(_collection, trxCollection);

    res = trx.finish(res);

    return res;
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief apply the cap constraint for the collection
////////////////////////////////////////////////////////////////////////////////

int CapConstraint::apply (TRI_document_collection_t* document,
                          TRI_transaction_collection_t* trxCollection) {
  TRI_headers_t* headers = document->_headersPtr;  // PROTECTED by trx in trxCollection
  int64_t currentCount   = static_cast<int64_t>(headers->count());
  int64_t currentSize    = headers->size();

  int res = TRI_ERROR_NO_ERROR;

  // delete while at least one of the constraints is still violated
  while ((_count > 0 && currentCount > _count) ||
         (_size > 0 && currentSize > _size)) {
    TRI_doc_mptr_t* oldest = headers->front();

    if (oldest != nullptr) {
      TRI_ASSERT(oldest->getDataPtr() != nullptr);  // ONLY IN INDEX, PROTECTED by RUNTIME
      size_t oldSize = ((TRI_df_marker_t*) (oldest->getDataPtr()))->_size;  // ONLY IN INDEX, PROTECTED by RUNTIME

      TRI_ASSERT(oldSize > 0);

      if (trxCollection != nullptr) {
        res = TRI_DeleteDocumentDocumentCollection(trxCollection, nullptr, oldest);

        if (res != TRI_ERROR_NO_ERROR) {
          LOG_WARNING("cannot cap collection: %s", TRI_errno_string(res));
          break;
        }
      }
      else {
        headers->unlink(oldest);
      }

      currentCount--;
      currentSize -= (int64_t) oldSize;
    }
    else {
      // we should not get here
      LOG_WARNING("logic error in %s", __FUNCTION__);
      break;
    }
  }

  return res;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <vector>
#include <msgpack.hpp>

using namespace std;
using namespace msgpack;

int main()
{
    vector<unsigned char> data;
    for (unsigned i = 0; i < 10; ++i)
        data.push_back(i * 2);
    cout << "The size of array 'data' is: "<<sizeof(data)<<endl;
    sbuffer sbuf;
    pack(sbuf, data);
    cout << "The size of packed is: " << sbuf.size() <<endl;
    unpacked msg;
    unpack(&msg, sbuf.data(), sbuf.size());

    object obj = msg.get();
    cout<<"The size of unpacked object is: "<<sizeof(obj)<<endl;
    cout << obj << endl;
}
<commit_msg>Update msgpackTest.cpp<commit_after>#include <iostream>
#include <string>
#include <vector>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <msgpack.hpp>
#include "hiredis/hiredis.h"
#include "hiredis/async.h"
#include "hiredis/adapters/libevent.h"

using namespace std;
using namespace msgpack;

int main()
{
    redisContext *c;
    void *reply;
    c = redisConnect("127.0.0.1", 6379);
    if(c!=NULL && c->err) {
        printf("Error: %s\n", c->errstr);
    }

    char str[] = "Hello World!!";
    vector<unsigned char> data;
    for (unsigned i = 0; i < 10; ++i)
        data.push_back(i * 2);
    cout << "The size of array 'data' is: "<<sizeof(str)<<endl;
    sbuffer sbuf;
    //string text = std::to_string(pack(sbuf, str));
    pack(sbuf, data);
    //pack(sbuf, str);
    cout << "The size of packed is: " << sbuf.size() <<endl;

    reply = redisCommand(c,"SET %s %s", "foo", sbuf.data());
    void *size = redisCommand(c, "DBSIZE");
    int size_of_db = *((int *)size);
    cout << "The size of key in RedisDB is: "<< size_of_db << endl;
    //void *al = redisCommand(c,"SET %s %s", to_string(size_of_db), "Aa");
    //printf("SET: %s\n", reply->str);
    freeReplyObject(reply);

    //void *bl = redisCommand(c,"GET foo");
    string getstr = "GET ";
    getstr = getstr + to_String(size_of_db);
    reply = redisCommand(c, getstr);
    //printf("GET foo: %s\n", reply->str);
    freeReplyObject(reply);
    redisFree(c);
    return 0;

    unpacked msg;
    unpack(&msg, sbuf.data(), sbuf.size());

    object obj = msg.get();
    cout<<"The size of unpacked object is: "<<sizeof(obj)<<endl;
    cout << "The object is: "<<endl;
    cout << obj << endl;

}
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS dr33 (1.23.20); FILE MERGED 2005/02/09 17:20:49 dr 1.23.20.1: #i36782# remove non-ASCII chars from sources<commit_after><|endoftext|>