<commit_before>#ifndef DEEPNESS_IMMUTABLE_MAP_HPP
#define DEEPNESS_IMMUTABLE_MAP_HPP

#include <memory>
#include <functional>
#include <vector>
#include <exception>
#include <cassert>
#include <cstdint>

namespace deepness
{
    template<class Key,
             class T,
             class Hash = std::hash<Key>,
             class Pred = std::equal_to<Key> >
    class immutable_map
    {
    public:
        typedef std::pair<const Key, T> value_type;
        typedef Key key_type;
        typedef T mapped_type;
        typedef Hash hasher;
        typedef Pred key_equals;

        class key_error: public std::exception
        {
        public:
            key_error(std::string message = "")
                :m_message(std::move(message))
            {}

            const char *what() const throw() override
            {
                return m_message.c_str();
            }
        private:
            std::string m_message;
        };

    private:
        struct node_type;
        typedef std::shared_ptr<node_type> shared_node_type;
        typedef std::shared_ptr<value_type> shared_value_type;
        struct node_type
        {
            node_type()
                :population(0)
            {}

            node_type(const node_type &other)
                :population(other.population)
                ,values(other.values)
            {
                size_t num_children = popcnt(population);
                if(num_children)
                {
                    children.reset(new shared_node_type[num_children]);
                    std::copy(other.children.get(), other.children.get() + num_children, children.get());
                }
            }

            // TODO this is just a naive implementation, redo it to optimize
            uint32_t population; //!< a 0 population indicates a leaf
            std::unique_ptr<shared_node_type[]> children;
            std::vector<shared_value_type> values;
        };

    public:
        immutable_map()
            :m_root(std::make_shared<node_type>())
        {}

        /*!
          \returns a new immutable_map with val.first mapped to val.second
        */
        immutable_map set(value_type val) const
        {
            uint32_t hash = static_cast<uint32_t>(hasher()(val.first));
            return immutable_map(set(std::move(val), hash, 0, m_root));
        }

        immutable_map set(key_type key, mapped_type value) const
        {
            return set(std::make_pair(std::move(key), std::move(value)));
        }

        /*!
          \throws key_error if the map doesn't contain the specified key.
        */
        mapped_type &operator[](const key_type &key) const
        {
            uint32_t hash = static_cast<uint32_t>(hasher()(key));
            return get(key, hash, m_root);
        }

    private:
        immutable_map(shared_node_type node)
            :m_root(std::move(node))
        {}

        static mapped_type &get(const key_type &val, uint32_t hash, const shared_node_type &node)
        {
            if(node->population)
            {
                uint32_t partial = hash & 0x1f;
                if((node->population >> partial) & 1)
                {
                    return get(val, hash >> 5, node->children[partial]);
                }
                else
                {
                    // no node with a matching key
                    throw key_error();
                }
            }
            else
            {
                // we have found a leaf
                for(auto it = node->values.begin(); it != node->values.end(); ++it)
                {
                    if(key_equals()((*it)->first, val))
                    {
                        return (*it)->second;
                    }
                    else
                    {
                        // the leaf didn't contain our value
                        throw key_error();
                    }
                }
            }
        }

        static shared_node_type set(value_type val, uint32_t hash, int level, const shared_node_type &node)
        {
            if(node->population)
            {
                uint32_t partial = hash & 0x1f;
                if((node->population >> partial) & 1)
                {
                    auto newnode = std::make_shared<node_type>(*node);
                    newnode->children[partial] = set(std::move(val), hash >> 5, level + 1, node->children[partial]);
                    return std::move(newnode);
                }
                else
                {
                    // no node with a matching key, create a new one
                    size_t num_children = popcnt(node->population);
                    auto newnode = std::make_shared<node_type>();
                    uint32_t partialbit = 1 << partial;
                    newnode->population = node->population & partialbit;
                    assert(num_children == popcnt(newnode->population) - 1);
                    newnode->children.reset(new shared_node_type[num_children + 1]);
                    uint32_t before_popcnt = popcnt(node->population & (partialbit - 1));
                    uint32_t after_popcnt = popcnt(node->population & ~(partialbit | (partialbit - 1)));
                    std::copy(node->children.get(), node->children.get() + before_popcnt, newnode->children.get());
                    newnode->children[partial] = std::make_shared<node_type>();
                    newnode->children[partial]->values.push_back(std::make_shared<value_type>(std::move(val)));
                    std::copy(node->children.get() + before_popcnt, node->children.get() + num_children, newnode->children.get() + before_popcnt + 1);
                    return std::move(newnode);
                }
            }
            else
            {
				if(node->values.size())
				{
					for(size_t i = 0; i < node->values.size(); ++i)
					{
						if(key_equals()(node->values[i]->first, val.first))
						{
							// the key already exists in the map, replace it
							auto newnode = std::make_shared<node_type>(*node);
							newnode->values[i] = std::make_shared<value_type>(std::move(val));
							return std::move(newnode);
						}
					}

					// the found leaf doesn't match the key
					if(level > 6)
					{
						auto newnode = std::make_shared<node_type>(*node);
						newnode->values.push_back(std::make_shared<value_type>(std::move(val)));
						return std::move(newnode);
					}
					else
					{
						auto splitnode = std::make_shared<node_type>();
						uint32_t oldhash = static_cast<uint32_t>(hasher()(node->values.front()->first));
						uint32_t shifted_oldhash = oldhash >> (5 * level);
						uint32_t shifted_partial = shifted_oldhash & 0x1f;
						splitnode->population = 1 << shifted_partial;
						splitnode->children.reset(new shared_node_type[1]);
						splitnode->children[0] = std::make_shared<node_type>(*node);
						return set(std::move(val), hash >> 5, level + 1, splitnode);
					}
				}
				else
				{
					// this is the root node
                    auto newnode = std::make_shared<node_type>();
                    newnode->values.push_back(std::make_shared<value_type>(std::move(val)));
                    return std::move(newnode);
				}
            }
        }

        static uint32_t popcnt(uint32_t val)
        {
            // TODO create compile time check for hardware popcnt instruction
            val = val - ((val >> 1) & 0x55555555);
            val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
            return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
        }

        shared_node_type m_root;
    };
}

#endif
<commit_msg>fixed error<commit_after>#ifndef DEEPNESS_IMMUTABLE_MAP_HPP
#define DEEPNESS_IMMUTABLE_MAP_HPP

#include <memory>
#include <functional>
#include <vector>
#include <exception>
#include <cassert>
#include <cstdint>

namespace deepness
{
    template<class Key,
             class T,
             class Hash = std::hash<Key>,
             class Pred = std::equal_to<Key> >
    class immutable_map
    {
    public:
        typedef std::pair<const Key, T> value_type;
        typedef Key key_type;
        typedef T mapped_type;
        typedef Hash hasher;
        typedef Pred key_equals;

        class key_error: public std::exception
        {
        public:
            key_error(std::string message = "")
                :m_message(std::move(message))
            {}

            const char *what() const throw() override
            {
                return m_message.c_str();
            }
        private:
            std::string m_message;
        };

    private:
        struct node_type;
        typedef std::shared_ptr<node_type> shared_node_type;
        typedef std::shared_ptr<value_type> shared_value_type;
        struct node_type
        {
            node_type()
                :population(0)
            {}

            node_type(const node_type &other)
                :population(other.population)
                ,values(other.values)
            {
                size_t num_children = popcnt(population);
                if(num_children)
                {
                    children.reset(new shared_node_type[num_children]);
                    std::copy(other.children.get(), other.children.get() + num_children, children.get());
                }
            }

            // TODO this is just a naive implementation, redo it to optimize
            uint32_t population; //!< a 0 population indicates a leaf
            std::unique_ptr<shared_node_type[]> children;
            std::vector<shared_value_type> values;
        };

    public:
        immutable_map()
            :m_root(std::make_shared<node_type>())
        {}

        /*!
          \returns a new immutable_map with val.first mapped to val.second
        */
        immutable_map set(value_type val) const
        {
            uint32_t hash = static_cast<uint32_t>(hasher()(val.first));
            return immutable_map(set(std::move(val), hash, 0, m_root));
        }

        immutable_map set(key_type key, mapped_type value) const
        {
            return set(std::make_pair(std::move(key), std::move(value)));
        }

        /*!
          \throws key_error if the map doesn't contain the specified key.
        */
        mapped_type &operator[](const key_type &key) const
        {
            uint32_t hash = static_cast<uint32_t>(hasher()(key));
            return get(key, hash, m_root);
        }

    private:
        immutable_map(shared_node_type node)
            :m_root(std::move(node))
        {}

        static mapped_type &get(const key_type &val, uint32_t hash, const shared_node_type &node)
        {
            if(node->population)
            {
                uint32_t partial = hash & 0x1f;
                if((node->population >> partial) & 1)
                {
                    return get(val, hash >> 5, node->children[partial]);
                }
                else
                {
                    // no node with a matching key
                    throw key_error();
                }
            }
            else
            {
                // we have found a leaf
                for(auto it = node->values.begin(); it != node->values.end(); ++it)
                {
                    if(key_equals()((*it)->first, val))
                    {
                        return (*it)->second;
                    }
                    else
                    {
                        // the leaf didn't contain our value
                        throw key_error();
                    }
                }
            }
        }

        static shared_node_type set(value_type val, uint32_t hash, int level, const shared_node_type &node)
        {
            if(node->population)
            {
                uint32_t partial = hash & 0x1f;
                if((node->population >> partial) & 1)
                {
                    auto newnode = std::make_shared<node_type>(*node);
                    newnode->children[partial] = set(std::move(val), hash >> 5, level + 1, node->children[partial]);
                    return std::move(newnode);
                }
                else
                {
                    // no node with a matching key, create a new one
                    size_t num_children = popcnt(node->population);
                    auto newnode = std::make_shared<node_type>();
                    uint32_t partialbit = 1 << partial;
                    newnode->population = node->population | partialbit;
                    assert(num_children == popcnt(newnode->population) - 1);
                    newnode->children.reset(new shared_node_type[num_children + 1]);
                    uint32_t before_popcnt = popcnt(node->population & (partialbit - 1));
                    uint32_t after_popcnt = popcnt(node->population & ~(partialbit | (partialbit - 1)));
                    std::copy(node->children.get(), node->children.get() + before_popcnt, newnode->children.get());
                    newnode->children[partial] = std::make_shared<node_type>();
                    newnode->children[partial]->values.push_back(std::make_shared<value_type>(std::move(val)));
                    std::copy(node->children.get() + before_popcnt, node->children.get() + num_children, newnode->children.get() + before_popcnt + 1);
                    return std::move(newnode);
                }
            }
            else
            {
				if(node->values.size())
				{
					for(size_t i = 0; i < node->values.size(); ++i)
					{
						if(key_equals()(node->values[i]->first, val.first))
						{
							// the key already exists in the map, replace it
							auto newnode = std::make_shared<node_type>(*node);
							newnode->values[i] = std::make_shared<value_type>(std::move(val));
							return std::move(newnode);
						}
					}

					// the found leaf doesn't match the key
					if(level > 6)
					{
						auto newnode = std::make_shared<node_type>(*node);
						newnode->values.push_back(std::make_shared<value_type>(std::move(val)));
						return std::move(newnode);
					}
					else
					{
						auto splitnode = std::make_shared<node_type>();
						uint32_t oldhash = static_cast<uint32_t>(hasher()(node->values.front()->first));
						uint32_t shifted_oldhash = oldhash >> (5 * level);
						uint32_t shifted_partial = shifted_oldhash & 0x1f;
						splitnode->population = 1 << shifted_partial;
						splitnode->children.reset(new shared_node_type[1]);
						splitnode->children[0] = std::make_shared<node_type>(*node);
						return set(std::move(val), hash >> 5, level + 1, splitnode);
					}
				}
				else
				{
					// this is the root node
                    auto newnode = std::make_shared<node_type>();
                    newnode->values.push_back(std::make_shared<value_type>(std::move(val)));
                    return std::move(newnode);
				}
            }
        }

        static uint32_t popcnt(uint32_t val)
        {
            // TODO create compile time check for hardware popcnt instruction
            val = val - ((val >> 1) & 0x55555555);
            val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
            return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
        }

        shared_node_type m_root;
    };
}

#endif
<|endoftext|>


<commit_before>// ----------------------------------------------------------------------------
//  This confidential and proprietary software may be used only as authorised
//  by a licensing agreement from Arm Limited.
//      (C) COPYRIGHT 2011-2020 Arm Limited, ALL RIGHTS RESERVED
//  The entire notice above must be reproduced on all authorised copies and
//  copies may only be made to the extent permitted by a licensing agreement
//  from Arm Limited.
// ----------------------------------------------------------------------------

/**
 * @brief Platform-specific function implementations.
 *
 * This module contains functions with strongly OS-dependent implementations:
 *
 *  * CPU count queries
 *  * Threading
 *  * Time
 *
 * In addition to the basic thread abstraction (which is native pthreads on
 * all platforms, except Windows where it is an emulation of pthreads), a
 * utility function to create N threads and wait for them to complete a batch
 * task has also been provided.
 */

#include "astc_codec_internals.h"

static int g_cpu_has_sse42 = -1;
static int g_cpu_has_avx2 = -1;
static int g_cpu_has_popcnt = -1;

/* ============================================================================
   Platform code for Visual Studio
============================================================================ */
#if defined(_MSC_VER)
#include <intrin.h>

static void detect_cpu_isa()
{
	int data[4];

	__cpuid(data, 0);
	int num_id = data[0];

	if (num_id >= 1)
	{
		__cpuidex(data, 1, 0);
		// SSE42 = Bank 1, ECX, bit 20
		g_cpu_has_sse42 = data[2] & (1 << 20) ? 1 : 0;
		// POPCNT = Bank 1, ECX, bit 23
		g_cpu_has_popcnt = data[2] & (1 << 23) ? 1 : 0;
	}

	if (num_id >= 7) {
		__cpuidex(data, 7, 0);
		// AVX2 = Bank 7, EBX, bit 5
		g_cpu_has_avx2 = data[1] & (1 << 5) ? 1 : 0;
	}
}

/* ============================================================================
   Platform code for GCC and Clang
============================================================================ */
#else
static void detect_cpu_isa()
{
	g_cpu_has_sse42 = __builtin_cpu_supports("sse4.2") ? 1 : 0;
	g_cpu_has_popcnt = __builtin_cpu_supports("popcnt") ? 1 : 0;
	g_cpu_has_avx2 = __builtin_cpu_supports("avx2") ? 1 : 0;
}
#endif

/* Public function, see header file for detailed documentation */
int cpu_supports_sse42()
{
	if (g_cpu_has_sse42 == -1)
		detect_cpu_isa();

	return g_cpu_has_sse42;
}

/* Public function, see header file for detailed documentation */
int cpu_supports_popcnt()
{
	if (g_cpu_has_popcnt == -1)
		detect_cpu_isa();

	return g_cpu_has_popcnt;
}

/* Public function, see header file for detailed documentation */
int cpu_supports_avx2()
{
	if (g_cpu_has_avx2 == -1)
		detect_cpu_isa();

	return g_cpu_has_avx2;
}<commit_msg>Cleanup platform ISA help text and header<commit_after>// SPDX-License-Identifier: Apache-2.0
// ----------------------------------------------------------------------------
// Copyright 2020 Arm Limited
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
// ----------------------------------------------------------------------------

/**
 * @brief Platform-specific function implementations.
 *
 * This module contains functions for querying the host extended ISA support.
 */

#include "astc_codec_internals.h"

static int g_cpu_has_sse42 = -1;
static int g_cpu_has_avx2 = -1;
static int g_cpu_has_popcnt = -1;

/* ============================================================================
   Platform code for Visual Studio
============================================================================ */
#if defined(_MSC_VER)
#include <intrin.h>

static void detect_cpu_isa()
{
	int data[4];

	__cpuid(data, 0);
	int num_id = data[0];

	if (num_id >= 1)
	{
		__cpuidex(data, 1, 0);
		// SSE42 = Bank 1, ECX, bit 20
		g_cpu_has_sse42 = data[2] & (1 << 20) ? 1 : 0;
		// POPCNT = Bank 1, ECX, bit 23
		g_cpu_has_popcnt = data[2] & (1 << 23) ? 1 : 0;
	}

	if (num_id >= 7) {
		__cpuidex(data, 7, 0);
		// AVX2 = Bank 7, EBX, bit 5
		g_cpu_has_avx2 = data[1] & (1 << 5) ? 1 : 0;
	}
}

/* ============================================================================
   Platform code for GCC and Clang
============================================================================ */
#else
static void detect_cpu_isa()
{
	g_cpu_has_sse42 = __builtin_cpu_supports("sse4.2") ? 1 : 0;
	g_cpu_has_popcnt = __builtin_cpu_supports("popcnt") ? 1 : 0;
	g_cpu_has_avx2 = __builtin_cpu_supports("avx2") ? 1 : 0;
}
#endif

/* Public function, see header file for detailed documentation */
int cpu_supports_sse42()
{
	if (g_cpu_has_sse42 == -1)
		detect_cpu_isa();

	return g_cpu_has_sse42;
}

/* Public function, see header file for detailed documentation */
int cpu_supports_popcnt()
{
	if (g_cpu_has_popcnt == -1)
		detect_cpu_isa();

	return g_cpu_has_popcnt;
}

/* Public function, see header file for detailed documentation */
int cpu_supports_avx2()
{
	if (g_cpu_has_avx2 == -1)
		detect_cpu_isa();

	return g_cpu_has_avx2;
}<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#include "caf/config.hpp"

// this suite tests whether actors terminate as expect in several use cases
#define CAF_SUITE thread_hook

#include "caf/all.hpp"
#include "caf/test/unit_test.hpp"

using namespace caf;

namespace {

using atomic_count = std::atomic<size_t>;

size_t assumed_thread_count;
size_t assumed_init_calls;

std::mutex mx;

struct dummy_thread_hook : thread_hook {
  void init(actor_system&) override {
    // nop
  }

  void thread_started() override {
    // nop
  }

  void thread_terminates() override {
    // nop
  }
};

class counting_thread_hook : public thread_hook {
public:
  counting_thread_hook()
      : count_init_{0},
        count_thread_started_{0},
        count_thread_terminates_{0} {
    // nop
  }

  ~counting_thread_hook() override {
    CAF_CHECK_EQUAL(count_init_, assumed_init_calls);
    CAF_CHECK_EQUAL(count_thread_started_, assumed_thread_count);
    CAF_CHECK_EQUAL(count_thread_terminates_, assumed_thread_count);
  }

  void init(actor_system&) override {
    ++count_init_;
  }

  void thread_started() override {
    ++count_thread_started_;
  }

  void thread_terminates() override {
    ++count_thread_terminates_;
  }

private:
  atomic_count count_init_;
  atomic_count count_thread_started_;
  atomic_count count_thread_terminates_;
};

template <class Hook>
struct config : actor_system_config {
  config() {
    add_thread_hook<Hook>();
    set("logger.verbosity", atom("quiet"));
  }
};

template <class Hook>
struct fixture {
  config<Hook> cfg;
  actor_system sys;
  fixture() : sys(cfg) {
    // nop
  }
};

} // namespace <anonymous>

CAF_TEST(counting_no_system) {
  assumed_init_calls = 0;
  actor_system_config cfg;
  cfg.add_thread_hook<counting_thread_hook>();
}

CAF_TEST_FIXTURE_SCOPE(dummy_hook, fixture<dummy_thread_hook>)

CAF_TEST(counting_no_args) {
  // nop
}

CAF_TEST_FIXTURE_SCOPE_END()

CAF_TEST_FIXTURE_SCOPE(counting_hook, fixture<counting_thread_hook>)

CAF_TEST(counting_system_without_actor) {
  assumed_init_calls = 1;
  assumed_thread_count = get_or(cfg, "scheduler.max-threads",
                                defaults::scheduler::max_threads)
                         + 2; // caf.clock and caf.logger
  auto& sched = sys.scheduler();
  if (sched.detaches_utility_actors())
    assumed_thread_count += sched.num_utility_actors();
}

CAF_TEST(counting_system_with_actor) {
  assumed_init_calls = 1;
  assumed_thread_count = get_or(cfg, "scheduler.max-threads",
                                defaults::scheduler::max_threads)
                         + 3; // caf.clock, caf.logger, and detached actor
  auto& sched = sys.scheduler();
  if (sched.detaches_utility_actors())
    assumed_thread_count += sched.num_utility_actors();
  sys.spawn<detached>([] {});
  sys.spawn([] {});
}

CAF_TEST_FIXTURE_SCOPE_END()

<commit_msg>Fix thread_hook unit test<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#include "caf/config.hpp"

// this suite tests whether actors terminate as expect in several use cases
#define CAF_SUITE thread_hook

#include "caf/all.hpp"
#include "caf/test/unit_test.hpp"

using namespace caf;

namespace {

using atomic_count = std::atomic<size_t>;

size_t assumed_thread_count;
size_t assumed_init_calls;

std::mutex mx;

struct dummy_thread_hook : thread_hook {
  void init(actor_system&) override {
    // nop
  }

  void thread_started() override {
    // nop
  }

  void thread_terminates() override {
    // nop
  }
};

class counting_thread_hook : public thread_hook {
public:
  counting_thread_hook()
      : count_init_{0},
        count_thread_started_{0},
        count_thread_terminates_{0} {
    // nop
  }

  ~counting_thread_hook() override {
    CAF_CHECK_EQUAL(count_init_, assumed_init_calls);
    CAF_CHECK_EQUAL(count_thread_started_, assumed_thread_count);
    CAF_CHECK_EQUAL(count_thread_terminates_, assumed_thread_count);
  }

  void init(actor_system&) override {
    ++count_init_;
  }

  void thread_started() override {
    ++count_thread_started_;
  }

  void thread_terminates() override {
    ++count_thread_terminates_;
  }

private:
  atomic_count count_init_;
  atomic_count count_thread_started_;
  atomic_count count_thread_terminates_;
};

template <class Hook>
struct config : actor_system_config {
  config() {
    add_thread_hook<Hook>();
    set("logger.verbosity", atom("quiet"));
  }
};

template <class Hook>
struct fixture {
  config<Hook> cfg;
  actor_system sys;
  fixture() : sys(cfg) {
    // nop
  }
};

} // namespace <anonymous>

CAF_TEST(counting_no_system) {
  assumed_init_calls = 0;
  actor_system_config cfg;
  cfg.add_thread_hook<counting_thread_hook>();
}

CAF_TEST_FIXTURE_SCOPE(dummy_hook, fixture<dummy_thread_hook>)

CAF_TEST(counting_no_args) {
  // nop
}

CAF_TEST_FIXTURE_SCOPE_END()

CAF_TEST_FIXTURE_SCOPE(counting_hook, fixture<counting_thread_hook>)

CAF_TEST(counting_system_without_actor) {
  assumed_init_calls = 1;
  assumed_thread_count = get_or(cfg, "scheduler.max-threads",
                                defaults::scheduler::max_threads)
                         + 1; // caf.clock
  auto& sched = sys.scheduler();
  if (sched.detaches_utility_actors())
    assumed_thread_count += sched.num_utility_actors();
}

CAF_TEST(counting_system_with_actor) {
  assumed_init_calls = 1;
  assumed_thread_count = get_or(cfg, "scheduler.max-threads",
                                defaults::scheduler::max_threads)
                         + 2; // caf.clock and detached actor
  auto& sched = sys.scheduler();
  if (sched.detaches_utility_actors())
    assumed_thread_count += sched.num_utility_actors();
  sys.spawn<detached>([] {});
  sys.spawn([] {});
}

CAF_TEST_FIXTURE_SCOPE_END()

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
 * Copyright (C) 2011 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "config.h"

#include "core/svg/SVGElementInstance.h"

#include "core/dom/ContainerNodeAlgorithms.h"
#include "core/events/Event.h"
#include "core/events/EventListener.h"
#include "core/svg/SVGElement.h"
#include "core/svg/SVGUseElement.h"

#include "wtf/RefCountedLeakCounter.h"

namespace WebCore {

DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, instanceCounter, ("WebCoreSVGElementInstance"));

// EventTarget API
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), abort);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), blur);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), change);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), click);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), contextmenu);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dblclick);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), error);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), focus);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), input);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), keydown);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), keypress);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), keyup);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), load);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mousedown);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseenter);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseleave);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mousemove);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseout);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseover);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseup);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mousewheel);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), wheel);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), beforecut);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), cut);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), beforecopy);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), copy);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), beforepaste);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), paste);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragenter);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragover);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragleave);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), drop);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragstart);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), drag);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragend);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), reset);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), resize);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), scroll);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), search);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), select);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), selectstart);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), submit);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), unload);

PassRefPtr<SVGElementInstance> SVGElementInstance::create(SVGUseElement* correspondingUseElement, SVGUseElement* directUseElement, PassRefPtr<SVGElement> originalElement)
{
    return adoptRef(new SVGElementInstance(correspondingUseElement, directUseElement, originalElement));
}

SVGElementInstance::SVGElementInstance(SVGUseElement* correspondingUseElement, SVGUseElement* directUseElement, PassRefPtr<SVGElement> originalElement)
    : m_parentInstance(nullptr)
    , m_correspondingUseElement(correspondingUseElement)
    , m_directUseElement(directUseElement)
    , m_element(originalElement)
    , m_previousSibling(nullptr)
    , m_nextSibling(nullptr)
    , m_firstChild(nullptr)
    , m_lastChild(nullptr)
{
    ASSERT(m_correspondingUseElement);
    ASSERT(m_element);
    ScriptWrappable::init(this);

#ifndef NDEBUG
    instanceCounter.increment();
#endif
}

SVGElementInstance::~SVGElementInstance()
{
#ifndef NDEBUG
    instanceCounter.decrement();
#endif

#if !ENABLE(OILPAN)
    // Call detach because we may be deleted directly if we are a child of a detached instance.
    detach();
    m_element = nullptr;
#endif
}

// It's important not to inline removedLastRef, because we don't want to inline the code to
// delete an SVGElementInstance at each deref call site.
void SVGElementInstance::removedLastRef()
{
#if !ENABLE(OILPAN)
#if SECURITY_ASSERT_ENABLED
    m_deletionHasBegun = true;
#endif
    delete this;
#endif
}

void SVGElementInstance::detach()
{
    // Clear all pointers. When the node is detached from the shadow DOM it should be removed but,
    // due to ref counting, it may not be. So clear everything to avoid dangling pointers.

    for (SVGElementInstance* node = firstChild(); node; node = node->nextSibling())
        node->detach();

    // Deregister as instance for passed element, if we haven't already.
    if (m_element->instancesForElement().contains(shadowTreeElement()))
        m_element->removeInstanceMapping(this);
    // DO NOT clear ref to m_element because JavaScriptCore uses it for garbage collection

    m_shadowTreeElement = nullptr;

    m_directUseElement = 0;
    m_correspondingUseElement = 0;

#if !ENABLE(OILPAN)
    removeDetachedChildrenInContainer<SVGElementInstance, SVGElementInstance>(*this);
#endif
}

void SVGElementInstance::setShadowTreeElement(SVGElement* element)
{
    ASSERT(element);
    m_shadowTreeElement = element;
    // Register as instance for passed element.
    m_element->mapInstanceToElement(this);

}

void SVGElementInstance::appendChild(PassRefPtr<SVGElementInstance> child)
{
    appendChildToContainer<SVGElementInstance, SVGElementInstance>(*child, *this);
}

const AtomicString& SVGElementInstance::interfaceName() const
{
    return EventTargetNames::SVGElementInstance;
}

ExecutionContext* SVGElementInstance::executionContext() const
{
    return &m_element->document();
}

bool SVGElementInstance::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
{
    return m_element->addEventListener(eventType, listener, useCapture);
}

bool SVGElementInstance::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
{
    return m_element->removeEventListener(eventType, listener, useCapture);
}

void SVGElementInstance::removeAllEventListeners()
{
    m_element->removeAllEventListeners();
}

Node* SVGElementInstance::toNode()
{
    return shadowTreeElement();
}

Document* SVGElementInstance::ownerDocument() const
{
    return m_element ? m_element->ownerDocument() : 0;
}

bool SVGElementInstance::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
{
    SVGElement* element = shadowTreeElement();
    if (!element)
        return false;

    return element->dispatchEvent(event);
}

EventTargetData* SVGElementInstance::eventTargetData()
{
    // Since no event listeners are added to an SVGElementInstance, we don't have eventTargetData.
    return 0;
}

EventTargetData& SVGElementInstance::ensureEventTargetData()
{
    // EventTarget would use these methods if we were actually using its add/removeEventListener logic.
    // As we're forwarding those calls to the correspondingElement(), no one should ever call this function.
    ASSERT_NOT_REACHED();
    return *eventTargetData();
}

void SVGElementInstance::trace(Visitor* visitor)
{
    visitor->trace(m_parentInstance);
    visitor->trace(m_element);
    visitor->trace(m_shadowTreeElement);
    visitor->trace(m_previousSibling);
    visitor->trace(m_nextSibling);
    visitor->trace(m_firstChild);
    visitor->trace(m_lastChild);
}

}
<commit_msg>Fix HashSet misuse in SVGElementInstance::detach()<commit_after>/*
 * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
 * Copyright (C) 2011 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "config.h"

#include "core/svg/SVGElementInstance.h"

#include "core/dom/ContainerNodeAlgorithms.h"
#include "core/events/Event.h"
#include "core/events/EventListener.h"
#include "core/svg/SVGElement.h"
#include "core/svg/SVGUseElement.h"

#include "wtf/RefCountedLeakCounter.h"

namespace WebCore {

DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, instanceCounter, ("WebCoreSVGElementInstance"));

// EventTarget API
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), abort);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), blur);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), change);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), click);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), contextmenu);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dblclick);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), error);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), focus);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), input);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), keydown);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), keypress);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), keyup);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), load);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mousedown);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseenter);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseleave);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mousemove);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseout);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseover);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mouseup);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), mousewheel);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), wheel);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), beforecut);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), cut);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), beforecopy);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), copy);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), beforepaste);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), paste);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragenter);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragover);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragleave);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), drop);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragstart);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), drag);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), dragend);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), reset);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), resize);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), scroll);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), search);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), select);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), selectstart);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), submit);
DEFINE_FORWARDING_ATTRIBUTE_EVENT_LISTENER(SVGElementInstance, correspondingElement(), unload);

PassRefPtr<SVGElementInstance> SVGElementInstance::create(SVGUseElement* correspondingUseElement, SVGUseElement* directUseElement, PassRefPtr<SVGElement> originalElement)
{
    return adoptRef(new SVGElementInstance(correspondingUseElement, directUseElement, originalElement));
}

SVGElementInstance::SVGElementInstance(SVGUseElement* correspondingUseElement, SVGUseElement* directUseElement, PassRefPtr<SVGElement> originalElement)
    : m_parentInstance(nullptr)
    , m_correspondingUseElement(correspondingUseElement)
    , m_directUseElement(directUseElement)
    , m_element(originalElement)
    , m_previousSibling(nullptr)
    , m_nextSibling(nullptr)
    , m_firstChild(nullptr)
    , m_lastChild(nullptr)
{
    ASSERT(m_correspondingUseElement);
    ASSERT(m_element);
    ScriptWrappable::init(this);

#ifndef NDEBUG
    instanceCounter.increment();
#endif
}

SVGElementInstance::~SVGElementInstance()
{
#ifndef NDEBUG
    instanceCounter.decrement();
#endif

#if !ENABLE(OILPAN)
    // Call detach because we may be deleted directly if we are a child of a detached instance.
    detach();
    m_element = nullptr;
#endif
}

// It's important not to inline removedLastRef, because we don't want to inline the code to
// delete an SVGElementInstance at each deref call site.
void SVGElementInstance::removedLastRef()
{
#if !ENABLE(OILPAN)
#if SECURITY_ASSERT_ENABLED
    m_deletionHasBegun = true;
#endif
    delete this;
#endif
}

void SVGElementInstance::detach()
{
    // Clear all pointers. When the node is detached from the shadow DOM it should be removed but,
    // due to ref counting, it may not be. So clear everything to avoid dangling pointers.

    for (SVGElementInstance* node = firstChild(); node; node = node->nextSibling())
        node->detach();

    // Deregister as instance for passed element, if we haven't already.
    if (shadowTreeElement() && m_element->instancesForElement().contains(shadowTreeElement()))
        m_element->removeInstanceMapping(this);
    // DO NOT clear ref to m_element because JavaScriptCore uses it for garbage collection

    m_shadowTreeElement = nullptr;

    m_directUseElement = 0;
    m_correspondingUseElement = 0;

#if !ENABLE(OILPAN)
    removeDetachedChildrenInContainer<SVGElementInstance, SVGElementInstance>(*this);
#endif
}

void SVGElementInstance::setShadowTreeElement(SVGElement* element)
{
    ASSERT(element);
    m_shadowTreeElement = element;
    // Register as instance for passed element.
    m_element->mapInstanceToElement(this);

}

void SVGElementInstance::appendChild(PassRefPtr<SVGElementInstance> child)
{
    appendChildToContainer<SVGElementInstance, SVGElementInstance>(*child, *this);
}

const AtomicString& SVGElementInstance::interfaceName() const
{
    return EventTargetNames::SVGElementInstance;
}

ExecutionContext* SVGElementInstance::executionContext() const
{
    return &m_element->document();
}

bool SVGElementInstance::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
{
    return m_element->addEventListener(eventType, listener, useCapture);
}

bool SVGElementInstance::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
{
    return m_element->removeEventListener(eventType, listener, useCapture);
}

void SVGElementInstance::removeAllEventListeners()
{
    m_element->removeAllEventListeners();
}

Node* SVGElementInstance::toNode()
{
    return shadowTreeElement();
}

Document* SVGElementInstance::ownerDocument() const
{
    return m_element ? m_element->ownerDocument() : 0;
}

bool SVGElementInstance::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
{
    SVGElement* element = shadowTreeElement();
    if (!element)
        return false;

    return element->dispatchEvent(event);
}

EventTargetData* SVGElementInstance::eventTargetData()
{
    // Since no event listeners are added to an SVGElementInstance, we don't have eventTargetData.
    return 0;
}

EventTargetData& SVGElementInstance::ensureEventTargetData()
{
    // EventTarget would use these methods if we were actually using its add/removeEventListener logic.
    // As we're forwarding those calls to the correspondingElement(), no one should ever call this function.
    ASSERT_NOT_REACHED();
    return *eventTargetData();
}

void SVGElementInstance::trace(Visitor* visitor)
{
    visitor->trace(m_parentInstance);
    visitor->trace(m_element);
    visitor->trace(m_shadowTreeElement);
    visitor->trace(m_previousSibling);
    visitor->trace(m_nextSibling);
    visitor->trace(m_firstChild);
    visitor->trace(m_lastChild);
}

}
<|endoftext|>


<commit_before><commit_msg>Updating test log inputs to include accumulative test duration at different steps in testing. Review URL: http://codereview.chromium.org/52038<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/worker/worker_webkitclient_impl.h"

#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/database_util.h"
#include "chrome/common/file_system/webfilesystem_impl.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "chrome/common/webblobregistry_impl.h"
#include "chrome/common/webmessageportchannel_impl.h"
#include "chrome/worker/worker_thread.h"
#include "ipc/ipc_sync_message_filter.h"
#include "third_party/WebKit/WebKit/chromium/public/WebBlobRegistry.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
#include "webkit/glue/webfileutilities_impl.h"
#include "webkit/glue/webkit_glue.h"

using WebKit::WebBlobRegistry;
using WebKit::WebClipboard;
using WebKit::WebFileSystem;
using WebKit::WebFileUtilities;
using WebKit::WebKitClient;
using WebKit::WebMessagePortChannel;
using WebKit::WebMimeRegistry;
using WebKit::WebSandboxSupport;
using WebKit::WebSharedWorkerRepository;
using WebKit::WebStorageNamespace;
using WebKit::WebString;
using WebKit::WebURL;

// TODO(kinuko): Probably this could be consolidated into
// RendererWebKitClientImpl::FileUtilities.
class WorkerWebKitClientImpl::FileUtilities
    : public webkit_glue::WebFileUtilitiesImpl {
 public:
  virtual bool getFileSize(const WebKit::WebString& path, long long& result);
  virtual bool getFileModificationTime(const WebKit::WebString& path,
                                       double& result);
};

static bool SendSyncMessageFromAnyThread(IPC::SyncMessage* msg) {
  WorkerThread* worker_thread = WorkerThread::current();
  if (worker_thread)
    return worker_thread->Send(msg);

  scoped_refptr<IPC::SyncMessageFilter> sync_msg_filter =
      ChildThread::current()->sync_message_filter();
  return sync_msg_filter->Send(msg);
}

bool WorkerWebKitClientImpl::FileUtilities::getFileSize(const WebString& path,
                                                        long long& result) {
  if (SendSyncMessageFromAnyThread(new ViewHostMsg_GetFileSize(
          webkit_glue::WebStringToFilePath(path),
          reinterpret_cast<int64*>(&result)))) {
    return result >= 0;
  }

  result = -1;
  return false;
}

bool WorkerWebKitClientImpl::FileUtilities::getFileModificationTime(
    const WebString& path,
    double& result) {
  base::Time time;
  if (SendSyncMessageFromAnyThread(new ViewHostMsg_GetFileModificationTime(
          webkit_glue::WebStringToFilePath(path), &time))) {
    result = time.ToDoubleT();
    return !time.is_null();
  }

  result = 0;
  return false;
}

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

WorkerWebKitClientImpl::WorkerWebKitClientImpl() {
}

WorkerWebKitClientImpl::~WorkerWebKitClientImpl() {
}

WebClipboard* WorkerWebKitClientImpl::clipboard() {
  NOTREACHED();
  return NULL;
}

WebMimeRegistry* WorkerWebKitClientImpl::mimeRegistry() {
  return this;
}

WebFileSystem* WorkerWebKitClientImpl::fileSystem() {
  if (!web_file_system_.get())
    web_file_system_.reset(new WebFileSystemImpl());
  return web_file_system_.get();
}

WebFileUtilities* WorkerWebKitClientImpl::fileUtilities() {
  if (!file_utilities_.get()) {
    file_utilities_.reset(new FileUtilities);
    file_utilities_->set_sandbox_enabled(sandboxEnabled());
  }
  return file_utilities_.get();
}

WebSandboxSupport* WorkerWebKitClientImpl::sandboxSupport() {
  NOTREACHED();
  return NULL;
}

bool WorkerWebKitClientImpl::sandboxEnabled() {
  // Always return true because WebKit should always act as though the Sandbox
  // is enabled for workers.  See the comment in WebKitClient for more info.
  return true;
}

unsigned long long WorkerWebKitClientImpl::visitedLinkHash(
    const char* canonical_url,
    size_t length) {
  NOTREACHED();
  return 0;
}

bool WorkerWebKitClientImpl::isLinkVisited(unsigned long long link_hash) {
  NOTREACHED();
  return false;
}

WebMessagePortChannel*
WorkerWebKitClientImpl::createMessagePortChannel() {
  return new WebMessagePortChannelImpl();
}

void WorkerWebKitClientImpl::setCookies(const WebURL& url,
                                        const WebURL& first_party_for_cookies,
                                        const WebString& value) {
  NOTREACHED();
}

WebString WorkerWebKitClientImpl::cookies(
    const WebURL& url, const WebURL& first_party_for_cookies) {
  // WebSocketHandshake may access cookies in worker process.
  return WebString();
}

void WorkerWebKitClientImpl::prefetchHostName(const WebString&) {
  NOTREACHED();
}

WebString WorkerWebKitClientImpl::defaultLocale() {
  NOTREACHED();
  return WebString();
}

WebStorageNamespace* WorkerWebKitClientImpl::createLocalStorageNamespace(
    const WebString& path, unsigned quota) {
  NOTREACHED();
  return 0;
}

void WorkerWebKitClientImpl::dispatchStorageEvent(
    const WebString& key, const WebString& old_value,
    const WebString& new_value, const WebString& origin,
    const WebKit::WebURL& url, bool is_local_storage) {
  NOTREACHED();
}

WebSharedWorkerRepository* WorkerWebKitClientImpl::sharedWorkerRepository() {
    return 0;
}

WebKitClient::FileHandle WorkerWebKitClientImpl::databaseOpenFile(
    const WebString& vfs_file_name, int desired_flags) {
  return DatabaseUtil::databaseOpenFile(vfs_file_name, desired_flags);
}

int WorkerWebKitClientImpl::databaseDeleteFile(
    const WebString& vfs_file_name, bool sync_dir) {
  return DatabaseUtil::databaseDeleteFile(vfs_file_name, sync_dir);
}

long WorkerWebKitClientImpl::databaseGetFileAttributes(
    const WebString& vfs_file_name) {
  return DatabaseUtil::databaseGetFileAttributes(vfs_file_name);
}

long long WorkerWebKitClientImpl::databaseGetFileSize(
    const WebString& vfs_file_name) {
  return DatabaseUtil::databaseGetFileSize(vfs_file_name);
}

WebMimeRegistry::SupportsType WorkerWebKitClientImpl::supportsMIMEType(
    const WebString&) {
  return WebMimeRegistry::IsSupported;
}

WebMimeRegistry::SupportsType WorkerWebKitClientImpl::supportsImageMIMEType(
    const WebString&) {
  NOTREACHED();
  return WebMimeRegistry::IsSupported;
}

WebMimeRegistry::SupportsType
WorkerWebKitClientImpl::supportsJavaScriptMIMEType(const WebString&) {
  NOTREACHED();
  return WebMimeRegistry::IsSupported;
}

WebMimeRegistry::SupportsType WorkerWebKitClientImpl::supportsMediaMIMEType(
    const WebString&, const WebString&) {
  NOTREACHED();
  return WebMimeRegistry::IsSupported;
}

WebMimeRegistry::SupportsType WorkerWebKitClientImpl::supportsNonImageMIMEType(
    const WebString&) {
  NOTREACHED();
  return WebMimeRegistry::IsSupported;
}

WebString WorkerWebKitClientImpl::mimeTypeForExtension(
    const WebString& file_extension) {
  std::string mime_type;
  WorkerThread::current()->Send(new ViewHostMsg_GetMimeTypeFromExtension(
      webkit_glue::WebStringToFilePathString(file_extension), &mime_type));
  return ASCIIToUTF16(mime_type);
}

WebString WorkerWebKitClientImpl::mimeTypeFromFile(
    const WebString& file_path) {
  std::string mime_type;
  WorkerThread::current()->Send(new ViewHostMsg_GetMimeTypeFromFile(
      FilePath(webkit_glue::WebStringToFilePathString(file_path)),
      &mime_type));
  return ASCIIToUTF16(mime_type);
}

WebString WorkerWebKitClientImpl::preferredExtensionForMIMEType(
    const WebString& mime_type) {
  FilePath::StringType file_extension;
  WorkerThread::current()->Send(
      new ViewHostMsg_GetPreferredExtensionForMimeType(UTF16ToASCII(mime_type),
          &file_extension));
  return webkit_glue::FilePathStringToWebString(file_extension);
}

WebBlobRegistry* WorkerWebKitClientImpl::blobRegistry() {
  if (!blob_registry_.get())
    blob_registry_.reset(new WebBlobRegistryImpl(WorkerThread::current()));
  return blob_registry_.get();
}
<commit_msg>Revert "Revert r63457, "WorkerWebKitClientImpl::mimeTypeForExtension should not use WorkerThread::current""<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/worker/worker_webkitclient_impl.h"

#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/database_util.h"
#include "chrome/common/file_system/webfilesystem_impl.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "chrome/common/webblobregistry_impl.h"
#include "chrome/common/webmessageportchannel_impl.h"
#include "chrome/worker/worker_thread.h"
#include "ipc/ipc_sync_message_filter.h"
#include "third_party/WebKit/WebKit/chromium/public/WebBlobRegistry.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
#include "webkit/glue/webfileutilities_impl.h"
#include "webkit/glue/webkit_glue.h"

using WebKit::WebBlobRegistry;
using WebKit::WebClipboard;
using WebKit::WebFileSystem;
using WebKit::WebFileUtilities;
using WebKit::WebKitClient;
using WebKit::WebMessagePortChannel;
using WebKit::WebMimeRegistry;
using WebKit::WebSandboxSupport;
using WebKit::WebSharedWorkerRepository;
using WebKit::WebStorageNamespace;
using WebKit::WebString;
using WebKit::WebURL;

// TODO(kinuko): Probably this could be consolidated into
// RendererWebKitClientImpl::FileUtilities.
class WorkerWebKitClientImpl::FileUtilities
    : public webkit_glue::WebFileUtilitiesImpl {
 public:
  virtual bool getFileSize(const WebKit::WebString& path, long long& result);
  virtual bool getFileModificationTime(const WebKit::WebString& path,
                                       double& result);
};

static bool SendSyncMessageFromAnyThread(IPC::SyncMessage* msg) {
  WorkerThread* worker_thread = WorkerThread::current();
  if (worker_thread)
    return worker_thread->Send(msg);

  scoped_refptr<IPC::SyncMessageFilter> sync_msg_filter =
      ChildThread::current()->sync_message_filter();
  return sync_msg_filter->Send(msg);
}

bool WorkerWebKitClientImpl::FileUtilities::getFileSize(const WebString& path,
                                                        long long& result) {
  if (SendSyncMessageFromAnyThread(new ViewHostMsg_GetFileSize(
          webkit_glue::WebStringToFilePath(path),
          reinterpret_cast<int64*>(&result)))) {
    return result >= 0;
  }

  result = -1;
  return false;
}

bool WorkerWebKitClientImpl::FileUtilities::getFileModificationTime(
    const WebString& path,
    double& result) {
  base::Time time;
  if (SendSyncMessageFromAnyThread(new ViewHostMsg_GetFileModificationTime(
          webkit_glue::WebStringToFilePath(path), &time))) {
    result = time.ToDoubleT();
    return !time.is_null();
  }

  result = 0;
  return false;
}

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

WorkerWebKitClientImpl::WorkerWebKitClientImpl() {
}

WorkerWebKitClientImpl::~WorkerWebKitClientImpl() {
}

WebClipboard* WorkerWebKitClientImpl::clipboard() {
  NOTREACHED();
  return NULL;
}

WebMimeRegistry* WorkerWebKitClientImpl::mimeRegistry() {
  return this;
}

WebFileSystem* WorkerWebKitClientImpl::fileSystem() {
  if (!web_file_system_.get())
    web_file_system_.reset(new WebFileSystemImpl());
  return web_file_system_.get();
}

WebFileUtilities* WorkerWebKitClientImpl::fileUtilities() {
  if (!file_utilities_.get()) {
    file_utilities_.reset(new FileUtilities);
    file_utilities_->set_sandbox_enabled(sandboxEnabled());
  }
  return file_utilities_.get();
}

WebSandboxSupport* WorkerWebKitClientImpl::sandboxSupport() {
  NOTREACHED();
  return NULL;
}

bool WorkerWebKitClientImpl::sandboxEnabled() {
  // Always return true because WebKit should always act as though the Sandbox
  // is enabled for workers.  See the comment in WebKitClient for more info.
  return true;
}

unsigned long long WorkerWebKitClientImpl::visitedLinkHash(
    const char* canonical_url,
    size_t length) {
  NOTREACHED();
  return 0;
}

bool WorkerWebKitClientImpl::isLinkVisited(unsigned long long link_hash) {
  NOTREACHED();
  return false;
}

WebMessagePortChannel*
WorkerWebKitClientImpl::createMessagePortChannel() {
  return new WebMessagePortChannelImpl();
}

void WorkerWebKitClientImpl::setCookies(const WebURL& url,
                                        const WebURL& first_party_for_cookies,
                                        const WebString& value) {
  NOTREACHED();
}

WebString WorkerWebKitClientImpl::cookies(
    const WebURL& url, const WebURL& first_party_for_cookies) {
  // WebSocketHandshake may access cookies in worker process.
  return WebString();
}

void WorkerWebKitClientImpl::prefetchHostName(const WebString&) {
  NOTREACHED();
}

WebString WorkerWebKitClientImpl::defaultLocale() {
  NOTREACHED();
  return WebString();
}

WebStorageNamespace* WorkerWebKitClientImpl::createLocalStorageNamespace(
    const WebString& path, unsigned quota) {
  NOTREACHED();
  return 0;
}

void WorkerWebKitClientImpl::dispatchStorageEvent(
    const WebString& key, const WebString& old_value,
    const WebString& new_value, const WebString& origin,
    const WebKit::WebURL& url, bool is_local_storage) {
  NOTREACHED();
}

WebSharedWorkerRepository* WorkerWebKitClientImpl::sharedWorkerRepository() {
    return 0;
}

WebKitClient::FileHandle WorkerWebKitClientImpl::databaseOpenFile(
    const WebString& vfs_file_name, int desired_flags) {
  return DatabaseUtil::databaseOpenFile(vfs_file_name, desired_flags);
}

int WorkerWebKitClientImpl::databaseDeleteFile(
    const WebString& vfs_file_name, bool sync_dir) {
  return DatabaseUtil::databaseDeleteFile(vfs_file_name, sync_dir);
}

long WorkerWebKitClientImpl::databaseGetFileAttributes(
    const WebString& vfs_file_name) {
  return DatabaseUtil::databaseGetFileAttributes(vfs_file_name);
}

long long WorkerWebKitClientImpl::databaseGetFileSize(
    const WebString& vfs_file_name) {
  return DatabaseUtil::databaseGetFileSize(vfs_file_name);
}

WebMimeRegistry::SupportsType WorkerWebKitClientImpl::supportsMIMEType(
    const WebString&) {
  return WebMimeRegistry::IsSupported;
}

WebMimeRegistry::SupportsType WorkerWebKitClientImpl::supportsImageMIMEType(
    const WebString&) {
  NOTREACHED();
  return WebMimeRegistry::IsSupported;
}

WebMimeRegistry::SupportsType
WorkerWebKitClientImpl::supportsJavaScriptMIMEType(const WebString&) {
  NOTREACHED();
  return WebMimeRegistry::IsSupported;
}

WebMimeRegistry::SupportsType WorkerWebKitClientImpl::supportsMediaMIMEType(
    const WebString&, const WebString&) {
  NOTREACHED();
  return WebMimeRegistry::IsSupported;
}

WebMimeRegistry::SupportsType WorkerWebKitClientImpl::supportsNonImageMIMEType(
    const WebString&) {
  NOTREACHED();
  return WebMimeRegistry::IsSupported;
}

WebString WorkerWebKitClientImpl::mimeTypeForExtension(
    const WebString& file_extension) {
  std::string mime_type;
  SendSyncMessageFromAnyThread(new ViewHostMsg_GetMimeTypeFromExtension(
      webkit_glue::WebStringToFilePathString(file_extension), &mime_type));
  return ASCIIToUTF16(mime_type);
}

WebString WorkerWebKitClientImpl::mimeTypeFromFile(
    const WebString& file_path) {
  std::string mime_type;
  SendSyncMessageFromAnyThread(new ViewHostMsg_GetMimeTypeFromFile(
      FilePath(webkit_glue::WebStringToFilePathString(file_path)),
      &mime_type));
  return ASCIIToUTF16(mime_type);
}

WebString WorkerWebKitClientImpl::preferredExtensionForMIMEType(
    const WebString& mime_type) {
  FilePath::StringType file_extension;
  SendSyncMessageFromAnyThread(
      new ViewHostMsg_GetPreferredExtensionForMimeType(UTF16ToASCII(mime_type),
          &file_extension));
  return webkit_glue::FilePathStringToWebString(file_extension);
}

WebBlobRegistry* WorkerWebKitClientImpl::blobRegistry() {
  if (!blob_registry_.get())
    blob_registry_.reset(new WebBlobRegistryImpl(WorkerThread::current()));
  return blob_registry_.get();
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "WebDevToolsFrontendImpl.h"

#include "InspectorFrontendClientImpl.h"
#include "V8InspectorFrontendHost.h"
#include "V8MouseEvent.h"
#include "V8Node.h"
#include "WebDevToolsFrontendClient.h"
#include "WebFrameImpl.h"
#include "WebScriptSource.h"
#include "WebViewImpl.h"
#include "bindings/v8/ScriptController.h"
#include "bindings/v8/V8Binding.h"
#include "bindings/v8/V8DOMWrapper.h"
#include "bindings/v8/V8Utilities.h"
#include "core/dom/Document.h"
#include "core/dom/Event.h"
#include "core/dom/Node.h"
#include "core/inspector/InspectorController.h"
#include "core/inspector/InspectorFrontendHost.h"
#include "core/page/ContextMenuController.h"
#include "core/page/DOMWindow.h"
#include "core/page/Frame.h"
#include "core/page/Page.h"
#include "core/page/Settings.h"
#include "core/platform/ContextMenuItem.h"
#include "core/platform/Pasteboard.h"
#include "weborigin/SecurityOrigin.h"
#include "wtf/OwnPtr.h"
#include "wtf/Vector.h"
#include "wtf/text/WTFString.h"

using namespace WebCore;

namespace WebKit {

class WebDevToolsFrontendImpl::InspectorFrontendResumeObserver : public ActiveDOMObject {
    WTF_MAKE_NONCOPYABLE(InspectorFrontendResumeObserver);
public:
    InspectorFrontendResumeObserver(WebDevToolsFrontendImpl* webDevToolsFrontendImpl, Document* document)
        : ActiveDOMObject(document)
        , m_webDevToolsFrontendImpl(webDevToolsFrontendImpl)
    {
        suspendIfNeeded();
    }

private:
    virtual bool canSuspend() const OVERRIDE
    {
        return true;
    }

    virtual void resume() OVERRIDE
    {
        m_webDevToolsFrontendImpl->resume();
    }

    WebDevToolsFrontendImpl* m_webDevToolsFrontendImpl;
};

WebDevToolsFrontend* WebDevToolsFrontend::create(
    WebView* view,
    WebDevToolsFrontendClient* client,
    const WebString& applicationLocale)
{
    return new WebDevToolsFrontendImpl(toWebViewImpl(view), client, applicationLocale);
}

WebDevToolsFrontendImpl::WebDevToolsFrontendImpl(
    WebViewImpl* webViewImpl,
    WebDevToolsFrontendClient* client,
    const String& applicationLocale)
    : m_webViewImpl(webViewImpl)
    , m_client(client)
    , m_applicationLocale(applicationLocale)
    , m_inspectorFrontendDispatchTimer(this, &WebDevToolsFrontendImpl::maybeDispatch)
{
    m_webViewImpl->page()->inspectorController().setInspectorFrontendClient(adoptPtr(new InspectorFrontendClientImpl(m_webViewImpl->page(), m_client, this)));

    // Put each DevTools frontend Page into a private group so that it's not
    // deferred along with the inspected page.
    m_webViewImpl->page()->setGroupType(Page::InspectorPageGroup);
}

WebDevToolsFrontendImpl::~WebDevToolsFrontendImpl()
{
}

void WebDevToolsFrontendImpl::dispatchOnInspectorFrontend(const WebString& message)
{
    m_messages.append(message);
    maybeDispatch(0);
}

void WebDevToolsFrontendImpl::resume()
{
    // We should call maybeDispatch asynchronously here because we are not allowed to update activeDOMObjects list in
    // resume (See ScriptExecutionContext::resumeActiveDOMObjects).
    if (!m_inspectorFrontendDispatchTimer.isActive())
        m_inspectorFrontendDispatchTimer.startOneShot(0);
}

void WebDevToolsFrontendImpl::maybeDispatch(WebCore::Timer<WebDevToolsFrontendImpl>*)
{
    while (!m_messages.isEmpty()) {
        Document* document = m_webViewImpl->page()->mainFrame()->document();
        if (document->activeDOMObjectsAreSuspended()) {
            m_inspectorFrontendResumeObserver = adoptPtr(new InspectorFrontendResumeObserver(this, document));
            return;
        }
        m_inspectorFrontendResumeObserver.clear();
        doDispatchOnInspectorFrontend(m_messages.takeFirst());
    }
}

void WebDevToolsFrontendImpl::doDispatchOnInspectorFrontend(const WebString& message)
{
    WebFrameImpl* frame = m_webViewImpl->mainFrameImpl();
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::HandleScope scope;
    v8::Handle<v8::Context> frameContext = frame->frame() ? frame->frame()->script()->currentWorldContext() : v8::Local<v8::Context>();
    v8::Context::Scope contextScope(frameContext);
    v8::Handle<v8::Value> inspectorFrontendApiValue = frameContext->Global()->Get(v8::String::New("InspectorFrontendAPI"));
    if (!inspectorFrontendApiValue->IsObject())
        return;
    v8::Handle<v8::Object> inspectorFrontendApi = v8::Handle<v8::Object>::Cast(inspectorFrontendApiValue);
    v8::Handle<v8::Value> dispatchFunction = inspectorFrontendApi->Get(v8::String::New("dispatchMessage"));
     // The frame might have navigated away from the front-end page (which is still weird).
    if (!dispatchFunction->IsFunction())
        return;
    v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(dispatchFunction);
    Vector< v8::Handle<v8::Value> > args;
    args.append(v8String(message, isolate));
    v8::TryCatch tryCatch;
    tryCatch.SetVerbose(true);
    ScriptController::callFunctionWithInstrumentation(frame->frame() ? frame->frame()->document() : 0, function, inspectorFrontendApi, args.size(), args.data());
}

} // namespace WebKit
<commit_msg>Fix remote debugging for Android Chrome M18<commit_after>/*
 * Copyright (C) 2010 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "WebDevToolsFrontendImpl.h"

#include "InspectorFrontendClientImpl.h"
#include "V8InspectorFrontendHost.h"
#include "V8MouseEvent.h"
#include "V8Node.h"
#include "WebDevToolsFrontendClient.h"
#include "WebFrameImpl.h"
#include "WebScriptSource.h"
#include "WebViewImpl.h"
#include "bindings/v8/ScriptController.h"
#include "bindings/v8/V8Binding.h"
#include "bindings/v8/V8DOMWrapper.h"
#include "bindings/v8/V8Utilities.h"
#include "core/dom/Document.h"
#include "core/dom/Event.h"
#include "core/dom/Node.h"
#include "core/inspector/InspectorController.h"
#include "core/inspector/InspectorFrontendHost.h"
#include "core/page/ContextMenuController.h"
#include "core/page/DOMWindow.h"
#include "core/page/Frame.h"
#include "core/page/Page.h"
#include "core/page/Settings.h"
#include "core/platform/ContextMenuItem.h"
#include "core/platform/Pasteboard.h"
#include "weborigin/SecurityOrigin.h"
#include "wtf/OwnPtr.h"
#include "wtf/Vector.h"
#include "wtf/text/WTFString.h"

using namespace WebCore;

namespace WebKit {

class WebDevToolsFrontendImpl::InspectorFrontendResumeObserver : public ActiveDOMObject {
    WTF_MAKE_NONCOPYABLE(InspectorFrontendResumeObserver);
public:
    InspectorFrontendResumeObserver(WebDevToolsFrontendImpl* webDevToolsFrontendImpl, Document* document)
        : ActiveDOMObject(document)
        , m_webDevToolsFrontendImpl(webDevToolsFrontendImpl)
    {
        suspendIfNeeded();
    }

private:
    virtual bool canSuspend() const OVERRIDE
    {
        return true;
    }

    virtual void resume() OVERRIDE
    {
        m_webDevToolsFrontendImpl->resume();
    }

    WebDevToolsFrontendImpl* m_webDevToolsFrontendImpl;
};

WebDevToolsFrontend* WebDevToolsFrontend::create(
    WebView* view,
    WebDevToolsFrontendClient* client,
    const WebString& applicationLocale)
{
    return new WebDevToolsFrontendImpl(toWebViewImpl(view), client, applicationLocale);
}

WebDevToolsFrontendImpl::WebDevToolsFrontendImpl(
    WebViewImpl* webViewImpl,
    WebDevToolsFrontendClient* client,
    const String& applicationLocale)
    : m_webViewImpl(webViewImpl)
    , m_client(client)
    , m_applicationLocale(applicationLocale)
    , m_inspectorFrontendDispatchTimer(this, &WebDevToolsFrontendImpl::maybeDispatch)
{
    m_webViewImpl->page()->inspectorController().setInspectorFrontendClient(adoptPtr(new InspectorFrontendClientImpl(m_webViewImpl->page(), m_client, this)));

    // Put each DevTools frontend Page into a private group so that it's not
    // deferred along with the inspected page.
    m_webViewImpl->page()->setGroupType(Page::InspectorPageGroup);
}

WebDevToolsFrontendImpl::~WebDevToolsFrontendImpl()
{
}

void WebDevToolsFrontendImpl::dispatchOnInspectorFrontend(const WebString& message)
{
    m_messages.append(message);
    maybeDispatch(0);
}

void WebDevToolsFrontendImpl::resume()
{
    // We should call maybeDispatch asynchronously here because we are not allowed to update activeDOMObjects list in
    // resume (See ScriptExecutionContext::resumeActiveDOMObjects).
    if (!m_inspectorFrontendDispatchTimer.isActive())
        m_inspectorFrontendDispatchTimer.startOneShot(0);
}

void WebDevToolsFrontendImpl::maybeDispatch(WebCore::Timer<WebDevToolsFrontendImpl>*)
{
    while (!m_messages.isEmpty()) {
        Document* document = m_webViewImpl->page()->mainFrame()->document();
        if (document->activeDOMObjectsAreSuspended()) {
            m_inspectorFrontendResumeObserver = adoptPtr(new InspectorFrontendResumeObserver(this, document));
            return;
        }
        m_inspectorFrontendResumeObserver.clear();
        doDispatchOnInspectorFrontend(m_messages.takeFirst());
    }
}

void WebDevToolsFrontendImpl::doDispatchOnInspectorFrontend(const WebString& message)
{
    WebFrameImpl* frame = m_webViewImpl->mainFrameImpl();
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::HandleScope scope;
    v8::Handle<v8::Context> frameContext = frame->frame() ? frame->frame()->script()->currentWorldContext() : v8::Local<v8::Context>();
    v8::Context::Scope contextScope(frameContext);
    v8::Handle<v8::Value> inspectorFrontendApiValue = frameContext->Global()->Get(v8::String::New("InspectorFrontendAPI"));
    if (!inspectorFrontendApiValue->IsObject())
        return;
    v8::Handle<v8::Object> dispatcherObject = v8::Handle<v8::Object>::Cast(inspectorFrontendApiValue);
    v8::Handle<v8::Value> dispatchFunction = dispatcherObject->Get(v8::String::New("dispatchMessage"));
    // The frame might have navigated away from the front-end page (which is still weird),
    // OR the older version of frontend might have a dispatch method in a different place.
    // FIXME(kaznacheev): Remove when Chrome for Android M18 is retired.
    if (!dispatchFunction->IsFunction()) {
        v8::Handle<v8::Value> inspectorBackendApiValue = frameContext->Global()->Get(v8::String::New("InspectorBackend"));
        if (!inspectorBackendApiValue->IsObject())
            return;
        dispatcherObject = v8::Handle<v8::Object>::Cast(inspectorBackendApiValue);
        dispatchFunction = dispatcherObject->Get(v8::String::New("dispatch"));
        if (!dispatchFunction->IsFunction())
            return;
    }
    v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(dispatchFunction);
    Vector< v8::Handle<v8::Value> > args;
    args.append(v8String(message, isolate));
    v8::TryCatch tryCatch;
    tryCatch.SetVerbose(true);
    ScriptController::callFunctionWithInstrumentation(frame->frame() ? frame->frame()->document() : 0, function, dispatcherObject, args.size(), args.data());
}

} // namespace WebKit
<|endoftext|>


<commit_before>#include "HomieSetting.hpp"

using namespace HomieInternals;

std::vector<IHomieSetting*> IHomieSetting::settings;

template <class T>
HomieSetting<T>::HomieSetting(const char* name, const char* description)
: _name(name)
, _description(description)
, _required(true)
, _provided(false)
, _value()
, _validator([](T candidate) { return true; }) {
  IHomieSetting::settings.push_back(this);
}

template <class T>
T HomieSetting<T>::get() const {
  return _value;
}

template <class T>
bool HomieSetting<T>::wasProvided() const {
  return _provided;
}

template <class T>
HomieSetting<T>& HomieSetting<T>::setDefaultValue(T defaultValue) {
  _value = defaultValue;
  _required = false;
  return *this;
}

template <class T>
HomieSetting<T>& HomieSetting<T>::setValidator(const std::function<bool(T candidate)>& validator) {
  _validator = validator;
  return *this;
}

template <class T>
bool HomieSetting<T>::validate(T candidate) const {
  return _validator(candidate);
}

template <class T>
void HomieSetting<T>::set(T value) {
  _value = value;
  _provided = true;
}

template <class T>
bool HomieSetting<T>::isRequired() const {
  return _required;
}

template <class T>
const char* HomieSetting<T>::getName() const {
  return _name;
}

template <class T>
const char* HomieSetting<T>::getDescription() const {
  return _description;
}

template <class T>
bool HomieSetting<T>::isBool() const { return false; }

template <class T>
bool HomieSetting<T>::isLong() const { return false; }

template <class T>
bool HomieSetting<T>::isDouble() const { return false; }

template <class T>
bool HomieSetting<T>::isConstChar() const { return false; }

template<>
bool HomieSetting<bool>::isBool() const { return true; }

template<>
bool HomieSetting<long>::isLong() const { return true; }

template<>
bool HomieSetting<double>::isDouble() const { return true; }

template<>
bool HomieSetting<const char*>::isConstChar() const { return true; }

template class HomieSetting<bool>;  // Needed because otherwise undefined reference to
template class HomieSetting<long>;
template class HomieSetting<double>;
template class HomieSetting<const char*>;
<commit_msg>:bug: IHomieSetting::settings first, HomieNode-settings second! (#335)<commit_after>#include "HomieSetting.hpp"

using namespace HomieInternals;

std::vector<IHomieSetting*> __attribute__((init_priority(101))) IHomieSetting::settings;

template <class T>
HomieSetting<T>::HomieSetting(const char* name, const char* description)
: _name(name)
, _description(description)
, _required(true)
, _provided(false)
, _value()
, _validator([](T candidate) { return true; }) {
  IHomieSetting::settings.push_back(this);
}

template <class T>
T HomieSetting<T>::get() const {
  return _value;
}

template <class T>
bool HomieSetting<T>::wasProvided() const {
  return _provided;
}

template <class T>
HomieSetting<T>& HomieSetting<T>::setDefaultValue(T defaultValue) {
  _value = defaultValue;
  _required = false;
  return *this;
}

template <class T>
HomieSetting<T>& HomieSetting<T>::setValidator(const std::function<bool(T candidate)>& validator) {
  _validator = validator;
  return *this;
}

template <class T>
bool HomieSetting<T>::validate(T candidate) const {
  return _validator(candidate);
}

template <class T>
void HomieSetting<T>::set(T value) {
  _value = value;
  _provided = true;
}

template <class T>
bool HomieSetting<T>::isRequired() const {
  return _required;
}

template <class T>
const char* HomieSetting<T>::getName() const {
  return _name;
}

template <class T>
const char* HomieSetting<T>::getDescription() const {
  return _description;
}

template <class T>
bool HomieSetting<T>::isBool() const { return false; }

template <class T>
bool HomieSetting<T>::isLong() const { return false; }

template <class T>
bool HomieSetting<T>::isDouble() const { return false; }

template <class T>
bool HomieSetting<T>::isConstChar() const { return false; }

template<>
bool HomieSetting<bool>::isBool() const { return true; }

template<>
bool HomieSetting<long>::isLong() const { return true; }

template<>
bool HomieSetting<double>::isDouble() const { return true; }

template<>
bool HomieSetting<const char*>::isConstChar() const { return true; }

template class HomieSetting<bool>;  // Needed because otherwise undefined reference to
template class HomieSetting<long>;
template class HomieSetting<double>;
template class HomieSetting<const char*>;
<|endoftext|>


<commit_before>#include "entity_template_system.h"
#include "core/array.h"
#include "core/crc32.h"
#include "core/iserializer.h"
#include "core/map.h"
#include "core/string.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "universe/entity.h"
#include "universe/universe.h"

namespace Lumix
{

	class EntityTemplateSystemImpl : public EntityTemplateSystem
	{
		public:
			EntityTemplateSystemImpl(WorldEditor& editor)
				: m_editor(editor)
			{
				m_universe = editor.getEngine().getUniverse();
				editor.universeCreated().bind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseCreated>(this);
				editor.universeDestroyed().bind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseDestroyed>(this);
			}

			~EntityTemplateSystemImpl()
			{
				m_editor.universeCreated().unbind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseCreated>(this);
				m_editor.universeDestroyed().unbind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseDestroyed>(this);
			}

			void onUniverseCreated()
			{
				m_instances.clear();
				m_template_names.clear();
				m_universe = m_editor.getEngine().getUniverse();
			}

			void onUniverseDestroyed()
			{
				m_instances.clear();
				m_template_names.clear();
				m_universe = NULL;
			}

			virtual void createTemplateFromEntity(const char* name, const Entity& entity) override
			{
				uint32_t name_hash = crc32(name);
				if (m_instances.find(name_hash) == m_instances.end())
				{
					m_template_names.push(string(name));
					m_instances[name_hash].push(entity);
					m_updated.invoke();
				}
				else
				{
					ASSERT(false);
				}
			}

			virtual uint32_t getTemplate(const Entity& entity) override
			{
				for (auto iter = m_instances.begin(), end = m_instances.end(); iter != end; ++iter)
				{
					Array<Entity>& entities = iter.second();
					for (int i = 0, c = entities.size(); i < c; ++i)
					{
						if (entities[i] == entity)
						{
							return iter.first();
						}
					}
				}
				return 0;
			}

			virtual const Array<Entity>& getInstances(uint32_t template_name_hash) override
			{
				return m_instances[template_name_hash];
			}

			virtual Entity createInstance(const char* name) override
			{
				uint32_t name_hash = crc32(name);
				Map<uint32_t, Array<Entity> >::iterator iter = m_instances.find(name_hash);
				if (iter == m_instances.end())
				{
					ASSERT(false);
					return Entity::INVALID;
				}
				else
				{
					Entity entity = m_editor.addEntity();
					m_instances[name_hash].push(entity);
					Entity template_entity = iter.second()[0];
					const Entity::ComponentList& template_cmps = template_entity.getComponents();
					for (int i = 0; i < template_cmps.size(); ++i)
					{
						m_editor.cloneComponent(template_cmps[i], entity);
					}
					return entity;
				}
			}

			virtual void serialize(ISerializer& serializer) override
			{
				serializer.serialize("templates_count", (int32_t)m_template_names.size());
				serializer.beginArray("template_names");
				for (int i = 0, c = m_template_names.size(); i < c;  ++i)
				{
					serializer.serializeArrayItem(m_template_names[i].c_str());
				}
				serializer.endArray();
				serializer.serialize("instance_count", (int32_t)m_instances.size());
				serializer.beginArray("instances");
				for (auto i = m_instances.begin(), end = m_instances.end(); i != end; ++i)
				{
					serializer.serializeArrayItem(i.first());
					serializer.serializeArrayItem((int32_t)i.second().size());
					for (int j = 0, c = i.second().size(); j < c; ++j)
					{
						serializer.serializeArrayItem(i.second()[j].index);
					}
				}
				serializer.endArray();

			}

			virtual void deserialize(ISerializer& serializer) override
			{
				int32_t count;
				serializer.deserialize("templates_count", count);
				serializer.deserializeArrayBegin("template_names");
				for (int i = 0; i < count; ++i)
				{
					const int MAX_NAME_LENGTH = 50;
					char name[MAX_NAME_LENGTH];
					serializer.deserializeArrayItem(name, MAX_NAME_LENGTH);
					m_template_names.push(string(name));
				}
				serializer.deserializeArrayEnd();
				serializer.deserialize("instance_count", count);
				serializer.deserializeArrayBegin("instances");
				for (int i = 0; i < count; ++i)
				{
					uint32_t hash;
					serializer.deserializeArrayItem(hash);
					int32_t instances_per_template;
					serializer.deserializeArrayItem(instances_per_template);
					m_instances.insert(hash, Array<Entity>());
					Array<Entity>& entities = m_instances[hash];
					for (int j = 0; j < instances_per_template; ++j)
					{
						int32_t entity_index;
						serializer.deserializeArrayItem(entity_index);
						entities.push(Entity(m_universe, entity_index));
					}
				}
				serializer.deserializeArrayEnd();
				m_updated.invoke();
			}

			virtual Array<string>& getTemplateNames() override
			{
				return m_template_names;
			}

			virtual DelegateList<void()>& updated() override
			{
				return m_updated;
			}

		private:
			Map<uint32_t, Array<Entity> > m_instances;
			Array<string> m_template_names;
			Universe* m_universe;
			WorldEditor& m_editor;
			DelegateList<void()> m_updated;

	}; // class EntityTemplateSystemImpl

	EntityTemplateSystem* EntityTemplateSystem::create(WorldEditor& editor)
	{
		return LUMIX_NEW(EntityTemplateSystemImpl)(editor);
	}

	void EntityTemplateSystem::destroy(EntityTemplateSystem* system)
	{
		LUMIX_DELETE(system);
	}

} // namespace Lumix<commit_msg>entity template serialization is reentrant<commit_after>#include "entity_template_system.h"
#include "core/array.h"
#include "core/crc32.h"
#include "core/iserializer.h"
#include "core/map.h"
#include "core/string.h"
#include "editor/world_editor.h"
#include "engine/engine.h"
#include "universe/entity.h"
#include "universe/universe.h"

namespace Lumix
{

	class EntityTemplateSystemImpl : public EntityTemplateSystem
	{
		public:
			EntityTemplateSystemImpl(WorldEditor& editor)
				: m_editor(editor)
			{
				m_universe = editor.getEngine().getUniverse();
				editor.universeCreated().bind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseCreated>(this);
				editor.universeDestroyed().bind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseDestroyed>(this);
			}

			~EntityTemplateSystemImpl()
			{
				m_editor.universeCreated().unbind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseCreated>(this);
				m_editor.universeDestroyed().unbind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseDestroyed>(this);
			}

			void onUniverseCreated()
			{
				m_instances.clear();
				m_template_names.clear();
				m_universe = m_editor.getEngine().getUniverse();
			}

			void onUniverseDestroyed()
			{
				m_instances.clear();
				m_template_names.clear();
				m_universe = NULL;
			}

			virtual void createTemplateFromEntity(const char* name, const Entity& entity) override
			{
				uint32_t name_hash = crc32(name);
				if (m_instances.find(name_hash) == m_instances.end())
				{
					m_template_names.push(string(name));
					m_instances[name_hash].push(entity);
					m_updated.invoke();
				}
				else
				{
					ASSERT(false);
				}
			}

			virtual uint32_t getTemplate(const Entity& entity) override
			{
				for (auto iter = m_instances.begin(), end = m_instances.end(); iter != end; ++iter)
				{
					Array<Entity>& entities = iter.second();
					for (int i = 0, c = entities.size(); i < c; ++i)
					{
						if (entities[i] == entity)
						{
							return iter.first();
						}
					}
				}
				return 0;
			}

			virtual const Array<Entity>& getInstances(uint32_t template_name_hash) override
			{
				return m_instances[template_name_hash];
			}

			virtual Entity createInstance(const char* name) override
			{
				uint32_t name_hash = crc32(name);
				Map<uint32_t, Array<Entity> >::iterator iter = m_instances.find(name_hash);
				if (iter == m_instances.end())
				{
					ASSERT(false);
					return Entity::INVALID;
				}
				else
				{
					Entity entity = m_editor.addEntity();
					m_instances[name_hash].push(entity);
					Entity template_entity = iter.second()[0];
					const Entity::ComponentList& template_cmps = template_entity.getComponents();
					for (int i = 0; i < template_cmps.size(); ++i)
					{
						m_editor.cloneComponent(template_cmps[i], entity);
					}
					return entity;
				}
			}

			virtual void serialize(ISerializer& serializer) override
			{
				serializer.serialize("templates_count", (int32_t)m_template_names.size());
				serializer.beginArray("template_names");
				for (int i = 0, c = m_template_names.size(); i < c;  ++i)
				{
					serializer.serializeArrayItem(m_template_names[i].c_str());
				}
				serializer.endArray();
				serializer.serialize("instance_count", (int32_t)m_instances.size());
				serializer.beginArray("instances");
				for (auto i = m_instances.begin(), end = m_instances.end(); i != end; ++i)
				{
					serializer.serializeArrayItem(i.first());
					serializer.serializeArrayItem((int32_t)i.second().size());
					for (int j = 0, c = i.second().size(); j < c; ++j)
					{
						serializer.serializeArrayItem(i.second()[j].index);
					}
				}
				serializer.endArray();

			}

			virtual void deserialize(ISerializer& serializer) override
			{
				m_template_names.clear();
				m_instances.clear();
				int32_t count;
				serializer.deserialize("templates_count", count);
				serializer.deserializeArrayBegin("template_names");
				for (int i = 0; i < count; ++i)
				{
					const int MAX_NAME_LENGTH = 50;
					char name[MAX_NAME_LENGTH];
					serializer.deserializeArrayItem(name, MAX_NAME_LENGTH);
					m_template_names.push(string(name));
				}
				serializer.deserializeArrayEnd();
				serializer.deserialize("instance_count", count);
				serializer.deserializeArrayBegin("instances");
				for (int i = 0; i < count; ++i)
				{
					uint32_t hash;
					serializer.deserializeArrayItem(hash);
					int32_t instances_per_template;
					serializer.deserializeArrayItem(instances_per_template);
					m_instances.insert(hash, Array<Entity>());
					Array<Entity>& entities = m_instances[hash];
					for (int j = 0; j < instances_per_template; ++j)
					{
						int32_t entity_index;
						serializer.deserializeArrayItem(entity_index);
						entities.push(Entity(m_universe, entity_index));
					}
				}
				serializer.deserializeArrayEnd();
				m_updated.invoke();
			}

			virtual Array<string>& getTemplateNames() override
			{
				return m_template_names;
			}

			virtual DelegateList<void()>& updated() override
			{
				return m_updated;
			}

		private:
			Map<uint32_t, Array<Entity> > m_instances;
			Array<string> m_template_names;
			Universe* m_universe;
			WorldEditor& m_editor;
			DelegateList<void()> m_updated;

	}; // class EntityTemplateSystemImpl

	EntityTemplateSystem* EntityTemplateSystem::create(WorldEditor& editor)
	{
		return LUMIX_NEW(EntityTemplateSystemImpl)(editor);
	}

	void EntityTemplateSystem::destroy(EntityTemplateSystem* system)
	{
		LUMIX_DELETE(system);
	}

} // namespace Lumix<|endoftext|>