<commit_before>//===-- SBAddress.cpp -------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/API/SBAddress.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBSection.h"
#include "lldb/API/SBStream.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Target/Target.h"

using namespace lldb;
using namespace lldb_private;

SBAddress::SBAddress () :
    m_opaque_ap ()
{
}

SBAddress::SBAddress (const Address *lldb_object_ptr) :
    m_opaque_ap ()
{
    if (lldb_object_ptr)
        ref() = *lldb_object_ptr;
}

SBAddress::SBAddress (const SBAddress &rhs) :
    m_opaque_ap ()
{
    if (rhs.IsValid())
        ref() = rhs.ref();
}

SBAddress::SBAddress (lldb::SBSection section, lldb::addr_t offset) :
    m_opaque_ap(new Address (section.GetSP(), offset))
{
}

// Create an address by resolving a load address using the supplied target
SBAddress::SBAddress (lldb::addr_t load_addr, lldb::SBTarget &target) :
    m_opaque_ap()
{
    SetLoadAddress (load_addr, target);
}

SBAddress::~SBAddress ()
{
}

const SBAddress &
SBAddress::operator = (const SBAddress &rhs)
{
    if (this != &rhs)
    {
        if (rhs.IsValid())
            ref() = rhs.ref();
        else
            m_opaque_ap.reset();
    }
    return *this;
}

bool
SBAddress::IsValid () const
{
    return m_opaque_ap.get() != NULL && m_opaque_ap->IsValid();
}

void
SBAddress::Clear ()
{
    m_opaque_ap.reset();
}

void
SBAddress::SetAddress (lldb::SBSection section, lldb::addr_t offset)
{
    Address &addr = ref();
    addr.SetSection (section.GetSP());
    addr.SetOffset (offset);
}

void
SBAddress::SetAddress (const Address *lldb_object_ptr)
{
    if (lldb_object_ptr)
        ref() =  *lldb_object_ptr;
    else
        m_opaque_ap.reset();
}

lldb::addr_t
SBAddress::GetFileAddress () const
{
    if (m_opaque_ap.get())
        return m_opaque_ap->GetFileAddress();
    else
        return LLDB_INVALID_ADDRESS;
}

lldb::addr_t
SBAddress::GetLoadAddress (const SBTarget &target) const
{
    LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));

    lldb::addr_t addr = LLDB_INVALID_ADDRESS;
    TargetSP target_sp (target.GetSP());
    if (m_opaque_ap.get())
    {
        Mutex::Locker api_locker (target_sp->GetAPIMutex());
        addr = m_opaque_ap->GetLoadAddress (target_sp.get());
    }

    if (log)
    {
        if (addr == LLDB_INVALID_ADDRESS)
            log->Printf ("SBAddress::GetLoadAddress (SBTarget(%p)) => LLDB_INVALID_ADDRESS", target_sp.get());
        else
            log->Printf ("SBAddress::GetLoadAddress (SBTarget(%p)) => 0x%llx", target_sp.get(), addr);
    }

    return addr;
}

void
SBAddress::SetLoadAddress (lldb::addr_t load_addr, lldb::SBTarget &target)
{
    // Create the address object if we don't already have one
    ref();
    if (target.IsValid())
        *this = target.ResolveLoadAddress(load_addr);
    else
        m_opaque_ap->Clear();

    // Check if we weren't were able to resolve a section offset address.
    // If we weren't it is ok, the load address might be a location on the
    // stack or heap, so we should just have an address with no section and
    // a valid offset
    if (!m_opaque_ap->IsValid())
        m_opaque_ap->SetOffset(load_addr);
}

bool
SBAddress::OffsetAddress (addr_t offset)
{
    if (m_opaque_ap.get())
    {
        addr_t addr_offset = m_opaque_ap->GetOffset();
        if (addr_offset != LLDB_INVALID_ADDRESS)
        {
            m_opaque_ap->SetOffset(addr_offset + offset);
            return true;
        }
    }
    return false;
}

lldb::SBSection
SBAddress::GetSection ()
{
    lldb::SBSection sb_section;
    if (m_opaque_ap.get())
        sb_section.SetSP (m_opaque_ap->GetSection());
    return sb_section;
}

lldb::addr_t
SBAddress::GetOffset ()
{
    if (m_opaque_ap.get())
        m_opaque_ap->GetOffset();
    return 0;
}

Address *
SBAddress::operator->()
{
    return m_opaque_ap.get();
}

const Address *
SBAddress::operator->() const
{
    return m_opaque_ap.get();
}

Address &
SBAddress::ref ()
{
    if (m_opaque_ap.get() == NULL)
        m_opaque_ap.reset (new Address());
    return *m_opaque_ap;
}

const Address &
SBAddress::ref () const
{
    // This object should already have checked with "IsValid()"
    // prior to calling this function. In case you didn't we will assert
    // and die to let you know.
    assert (m_opaque_ap.get());
    return *m_opaque_ap;
}

Address *
SBAddress::get ()
{
    return m_opaque_ap.get();
}

bool
SBAddress::GetDescription (SBStream &description)
{
    // Call "ref()" on the stream to make sure it creates a backing stream in
    // case there isn't one already...
    Stream &strm = description.ref();
    if (m_opaque_ap.get())
    {
        m_opaque_ap->Dump (&strm,
                           NULL,
                           Address::DumpStyleResolvedDescription,
                           Address::DumpStyleModuleWithFileAddress,
                           4);
        StreamString sstrm;
//        m_opaque_ap->Dump (&sstrm, NULL, Address::DumpStyleResolvedDescription, Address::DumpStyleInvalid, 4);
//        if (sstrm.GetData())
//            strm.Printf (" (%s)", sstrm.GetData());
    }
    else
        strm.PutCString ("No value");

    return true;
}

SBModule
SBAddress::GetModule ()
{
    SBModule sb_module;
    if (m_opaque_ap.get())
        sb_module.SetSP (m_opaque_ap->GetModule());
    return sb_module;
}

SBSymbolContext
SBAddress::GetSymbolContext (uint32_t resolve_scope)
{
    SBSymbolContext sb_sc;
    if (m_opaque_ap.get())
        m_opaque_ap->CalculateSymbolContext (&sb_sc.ref(), resolve_scope);
    return sb_sc;
}

SBCompileUnit
SBAddress::GetCompileUnit ()
{
    SBCompileUnit sb_comp_unit;
    if (m_opaque_ap.get())
        sb_comp_unit.reset(m_opaque_ap->CalculateSymbolContextCompileUnit());
    return sb_comp_unit;
}

SBFunction
SBAddress::GetFunction ()
{
    SBFunction sb_function;
    if (m_opaque_ap.get())
        sb_function.reset(m_opaque_ap->CalculateSymbolContextFunction());
    return sb_function;
}

SBBlock
SBAddress::GetBlock ()
{
    SBBlock sb_block;
    if (m_opaque_ap.get())
        sb_block.SetPtr(m_opaque_ap->CalculateSymbolContextBlock());
    return sb_block;
}

SBSymbol
SBAddress::GetSymbol ()
{
    SBSymbol sb_symbol;
    if (m_opaque_ap.get())
        sb_symbol.reset(m_opaque_ap->CalculateSymbolContextSymbol());
    return sb_symbol;
}

SBLineEntry
SBAddress::GetLineEntry ()
{
    SBLineEntry sb_line_entry;
    if (m_opaque_ap.get())
    {
        LineEntry line_entry;
        if (m_opaque_ap->CalculateSymbolContextLineEntry (line_entry))
            sb_line_entry.SetLineEntry (line_entry);
    }
    return sb_line_entry;
}

AddressClass
SBAddress::GetAddressClass ()
{
    if (m_opaque_ap.get())
        return m_opaque_ap->GetAddressClass();
    return eAddressClassInvalid;
}

<commit_msg><rdar://problem/12524810><commit_after>//===-- SBAddress.cpp -------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/API/SBAddress.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBSection.h"
#include "lldb/API/SBStream.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Target/Target.h"

using namespace lldb;
using namespace lldb_private;

SBAddress::SBAddress () :
    m_opaque_ap ()
{
}

SBAddress::SBAddress (const Address *lldb_object_ptr) :
    m_opaque_ap ()
{
    if (lldb_object_ptr)
        ref() = *lldb_object_ptr;
}

SBAddress::SBAddress (const SBAddress &rhs) :
    m_opaque_ap ()
{
    if (rhs.IsValid())
        ref() = rhs.ref();
}

SBAddress::SBAddress (lldb::SBSection section, lldb::addr_t offset) :
    m_opaque_ap(new Address (section.GetSP(), offset))
{
}

// Create an address by resolving a load address using the supplied target
SBAddress::SBAddress (lldb::addr_t load_addr, lldb::SBTarget &target) :
    m_opaque_ap()
{
    SetLoadAddress (load_addr, target);
}

SBAddress::~SBAddress ()
{
}

const SBAddress &
SBAddress::operator = (const SBAddress &rhs)
{
    if (this != &rhs)
    {
        if (rhs.IsValid())
            ref() = rhs.ref();
        else
            m_opaque_ap.reset();
    }
    return *this;
}

bool
SBAddress::IsValid () const
{
    return m_opaque_ap.get() != NULL && m_opaque_ap->IsValid();
}

void
SBAddress::Clear ()
{
    m_opaque_ap.reset();
}

void
SBAddress::SetAddress (lldb::SBSection section, lldb::addr_t offset)
{
    Address &addr = ref();
    addr.SetSection (section.GetSP());
    addr.SetOffset (offset);
}

void
SBAddress::SetAddress (const Address *lldb_object_ptr)
{
    if (lldb_object_ptr)
        ref() =  *lldb_object_ptr;
    else
        m_opaque_ap.reset();
}

lldb::addr_t
SBAddress::GetFileAddress () const
{
    if (m_opaque_ap.get())
        return m_opaque_ap->GetFileAddress();
    else
        return LLDB_INVALID_ADDRESS;
}

lldb::addr_t
SBAddress::GetLoadAddress (const SBTarget &target) const
{
    LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));

    lldb::addr_t addr = LLDB_INVALID_ADDRESS;
    TargetSP target_sp (target.GetSP());
    if (target_sp)
    {
        if (m_opaque_ap.get())
        {
            Mutex::Locker api_locker (target_sp->GetAPIMutex());
            addr = m_opaque_ap->GetLoadAddress (target_sp.get());
        }
    }

    if (log)
    {
        if (addr == LLDB_INVALID_ADDRESS)
            log->Printf ("SBAddress::GetLoadAddress (SBTarget(%p)) => LLDB_INVALID_ADDRESS", target_sp.get());
        else
            log->Printf ("SBAddress::GetLoadAddress (SBTarget(%p)) => 0x%llx", target_sp.get(), addr);
    }

    return addr;
}

void
SBAddress::SetLoadAddress (lldb::addr_t load_addr, lldb::SBTarget &target)
{
    // Create the address object if we don't already have one
    ref();
    if (target.IsValid())
        *this = target.ResolveLoadAddress(load_addr);
    else
        m_opaque_ap->Clear();

    // Check if we weren't were able to resolve a section offset address.
    // If we weren't it is ok, the load address might be a location on the
    // stack or heap, so we should just have an address with no section and
    // a valid offset
    if (!m_opaque_ap->IsValid())
        m_opaque_ap->SetOffset(load_addr);
}

bool
SBAddress::OffsetAddress (addr_t offset)
{
    if (m_opaque_ap.get())
    {
        addr_t addr_offset = m_opaque_ap->GetOffset();
        if (addr_offset != LLDB_INVALID_ADDRESS)
        {
            m_opaque_ap->SetOffset(addr_offset + offset);
            return true;
        }
    }
    return false;
}

lldb::SBSection
SBAddress::GetSection ()
{
    lldb::SBSection sb_section;
    if (m_opaque_ap.get())
        sb_section.SetSP (m_opaque_ap->GetSection());
    return sb_section;
}

lldb::addr_t
SBAddress::GetOffset ()
{
    if (m_opaque_ap.get())
        m_opaque_ap->GetOffset();
    return 0;
}

Address *
SBAddress::operator->()
{
    return m_opaque_ap.get();
}

const Address *
SBAddress::operator->() const
{
    return m_opaque_ap.get();
}

Address &
SBAddress::ref ()
{
    if (m_opaque_ap.get() == NULL)
        m_opaque_ap.reset (new Address());
    return *m_opaque_ap;
}

const Address &
SBAddress::ref () const
{
    // This object should already have checked with "IsValid()"
    // prior to calling this function. In case you didn't we will assert
    // and die to let you know.
    assert (m_opaque_ap.get());
    return *m_opaque_ap;
}

Address *
SBAddress::get ()
{
    return m_opaque_ap.get();
}

bool
SBAddress::GetDescription (SBStream &description)
{
    // Call "ref()" on the stream to make sure it creates a backing stream in
    // case there isn't one already...
    Stream &strm = description.ref();
    if (m_opaque_ap.get())
    {
        m_opaque_ap->Dump (&strm,
                           NULL,
                           Address::DumpStyleResolvedDescription,
                           Address::DumpStyleModuleWithFileAddress,
                           4);
        StreamString sstrm;
//        m_opaque_ap->Dump (&sstrm, NULL, Address::DumpStyleResolvedDescription, Address::DumpStyleInvalid, 4);
//        if (sstrm.GetData())
//            strm.Printf (" (%s)", sstrm.GetData());
    }
    else
        strm.PutCString ("No value");

    return true;
}

SBModule
SBAddress::GetModule ()
{
    SBModule sb_module;
    if (m_opaque_ap.get())
        sb_module.SetSP (m_opaque_ap->GetModule());
    return sb_module;
}

SBSymbolContext
SBAddress::GetSymbolContext (uint32_t resolve_scope)
{
    SBSymbolContext sb_sc;
    if (m_opaque_ap.get())
        m_opaque_ap->CalculateSymbolContext (&sb_sc.ref(), resolve_scope);
    return sb_sc;
}

SBCompileUnit
SBAddress::GetCompileUnit ()
{
    SBCompileUnit sb_comp_unit;
    if (m_opaque_ap.get())
        sb_comp_unit.reset(m_opaque_ap->CalculateSymbolContextCompileUnit());
    return sb_comp_unit;
}

SBFunction
SBAddress::GetFunction ()
{
    SBFunction sb_function;
    if (m_opaque_ap.get())
        sb_function.reset(m_opaque_ap->CalculateSymbolContextFunction());
    return sb_function;
}

SBBlock
SBAddress::GetBlock ()
{
    SBBlock sb_block;
    if (m_opaque_ap.get())
        sb_block.SetPtr(m_opaque_ap->CalculateSymbolContextBlock());
    return sb_block;
}

SBSymbol
SBAddress::GetSymbol ()
{
    SBSymbol sb_symbol;
    if (m_opaque_ap.get())
        sb_symbol.reset(m_opaque_ap->CalculateSymbolContextSymbol());
    return sb_symbol;
}

SBLineEntry
SBAddress::GetLineEntry ()
{
    SBLineEntry sb_line_entry;
    if (m_opaque_ap.get())
    {
        LineEntry line_entry;
        if (m_opaque_ap->CalculateSymbolContextLineEntry (line_entry))
            sb_line_entry.SetLineEntry (line_entry);
    }
    return sb_line_entry;
}

AddressClass
SBAddress::GetAddressClass ()
{
    if (m_opaque_ap.get())
        return m_opaque_ap->GetAddressClass();
    return eAddressClassInvalid;
}

<|endoftext|>


<commit_before>// FT_gl_demo.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdlib.h>
#include <GL/glut.h>

#include <ft2build.h>
#include FT_FREETYPE_H
#include <freetype/freetype.h>
#include <freetype/ftglyph.h>

#include <iostream>
#include <FTGL/ftgl.h>

using namespace std;

const char* FontLibFilePath = "C:\\Pub\\FontLib\\SourceHanSansCN\\SourceHanSansCN-Light.otf";

static void keyboard(unsigned char key, int x, int y);
static void display(void);

FTGLPixmapFont *freeTypeFont = NULL;

void init(void)
{
	glShadeModel(GL_SMOOTH); // Enable Shadow Smooth Mode
	glClearDepth(1.0f); // Set Buffer Depth
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);

	// Initialize FTGL
	freeTypeFont = new FTGLPixmapFont(FontLibFilePath);

}

int main(int argc, char* argv[])
{
	glutInit(&argc, argv);
	glutCreateWindow("GLUT Test");
	glutKeyboardFunc(&keyboard);
	glutDisplayFunc(&display);
	glutMainLoop();

	return 0;
}

static void keyboard(unsigned char key, int x, int y)
{
	switch (key)
	{
	case '\x1B':
		exit(EXIT_SUCCESS);
		break;
	}
}

static void display()
{
	glClear(GL_COLOR_BUFFER_BIT);

	glColor3f(1.0f, 0.0f, 0.0f);

	glBegin(GL_POLYGON);
	glVertex2f(-0.5f, -0.5f);
	glVertex2f(0.5f, -0.5f);
	glVertex2f(0.5f, 0.5f);
	glVertex2f(-0.5f, 0.5f);
	glEnd();

	glFlush();
}

<commit_msg>[FTGL] multilingual display<commit_after>// FT_gl_demo.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdlib.h>
#include <GL/glut.h>

#include <ft2build.h>
#include FT_FREETYPE_H
#include <freetype/freetype.h>
#include <freetype/ftglyph.h>

#include <iostream>
#include <FTGL/ftgl.h>

using namespace std;

const char* FontLibFilePath = "C:\\Pub\\FontLib\\SourceHanSansCN\\SourceHanSansCN-Light.otf";

static void keyboard(unsigned char key, int x, int y);
static void display(void);

FTGLPixmapFont *freeTypeFont = NULL;
wchar_t str[128] = L"FTGL 中文输出测试";

void init(void)
{
	glShadeModel(GL_SMOOTH); // Enable Shadow Smooth Mode
	glClearDepth(1.0f); // Set Buffer Depth
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);

	// Initialize FTGL
	freeTypeFont = new FTGLPixmapFont(FontLibFilePath);
	if (freeTypeFont == NULL)
	{
		printf("%s", "Font lib data file cannot be loaded.");
		exit(0);
	}
	else
	{
		freeTypeFont->FaceSize(24); // <-- !!!
	}
}

void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 10.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
	glRasterPos2f(0.2, 0.5);
	freeTypeFont->Render(str);

	glutSwapBuffers();
}

void reshape(int w, int h)
{
	glViewport(0, 0, (GLsizei)w, (GLsizei)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0, (GLdouble)w / (GLdouble)h, 1.0, 10.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glutPostRedisplay();
}

int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(600, 600);
	glutInitWindowPosition(100, 100);
	glutCreateWindow("FreeType multilingual display");
	init();
	glutReshapeFunc(reshape);
	glutDisplayFunc(display);
	glutMainLoop();
	return 0;
}

static void keyboard(unsigned char key, int x, int y)
{
	switch (key)
	{
	case '\x1B':
		exit(EXIT_SUCCESS);
		break;
	}
}

<|endoftext|>


<commit_before>/*
 * opencog/benchmark/BenchmarkModule.cc
 *
 * Copyright (C) 2014 Cosmo Harrigan
 * All Rights Reserved
 *
 * Written by Cosmo Harrigan
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * 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 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, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "BenchmarkModule.h"

#include <opencog/server/CogServer.h>
#include <opencog/util/Logger.h>
#include <opencog/util/Config.h>
#include <opencog/util/oc_omp.h>
#include <opencog/dynamics/attention/atom_types.h>
#include <opencog/atomspace/SimpleTruthValue.h>
#include <boost/range/irange.hpp>
#include <iostream>
#include <thread>
#include <iomanip>
#include <time.h>
#include <future>

using namespace std;
using namespace opencog;

DECLARE_MODULE(BenchmarkModule)

BenchmarkModule::BenchmarkModule(CogServer& cs) : Module(cs)
{
    logger().info("[BenchmarkModule] constructor");
    this->as = &cs.getAtomSpace();

    do_fullyConnectedTest_register();
}

void BenchmarkModule::init(void)
{
    logger().info("Initializing BenchmarkModule.");
}

void BenchmarkModule::run()
{
}

BenchmarkModule::~BenchmarkModule()
{
    logger().info("Terminating BenchmarkModule.");

    do_fullyConnectedTest_unregister();
}

int BenchmarkModule::fullyConnectedTestConcurrent(int numAtoms)
{
    // Multithreaded using GNU libstdc++ parallel mode
    // Add numAtoms ConceptNodes
    auto ir = boost::irange((size_t)0, (size_t)numAtoms);
    vector<size_t> indices(ir.begin(), ir.end());

    OMP_ALGO::for_each(indices.begin(), indices.end(), [&as](int index)
    {
        as->addPrefixedNode(CONCEPT_NODE, "test_atom_");
    });

    // Retrieve all the ConceptNodes into an iterator
    HandleSeq atoms;
    as->getHandlesByType(back_inserter(atoms), CONCEPT_NODE);

    // Create a fully connected graph between them with bidirectional directed
    // edges: requires n^2 - n edges
    OMP_ALGO::for_each(atoms.begin(), atoms.end(),
        [&atoms, &as](Handle handleSource)
    {
        for_each(atoms.begin(), atoms.end(),
            [&handleSource, &as](Handle handleTarget)
        {
            as->addLink(ASYMMETRIC_HEBBIAN_LINK, handleSource, handleTarget);
        });
    });

    return atoms.size();
}

std::string BenchmarkModule
::do_fullyConnectedTest(Request *dummy, std::list<std::string> args)
{
    std::vector<std::string> argv{ std::begin(args), std::end(args) };

    std::string option = argv.size() > 0 ? argv[0] : "concurrent";

    int numNewNodes;
    try
    {
        numNewNodes = argv.size() > 1 ? std::stoi(argv[1]) : 500;
    }
    catch(std::invalid_argument& e)
    {
        return "Error: argument COUNT must be an integer.\n";
    }

    int numThreads;
    try
    {
        // User can specify the number of threads. Otherwise, defaults to 2
        numThreads = argv.size() > 2 ? std::stoi(argv[2]) : 2;
    }
    catch(std::invalid_argument& e)
    {
        return "Error: argument THREADS must be an integer.\n";
    }
    // Set the number of threads for OpenMP parallelization
    setting_omp(numThreads);

    const clock_t begin_time_cpu = clock();
    const time_t begin_time_wall = time(NULL);

    int numNodes;

    if (option == "reset")
    {
        // Delete all ConceptNodes and their incoming sets
        HandleSeq atoms;
        as->getHandlesByType(back_inserter(atoms), CONCEPT_NODE);

        OMP_ALGO::for_each(atoms.begin(), atoms.end(),
            [&as](Handle handle)
        {
            as->deleteAtom(handle, true);
        });

        return "All ConceptNodes and their incoming sets deleted.\n";
    }
    else if (option == "concurrent")
    {
        numNodes = fullyConnectedTestConcurrent(numNewNodes);
    }
    else
    {
        return "Error, unrecognized argument. Usage:\n"
               "  benchmark-fully-connected OPTION COUNT THREADS\n"
               "where OPTION is 'concurrent' or 'reset', COUNT is an integer "
               "number of nodes,\nand THREADS is an integer number of threads. "
               "If no arguments are specified,\ndefaults to:\n"
               "  concurrent 500 2\n";
    }

    const clock_t end_time_cpu = clock();
    const time_t end_time_wall = time(NULL);

    std::string message;
    message =
        "Test complete. Fully connected graph of " +
        std::to_string(numNodes) +
        " total nodes including " +
        std::to_string(numNewNodes) +
        " new nodes.\nWall clock time: " +
        std::to_string(end_time_wall - begin_time_wall) +
        " seconds\nCPU clock time: " +
        std::to_string((end_time_cpu - begin_time_cpu) / CLOCKS_PER_SEC) +
        " seconds\nNumber of threads used: " +
        std::to_string(numThreads) + "\n";
    return message;
}
<commit_msg>Fix some closure compile errors on gcc 4.7.3<commit_after>/*
 * opencog/benchmark/BenchmarkModule.cc
 *
 * Copyright (C) 2014 Cosmo Harrigan
 * All Rights Reserved
 *
 * Written by Cosmo Harrigan
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * 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 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, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "BenchmarkModule.h"

#include <opencog/server/CogServer.h>
#include <opencog/util/Logger.h>
#include <opencog/util/Config.h>
#include <opencog/util/oc_omp.h>
#include <opencog/dynamics/attention/atom_types.h>
#include <opencog/atomspace/SimpleTruthValue.h>
#include <boost/range/irange.hpp>
#include <iostream>
#include <thread>
#include <iomanip>
#include <time.h>
#include <future>

using namespace std;
using namespace opencog;

DECLARE_MODULE(BenchmarkModule)

BenchmarkModule::BenchmarkModule(CogServer& cs) : Module(cs)
{
    logger().info("[BenchmarkModule] constructor");
    this->as = &cs.getAtomSpace();

    do_fullyConnectedTest_register();
}

void BenchmarkModule::init(void)
{
    logger().info("Initializing BenchmarkModule.");
}

void BenchmarkModule::run()
{
}

BenchmarkModule::~BenchmarkModule()
{
    logger().info("Terminating BenchmarkModule.");

    do_fullyConnectedTest_unregister();
}

int BenchmarkModule::fullyConnectedTestConcurrent(int numAtoms)
{
    // Multithreaded using GNU libstdc++ parallel mode
    // Add numAtoms ConceptNodes
    auto ir = boost::irange((size_t)0, (size_t)numAtoms);
    vector<size_t> indices(ir.begin(), ir.end());

    OMP_ALGO::for_each(indices.begin(), indices.end(), [this](int index)
    {
        as->addPrefixedNode(CONCEPT_NODE, "test_atom_");
    });

    // Retrieve all the ConceptNodes into an iterator
    HandleSeq atoms;
    as->getHandlesByType(back_inserter(atoms), CONCEPT_NODE);

    // Create a fully connected graph between them with bidirectional directed
    // edges: requires n^2 - n edges
    OMP_ALGO::for_each(atoms.begin(), atoms.end(),
    [&atoms, this](Handle handleSource)
    {
        for_each(atoms.begin(), atoms.end(),
            [&handleSource, this](Handle handleTarget)
        {
            as->addLink(ASYMMETRIC_HEBBIAN_LINK, handleSource, handleTarget);
        });
    });

    return atoms.size();
}

std::string BenchmarkModule
::do_fullyConnectedTest(Request *dummy, std::list<std::string> args)
{
    std::vector<std::string> argv{ std::begin(args), std::end(args) };

    std::string option = argv.size() > 0 ? argv[0] : "concurrent";

    int numNewNodes;
    try
    {
        numNewNodes = argv.size() > 1 ? std::stoi(argv[1]) : 500;
    }
    catch(std::invalid_argument& e)
    {
        return "Error: argument COUNT must be an integer.\n";
    }

    int numThreads;
    try
    {
        // User can specify the number of threads. Otherwise, defaults to 2
        numThreads = argv.size() > 2 ? std::stoi(argv[2]) : 2;
    }
    catch(std::invalid_argument& e)
    {
        return "Error: argument THREADS must be an integer.\n";
    }
    // Set the number of threads for OpenMP parallelization
    setting_omp(numThreads);

    const clock_t begin_time_cpu = clock();
    const time_t begin_time_wall = time(NULL);

    int numNodes;

    if (option == "reset")
    {
        // Delete all ConceptNodes and their incoming sets
        HandleSeq atoms;
        as->getHandlesByType(back_inserter(atoms), CONCEPT_NODE);

        OMP_ALGO::for_each(atoms.begin(), atoms.end(),
            [this](Handle handle)
        {
            as->deleteAtom(handle, true);
        });

        return "All ConceptNodes and their incoming sets deleted.\n";
    }
    else if (option == "concurrent")
    {
        numNodes = fullyConnectedTestConcurrent(numNewNodes);
    }
    else
    {
        return "Error, unrecognized argument. Usage:\n"
               "  benchmark-fully-connected OPTION COUNT THREADS\n"
               "where OPTION is 'concurrent' or 'reset', COUNT is an integer "
               "number of nodes,\nand THREADS is an integer number of threads. "
               "If no arguments are specified,\ndefaults to:\n"
               "  concurrent 500 2\n";
    }

    const clock_t end_time_cpu = clock();
    const time_t end_time_wall = time(NULL);

    std::string message;
    message =
        "Test complete. Fully connected graph of " +
        std::to_string(numNodes) +
        " total nodes including " +
        std::to_string(numNewNodes) +
        " new nodes.\nWall clock time: " +
        std::to_string(end_time_wall - begin_time_wall) +
        " seconds\nCPU clock time: " +
        std::to_string((end_time_cpu - begin_time_cpu) / CLOCKS_PER_SEC) +
        " seconds\nNumber of threads used: " +
        std::to_string(numThreads) + "\n";
    return message;
}
<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "DebugOperatorNew.h"
#include "EC_DynamicComponent.h"

#include "SceneAPI.h"

#include "Entity.h"
#include "LoggingFunctions.h"
#include "Scene.h"

#include <QScriptEngine>
#include <QScriptValueIterator>

#include <kNet.h>

#include <QDomDocument>

#include "MemoryLeakCheck.h"

struct DeserializeData
{
    DeserializeData(const QString &name = "", const QString &type = "", const QString &value = ""):
        name_(name),
        type_(type),
        value_(value)
    {
    }

    /// Checks if any of data structure's values are null.
    bool isNull() const
    {
        return name_ == "" || type_ == "" || value_ == "";
    }

    QString name_;
    QString type_;
    QString value_;
};

/// Function that is used by std::sort algorithm to sort attributes by their name.
bool CmpAttributeByName(const IAttribute *a, const IAttribute *b)
{
    return a->Name() < b->Name();
}

/// Function that is used by std::sort algorithm to sort DeserializeData by their name.
bool CmpAttributeDataByName(const DeserializeData &a, const DeserializeData &b)
{
    return a.name_ < b.name_;
}

EC_DynamicComponent::EC_DynamicComponent(Scene* scene):
    IComponent(scene)
{
}

EC_DynamicComponent::~EC_DynamicComponent()
{
}

void EC_DynamicComponent::SerializeTo(QDomDocument& doc, QDomElement& base_element) const
{
    QDomElement comp_element = BeginSerialization(doc, base_element);

    AttributeVector::const_iterator iter = attributes.begin();
    while(iter != attributes.end())
    {
        if (*iter)
            WriteAttribute(doc, comp_element, (*iter)->Name(), (*iter)->ToString().c_str(), (*iter)->TypeName());
        ++iter;
    }
}

void EC_DynamicComponent::DeserializeFrom(QDomElement& element, AttributeChange::Type change)
{
    if (!BeginDeserialization(element))
        return;

    std::vector<DeserializeData> deserializedAttributes;
    QDomElement child = element.firstChildElement("attribute");
    while(!child.isNull())
    {
        QString name = child.attribute("name");
        QString type = child.attribute("type");
        QString value = child.attribute("value");
        DeserializeData attributeData(name, type, value);
        deserializedAttributes.push_back(attributeData);

        child = child.nextSiblingElement("attribute");
    }

    DeserializeCommon(deserializedAttributes, change);
}

void EC_DynamicComponent::DeserializeCommon(std::vector<DeserializeData>& deserializedAttributes, AttributeChange::Type change)
{
    // Sort both lists in alphabetical order.
    AttributeVector oldAttributes = NonEmptyAttributes();
    std::stable_sort(oldAttributes.begin(), oldAttributes.end(), &CmpAttributeByName);
    std::stable_sort(deserializedAttributes.begin(), deserializedAttributes.end(), &CmpAttributeDataByName);

    std::vector<DeserializeData> addAttributes;
    std::vector<DeserializeData> remAttributes;
    AttributeVector::iterator iter1 = oldAttributes.begin();
    std::vector<DeserializeData>::iterator iter2 = deserializedAttributes.begin();

    // Check what attributes we need to add or remove from the dynamic component (done by comparing two list differences).
    while(iter1 != oldAttributes.end() || iter2 != deserializedAttributes.end())
    {
        // No point to continue the iteration if other list is empty. We can just push all new attributes into the dynamic component.
        if(iter1 == oldAttributes.end())
        {
            for(;iter2 != deserializedAttributes.end(); ++iter2)
                addAttributes.push_back(*iter2);
            break;
        }
        // Only old attributes are left and they can be removed from the dynamic component.
        else if(iter2 == deserializedAttributes.end())
        {
            for(;iter1 != oldAttributes.end(); ++iter1)
                remAttributes.push_back(DeserializeData((*iter1)->Name()));
            break;
        }

        // Attribute has already created and we only need to update it's value.
        if((*iter1)->Name() == (*iter2).name_)
        {
            //SetAttribute(QString::fromStdString(iter2->name_), QString::fromStdString(iter2->value_), change);
            for(AttributeVector::const_iterator attr_iter = attributes.begin(); attr_iter != attributes.end(); ++attr_iter)
                if((*attr_iter)->Name() == iter2->name_)
                    (*attr_iter)->FromString(iter2->value_.toStdString(), change);

            ++iter2;
            ++iter1;
        }
        // Found a new attribute that need to be created and added to the component.
        else if((*iter1)->Name() > (*iter2).name_)
        {
            addAttributes.push_back(*iter2);
            ++iter2;
        }
        // Couldn't find the attribute in a new list so it need to be removed from the component.
        else
        {
            remAttributes.push_back(DeserializeData((*iter1)->Name()));
            ++iter1;
        }
    }

    while(!addAttributes.empty())
    {
        DeserializeData attributeData = addAttributes.back();
        IAttribute *attribute = CreateAttribute(attributeData.type_, attributeData.name_);
        if (attribute)
            attribute->FromString(attributeData.value_.toStdString(), change);
        addAttributes.pop_back();
    }
    while(!remAttributes.empty())
    {
        DeserializeData attributeData = remAttributes.back();
        RemoveAttribute(attributeData.name_);
        remAttributes.pop_back();
    }
}

IAttribute *EC_DynamicComponent::CreateAttribute(const QString &typeName, const QString &name, AttributeChange::Type change)
{
    if(ContainsAttribute(name))
        return IComponent::GetAttribute(name);

    IAttribute *attribute = SceneAPI::CreateAttribute(typeName, name);
    if(!attribute)
    {
        LogError("Failed to create new attribute:" + name + " in dynamic component:" + Name());
        return 0;
    }

    IComponent::AddAttribute(attribute);

    // Trigger scenemanager signal
    Scene* scene = ParentScene();
    if (scene)
        scene->EmitAttributeAdded(this, attribute, change);

    // Trigger internal signal
    emit AttributeAdded(attribute);
    EmitAttributeChanged(attribute, change);
    return attribute;
}

void EC_DynamicComponent::RemoveAttribute(const QString &name, AttributeChange::Type change)
{
    for(AttributeVector::iterator iter = attributes.begin(); iter != attributes.end(); iter++)
    {
        if((*iter) && (*iter)->Name() == name)
        {
            // Trigger scenemanager signal
            Scene* scene = ParentScene();
            if (scene)
                scene->EmitAttributeRemoved(this, *iter, change);

            // Trigger internal signal(s)
            emit AttributeAboutToBeRemoved(*iter);
            // Leave a hole in the array, which will be filled when new attributes are created
            SAFE_DELETE(*iter);
            break;
        }
    }
}

void EC_DynamicComponent::RemoveAllAttributes(AttributeChange::Type change)
{
    for(unsigned i = attributes.size() - 1; i < attributes.size(); --i)
    {
        if (attributes[i])
        {
            // Trigger scenemanager signal
            Scene* scene = ParentScene();
            if (scene)
                scene->EmitAttributeRemoved(this, attributes[i], change);

            QString name(attributes[i]->Name());

            // Trigger internal signal(s)
            emit AttributeAboutToBeRemoved(attributes[i]);
            SAFE_DELETE(attributes[i]);
            attributes[i] = 0;
        }
        attributes.clear();
    }
}

int EC_DynamicComponent::GetInternalAttributeIndex(int index) const
{
    if (index >= (int)attributes.size())
        return -1; // Can be sure that is not found.
    int cmp = 0;
    for (unsigned i = 0; i < attributes.size(); ++i)
    {
        if (!attributes[i])
            continue;
        if (cmp == index)
            return i;
        ++cmp;
    }
    return -1;
}

void EC_DynamicComponent::AddQVariantAttribute(const QString &name, AttributeChange::Type change)
{
    //Check if the attribute has already been created.
    if(!ContainsAttribute(name))
    {
        Attribute<QVariant> *attribute = new Attribute<QVariant>(this, name.toStdString().c_str());
        EmitAttributeChanged(attribute, change);
        emit AttributeAdded(attribute);
    }
    else
        LogWarning("Failed to add a new QVariant in name of " + name + ", cause there already is an attribute in that name.");
}

QVariant EC_DynamicComponent::GetAttribute(int index) const
{
    // Do not count holes.
    int attrIndex = GetInternalAttributeIndex(index);
    if (attrIndex < 0)
        return QVariant();
    return attributes[attrIndex]->ToQVariant();
}

QVariant EC_DynamicComponent::GetAttribute(const QString &name) const
{
    return IComponent::GetAttributeQVariant(name);
}

void EC_DynamicComponent::SetAttribute(int index, const QVariant &value, AttributeChange::Type change)
{
    int attrIndex = GetInternalAttributeIndex(index);
    if (attrIndex < 0)
    {
        LogWarning("Cannot set attribute, index out of bounds");
        return;
    }

    attributes[attrIndex]->FromQVariant(value, change);
}

void EC_DynamicComponent::SetAttributeQScript(const QString &name, const QScriptValue &value, AttributeChange::Type change)
{
    for(AttributeVector::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
        if((*iter) && (*iter)->Name() == name)
        {
            (*iter)->FromScriptValue(value, change);
            break;
        }
}

void EC_DynamicComponent::SetAttribute(const QString &name, const QVariant &value, AttributeChange::Type change)
{
    for(AttributeVector::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
        if((*iter) && (*iter)->Name() == name)
        {
            (*iter)->FromQVariant(value, change);
            break;
        }
}

QString EC_DynamicComponent::GetAttributeName(int index) const
{
    // Do not count holes.
    int attrIndex = GetInternalAttributeIndex(index);
    if (attrIndex < 0)
    {
        LogWarning("Cannot get attribute name, index out of bounds");
        return QString();
    }
    return attributes[index]->Name();
}

bool EC_DynamicComponent::ContainSameAttributes(const EC_DynamicComponent &comp) const
{
    AttributeVector myAttributeVector = NonEmptyAttributes();
    AttributeVector attributeVector = comp.NonEmptyAttributes();
    if(attributeVector.size() != myAttributeVector.size())
        return false;
    if(attributeVector.empty() && myAttributeVector.empty())
        return true;

    std::sort(myAttributeVector.begin(), myAttributeVector.end(), &CmpAttributeByName);
    std::sort(attributeVector.begin(), attributeVector.end(), &CmpAttributeByName);

    AttributeVector::const_iterator iter1 = myAttributeVector.begin();
    AttributeVector::const_iterator iter2 = attributeVector.begin();
    while(iter1 != myAttributeVector.end() && iter2 != attributeVector.end())
    {
        // Compare attribute names and type and if they mach continue iteration if not components aren't exactly the same.
        if ((*iter1)->Name() == (*iter2)->Name() && (*iter1)->TypeName() == (*iter2)->TypeName())
        {
            if(iter1 != myAttributeVector.end())
                ++iter1;
            if(iter2 != attributeVector.end())
                ++iter2;
        }
        else
        {
            return false;
        }
    }
    return true;

    /*// Get both attributes and check if they are holding exact number of attributes.
    AttributeVector myAttributeVector = Attributes();
    AttributeVector attributeVector = comp.Attributes();
    if(attributeVector.size() != myAttributeVector.size())
        return false;

    // Compare that every attribute is same in both components.
    QSet<IAttribute*> myAttributeSet;
    QSet<IAttribute*> attributeSet;
    for(uint i = 0; i < myAttributeSet.size(); i++)
    {
        attributeSet.insert(myAttributeVector[i]);
        myAttributeSet.insert(attributeVector[i]);
    }
    if(attributeSet != myAttributeSet)
        return false;
    return true;*/
}

bool EC_DynamicComponent::ContainsAttribute(const QString &name) const
{
    AttributeVector::const_iterator iter = attributes.begin();
    while(iter != attributes.end())
    {
        if((*iter) && (*iter)->Name() == name)
            return true;
        ++iter;
    }

    return false;
}

void EC_DynamicComponent::SerializeToBinary(kNet::DataSerializer& dest) const
{
    dest.Add<u8>(attributes.size());
    // For now, transmit all values as strings
    AttributeVector::const_iterator iter = attributes.begin();
    while(iter != attributes.end())
    {
        if (*iter)
        {
            dest.AddString((*iter)->Name().toStdString());
            dest.AddString((*iter)->TypeName().toStdString());
            dest.AddString((*iter)->ToString());
        }
        ++iter;
    }
}

void EC_DynamicComponent::DeserializeFromBinary(kNet::DataDeserializer& source, AttributeChange::Type change)
{
    u8 num_attributes = source.Read<u8>();
    std::vector<DeserializeData> deserializedAttributes;
    for(uint i = 0; i < num_attributes; ++i)
    {
        std::string name = source.ReadString();
        std::string typeName = source.ReadString();
        std::string value = source.ReadString();

        DeserializeData attrData(name.c_str(), typeName.c_str(), value.c_str());
        deserializedAttributes.push_back(attrData);
    }

    DeserializeCommon(deserializedAttributes, change);
}
<commit_msg>Add LogWarnings to EC_DynamicComponent's AddQVariantAttribute and SetAttributeQScript telling that these functions are deprecated and will be removed.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "DebugOperatorNew.h"
#include "EC_DynamicComponent.h"

#include "SceneAPI.h"

#include "Entity.h"
#include "LoggingFunctions.h"
#include "Scene.h"

#include <QScriptEngine>
#include <QScriptValueIterator>

#include <kNet.h>

#include <QDomDocument>

#include "MemoryLeakCheck.h"

struct DeserializeData
{
    DeserializeData(const QString &name = "", const QString &type = "", const QString &value = ""):
        name_(name),
        type_(type),
        value_(value)
    {
    }

    /// Checks if any of data structure's values are null.
    bool isNull() const
    {
        return name_ == "" || type_ == "" || value_ == "";
    }

    QString name_;
    QString type_;
    QString value_;
};

/// Function that is used by std::sort algorithm to sort attributes by their name.
bool CmpAttributeByName(const IAttribute *a, const IAttribute *b)
{
    return a->Name() < b->Name();
}

/// Function that is used by std::sort algorithm to sort DeserializeData by their name.
bool CmpAttributeDataByName(const DeserializeData &a, const DeserializeData &b)
{
    return a.name_ < b.name_;
}

EC_DynamicComponent::EC_DynamicComponent(Scene* scene):
    IComponent(scene)
{
}

EC_DynamicComponent::~EC_DynamicComponent()
{
}

void EC_DynamicComponent::SerializeTo(QDomDocument& doc, QDomElement& base_element) const
{
    QDomElement comp_element = BeginSerialization(doc, base_element);

    AttributeVector::const_iterator iter = attributes.begin();
    while(iter != attributes.end())
    {
        if (*iter)
            WriteAttribute(doc, comp_element, (*iter)->Name(), (*iter)->ToString().c_str(), (*iter)->TypeName());
        ++iter;
    }
}

void EC_DynamicComponent::DeserializeFrom(QDomElement& element, AttributeChange::Type change)
{
    if (!BeginDeserialization(element))
        return;

    std::vector<DeserializeData> deserializedAttributes;
    QDomElement child = element.firstChildElement("attribute");
    while(!child.isNull())
    {
        QString name = child.attribute("name");
        QString type = child.attribute("type");
        QString value = child.attribute("value");
        DeserializeData attributeData(name, type, value);
        deserializedAttributes.push_back(attributeData);

        child = child.nextSiblingElement("attribute");
    }

    DeserializeCommon(deserializedAttributes, change);
}

void EC_DynamicComponent::DeserializeCommon(std::vector<DeserializeData>& deserializedAttributes, AttributeChange::Type change)
{
    // Sort both lists in alphabetical order.
    AttributeVector oldAttributes = NonEmptyAttributes();
    std::stable_sort(oldAttributes.begin(), oldAttributes.end(), &CmpAttributeByName);
    std::stable_sort(deserializedAttributes.begin(), deserializedAttributes.end(), &CmpAttributeDataByName);

    std::vector<DeserializeData> addAttributes;
    std::vector<DeserializeData> remAttributes;
    AttributeVector::iterator iter1 = oldAttributes.begin();
    std::vector<DeserializeData>::iterator iter2 = deserializedAttributes.begin();

    // Check what attributes we need to add or remove from the dynamic component (done by comparing two list differences).
    while(iter1 != oldAttributes.end() || iter2 != deserializedAttributes.end())
    {
        // No point to continue the iteration if other list is empty. We can just push all new attributes into the dynamic component.
        if(iter1 == oldAttributes.end())
        {
            for(;iter2 != deserializedAttributes.end(); ++iter2)
                addAttributes.push_back(*iter2);
            break;
        }
        // Only old attributes are left and they can be removed from the dynamic component.
        else if(iter2 == deserializedAttributes.end())
        {
            for(;iter1 != oldAttributes.end(); ++iter1)
                remAttributes.push_back(DeserializeData((*iter1)->Name()));
            break;
        }

        // Attribute has already created and we only need to update it's value.
        if((*iter1)->Name() == (*iter2).name_)
        {
            //SetAttribute(QString::fromStdString(iter2->name_), QString::fromStdString(iter2->value_), change);
            for(AttributeVector::const_iterator attr_iter = attributes.begin(); attr_iter != attributes.end(); ++attr_iter)
                if((*attr_iter)->Name() == iter2->name_)
                    (*attr_iter)->FromString(iter2->value_.toStdString(), change);

            ++iter2;
            ++iter1;
        }
        // Found a new attribute that need to be created and added to the component.
        else if((*iter1)->Name() > (*iter2).name_)
        {
            addAttributes.push_back(*iter2);
            ++iter2;
        }
        // Couldn't find the attribute in a new list so it need to be removed from the component.
        else
        {
            remAttributes.push_back(DeserializeData((*iter1)->Name()));
            ++iter1;
        }
    }

    while(!addAttributes.empty())
    {
        DeserializeData attributeData = addAttributes.back();
        IAttribute *attribute = CreateAttribute(attributeData.type_, attributeData.name_);
        if (attribute)
            attribute->FromString(attributeData.value_.toStdString(), change);
        addAttributes.pop_back();
    }
    while(!remAttributes.empty())
    {
        DeserializeData attributeData = remAttributes.back();
        RemoveAttribute(attributeData.name_);
        remAttributes.pop_back();
    }
}

IAttribute *EC_DynamicComponent::CreateAttribute(const QString &typeName, const QString &name, AttributeChange::Type change)
{
    if(ContainsAttribute(name))
        return IComponent::GetAttribute(name);

    IAttribute *attribute = SceneAPI::CreateAttribute(typeName, name);
    if(!attribute)
    {
        LogError("Failed to create new attribute:" + name + " in dynamic component:" + Name());
        return 0;
    }

    IComponent::AddAttribute(attribute);

    // Trigger scenemanager signal
    Scene* scene = ParentScene();
    if (scene)
        scene->EmitAttributeAdded(this, attribute, change);

    // Trigger internal signal
    emit AttributeAdded(attribute);
    EmitAttributeChanged(attribute, change);
    return attribute;
}

void EC_DynamicComponent::RemoveAttribute(const QString &name, AttributeChange::Type change)
{
    for(AttributeVector::iterator iter = attributes.begin(); iter != attributes.end(); iter++)
    {
        if((*iter) && (*iter)->Name() == name)
        {
            // Trigger scenemanager signal
            Scene* scene = ParentScene();
            if (scene)
                scene->EmitAttributeRemoved(this, *iter, change);

            // Trigger internal signal(s)
            emit AttributeAboutToBeRemoved(*iter);
            // Leave a hole in the array, which will be filled when new attributes are created
            SAFE_DELETE(*iter);
            break;
        }
    }
}

void EC_DynamicComponent::RemoveAllAttributes(AttributeChange::Type change)
{
    for(unsigned i = attributes.size() - 1; i < attributes.size(); --i)
    {
        if (attributes[i])
        {
            // Trigger scenemanager signal
            Scene* scene = ParentScene();
            if (scene)
                scene->EmitAttributeRemoved(this, attributes[i], change);

            QString name(attributes[i]->Name());

            // Trigger internal signal(s)
            emit AttributeAboutToBeRemoved(attributes[i]);
            SAFE_DELETE(attributes[i]);
            attributes[i] = 0;
        }
        attributes.clear();
    }
}

int EC_DynamicComponent::GetInternalAttributeIndex(int index) const
{
    if (index >= (int)attributes.size())
        return -1; // Can be sure that is not found.
    int cmp = 0;
    for (unsigned i = 0; i < attributes.size(); ++i)
    {
        if (!attributes[i])
            continue;
        if (cmp == index)
            return i;
        ++cmp;
    }
    return -1;
}

void EC_DynamicComponent::AddQVariantAttribute(const QString &name, AttributeChange::Type change)
{
    LogWarning("EC_DynamicComponent::AddQVariantAttribute is deprecated and will be removed. Use CreateAttribute(\"qvariant\",...) instead.");
    //Check if the attribute has already been created.
    if(!ContainsAttribute(name))
    {
        Attribute<QVariant> *attribute = new Attribute<QVariant>(this, name.toStdString().c_str());
        EmitAttributeChanged(attribute, change);
        emit AttributeAdded(attribute);
    }
    else
        LogWarning("Failed to add a new QVariant in name of " + name + ", cause there already is an attribute in that name.");
}

QVariant EC_DynamicComponent::GetAttribute(int index) const
{
    // Do not count holes.
    int attrIndex = GetInternalAttributeIndex(index);
    if (attrIndex < 0)
        return QVariant();
    return attributes[attrIndex]->ToQVariant();
}

QVariant EC_DynamicComponent::GetAttribute(const QString &name) const
{
    return IComponent::GetAttributeQVariant(name);
}

void EC_DynamicComponent::SetAttribute(int index, const QVariant &value, AttributeChange::Type change)
{
    int attrIndex = GetInternalAttributeIndex(index);
    if (attrIndex < 0)
    {
        LogWarning("Cannot set attribute, index out of bounds");
        return;
    }

    attributes[attrIndex]->FromQVariant(value, change);
}

void EC_DynamicComponent::SetAttributeQScript(const QString &name, const QScriptValue &value, AttributeChange::Type change)
{
    LogWarning("EC_DynamicComponent::SetAttributeQScript is deprecated and will be removed. Use SetAttribute instead.");
    for(AttributeVector::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
        if((*iter) && (*iter)->Name() == name)
        {
            (*iter)->FromScriptValue(value, change);
            break;
        }
}

void EC_DynamicComponent::SetAttribute(const QString &name, const QVariant &value, AttributeChange::Type change)
{
    for(AttributeVector::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
        if((*iter) && (*iter)->Name() == name)
        {
            (*iter)->FromQVariant(value, change);
            break;
        }
}

QString EC_DynamicComponent::GetAttributeName(int index) const
{
    // Do not count holes.
    int attrIndex = GetInternalAttributeIndex(index);
    if (attrIndex < 0)
    {
        LogWarning("Cannot get attribute name, index out of bounds");
        return QString();
    }
    return attributes[index]->Name();
}

bool EC_DynamicComponent::ContainSameAttributes(const EC_DynamicComponent &comp) const
{
    AttributeVector myAttributeVector = NonEmptyAttributes();
    AttributeVector attributeVector = comp.NonEmptyAttributes();
    if(attributeVector.size() != myAttributeVector.size())
        return false;
    if(attributeVector.empty() && myAttributeVector.empty())
        return true;

    std::sort(myAttributeVector.begin(), myAttributeVector.end(), &CmpAttributeByName);
    std::sort(attributeVector.begin(), attributeVector.end(), &CmpAttributeByName);

    AttributeVector::const_iterator iter1 = myAttributeVector.begin();
    AttributeVector::const_iterator iter2 = attributeVector.begin();
    while(iter1 != myAttributeVector.end() && iter2 != attributeVector.end())
    {
        // Compare attribute names and type and if they mach continue iteration if not components aren't exactly the same.
        if ((*iter1)->Name() == (*iter2)->Name() && (*iter1)->TypeName() == (*iter2)->TypeName())
        {
            if(iter1 != myAttributeVector.end())
                ++iter1;
            if(iter2 != attributeVector.end())
                ++iter2;
        }
        else
        {
            return false;
        }
    }
    return true;

    /*// Get both attributes and check if they are holding exact number of attributes.
    AttributeVector myAttributeVector = Attributes();
    AttributeVector attributeVector = comp.Attributes();
    if(attributeVector.size() != myAttributeVector.size())
        return false;

    // Compare that every attribute is same in both components.
    QSet<IAttribute*> myAttributeSet;
    QSet<IAttribute*> attributeSet;
    for(uint i = 0; i < myAttributeSet.size(); i++)
    {
        attributeSet.insert(myAttributeVector[i]);
        myAttributeSet.insert(attributeVector[i]);
    }
    if(attributeSet != myAttributeSet)
        return false;
    return true;*/
}

bool EC_DynamicComponent::ContainsAttribute(const QString &name) const
{
    AttributeVector::const_iterator iter = attributes.begin();
    while(iter != attributes.end())
    {
        if((*iter) && (*iter)->Name() == name)
            return true;
        ++iter;
    }

    return false;
}

void EC_DynamicComponent::SerializeToBinary(kNet::DataSerializer& dest) const
{
    dest.Add<u8>(attributes.size());
    // For now, transmit all values as strings
    AttributeVector::const_iterator iter = attributes.begin();
    while(iter != attributes.end())
    {
        if (*iter)
        {
            dest.AddString((*iter)->Name().toStdString());
            dest.AddString((*iter)->TypeName().toStdString());
            dest.AddString((*iter)->ToString());
        }
        ++iter;
    }
}

void EC_DynamicComponent::DeserializeFromBinary(kNet::DataDeserializer& source, AttributeChange::Type change)
{
    u8 num_attributes = source.Read<u8>();
    std::vector<DeserializeData> deserializedAttributes;
    for(uint i = 0; i < num_attributes; ++i)
    {
        std::string name = source.ReadString();
        std::string typeName = source.ReadString();
        std::string value = source.ReadString();

        DeserializeData attrData(name.c_str(), typeName.c_str(), value.c_str());
        deserializedAttributes.push_back(attrData);
    }

    DeserializeCommon(deserializedAttributes, change);
}
<|endoftext|>


<commit_before>#include <iostream>

#include <list>
#include <string>

#include <clotho/testserver.hpp>
#include <clotho/socket.hpp>

#include "locktestmaster.hpp"
#include "imapsession.hpp"
#include "mailstorelocktest.hpp"

/*
 * Reimplement these classes:  imapmaster, internetserver
 */

typedef std::list<std::string *> StringList;

class TestSocket : public Socket {
public:
  TestSocket(void);
  virtual ~TestSocket();
  virtual ssize_t receive(uint8_t *buffer, size_t size);
  virtual ssize_t send(const uint8_t *data, size_t length);
  void in(const std::string &s);
  const std::string *out(void);
  void reset(void);

private:
  StringList *m_inputs;
  StringList *m_outputs;
  size_t m_inputOffset;
  StringList::iterator m_pIn;
  StringList::iterator m_pOut;
};

TestSocket::TestSocket() : Socket(0, 0, 16384) {
  m_inputs = NULL;
  m_outputs = NULL;
}

TestSocket::~TestSocket() {
}

ssize_t TestSocket::receive(uint8_t *buffer, size_t size) {
  ssize_t result = -1;
  if ((NULL != m_inputs) && (m_inputs->end() != m_pIn)) {
    strcpy((char *)buffer, (*m_pIn)->c_str());
    result = (*m_pIn)->length();
    m_pIn++;
  }

  return result;
}

ssize_t TestSocket::send(const uint8_t *data, size_t length) {
  if (NULL == m_outputs) {
    m_outputs = new StringList;
  }

  m_outputs->push_back(new std::string((char *)data, length));
  // std::cout << data << std::endl;
  m_pOut = m_outputs->begin();

  return length;
}

void TestSocket::in(const std::string &s) {
  if (NULL == m_inputs) {
    m_inputs = new StringList;
  }
  m_inputs->push_back(new std::string(s));
  m_pIn = m_inputs->begin();
}

const std::string *TestSocket::out(void) {
  std::string *result = NULL;
  if ((NULL != m_outputs) && (m_outputs->end() != m_pOut)) {
    result = *m_pOut;
    m_pOut++;
  }
  return result;
}

void TestSocket::reset(void) {
  delete m_inputs;
  delete m_outputs;
  m_inputs = NULL;
  m_outputs = NULL;
}

bool test(TestServer &server, TestSocket *s, const std::string commands[],
	  int command_count, const std::string &match, int response,
	  int initial_retry_count, int final_retry_count) {
  bool result = true;
  const std::string *o;

  g_lockState.retryCount(initial_retry_count);
  s->reset();
  for (int i=0; i<command_count; ++i) {
    s->in(commands[i]);
  }
  server.test(s);
  for (int i=0; i< response; ++i) {
    o = s->out();
  }
  if ((NULL == o) || (*o != match)) {
    std::cout << "Response doesn't match. \"";
    if (NULL != o) {
      std::cout << *o;
    }
    else {
      std::cout << "NULL";
    }
    std::cout << "\" expecting \"" << match << "\"" << std::endl;
    result = false;
  }
  if (final_retry_count != g_lockState.retryCount()) {
    std:: cout << "The retry count is " << g_lockState.retryCount() << " and I was expecting " << final_retry_count << std::endl;
    result = false;
  }
  return result;
}

typedef struct {
  const std::string commands[10];
  int command_count;
  const std::string match;
  int response_number;
  int initial_retry_count;
  int final_retry_count;
  const std::string test_name;
} test_descriptor;

test_descriptor descriptors[] = {
  {{
    "1 login foo bar\r\n",
    "2 create inbox\r\n",
    "3 logout\r\n"
    }, 3, "2 NO create Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Creation failure"},
  {{
    "1 login foo bar\r\n",
    "2 create inbox\r\n",
    "3 logout\r\n"
    }, 3, "2 OK create Completed\r\n", 3, 0, -1,
   "Successful creation"},
  {{
      "1 login foo bar\r\n",
      "2 delete inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO delete Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Deletion failure"},
  {{
      "1 login foo bar\r\n",
      "2 delete inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK delete Completed\r\n", 3, 0, -1,
   "Successful deletion"},
  {{
      "1 login foo bar\r\n",
      "2 rename inbox outbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO rename Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Renaming failure"},
  {{
      "1 login foo bar\r\n",
      "2 rename inbox outbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK rename Completed\r\n", 3, 0, -1,
   "Successful renaming"},
  {{
      "1 login foo bar\r\n",
      "2 subscribe inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO subscribe Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Subscribing failure"},
  {{
      "1 login foo bar\r\n",
      "2 subscribe inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK subscribe Completed\r\n", 3, 0, -1,
   "Successful subscribing"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO select Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Selecting failure"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK [READ-WRITE] select Completed\r\n", 4, 0, -2,  // -2 instead of -1 because it also does a close
   "Successful selecting"},
  {{
      "1 login foo bar\r\n",
      "2 examine inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO examine Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Examining failure"},
  {{
      "1 login foo bar\r\n",
      "2 examine inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK [READ-ONLY] examine Completed\r\n", 4, 0, -2, // -2 instead of -1 b3ecause it also does a close
   "Successful examining"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 close\r\n",
      "5 logout\r\n"
    }, 5, "3 NO close Locking Error:  Too Many Retries\r\n", 5, 1, 4,
   "Selecting failure"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 logout\r\n"
    }, 4, "3 OK close Completed\r\n", 5, 0, -3,  // -3 instead of -1 because it also does a close
   "Successful selecting"},
};

int main() {
  LockTestMaster master("localhost", 60, 1800, 900, 5, 12, 5);
  TestServer server(&master);
  TestSocket *s = new TestSocket();
  int pass_count = 0;
  int fail_count = 0;

  for (int i=0; i<(sizeof(descriptors)/sizeof(test_descriptor)); ++i) {
    bool result = test(server, s, descriptors[i].commands, descriptors[i].command_count, descriptors[i].match, descriptors[i].response_number, descriptors[i].initial_retry_count, descriptors[i].final_retry_count);
    std::cout << descriptors[i].test_name;
    if (result) {
      std::cout << " success" << std::endl;
      ++pass_count;
    }
    else {
      std::cout << " failure" << std::endl;
      ++fail_count;
    }
  }

  return 0;
}
<commit_msg>Begin the reformulation needed to make the system smarter about how it does things.<commit_after>#include <iostream>

#include <list>
#include <string>

#include <clotho/testserver.hpp>
#include <clotho/socket.hpp>

#include "locktestmaster.hpp"
#include "imapsession.hpp"
#include "mailstorelocktest.hpp"

/*
 * Reimplement these classes:  imapmaster, internetserver
 */

typedef struct {
  std::string s;
  int retry_count;
} commands;

typedef std::list<commands> StringList;

class TestSocket : public Socket {
public:
  TestSocket(void);
  virtual ~TestSocket();
  virtual ssize_t receive(uint8_t *buffer, size_t size);
  virtual ssize_t send(const uint8_t *data, size_t length);
  void in(const std::string &s, int count);
  const std::string *out(void);
  int retry_out(void);
  void reset(void);

private:
  StringList *m_inputs;
  StringList *m_outputs;
  size_t m_inputOffset;
  StringList::iterator m_pIn;
  StringList::iterator m_pOut;
};

TestSocket::TestSocket() : Socket(0, 0, 16384) {
  m_inputs = NULL;
  m_outputs = NULL;
}

TestSocket::~TestSocket() {
}

ssize_t TestSocket::receive(uint8_t *buffer, size_t size) {
  ssize_t result = -1;
  if ((NULL != m_inputs) && (m_inputs->end() != m_pIn)) {
    strcpy((char *)buffer, (*m_pIn).s.c_str());
    result = (*m_pIn).s.length();
    g_lockState.retryCount((*m_pIn).retry_count);
    m_pIn++;
  }

  return result;
}

ssize_t TestSocket::send(const uint8_t *data, size_t length) {
  if (NULL == m_outputs) {
    m_outputs = new StringList;
  }

  commands command = { std::string((char *)data, length), g_lockState.retryCount() };
  m_outputs->push_back(command);
  // m_outputs->push_back(new std::string((char *)data, length));
  // std::cout << data << std::endl;
  m_pOut = m_outputs->begin();

  return length;
}

void TestSocket::in(const std::string &s, int count) {
  if (NULL == m_inputs) {
    m_inputs = new StringList;
  }
  commands command = { s, count };
  m_inputs->push_back(command);
  m_pIn = m_inputs->begin();
}

const std::string *TestSocket::out(void) {
  std::string *result = NULL;
  if ((NULL != m_outputs) && (m_outputs->end() != m_pOut)) {
    result = new std::string ((*m_pOut).s);
    m_pOut++;
  }
  return result;
}

int TestSocket::retry_out(void) {
  if ((NULL != m_outputs) && (m_outputs->end() != m_pOut)) {
    return (*m_pOut).retry_count;
  }
  return -999;
}

void TestSocket::reset(void) {
  delete m_inputs;
  delete m_outputs;
  m_inputs = NULL;
  m_outputs = NULL;
}

bool test(TestServer &server, TestSocket *s, const std::string commands[],
	  int command_count, const std::string &match, int response,
	  int initial_retry_count, int final_retry_count) {
  bool result = true;
  const std::string *o;

  s->reset();
  for (int i=0; i<command_count; ++i) {
    s->in(commands[i], initial_retry_count);
  }
  server.test(s);
  int retries;
  for (int i=0; i< response; ++i) {
    retries = s->retry_out();
    o = s->out();
  }
  if ((NULL == o) || (*o != match)) {
    std::cout << "Response doesn't match. \"";
    if (NULL != o) {
      std::cout << *o;
    }
    else {
      std::cout << "NULL";
    }
    std::cout << "\" expecting \"" << match << "\"" << std::endl;
    result = false;
  }
  if (final_retry_count != retries) {
    std:: cout << "The retry count is " << retries << " and I was expecting " << final_retry_count << std::endl;
    result = false;
  }
  return result;
}

typedef struct {
  const std::string commands[10];
  int command_count;
  const std::string match;
  int response_number;
  int initial_retry_count;
  int final_retry_count;
  const std::string test_name;
} test_descriptor;

test_descriptor descriptors[] = {
#if 0
#endif // 0
  {{
    "1 login foo bar\r\n",
    "2 create inbox\r\n",
    "3 logout\r\n"
    }, 3, "2 NO create Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Creation failure"},
  {{
    "1 login foo bar\r\n",
    "2 create inbox\r\n",
    "3 logout\r\n"
    }, 3, "2 OK create Completed\r\n", 3, 0, -1,
   "Successful creation"},
  {{
      "1 login foo bar\r\n",
      "2 delete inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO delete Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Deletion failure"},
  {{
      "1 login foo bar\r\n",
      "2 delete inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK delete Completed\r\n", 3, 0, -1,
   "Successful deletion"},
  {{
      "1 login foo bar\r\n",
      "2 rename inbox outbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO rename Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Renaming failure"},
  {{
      "1 login foo bar\r\n",
      "2 rename inbox outbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK rename Completed\r\n", 3, 0, -1,
   "Successful renaming"},
  {{
      "1 login foo bar\r\n",
      "2 subscribe inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO subscribe Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Subscribing failure"},
  {{
      "1 login foo bar\r\n",
      "2 subscribe inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK subscribe Completed\r\n", 3, 0, -1,
   "Successful subscribing"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO select Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Selecting failure"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK [READ-WRITE] select Completed\r\n", 4, 0, -1,
   "Successful selecting"},
  {{
      "1 login foo bar\r\n",
      "2 examine inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO examine Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Examining failure"},
  {{
      "1 login foo bar\r\n",
      "2 examine inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK [READ-ONLY] examine Completed\r\n", 4, 0, -1,
   "Successful examining"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 close\r\n",
      "5 logout\r\n"
    }, 5, "3 NO close Locking Error:  Too Many Retries\r\n", 5, 1, 4,
   "Selecting failure"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 logout\r\n"
    }, 4, "3 OK close Completed\r\n", 5, 0, -1,
   "Successful selecting"},
};

int main() {
  LockTestMaster master("localhost", 60, 1800, 900, 5, 12, 5);
  TestServer server(&master);
  TestSocket *s = new TestSocket();
  int pass_count = 0;
  int fail_count = 0;

  for (int i=0; i<(sizeof(descriptors)/sizeof(test_descriptor)); ++i) {
    bool result = test(server, s, descriptors[i].commands, descriptors[i].command_count, descriptors[i].match, descriptors[i].response_number, descriptors[i].initial_retry_count, descriptors[i].final_retry_count);
    std::cout << descriptors[i].test_name;
    if (result) {
      std::cout << " success" << std::endl;
      ++pass_count;
    }
    else {
      std::cout << " failure" << std::endl;
      ++fail_count;
    }
  }

  return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "DexUtil.h"
#include "MethodDedup.h"
#include "MethodOverrideGraph.h"
#include "Show.h"
#include "Trace.h"
#include "Walkers.h"

namespace {
// Only look at small methods. Increase the limit does not match more
// identical code in practise.
constexpr const uint32_t MAX_NUM_INSTRUCTIONS = 32;

/**
 * Allow code without invoke-super and with less than MAX_NUM_INSTRUCTIONS
 * instructions.
 */
bool eligible_code(const IRCode* code) {
  bool eligible = true;
  uint32_t count = 0;
  editable_cfg_adapter::iterate(code, [&](const MethodItemEntry& mie) {
    auto opcode = mie.insn->opcode();
    if (opcode::is_invoke_super(opcode)) {
      eligible = false;
      return editable_cfg_adapter::LOOP_BREAK;
    }
    if (!opcode::is_an_internal(opcode)) {
      count++;
    }
    if (count > MAX_NUM_INSTRUCTIONS) {
      eligible = false;
      return editable_cfg_adapter::LOOP_BREAK;
    }
    return editable_cfg_adapter::LOOP_CONTINUE;
  });
  return eligible;
}

void find_duplications(const method_override_graph::Graph* graph,
                       const DexMethod* root_method,
                       std::unordered_set<DexMethod*>* result) {
  auto root_code = root_method->get_code();
  if (!root_code) {
    return;
  }
  for (auto* child : graph->get_node(root_method).children) {
    // The method definition may be deleted after the overriding graph is
    // created, check if it's still a definition.
    if (root(child) || !child->is_def() || !can_rename(child)) {
      continue;
    }
    auto child_code = child->get_code();
    if (child_code && eligible_code(child_code) &&
        root_code->structural_equals(*child_code)) {
      result->insert(const_cast<DexMethod*>(child));
      find_duplications(graph, child, result);
    }
  }
}

/**
 * Make the method and all its overriding methods be public.
 */
void publicize_methods(const method_override_graph::Graph* graph,
                       DexMethod* root_method) {
  set_public(root_method);
  for (auto* child : graph->get_node(root_method).children) {
    if (is_public(child)) {
      // The children of child should all be public, otherwise the code is
      // invalid before this transformation.
      continue;
    }
    redex_assert(is_protected(child));
    publicize_methods(graph, const_cast<DexMethod*>(child));
  }
}

/**
 * Deduplicate identical overriding code.
 */
uint32_t remove_duplicated_vmethods(
    const Scope& scope,
    const ConcurrentSet<DexMethodRef*>& super_invoked_methods) {
  uint32_t ret = 0;
  auto graph = method_override_graph::build_graph(scope);
  std::unordered_map<DexMethodRef*, DexMethodRef*> removed_vmethods;

  walk::classes(scope, [&](DexClass* cls) {
    for (auto method : cls->get_vmethods()) {
      if (!method->get_code()) {
        // TODO: look at the abstract methods and we can lift the
        // implementations to the abstract class if lots of them are identical.
        continue;
      }
      if (!is_public_or_protected(method)) {
        // Note: package-private methods are skipped. Need consider package
        // names when change the accessibility of them.
        continue;
      }
      if (!eligible_code(method->get_code())) {
        continue;
      }
      std::unordered_set<DexMethod*> duplicates;
      find_duplications(graph.get(), method, &duplicates);

      // Now, remove the methods that are called with INVOKE_SUPER from
      // the duplicates set.
      for (auto& m : duplicates) {
        if (super_invoked_methods.count_unsafe(m) != 0) {
          duplicates.erase(m);
        }
      }

      if (!duplicates.empty()) {
        if (is_protected(method)) {
          publicize_methods(graph.get(), method);
        }
        TRACE(VM, 8, "Same as %s", SHOW(method));
        for (auto m : duplicates) {
          TRACE(VM, 8, "\t%s", SHOW(m));
          type_class(m->get_class())->remove_method(m);
          removed_vmethods.emplace(m, method);
          DexMethod::erase_method(m);
          DexMethod::delete_method(m);
        }
        ret += duplicates.size();
        TRACE(VM, 9, "%s\n", SHOW(method->get_code()));
      }
    }
  });

  method_dedup::fixup_references_to_removed_methods(scope, removed_vmethods);

  return ret;
}

/**
 * Collect all the methods that are called with INVOKE_SUPPER opcode
 */
void collect_all_invoke_super_called(
    const Scope& scope, ConcurrentSet<DexMethodRef*>* super_invoked_methods) {
  walk::parallel::code(scope, [&](DexMethod* method, IRCode& code) {
    editable_cfg_adapter::iterate(&code, [&](MethodItemEntry& mie) {
      auto insn = mie.insn;
      if (insn->opcode() == OPCODE_INVOKE_SUPER) {
        auto callee_ref = insn->get_method();
        super_invoked_methods->insert(callee_ref);
      }
      return editable_cfg_adapter::LOOP_CONTINUE;
    });
  });
}
} // namespace

namespace dedup_vmethods {

uint32_t dedup(const DexStoresVector& stores) {
  auto scope = build_class_scope(stores);
  ConcurrentSet<DexMethodRef*> super_invoked_methods;
  collect_all_invoke_super_called(scope, &super_invoked_methods);
  auto deduplicated_vmethods =
      remove_duplicated_vmethods(scope, super_invoked_methods);
  TRACE(VM, 2, "deduplicated_vmethods %d\n", deduplicated_vmethods);
  return deduplicated_vmethods;
}

} // namespace dedup_vmethods
<commit_msg>Use std20::erase_if function<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "DexUtil.h"
#include "MethodDedup.h"
#include "MethodOverrideGraph.h"
#include "Show.h"
#include "StlUtil.h"
#include "Trace.h"
#include "Walkers.h"

namespace {
// Only look at small methods. Increase the limit does not match more
// identical code in practise.
constexpr const uint32_t MAX_NUM_INSTRUCTIONS = 32;

/**
 * Allow code without invoke-super and with less than MAX_NUM_INSTRUCTIONS
 * instructions.
 */
bool eligible_code(const IRCode* code) {
  bool eligible = true;
  uint32_t count = 0;
  editable_cfg_adapter::iterate(code, [&](const MethodItemEntry& mie) {
    auto opcode = mie.insn->opcode();
    if (opcode::is_invoke_super(opcode)) {
      eligible = false;
      return editable_cfg_adapter::LOOP_BREAK;
    }
    if (!opcode::is_an_internal(opcode)) {
      count++;
    }
    if (count > MAX_NUM_INSTRUCTIONS) {
      eligible = false;
      return editable_cfg_adapter::LOOP_BREAK;
    }
    return editable_cfg_adapter::LOOP_CONTINUE;
  });
  return eligible;
}

void find_duplications(const method_override_graph::Graph* graph,
                       const DexMethod* root_method,
                       std::vector<DexMethod*>* result) {
  auto root_code = root_method->get_code();
  if (!root_code) {
    return;
  }
  for (auto* child : graph->get_node(root_method).children) {
    // The method definition may be deleted after the overriding graph is
    // created, check if it's still a definition.
    if (root(child) || !child->is_def() || !can_rename(child)) {
      continue;
    }
    auto child_code = child->get_code();
    if (child_code && eligible_code(child_code) &&
        root_code->structural_equals(*child_code)) {
      result->push_back(const_cast<DexMethod*>(child));
      find_duplications(graph, child, result);
    }
  }
}

/**
 * Make the method and all its overriding methods be public.
 */
void publicize_methods(const method_override_graph::Graph* graph,
                       DexMethod* root_method) {
  set_public(root_method);
  for (auto* child : graph->get_node(root_method).children) {
    if (is_public(child)) {
      // The children of child should all be public, otherwise the code is
      // invalid before this transformation.
      continue;
    }
    redex_assert(is_protected(child));
    publicize_methods(graph, const_cast<DexMethod*>(child));
  }
}

/**
 * Deduplicate identical overriding code.
 */
uint32_t remove_duplicated_vmethods(
    const Scope& scope,
    const ConcurrentSet<DexMethodRef*>& super_invoked_methods) {
  uint32_t ret = 0;
  auto graph = method_override_graph::build_graph(scope);
  std::unordered_map<DexMethodRef*, DexMethodRef*> removed_vmethods;

  walk::classes(scope, [&](DexClass* cls) {
    for (auto method : cls->get_vmethods()) {
      if (!method->get_code()) {
        // TODO: look at the abstract methods and we can lift the
        // implementations to the abstract class if lots of them are identical.
        continue;
      }
      if (!is_public_or_protected(method)) {
        // Note: package-private methods are skipped. Need consider package
        // names when change the accessibility of them.
        continue;
      }
      if (!eligible_code(method->get_code())) {
        continue;
      }
      std::vector<DexMethod*> duplicates;
      find_duplications(graph.get(), method, &duplicates);

      // Now, remove the methods that are called with INVOKE_SUPER from
      // the duplicates set.
      std20::erase_if(duplicates, [&](auto& m) {
        return super_invoked_methods.count_unsafe(m);
      });

      if (!duplicates.empty()) {
        if (is_protected(method)) {
          publicize_methods(graph.get(), method);
        }
        TRACE(VM, 8, "Same as %s", SHOW(method));
        for (auto m : duplicates) {
          TRACE(VM, 8, "\t%s", SHOW(m));
          type_class(m->get_class())->remove_method(m);
          removed_vmethods.emplace(m, method);
          DexMethod::erase_method(m);
          DexMethod::delete_method(m);
        }
        ret += duplicates.size();
        TRACE(VM, 9, "%s\n", SHOW(method->get_code()));
      }
    }
  });

  method_dedup::fixup_references_to_removed_methods(scope, removed_vmethods);

  return ret;
}

/**
 * Collect all the methods that are called with INVOKE_SUPPER opcode
 */
void collect_all_invoke_super_called(
    const Scope& scope, ConcurrentSet<DexMethodRef*>* super_invoked_methods) {
  walk::parallel::code(scope, [&](DexMethod* method, IRCode& code) {
    editable_cfg_adapter::iterate(&code, [&](MethodItemEntry& mie) {
      auto insn = mie.insn;
      if (insn->opcode() == OPCODE_INVOKE_SUPER) {
        auto callee_ref = insn->get_method();
        super_invoked_methods->insert(callee_ref);
      }
      return editable_cfg_adapter::LOOP_CONTINUE;
    });
  });
}
} // namespace

namespace dedup_vmethods {

uint32_t dedup(const DexStoresVector& stores) {
  auto scope = build_class_scope(stores);
  ConcurrentSet<DexMethodRef*> super_invoked_methods;
  collect_all_invoke_super_called(scope, &super_invoked_methods);
  auto deduplicated_vmethods =
      remove_duplicated_vmethods(scope, super_invoked_methods);
  TRACE(VM, 2, "deduplicated_vmethods %d\n", deduplicated_vmethods);
  return deduplicated_vmethods;
}

} // namespace dedup_vmethods
<|endoftext|>


<commit_before>/*
    example1.cpp
    ============

    Basic usage of the Horse Whisperer

    Compile with:
        c++ -std=c++11 example1.cpp -o example

    Run with
        ./example

    Try to run:
        ./example
        ./example --help
        ./example gallop
        ./example gallop --ponies 5
        ./example gallop --ponies 6
        ./example gallop --ponies 5 --tired
        ./example trot 'mode elegant dancer' 'mode drunk panda'
*/
#include "../include/horsewhisperer/horsewhisperer.h"
#include <string>
#include <vector>

using namespace HorseWhisperer;

// flag validation callback
void validation(int x) {
    // Max value we accept is 5
    if (x > 5) {
        throw flag_validation_error { "You have assigned too many ponies!" };
    }
}

// help messages
std::string gallop_help = "The horses, they be a galloping\n";
std::string trot_help = "The horses, they be trotting in some 'mode ...'\n";

// gallop: action callback
int gallop(const Arguments& arguments) {
    for (int i = 0; i < GetFlag<int>("ponies"); i++) {
        if (!GetFlag<int>("tired")) {
            std::cout << "Galloping into the night!" << std::endl;
        } else {
            std::cout << "The pony is too tired to gallop." << std::endl;
        }
    }
    return 0;
}

// trot: arguments validation callback
void trotArgumentsCallback(const std::vector<std::string>& arguments) {
    for (const auto& arg : arguments) {
        if (arg.find("mode", 0) == std::string::npos) {
            throw action_validation_error { "unknown trot mode '" + arg + "'" };
        }
    }
}

// trot: action callback
int trot(const std::vector<std::string>& arguments) {
    for (const auto& mode : arguments) {
        std::cout << "Trotting like a " << mode << std::endl;
    }
    return 0;
}

int main(int argc, char* argv[]) {
    // Configuring the global context
    SetHelpBanner("Usage: MyProg [global options] <action> [options]");
    SetAppName("MyProg");
    SetVersion("MyProg version - 0.1.0\n");
    SetDelimiters(std::vector<std::string>{"+", ";", "_then"});

    // Define global flags
    DefineGlobalFlag<int>("ponies", "all the ponies", 1, validation);

    // Define action: gallop
    DefineAction("gallop", 0, true, "make the ponies gallop", gallop_help, gallop);
    DefineActionFlag<bool>("gallop", "tired", "are the horses tired?", false, nullptr);

    // Define action: trot (at least two arguments are required)
    DefineAction("trot", -2, true, "make the ponies trot in some way", trot_help,
                 trot, trotArgumentsCallback);

    // Parse command line: global flags, action arguments, and action flags
    try {
        switch (Parse(argc, argv)) {
            case ParseResult::OK:
                break;
            case ParseResult::HELP:
                ShowHelp();
                return 0;
            case ParseResult::VERSION:
                ShowVersion();
                return 0;
            case ParseResult::FAILURE:
                std::cout << "Failed to parse the command line input.\n";
                return 1;
            case ParseResult::INVALID_FLAG:
                std::cout << "Invalid flag.\n";
                return 2;
        }
    } catch (horsewhisperer_error& e) {
        std::cout << e.what() << "\n";
    }

    // Start execution
    return Start();
}
<commit_msg>Update example<commit_after>/*
    example1.cpp
    ============

    Basic usage of the Horse Whisperer

    Compile with:
        c++ -std=c++11 example1.cpp -o example

    Run with
        ./example

    Try to run:
        ./example
        ./example --help
        ./example gallop
        ./example gallop --ponies 5
        ./example gallop --ponies 6
        ./example gallop --ponies 5 --tired
        ./example trot 'mode elegant dancer' 'mode drunk panda'
*/
#include "../include/horsewhisperer/horsewhisperer.h"
#include <string>
#include <vector>

using namespace HorseWhisperer;

// flag validation callback
void validation(int x) {
    // Max value we accept is 5
    if (x > 5) {
        throw flag_validation_error { "You have assigned too many ponies!" };
    }
}

// help messages
std::string gallop_help = "The horses, they be a galloping\n";
std::string trot_help = "The horses, they be trotting in some 'mode ...'\n";

// gallop: action callback
int gallop(const Arguments& arguments) {
    for (int i = 0; i < GetFlag<int>("ponies"); i++) {
        if (!GetFlag<int>("tired")) {
            std::cout << "Galloping into the night!" << std::endl;
        } else {
            std::cout << "The pony is too tired to gallop." << std::endl;
        }
    }
    return 0;
}

// trot: arguments validation callback
void trotArgumentsCallback(const std::vector<std::string>& arguments) {
    for (const auto& arg : arguments) {
        if (arg.find("mode", 0) == std::string::npos) {
            throw action_validation_error { "unknown trot mode '" + arg + "'" };
        }
    }
}

// trot: action callback
int trot(const std::vector<std::string>& arguments) {
    for (const auto& mode : arguments) {
        std::cout << "Trotting like a " << mode << std::endl;
    }
    return 0;
}

int main(int argc, char* argv[]) {
    // Configuring the global context
    SetHelpBanner("Usage: MyProg [global options] <action> [options]");
    SetAppName("MyProg");
    SetVersion("MyProg version - 0.1.0\n");
    SetDelimiters(std::vector<std::string>{"+", ";", "_then"});

    // Define global flags
    DefineGlobalFlag<int>("ponies", "all the ponies", 1, validation);

    // Define action: gallop
    DefineAction("gallop", 0, true, "make the ponies gallop", gallop_help,
                 gallop, nullptr, false);
    DefineActionFlag<bool>("gallop", "tired", "are the horses tired?", false, nullptr);

    // Define action: trot (at least two arguments are required)
    DefineAction("trot", 2, true, "make the ponies trot in some way", trot_help,
                 trot, trotArgumentsCallback, true);

    // Parse command line: global flags, action arguments, and action flags
    try {
        switch (Parse(argc, argv)) {
            case ParseResult::OK:
                break;
            case ParseResult::HELP:
                ShowHelp();
                return 0;
            case ParseResult::VERSION:
                ShowVersion();
                return 0;
            case ParseResult::FAILURE:
                std::cout << "Failed to parse the command line input.\n";
                return 1;
            case ParseResult::INVALID_FLAG:
                std::cout << "Invalid flag.\n";
                return 2;
        }
    } catch (horsewhisperer_error& e) {
        std::cout << e.what() << "\n";
    }

    // Start execution
    return Start();
}
<|endoftext|>