<commit_before>/**
 * KeybdInput 1.0.1
 *
 * @author Roger Lima (rogerlima@outlook.com)
 * @date 31/aug/2014
 * @update 02/feb/2016
 * @desc Reads the keyboard input them according to the format specified (only works on Windows)
 * @example
	int day, month, year;
	KeybdInput< int > userin;

	userin.solicit(
		"Type a date (btw 01/01/1900 and 31/12/2009): ",
		std::regex( "([0-2]?[0-9]|3[0-1])/(0?[1-9]|1[012])/(19[0-9]{2}|200[0-9])" ),
		{ &day, &month, &year },
		false,
		false,
		false,
		'/'
	);
*/

#pragma once
#include <conio.h>
#include <iostream>
#include <regex>
#include <sstream>
#include <vector>
#include <Windows.h>

template< typename T >
class KeybdInput {
private:
	// Stores the values to be used in KeybdInput::reset()
	bool _instverify, _reset, _ispw;
	char _sep;
	size_t _inmaxsize;
	std::regex _restriction;
	std::string _rmsg;
	std::vector< T * > _references = {};

	// Stores the user input
	std::string input;

	// Receives the current X and Y cursor position from get_cursor_position()
	std::vector< size_t > cursor_position = { 0, 0 };

	// Erase the input of user
	// @param {size_t=input.size()} Erase range
	void erase_input( size_t = 0 );

	// Get the console cursor position and pass to the cursor_position
	void get_cursor_position();

	// Set the console cursor position
	// @param {short} X position of cursor
	// @param {short} Y position of cursor
	void set_cursor_position( short, short );

	// Split a string
	// @param {std::string} Target string
	// @param {char} Delimiter
	std::vector< std::string > split( std::string str, char delim );

	// Set the reference with input value
	// @param {const std::string&} Input value
	// @param {T*} Target place
	void set_reference( const std::string&, T * );

	// Clear all values of references
	// @param {T*} Target place
	void clear_references( std::vector< T * > );
public:
	// Clipboard (arrow up or down to show the last inputs)
	std::vector< std::string > clipboard;

	// Requires the user input again
	// @param [{std::string=_rmsg}] Request message
	void reset( std::string = "" );

	// Requires the keyboard input
	// @param {string} Request message
	// @param {regex} The regex
	// @param {vector< T * >} The place(s) where it will be stored the input
	// @param {bool=false} Instant verify
	// @param {bool=false} Reset possibility
	// @param {bool=false} Is password
	// @param {char=' '} Separator
	// @param {size_t=1000} Input size
	void solicit( std::string, std::regex, std::vector< T * >, bool = false, bool = false, bool = false, char = ' ', size_t = 1000 );
};

template< typename T >
void KeybdInput< T >::erase_input( size_t erase_range = 0 ) {
	// Default erase range
	if ( !erase_range )
		erase_range = input.size();

	for ( size_t i = 0; i < erase_range; i++ )
		std::cout << "\b \b";

	input = "";
};

template < typename T >
void KeybdInput< T >::set_reference( const std::string& value, T *target ) {
	std::stringstream convert;
	convert << value;
	convert >> *target;
};

void KeybdInput< std::string >::set_reference( const std::string& value, std::string *target ) {
	*target = value;
};

template < typename T >
void KeybdInput< T >::clear_references( std::vector< T * > target ) {
	for ( size_t i = 0; i < _references.size(); *target[ i++ ] = 0 );
};

void KeybdInput< std::string >::clear_references( std::vector< std::string * > target ) {
	for ( size_t i = 0; i < _references.size(); *target[ i++ ] = "" );
};

template< typename T >
void KeybdInput< T >::get_cursor_position() {
	CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
	HANDLE hStd = GetStdHandle( STD_OUTPUT_HANDLE );

	if ( !GetConsoleScreenBufferInfo( hStd, &screen_buffer_info ) )
		MessageBox( NULL, L"An error occurred getting the console cursor position.", L"KeybdInput ERROR", NULL );

	cursor_position[ 0 ] = screen_buffer_info.dwCursorPosition.X;
	cursor_position[ 1 ] = screen_buffer_info.dwCursorPosition.Y;
};

template< typename T >
void KeybdInput< T >::set_cursor_position( short x, short y ) {
	if ( !SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), { x, y } ) )
		MessageBox( NULL, L"An error occurred setting the console cursor position.", L"KeybdInput ERROR", NULL );
};

template< typename T >
std::vector< std::string > KeybdInput< T >::split( std::string str, char delim ) {
	std::vector< std::string > elems;
	std::stringstream stream( str );
	std::string item;

	for ( ; getline( stream, item, delim ); elems.push_back( item ) );

	return elems;
};

template< typename T >
void KeybdInput< T >::reset( std::string msg = "" ) {
	// Default request message
	if ( msg == "" && _rmsg != "" )
		msg = _rmsg;

	if ( !_reset ) {
		MessageBox( NULL, L"Can't possible execute KeybdInput::reset() without set reset_possibility=true in KeybdInput::solicit().", L"KeybdInput ERROR", NULL );
		return;
	}

	// Clear previously set values
	clear_references( _references );

	// Sets the cursor in the previous line, erase all and requires input again
	get_cursor_position();
	set_cursor_position( short ( msg.size() + input.size() ), cursor_position[ 1 ] - 1 );
	erase_input( msg.size() + input.size() );
	solicit( msg, std::regex( _restriction ), _references, _instverify, _reset, _ispw, _sep, _inmaxsize );
};

template< typename T >
void KeybdInput< T >::solicit( std::string request_msg, std::regex restriction, std::vector< T * > references, bool instant_verify, bool reset_possibility, bool is_password, char separator, size_t input_max_size ) {
	static size_t clipboard_index = 0;
	size_t i, cursor_pos_x,
		inputLength = 0;
	char key = 0;
	bool is_function_key = false,
		arrow = false,
		waiting_input = true;
	std::string input_subtr;
	std::vector< std::string > inputParts;

	if ( references.size() == 0 ) {
		MessageBox( NULL, L"\"refereces\" param need be set with at least one member.", L"KeybdInput ERROR", NULL );
		return;
	}

	input = "";
	std::cout << request_msg;

	// Retrieves the values to be used in KeybdInput::reset()
	if ( reset_possibility ) {
		_rmsg = request_msg;
		_restriction = restriction;
		_references = references;
		_instverify = instant_verify;
		_reset = reset_possibility;
		_ispw = is_password;
		_sep = separator;
		_inmaxsize = input_max_size;
	}

	// Clears previous data
	else if ( _reset ) {
		_rmsg = "";
		_restriction = "";
		_references = {};
		_instverify = false;
		_reset = false;
		_ispw = false;
		_sep = ' ';
		_inmaxsize = 0;
	}

	while ( waiting_input ) {
		key = _getch();

		// Arrow keys prefix
		if ( key == -32 ) {
			arrow = true;
			continue;
		}

		// Prevents function keys
		if ( key == 0 ) {
			is_function_key = true;
			continue;
		} else if ( is_function_key ) {
			is_function_key = false;
			continue;
		}

		// Arrows
		if ( arrow ) {
			get_cursor_position();

			// LEFT
			if ( key == 75 && cursor_position[ 0 ] > request_msg.size() )
				set_cursor_position( cursor_position[ 0 ] - 1, cursor_position[ 1 ] );

			// RIGHT
			else if ( key == 77 && cursor_position[ 0 ] < input.size() + request_msg.size() )
				set_cursor_position( cursor_position[ 0 ] + 1, cursor_position[ 1 ] );

			// UP
			else if ( key == 72 && !is_password && clipboard.size() > 0 && clipboard_index > 0 ) {
				erase_input();
				std::cout << clipboard[ --clipboard_index ];

				input = clipboard[ clipboard_index ];
				inputLength = clipboard[ clipboard_index ].size();
			}

			// DOWN
			else if ( key == 80 && !is_password && clipboard.size() > 0 && clipboard_index < clipboard.size() - 1 ) {
				erase_input();
				std::cout << clipboard[ ++clipboard_index ];

				input = clipboard[ clipboard_index ];
				inputLength = clipboard[ clipboard_index ].size();

				if ( clipboard_index >= clipboard.size() )
					clipboard_index = clipboard.size() - 1;
			}

		}

		// Valid character
		else if ( key != 8 && key != 13 ) {
			// Inserts the character in current cursor position
			get_cursor_position();
			input.insert( cursor_position[ 0 ] - request_msg.size(), std::string( 1, key ) );

			// If the user input satisfy the restrictions, removes the character
			if ( instant_verify && ( input.size() > input_max_size || !std::regex_match( input, restriction ) ) ) {
				input.erase( cursor_position[ 0 ] - request_msg.size(), 1 );
			} else {
				// Appends the character if cursor is at the end, otherwise, interleaves
				if ( cursor_position[ 0 ] == ( request_msg.size() + input.size() - 1 ) ) {
					std::cout << ( ( is_password ) ? '*' : key );
				} else {
					input_subtr = input.substr( input.size() - ( ( request_msg.size() + input.size() ) - cursor_position[ 0 ] - 1 ), input.size() );

					std::cout << ( ( is_password ) ? '*' : key )
						<< ( ( is_password ) ? std::string( input_subtr.size(), '*' ) : input_subtr );
					set_cursor_position( cursor_position[ 0 ] + 1, cursor_position[ 1 ] );
				}

				inputLength++;
			}
		}

		// ENTER
		else if ( key == 13 && inputLength ) {
			// If the user input satisfy the restrictions, clear input
			if ( input.size() > input_max_size || !std::regex_match( input, restriction ) ) {
				erase_input();
				inputLength = 0;
			} else {
				// Trim left and right
				input.erase( 0, input.find_first_not_of( ' ' ) );
				input.erase( input.find_last_not_of( ' ' ) + 1 );

				if ( references.size() == 1 )
					set_reference( input, references[ 0 ] );
				else
					for ( i = 0, inputParts = split( input, separator ); i < references.size(); i++ )
						if ( i < inputParts.size() )
							set_reference( inputParts[ i ], references[ i ] );

				std::cout << std::endl;

				// Prevents repetition on clipboard and don't save if it's a password
				if ( !is_password && ( clipboard.size() == 0 || input != clipboard[ clipboard.size() - 1 ] ) ) {
					clipboard.push_back( input );
					clipboard_index = clipboard.size();
				}

				waiting_input = false;
			}
		}

		// BACKSPACE
		else if ( key == 8 && inputLength ) {
			get_cursor_position();
			cursor_pos_x = cursor_position[ 0 ];

			if ( cursor_pos_x == ( request_msg.size() + input.size() - 1 ) && inputLength == 1 )
				continue;

			std::cout << "\b \b";
			input.erase( cursor_pos_x - request_msg.size() - 1, 1 );
			inputLength--;

			// If the cursor isn't at the end
			if ( cursor_pos_x <= ( request_msg.size() + input.size() ) ) {
				// Put the cursor at the start and rewrites the input
				set_cursor_position( short ( request_msg.size() ), cursor_position[ 1 ] );
				std::cout << ( ( is_password ) ? std::string( input.size(), '*' ) : input );

				// Put the cursor at the end and erase the last char
				set_cursor_position( short ( request_msg.size() + input.size() + 1 ), cursor_position[ 1 ] );
				std::cout << "\b \b";

				// Put the cursor at the original position
				set_cursor_position( short ( cursor_pos_x - 1 ), cursor_position[ 1 ] );
			}
		}

		arrow = false;
	}
};
<commit_msg>Change on split method<commit_after>/**
 * KeybdInput 1.0.1
 *
 * @author Roger Lima (rogerlima@outlook.com)
 * @date 31/aug/2014
 * @update 11/feb/2016
 * @desc Reads the keyboard input them according to the format specified (only works on Windows)
 * @example
	int day, month, year;
	KeybdInput< int > userin;

	userin.solicit(
		"Type a date (btw 01/01/1900 and 31/12/2009): ",
		std::regex( "([0-2]?[0-9]|3[0-1])/(0?[1-9]|1[012])/(19[0-9]{2}|200[0-9])" ),
		{ &day, &month, &year },
		false,
		false,
		false,
		'/'
	);
*/

#pragma once
#include <conio.h>
#include <iostream>
#include <regex>
#include <sstream>
#include <vector>
#include <Windows.h>

template< typename T >
class KeybdInput {
private:
	// Stores the values to be used in KeybdInput::reset()
	bool _instverify, _reset, _ispw;
	size_t _inmaxsize;
	std::regex _restriction;
	std::string _rmsg, _sep;
	std::vector< T * > _references = {};

	// Stores the user input
	std::string input;

	// Receives the current X and Y cursor position from get_cursor_position()
	std::vector< size_t > cursor_position = { 0, 0 };

	// Erase the input of user
	// @param {size_t=input.size()} Erase range
	void erase_input( size_t = 0 );

	// Get the console cursor position and pass to the cursor_position
	void get_cursor_position();

	// Set the console cursor position
	// @param {short} X position of cursor
	// @param {short} Y position of cursor
	void set_cursor_position( short, short );

	// Split a string
	// @param {std::string} Target string
	// @param {std::string} Separator
	std::vector< std::string > splitstr( std::string str, std::string separator );

	// Set the reference with input value
	// @param {const std::string&} Input value
	// @param {T*} Target place
	void set_reference( const std::string&, T * );

	// Clear all values of references
	// @param {T*} Target place
	void clear_references( std::vector< T * > );
public:
	// Clipboard (arrow up or down to show the last inputs)
	std::vector< std::string > clipboard;

	// Requires the user input again
	// @param [{std::string=_rmsg}] Request message
	void reset( std::string = "" );

	// Requires the keyboard input
	// @param {string} Request message
	// @param {regex} The regex
	// @param {vector< T * >} The place(s) where it will be stored the input
	// @param {bool=false} Instant verify
	// @param {bool=false} Reset possibility
	// @param {bool=false} Is password
	// @param {char=' '} Separator
	// @param {size_t=1000} Input size
	void solicit( std::string, std::regex, std::vector< T * >, bool = false, bool = false, bool = false, std::string = " ", size_t = 1000 );
};

template< typename T >
void KeybdInput< T >::erase_input( size_t erase_range = 0 ) {
	// Default erase range
	if ( !erase_range )
		erase_range = input.size();

	for ( size_t i = 0; i < erase_range; i++ )
		std::cout << "\b \b";

	input = "";
};

template < typename T >
void KeybdInput< T >::set_reference( const std::string& value, T *target ) {
	std::stringstream convert;
	convert << value;
	convert >> *target;
};

void KeybdInput< std::string >::set_reference( const std::string& value, std::string *target ) {
	*target = value;
};

template < typename T >
void KeybdInput< T >::clear_references( std::vector< T * > target ) {
	for ( size_t i = 0; i < _references.size(); *target[ i++ ] = 0 );
};

void KeybdInput< std::string >::clear_references( std::vector< std::string * > target ) {
	for ( size_t i = 0; i < _references.size(); *target[ i++ ] = "" );
};

template< typename T >
void KeybdInput< T >::get_cursor_position() {
	CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
	HANDLE hStd = GetStdHandle( STD_OUTPUT_HANDLE );

	if ( !GetConsoleScreenBufferInfo( hStd, &screen_buffer_info ) )
		MessageBox( NULL, L"An error occurred getting the console cursor position.", L"KeybdInput ERROR", NULL );

	cursor_position[ 0 ] = screen_buffer_info.dwCursorPosition.X;
	cursor_position[ 1 ] = screen_buffer_info.dwCursorPosition.Y;
};

template< typename T >
void KeybdInput< T >::set_cursor_position( short x, short y ) {
	if ( !SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), { x, y } ) )
		MessageBox( NULL, L"An error occurred setting the console cursor position.", L"KeybdInput ERROR", NULL );
};

template< typename T >
std::vector< std::string > KeybdInput< T >::splitstr( std::string str, std::string separator = "" ) {
	size_t index;
	std::vector< std::string > elems;

	while ( ( index = str.find( separator ) ) != std::string::npos && str.size() > 1 ) {
		elems.push_back( str.substr( 0, index ? index : 1 ) );
		str.erase( 0, index + ( !separator.size() ? 1 : separator.size() ) );
	}

	elems.push_back( str );

	return elems;
};

template< typename T >
void KeybdInput< T >::reset( std::string msg = "" ) {
	// Default request message
	if ( msg == "" && _rmsg != "" )
		msg = _rmsg;

	if ( !_reset ) {
		MessageBox( NULL, L"Can't possible execute KeybdInput::reset() without set reset_possibility=true in KeybdInput::solicit().", L"KeybdInput ERROR", NULL );
		return;
	}

	// Clear previously set values
	clear_references( _references );

	// Sets the cursor in the previous line, erase all and requires input again
	get_cursor_position();
	set_cursor_position( short ( msg.size() + input.size() ), cursor_position[ 1 ] - 1 );
	erase_input( msg.size() + input.size() );
	solicit( msg, std::regex( _restriction ), _references, _instverify, _reset, _ispw, _sep, _inmaxsize );
};

template< typename T >
void KeybdInput< T >::solicit( std::string request_msg, std::regex restriction, std::vector< T * > references, bool instant_verify, bool reset_possibility, bool is_password, std::string separator, size_t input_max_size ) {
	static size_t clipboard_index = 0;
	size_t i, cursor_pos_x,
		inputLength = 0;
	char key = 0;
	bool is_function_key = false,
		arrow = false,
		waiting_input = true;
	std::string input_subtr;
	std::vector< std::string > inputParts;

	if ( references.size() == 0 ) {
		MessageBox( NULL, L"\"refereces\" param need be set with at least one member.", L"KeybdInput ERROR", NULL );
		return;
	}

	input = "";
	std::cout << request_msg;

	// Retrieves the values to be used in KeybdInput::reset()
	if ( reset_possibility ) {
		_rmsg = request_msg;
		_restriction = restriction;
		_references = references;
		_instverify = instant_verify;
		_reset = reset_possibility;
		_ispw = is_password;
		_sep = separator;
		_inmaxsize = input_max_size;
	}

	// Clears previous data
	else if ( _reset ) {
		_rmsg = "";
		_restriction = "";
		_references = {};
		_instverify = false;
		_reset = false;
		_ispw = false;
		_sep = ' ';
		_inmaxsize = 0;
	}

	while ( waiting_input ) {
		key = _getch();

		// Arrow keys prefix
		if ( key == -32 ) {
			arrow = true;
			continue;
		}

		// Prevents function keys
		if ( key == 0 ) {
			is_function_key = true;
			continue;
		} else if ( is_function_key ) {
			is_function_key = false;
			continue;
		}

		// Arrows
		if ( arrow ) {
			get_cursor_position();

			// LEFT
			if ( key == 75 && cursor_position[ 0 ] > request_msg.size() )
				set_cursor_position( cursor_position[ 0 ] - 1, cursor_position[ 1 ] );

			// RIGHT
			else if ( key == 77 && cursor_position[ 0 ] < input.size() + request_msg.size() )
				set_cursor_position( cursor_position[ 0 ] + 1, cursor_position[ 1 ] );

			// UP
			else if ( key == 72 && !is_password && clipboard.size() > 0 && clipboard_index > 0 ) {
				erase_input();
				std::cout << clipboard[ --clipboard_index ];

				input = clipboard[ clipboard_index ];
				inputLength = clipboard[ clipboard_index ].size();
			}

			// DOWN
			else if ( key == 80 && !is_password && clipboard.size() > 0 && clipboard_index < clipboard.size() - 1 ) {
				erase_input();
				std::cout << clipboard[ ++clipboard_index ];

				input = clipboard[ clipboard_index ];
				inputLength = clipboard[ clipboard_index ].size();

				if ( clipboard_index >= clipboard.size() )
					clipboard_index = clipboard.size() - 1;
			}

		}

		// Valid character
		else if ( key != 8 && key != 13 ) {
			// Inserts the character in current cursor position
			get_cursor_position();
			input.insert( cursor_position[ 0 ] - request_msg.size(), std::string( 1, key ) );

			// If the user input satisfy the restrictions, removes the character
			if ( instant_verify && ( input.size() > input_max_size || !std::regex_match( input, restriction ) ) ) {
				input.erase( cursor_position[ 0 ] - request_msg.size(), 1 );
			} else {
				// Appends the character if cursor is at the end, otherwise, interleaves
				if ( cursor_position[ 0 ] == ( request_msg.size() + input.size() - 1 ) ) {
					std::cout << ( ( is_password ) ? '*' : key );
				} else {
					input_subtr = input.substr( input.size() - ( ( request_msg.size() + input.size() ) - cursor_position[ 0 ] - 1 ), input.size() );

					std::cout << ( ( is_password ) ? '*' : key )
						<< ( ( is_password ) ? std::string( input_subtr.size(), '*' ) : input_subtr );
					set_cursor_position( cursor_position[ 0 ] + 1, cursor_position[ 1 ] );
				}

				inputLength++;
			}
		}

		// ENTER
		else if ( key == 13 && inputLength ) {
			// If the user input satisfy the restrictions, clear input
			if ( input.size() > input_max_size || !std::regex_match( input, restriction ) ) {
				erase_input();
				inputLength = 0;
			} else {
				// Trim left and right
				input.erase( 0, input.find_first_not_of( ' ' ) );
				input.erase( input.find_last_not_of( ' ' ) + 1 );

				if ( references.size() == 1 )
					set_reference( input, references[ 0 ] );
				else
					for ( i = 0, inputParts = splitstr( input, separator ); i < references.size(); i++ )
						if ( i < inputParts.size() )
							set_reference( inputParts[ i ], references[ i ] );

				std::cout << std::endl;

				// Prevents repetition on clipboard and don't save if it's a password
				if ( !is_password && ( clipboard.size() == 0 || input != clipboard[ clipboard.size() - 1 ] ) ) {
					clipboard.push_back( input );
					clipboard_index = clipboard.size();
				}

				waiting_input = false;
			}
		}

		// BACKSPACE
		else if ( key == 8 && inputLength ) {
			get_cursor_position();
			cursor_pos_x = cursor_position[ 0 ];

			if ( cursor_pos_x == ( request_msg.size() + input.size() - 1 ) && inputLength == 1 )
				continue;

			std::cout << "\b \b";
			input.erase( cursor_pos_x - request_msg.size() - 1, 1 );
			inputLength--;

			// If the cursor isn't at the end
			if ( cursor_pos_x <= ( request_msg.size() + input.size() ) ) {
				// Put the cursor at the start and rewrites the input
				set_cursor_position( short ( request_msg.size() ), cursor_position[ 1 ] );
				std::cout << ( ( is_password ) ? std::string( input.size(), '*' ) : input );

				// Put the cursor at the end and erase the last char
				set_cursor_position( short ( request_msg.size() + input.size() + 1 ), cursor_position[ 1 ] );
				std::cout << "\b \b";

				// Put the cursor at the original position
				set_cursor_position( short ( cursor_pos_x - 1 ), cursor_position[ 1 ] );
			}
		}

		arrow = false;
	}
};
<|endoftext|>


<commit_before>//===--- CGCXX.cpp - Emit LLVM Code for declarations ----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This contains code dealing with C++ code generation.
//
//===----------------------------------------------------------------------===//

// We might split this into multiple files if it gets too unwieldy

#include "CodeGenModule.h"
#include "CGCXXABI.h"
#include "CodeGenFunction.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace CodeGen;

/// Try to emit a base destructor as an alias to its primary
/// base-class destructor.
bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
  if (!getCodeGenOpts().CXXCtorDtorAliases)
    return true;

  // Producing an alias to a base class ctor/dtor can degrade debug quality
  // as the debugger cannot tell them apart.
  if (getCodeGenOpts().OptimizationLevel == 0)
    return true;

  // If the destructor doesn't have a trivial body, we have to emit it
  // separately.
  if (!D->hasTrivialBody())
    return true;

  const CXXRecordDecl *Class = D->getParent();

  // We are going to instrument this destructor, so give up even if it is
  // currently empty.
  if (Class->mayInsertExtraPadding())
    return true;

  // If we need to manipulate a VTT parameter, give up.
  if (Class->getNumVBases()) {
    // Extra Credit:  passing extra parameters is perfectly safe
    // in many calling conventions, so only bail out if the ctor's
    // calling convention is nonstandard.
    return true;
  }

  // If any field has a non-trivial destructor, we have to emit the
  // destructor separately.
  for (const auto *I : Class->fields())
    if (I->getType().isDestructedType())
      return true;

  // Try to find a unique base class with a non-trivial destructor.
  const CXXRecordDecl *UniqueBase = nullptr;
  for (const auto &I : Class->bases()) {

    // We're in the base destructor, so skip virtual bases.
    if (I.isVirtual()) continue;

    // Skip base classes with trivial destructors.
    const auto *Base =
        cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
    if (Base->hasTrivialDestructor()) continue;

    // If we've already found a base class with a non-trivial
    // destructor, give up.
    if (UniqueBase) return true;
    UniqueBase = Base;
  }

  // If we didn't find any bases with a non-trivial destructor, then
  // the base destructor is actually effectively trivial, which can
  // happen if it was needlessly user-defined or if there are virtual
  // bases with non-trivial destructors.
  if (!UniqueBase)
    return true;

  // If the base is at a non-zero offset, give up.
  const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(Class);
  if (!ClassLayout.getBaseClassOffset(UniqueBase).isZero())
    return true;

  // Give up if the calling conventions don't match. We could update the call,
  // but it is probably not worth it.
  const CXXDestructorDecl *BaseD = UniqueBase->getDestructor();
  if (BaseD->getType()->getAs<FunctionType>()->getCallConv() !=
      D->getType()->getAs<FunctionType>()->getCallConv())
    return true;

  return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base),
                                  GlobalDecl(BaseD, Dtor_Base),
                                  false);
}

/// Try to emit a definition as a global alias for another definition.
/// If \p InEveryTU is true, we know that an equivalent alias can be produced
/// in every translation unit.
bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
                                             GlobalDecl TargetDecl,
                                             bool InEveryTU) {
  if (!getCodeGenOpts().CXXCtorDtorAliases)
    return true;

  // The alias will use the linkage of the referent.  If we can't
  // support aliases with that linkage, fail.
  llvm::GlobalValue::LinkageTypes Linkage = getFunctionLinkage(AliasDecl);

  // We can't use an alias if the linkage is not valid for one.
  if (!llvm::GlobalAlias::isValidLinkage(Linkage))
    return true;

  // Don't create a weak alias for a dllexport'd symbol.
  if (AliasDecl.getDecl()->hasAttr<DLLExportAttr>() &&
      llvm::GlobalValue::isWeakForLinker(Linkage))
    return true;

  llvm::GlobalValue::LinkageTypes TargetLinkage =
      getFunctionLinkage(TargetDecl);

  // Check if we have it already.
  StringRef MangledName = getMangledName(AliasDecl);
  llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
  if (Entry && !Entry->isDeclaration())
    return false;
  if (Replacements.count(MangledName))
    return false;

  // Derive the type for the alias.
  llvm::PointerType *AliasType
    = getTypes().GetFunctionType(AliasDecl)->getPointerTo();

  // Find the referent.  Some aliases might require a bitcast, in
  // which case the caller is responsible for ensuring the soundness
  // of these semantics.
  auto *Ref = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl));
  llvm::Constant *Aliasee = Ref;
  if (Ref->getType() != AliasType)
    Aliasee = llvm::ConstantExpr::getBitCast(Ref, AliasType);

  // Instead of creating as alias to a linkonce_odr, replace all of the uses
  // of the aliasee.
  if (llvm::GlobalValue::isDiscardableIfUnused(Linkage) &&
     (TargetLinkage != llvm::GlobalValue::AvailableExternallyLinkage ||
      !TargetDecl.getDecl()->hasAttr<AlwaysInlineAttr>())) {
    // FIXME: An extern template instantiation will create functions with
    // linkage "AvailableExternally". In libc++, some classes also define
    // members with attribute "AlwaysInline" and expect no reference to
    // be generated. It is desirable to reenable this optimisation after
    // corresponding LLVM changes.
    Replacements[MangledName] = Aliasee;
    return false;
  }

  if (!InEveryTU) {
    // If we don't have a definition for the destructor yet, don't
    // emit.  We can't emit aliases to declarations; that's just not
    // how aliases work.
    if (Ref->isDeclaration())
      return true;
  }

  // Don't create an alias to a linker weak symbol. This avoids producing
  // different COMDATs in different TUs. Another option would be to
  // output the alias both for weak_odr and linkonce_odr, but that
  // requires explicit comdat support in the IL.
  if (llvm::GlobalValue::isWeakForLinker(TargetLinkage))
    return true;

  // Create the alias with no name.
  auto *Alias =
      llvm::GlobalAlias::create(AliasType, Linkage, "", Aliasee, &getModule());

  // Switch any previous uses to the alias.
  if (Entry) {
    assert(Entry->getType() == AliasType &&
           "declaration exists with different type");
    Alias->takeName(Entry);
    Entry->replaceAllUsesWith(Alias);
    Entry->eraseFromParent();
  } else {
    Alias->setName(MangledName);
  }

  // Finally, set up the alias with its proper name and attributes.
  setAliasAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias);

  return false;
}

llvm::Function *CodeGenModule::codegenCXXStructor(const CXXMethodDecl *MD,
                                                  StructorType Type) {
  const CGFunctionInfo &FnInfo =
      getTypes().arrangeCXXStructorDeclaration(MD, Type);
  auto *Fn = cast<llvm::Function>(
      getAddrOfCXXStructor(MD, Type, &FnInfo, nullptr, true));

  GlobalDecl GD;
  if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD)) {
    GD = GlobalDecl(DD, toCXXDtorType(Type));
  } else {
    const auto *CD = cast<CXXConstructorDecl>(MD);
    GD = GlobalDecl(CD, toCXXCtorType(Type));
  }

  setFunctionLinkage(GD, Fn);
  CodeGenFunction(*this).GenerateCode(GD, Fn, FnInfo);
  setFunctionDefinitionAttributes(MD, Fn);
  SetLLVMFunctionAttributesForDefinition(MD, Fn);
  return Fn;
}

llvm::GlobalValue *CodeGenModule::getAddrOfCXXStructor(
    const CXXMethodDecl *MD, StructorType Type, const CGFunctionInfo *FnInfo,
    llvm::FunctionType *FnType, bool DontDefer) {
  GlobalDecl GD;
  if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
    GD = GlobalDecl(CD, toCXXCtorType(Type));
  } else {
    auto *DD = dyn_cast<CXXDestructorDecl>(MD);
    GD = GlobalDecl(DD, toCXXDtorType(Type));
  }

  StringRef Name = getMangledName(GD);
  if (llvm::GlobalValue *Existing = GetGlobalValue(Name))
    return Existing;

  if (!FnType) {
    if (!FnInfo)
      FnInfo = &getTypes().arrangeCXXStructorDeclaration(MD, Type);
    FnType = getTypes().GetFunctionType(*FnInfo);
  }

  return cast<llvm::Function>(GetOrCreateLLVMFunction(Name, FnType, GD,
                                                      /*ForVTable=*/false,
                                                      DontDefer));
}

static llvm::Value *BuildAppleKextVirtualCall(CodeGenFunction &CGF,
                                              GlobalDecl GD,
                                              llvm::Type *Ty,
                                              const CXXRecordDecl *RD) {
  assert(!CGF.CGM.getTarget().getCXXABI().isMicrosoft() &&
         "No kext in Microsoft ABI");
  GD = GD.getCanonicalDecl();
  CodeGenModule &CGM = CGF.CGM;
  llvm::Value *VTable = CGM.getCXXABI().getAddrOfVTable(RD, CharUnits());
  Ty = Ty->getPointerTo()->getPointerTo();
  VTable = CGF.Builder.CreateBitCast(VTable, Ty);
  assert(VTable && "BuildVirtualCall = kext vtbl pointer is null");
  uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
  uint64_t AddressPoint =
    CGM.getItaniumVTableContext().getVTableLayout(RD)
       .getAddressPoint(BaseSubobject(RD, CharUnits::Zero()));
  VTableIndex += AddressPoint;
  llvm::Value *VFuncPtr =
    CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt");
  return CGF.Builder.CreateLoad(VFuncPtr);
}

/// BuildAppleKextVirtualCall - This routine is to support gcc's kext ABI making
/// indirect call to virtual functions. It makes the call through indexing
/// into the vtable.
llvm::Value *
CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
                                  NestedNameSpecifier *Qual,
                                  llvm::Type *Ty) {
  assert((Qual->getKind() == NestedNameSpecifier::TypeSpec) &&
         "BuildAppleKextVirtualCall - bad Qual kind");

  const Type *QTy = Qual->getAsType();
  QualType T = QualType(QTy, 0);
  const RecordType *RT = T->getAs<RecordType>();
  assert(RT && "BuildAppleKextVirtualCall - Qual type must be record");
  const auto *RD = cast<CXXRecordDecl>(RT->getDecl());

  if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD))
    return BuildAppleKextVirtualDestructorCall(DD, Dtor_Complete, RD);

  return ::BuildAppleKextVirtualCall(*this, MD, Ty, RD);
}

/// BuildVirtualCall - This routine makes indirect vtable call for
/// call to virtual destructors. It returns 0 if it could not do it.
llvm::Value *
CodeGenFunction::BuildAppleKextVirtualDestructorCall(
                                            const CXXDestructorDecl *DD,
                                            CXXDtorType Type,
                                            const CXXRecordDecl *RD) {
  const auto *MD = cast<CXXMethodDecl>(DD);
  // FIXME. Dtor_Base dtor is always direct!!
  // It need be somehow inline expanded into the caller.
  // -O does that. But need to support -O0 as well.
  if (MD->isVirtual() && Type != Dtor_Base) {
    // Compute the function type we're calling.
    const CGFunctionInfo &FInfo = CGM.getTypes().arrangeCXXStructorDeclaration(
        DD, StructorType::Complete);
    llvm::Type *Ty = CGM.getTypes().GetFunctionType(FInfo);
    return ::BuildAppleKextVirtualCall(*this, GlobalDecl(DD, Type), Ty, RD);
  }
  return nullptr;
}
<commit_msg>CGCXX: Use cast in getAddrOfCXXStructor()<commit_after>//===--- CGCXX.cpp - Emit LLVM Code for declarations ----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This contains code dealing with C++ code generation.
//
//===----------------------------------------------------------------------===//

// We might split this into multiple files if it gets too unwieldy

#include "CodeGenModule.h"
#include "CGCXXABI.h"
#include "CodeGenFunction.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace CodeGen;

/// Try to emit a base destructor as an alias to its primary
/// base-class destructor.
bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
  if (!getCodeGenOpts().CXXCtorDtorAliases)
    return true;

  // Producing an alias to a base class ctor/dtor can degrade debug quality
  // as the debugger cannot tell them apart.
  if (getCodeGenOpts().OptimizationLevel == 0)
    return true;

  // If the destructor doesn't have a trivial body, we have to emit it
  // separately.
  if (!D->hasTrivialBody())
    return true;

  const CXXRecordDecl *Class = D->getParent();

  // We are going to instrument this destructor, so give up even if it is
  // currently empty.
  if (Class->mayInsertExtraPadding())
    return true;

  // If we need to manipulate a VTT parameter, give up.
  if (Class->getNumVBases()) {
    // Extra Credit:  passing extra parameters is perfectly safe
    // in many calling conventions, so only bail out if the ctor's
    // calling convention is nonstandard.
    return true;
  }

  // If any field has a non-trivial destructor, we have to emit the
  // destructor separately.
  for (const auto *I : Class->fields())
    if (I->getType().isDestructedType())
      return true;

  // Try to find a unique base class with a non-trivial destructor.
  const CXXRecordDecl *UniqueBase = nullptr;
  for (const auto &I : Class->bases()) {

    // We're in the base destructor, so skip virtual bases.
    if (I.isVirtual()) continue;

    // Skip base classes with trivial destructors.
    const auto *Base =
        cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
    if (Base->hasTrivialDestructor()) continue;

    // If we've already found a base class with a non-trivial
    // destructor, give up.
    if (UniqueBase) return true;
    UniqueBase = Base;
  }

  // If we didn't find any bases with a non-trivial destructor, then
  // the base destructor is actually effectively trivial, which can
  // happen if it was needlessly user-defined or if there are virtual
  // bases with non-trivial destructors.
  if (!UniqueBase)
    return true;

  // If the base is at a non-zero offset, give up.
  const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(Class);
  if (!ClassLayout.getBaseClassOffset(UniqueBase).isZero())
    return true;

  // Give up if the calling conventions don't match. We could update the call,
  // but it is probably not worth it.
  const CXXDestructorDecl *BaseD = UniqueBase->getDestructor();
  if (BaseD->getType()->getAs<FunctionType>()->getCallConv() !=
      D->getType()->getAs<FunctionType>()->getCallConv())
    return true;

  return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base),
                                  GlobalDecl(BaseD, Dtor_Base),
                                  false);
}

/// Try to emit a definition as a global alias for another definition.
/// If \p InEveryTU is true, we know that an equivalent alias can be produced
/// in every translation unit.
bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
                                             GlobalDecl TargetDecl,
                                             bool InEveryTU) {
  if (!getCodeGenOpts().CXXCtorDtorAliases)
    return true;

  // The alias will use the linkage of the referent.  If we can't
  // support aliases with that linkage, fail.
  llvm::GlobalValue::LinkageTypes Linkage = getFunctionLinkage(AliasDecl);

  // We can't use an alias if the linkage is not valid for one.
  if (!llvm::GlobalAlias::isValidLinkage(Linkage))
    return true;

  // Don't create a weak alias for a dllexport'd symbol.
  if (AliasDecl.getDecl()->hasAttr<DLLExportAttr>() &&
      llvm::GlobalValue::isWeakForLinker(Linkage))
    return true;

  llvm::GlobalValue::LinkageTypes TargetLinkage =
      getFunctionLinkage(TargetDecl);

  // Check if we have it already.
  StringRef MangledName = getMangledName(AliasDecl);
  llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
  if (Entry && !Entry->isDeclaration())
    return false;
  if (Replacements.count(MangledName))
    return false;

  // Derive the type for the alias.
  llvm::PointerType *AliasType
    = getTypes().GetFunctionType(AliasDecl)->getPointerTo();

  // Find the referent.  Some aliases might require a bitcast, in
  // which case the caller is responsible for ensuring the soundness
  // of these semantics.
  auto *Ref = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl));
  llvm::Constant *Aliasee = Ref;
  if (Ref->getType() != AliasType)
    Aliasee = llvm::ConstantExpr::getBitCast(Ref, AliasType);

  // Instead of creating as alias to a linkonce_odr, replace all of the uses
  // of the aliasee.
  if (llvm::GlobalValue::isDiscardableIfUnused(Linkage) &&
     (TargetLinkage != llvm::GlobalValue::AvailableExternallyLinkage ||
      !TargetDecl.getDecl()->hasAttr<AlwaysInlineAttr>())) {
    // FIXME: An extern template instantiation will create functions with
    // linkage "AvailableExternally". In libc++, some classes also define
    // members with attribute "AlwaysInline" and expect no reference to
    // be generated. It is desirable to reenable this optimisation after
    // corresponding LLVM changes.
    Replacements[MangledName] = Aliasee;
    return false;
  }

  if (!InEveryTU) {
    // If we don't have a definition for the destructor yet, don't
    // emit.  We can't emit aliases to declarations; that's just not
    // how aliases work.
    if (Ref->isDeclaration())
      return true;
  }

  // Don't create an alias to a linker weak symbol. This avoids producing
  // different COMDATs in different TUs. Another option would be to
  // output the alias both for weak_odr and linkonce_odr, but that
  // requires explicit comdat support in the IL.
  if (llvm::GlobalValue::isWeakForLinker(TargetLinkage))
    return true;

  // Create the alias with no name.
  auto *Alias =
      llvm::GlobalAlias::create(AliasType, Linkage, "", Aliasee, &getModule());

  // Switch any previous uses to the alias.
  if (Entry) {
    assert(Entry->getType() == AliasType &&
           "declaration exists with different type");
    Alias->takeName(Entry);
    Entry->replaceAllUsesWith(Alias);
    Entry->eraseFromParent();
  } else {
    Alias->setName(MangledName);
  }

  // Finally, set up the alias with its proper name and attributes.
  setAliasAttributes(cast<NamedDecl>(AliasDecl.getDecl()), Alias);

  return false;
}

llvm::Function *CodeGenModule::codegenCXXStructor(const CXXMethodDecl *MD,
                                                  StructorType Type) {
  const CGFunctionInfo &FnInfo =
      getTypes().arrangeCXXStructorDeclaration(MD, Type);
  auto *Fn = cast<llvm::Function>(
      getAddrOfCXXStructor(MD, Type, &FnInfo, nullptr, true));

  GlobalDecl GD;
  if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD)) {
    GD = GlobalDecl(DD, toCXXDtorType(Type));
  } else {
    const auto *CD = cast<CXXConstructorDecl>(MD);
    GD = GlobalDecl(CD, toCXXCtorType(Type));
  }

  setFunctionLinkage(GD, Fn);
  CodeGenFunction(*this).GenerateCode(GD, Fn, FnInfo);
  setFunctionDefinitionAttributes(MD, Fn);
  SetLLVMFunctionAttributesForDefinition(MD, Fn);
  return Fn;
}

llvm::GlobalValue *CodeGenModule::getAddrOfCXXStructor(
    const CXXMethodDecl *MD, StructorType Type, const CGFunctionInfo *FnInfo,
    llvm::FunctionType *FnType, bool DontDefer) {
  GlobalDecl GD;
  if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
    GD = GlobalDecl(CD, toCXXCtorType(Type));
  } else {
    GD = GlobalDecl(cast<CXXDestructorDecl>(MD), toCXXDtorType(Type));
  }

  StringRef Name = getMangledName(GD);
  if (llvm::GlobalValue *Existing = GetGlobalValue(Name))
    return Existing;

  if (!FnType) {
    if (!FnInfo)
      FnInfo = &getTypes().arrangeCXXStructorDeclaration(MD, Type);
    FnType = getTypes().GetFunctionType(*FnInfo);
  }

  return cast<llvm::Function>(GetOrCreateLLVMFunction(Name, FnType, GD,
                                                      /*ForVTable=*/false,
                                                      DontDefer));
}

static llvm::Value *BuildAppleKextVirtualCall(CodeGenFunction &CGF,
                                              GlobalDecl GD,
                                              llvm::Type *Ty,
                                              const CXXRecordDecl *RD) {
  assert(!CGF.CGM.getTarget().getCXXABI().isMicrosoft() &&
         "No kext in Microsoft ABI");
  GD = GD.getCanonicalDecl();
  CodeGenModule &CGM = CGF.CGM;
  llvm::Value *VTable = CGM.getCXXABI().getAddrOfVTable(RD, CharUnits());
  Ty = Ty->getPointerTo()->getPointerTo();
  VTable = CGF.Builder.CreateBitCast(VTable, Ty);
  assert(VTable && "BuildVirtualCall = kext vtbl pointer is null");
  uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
  uint64_t AddressPoint =
    CGM.getItaniumVTableContext().getVTableLayout(RD)
       .getAddressPoint(BaseSubobject(RD, CharUnits::Zero()));
  VTableIndex += AddressPoint;
  llvm::Value *VFuncPtr =
    CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt");
  return CGF.Builder.CreateLoad(VFuncPtr);
}

/// BuildAppleKextVirtualCall - This routine is to support gcc's kext ABI making
/// indirect call to virtual functions. It makes the call through indexing
/// into the vtable.
llvm::Value *
CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
                                  NestedNameSpecifier *Qual,
                                  llvm::Type *Ty) {
  assert((Qual->getKind() == NestedNameSpecifier::TypeSpec) &&
         "BuildAppleKextVirtualCall - bad Qual kind");

  const Type *QTy = Qual->getAsType();
  QualType T = QualType(QTy, 0);
  const RecordType *RT = T->getAs<RecordType>();
  assert(RT && "BuildAppleKextVirtualCall - Qual type must be record");
  const auto *RD = cast<CXXRecordDecl>(RT->getDecl());

  if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD))
    return BuildAppleKextVirtualDestructorCall(DD, Dtor_Complete, RD);

  return ::BuildAppleKextVirtualCall(*this, MD, Ty, RD);
}

/// BuildVirtualCall - This routine makes indirect vtable call for
/// call to virtual destructors. It returns 0 if it could not do it.
llvm::Value *
CodeGenFunction::BuildAppleKextVirtualDestructorCall(
                                            const CXXDestructorDecl *DD,
                                            CXXDtorType Type,
                                            const CXXRecordDecl *RD) {
  const auto *MD = cast<CXXMethodDecl>(DD);
  // FIXME. Dtor_Base dtor is always direct!!
  // It need be somehow inline expanded into the caller.
  // -O does that. But need to support -O0 as well.
  if (MD->isVirtual() && Type != Dtor_Base) {
    // Compute the function type we're calling.
    const CGFunctionInfo &FInfo = CGM.getTypes().arrangeCXXStructorDeclaration(
        DD, StructorType::Complete);
    llvm::Type *Ty = CGM.getTypes().GetFunctionType(FInfo);
    return ::BuildAppleKextVirtualCall(*this, GlobalDecl(DD, Type), Ty, RD);
  }
  return nullptr;
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS)
 *
 * This file is part of libbitcoin.
 *
 * libbitcoin is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef LIBBITCOIN_MISC_IPP
#define LIBBITCOIN_MISC_IPP

#include <bitcoin/bitcoin/constants.hpp>
#include <bitcoin/bitcoin/math/checksum.hpp>
#include <bitcoin/bitcoin/primitives.hpp>
#include <bitcoin/bitcoin/utility/assert.hpp>
#include <bitcoin/bitcoin/utility/data.hpp>
#include <bitcoin/bitcoin/utility/serializer.hpp>

namespace libbitcoin {

// message headers
template <typename Iterator>
Iterator satoshi_save(const header_type& head, Iterator result)
{
    auto serial = make_serializer(result);
    serial.write_4_bytes(head.magic);
    serial.write_fixed_string(head.command, command_size);
    serial.write_4_bytes(head.payload_length);
    if (head.checksum != 0)
        serial.write_4_bytes(head.checksum);
    return serial.iterator();
}
template <typename Iterator>
void satoshi_load(const Iterator first, const Iterator last,
    header_type& head)
{
    auto deserial = make_deserializer(first, last);
    head.magic = deserial.read_4_bytes();
    head.command = deserial.read_fixed_string(command_size);
    head.payload_length = deserial.read_4_bytes();
    head.checksum = 0;
}

// version messages
template <typename Iterator>
Iterator satoshi_save(const version_type& packet, Iterator result)
{
    auto serial = make_serializer(result);
    serial.write_4_bytes(packet.version);
    serial.write_8_bytes(packet.services);
    serial.write_8_bytes(packet.timestamp);
    serial.write_network_address(packet.address_me);
    serial.write_network_address(packet.address_you);
    serial.write_8_bytes(packet.nonce);
    serial.write_string(packet.user_agent);
    serial.write_4_bytes(packet.start_height);
    const uint8_t relay = packet.relay ? 1 : 0;
    serial.write_byte(relay);
    return serial.iterator();
}
template <typename Iterator>
void satoshi_load(const Iterator first, const Iterator last,
    version_type& packet)
{
    // Address timestamps are not used in the version message.
    // read_network_address skips timestamp but it is read load address_type.
    auto deserial = make_deserializer(first, last);
    packet.version = deserial.read_4_bytes();
    packet.services = deserial.read_8_bytes();
    packet.timestamp = deserial.read_8_bytes();
    packet.address_me = deserial.read_network_address();
    packet.address_me.timestamp = 0;
    if (packet.version < 106)
    {
        BITCOIN_ASSERT(std::distance(first, last) >= 46);
        return;
    }
    packet.address_you = deserial.read_network_address();
    packet.address_you.timestamp = 0;
    packet.nonce = deserial.read_8_bytes();
    packet.user_agent = deserial.read_string();
    if (packet.version < 209)
    {
        BITCOIN_ASSERT(std::distance(first, last) >= 46 + 26 + 8 + 1);
        return;
    }
    // The satoshi client treats 209 as the "initial protocol version"
    // and disconnects peers below 31800 (for getheaders support).
    packet.start_height = deserial.read_4_bytes();
    if (packet.version < 70001)
    {
        BITCOIN_ASSERT(std::distance(first, last) >= 81 + 4);
        return;
    }
    packet.relay = deserial.read_byte() != 0;
    BITCOIN_ASSERT(std::distance(first, last) >= 85 + 1);
}

// verack messages
template <typename Iterator>
Iterator satoshi_save(const verack_type& DEBUG_ONLY(packet), Iterator result)
{
    BITCOIN_ASSERT(satoshi_raw_size(packet) == 0);
    return result;
}
template <typename Iterator>
void satoshi_load(const Iterator, const Iterator,
    verack_type& DEBUG_ONLY(packet))
{
    BITCOIN_ASSERT(satoshi_raw_size(packet) == 0);
}

// addr messages
template <typename Iterator>
Iterator satoshi_save(const address_type& packet, Iterator result)
{
    auto serial = make_serializer(result);
    serial.write_variable_uint(packet.addresses.size());
    for (const auto& net_address: packet.addresses)
    {
        serial.write_4_bytes(net_address.timestamp);
        serial.write_network_address(net_address);
    }
    return serial.iterator();
}
template <typename Iterator>
void satoshi_load(const Iterator first, const Iterator last,
    address_type& packet)
{
    auto deserial = make_deserializer(first, last);
    uint64_t count = deserial.read_variable_uint();
    for (size_t i = 0; i < count; ++i)
    {
        uint32_t timestamp = deserial.read_4_bytes();
        network_address_type addr = deserial.read_network_address();
        addr.timestamp = timestamp;
        packet.addresses.push_back(addr);
    }
    BITCOIN_ASSERT(deserial.iterator() == first + satoshi_raw_size(packet));
    BITCOIN_ASSERT(deserial.iterator() == last);
}

// getaddr messages
template <typename Iterator>
Iterator satoshi_save(const get_address_type& DEBUG_ONLY(packet),
    Iterator result)
{
    BITCOIN_ASSERT(satoshi_raw_size(packet) == 0);
    return result;
}
template <typename Iterator>
void satoshi_load(const Iterator, const Iterator,
    get_address_type& DEBUG_ONLY(packet))
{
    BITCOIN_ASSERT(satoshi_raw_size(packet) == 0);
}

// inventory related stuff
BC_API uint32_t inventory_type_to_number(inventory_type_id inv_type);
BC_API inventory_type_id inventory_type_from_number(uint32_t raw_type);

template <typename Message>
size_t raw_size_inventory_impl(const Message& packet)
{
    return variable_uint_size(packet.inventories.size()) +
        36 * packet.inventories.size();
}
template <typename Message, typename Iterator>
Iterator save_inventory_impl(const Message& packet, Iterator result)
{
    auto serial = make_serializer(result);
    serial.write_variable_uint(packet.inventories.size());
    for (const auto& inv: packet.inventories)
    {
        uint32_t raw_type = inventory_type_to_number(inv.type);
        serial.write_4_bytes(raw_type);
        serial.write_hash(inv.hash);
    }
    return serial.iterator();
}
template <typename Message, typename Iterator>
void load_inventory_impl(const Iterator first, const Iterator last,
    Message& packet)
{
    auto deserial = make_deserializer(first, last);
    uint64_t count = deserial.read_variable_uint();
    for (size_t i = 0; i < count; ++i)
    {
        inventory_vector_type inv;
        uint32_t raw_type = deserial.read_4_bytes();
        inv.type = inventory_type_from_number(raw_type);
        inv.hash = deserial.read_hash();
        packet.inventories.push_back(inv);
    }
    BITCOIN_ASSERT(deserial.iterator() == first + satoshi_raw_size(packet));
}

// inv messages
template <typename Iterator>
Iterator satoshi_save(const inventory_type& packet, Iterator result)
{
    return save_inventory_impl(packet, result);
}
template <typename Iterator>
void satoshi_load(const Iterator first, const Iterator last,
    inventory_type& packet)
{
    load_inventory_impl(first, last, packet);
}

// getdata messages
template <typename Iterator>
Iterator satoshi_save(const get_data_type& packet, Iterator result)
{
    return save_inventory_impl(packet, result);
}
template <typename Iterator>
void satoshi_load(const Iterator first, const Iterator last,
    get_data_type& packet)
{
    load_inventory_impl(first, last, packet);
}

// getblocks messages
template <typename Iterator>
Iterator satoshi_save(const get_blocks_type& packet, Iterator result)
{
    auto serial = make_serializer(result);
    serial.write_4_bytes(protocol_version);
    serial.write_variable_uint(packet.start_hashes.size());
    for (const auto& start_hash: packet.start_hashes)
        serial.write_hash(start_hash);
    serial.write_hash(packet.hash_stop);
    return serial.iterator();
}
template <typename Iterator>
void satoshi_load(const Iterator first, const Iterator last,
    get_blocks_type& packet)
{
    auto deserial = make_deserializer(first, last);
    // Discard protocol version because it is stupid
    deserial.read_4_bytes();

    // Note: changed to uint64_t to preclude possible loss of data.
    uint64_t count = deserial.read_variable_uint();
    for (uint64_t i = 0; i < count; ++i)
    {
        hash_digest start_hash = deserial.read_hash();
        packet.start_hashes.push_back(start_hash);
    }
    packet.hash_stop = deserial.read_hash();
    BITCOIN_ASSERT(deserial.iterator() == first + satoshi_raw_size(packet));
    BITCOIN_ASSERT(deserial.iterator() == last);
}

// ping messages
template <typename Iterator>
Iterator satoshi_save(const ping_type& packet, Iterator result)
{
    // We always send value, which implies our protocol version > 60000.
    auto serial = make_serializer(result);
    serial.write_8_bytes(packet.nonce);
    return serial.iterator();
}
template <typename Iterator>
void satoshi_load(const Iterator first, const Iterator last,
    ping_type& packet)
{
    // We require a value, implying a peer protocol version > 60000 (BIP31).
    // We are currently setting protocol_version to 60001.
    auto deserial = make_deserializer(first, last);
    packet.nonce = deserial.read_8_bytes();
    BITCOIN_ASSERT(deserial.iterator() == first + satoshi_raw_size(packet));
    BITCOIN_ASSERT(deserial.iterator() == last);
}

// pong messages
template <typename Iterator>
Iterator satoshi_save(const pong_type& packet, Iterator result)
{
    auto serial = make_serializer(result);
    serial.write_8_bytes(packet.nonce);
    return serial.iterator();
}
template <typename Iterator>
void satoshi_load(const Iterator first, const Iterator last,
    pong_type& packet)
{
    auto deserial = make_deserializer(first, last);
    packet.nonce = deserial.read_8_bytes();
    BITCOIN_ASSERT(deserial.iterator() == first + satoshi_raw_size(packet));
    BITCOIN_ASSERT(deserial.iterator() == last);
}

template <typename Message>
data_chunk create_raw_message(const Message& packet)
{
    const auto payload_size = static_cast<uint32_t>(satoshi_raw_size(packet));

    // Serialize the payload (required for header size).
    data_chunk payload(payload_size);
    satoshi_save(packet, payload.begin());

    // Construct the header.
    header_type header;
    header.magic = bc::magic_value;
    header.command = satoshi_command(packet);
    header.payload_length = payload_size;
    header.checksum = bitcoin_checksum(payload);

    // Serialize header and copy the payload into a single message buffer.
    data_chunk message(satoshi_raw_size(header));
    satoshi_save(header, message.begin());
    extend_data(message, payload);
    return message;
}

} // libbitcoin

#endif

<commit_msg>Remove dead code.<commit_after><|endoftext|>


<commit_before>#include "ResourceView.hpp"

#include <Engine/Geometry/Model.hpp>
#include <Engine/Texture/TextureAsset.hpp>
#include <Engine/Audio/SoundBuffer.hpp>
#include <Engine/Script/ScriptFile.hpp>
#include <Engine/Util/FileSystem.hpp>
#include <Editor/Util/EditorSettings.hpp>
#include <Engine/Hymn.hpp>
#include <Engine/Entity/Entity.hpp>
#include <Engine/MainWindow.hpp>
#include <imgui.h>
#include <limits>
#include "../ImGui/Splitter.hpp"
#include <Engine/Manager/Managers.hpp>
#include <Engine/Manager/ResourceManager.hpp>
#include <cstdio>
#include <Utility/Log.hpp>

using namespace GUI;
using namespace std;

ResourceView::ResourceView() {

}

void ResourceView::Show() {
    ImVec2 size(MainWindow::GetInstance()->GetSize().x, MainWindow::GetInstance()->GetSize().y);

    // Splitter.
    ImGui::VerticalSplitter(ImVec2(sceneWidth, size.y - resourceHeight), size.x - sceneWidth - editorWidth, splitterSize, resourceHeight, resourceResize, 20, size.y - 20);
    if (resourceResize)
        resourceHeight = size.y - resourceHeight;

    ImGui::SetNextWindowPos(ImVec2(sceneWidth, size.y - resourceHeight));
    ImGui::SetNextWindowSize(ImVec2(size.x - sceneWidth - editorWidth, resourceHeight));

    ImGui::Begin("Resources", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_ShowBorders);

    /// @todo Add resources.

    // Show resources.
    scriptPressed = false;
    texturePressed = false;
    modelPressed = false;
    soundPressed = false;

    ShowResourceFolder(Resources().resourceFolder, Resources().resourceFolder.name);

    // Change scene.
    if (changeScene) {
        if (Hymn().GetPath() != "") {
            savePromptWindow.SetVisible(true);
            savePromptWindow.Show();

            switch (savePromptWindow.GetDecision()) {
            case 0:
                sceneEditor.Save();
                sceneEditor.SetVisible(true);
                sceneEditor.SetScene(scene);
                Resources().activeScene = resourcePath + "/" + *scene;
                sceneEditor.entityEditor.SetVisible(false);
                Hymn().world.Clear();
                Hymn().world.Load(Hymn().GetPath() + "/" + Resources().activeScene + ".json");
                changeScene = false;
                savePromptWindow.SetVisible(false);
                savePromptWindow.ResetDecision();
                break;

            case 1:
                sceneEditor.SetVisible(true);
                sceneEditor.SetScene(scene);
                Resources().activeScene = resourcePath + "/" + *scene;
                sceneEditor.entityEditor.SetVisible(false);
                Hymn().world.Clear();
                Hymn().world.Load(Hymn().GetPath() + "/" + Resources().activeScene + ".json");
                changeScene = false;
                savePromptWindow.SetVisible(false);
                savePromptWindow.ResetDecision();
                break;

            default:
                break;
            }
        }
    }

    if (sceneEditor.entityPressed || scriptPressed || texturePressed || modelPressed || soundPressed) {
        sceneEditor.entityEditor.SetVisible(sceneEditor.entityPressed);
        scriptEditor.SetVisible(scriptPressed);
        textureEditor.SetVisible(texturePressed);
        modelEditor.SetVisible(modelPressed);
        soundEditor.SetVisible(soundPressed);
    }

    if (sceneEditor.IsVisible()) {
        ImGui::HorizontalSplitter(ImVec2(sceneWidth, 20), size.y - 20, splitterSize, sceneWidth, sceneResize, 20, size.x - editorWidth - 20);
        ImGui::SetNextWindowPos(ImVec2(0, 20));
        ImGui::SetNextWindowSize(ImVec2(sceneWidth, size.y - 20));
        sceneEditor.Show();
    }

    if (sceneEditor.entityEditor.IsVisible() || scriptEditor.IsVisible() || textureEditor.IsVisible() || modelEditor.IsVisible() || soundEditor.IsVisible()) {
        editorWidth = size.x - editorWidth;
        ImGui::HorizontalSplitter(ImVec2(editorWidth, 20), size.y - 20, splitterSize, editorWidth, editorResize, sceneWidth + 20, size.x - 20);
        editorWidth = size.x - editorWidth;

        ImGui::SetNextWindowPos(ImVec2(size.x - editorWidth, 20));
        ImGui::SetNextWindowSize(ImVec2(editorWidth, size.y - 20));
    }

    if (sceneEditor.entityEditor.IsVisible())
        sceneEditor.entityEditor.Show();
    if (scriptEditor.IsVisible())
        scriptEditor.Show();
    if (textureEditor.IsVisible())
        textureEditor.Show();
    if (modelEditor.IsVisible())
        modelEditor.Show();
    if (soundEditor.IsVisible())
        soundEditor.Show();

    ImGui::End();
}

bool ResourceView::IsVisible() const {
    return visible;
}

void ResourceView::SetVisible(bool visible) {
    this->visible = visible;
}

void ResourceView::HideEditors() {
    sceneEditor.SetVisible(false);
    sceneEditor.entityEditor.SetVisible(false);
    scriptEditor.SetVisible(false);
    modelEditor.SetVisible(false);
    textureEditor.SetVisible(false);
    soundEditor.SetVisible(false);
}

void ResourceView::SaveScene() const {
    sceneEditor.Save();
}

#undef max
void ResourceView::ResetScene() {
    sceneEditor.SetScene(nullptr);
    sceneEditor.SetVisible(false);
}

SceneEditor& ResourceView::GetScene() {
    return sceneEditor;
}

void ResourceView::ShowResourceFolder(ResourceList::ResourceFolder& folder, const std::string& path) {
    bool opened = ImGui::TreeNode(folder.name.c_str());

    /// @todo Remove folder.

    if (opened) {
        // Show subfolders.
        for (ResourceList::ResourceFolder& subfolder : folder.subfolders) {
            ShowResourceFolder(subfolder, path + "/" + subfolder.name);
        }

        // Show resources.
        for (auto it = folder.resources.begin(); it != folder.resources.end(); ++it) {
            if (ShowResource(*it, path)) {
                folder.resources.erase(it);
                return;
            }
        }

        ImGui::TreePop();
    }
}

bool ResourceView::ShowResource(ResourceList::Resource& resource, const std::string& path) {
    // Scene.
    if (resource.type == ResourceList::Resource::SCENE) {
        if (ImGui::Selectable(resource.scene.c_str())) {
            // Sets to don't save when opening first scene.
            if (scene == nullptr) {
                changeScene = true;
                resourcePath = path;
                scene = &resource.scene;
                savePromptWindow.SetVisible(false);
                savePromptWindow.SetDecision(1);
            } else {
                // Does so that the prompt window won't show if you select active scene.
                if (resource.scene != Resources().activeScene) {
                    changeScene = true;
                    resourcePath = path;
                    scene = &resource.scene;
                    savePromptWindow.SetTitle("Save before you switch scene?");
                }
            }
        }

        // Delete scene.
        if (ImGui::BeginPopupContextItem(resource.scene.c_str())) {
            if (ImGui::Selectable("Delete")) {
                if (Resources().activeScene == resource.scene) {
                    Resources().activeScene = "";
                    sceneEditor.SetScene(nullptr);
                }

                ImGui::EndPopup();

                return true;
            }
            ImGui::EndPopup();
        }
    }

    /*
    // Models.
    bool modelPressed = false;
    if (ImGui::TreeNode("Models")) {
        if (ImGui::Button("Add model")) {
            Geometry::Model* model = new Geometry::Model();
            model->name = "Model #" + std::to_string(Resources().modelNumber++);
            Resources().models.push_back(model);
        }

        for (auto it = Resources().models.begin(); it != Resources().models.end(); ++it) {
            Geometry::Model* model = *it;
            if (ImGui::Selectable(model->name.c_str())) {
                modelPressed = true;
                modelEditor.SetModel(model);
            }

            if (ImGui::BeginPopupContextItem(model->name.c_str())) {
                if (ImGui::Selectable("Delete")) {
                    if (modelEditor.GetModel() == model)
                        modelEditor.SetVisible(false);

                    delete model;
                    Resources().models.erase(it);
                    ImGui::EndPopup();
                    break;
                }
                ImGui::EndPopup();
            }
        }
        ImGui::TreePop();
    }

    // Textures.
    bool texturePressed = false;
    if (ImGui::TreeNode("Textures")) {
        if (ImGui::Button("Add texture")) {
            TextureAsset* texture = new TextureAsset();
            texture->name = "Texture #" + std::to_string(Resources().textureNumber++);
            Resources().textures.push_back(texture);
        }

        for (auto it = Resources().textures.begin(); it != Resources().textures.end(); ++it) {
            TextureAsset* texture = *it;
            if (ImGui::Selectable(texture->name.c_str())) {
                texturePressed = true;
                textureEditor.SetTexture(texture);
            }

            if (ImGui::BeginPopupContextItem(texture->name.c_str())) {
                if (ImGui::Selectable("Delete")) {
                    if (Managers().resourceManager->GetTextureAssetInstanceCount(texture) > 1) {
                        Log() << "This texture is in use. Remove all references to the texture first.\n";
                    } else {
                        if (textureEditor.GetTexture() == texture)
                            textureEditor.SetVisible(false);

                        // Remove files.
                        remove((Hymn().GetPath() + FileSystem::DELIMITER + "Textures" + FileSystem::DELIMITER + texture->name + ".png").c_str());
                        remove((Hymn().GetPath() + FileSystem::DELIMITER + "Textures" + FileSystem::DELIMITER + texture->name + ".json").c_str());

                        Managers().resourceManager->FreeTextureAsset(texture);
                        Resources().textures.erase(it);
                    }
                    ImGui::EndPopup();
                    break;
                }
                ImGui::EndPopup();
            }
        }

        ImGui::TreePop();
    }

    // Scripts.
    bool scriptPressed = false;
    if (ImGui::TreeNode("Scripts")) {
        if (ImGui::Button("Add script")) {
            ScriptFile* scriptFile = new ScriptFile();
            scriptFile->name = "Script #" + std::to_string(Hymn().scriptNumber++);
            Hymn().scripts.push_back(scriptFile);
        }

        for (auto it = Hymn().scripts.begin(); it != Hymn().scripts.end(); ++it) {
            ScriptFile* script = *it;
            std::string name = script->name;

            if (ImGui::Selectable(name.c_str())) {
                scriptPressed = true;
                scriptEditor.SetScript(script);
            }

            if (ImGui::BeginPopupContextItem(name.c_str())) {
                if (ImGui::Selectable("Delete")) {
                    if (scriptEditor.GetScript() == script)
                        scriptEditor.SetVisible(false);

                    delete script;
                    Hymn().scripts.erase(it);
                    ImGui::EndPopup();
                    break;
                }
                ImGui::EndPopup();
            }
        }

        ImGui::TreePop();
    }

    // Sounds.
    bool soundPressed = false;
    if (ImGui::TreeNode("Sounds")) {
        if (ImGui::Button("Add sound")) {
            Audio::SoundBuffer* sound = new Audio::SoundBuffer();
            sound->name = "Sound #" + std::to_string(Resources().soundNumber++);
            Resources().sounds.push_back(sound);
        }

        for (auto it = Resources().sounds.begin(); it != Resources().sounds.end(); ++it) {
            Audio::SoundBuffer* sound = *it;
            if (ImGui::Selectable(sound->name.c_str())) {
                soundPressed = true;
                soundEditor.SetSound(sound);
            }

            if (ImGui::BeginPopupContextItem(sound->name.c_str())) {
                if (ImGui::Selectable("Delete")) {
                    if (soundEditor.GetSound() == sound)
                        soundEditor.SetVisible(false);

                    delete sound;
                    Resources().sounds.erase(it);
                    ImGui::EndPopup();
                    break;
                }
                ImGui::EndPopup();
            }
        }

        ImGui::TreePop();
    }*/

    return false;
}
<commit_msg>Add resource menu<commit_after>#include "ResourceView.hpp"

#include <Engine/Geometry/Model.hpp>
#include <Engine/Texture/TextureAsset.hpp>
#include <Engine/Audio/SoundBuffer.hpp>
#include <Engine/Script/ScriptFile.hpp>
#include <Engine/Util/FileSystem.hpp>
#include <Editor/Util/EditorSettings.hpp>
#include <Engine/Hymn.hpp>
#include <Engine/Entity/Entity.hpp>
#include <Engine/MainWindow.hpp>
#include <imgui.h>
#include <limits>
#include "../ImGui/Splitter.hpp"
#include <Engine/Manager/Managers.hpp>
#include <Engine/Manager/ResourceManager.hpp>
#include <cstdio>
#include <Utility/Log.hpp>

using namespace GUI;
using namespace std;

ResourceView::ResourceView() {

}

void ResourceView::Show() {
    ImVec2 size(MainWindow::GetInstance()->GetSize().x, MainWindow::GetInstance()->GetSize().y);

    // Splitter.
    ImGui::VerticalSplitter(ImVec2(sceneWidth, size.y - resourceHeight), size.x - sceneWidth - editorWidth, splitterSize, resourceHeight, resourceResize, 20, size.y - 20);
    if (resourceResize)
        resourceHeight = size.y - resourceHeight;

    ImGui::SetNextWindowPos(ImVec2(sceneWidth, size.y - resourceHeight));
    ImGui::SetNextWindowSize(ImVec2(size.x - sceneWidth - editorWidth, resourceHeight));

    ImGui::Begin("Resources", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_ShowBorders);

    // Show resources.
    scriptPressed = false;
    texturePressed = false;
    modelPressed = false;
    soundPressed = false;

    ShowResourceFolder(Resources().resourceFolder, Resources().resourceFolder.name);

    // Change scene.
    if (changeScene) {
        if (Hymn().GetPath() != "") {
            savePromptWindow.SetVisible(true);
            savePromptWindow.Show();

            switch (savePromptWindow.GetDecision()) {
            case 0:
                sceneEditor.Save();
                sceneEditor.SetVisible(true);
                sceneEditor.SetScene(scene);
                Resources().activeScene = resourcePath + "/" + *scene;
                sceneEditor.entityEditor.SetVisible(false);
                Hymn().world.Clear();
                Hymn().world.Load(Hymn().GetPath() + "/" + Resources().activeScene + ".json");
                changeScene = false;
                savePromptWindow.SetVisible(false);
                savePromptWindow.ResetDecision();
                break;

            case 1:
                sceneEditor.SetVisible(true);
                sceneEditor.SetScene(scene);
                Resources().activeScene = resourcePath + "/" + *scene;
                sceneEditor.entityEditor.SetVisible(false);
                Hymn().world.Clear();
                Hymn().world.Load(Hymn().GetPath() + "/" + Resources().activeScene + ".json");
                changeScene = false;
                savePromptWindow.SetVisible(false);
                savePromptWindow.ResetDecision();
                break;

            default:
                break;
            }
        }
    }

    if (sceneEditor.entityPressed || scriptPressed || texturePressed || modelPressed || soundPressed) {
        sceneEditor.entityEditor.SetVisible(sceneEditor.entityPressed);
        scriptEditor.SetVisible(scriptPressed);
        textureEditor.SetVisible(texturePressed);
        modelEditor.SetVisible(modelPressed);
        soundEditor.SetVisible(soundPressed);
    }

    if (sceneEditor.IsVisible()) {
        ImGui::HorizontalSplitter(ImVec2(sceneWidth, 20), size.y - 20, splitterSize, sceneWidth, sceneResize, 20, size.x - editorWidth - 20);
        ImGui::SetNextWindowPos(ImVec2(0, 20));
        ImGui::SetNextWindowSize(ImVec2(sceneWidth, size.y - 20));
        sceneEditor.Show();
    }

    if (sceneEditor.entityEditor.IsVisible() || scriptEditor.IsVisible() || textureEditor.IsVisible() || modelEditor.IsVisible() || soundEditor.IsVisible()) {
        editorWidth = size.x - editorWidth;
        ImGui::HorizontalSplitter(ImVec2(editorWidth, 20), size.y - 20, splitterSize, editorWidth, editorResize, sceneWidth + 20, size.x - 20);
        editorWidth = size.x - editorWidth;

        ImGui::SetNextWindowPos(ImVec2(size.x - editorWidth, 20));
        ImGui::SetNextWindowSize(ImVec2(editorWidth, size.y - 20));
    }

    if (sceneEditor.entityEditor.IsVisible())
        sceneEditor.entityEditor.Show();
    if (scriptEditor.IsVisible())
        scriptEditor.Show();
    if (textureEditor.IsVisible())
        textureEditor.Show();
    if (modelEditor.IsVisible())
        modelEditor.Show();
    if (soundEditor.IsVisible())
        soundEditor.Show();

    ImGui::End();
}

bool ResourceView::IsVisible() const {
    return visible;
}

void ResourceView::SetVisible(bool visible) {
    this->visible = visible;
}

void ResourceView::HideEditors() {
    sceneEditor.SetVisible(false);
    sceneEditor.entityEditor.SetVisible(false);
    scriptEditor.SetVisible(false);
    modelEditor.SetVisible(false);
    textureEditor.SetVisible(false);
    soundEditor.SetVisible(false);
}

void ResourceView::SaveScene() const {
    sceneEditor.Save();
}

#undef max
void ResourceView::ResetScene() {
    sceneEditor.SetScene(nullptr);
    sceneEditor.SetVisible(false);
}

SceneEditor& ResourceView::GetScene() {
    return sceneEditor;
}

void ResourceView::ShowResourceFolder(ResourceList::ResourceFolder& folder, const std::string& path) {
    bool opened = ImGui::TreeNode(folder.name.c_str());

    if (ImGui::BeginPopupContextItem(folder.name.c_str())) {
        /// @todo Add subfolder.
        if (ImGui::Selectable("Add folder")) {

        }

        /// @todo Add scene.
        if (ImGui::Selectable("Add scene")) {

        }

        /// @todo Add model.
        if (ImGui::Selectable("Add model")) {

        }

        /// @todo Add texture.
        if (ImGui::Selectable("Add texture")) {

        }

        /// @todo Add script.
        if (ImGui::Selectable("Add script")) {

        }

        /// @todo Add sound.
        if (ImGui::Selectable("Add sound")) {

        }

        /// @todo Remove folder.

        ImGui::EndPopup();
    }

    if (opened) {
        // Show subfolders.
        for (ResourceList::ResourceFolder& subfolder : folder.subfolders) {
            ShowResourceFolder(subfolder, path + "/" + subfolder.name);
        }

        // Show resources.
        for (auto it = folder.resources.begin(); it != folder.resources.end(); ++it) {
            if (ShowResource(*it, path)) {
                folder.resources.erase(it);
                return;
            }
        }

        ImGui::TreePop();
    }
}

bool ResourceView::ShowResource(ResourceList::Resource& resource, const std::string& path) {
    // Scene.
    if (resource.type == ResourceList::Resource::SCENE) {
        if (ImGui::Selectable(resource.scene.c_str())) {
            // Sets to don't save when opening first scene.
            if (scene == nullptr) {
                changeScene = true;
                resourcePath = path;
                scene = &resource.scene;
                savePromptWindow.SetVisible(false);
                savePromptWindow.SetDecision(1);
            } else {
                // Does so that the prompt window won't show if you select active scene.
                if (resource.scene != Resources().activeScene) {
                    changeScene = true;
                    resourcePath = path;
                    scene = &resource.scene;
                    savePromptWindow.SetTitle("Save before you switch scene?");
                }
            }
        }

        // Delete scene.
        if (ImGui::BeginPopupContextItem(resource.scene.c_str())) {
            if (ImGui::Selectable("Delete")) {
                if (Resources().activeScene == resource.scene) {
                    Resources().activeScene = "";
                    sceneEditor.SetScene(nullptr);
                }

                ImGui::EndPopup();

                return true;
            }
            ImGui::EndPopup();
        }
    }

    /*
    // Models.
    bool modelPressed = false;
    if (ImGui::TreeNode("Models")) {
        if (ImGui::Button("Add model")) {
            Geometry::Model* model = new Geometry::Model();
            model->name = "Model #" + std::to_string(Resources().modelNumber++);
            Resources().models.push_back(model);
        }

        for (auto it = Resources().models.begin(); it != Resources().models.end(); ++it) {
            Geometry::Model* model = *it;
            if (ImGui::Selectable(model->name.c_str())) {
                modelPressed = true;
                modelEditor.SetModel(model);
            }

            if (ImGui::BeginPopupContextItem(model->name.c_str())) {
                if (ImGui::Selectable("Delete")) {
                    if (modelEditor.GetModel() == model)
                        modelEditor.SetVisible(false);

                    delete model;
                    Resources().models.erase(it);
                    ImGui::EndPopup();
                    break;
                }
                ImGui::EndPopup();
            }
        }
        ImGui::TreePop();
    }

    // Textures.
    bool texturePressed = false;
    if (ImGui::TreeNode("Textures")) {
        if (ImGui::Button("Add texture")) {
            TextureAsset* texture = new TextureAsset();
            texture->name = "Texture #" + std::to_string(Resources().textureNumber++);
            Resources().textures.push_back(texture);
        }

        for (auto it = Resources().textures.begin(); it != Resources().textures.end(); ++it) {
            TextureAsset* texture = *it;
            if (ImGui::Selectable(texture->name.c_str())) {
                texturePressed = true;
                textureEditor.SetTexture(texture);
            }

            if (ImGui::BeginPopupContextItem(texture->name.c_str())) {
                if (ImGui::Selectable("Delete")) {
                    if (Managers().resourceManager->GetTextureAssetInstanceCount(texture) > 1) {
                        Log() << "This texture is in use. Remove all references to the texture first.\n";
                    } else {
                        if (textureEditor.GetTexture() == texture)
                            textureEditor.SetVisible(false);

                        // Remove files.
                        remove((Hymn().GetPath() + FileSystem::DELIMITER + "Textures" + FileSystem::DELIMITER + texture->name + ".png").c_str());
                        remove((Hymn().GetPath() + FileSystem::DELIMITER + "Textures" + FileSystem::DELIMITER + texture->name + ".json").c_str());

                        Managers().resourceManager->FreeTextureAsset(texture);
                        Resources().textures.erase(it);
                    }
                    ImGui::EndPopup();
                    break;
                }
                ImGui::EndPopup();
            }
        }

        ImGui::TreePop();
    }

    // Scripts.
    bool scriptPressed = false;
    if (ImGui::TreeNode("Scripts")) {
        if (ImGui::Button("Add script")) {
            ScriptFile* scriptFile = new ScriptFile();
            scriptFile->name = "Script #" + std::to_string(Hymn().scriptNumber++);
            Hymn().scripts.push_back(scriptFile);
        }

        for (auto it = Hymn().scripts.begin(); it != Hymn().scripts.end(); ++it) {
            ScriptFile* script = *it;
            std::string name = script->name;

            if (ImGui::Selectable(name.c_str())) {
                scriptPressed = true;
                scriptEditor.SetScript(script);
            }

            if (ImGui::BeginPopupContextItem(name.c_str())) {
                if (ImGui::Selectable("Delete")) {
                    if (scriptEditor.GetScript() == script)
                        scriptEditor.SetVisible(false);

                    delete script;
                    Hymn().scripts.erase(it);
                    ImGui::EndPopup();
                    break;
                }
                ImGui::EndPopup();
            }
        }

        ImGui::TreePop();
    }

    // Sounds.
    bool soundPressed = false;
    if (ImGui::TreeNode("Sounds")) {
        if (ImGui::Button("Add sound")) {
            Audio::SoundBuffer* sound = new Audio::SoundBuffer();
            sound->name = "Sound #" + std::to_string(Resources().soundNumber++);
            Resources().sounds.push_back(sound);
        }

        for (auto it = Resources().sounds.begin(); it != Resources().sounds.end(); ++it) {
            Audio::SoundBuffer* sound = *it;
            if (ImGui::Selectable(sound->name.c_str())) {
                soundPressed = true;
                soundEditor.SetSound(sound);
            }

            if (ImGui::BeginPopupContextItem(sound->name.c_str())) {
                if (ImGui::Selectable("Delete")) {
                    if (soundEditor.GetSound() == sound)
                        soundEditor.SetVisible(false);

                    delete sound;
                    Resources().sounds.erase(it);
                    ImGui::EndPopup();
                    break;
                }
                ImGui::EndPopup();
            }
        }

        ImGui::TreePop();
    }*/

    return false;
}
<|endoftext|>