<commit_before>#include "library.h"

#include <stdint.h>

#ifdef _WIN32
#include <windows.h>
#elif __linux__
#include <dlfcn.h>
#else
#warning file::library is incompatible with target OS!
#endif

namespace z
{
	namespace file
	{
		/**
		 * \brief Default empty constructor.
		 */
		library::library()
		{
			lib_ptr = 0;
		}

		/**
		 * \brief Destructor frees any loaded library.
		 */
		library::~library()
		{
#			ifdef _WIN32
			if (lib_ptr) FreeLibrary((HMODULE)lib_ptr);
#			elif __linux__
			if (lib_ptr) dlclose(lib_ptr);
#			endif
		}

		/**
		 * \brief Load a dynamic library with the given file name.
		 *
		 * \param file_name the path of the library to load.
		 *
		 * \return \b True if the library loaded successfully.
		 * \b False otherwise.
		 */
		bool library::load(const zpath& file_name)
		{
#			ifdef _WIN32
			if (lib_ptr) FreeLibrary((HMODULE)lib_ptr);
			lib_ptr = (void*)LoadLibrary((char*)file_name.cstring());
			return (bool)lib_ptr;
#			elif __linux__
			if (lib_ptr) dlclose(lib_ptr);
			lib_ptr = dlopen((char*)file_name.cstring(), RTLD_NOW);
			return (bool)lib_ptr;
#			else
			return false;
#			endif
		}

		/**
		 * \brief Unload the dynamic library.
		 *
		 * \return \b False if unable to unload previously
		 * loaded library. \b True otherwise.
		 */
		bool library::unload()
		{
#			ifdef _WIN32
			if (lib_ptr)
				return (bool)FreeLibrary((HMODULE)lib_ptr);
			else
				return true;
#			elif __linux__
			if (lib_ptr)
				return (bool)dlclose(lib_ptr);
			else
				return true;
#			else
			return true;
#			endif
		}

		/**
		 * \brief Get whether the library has been loaded.
		 *
		 * \return \b True if the library has been loaded.
		 * \b False otherwise.
		 *
		 * \see bad()
		 */
		bool library::good()
		{
			return (bool)lib_ptr;
		}

		/**
		 * \brief Get whether the library has not been loaded.
		 *
		 * \return \b False if the library has been loaded.
		 * \b True otherwise.
		 *
		 * \see good()
		 */
		bool library::bad()
		{
			return !lib_ptr;
		}

		void* library::symbol(const zpath& symbol_name)
		{
			void* symbol_pointer = NULL;
#			ifdef _WIN32
			if (lib_ptr)
				symbol_pointer = GetProcAddress((HMODULE)lib_ptr, (char*)symbol_name.cstring());
#			elif __linux__
			if(lib_ptr)
				symbol_pointer = dlsym(lib_ptr, (const char*)symbol_name.cstring());
#			endif
			return symbol_pointer;
		}

		func library::function(const zpath& symbol_name)
		{
			void* symbol_pointer = NULL;
			func func_pointer = NULL;
#			ifdef _WIN32
			if (lib_ptr)
				symbol_pointer = GetProcAddress((HMODULE)lib_ptr, (const char*)symbol_name.cstring());
#			elif __linux__
			if(lib_ptr)
				symbol_pointer = dlsym(lib_ptr, (const char*)symbol_name.cstring());
#			endif
			if (symbol_pointer)
			{
				if (sizeof(void*) == 8) //64 bit pointers
					func_pointer = reinterpret_cast<func>(reinterpret_cast<long long>(symbol_pointer));
				else
					func_pointer = reinterpret_cast<func>(reinterpret_cast<long>(symbol_pointer));
			}
			return func_pointer;
		}

	}
}
<commit_msg>removed documentation from library.cpp<commit_after>#include "library.h"

#include <stdint.h>

#ifdef _WIN32
#include <windows.h>
#elif __linux__
#include <dlfcn.h>
#else
#warning file::library is incompatible with target OS!
#endif

namespace z
{
	namespace file
	{
		library::library()
		{
			lib_ptr = 0;
		}

		library::~library()
		{
#			ifdef _WIN32
			if (lib_ptr) FreeLibrary((HMODULE)lib_ptr);
#			elif __linux__
			if (lib_ptr) dlclose(lib_ptr);
#			endif
		}

		bool library::load(const zpath& file_name)
		{
#			ifdef _WIN32
			if (lib_ptr) FreeLibrary((HMODULE)lib_ptr);
			lib_ptr = (void*)LoadLibrary((char*)file_name.cstring());
			return (bool)lib_ptr;
#			elif __linux__
			if (lib_ptr) dlclose(lib_ptr);
			lib_ptr = dlopen((char*)file_name.cstring(), RTLD_NOW);
			return (bool)lib_ptr;
#			else
			return false;
#			endif
		}

		bool library::unload()
		{
#			ifdef _WIN32
			if (lib_ptr)
				return (bool)FreeLibrary((HMODULE)lib_ptr);
			else
				return true;
#			elif __linux__
			if (lib_ptr)
				return (bool)dlclose(lib_ptr);
			else
				return true;
#			else
			return true;
#			endif
		}

		bool library::good()
		{
			return (bool)lib_ptr;
		}

		bool library::bad()
		{
			return !lib_ptr;
		}

		void* library::symbol(const zpath& symbol_name)
		{
			void* symbol_pointer = NULL;
#			ifdef _WIN32
			if (lib_ptr)
				symbol_pointer = GetProcAddress((HMODULE)lib_ptr, (char*)symbol_name.cstring());
#			elif __linux__
			if(lib_ptr)
				symbol_pointer = dlsym(lib_ptr, (const char*)symbol_name.cstring());
#			endif
			return symbol_pointer;
		}

		func library::function(const zpath& symbol_name)
		{
			void* symbol_pointer = NULL;
			func func_pointer = NULL;
#			ifdef _WIN32
			if (lib_ptr)
				symbol_pointer = GetProcAddress((HMODULE)lib_ptr, (const char*)symbol_name.cstring());
#			elif __linux__
			if(lib_ptr)
				symbol_pointer = dlsym(lib_ptr, (const char*)symbol_name.cstring());
#			endif
			if (symbol_pointer)
			{
				if (sizeof(void*) == 8) //64 bit pointers
					func_pointer = reinterpret_cast<func>(reinterpret_cast<long long>(symbol_pointer));
				else
					func_pointer = reinterpret_cast<func>(reinterpret_cast<long>(symbol_pointer));
			}
			return func_pointer;
		}

	}
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.4  2000/03/02 19:54:29  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.3  2000/02/06 07:47:53  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.2  1999/12/15 19:49:37  roddey
 * Added second getValue() method which takes a short name for the attribute
 * to get the value for. Just a convenience method.
 *
 * Revision 1.1.1.1  1999/11/09 01:08:19  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:44:44  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <util/Janitor.hpp>
#include <internal/VecAttrListImpl.hpp>

// ---------------------------------------------------------------------------
//  Constructors and Destructor
// ---------------------------------------------------------------------------
VecAttrListImpl::VecAttrListImpl() :

    fAdopt(false)
    , fCount(0)
    , fVector(0)
{
}

VecAttrListImpl::~VecAttrListImpl()
{
    //
    //  Note that some compilers can't deal with the fact that the pointer
    //  is to a const object, so we have to cast off the const'ness here!
    //
    if (fAdopt)
        delete (RefVectorOf<XMLAttr>*)fVector;
}

// ---------------------------------------------------------------------------
//  Implementation of the attribute list interface
// ---------------------------------------------------------------------------
unsigned int VecAttrListImpl::getLength() const
{
    return fCount;
}

const XMLCh* VecAttrListImpl::getName(const unsigned int index) const
{
    if (index >= fCount)
        ThrowXML(ArrayIndexOutOfBoundsException, XMLExcepts::AttrList_BadIndex);
    return fVector->elementAt(index)->getName();
}

const XMLCh* VecAttrListImpl::getType(const unsigned int index) const
{
    if (index >= fCount)
        ThrowXML(ArrayIndexOutOfBoundsException, XMLExcepts::AttrList_BadIndex);
    return XMLAttDef::getAttTypeString(fVector->elementAt(index)->getType());
}

const XMLCh* VecAttrListImpl::getValue(const unsigned int index) const
{
    if (index >= fCount)
        ThrowXML(ArrayIndexOutOfBoundsException, XMLExcepts::AttrList_BadIndex);
    return fVector->elementAt(index)->getValue();
}

const XMLCh* VecAttrListImpl::getType(const XMLCh* const name) const
{
    //
    //  Search the vector for the attribute with the given name and return
    //  its type.
    //
    for (unsigned int index = 0; index < fCount; index++)
    {
        const XMLAttr* curElem = fVector->elementAt(index);

        if (!XMLString::compareString(curElem->getName(), name))
            return XMLAttDef::getAttTypeString(curElem->getType());
    }
    return 0;
}

const XMLCh* VecAttrListImpl::getValue(const XMLCh* const name) const
{
    //
    //  Search the vector for the attribute with the given name and return
    //  its type.
    //
    for (unsigned int index = 0; index < fCount; index++)
    {
        const XMLAttr* curElem = fVector->elementAt(index);

        if (!XMLString::compareString(curElem->getName(), name))
            return curElem->getValue();
    }
    return 0;
}

const XMLCh* VecAttrListImpl::getValue(const char* const name) const
{
    // Temporarily transcode the name for lookup
    XMLCh* wideName = XMLString::transcode(name);
    ArrayJanitor<XMLCh> janName(wideName);

    //
    //  Search the vector for the attribute with the given name and return
    //  its type.
    //
    for (unsigned int index = 0; index < fCount; index++)
    {
        const XMLAttr* curElem = fVector->elementAt(index);

        if (!XMLString::compareString(curElem->getName(), wideName))
            return curElem->getValue();
    }
    return 0;
}

// ---------------------------------------------------------------------------
//  Setter methods
// ---------------------------------------------------------------------------
void VecAttrListImpl::setVector(const   RefVectorOf<XMLAttr>* const srcVec
                                , const unsigned int                count
                                , const bool                        adopt)
{
    //
    //  Delete the previous vector (if any) if we are adopting. Note that some
    //  compilers can't deal with the fact that the pointer is to a const
    //  object, so we have to cast off the const'ness here!
    //
    if (fAdopt)
        delete (RefVectorOf<XMLAttr>*)fVector;

    fAdopt = fAdopt;
    fCount = count;
    fVector = srcVec;
}
<commit_msg>Fixed #54. Changed self-assignment to now use the parameter value. Reported by Helmut Eiken <H.Eiken@cli.de><commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.5  2000/03/13 20:19:11  rahulj
 * Fixed #54. Changed self-assignment to now use the parameter value.
 * Reported by Helmut Eiken <H.Eiken@cli.de>
 *
 * Revision 1.4  2000/03/02 19:54:29  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.3  2000/02/06 07:47:53  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.2  1999/12/15 19:49:37  roddey
 * Added second getValue() method which takes a short name for the attribute
 * to get the value for. Just a convenience method.
 *
 * Revision 1.1.1.1  1999/11/09 01:08:19  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:44:44  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <util/Janitor.hpp>
#include <internal/VecAttrListImpl.hpp>

// ---------------------------------------------------------------------------
//  Constructors and Destructor
// ---------------------------------------------------------------------------
VecAttrListImpl::VecAttrListImpl() :

    fAdopt(false)
    , fCount(0)
    , fVector(0)
{
}

VecAttrListImpl::~VecAttrListImpl()
{
    //
    //  Note that some compilers can't deal with the fact that the pointer
    //  is to a const object, so we have to cast off the const'ness here!
    //
    if (fAdopt)
        delete (RefVectorOf<XMLAttr>*)fVector;
}

// ---------------------------------------------------------------------------
//  Implementation of the attribute list interface
// ---------------------------------------------------------------------------
unsigned int VecAttrListImpl::getLength() const
{
    return fCount;
}

const XMLCh* VecAttrListImpl::getName(const unsigned int index) const
{
    if (index >= fCount)
        ThrowXML(ArrayIndexOutOfBoundsException, XMLExcepts::AttrList_BadIndex);
    return fVector->elementAt(index)->getName();
}

const XMLCh* VecAttrListImpl::getType(const unsigned int index) const
{
    if (index >= fCount)
        ThrowXML(ArrayIndexOutOfBoundsException, XMLExcepts::AttrList_BadIndex);
    return XMLAttDef::getAttTypeString(fVector->elementAt(index)->getType());
}

const XMLCh* VecAttrListImpl::getValue(const unsigned int index) const
{
    if (index >= fCount)
        ThrowXML(ArrayIndexOutOfBoundsException, XMLExcepts::AttrList_BadIndex);
    return fVector->elementAt(index)->getValue();
}

const XMLCh* VecAttrListImpl::getType(const XMLCh* const name) const
{
    //
    //  Search the vector for the attribute with the given name and return
    //  its type.
    //
    for (unsigned int index = 0; index < fCount; index++)
    {
        const XMLAttr* curElem = fVector->elementAt(index);

        if (!XMLString::compareString(curElem->getName(), name))
            return XMLAttDef::getAttTypeString(curElem->getType());
    }
    return 0;
}

const XMLCh* VecAttrListImpl::getValue(const XMLCh* const name) const
{
    //
    //  Search the vector for the attribute with the given name and return
    //  its type.
    //
    for (unsigned int index = 0; index < fCount; index++)
    {
        const XMLAttr* curElem = fVector->elementAt(index);

        if (!XMLString::compareString(curElem->getName(), name))
            return curElem->getValue();
    }
    return 0;
}

const XMLCh* VecAttrListImpl::getValue(const char* const name) const
{
    // Temporarily transcode the name for lookup
    XMLCh* wideName = XMLString::transcode(name);
    ArrayJanitor<XMLCh> janName(wideName);

    //
    //  Search the vector for the attribute with the given name and return
    //  its type.
    //
    for (unsigned int index = 0; index < fCount; index++)
    {
        const XMLAttr* curElem = fVector->elementAt(index);

        if (!XMLString::compareString(curElem->getName(), wideName))
            return curElem->getValue();
    }
    return 0;
}

// ---------------------------------------------------------------------------
//  Setter methods
// ---------------------------------------------------------------------------
void VecAttrListImpl::setVector(const   RefVectorOf<XMLAttr>* const srcVec
                                , const unsigned int                count
                                , const bool                        adopt)
{
    //
    //  Delete the previous vector (if any) if we are adopting. Note that some
    //  compilers can't deal with the fact that the pointer is to a const
    //  object, so we have to cast off the const'ness here!
    //
    if (fAdopt)
        delete (RefVectorOf<XMLAttr>*)fVector;

    fAdopt = adopt;
    fCount = count;
    fVector = srcVec;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2022 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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 "YamlSubstIstream.hxx"
#include "SubstIstream.hxx"
#include "UnusedPtr.hxx"
#include "pool/pool.hxx"
#include "util/IterableSplitString.hxx"
#include "util/RuntimeError.hxx"
#include "util/StringView.hxx"

#include <yaml-cpp/node/parse.h>
#include <yaml-cpp/node/node.h>
#include <yaml-cpp/node/iterator.h>
#include <yaml-cpp/node/impl.h>
#include <yaml-cpp/node/convert.h>
#include <yaml-cpp/node/detail/impl.h>

#include <assert.h>

static YAML::Node
ResolveYamlPathSegment(const YAML::Node &parent, StringView segment)
{
	if (parent.IsMap()) {
		auto result = parent[std::string(segment.data, segment.size).c_str()];
		if (!result)
			throw FormatRuntimeError("YAML path segment '%.*s' does not exist",
						 int(segment.size), segment.data);

		return result;
	} else
		throw FormatRuntimeError("Failed to resolve YAML path segment '%.*s'",
					 int(segment.size), segment.data);
}

static YAML::Node
ResolveYamlPath(YAML::Node node, StringView path)
{
	for (StringView s : IterableSplitString(path, '.')) {
		if (s.empty())
			continue;

		node = ResolveYamlPathSegment(node, s);
	}

	return node;
}

static YAML::Node
ResolveYamlMap(YAML::Node node, StringView path)
{
	node = ResolveYamlPath(node, path);
	if (!node.IsMap())
		throw path.empty()
			? std::runtime_error("Not a YAML map")
			: FormatRuntimeError("Path '%.*s' is not a YAML map",
					     int(path.size), path.data);

	return node;
}

static auto
MakePrefix(bool alt_syntax, const char *_prefix)
{
	std::string prefix = alt_syntax ? "{[" : "{%";
	if (_prefix != nullptr)
		prefix += _prefix;
	return prefix;
}

static void
LoadYamlMap(struct pool &pool, SubstTree &tree,
	    const std::string &prefix,
	    const std::string &suffix,
	    const YAML::Node &node) noexcept
{
	assert(node.IsMap());

	for (const auto &i : node) {
		if (!i.first.IsScalar())
			continue;

		if (i.second.IsScalar()) {
			const auto name = prefix + i.first.as<std::string>() + suffix;
			const auto value = i.second.as<std::string>();
			tree.Add(pool, p_strndup(&pool, name.data(), name.length()),
				 {p_strndup(&pool, value.data(), value.length()), value.length()});
		} else if (i.second.IsMap()) {
			LoadYamlMap(pool, tree, prefix + i.first.as<std::string>() + ".",
				    suffix,
				    i.second);
		}
	}
}

static SubstTree
LoadYamlMap(struct pool &pool, bool alt_syntax, const char *_prefix,
	    const YAML::Node &node) noexcept
{
	assert(node.IsMap());

	const auto prefix = MakePrefix(alt_syntax, _prefix);
	const std::string suffix(alt_syntax ? "]}" : "%}");

	SubstTree tree;
	LoadYamlMap(pool, tree, prefix, suffix, node);
	return tree;
}

UnusedIstreamPtr
NewYamlSubstIstream(struct pool &pool, UnusedIstreamPtr input,
		    bool alt_syntax,
		    const char *prefix,
		    const YAML::Node &yaml_node, const char *yaml_map_path)
{
	return istream_subst_new(&pool, std::move(input),
				 LoadYamlMap(pool, alt_syntax, prefix,
					     ResolveYamlMap(yaml_node,
							    yaml_map_path)));
}

static SubstTree
LoadYamlFile(struct pool &pool, bool alt_syntax,
	     const char *prefix,
	     const char *file_path, const char *map_path)
	try {
		return LoadYamlMap(pool, alt_syntax, prefix,
				   ResolveYamlMap(YAML::LoadFile(file_path), map_path));
	} catch (...) {
		std::throw_with_nested(FormatRuntimeError("Failed to load YAML file '%s'",
							  file_path));
	}

UnusedIstreamPtr
NewYamlSubstIstream(struct pool &pool, UnusedIstreamPtr input,
		    bool alt_syntax,
		    const char *prefix,
		    const char *yaml_file, const char *yaml_map_path)
{
	return istream_subst_new(&pool, std::move(input),
				 LoadYamlFile(pool, alt_syntax, prefix,
					      yaml_file, yaml_map_path));
}
<commit_msg>istream/YamlSubst: use std::string_view<commit_after>/*
 * Copyright 2007-2022 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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 "YamlSubstIstream.hxx"
#include "SubstIstream.hxx"
#include "UnusedPtr.hxx"
#include "pool/pool.hxx"
#include "util/IterableSplitString.hxx"
#include "util/RuntimeError.hxx"

#include <yaml-cpp/node/parse.h>
#include <yaml-cpp/node/node.h>
#include <yaml-cpp/node/iterator.h>
#include <yaml-cpp/node/impl.h>
#include <yaml-cpp/node/convert.h>
#include <yaml-cpp/node/detail/impl.h>

#include <assert.h>

static YAML::Node
ResolveYamlPathSegment(const YAML::Node &parent, std::string_view segment)
{
	if (parent.IsMap()) {
		auto result = parent[std::string{segment}.c_str()];
		if (!result)
			throw FormatRuntimeError("YAML path segment '%.*s' does not exist",
						 int(segment.size()), segment.data());

		return result;
	} else
		throw FormatRuntimeError("Failed to resolve YAML path segment '%.*s'",
					 int(segment.size()), segment.data());
}

static YAML::Node
ResolveYamlPath(YAML::Node node, std::string_view path)
{
	for (const auto s : IterableSplitString(path, '.')) {
		if (s.empty())
			continue;

		node = ResolveYamlPathSegment(node, s);
	}

	return node;
}

static YAML::Node
ResolveYamlMap(YAML::Node node, std::string_view path)
{
	node = ResolveYamlPath(node, path);
	if (!node.IsMap())
		throw path.empty()
			? std::runtime_error("Not a YAML map")
			: FormatRuntimeError("Path '%.*s' is not a YAML map",
					     int(path.size()), path.data());

	return node;
}

static auto
MakePrefix(bool alt_syntax, const char *_prefix)
{
	std::string prefix = alt_syntax ? "{[" : "{%";
	if (_prefix != nullptr)
		prefix += _prefix;
	return prefix;
}

static void
LoadYamlMap(struct pool &pool, SubstTree &tree,
	    const std::string &prefix,
	    const std::string &suffix,
	    const YAML::Node &node) noexcept
{
	assert(node.IsMap());

	for (const auto &i : node) {
		if (!i.first.IsScalar())
			continue;

		if (i.second.IsScalar()) {
			const auto name = prefix + i.first.as<std::string>() + suffix;
			const auto value = i.second.as<std::string>();
			tree.Add(pool, p_strndup(&pool, name.data(), name.length()),
				 {p_strndup(&pool, value.data(), value.length()), value.length()});
		} else if (i.second.IsMap()) {
			LoadYamlMap(pool, tree, prefix + i.first.as<std::string>() + ".",
				    suffix,
				    i.second);
		}
	}
}

static SubstTree
LoadYamlMap(struct pool &pool, bool alt_syntax, const char *_prefix,
	    const YAML::Node &node) noexcept
{
	assert(node.IsMap());

	const auto prefix = MakePrefix(alt_syntax, _prefix);
	const std::string suffix(alt_syntax ? "]}" : "%}");

	SubstTree tree;
	LoadYamlMap(pool, tree, prefix, suffix, node);
	return tree;
}

UnusedIstreamPtr
NewYamlSubstIstream(struct pool &pool, UnusedIstreamPtr input,
		    bool alt_syntax,
		    const char *prefix,
		    const YAML::Node &yaml_node, const char *yaml_map_path)
{
	return istream_subst_new(&pool, std::move(input),
				 LoadYamlMap(pool, alt_syntax, prefix,
					     ResolveYamlMap(yaml_node,
							    yaml_map_path)));
}

static SubstTree
LoadYamlFile(struct pool &pool, bool alt_syntax,
	     const char *prefix,
	     const char *file_path, const char *map_path)
	try {
		return LoadYamlMap(pool, alt_syntax, prefix,
				   ResolveYamlMap(YAML::LoadFile(file_path), map_path));
	} catch (...) {
		std::throw_with_nested(FormatRuntimeError("Failed to load YAML file '%s'",
							  file_path));
	}

UnusedIstreamPtr
NewYamlSubstIstream(struct pool &pool, UnusedIstreamPtr input,
		    bool alt_syntax,
		    const char *prefix,
		    const char *yaml_file, const char *yaml_map_path)
{
	return istream_subst_new(&pool, std::move(input),
				 LoadYamlFile(pool, alt_syntax, prefix,
					      yaml_file, yaml_map_path));
}
<|endoftext|>


<commit_before><commit_msg>fix compilation errors<commit_after><|endoftext|>


<commit_before><commit_msg>Bump version<commit_after><|endoftext|>


<commit_before><commit_msg>exception message improved<commit_after><|endoftext|>


<commit_before>
//
// A WebAssembly shell, loads a .wast file (WebAssembly in S-Expression format) and executes it.
//

#include <setjmp.h>

#include "wasm-s-parser.h"
#include "wasm-interpreter.h"

using namespace cashew;
using namespace wasm;

IString ASSERT_RETURN("assert_return"),
        ASSERT_TRAP("assert_trap"),
        PRINT("print"),
        INVOKE("invoke");

//
// Implementation of the shell interpreter execution environment
//

struct ShellExternalInterface : ModuleInstance::ExternalInterface {
  char *memory;
  size_t memorySize;

  ShellExternalInterface() : memory(nullptr) {}

  void init(Module& wasm) override {
    memory = new char[wasm.memory.initial];
    memorySize = wasm.memory.initial;
    // apply memory segments
    for (auto segment : wasm.memory.segments) {
      memcpy(memory + segment.offset, segment.data, segment.size);
    }
  }

  Literal callImport(Import *import, ModuleInstance::LiteralList& arguments) override {
    if (import->name == PRINT) {
      for (auto argument : arguments) {
        std::cout << argument << ' ';
      }
      std::cout << '\n';
      return Literal();
    }
    std::cout << "callImport " << import->name.str << "\n";
    abort();
  }

  Literal load(Load* load, size_t addr) override {
    // ignore align - assume we are on x86 etc. which does that
    switch (load->type) {
      case i32: {
        switch (load->bytes) {
          case 1: return load->signed_ ? (int32_t)((int8_t*)memory)[addr]  : (int32_t)((uint8_t*)memory)[addr];
          case 2: return load->signed_ ? (int32_t)((int16_t*)memory)[addr] : (int32_t)((uint16_t*)memory)[addr];
          case 4: return load->signed_ ? (int32_t)((int32_t*)memory)[addr] : (int32_t)((uint32_t*)memory)[addr];
          default: abort();
        }
        break;
      }
      case i64: {
        switch (load->bytes) {
          case 1: return load->signed_ ? (int64_t)((int8_t*)memory)[addr]  : (int64_t)((uint8_t*)memory)[addr];
          case 2: return load->signed_ ? (int64_t)((int16_t*)memory)[addr] : (int64_t)((uint16_t*)memory)[addr];
          case 4: return load->signed_ ? (int64_t)((int32_t*)memory)[addr] : (int64_t)((uint32_t*)memory)[addr];
          case 8: return load->signed_ ? (int64_t)((int64_t*)memory)[addr] : (int64_t)((uint64_t*)memory)[addr];
          default: abort();
        }
        break;
      }
      case f32: return ((float*)memory)[addr];
      case f64: return ((double*)memory)[addr];
      default: abort();
    }
  }

  void store(Store* store, size_t addr, Literal value) override {
    // ignore align - assume we are on x86 etc. which does that
    switch (store->type) {
      case i32: {
        switch (store->bytes) {
          case 1: ((int8_t*)memory)[addr] = value.geti32(); break;
          case 2: ((int16_t*)memory)[addr] = value.geti32(); break;
          case 4: ((int32_t*)memory)[addr] = value.geti32(); break;
          case 8: ((int64_t*)memory)[addr] = value.geti64(); break;
          default: abort();
        }
        break;
      }
      case f32: ((float*)memory)[addr] = value.getf32(); break;
      case f64: ((double*)memory)[addr] = value.getf64(); break;
      default: abort();
    }
  }

  jmp_buf trapState;

  void trap() override {
    longjmp(trapState, 1);
  }
};

int main(int argc, char **argv) {
  debug = getenv("WASM_SHELL_DEBUG") ? getenv("WASM_SHELL_DEBUG")[0] - '0' : 0;

  char *infile = argv[1];
  bool print_wasm = argc >= 3; // second arg means print it out

  if (debug) std::cerr << "loading '" << infile << "'...\n";
  FILE *f = fopen(argv[1], "r");
  assert(f);
  fseek(f, 0, SEEK_END);
  int size = ftell(f);
  char *input = new char[size+1];
  rewind(f);
  int num = fread(input, 1, size, f);
  // On Windows, ftell() gives the byte position (\r\n counts as two bytes), but when
  // reading, fread() returns the number of characters read (\r\n is read as one char \n, and counted as one),
  // so return value of fread can be less than size reported by ftell, and that is normal.
  assert((num > 0 || size == 0) && num <= size);
  fclose(f);
  input[num] = 0;

  if (debug) std::cerr << "parsing text to s-expressions...\n";
  SExpressionParser parser(input);
  Element& root = *parser.root;
  if (debug) std::cout << root << '\n';

  // A .wast may have multiple modules, with some asserts after them
  size_t i = 0;
  while (i < root.size()) {
    if (debug) std::cerr << "parsing s-expressions to wasm...\n";
    Module wasm;
    SExpressionWasmBuilder builder(wasm, *root[i]);
    i++;

    auto interface = new ShellExternalInterface();
    auto instance = new ModuleInstance(wasm, interface);

    if (print_wasm) {
      if (debug) std::cerr << "printing...\n";
      std::cout << wasm;
    }

    // run asserts
    while (i < root.size()) {
      Element& curr = *root[i];
      IString id = curr[0]->str();
      if (id == MODULE) break;
      Colors::red(std::cerr);
      std::cerr << i << '/' << (root.size()-1);
      Colors::green(std::cerr);
      std::cerr << " CHECKING: ";
      Colors::normal(std::cerr);
      std::cerr << curr << '\n';
      Element& invoke = *curr[1];
      assert(invoke[0]->str() == INVOKE);
      IString name = invoke[1]->str();
      ModuleInstance::LiteralList arguments;
      for (size_t j = 2; j < invoke.size(); j++) {
        Expression* argument = builder.parseExpression(*invoke[2]);
        arguments.push_back(argument->dyn_cast<Const>()->value);
      }
      bool trapped = false;
      Literal result;
      if (setjmp(interface->trapState) == 0) {
        result = instance->callFunction(name, arguments);
      } else {
        trapped = true;
      }
      if (id == ASSERT_RETURN) {
        assert(!trapped);
        Literal expected;
        if (curr.size() >= 3) {
          expected = builder.parseExpression(*curr[2])->dyn_cast<Const>()->value;
        }
        std::cerr << "seen " << result << ", expected " << expected << '\n';
        assert(expected == result);
      }
      if (id == ASSERT_TRAP) assert(trapped);
      i++;
    }
  }

  if (debug) std::cerr << "done.\n";
}

<commit_msg>i64 stores in shell<commit_after>
//
// A WebAssembly shell, loads a .wast file (WebAssembly in S-Expression format) and executes it.
//

#include <setjmp.h>

#include "wasm-s-parser.h"
#include "wasm-interpreter.h"

using namespace cashew;
using namespace wasm;

IString ASSERT_RETURN("assert_return"),
        ASSERT_TRAP("assert_trap"),
        PRINT("print"),
        INVOKE("invoke");

//
// Implementation of the shell interpreter execution environment
//

struct ShellExternalInterface : ModuleInstance::ExternalInterface {
  char *memory;
  size_t memorySize;

  ShellExternalInterface() : memory(nullptr) {}

  void init(Module& wasm) override {
    memory = new char[wasm.memory.initial];
    memorySize = wasm.memory.initial;
    // apply memory segments
    for (auto segment : wasm.memory.segments) {
      memcpy(memory + segment.offset, segment.data, segment.size);
    }
  }

  Literal callImport(Import *import, ModuleInstance::LiteralList& arguments) override {
    if (import->name == PRINT) {
      for (auto argument : arguments) {
        std::cout << argument << ' ';
      }
      std::cout << '\n';
      return Literal();
    }
    std::cout << "callImport " << import->name.str << "\n";
    abort();
  }

  Literal load(Load* load, size_t addr) override {
    // ignore align - assume we are on x86 etc. which does that
    switch (load->type) {
      case i32: {
        switch (load->bytes) {
          case 1: return load->signed_ ? (int32_t)((int8_t*)memory)[addr]  : (int32_t)((uint8_t*)memory)[addr];
          case 2: return load->signed_ ? (int32_t)((int16_t*)memory)[addr] : (int32_t)((uint16_t*)memory)[addr];
          case 4: return load->signed_ ? (int32_t)((int32_t*)memory)[addr] : (int32_t)((uint32_t*)memory)[addr];
          default: abort();
        }
        break;
      }
      case i64: {
        switch (load->bytes) {
          case 1: return load->signed_ ? (int64_t)((int8_t*)memory)[addr]  : (int64_t)((uint8_t*)memory)[addr];
          case 2: return load->signed_ ? (int64_t)((int16_t*)memory)[addr] : (int64_t)((uint16_t*)memory)[addr];
          case 4: return load->signed_ ? (int64_t)((int32_t*)memory)[addr] : (int64_t)((uint32_t*)memory)[addr];
          case 8: return load->signed_ ? (int64_t)((int64_t*)memory)[addr] : (int64_t)((uint64_t*)memory)[addr];
          default: abort();
        }
        break;
      }
      case f32: return ((float*)memory)[addr];
      case f64: return ((double*)memory)[addr];
      default: abort();
    }
  }

  void store(Store* store, size_t addr, Literal value) override {
    // ignore align - assume we are on x86 etc. which does that
    switch (store->type) {
      case i32: {
        switch (store->bytes) {
          case 1: ((int8_t*)memory)[addr] = value.geti32(); break;
          case 2: ((int16_t*)memory)[addr] = value.geti32(); break;
          case 4: ((int32_t*)memory)[addr] = value.geti32(); break;
          default: abort();
        }
        break;
      }
      case i64: {
        switch (store->bytes) {
          case 1: ((int8_t*)memory)[addr] = value.geti64(); break;
          case 2: ((int16_t*)memory)[addr] = value.geti64(); break;
          case 4: ((int32_t*)memory)[addr] = value.geti64(); break;
          case 8: ((int64_t*)memory)[addr] = value.geti64(); break;
          default: abort();
        }
        break;
      }
      case f32: ((float*)memory)[addr] = value.getf32(); break;
      case f64: ((double*)memory)[addr] = value.getf64(); break;
      default: abort();
    }
  }

  jmp_buf trapState;

  void trap() override {
    longjmp(trapState, 1);
  }
};

int main(int argc, char **argv) {
  debug = getenv("WASM_SHELL_DEBUG") ? getenv("WASM_SHELL_DEBUG")[0] - '0' : 0;

  char *infile = argv[1];
  bool print_wasm = argc >= 3; // second arg means print it out

  if (debug) std::cerr << "loading '" << infile << "'...\n";
  FILE *f = fopen(argv[1], "r");
  assert(f);
  fseek(f, 0, SEEK_END);
  int size = ftell(f);
  char *input = new char[size+1];
  rewind(f);
  int num = fread(input, 1, size, f);
  // On Windows, ftell() gives the byte position (\r\n counts as two bytes), but when
  // reading, fread() returns the number of characters read (\r\n is read as one char \n, and counted as one),
  // so return value of fread can be less than size reported by ftell, and that is normal.
  assert((num > 0 || size == 0) && num <= size);
  fclose(f);
  input[num] = 0;

  if (debug) std::cerr << "parsing text to s-expressions...\n";
  SExpressionParser parser(input);
  Element& root = *parser.root;
  if (debug) std::cout << root << '\n';

  // A .wast may have multiple modules, with some asserts after them
  size_t i = 0;
  while (i < root.size()) {
    if (debug) std::cerr << "parsing s-expressions to wasm...\n";
    Module wasm;
    SExpressionWasmBuilder builder(wasm, *root[i]);
    i++;

    auto interface = new ShellExternalInterface();
    auto instance = new ModuleInstance(wasm, interface);

    if (print_wasm) {
      if (debug) std::cerr << "printing...\n";
      std::cout << wasm;
    }

    // run asserts
    while (i < root.size()) {
      Element& curr = *root[i];
      IString id = curr[0]->str();
      if (id == MODULE) break;
      Colors::red(std::cerr);
      std::cerr << i << '/' << (root.size()-1);
      Colors::green(std::cerr);
      std::cerr << " CHECKING: ";
      Colors::normal(std::cerr);
      std::cerr << curr << '\n';
      Element& invoke = *curr[1];
      assert(invoke[0]->str() == INVOKE);
      IString name = invoke[1]->str();
      ModuleInstance::LiteralList arguments;
      for (size_t j = 2; j < invoke.size(); j++) {
        Expression* argument = builder.parseExpression(*invoke[2]);
        arguments.push_back(argument->dyn_cast<Const>()->value);
      }
      bool trapped = false;
      Literal result;
      if (setjmp(interface->trapState) == 0) {
        result = instance->callFunction(name, arguments);
      } else {
        trapped = true;
      }
      if (id == ASSERT_RETURN) {
        assert(!trapped);
        Literal expected;
        if (curr.size() >= 3) {
          expected = builder.parseExpression(*curr[2])->dyn_cast<Const>()->value;
        }
        std::cerr << "seen " << result << ", expected " << expected << '\n';
        assert(expected == result);
      }
      if (id == ASSERT_TRAP) assert(trapped);
      i++;
    }
  }

  if (debug) std::cerr << "done.\n";
}

<|endoftext|>


<commit_before><commit_msg>* 修复识别不了canvas.fillStyle("#ffff0000"); 这种四个字节的颜色格式的问题<commit_after><|endoftext|>


<commit_before>// @(#)root/base:$Id$
// Author: Fons Rademakers   29/07/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TStorage                                                             //
//                                                                      //
// Storage manager. The storage manager works best in conjunction with  //
// the custom ROOT new and delete operators defined in the file         //
// NewDelete.cxx (libNew.so). Only when using the custom allocation     //
// operators will memory usage statistics be gathered using the         //
// TStorage EnterStat(), RemoveStat(), etc. functions.                  //
// Memory checking is by default enabled (when using libNew.so) and     //
// usage statistics is gathered. Using the resource (in .rootrc):       //
// Root.MemStat one can toggle statistics gathering on or off. More     //
// specifically on can trap the allocation of a block of memory of a    //
// certain size. This can be specified using the resource:              //
// Root.MemStat.size, using the resource Root.MemStat.cnt one can       //
// specify after how many allocations of this size the trap should      //
// occur.                                                               //
// Set the compile option R__NOSTATS to de-activate all memory checking //
// and statistics gathering in the system.                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <stdlib.h>

#include "TROOT.h"
#include "TObjectTable.h"
#include "TError.h"
#include "TString.h"
#include "TVirtualMutex.h"
#include "TInterpreter.h"

#if !defined(R__NOSTATS)
#   define MEM_DEBUG
#   define MEM_STAT
#   define MEM_CHECKOBJECTPOINTERS
#endif

#if defined(MEM_STAT) && !defined(MEM_DEBUG)
#   define MEM_DEBUG
#endif

#ifdef MEM_DEBUG
#   ifdef R__B64
#      define storage_size(p) ((size_t)(((size_t*)p)[-1]))
#   else
#      define storage_size(p) ((size_t)(((int*)p)[-2]))
#   endif
#else
#   define storage_size(p) ((size_t)0)
#endif

#define PVOID (-1)

ULong_t       TStorage::fgHeapBegin = (ULong_t)-1L;
ULong_t       TStorage::fgHeapEnd;
size_t        TStorage::fgMaxBlockSize;
FreeHookFun_t TStorage::fgFreeHook;
void         *TStorage::fgFreeHookData;
ReAllocFun_t  TStorage::fgReAllocHook;
ReAllocCFun_t TStorage::fgReAllocCHook;
Bool_t        TStorage::fgHasCustomNewDelete;

ClassImp(TStorage)

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

static const char *gSpaceErr = "storage exhausted";

const size_t kObjMaxSize = 10024;

static Bool_t   gMemStatistics;
static Int_t    gAllocated[kObjMaxSize], gFreed[kObjMaxSize];
static Int_t    gAllocatedTotal, gFreedTotal;
static void   **gTraceArray = 0;
static Int_t    gTraceCapacity = 10, gTraceIndex = 0,
                gMemSize = -1, gMemIndex = -1;

//______________________________________________________________________________
void TStorage::EnterStat(size_t size, void *p)
{
   // Register a memory allocation operation. If desired one can trap an
   // allocation of a certain size in case one tries to find a memory
   // leak of that particular size. This function is only called via
   // the ROOT custom new operators.

   TStorage::SetMaxBlockSize(TMath::Max(TStorage::GetMaxBlockSize(), size));

   if (!gMemStatistics) return;

   if ((Int_t)size == gMemSize) {
      if (gTraceIndex == gMemIndex)
         Fatal("EnterStat", "trapped allocation %d", gMemIndex);

      if (!gTraceArray)
         gTraceArray = (void**) malloc(sizeof(void*)*gTraceCapacity);

      if (gTraceIndex >= gTraceCapacity) {
         gTraceCapacity = gTraceCapacity*2;
         gTraceArray = (void**) realloc(gTraceArray, sizeof(void*)*gTraceCapacity);
      }
      gTraceArray[gTraceIndex++] = p;
   }
   if (size >= kObjMaxSize)
      gAllocated[kObjMaxSize-1]++;
   else
      gAllocated[size]++;
   gAllocatedTotal += size;
}

//______________________________________________________________________________
void TStorage::RemoveStat(void *vp)
{
   // Register a memory free operation. This function is only called via
   // the custom ROOT delete operator.

   if (!gMemStatistics) return;

   size_t size = storage_size(vp);
   if ((Int_t)size == gMemSize) {
      for (int i = 0; i < gTraceIndex; i++)
         if (gTraceArray[i] == vp) {
            gTraceArray[i] = 0;
            break;
         }
   }
   if (size >= kObjMaxSize)
      gFreed[kObjMaxSize-1]++;
   else
      gFreed[size]++;
   gFreedTotal += size;
}

//______________________________________________________________________________
void *TStorage::Alloc(size_t size)
{
   // Allocate a block of memory, that later can be resized using
   // TStorage::ReAlloc().

   static const char *where = "TStorage::Alloc";

#ifndef WIN32
   void *vp = ::operator new[](size);
#else
   void *vp = ::operator new(size);
#endif
   if (vp == 0)
      Fatal(where, "%s", gSpaceErr);

   return vp;
}

//______________________________________________________________________________
void TStorage::Dealloc(void *ptr)
{
   // De-allocate block of memory, that was allocated via TStorage::Alloc().

#ifndef WIN32
   ::operator delete[](ptr);
#else
   ::operator delete(ptr);
#endif
}

//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size)
{
   // Reallocate (i.e. resize) block of memory.

   // Needs to be protected by global mutex
   R__LOCKGUARD(gGlobalMutex);

   if (fgReAllocHook && fgHasCustomNewDelete && !TROOT::MemCheck())
      return (*fgReAllocHook)(ovp, size);

   static const char *where = "TStorage::ReAlloc";

#ifndef WIN32
   void *vp = ::operator new[](size);
#else
   void *vp = ::operator new(size);
#endif
   if (vp == 0)
      Fatal(where, "%s", gSpaceErr);

   if (ovp == 0)
      return vp;

   memmove(vp, ovp, size);
#ifndef WIN32
   ::operator delete[](ovp);
#else
   ::operator delete(ovp);
#endif
   return vp;
}

//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size, size_t oldsize)
{
   // Reallocate (i.e. resize) block of memory. Checks if current size is
   // equal to oldsize. If not memory was overwritten.

   // Needs to be protected by global mutex
   R__LOCKGUARD(gGlobalMutex);

   if (fgReAllocCHook && fgHasCustomNewDelete && !TROOT::MemCheck())
      return (*fgReAllocCHook)(ovp, size, oldsize);

   static const char *where = "TStorage::ReAlloc";

   if (oldsize == size)
      return ovp;

#ifndef WIN32
   void *vp = ::operator new[](size);
#else
   void *vp = ::operator new(size);
#endif
   if (vp == 0)
      Fatal(where, "%s", gSpaceErr);

   if (ovp == 0)
      return vp;

   if (size > oldsize) {
      memcpy(vp, ovp, oldsize);
      memset((char*)vp+oldsize, 0, size-oldsize);
   } else
      memcpy(vp, ovp, size);
#ifndef WIN32
   ::operator delete[](ovp);
#else
   ::operator delete(ovp);
#endif
   return vp;
}

//______________________________________________________________________________
char *TStorage::ReAllocChar(char *ovp, size_t size, size_t oldsize)
{
   // Reallocate (i.e. resize) array of chars. Size and oldsize are
   // in number of chars.

   // Needs to be protected by global mutex
   R__LOCKGUARD(gGlobalMutex);

   static const char *where = "TStorage::ReAllocChar";

   char *vp;
   if (ovp == 0) {
      vp = new char[size];
      if (vp == 0)
         Fatal(where, "%s", gSpaceErr);
      return vp;
   }
   if (oldsize == size)
      return ovp;

   vp = new char[size];
   if (vp == 0)
      Fatal(where, "%s", gSpaceErr);
   if (size > oldsize) {
      memcpy(vp, ovp, oldsize);
      memset((char*)vp+oldsize, 0, size-oldsize);
   } else
      memcpy(vp, ovp, size);
   delete [] ovp;
   return vp;
}

//______________________________________________________________________________
Int_t *TStorage::ReAllocInt(Int_t *ovp, size_t size, size_t oldsize)
{
   // Reallocate (i.e. resize) array of integers. Size and oldsize are
   // number of integers (not number of bytes).

   // Needs to be protected by global mutex
   R__LOCKGUARD(gGlobalMutex);

   static const char *where = "TStorage::ReAllocInt";

   Int_t *vp;
   if (ovp == 0) {
      vp = new Int_t[size];
      if (vp == 0)
         Fatal(where, "%s", gSpaceErr);
      return vp;
   }
   if (oldsize == size)
      return ovp;

   vp = new Int_t[size];
   if (vp == 0)
      Fatal(where, "%s", gSpaceErr);
   if (size > oldsize) {
      memcpy(vp, ovp, oldsize*sizeof(Int_t));
      memset((Int_t*)vp+oldsize, 0, (size-oldsize)*sizeof(Int_t));
   } else
      memcpy(vp, ovp, size*sizeof(Int_t));
   delete [] ovp;
   return vp;
}

//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t sz)
{
   // Used to allocate a TObject on the heap (via TObject::operator new()).
   // Directly after this routine one can call (in the TObject ctor)
   // TStorage::IsOnHeap() to find out if the just created object is on
   // the heap.

   // Needs to be protected by global mutex
   R__LOCKGUARD(gGlobalMutex);

   ULong_t space = (ULong_t) ::operator new(sz);
   AddToHeap(space, space+sz);
   return (void*) space;
}

//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t , void *vp)
{
   // Used to allocate a TObject on the heap (via TObject::operator new(size_t,void*))
   // in position vp. vp is already allocated (maybe on heap, maybe on
   // stack) so just return.

   return vp;
}

//______________________________________________________________________________
void TStorage::ObjectDealloc(void *vp)
{
   // Used to deallocate a TObject on the heap (via TObject::operator delete()).

   ::operator delete(vp);
}

//______________________________________________________________________________
void TStorage::ObjectDealloc(void *vp, void *ptr)
{
   // Used to deallocate a TObject on the heap (via TObject::operator delete(void*,void*)).

   if (vp && ptr) { }
}

//______________________________________________________________________________
void TStorage::SetFreeHook(FreeHookFun_t fh, void *data)
{
   // Set a free handler.

   fgFreeHook     = fh;
   fgFreeHookData = data;
}

//______________________________________________________________________________
void TStorage::SetReAllocHooks(ReAllocFun_t rh1, ReAllocCFun_t rh2)
{
   // Set a custom ReAlloc handlers. This function is typically
   // called via a static object in the ROOT libNew.so shared library.

   fgReAllocHook  = rh1;
   fgReAllocCHook = rh2;
}

//______________________________________________________________________________
void TStorage::PrintStatistics()
{
   // Print memory usage statistics.

   // Needs to be protected by global mutex
   R__LOCKGUARD(gGlobalMutex);

#if defined(MEM_DEBUG) && defined(MEM_STAT)

   if (!gMemStatistics || !HasCustomNewDelete())
      return;

   //Printf("");
   Printf("Heap statistics");
   Printf("%12s%12s%12s%12s", "size", "alloc", "free", "diff");
   Printf("================================================");

   int i;
   for (i = 0; i < (int)kObjMaxSize; i++)
      if (gAllocated[i] != gFreed[i])
      //if (gAllocated[i])
         Printf("%12d%12d%12d%12d", i, gAllocated[i], gFreed[i],
                gAllocated[i]-gFreed[i]);

   if (gAllocatedTotal != gFreedTotal) {
      Printf("------------------------------------------------");
      Printf("Total:      %12d%12d%12d", gAllocatedTotal, gFreedTotal,
              gAllocatedTotal-gFreedTotal);
   }

   if (gMemSize != -1) {
      Printf("------------------------------------------------");
      for (i= 0; i < gTraceIndex; i++)
         if (gTraceArray[i])
            Printf("block %d of size %d not freed", i, gMemSize);
   }
   Printf("================================================");
   Printf(" ");
#endif
}

//______________________________________________________________________________
void TStorage::EnableStatistics(int size, int ix)
{
   // Enable memory usage statistics gathering. Size is the size of the memory
   // block that should be trapped and ix is after how many such allocations
   // the trap should happen.

#ifdef MEM_STAT
   gMemSize       = size;
   gMemIndex      = ix;
   gMemStatistics = kTRUE;
#else
   int idum = size; int iidum = ix;
#endif
}

//______________________________________________________________________________
ULong_t TStorage::GetHeapBegin()
{
   //return begin of heap
   return fgHeapBegin;
}

//______________________________________________________________________________
ULong_t TStorage::GetHeapEnd()
{
   //return end of heap
   return fgHeapEnd;
}

//______________________________________________________________________________
void *TStorage::GetFreeHookData()
{
   //return static free hook data
   return fgFreeHookData;
}

//______________________________________________________________________________
Bool_t TStorage::HasCustomNewDelete()
{
   //return the has custom delete flag
   return fgHasCustomNewDelete;
}

//______________________________________________________________________________
void TStorage::SetCustomNewDelete()
{
   //set the has custom delete flag
   fgHasCustomNewDelete = kTRUE;
}

#ifdef WIN32

//______________________________________________________________________________
void TStorage::AddToHeap(ULong_t begin, ULong_t end)
{
   //add a range to the heap
   if (begin < fgHeapBegin) fgHeapBegin = begin;
   if (end   > fgHeapEnd)   fgHeapEnd   = end;
}

//______________________________________________________________________________
Bool_t TStorage::IsOnHeap(void *p)
{
   //is object at p in the heap?
   return (ULong_t)p >= fgHeapBegin && (ULong_t)p < fgHeapEnd;
}

//______________________________________________________________________________
size_t TStorage::GetMaxBlockSize()
{
   //return max block size
   return fgMaxBlockSize;
}

//______________________________________________________________________________
void TStorage::SetMaxBlockSize(size_t size)
{
   //set max block size
   fgMaxBlockSize = size;
}

//______________________________________________________________________________
FreeHookFun_t TStorage::GetFreeHook()
{
   //return free hook
   return fgFreeHook;
}

#endif
<commit_msg>mark ReAlloc(void*,size_t) as obsolete for v6-02-00 as it is non-safe.<commit_after>// @(#)root/base:$Id$
// Author: Fons Rademakers   29/07/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TStorage                                                             //
//                                                                      //
// Storage manager. The storage manager works best in conjunction with  //
// the custom ROOT new and delete operators defined in the file         //
// NewDelete.cxx (libNew.so). Only when using the custom allocation     //
// operators will memory usage statistics be gathered using the         //
// TStorage EnterStat(), RemoveStat(), etc. functions.                  //
// Memory checking is by default enabled (when using libNew.so) and     //
// usage statistics is gathered. Using the resource (in .rootrc):       //
// Root.MemStat one can toggle statistics gathering on or off. More     //
// specifically on can trap the allocation of a block of memory of a    //
// certain size. This can be specified using the resource:              //
// Root.MemStat.size, using the resource Root.MemStat.cnt one can       //
// specify after how many allocations of this size the trap should      //
// occur.                                                               //
// Set the compile option R__NOSTATS to de-activate all memory checking //
// and statistics gathering in the system.                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <stdlib.h>

#include "TROOT.h"
#include "TObjectTable.h"
#include "TError.h"
#include "TString.h"
#include "TVirtualMutex.h"
#include "TInterpreter.h"

#if !defined(R__NOSTATS)
#   define MEM_DEBUG
#   define MEM_STAT
#   define MEM_CHECKOBJECTPOINTERS
#endif

#if defined(MEM_STAT) && !defined(MEM_DEBUG)
#   define MEM_DEBUG
#endif

#ifdef MEM_DEBUG
#   ifdef R__B64
#      define storage_size(p) ((size_t)(((size_t*)p)[-1]))
#   else
#      define storage_size(p) ((size_t)(((int*)p)[-2]))
#   endif
#else
#   define storage_size(p) ((size_t)0)
#endif

#define PVOID (-1)

ULong_t       TStorage::fgHeapBegin = (ULong_t)-1L;
ULong_t       TStorage::fgHeapEnd;
size_t        TStorage::fgMaxBlockSize;
FreeHookFun_t TStorage::fgFreeHook;
void         *TStorage::fgFreeHookData;
ReAllocFun_t  TStorage::fgReAllocHook;
ReAllocCFun_t TStorage::fgReAllocCHook;
Bool_t        TStorage::fgHasCustomNewDelete;

ClassImp(TStorage)

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

static const char *gSpaceErr = "storage exhausted";

const size_t kObjMaxSize = 10024;

static Bool_t   gMemStatistics;
static Int_t    gAllocated[kObjMaxSize], gFreed[kObjMaxSize];
static Int_t    gAllocatedTotal, gFreedTotal;
static void   **gTraceArray = 0;
static Int_t    gTraceCapacity = 10, gTraceIndex = 0,
                gMemSize = -1, gMemIndex = -1;

//______________________________________________________________________________
void TStorage::EnterStat(size_t size, void *p)
{
   // Register a memory allocation operation. If desired one can trap an
   // allocation of a certain size in case one tries to find a memory
   // leak of that particular size. This function is only called via
   // the ROOT custom new operators.

   TStorage::SetMaxBlockSize(TMath::Max(TStorage::GetMaxBlockSize(), size));

   if (!gMemStatistics) return;

   if ((Int_t)size == gMemSize) {
      if (gTraceIndex == gMemIndex)
         Fatal("EnterStat", "trapped allocation %d", gMemIndex);

      if (!gTraceArray)
         gTraceArray = (void**) malloc(sizeof(void*)*gTraceCapacity);

      if (gTraceIndex >= gTraceCapacity) {
         gTraceCapacity = gTraceCapacity*2;
         gTraceArray = (void**) realloc(gTraceArray, sizeof(void*)*gTraceCapacity);
      }
      gTraceArray[gTraceIndex++] = p;
   }
   if (size >= kObjMaxSize)
      gAllocated[kObjMaxSize-1]++;
   else
      gAllocated[size]++;
   gAllocatedTotal += size;
}

//______________________________________________________________________________
void TStorage::RemoveStat(void *vp)
{
   // Register a memory free operation. This function is only called via
   // the custom ROOT delete operator.

   if (!gMemStatistics) return;

   size_t size = storage_size(vp);
   if ((Int_t)size == gMemSize) {
      for (int i = 0; i < gTraceIndex; i++)
         if (gTraceArray[i] == vp) {
            gTraceArray[i] = 0;
            break;
         }
   }
   if (size >= kObjMaxSize)
      gFreed[kObjMaxSize-1]++;
   else
      gFreed[size]++;
   gFreedTotal += size;
}

//______________________________________________________________________________
void *TStorage::Alloc(size_t size)
{
   // Allocate a block of memory, that later can be resized using
   // TStorage::ReAlloc().

   static const char *where = "TStorage::Alloc";

#ifndef WIN32
   void *vp = ::operator new[](size);
#else
   void *vp = ::operator new(size);
#endif
   if (vp == 0)
      Fatal(where, "%s", gSpaceErr);

   return vp;
}

//______________________________________________________________________________
void TStorage::Dealloc(void *ptr)
{
   // De-allocate block of memory, that was allocated via TStorage::Alloc().

#ifndef WIN32
   ::operator delete[](ptr);
#else
   ::operator delete(ptr);
#endif
}

//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size)
{
   // Reallocate (i.e. resize) block of memory. Don't use if size is larger
   // than old size, use ReAlloc(void *, size_t, size_t) instead.

   ::Obsolete("ReAlloc(void*,size_t)", "v5-34-00", "v6-02-00");
   ::Info("ReAlloc(void*,size_t)", "please use ReAlloc(void*,size_t,size_t)");

   // Needs to be protected by global mutex
   R__LOCKGUARD(gGlobalMutex);

   if (fgReAllocHook && fgHasCustomNewDelete && !TROOT::MemCheck())
      return (*fgReAllocHook)(ovp, size);

   static const char *where = "TStorage::ReAlloc";

#ifndef WIN32
   void *vp = ::operator new[](size);
#else
   void *vp = ::operator new(size);
#endif
   if (vp == 0)
      Fatal(where, "%s", gSpaceErr);

   if (ovp == 0)
      return vp;

   memmove(vp, ovp, size);
#ifndef WIN32
   ::operator delete[](ovp);
#else
   ::operator delete(ovp);
#endif
   return vp;
}

//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size, size_t oldsize)
{
   // Reallocate (i.e. resize) block of memory. Checks if current size is
   // equal to oldsize. If not memory was overwritten.

   // Needs to be protected by global mutex
   R__LOCKGUARD(gGlobalMutex);

   if (fgReAllocCHook && fgHasCustomNewDelete && !TROOT::MemCheck())
      return (*fgReAllocCHook)(ovp, size, oldsize);

   static const char *where = "TStorage::ReAlloc";

   if (oldsize == size)
      return ovp;

#ifndef WIN32
   void *vp = ::operator new[](size);
#else
   void *vp = ::operator new(size);
#endif
   if (vp == 0)
      Fatal(where, "%s", gSpaceErr);

   if (ovp == 0)
      return vp;

   if (size > oldsize) {
      memcpy(vp, ovp, oldsize);
      memset((char*)vp+oldsize, 0, size-oldsize);
   } else
      memcpy(vp, ovp, size);
#ifndef WIN32
   ::operator delete[](ovp);
#else
   ::operator delete(ovp);
#endif
   return vp;
}

//______________________________________________________________________________
char *TStorage::ReAllocChar(char *ovp, size_t size, size_t oldsize)
{
   // Reallocate (i.e. resize) array of chars. Size and oldsize are
   // in number of chars.

   // Needs to be protected by global mutex
   R__LOCKGUARD(gGlobalMutex);

   static const char *where = "TStorage::ReAllocChar";

   char *vp;
   if (ovp == 0) {
      vp = new char[size];
      if (vp == 0)
         Fatal(where, "%s", gSpaceErr);
      return vp;
   }
   if (oldsize == size)
      return ovp;

   vp = new char[size];
   if (vp == 0)
      Fatal(where, "%s", gSpaceErr);
   if (size > oldsize) {
      memcpy(vp, ovp, oldsize);
      memset((char*)vp+oldsize, 0, size-oldsize);
   } else
      memcpy(vp, ovp, size);
   delete [] ovp;
   return vp;
}

//______________________________________________________________________________
Int_t *TStorage::ReAllocInt(Int_t *ovp, size_t size, size_t oldsize)
{
   // Reallocate (i.e. resize) array of integers. Size and oldsize are
   // number of integers (not number of bytes).

   // Needs to be protected by global mutex
   R__LOCKGUARD(gGlobalMutex);

   static const char *where = "TStorage::ReAllocInt";

   Int_t *vp;
   if (ovp == 0) {
      vp = new Int_t[size];
      if (vp == 0)
         Fatal(where, "%s", gSpaceErr);
      return vp;
   }
   if (oldsize == size)
      return ovp;

   vp = new Int_t[size];
   if (vp == 0)
      Fatal(where, "%s", gSpaceErr);
   if (size > oldsize) {
      memcpy(vp, ovp, oldsize*sizeof(Int_t));
      memset((Int_t*)vp+oldsize, 0, (size-oldsize)*sizeof(Int_t));
   } else
      memcpy(vp, ovp, size*sizeof(Int_t));
   delete [] ovp;
   return vp;
}

//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t sz)
{
   // Used to allocate a TObject on the heap (via TObject::operator new()).
   // Directly after this routine one can call (in the TObject ctor)
   // TStorage::IsOnHeap() to find out if the just created object is on
   // the heap.

   // Needs to be protected by global mutex
   R__LOCKGUARD(gGlobalMutex);

   ULong_t space = (ULong_t) ::operator new(sz);
   AddToHeap(space, space+sz);
   return (void*) space;
}

//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t , void *vp)
{
   // Used to allocate a TObject on the heap (via TObject::operator new(size_t,void*))
   // in position vp. vp is already allocated (maybe on heap, maybe on
   // stack) so just return.

   return vp;
}

//______________________________________________________________________________
void TStorage::ObjectDealloc(void *vp)
{
   // Used to deallocate a TObject on the heap (via TObject::operator delete()).

   ::operator delete(vp);
}

//______________________________________________________________________________
void TStorage::ObjectDealloc(void *vp, void *ptr)
{
   // Used to deallocate a TObject on the heap (via TObject::operator delete(void*,void*)).

   if (vp && ptr) { }
}

//______________________________________________________________________________
void TStorage::SetFreeHook(FreeHookFun_t fh, void *data)
{
   // Set a free handler.

   fgFreeHook     = fh;
   fgFreeHookData = data;
}

//______________________________________________________________________________
void TStorage::SetReAllocHooks(ReAllocFun_t rh1, ReAllocCFun_t rh2)
{
   // Set a custom ReAlloc handlers. This function is typically
   // called via a static object in the ROOT libNew.so shared library.

   fgReAllocHook  = rh1;
   fgReAllocCHook = rh2;
}

//______________________________________________________________________________
void TStorage::PrintStatistics()
{
   // Print memory usage statistics.

   // Needs to be protected by global mutex
   R__LOCKGUARD(gGlobalMutex);

#if defined(MEM_DEBUG) && defined(MEM_STAT)

   if (!gMemStatistics || !HasCustomNewDelete())
      return;

   //Printf("");
   Printf("Heap statistics");
   Printf("%12s%12s%12s%12s", "size", "alloc", "free", "diff");
   Printf("================================================");

   int i;
   for (i = 0; i < (int)kObjMaxSize; i++)
      if (gAllocated[i] != gFreed[i])
      //if (gAllocated[i])
         Printf("%12d%12d%12d%12d", i, gAllocated[i], gFreed[i],
                gAllocated[i]-gFreed[i]);

   if (gAllocatedTotal != gFreedTotal) {
      Printf("------------------------------------------------");
      Printf("Total:      %12d%12d%12d", gAllocatedTotal, gFreedTotal,
              gAllocatedTotal-gFreedTotal);
   }

   if (gMemSize != -1) {
      Printf("------------------------------------------------");
      for (i= 0; i < gTraceIndex; i++)
         if (gTraceArray[i])
            Printf("block %d of size %d not freed", i, gMemSize);
   }
   Printf("================================================");
   Printf(" ");
#endif
}

//______________________________________________________________________________
void TStorage::EnableStatistics(int size, int ix)
{
   // Enable memory usage statistics gathering. Size is the size of the memory
   // block that should be trapped and ix is after how many such allocations
   // the trap should happen.

#ifdef MEM_STAT
   gMemSize       = size;
   gMemIndex      = ix;
   gMemStatistics = kTRUE;
#else
   int idum = size; int iidum = ix;
#endif
}

//______________________________________________________________________________
ULong_t TStorage::GetHeapBegin()
{
   //return begin of heap
   return fgHeapBegin;
}

//______________________________________________________________________________
ULong_t TStorage::GetHeapEnd()
{
   //return end of heap
   return fgHeapEnd;
}

//______________________________________________________________________________
void *TStorage::GetFreeHookData()
{
   //return static free hook data
   return fgFreeHookData;
}

//______________________________________________________________________________
Bool_t TStorage::HasCustomNewDelete()
{
   //return the has custom delete flag
   return fgHasCustomNewDelete;
}

//______________________________________________________________________________
void TStorage::SetCustomNewDelete()
{
   //set the has custom delete flag
   fgHasCustomNewDelete = kTRUE;
}

#ifdef WIN32

//______________________________________________________________________________
void TStorage::AddToHeap(ULong_t begin, ULong_t end)
{
   //add a range to the heap
   if (begin < fgHeapBegin) fgHeapBegin = begin;
   if (end   > fgHeapEnd)   fgHeapEnd   = end;
}

//______________________________________________________________________________
Bool_t TStorage::IsOnHeap(void *p)
{
   //is object at p in the heap?
   return (ULong_t)p >= fgHeapBegin && (ULong_t)p < fgHeapEnd;
}

//______________________________________________________________________________
size_t TStorage::GetMaxBlockSize()
{
   //return max block size
   return fgMaxBlockSize;
}

//______________________________________________________________________________
void TStorage::SetMaxBlockSize(size_t size)
{
   //set max block size
   fgMaxBlockSize = size;
}

//______________________________________________________________________________
FreeHookFun_t TStorage::GetFreeHook()
{
   //return free hook
   return fgFreeHook;
}

#endif
<|endoftext|>


<commit_before>
//
// A WebAssembly shell, loads a .wast file (WebAssembly in S-Expression format) and executes it.
//

#include <setjmp.h>

#include "wasm-s-parser.h"
#include "wasm-interpreter.h"

using namespace cashew;
using namespace wasm;

IString ASSERT_RETURN("assert_return"),
        ASSERT_TRAP("assert_trap"),
        PRINT("print"),
        INVOKE("invoke");

//
// Implementation of the shell interpreter execution environment
//

struct ShellExternalInterface : ModuleInstance::ExternalInterface {
  char *memory;
  size_t memorySize;

  ShellExternalInterface() : memory(nullptr) {}

  void init(Module& wasm) override {
    memory = new char[wasm.memory.initial];
    memorySize = wasm.memory.initial;
    // apply memory segments
    for (auto segment : wasm.memory.segments) {
      memcpy(memory + segment.offset, segment.data, segment.size);
    }
  }

  jmp_buf trapState;

  void trap() {
    longjmp(trapState, 1);
  }

  Literal callImport(Import *import, ModuleInstance::LiteralList& arguments) override {
    if (import->name == PRINT) {
      for (auto argument : arguments) {
        std::cout << argument << ' ';
      }
      std::cout << '\n';
      return Literal();
    }
    std::cout << "callImport " << import->name.str << "\n";
    abort();
  }

  Literal load(Load* load, Literal ptr) override {
    // ignore align - assume we are on x86 etc. which does that
    size_t addr = ptr.geti32();
    int64_t full = addr;
    full += load->offset;
    if (full + load->bytes > memorySize) trap();
    addr = full;
    switch (load->type) {
      case i32: {
        switch (load->bytes) {
          case 1: return load->signed_ ? (int32_t)((int8_t*)memory)[addr]  : (int32_t)((uint8_t*)memory)[addr];
          case 2: return load->signed_ ? (int32_t)((int16_t*)memory)[addr] : (int32_t)((uint16_t*)memory)[addr];
          case 4: return load->signed_ ? (int32_t)((int32_t*)memory)[addr] : (int32_t)((uint32_t*)memory)[addr];
          default: abort();
        }
        break;
      }
      case f32: return ((float*)memory)[addr];
      case f64: return ((double*)memory)[addr];
      default: abort();
    }
  }

  void store(Store* store, Literal ptr, Literal value) override {
    // ignore align - assume we are on x86 etc. which does that
    size_t addr = ptr.geti32();
    int64_t full = addr;
    full += store->offset;
    if (full + store->bytes > memorySize) trap();
    switch (store->type) {
      case i32: {
        switch (store->bytes) {
          case 1: ((int8_t*)memory)[addr] = value.geti32();
          case 2: ((int16_t*)memory)[addr] = value.geti32();
          case 4: ((int32_t*)memory)[addr] = value.geti32();
          default: abort();
        }
        break;
      }
      case f32: ((float*)memory)[addr] = value.getf32();
      case f64: ((double*)memory)[addr] = value.getf64();
      default: abort();
    }
  }
};

int main(int argc, char **argv) {
  debug = getenv("WASM_SHELL_DEBUG") ? getenv("WASM_SHELL_DEBUG")[0] - '0' : 0;

  char *infile = argv[1];
  bool print_wasm = argc >= 3; // second arg means print it out

  if (debug) std::cerr << "loading '" << infile << "'...\n";
  FILE *f = fopen(argv[1], "r");
  assert(f);
  fseek(f, 0, SEEK_END);
  int size = ftell(f);
  char *input = new char[size+1];
  rewind(f);
  int num = fread(input, 1, size, f);
  // On Windows, ftell() gives the byte position (\r\n counts as two bytes), but when
  // reading, fread() returns the number of characters read (\r\n is read as one char \n, and counted as one),
  // so return value of fread can be less than size reported by ftell, and that is normal.
  assert((num > 0 || size == 0) && num <= size);
  fclose(f);
  input[num] = 0;

  if (debug) std::cerr << "parsing text to s-expressions...\n";
  SExpressionParser parser(input);
  Element& root = *parser.root;
  if (debug) std::cout << root << '\n';

  // A .wast may have multiple modules, with some asserts after them
  size_t i = 0;
  while (i < root.size()) {
    if (debug) std::cerr << "parsing s-expressions to wasm...\n";
    Module wasm;
    SExpressionWasmBuilder builder(wasm, *root[i]);
    i++;

    auto interface = new ShellExternalInterface();
    auto instance = new ModuleInstance(wasm, interface);

    if (print_wasm) {
      if (debug) std::cerr << "printing...\n";
      std::cout << wasm;
    }

    // run asserts
    while (i < root.size()) {
      Element& curr = *root[i];
      IString id = curr[0]->str();
      if (id == MODULE) break;
      std::cerr << curr << '\n';
      Element& invoke = *curr[1];
      assert(invoke[0]->str() == INVOKE);
      IString name = invoke[1]->str();
      ModuleInstance::LiteralList arguments;
      for (size_t j = 2; j < invoke.size(); j++) {
        Expression* argument = builder.parseExpression(*invoke[2]);
        arguments.push_back(argument->dyn_cast<Const>()->value);
      }
      bool trapped = false;
      if (setjmp(interface->trapState) == 0) {
        instance->callFunction(name, arguments);
      } else {
        trapped = true;
      }
      if (id == ASSERT_RETURN) assert(!trapped);
      if (id == ASSERT_TRAP) assert(trapped);
      i++;
    }
  }

  if (debug) std::cerr << "done.\n";
}

<commit_msg>verify return values<commit_after>
//
// A WebAssembly shell, loads a .wast file (WebAssembly in S-Expression format) and executes it.
//

#include <setjmp.h>

#include "wasm-s-parser.h"
#include "wasm-interpreter.h"

using namespace cashew;
using namespace wasm;

IString ASSERT_RETURN("assert_return"),
        ASSERT_TRAP("assert_trap"),
        PRINT("print"),
        INVOKE("invoke");

//
// Implementation of the shell interpreter execution environment
//

struct ShellExternalInterface : ModuleInstance::ExternalInterface {
  char *memory;
  size_t memorySize;

  ShellExternalInterface() : memory(nullptr) {}

  void init(Module& wasm) override {
    memory = new char[wasm.memory.initial];
    memorySize = wasm.memory.initial;
    // apply memory segments
    for (auto segment : wasm.memory.segments) {
      memcpy(memory + segment.offset, segment.data, segment.size);
    }
  }

  jmp_buf trapState;

  void trap() {
    longjmp(trapState, 1);
  }

  Literal callImport(Import *import, ModuleInstance::LiteralList& arguments) override {
    if (import->name == PRINT) {
      for (auto argument : arguments) {
        std::cout << argument << ' ';
      }
      std::cout << '\n';
      return Literal();
    }
    std::cout << "callImport " << import->name.str << "\n";
    abort();
  }

  Literal load(Load* load, Literal ptr) override {
    // ignore align - assume we are on x86 etc. which does that
    size_t addr = ptr.geti32();
    int64_t full = addr;
    full += load->offset;
    if (full + load->bytes > memorySize) trap();
    addr = full;
    switch (load->type) {
      case i32: {
        switch (load->bytes) {
          case 1: return load->signed_ ? (int32_t)((int8_t*)memory)[addr]  : (int32_t)((uint8_t*)memory)[addr];
          case 2: return load->signed_ ? (int32_t)((int16_t*)memory)[addr] : (int32_t)((uint16_t*)memory)[addr];
          case 4: return load->signed_ ? (int32_t)((int32_t*)memory)[addr] : (int32_t)((uint32_t*)memory)[addr];
          default: abort();
        }
        break;
      }
      case f32: return ((float*)memory)[addr];
      case f64: return ((double*)memory)[addr];
      default: abort();
    }
  }

  void store(Store* store, Literal ptr, Literal value) override {
    // ignore align - assume we are on x86 etc. which does that
    size_t addr = ptr.geti32();
    int64_t full = addr;
    full += store->offset;
    if (full + store->bytes > memorySize) trap();
    switch (store->type) {
      case i32: {
        switch (store->bytes) {
          case 1: ((int8_t*)memory)[addr] = value.geti32();
          case 2: ((int16_t*)memory)[addr] = value.geti32();
          case 4: ((int32_t*)memory)[addr] = value.geti32();
          default: abort();
        }
        break;
      }
      case f32: ((float*)memory)[addr] = value.getf32();
      case f64: ((double*)memory)[addr] = value.getf64();
      default: abort();
    }
  }
};

int main(int argc, char **argv) {
  debug = getenv("WASM_SHELL_DEBUG") ? getenv("WASM_SHELL_DEBUG")[0] - '0' : 0;

  char *infile = argv[1];
  bool print_wasm = argc >= 3; // second arg means print it out

  if (debug) std::cerr << "loading '" << infile << "'...\n";
  FILE *f = fopen(argv[1], "r");
  assert(f);
  fseek(f, 0, SEEK_END);
  int size = ftell(f);
  char *input = new char[size+1];
  rewind(f);
  int num = fread(input, 1, size, f);
  // On Windows, ftell() gives the byte position (\r\n counts as two bytes), but when
  // reading, fread() returns the number of characters read (\r\n is read as one char \n, and counted as one),
  // so return value of fread can be less than size reported by ftell, and that is normal.
  assert((num > 0 || size == 0) && num <= size);
  fclose(f);
  input[num] = 0;

  if (debug) std::cerr << "parsing text to s-expressions...\n";
  SExpressionParser parser(input);
  Element& root = *parser.root;
  if (debug) std::cout << root << '\n';

  // A .wast may have multiple modules, with some asserts after them
  size_t i = 0;
  while (i < root.size()) {
    if (debug) std::cerr << "parsing s-expressions to wasm...\n";
    Module wasm;
    SExpressionWasmBuilder builder(wasm, *root[i]);
    i++;

    auto interface = new ShellExternalInterface();
    auto instance = new ModuleInstance(wasm, interface);

    if (print_wasm) {
      if (debug) std::cerr << "printing...\n";
      std::cout << wasm;
    }

    // run asserts
    while (i < root.size()) {
      Element& curr = *root[i];
      IString id = curr[0]->str();
      if (id == MODULE) break;
      std::cerr << curr << '\n';
      Element& invoke = *curr[1];
      assert(invoke[0]->str() == INVOKE);
      IString name = invoke[1]->str();
      ModuleInstance::LiteralList arguments;
      for (size_t j = 2; j < invoke.size(); j++) {
        Expression* argument = builder.parseExpression(*invoke[2]);
        arguments.push_back(argument->dyn_cast<Const>()->value);
      }
      bool trapped = false;
      Literal result;
      if (setjmp(interface->trapState) == 0) {
        result = instance->callFunction(name, arguments);
      } else {
        trapped = true;
      }
      if (id == ASSERT_RETURN) {
        assert(!trapped);
        Literal expected;
        if (curr.size() >= 3) {
          expected = builder.parseExpression(*curr[2])->dyn_cast<Const>()->value;
        }
        std::cerr << "seen " << result << ", expected " << expected << '\n';
        assert(expected == result);
      }
      if (id == ASSERT_TRAP) assert(trapped);
      i++;
    }
  }

  if (debug) std::cerr << "done.\n";
}

<|endoftext|>


<commit_before>#include <string>
#include <iostream>
#include <fstream>

#include "Matrix.hpp"

Matrix::Matrix(const Matrix &matrix) : m_rows(matrix.m_rows), m_columns(matrix.m_columns)
{
    fill(matrix.m_elements);
}

Matrix::Matrix(unsigned int rows, unsigned int columns) : m_rows(rows), m_columns(columns)
{
    fill(nullptr);
}

Matrix::Matrix(unsigned int rows, unsigned int columns, int **elements) : m_rows(rows), m_columns(columns)
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
    fill(elements);
}

void Matrix::fill(int **elements)
{
    m_elements = new int *[m_columns];
    for (unsigned int i = 0; i < m_columns; ++i) {
        m_elements[i] = new int[m_rows];
        for (unsigned int j = 0; j < m_rows; ++j) {
            m_elements[i][j] = elements ? elements[i][j] : 0;
        }
    }
}

Matrix & Matrix::operator=(const Matrix &matrix)
{
    if ( this != &matrix ) {
        Matrix(matrix).swap(*this);
    }

    return *this;
}

void Matrix::swap(Matrix &matrix)
{
    std::swap(m_rows, matrix.m_rows);
    std::swap(m_columns, matrix.m_columns);
    std::swap(m_elements, matrix.m_elements);
}

Matrix::~Matrix()
{
    for (unsigned int i = 0; i < m_rows; ++i) {
        delete [] m_elements[i];
    }

    delete [] m_elements;
}

unsigned int Matrix::rows() const
{
    return m_rows;
}

unsigned int Matrix::columns() const
{
    return m_columns;
}

bool Matrix::fill(const std::string filePath)
{
    std::ifstream input;
    input.open(filePath);

    bool isSucess = true;
    if ( input.is_open() ) {
        for (unsigned int i = 0; i < m_rows; ++i) {
            for (unsigned int j = 0; j < m_columns; ++j) {
                if ( !(input >> m_elements[i][j]) ) {
                    throw "exception in fill matrix";
                }
            }
        }
    }
    else {
        isSucess = false;
    }

    input.close();

    return isSucess;
}

const int *Matrix::operator[](unsigned int index) const
{
    if ( index >= m_rows ) {
        throw std::invalid_argument("index goes abroad");
    }

    return m_elements[index];
}

Matrix Matrix::operator *(const Matrix &matrix) const
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;

    if ( m_columns != matrix.m_rows ) {
        throw std::invalid_argument("matrix sizes do not match");
    }

    unsigned int n = m_rows;
    unsigned int m = matrix.m_columns;
    unsigned int s = m_columns;

    int **elements = new int *[n];
    for (unsigned int i = 0; i < n; ++i) {
        elements[i] = new int[m];
        for (unsigned int j = 0; j < m; ++j) {
            int value = 0;
            for (unsigned int k = 0; k < s; ++k) {
                value += m_elements[i][k] * matrix.m_elements[k][j];
            }
            elements[i][j] = value;
        }
    }

    return Matrix(n, m, elements);
}

Matrix Matrix::operator +(const Matrix &matrix) const
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;

    if ( m_rows != matrix.m_rows || m_columns != matrix.m_columns ) {
        throw std::invalid_argument("matrix sizes do not match");
    }

    unsigned int n = m_rows;
    unsigned int m = m_columns;

    int **data = new int *[n];
    for (unsigned int i = 0; i < n; ++i) {
        data[i] = new int[m];
        for (unsigned int j = 0; j < m; ++j) {
            data[i][j] = m_elements[i][j] + matrix.m_elements[i][j];
        }
    }

    return Matrix(n, m, data);
}

bool Matrix::operator==(const Matrix &matrix) const
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;

    if ( m_rows != matrix.m_rows || m_columns != matrix.m_columns ) {
        return false;
    }

    for (unsigned int i = 0; i < m_rows; ++i) {
        for (unsigned int j = 0; j < m_columns; ++j) {
            if ( m_elements[i][j] != matrix.m_elements[i][j] ) {
                return false;
            }
        }
    }

    return true;
}

void Matrix::show() const
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;

    std::cout << m_rows << " * " << m_columns << std::endl;
    for (unsigned int i = 0; i < m_rows; ++i) {
        for (unsigned int j = 0; j < m_columns; ++j) {
            std::cout << m_elements[i][j] << "\t";
        }
        std::cout << std::endl;
    }
}
<commit_msg>Update Matrix.cpp<commit_after>#include <string>
#include <iostream>
#include <fstream>

#include "Matrix.hpp"

Matrix::Matrix(const Matrix &matrix) : m_rows(matrix.m_rows), m_columns(matrix.m_columns)
{
    fill(matrix.m_elements);
}

Matrix::Matrix(unsigned int rows, unsigned int columns) : m_rows(rows), m_columns(columns)
{
    fill(nullptr);
}

Matrix::Matrix(unsigned int rows, unsigned int columns, int **elements) : m_rows(rows), m_columns(columns)
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
    fill(elements);
}

void Matrix::fill(int **elements)
{
    m_elements = new int *[m_columns];
    for (unsigned int i = 0; i < m_columns; ++i) {
        m_elements[i] = new int[m_rows];
        for (unsigned int j = 0; j < m_rows; ++j) {
            m_elements[i][j] = elements ? elements[i][j] : 0;
        }
    }
}

Matrix & Matrix::operator=(const Matrix &matrix)
{
    if ( this != &matrix ) {
        Matrix(matrix).swap(*this);
    }

    return *this;
}

void Matrix::swap(Matrix &matrix)
{
    std::swap(m_rows, matrix.m_rows);
    std::swap(m_columns, matrix.m_columns);
    std::swap(m_elements, matrix.m_elements);
}

Matrix::~Matrix()
{
    for (unsigned int i = 0; i < m_rows; ++i) {
        delete [] m_elements[i];
    }

    delete [] m_elements;
}

unsigned int Matrix::rows() const
{
    return m_rows;
}

unsigned int Matrix::columns() const
{
    return m_columns;
}

bool Matrix::fill(const std::string filePath)
{
    std::ifstream input;
    input.open(filePath);

    bool isSucess = true;
    if ( input.is_open() ) {
        for (unsigned int i = 0; i < m_rows; ++i) {
            for (unsigned int j = 0; j < m_columns; ++j) {
                if ( !(input >> m_elements[i][j]) ) {
                    throw "exception in fill matrix";
                }
            }
        }
    }
    else {
        isSucess = false;
    }

    input.close();

    return isSucess;
}

const int *Matrix::operator[](unsigned int index) const
{
    if ( index >= m_rows ) {
        throw std::invalid_argument("index goes abroad");
    }

    return m_elements[index];
}

Matrix Matrix::operator *(const Matrix &matrix) const
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;

    if ( m_columns != matrix.m_rows ) {
        throw std::invalid_argument("matrix sizes do not match");
    }

    unsigned int n = m_rows;
    unsigned int m = matrix.m_columns;
    unsigned int s = m_columns;

    int **elements = new int *[n];
    for (unsigned int i = 0; i < n; ++i) {
        elements[i] = new int[m];
        for (unsigned int j = 0; j < m; ++j) {
            int value = 0;
            for (unsigned int k = 0; k < s; ++k) {
                value += m_elements[i][k] * matrix.m_elements[k][j];
            }
            elements[i][j] = value;
        }
    }

    return Matrix(n, m, elements);
}

Matrix Matrix::operator +(const Matrix &matrix) const
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;

    if ( m_rows != matrix.m_rows || m_columns != matrix.m_columns ) {
        throw std::invalid_argument("matrix sizes do not match");
    }

    unsigned int n = m_rows;
    unsigned int m = m_columns;

    int **data = new int *[n];
    for (unsigned int i = 0; i < n; ++i) {
        data[i] = new int[m];
        for (unsigned int j = 0; j < m; ++j) {
            data[i][j] = m_elements[i][j] + m_elements[i][j];
        }
    }

    return Matrix(n, m, data);
}

bool Matrix::operator==(const Matrix &matrix) const
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;

    if ( m_rows != matrix.m_rows || m_columns != matrix.m_columns ) {
        return false;
    }

    for (unsigned int i = 0; i < m_rows; ++i) {
        for (unsigned int j = 0; j < m_columns; ++j) {
            if ( m_elements[i][j] != matrix.m_elements[i][j] ) {
                return false;
            }
        }
    }

    return true;
}

void Matrix::show() const
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;

    std::cout << m_rows << " * " << m_columns << std::endl;
    for (unsigned int i = 0; i < m_rows; ++i) {
        for (unsigned int j = 0; j < m_columns; ++j) {
            std::cout << m_elements[i][j] << "\t";
        }
        std::cout << std::endl;
    }
}
<|endoftext|>


<commit_before><commit_msg>Fixed a small bug where if no linear solver packages were defined, there was a compilation error.  This was due to auto_ptr.h not being included properly in that case.<commit_after><|endoftext|>


<commit_before><commit_msg>Fix bug in Windows.<commit_after><|endoftext|>