<commit_before>///
/// anax
/// An open source C++ entity system.
///
/// Copyright (C) 2013 Miguel Martin (miguel.martin7.5@hotmail.com)
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
/// copies of the Software, and to permit persons to whom the Software is
/// furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in
/// all copies or substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
/// THE SOFTWARE.
///

#ifndef __ANAX_ENTITY_HPP__
#define __ANAX_ENTITY_HPP__

#include <type_traits>
#include <cstdint>

#include <anax/detail/ClassTypeId.hpp>

#include <anax/config.hpp>
#include <anax/Component.hpp>
#include <anax/ComponentTypeList.hpp>

namespace anax
{
    class World;

    /// \brief A handle to an Entity within a World
    ///
    /// This class is used as a handle to an entity within a world.
    /// The handle can be invalid, as it "handle" no entity at all.
    ///
    /// \todo
    /// Benchmark this against a plain old 64-bit Id (as in just use
    /// the ID class)
    ///
    /// \author Miguel Martin
    class Entity
    {
    public:

        /// \brief A class to describe an ID for an entity
        ///
        /// An ID for entity is composed of two values:
        /// - an index variable
        /// - a counter variable
        ///
        /// The index variable is used to locate components/location
        /// in the entity ID pool. The counter variable is used to
        /// determine if this ID is valid, and has not been killed.
        ///
        /// \author Miguel Martin
        struct Id
        {
            typedef

#   ifdef ANAX_32_BIT_ENTITY_IDS
            std::uint32_t
#   else
            std::uint64_t
#   endif // ANAX_32_BIT_ENTITY_IDS

            int_type;

            /// Default constructor
            /// \note
            /// This constructor will automatically nullify the ID
            Id()
                : index(0),
                  counter(0)
            {
            }

            /// Sets the index and counter variables of the ID
            /// \param Index The value for the index you wish to set
            /// \param Counter The value for the counter you wish to set
            Id(int_type Index, int_type Counter)
                : index(Index),
                  counter(Counter)
            {
            }

            /// \return The value of the ID, as an integer
            inline operator int_type() const
            { return value(); }

            /// \return The value of the ID, as an integer
            inline int_type value() const
            { return (counter << ANAX_ENTITY_ID_COUNTER_BIT_COUNT) | index; }

            /// Clears the ID by setting the index and counter to 0.
            void clear() { index = counter = 0; }

            /// Determines if the ID is null
            /// \return true if the ID is null
            bool isNull() const { return value() == 0; }

            int_type index : ANAX_ENTITY_ID_INDEX_BIT_COUNT;
            int_type counter : ANAX_ENTITY_ID_COUNTER_BIT_COUNT;
        };

        /// Default constructor
        Entity();

        /// \param world The World the entity belongs to
        /// \param id The designated ID of the Entity
        /// \note You should not call this ctor
        Entity(World& world, Id id);

        /// Default copy/move ctors and assignment operators
        Entity(const Entity&) = default;
        Entity(Entity&&) = default;
        Entity& operator=(const Entity&) = default;
        Entity& operator=(Entity&&) = default;

        /// Determines if this Entity handle is valid & able to be used.
        /// \note You should only use this for DEBUG builds
        ///       as checking if an Entity is valid may/may not
        ///       impact your performance.
        /// \return true if this Entity is valid, false otherwise
        bool isValid() const;

        /// \return The Entity's ID
        const Id& getId() const;

        /// \return The World that the Entity belongs to.
        /// \note This function will fail if the Entity is null.
        /// \see isNull() To check whether the Entity is null.
        World& getWorld() const;

        /// \return true if this Entity is activated
        bool isActivated() const;

        /// Activates this Entity
        void activate();

        /// Deactivates this Entity
        void deactivate();

        /// Kills this Entity
        /// \see World::killEntity for an alternate way to kill an Entity
        void kill();

        /// Adds a component
        /// \param component The component you wish to add
        /// \note component must be dynamically allocated with new, as
        /// it is stored as a unique_ptr. I may change this in the future
        /// by adding an option to alter how it's stored or something
        /// along those lines.
        //void addComponent(BaseComponent* component);

        /// Adds a component to the Entity
        /// \tparam The type of component you wish to add
        /// \param component The component you wish to add
        /// \note component must be dynamically allocated with new, as
        /// it is stored as a unique_ptr. I may change this in the future
        /// by adding an option to alter how it's stored or something
        /// along those lines.
        /// \return The entity you added
        template <typename T>
        T& addComponent(T* component);

#ifdef ANAX_USE_VARIADIC_TEMPLATES

        /// Adds a component to the Entity
        /// \tparam The type of component you wish to add
        /// \param args The arguments for the constructor of the component
        template <typename T, typename... Args>
        T& addComponent(Args&&... args);

#endif // ANAX_USE_VARIADIC_TEMPLATES

        /// Removes a component
        /// \tparam The type of component you wish to remove
        template <typename T>
        void removeComponent();

        /// Removes all the components attached to the Entity
        void removeAllComponents();

        /// Retrives a component from this Entity
        /// \tparam The type of component you wish to retrieve
        /// \return A pointer to the component
        template <typename T>
        T& getComponent() const;

        /// Determines if this Entity has a component or not
        /// \tparam The type of component you wish to check for
        /// \return true if this Entity contains a component
        template <typename T>
        bool hasComponent() const;

        /// \return All the components the Entity has
        ComponentArray getComponents() const;

        /// \return A component type list, which resembles the components
        /// this entity has attached to it
        ComponentTypeList getComponentTypeList() const;

        /// Comparrision operator
        bool operator==(const Entity& entity) const;
        bool operator!=(const Entity& entity) const { return !operator==(entity); }

    private:

        // wrappers to add components
        // so I may call them from templated public interfaces
        void addComponent(BaseComponent* component, detail::TypeId componentTypeId);
        void removeComponent(detail::TypeId componentTypeId);
        BaseComponent& getComponent(detail::TypeId componentTypeId) const;
        bool hasComponent(detail::TypeId componentTypeId) const;

        /// The ID of the Entity
        Id _id;

        /// The world that this Entity belongs to. This is guarenteed
        /// to not be null, as long as this entity is not null.
        /// \see isNull() To determine if the entity is null or not.
        World* _world;

        //friend class World;
    };

    template <typename T>
    T& Entity::addComponent(T* component)
    {
        static_assert(std::is_base_of<BaseComponent, T>(), "T is not a component, cannot add T to entity");
        addComponent(component, T::GetTypeId());
        return *component;
    }

#ifdef ANAX_USE_VARIADIC_TEMPLATES

<<<<<<< HEAD
    template <typename T, typename... Args>
    T& Entity::addComponent(Args&&... args)
    {
        return addComponent<T>(new T{args...});
    }

=======
	template <typename T, typename... Args>
	T& Entity::addComponent(Args&&... args)
	{
		return addComponent<T>(new T{std::forward<Args>(args)...});
	}

>>>>>>> 6f961930803599b5942ee5f4bf9b6c8a5f61ea34
#endif // ANAX_USE_VARIADIC_TEMPLATES

    template <typename T>
    void Entity::removeComponent()
    {
        static_assert(std::is_base_of<BaseComponent, T>(), "T is not a component, cannot remove T from entity");
        removeComponent(T::GetTypeId());
    }

    template <typename T>
    T& Entity::getComponent() const
    {
        static_assert(std::is_base_of<BaseComponent, T>(), "T is not a component, cannot retrieve T from entity");
        return static_cast<T&>(getComponent(T::GetTypeId()));
    }

    template <typename T>
    bool Entity::hasComponent() const
    {
        static_assert(std::is_base_of<BaseComponent, T>(), "T is not a component, cannot determine if entity has T");
        return hasComponent(T::GetTypeId());
    }
}

#endif // __ANAX_ENTITY_HPP__
<commit_msg>Fixed compilation errors within Entity.hpp Forgot to remove when merging<commit_after>///
/// anax
/// An open source C++ entity system.
///
/// Copyright (C) 2013 Miguel Martin (miguel.martin7.5@hotmail.com)
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
/// copies of the Software, and to permit persons to whom the Software is
/// furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in
/// all copies or substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
/// THE SOFTWARE.
///

#ifndef __ANAX_ENTITY_HPP__
#define __ANAX_ENTITY_HPP__

#include <type_traits>
#include <cstdint>

#include <anax/detail/ClassTypeId.hpp>

#include <anax/config.hpp>
#include <anax/Component.hpp>
#include <anax/ComponentTypeList.hpp>

namespace anax
{
    class World;

    /// \brief A handle to an Entity within a World
    ///
    /// This class is used as a handle to an entity within a world.
    /// The handle can be invalid, as it "handle" no entity at all.
    ///
    /// \todo
    /// Benchmark this against a plain old 64-bit Id (as in just use
    /// the ID class)
    ///
    /// \author Miguel Martin
    class Entity
    {
    public:

        /// \brief A class to describe an ID for an entity
        ///
        /// An ID for entity is composed of two values:
        /// - an index variable
        /// - a counter variable
        ///
        /// The index variable is used to locate components/location
        /// in the entity ID pool. The counter variable is used to
        /// determine if this ID is valid, and has not been killed.
        ///
        /// \author Miguel Martin
        struct Id
        {
            typedef

#   ifdef ANAX_32_BIT_ENTITY_IDS
            std::uint32_t
#   else
            std::uint64_t
#   endif // ANAX_32_BIT_ENTITY_IDS

            int_type;

            /// Default constructor
            /// \note
            /// This constructor will automatically nullify the ID
            Id()
                : index(0),
                  counter(0)
            {
            }

            /// Sets the index and counter variables of the ID
            /// \param Index The value for the index you wish to set
            /// \param Counter The value for the counter you wish to set
            Id(int_type Index, int_type Counter)
                : index(Index),
                  counter(Counter)
            {
            }

            /// \return The value of the ID, as an integer
            inline operator int_type() const
            { return value(); }

            /// \return The value of the ID, as an integer
            inline int_type value() const
            { return (counter << ANAX_ENTITY_ID_COUNTER_BIT_COUNT) | index; }

            /// Clears the ID by setting the index and counter to 0.
            void clear() { index = counter = 0; }

            /// Determines if the ID is null
            /// \return true if the ID is null
            bool isNull() const { return value() == 0; }

            int_type index : ANAX_ENTITY_ID_INDEX_BIT_COUNT;
            int_type counter : ANAX_ENTITY_ID_COUNTER_BIT_COUNT;
        };

        /// Default constructor
        Entity();

        /// \param world The World the entity belongs to
        /// \param id The designated ID of the Entity
        /// \note You should not call this ctor
        Entity(World& world, Id id);

        /// Default copy/move ctors and assignment operators
        Entity(const Entity&) = default;
        Entity(Entity&&) = default;
        Entity& operator=(const Entity&) = default;
        Entity& operator=(Entity&&) = default;

        /// Determines if this Entity handle is valid & able to be used.
        /// \note You should only use this for DEBUG builds
        ///       as checking if an Entity is valid may/may not
        ///       impact your performance.
        /// \return true if this Entity is valid, false otherwise
        bool isValid() const;

        /// \return The Entity's ID
        const Id& getId() const;

        /// \return The World that the Entity belongs to.
        /// \note This function will fail if the Entity is null.
        /// \see isNull() To check whether the Entity is null.
        World& getWorld() const;

        /// \return true if this Entity is activated
        bool isActivated() const;

        /// Activates this Entity
        void activate();

        /// Deactivates this Entity
        void deactivate();

        /// Kills this Entity
        /// \see World::killEntity for an alternate way to kill an Entity
        void kill();

        /// Adds a component
        /// \param component The component you wish to add
        /// \note component must be dynamically allocated with new, as
        /// it is stored as a unique_ptr. I may change this in the future
        /// by adding an option to alter how it's stored or something
        /// along those lines.
        //void addComponent(BaseComponent* component);

        /// Adds a component to the Entity
        /// \tparam The type of component you wish to add
        /// \param component The component you wish to add
        /// \note component must be dynamically allocated with new, as
        /// it is stored as a unique_ptr. I may change this in the future
        /// by adding an option to alter how it's stored or something
        /// along those lines.
        /// \return The entity you added
        template <typename T>
        T& addComponent(T* component);

#ifdef ANAX_USE_VARIADIC_TEMPLATES

        /// Adds a component to the Entity
        /// \tparam The type of component you wish to add
        /// \param args The arguments for the constructor of the component
        template <typename T, typename... Args>
        T& addComponent(Args&&... args);

#endif // ANAX_USE_VARIADIC_TEMPLATES

        /// Removes a component
        /// \tparam The type of component you wish to remove
        template <typename T>
        void removeComponent();

        /// Removes all the components attached to the Entity
        void removeAllComponents();

        /// Retrives a component from this Entity
        /// \tparam The type of component you wish to retrieve
        /// \return A pointer to the component
        template <typename T>
        T& getComponent() const;

        /// Determines if this Entity has a component or not
        /// \tparam The type of component you wish to check for
        /// \return true if this Entity contains a component
        template <typename T>
        bool hasComponent() const;

        /// \return All the components the Entity has
        ComponentArray getComponents() const;

        /// \return A component type list, which resembles the components
        /// this entity has attached to it
        ComponentTypeList getComponentTypeList() const;

        /// Comparrision operator
        bool operator==(const Entity& entity) const;
        bool operator!=(const Entity& entity) const { return !operator==(entity); }

    private:

        // wrappers to add components
        // so I may call them from templated public interfaces
        void addComponent(BaseComponent* component, detail::TypeId componentTypeId);
        void removeComponent(detail::TypeId componentTypeId);
        BaseComponent& getComponent(detail::TypeId componentTypeId) const;
        bool hasComponent(detail::TypeId componentTypeId) const;

        /// The ID of the Entity
        Id _id;

        /// The world that this Entity belongs to. This is guarenteed
        /// to not be null, as long as this entity is not null.
        /// \see isNull() To determine if the entity is null or not.
        World* _world;

        //friend class World;
    };

    template <typename T>
    T& Entity::addComponent(T* component)
    {
        static_assert(std::is_base_of<BaseComponent, T>(), "T is not a component, cannot add T to entity");
        addComponent(component, T::GetTypeId());
        return *component;
    }

#ifdef ANAX_USE_VARIADIC_TEMPLATES

	template <typename T, typename... Args>
	T& Entity::addComponent(Args&&... args)
	{
		return addComponent<T>(new T{std::forward<Args>(args)...});
	}

#endif // ANAX_USE_VARIADIC_TEMPLATES

    template <typename T>
    void Entity::removeComponent()
    {
        static_assert(std::is_base_of<BaseComponent, T>(), "T is not a component, cannot remove T from entity");
        removeComponent(T::GetTypeId());
    }

    template <typename T>
    T& Entity::getComponent() const
    {
        static_assert(std::is_base_of<BaseComponent, T>(), "T is not a component, cannot retrieve T from entity");
        return static_cast<T&>(getComponent(T::GetTypeId()));
    }

    template <typename T>
    bool Entity::hasComponent() const
    {
        static_assert(std::is_base_of<BaseComponent, T>(), "T is not a component, cannot determine if entity has T");
        return hasComponent(T::GetTypeId());
    }
}

#endif // __ANAX_ENTITY_HPP__
<|endoftext|>


<commit_before>#ifdef  CLPP_KERNEL_IPP
	#error "multiple inclusions of the same implementation file"
#else
#define CLPP_KERNEL_IPP

#ifndef CLPP_KERNEL_HPP
	#error "header file has not been included; maybe it isn't required anymore?"
	#include "clpp/kernel.hpp"
#endif

#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

#include "clpp/local_memory.hpp"

namespace cl {
	auto Kernel::operator=(Kernel const& rhs) -> Kernel & {
		if (this != &rhs) {
		    detail::Object<cl_type>::operator=(rhs);
		}
		return *this;
	}

	namespace detail {
		template<typename V>
		struct SetArgImpl final {
			static auto setArg(Kernel const& kernel, cl_uint index, V&& arg) {
				return clSetKernelArg(
					kernel.get(), index, sizeof(V), std::addressof(std::forward<V>(arg)));
			}
		};

		template<typename V>
		struct SetArgImpl<LocalMemory<V>> final {
			static auto setArg(Kernel const& kernel, cl_uint index, LocalMemory<V> const& arg) {
				return clSetKernelArg(kernel.get(), index, arg.getSizeInBytes(), nullptr);
			}
		};
	}

	template<typename T>
	void Kernel::setArg(cl_uint index, T&& arg) const {
		const auto error = detail::SetArgImpl<T>::setArg(*this, index, arg);
		detail::handleError(detail::CLFunction::clSetKernelArg(), error);
	}

	template<typename T>
	void Kernel::setArgsHelper(cl_uint index, T&& head) const {
		setArg(index, std::forward<T>(head));
	}

	template<typename T, typename... Args>
	void Kernel::setArgsHelper(cl_uint index, T&& head, Args&&... tail) const {
		setArg(index, std::forward<T>(head));
		setArgsHelper(index + 1, std::forward<Args>(tail)...);
	}

	template<typename... Args>
	void Kernel::setArgs(Args&&... tail) const {
		setArgsHelper(0, std::forward<Args>(tail)...);
	}

//	auto Kernel::getArg(cl_uint index) const -> KernelArg {
//		// TODO
//	}

//	auto Kernel::getWorkGroup(Device const& device) const -> KernelWorkGroup {
//		// TODO
//	}

	auto Kernel::getFunctionName() const -> std::string {
		return getInfoString(CL_KERNEL_FUNCTION_NAME);
	}

	auto Kernel::getNumArgs() const -> cl_uint {
		return getInfo<cl_uint>(CL_KERNEL_NUM_ARGS);
	}

	auto Kernel::getReferenceCount() const -> cl_uint {
		return getInfo<cl_uint>(CL_KERNEL_REFERENCE_COUNT);
	}

	auto Kernel::getContext() const -> std::unique_ptr<Context> {
		return std::make_unique<Context>(
			getInfo<cl_context>(CL_KERNEL_CONTEXT));
	}

	auto Kernel::getProgram() const -> std::unique_ptr<Program> {
		return std::make_unique<Program>(
			getInfo<cl_program>(CL_KERNEL_PROGRAM));
	}

	auto Kernel::getAttributes() const -> std::vector<std::string> {
			  auto attributes = std::vector<std::string>{};
		const auto attrStr    = getInfoString(CL_KERNEL_ATTRIBUTES);
		boost::split(attributes, attrStr, boost::is_any_of("\t "), boost::token_compress_on);
		return attributes;
	}
}

#endif
<commit_msg>extended Kernel::setArg() function to work with dynamic local memory. #3<commit_after>#ifdef  CLPP_KERNEL_IPP
	#error "multiple inclusions of the same implementation file"
#else
#define CLPP_KERNEL_IPP

#ifndef CLPP_KERNEL_HPP
	#error "header file has not been included; maybe it isn't required anymore?"
	#include "clpp/kernel.hpp"
#endif

#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

#include "clpp/local_memory.hpp"

namespace cl {
	auto Kernel::operator=(Kernel const& rhs) -> Kernel & {
		if (this != &rhs) {
		    detail::Object<cl_type>::operator=(rhs);
		}
		return *this;
	}

	namespace detail {
		template<typename V>
		struct SetArgImpl final {
			static inline auto setArg(Kernel const& kernel, cl_uint index, V&& arg) {
				return clSetKernelArg(
					kernel.get(), index, sizeof(V), std::addressof(std::forward<V>(arg)));
			}
		};

		template<typename V>
		struct SetArgImpl<LocalMemory<V>> final {
			static inline auto setArg(Kernel const& kernel, cl_uint index, LocalMemory<V> const& arg) {
				return clSetKernelArg(kernel.get(), index, arg.getSizeInBytes(), nullptr);
			}
		};
	}

	template<typename T>
	void Kernel::setArg(cl_uint index, T&& arg) const {
		const auto error = detail::SetArgImpl<T>::setArg(*this, index, arg);
		detail::handleError(detail::CLFunction::clSetKernelArg(), error);
	}

	template<typename T>
	void Kernel::setArgsHelper(cl_uint index, T&& head) const {
		setArg(index, std::forward<T>(head));
	}

	template<typename T, typename... Args>
	void Kernel::setArgsHelper(cl_uint index, T&& head, Args&&... tail) const {
		setArg(index, std::forward<T>(head));
		setArgsHelper(index + 1, std::forward<Args>(tail)...);
	}

	template<typename... Args>
	void Kernel::setArgs(Args&&... tail) const {
		setArgsHelper(0, std::forward<Args>(tail)...);
	}

//	auto Kernel::getArg(cl_uint index) const -> KernelArg {
//		// TODO
//	}

//	auto Kernel::getWorkGroup(Device const& device) const -> KernelWorkGroup {
//		// TODO
//	}

	auto Kernel::getFunctionName() const -> std::string {
		return getInfoString(CL_KERNEL_FUNCTION_NAME);
	}

	auto Kernel::getNumArgs() const -> cl_uint {
		return getInfo<cl_uint>(CL_KERNEL_NUM_ARGS);
	}

	auto Kernel::getReferenceCount() const -> cl_uint {
		return getInfo<cl_uint>(CL_KERNEL_REFERENCE_COUNT);
	}

	auto Kernel::getContext() const -> std::unique_ptr<Context> {
		return std::make_unique<Context>(
			getInfo<cl_context>(CL_KERNEL_CONTEXT));
	}

	auto Kernel::getProgram() const -> std::unique_ptr<Program> {
		return std::make_unique<Program>(
			getInfo<cl_program>(CL_KERNEL_PROGRAM));
	}

	auto Kernel::getAttributes() const -> std::vector<std::string> {
			  auto attributes = std::vector<std::string>{};
		const auto attrStr    = getInfoString(CL_KERNEL_ATTRIBUTES);
		boost::split(attributes, attrStr, boost::is_any_of("\t "), boost::token_compress_on);
		return attributes;
	}
}

#endif
<|endoftext|>


<commit_before>#ifndef _COTL_STDLIB_HPP
#define _COTL_STDLIB_HPP

#include <cstdlib>
#include <cstddef>
#include <cstdarg>

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

#include <iostream>

#endif
<commit_msg>add assert header<commit_after>#ifndef _COTL_STDLIB_HPP
#define _COTL_STDLIB_HPP

#define NDEBUG
#include <cassert>

#include <cstdlib>
#include <cstddef>
#include <cstdarg>

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

#include <iostream>

#endif
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef DLL_CONTEXT_HPP
#define DLL_CONTEXT_HPP

namespace dll {

template<template<typename> class Context, typename T>
struct context_builder;

template<template<typename> class Context, typename... Args>
struct context_builder<Context, std::tuple<Args...>> {
    using type = std::tuple<Context<Args>...>;
};

template<template<typename...> class Context, typename DBN, typename T>
struct dbn_context_builder;

template<template<typename...> class Context, typename DBN, typename... Args>
struct dbn_context_builder<Context, DBN, std::tuple<Args...>> {
    using type = std::tuple<Context<DBN, Args>...>;
};

} //end of dll namespace

#endif
<commit_msg>New builder with indexes<commit_after>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef DLL_CONTEXT_HPP
#define DLL_CONTEXT_HPP

namespace dll {

template<template<typename> class Context, typename T>
struct context_builder;

template<template<typename> class Context, typename... Args>
struct context_builder<Context, std::tuple<Args...>> {
    using type = std::tuple<Context<Args>...>;
};

template<template<typename...> class Context, typename DBN, typename T>
struct dbn_context_builder;

template<template<typename...> class Context, typename DBN, typename... Args>
struct dbn_context_builder<Context, DBN, std::tuple<Args...>> {
    using type = std::tuple<Context<DBN, Args>...>;
};

template<template<typename, std::size_t, typename...> class Context, typename DBN, typename T>
struct dbn_context_builder_i_impl;

template<template<typename, std::size_t, typename...> class Context, typename DBN, std::size_t... I>
struct dbn_context_builder_i_impl <Context, DBN, std::index_sequence<I...>> {
    using type = std::tuple<Context<DBN, I>...>;
};

template<template<typename, std::size_t, typename...> class Context, typename DBN>
struct dbn_context_builder_i {
    using type = typename dbn_context_builder_i_impl<Context, DBN, std::make_index_sequence<DBN::layers>>::type;
};

} //end of dll namespace

#endif
<|endoftext|>


<commit_before>#ifdef WIN32
#define UNICODE
#define _UNICODE

#include "win32bindings.h"
#include "javasigar.h"

#ifdef __cplusplus
extern "C" {
#endif

#define STRING_SIG "Ljava/lang/String;"

#define SERVICE_SetStringField(field, str) \
    id = env->GetFieldID(cls, field, STRING_SIG); \
    value = env->NewString((const jchar *)str, lstrlen(str)); \
    env->SetObjectField(obj, id, value)

#define SERVICE_SetIntField(field, val) \
    id = env->GetFieldID(cls, field, "I"); \
    env->SetIntField(obj, id, val)

/**
 * This code is stolen from misc/win32/misc.c and apr_private.h
 * This helper code resolves late bound entry points
 * missing from one or more releases of the Win32 API...
 * This is covered under the Apache Software License
 *
 * ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2003 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 "Apache" 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.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * Portions of this software are based upon public domain software
 * originally written at the National Center for Supercomputing Applications,
 * University of Illinois, Urbana-Champaign.
 */

typedef enum {
    DLL_WINBASEAPI = 0,    // kernel32 From WinBase.h
    DLL_WINADVAPI = 1,     // advapi32 From WinBase.h
    DLL_WINSOCKAPI = 2,    // mswsock  From WinSock.h
    DLL_WINSOCK2API = 3,   // ws2_32   From WinSock2.h
    DLL_SHSTDAPI = 4,      // shell32  From ShellAPI.h
    DLL_NTDLL = 5,         // shell32  From our real kernel
    DLL_defined = 6        // must define as last idx_ + 1
} dlltoken_e;

FARPROC load_dll_func(dlltoken_e fnLib, TCHAR* fnName, int ordinal);

#define DECLARE_LATE_DLL_FUNC(lib, rettype, calltype, fn, ord, args, names) \
typedef rettype (calltype *winapi_fpt_##fn) args; \
static winapi_fpt_##fn winapi_pfn_##fn = NULL; \
__inline rettype winapi_##fn args \
{ if (!winapi_pfn_##fn) \
winapi_pfn_##fn = (winapi_fpt_##fn) load_dll_func(lib, (wchar_t *)#fn, ord); \
return (*(winapi_pfn_##fn)) names; }; \

/* Win2K kernel only */
DECLARE_LATE_DLL_FUNC(DLL_WINADVAPI, BOOL, WINAPI,
                      ChangeServiceConfig2W, 0,
                      (SC_HANDLE hService,
                       DWORD dwInfoLevel,
                       LPVOID lpInfo),
                      (hService, dwInfoLevel, lpInfo));
#undef ChangeServiceConfig2
#define ChangeServiceConfig2 winapi_ChangeServiceConfig2W

/* End Apache licensed code */

static TCHAR* lateDllName[] = {
    L"kernel32", L"advapi32", L"mswsock", L"ws2_32"  };
static HMODULE lateDllHandle[] = {
    NULL, NULL, NULL, NULL };

FARPROC load_dll_func(dlltoken_e fnLib, TCHAR* fnName, int ordinal)
{
    if (!lateDllHandle[fnLib]) {
        lateDllHandle[fnLib] = LoadLibrary(lateDllName[fnLib]);
        if (!lateDllHandle[fnLib]) {
            DWORD err = GetLastError();
            fprintf(stderr, "GetLastError():   %d  %s\r\n",
                    err, lateDllName[fnLib]);
            return NULL;
        }
    }
    if (ordinal)
        return GetProcAddress(lateDllHandle[fnLib], (char *)ordinal);
    else
        return GetProcAddress(lateDllHandle[fnLib], (char *)fnName);
}

/*End ASF licensed code */

JNIEXPORT jboolean SIGAR_JNI(win32_Service_ChangeServiceDescription)
(JNIEnv *env, jclass, jlong handle, jstring description)
{
    jboolean            bResult = TRUE;
    SERVICE_DESCRIPTION servdesc;

    OSVERSIONINFO osver; /* VER_PLATFORM_WIN32_NT */
    osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    GetVersionEx(&osver);

    if ((osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
          && (osver.dwMajorVersion > 4)
          && (ChangeServiceConfig2 != NULL)) {
        servdesc.lpDescription = (LPTSTR)env->GetStringChars(description,
                                                             NULL);
        bResult = ChangeServiceConfig2((SC_HANDLE)handle,
                                       SERVICE_CONFIG_DESCRIPTION, &servdesc);
        env->ReleaseStringChars(description,
                                (const jchar *)servdesc.lpDescription);
    }
    return bResult;
}

JNIEXPORT jboolean SIGAR_JNI(win32_Service_CloseServiceHandle)
(JNIEnv *, jclass, jlong handle)
{
    return CloseServiceHandle((SC_HANDLE)handle);
}

JNIEXPORT jboolean SIGAR_JNI(win32_Service_ControlService)
(JNIEnv *, jclass, jlong handle, jint control)
{
    SERVICE_STATUS  status;
    return ControlService((SC_HANDLE)handle, control, &status);
}

JNIEXPORT jlong SIGAR_JNI(win32_Service_CreateService)
(JNIEnv *env,
 jclass,
 jlong handle,
 jstring serviceName,
 jstring displayName,
 jint serviceType,
 jint startType,
 jint errorControl,
 jstring path,
 jobjectArray dependencies,
 jstring startName,
 jstring password)
{
    TCHAR   szBuf[4048];
    LPCTSTR lpDepend = NULL;
    jlong   lResult;
    LPCTSTR lpStartName;

    LPCTSTR lpServiceName = (LPCTSTR)env->GetStringChars(serviceName, NULL);
    LPCTSTR lpDisplayName = (LPCTSTR)env->GetStringChars(displayName, NULL);
    LPCTSTR lpPath        = (LPCTSTR)env->GetStringChars(path, NULL);
    LPCTSTR lpPassword    = (LPCTSTR)env->GetStringChars(password, NULL);

    if(startName != NULL)
        lpStartName = (LPCTSTR)env->GetStringChars(path, NULL);
    else
        lpStartName = NULL;

    if(dependencies != NULL)
    {
        // Build a buffer of a double null terminated array of
        // null terminated service names
        lpDepend             = szBuf;

        LPTSTR  lpBuf = szBuf;
        size_t  cbLen = 0;
        jsize   cSize = env->GetArrayLength(dependencies);

        for(int i = 0;i < cSize;i ++)
        {
            jstring str = (jstring)env->GetObjectArrayElement(dependencies, i);

            LPCTSTR lpStr = (LPCTSTR)env->GetStringChars(str, NULL);
            cbLen         = lstrlen(lpStr);

            // If we're going to overrun the buffer then break out of the loop
            if((lpBuf + cbLen + 1) >= (szBuf + sizeof(szBuf) / sizeof(TCHAR)))
                break;

            lstrcpy(lpBuf, lpStr);
            env->ReleaseStringChars(str, (const jchar *)lpStr);

            // Move the buffer to the byte beyond the current string
            // null terminator
            lpBuf = lpBuf + cbLen + 1;
        }

        *lpBuf = 0;  // Double null terminate the string
    }

    // Create the Service
    lResult = (jlong)CreateService((SC_HANDLE)handle, lpServiceName,
                                   lpDisplayName, SERVICE_ALL_ACCESS,
                                   serviceType,
                                   startType, errorControl, lpPath,
                                   NULL, NULL, lpDepend, lpStartName,
                                   lpPassword);

    if(lpStartName != NULL)
        env->ReleaseStringChars(path, (const jchar *)lpStartName);

    env->ReleaseStringChars(password, (const jchar *)lpPassword);
    env->ReleaseStringChars(path, (const jchar *)lpPath);
    env->ReleaseStringChars(displayName, (const jchar *)lpDisplayName);
    env->ReleaseStringChars(serviceName, (const jchar *)lpServiceName);

    return lResult;
}

JNIEXPORT jboolean SIGAR_JNI(win32_Service_DeleteService)
(JNIEnv *env, jclass, jlong handle)
{
    return DeleteService((SC_HANDLE)handle);
}

JNIEXPORT jlong SIGAR_JNI(win32_Service_OpenSCManager)
(JNIEnv *env, jclass, jstring machine, jint access)
{
    jlong   lResult;

    LPCTSTR lpMachine  = (LPCTSTR)env->GetStringChars(machine, NULL);
    lResult            = (jlong)OpenSCManager(lpMachine, NULL, access);
    env->ReleaseStringChars(machine, (const jchar *)lpMachine);

    return lResult;
}

JNIEXPORT jlong SIGAR_JNI(win32_Service_OpenService)
(JNIEnv *env,
 jclass,
 jlong handle,
 jstring service,
 jint access)
{
    jlong   lResult;

    LPCTSTR lpService = (LPCTSTR)env->GetStringChars(service, NULL);
    lResult           = (jlong)OpenService((SC_HANDLE)handle,
                                           lpService, access);
    env->ReleaseStringChars(service, (const jchar *)lpService);

    return lResult;
}

JNIEXPORT jint
SIGAR_JNI(win32_Service_QueryServiceStatus)
(JNIEnv *, jclass, jlong handle)
{
    SERVICE_STATUS status;
    int            iResult;

    if(QueryServiceStatus((SC_HANDLE)handle, &status) == TRUE) {
        iResult = status.dwCurrentState;
    } else
        iResult = -1;

    return iResult;
}

JNIEXPORT jboolean SIGAR_JNI(win32_Service_StartService)
(JNIEnv *, jclass, jlong handle)
{
    return StartService((SC_HANDLE)handle, 0, NULL);
}

JNIEXPORT jboolean SIGAR_JNI(win32_Service_StopService)
(JNIEnv *, jclass, jlong handle)
{
    SERVICE_STATUS  status;

    return ControlService((SC_HANDLE)handle, SERVICE_CONTROL_STOP, &status);
}

JNIEXPORT jobject SIGAR_JNI(win32_Service_getServiceNames)
(JNIEnv *env, jclass)
{
    SC_HANDLE handle =
        OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
    ENUM_SERVICE_STATUS status, *services;
    BOOL retval;
    DWORD bytes, count, resume=0;
    DWORD type = SERVICE_WIN32, state = SERVICE_STATE_ALL;
    jobject listobj;
    jclass listclass =
        env->FindClass("java/util/ArrayList");
    jmethodID listid =
        env->GetMethodID(listclass, "<init>", "()V");
    jmethodID addid =
        env->GetMethodID(listclass, "add",
                         "(Ljava/lang/Object;)"
                         "Z");

    if (handle == NULL) {
        return NULL;
    }

    retval = EnumServicesStatus(handle, type, state,
                                &status, sizeof(status),
                                &bytes, &count, &resume);

    DWORD err = GetLastError();

    if ((retval == FALSE) || err == ERROR_MORE_DATA) {
        DWORD size = bytes + sizeof(ENUM_SERVICE_STATUS);
        services = new ENUM_SERVICE_STATUS[size];
        EnumServicesStatus(handle, type, state, services,
                           size, &bytes, &count, &resume);
    }

    listobj = env->NewObject(listclass, listid);
    for (int i=0; i<count; i++) {
        jstring name =
            env->NewString((const jchar *)services[i].lpServiceName,
                           lstrlen(services[i].lpServiceName));
        env->CallBooleanMethod(listobj, addid, name);
    }

    CloseServiceHandle(handle);
    delete services;

    return listobj;
}

JNIEXPORT jboolean SIGAR_JNI(win32_Service_QueryServiceConfig)
(JNIEnv *env, jclass, jlong handle, jobject obj)
{
    char buffer[8096]; /* 8k is max size from mdsn docs */
    LPQUERY_SERVICE_CONFIG config = (LPQUERY_SERVICE_CONFIG)buffer;
    DWORD bytes;
    jfieldID id;
    jclass cls = env->GetObjectClass(obj);
    jstring value;

    if (!QueryServiceConfig((SC_HANDLE)handle, config,
                            sizeof(buffer), &bytes))
    {
        return JNI_FALSE;
    }

    SERVICE_SetIntField("type", config->dwServiceType);

    SERVICE_SetIntField("startType", config->dwStartType);

    SERVICE_SetIntField("errorControl", config->dwErrorControl);

    SERVICE_SetStringField("binaryPathName", config->lpBinaryPathName);

    SERVICE_SetStringField("loadOrderGroup", config->lpLoadOrderGroup);

    SERVICE_SetIntField("tagId", config->dwTagId);

    SERVICE_SetStringField("dependencies", config->lpDependencies);

    SERVICE_SetStringField("serviceStartName", config->lpServiceStartName);

    SERVICE_SetStringField("displayName", config->lpDisplayName);

    return JNI_TRUE;
}

#ifdef __cplusplus
}
#endif
#endif /* WIN32 */
<commit_msg>remove dll late binding code from asf.  not only is it super ugly, it is not thread safe.  change to use GetProcAddress the same way everyone else in the world does.  (M-x un-bloom-ify)<commit_after>#ifdef WIN32
#define UNICODE
#define _UNICODE

#include "win32bindings.h"
#include "javasigar.h"

#ifdef __cplusplus
extern "C" {
#endif

#define STRING_SIG "Ljava/lang/String;"

#define SERVICE_SetStringField(field, str) \
    id = env->GetFieldID(cls, field, STRING_SIG); \
    value = env->NewString((const jchar *)str, lstrlen(str)); \
    env->SetObjectField(obj, id, value)

#define SERVICE_SetIntField(field, val) \
    id = env->GetFieldID(cls, field, "I"); \
    env->SetIntField(obj, id, val)

typedef DWORD (CALLBACK *ChangeServiceConfig2_func_t)(SC_HANDLE,
                                                      DWORD, LPVOID);

JNIEXPORT jboolean SIGAR_JNI(win32_Service_ChangeServiceDescription)
(JNIEnv *env, jclass, jlong handle, jstring description)
{
    jboolean result = FALSE;
    SERVICE_DESCRIPTION servdesc;
    HINSTANCE lib;
    ChangeServiceConfig2_func_t change_config;

    if ((lib = LoadLibrary(L"advapi32"))) {
        change_config = (ChangeServiceConfig2_func_t)
            GetProcAddress(lib, "ChangeServiceConfig2W");

        if (change_config) {
            servdesc.lpDescription =
                (LPTSTR)env->GetStringChars(description, NULL);

            result = change_config((SC_HANDLE)handle,
                                   SERVICE_CONFIG_DESCRIPTION, &servdesc);
            env->ReleaseStringChars(description,
                                    (const jchar *)servdesc.lpDescription);
        }

        FreeLibrary(lib);
    }

    return result;
}

JNIEXPORT jboolean SIGAR_JNI(win32_Service_CloseServiceHandle)
(JNIEnv *, jclass, jlong handle)
{
    return CloseServiceHandle((SC_HANDLE)handle);
}

JNIEXPORT jboolean SIGAR_JNI(win32_Service_ControlService)
(JNIEnv *, jclass, jlong handle, jint control)
{
    SERVICE_STATUS  status;
    return ControlService((SC_HANDLE)handle, control, &status);
}

JNIEXPORT jlong SIGAR_JNI(win32_Service_CreateService)
(JNIEnv *env,
 jclass,
 jlong handle,
 jstring serviceName,
 jstring displayName,
 jint serviceType,
 jint startType,
 jint errorControl,
 jstring path,
 jobjectArray dependencies,
 jstring startName,
 jstring password)
{
    TCHAR   szBuf[4048];
    LPCTSTR lpDepend = NULL;
    jlong   lResult;
    LPCTSTR lpStartName;

    LPCTSTR lpServiceName = (LPCTSTR)env->GetStringChars(serviceName, NULL);
    LPCTSTR lpDisplayName = (LPCTSTR)env->GetStringChars(displayName, NULL);
    LPCTSTR lpPath        = (LPCTSTR)env->GetStringChars(path, NULL);
    LPCTSTR lpPassword    = (LPCTSTR)env->GetStringChars(password, NULL);

    if(startName != NULL)
        lpStartName = (LPCTSTR)env->GetStringChars(path, NULL);
    else
        lpStartName = NULL;

    if(dependencies != NULL)
    {
        // Build a buffer of a double null terminated array of
        // null terminated service names
        lpDepend             = szBuf;

        LPTSTR  lpBuf = szBuf;
        size_t  cbLen = 0;
        jsize   cSize = env->GetArrayLength(dependencies);

        for(int i = 0;i < cSize;i ++)
        {
            jstring str = (jstring)env->GetObjectArrayElement(dependencies, i);

            LPCTSTR lpStr = (LPCTSTR)env->GetStringChars(str, NULL);
            cbLen         = lstrlen(lpStr);

            // If we're going to overrun the buffer then break out of the loop
            if((lpBuf + cbLen + 1) >= (szBuf + sizeof(szBuf) / sizeof(TCHAR)))
                break;

            lstrcpy(lpBuf, lpStr);
            env->ReleaseStringChars(str, (const jchar *)lpStr);

            // Move the buffer to the byte beyond the current string
            // null terminator
            lpBuf = lpBuf + cbLen + 1;
        }

        *lpBuf = 0;  // Double null terminate the string
    }

    // Create the Service
    lResult = (jlong)CreateService((SC_HANDLE)handle, lpServiceName,
                                   lpDisplayName, SERVICE_ALL_ACCESS,
                                   serviceType,
                                   startType, errorControl, lpPath,
                                   NULL, NULL, lpDepend, lpStartName,
                                   lpPassword);

    if(lpStartName != NULL)
        env->ReleaseStringChars(path, (const jchar *)lpStartName);

    env->ReleaseStringChars(password, (const jchar *)lpPassword);
    env->ReleaseStringChars(path, (const jchar *)lpPath);
    env->ReleaseStringChars(displayName, (const jchar *)lpDisplayName);
    env->ReleaseStringChars(serviceName, (const jchar *)lpServiceName);

    return lResult;
}

JNIEXPORT jboolean SIGAR_JNI(win32_Service_DeleteService)
(JNIEnv *env, jclass, jlong handle)
{
    return DeleteService((SC_HANDLE)handle);
}

JNIEXPORT jlong SIGAR_JNI(win32_Service_OpenSCManager)
(JNIEnv *env, jclass, jstring machine, jint access)
{
    jlong   lResult;

    LPCTSTR lpMachine  = (LPCTSTR)env->GetStringChars(machine, NULL);
    lResult            = (jlong)OpenSCManager(lpMachine, NULL, access);
    env->ReleaseStringChars(machine, (const jchar *)lpMachine);

    return lResult;
}

JNIEXPORT jlong SIGAR_JNI(win32_Service_OpenService)
(JNIEnv *env,
 jclass,
 jlong handle,
 jstring service,
 jint access)
{
    jlong   lResult;

    LPCTSTR lpService = (LPCTSTR)env->GetStringChars(service, NULL);
    lResult           = (jlong)OpenService((SC_HANDLE)handle,
                                           lpService, access);
    env->ReleaseStringChars(service, (const jchar *)lpService);

    return lResult;
}

JNIEXPORT jint
SIGAR_JNI(win32_Service_QueryServiceStatus)
(JNIEnv *, jclass, jlong handle)
{
    SERVICE_STATUS status;
    int            iResult;

    if(QueryServiceStatus((SC_HANDLE)handle, &status) == TRUE) {
        iResult = status.dwCurrentState;
    } else
        iResult = -1;

    return iResult;
}

JNIEXPORT jboolean SIGAR_JNI(win32_Service_StartService)
(JNIEnv *, jclass, jlong handle)
{
    return StartService((SC_HANDLE)handle, 0, NULL);
}

JNIEXPORT jboolean SIGAR_JNI(win32_Service_StopService)
(JNIEnv *, jclass, jlong handle)
{
    SERVICE_STATUS  status;

    return ControlService((SC_HANDLE)handle, SERVICE_CONTROL_STOP, &status);
}

JNIEXPORT jobject SIGAR_JNI(win32_Service_getServiceNames)
(JNIEnv *env, jclass)
{
    SC_HANDLE handle =
        OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
    ENUM_SERVICE_STATUS status, *services;
    BOOL retval;
    DWORD bytes, count, resume=0;
    DWORD type = SERVICE_WIN32, state = SERVICE_STATE_ALL;
    jobject listobj;
    jclass listclass =
        env->FindClass("java/util/ArrayList");
    jmethodID listid =
        env->GetMethodID(listclass, "<init>", "()V");
    jmethodID addid =
        env->GetMethodID(listclass, "add",
                         "(Ljava/lang/Object;)"
                         "Z");

    if (handle == NULL) {
        return NULL;
    }

    retval = EnumServicesStatus(handle, type, state,
                                &status, sizeof(status),
                                &bytes, &count, &resume);

    DWORD err = GetLastError();

    if ((retval == FALSE) || err == ERROR_MORE_DATA) {
        DWORD size = bytes + sizeof(ENUM_SERVICE_STATUS);
        services = new ENUM_SERVICE_STATUS[size];
        EnumServicesStatus(handle, type, state, services,
                           size, &bytes, &count, &resume);
    }

    listobj = env->NewObject(listclass, listid);
    for (int i=0; i<count; i++) {
        jstring name =
            env->NewString((const jchar *)services[i].lpServiceName,
                           lstrlen(services[i].lpServiceName));
        env->CallBooleanMethod(listobj, addid, name);
    }

    CloseServiceHandle(handle);
    delete services;

    return listobj;
}

JNIEXPORT jboolean SIGAR_JNI(win32_Service_QueryServiceConfig)
(JNIEnv *env, jclass, jlong handle, jobject obj)
{
    char buffer[8096]; /* 8k is max size from mdsn docs */
    LPQUERY_SERVICE_CONFIG config = (LPQUERY_SERVICE_CONFIG)buffer;
    DWORD bytes;
    jfieldID id;
    jclass cls = env->GetObjectClass(obj);
    jstring value;

    if (!QueryServiceConfig((SC_HANDLE)handle, config,
                            sizeof(buffer), &bytes))
    {
        return JNI_FALSE;
    }

    SERVICE_SetIntField("type", config->dwServiceType);

    SERVICE_SetIntField("startType", config->dwStartType);

    SERVICE_SetIntField("errorControl", config->dwErrorControl);

    SERVICE_SetStringField("binaryPathName", config->lpBinaryPathName);

    SERVICE_SetStringField("loadOrderGroup", config->lpLoadOrderGroup);

    SERVICE_SetIntField("tagId", config->dwTagId);

    SERVICE_SetStringField("dependencies", config->lpDependencies);

    SERVICE_SetStringField("serviceStartName", config->lpServiceStartName);

    SERVICE_SetStringField("displayName", config->lpDisplayName);

    return JNI_TRUE;
}

#ifdef __cplusplus
}
#endif
#endif /* WIN32 */
<|endoftext|>


<commit_before>// Copyright 2019 Global Phasing Ltd.
//
// Reads reflection data from the mmCIF format.

#ifndef GEMMI_REFLN_HPP_
#define GEMMI_REFLN_HPP_

#include <array>
#include "cifdoc.hpp"
#include "fail.hpp"       // for fail
#include "mmcif_impl.hpp" // for set_cell_from_mmcif, read_spacegroup_from_block
#include "numb.hpp"       // for as_number
#include "symmetry.hpp"   // for SpaceGroup
#include "unitcell.hpp"   // for UnitCell

namespace gemmi {

struct ReflnBlock {
  cif::Block block;
  std::string entry_id;
  UnitCell cell;
  const SpaceGroup* spacegroup = nullptr;
  double wavelength;
  cif::Loop* refln_loop = nullptr;
  cif::Loop* diffrn_refln_loop = nullptr;
  cif::Loop* default_loop = nullptr;

  ReflnBlock() = default;
  ReflnBlock(ReflnBlock&& rblock_) = default;
  ReflnBlock(cif::Block&& block_) : block(block_) {
    entry_id = cif::as_string(block.find_value("_entry.id"));
    impl::set_cell_from_mmcif(block, cell);
    if (const std::string* hm = impl::find_spacegroup_hm_value(block))
      spacegroup = find_spacegroup_by_name(cif::as_string(*hm),
                                           cell.alpha, cell.gamma);
    cell.set_cell_images_from_spacegroup(spacegroup);
    const char* wave_tag = "_diffrn_radiation_wavelength.wavelength";
    cif::Column wave_col = block.find_values(wave_tag);
    wavelength = wave_col.length() == 1 ? cif::as_number(wave_col[0]) : 0.;
    refln_loop = block.find_loop("_refln.index_h").get_loop();
    diffrn_refln_loop = block.find_loop("_diffrn_refln.index_h").get_loop();
    default_loop = refln_loop ? refln_loop : diffrn_refln_loop;
  }
  ReflnBlock& operator=(ReflnBlock&&) = default;
  ReflnBlock& operator=(const ReflnBlock& o) {
    block = o.block;
    entry_id = o.entry_id;
    cell = o.cell;
    spacegroup = o.spacegroup;
    wavelength = o.wavelength;
    if (o.refln_loop)
      refln_loop = block.find_loop("_refln.index_h").get_loop();
    if (o.diffrn_refln_loop)
      diffrn_refln_loop = block.find_loop("_diffrn_refln.index_h").get_loop();
    default_loop = refln_loop ? refln_loop : diffrn_refln_loop;
    return *this;
  }

  bool ok() const { return default_loop != nullptr; }
  void check_ok() const { if (!ok()) fail("Invalid ReflnBlock"); }

  // position after "_refln." or "_diffrn_refln."
  size_t tag_offset() const { return refln_loop ? 7 : 14; }

  void use_unmerged(bool unmerged) {
    default_loop = unmerged ? diffrn_refln_loop : refln_loop;
  }
  bool is_unmerged() const { return ok() && default_loop == diffrn_refln_loop; }

  std::vector<std::string> column_labels() const {
    check_ok();
    std::vector<std::string> labels(default_loop->tags.size());
    for (size_t i = 0; i != labels.size(); ++i)
      labels[i].assign(default_loop->tags[i], tag_offset(), std::string::npos);
    return labels;
  }

  int find_column_index(const std::string& tag) const {
    if (!ok())
      return -1;
    size_t name_pos = tag_offset();
    for (int i = 0; i != (int) default_loop->tags.size(); ++i)
      if (default_loop->tags[i].compare(name_pos, std::string::npos, tag) == 0)
        return i;
    return -1;
  }

  size_t get_column_index(const std::string& tag) const {
    int idx = find_column_index(tag);
    if (idx == -1)
      fail("Column not found: " + tag);
    return idx;
  }

  template<typename T>
  std::vector<T> make_vector(const std::string& tag, T null) const {
    size_t n = get_column_index(tag);
    std::vector<T> v(default_loop->length());
    for (size_t j = 0; j != v.size(); n += default_loop->width(), ++j)
      v[j] = cif::as_any(default_loop->values[n], null);
    return v;
  }

  std::array<size_t,3> get_hkl_column_indices() const {
    return {{get_column_index("index_h"),
             get_column_index("index_k"),
             get_column_index("index_l")}};
  }

  std::vector<Miller> make_miller_vector() const {
    auto hkl_idx = get_hkl_column_indices();
    std::vector<Miller> v(default_loop->length());
    for (size_t j = 0, n = 0; j != v.size(); j++, n += default_loop->width())
      for (int i = 0; i != 3; ++i)
        v[j][i] = cif::as_int(default_loop->values[n + hkl_idx[i]]);
    return v;
  }

  std::vector<double> make_1_d2_vector() const {
    if (!cell.is_crystal() || cell.a <= 0)
      fail("Unit cell is not known");
    auto hkl_idx = get_hkl_column_indices();
    std::vector<double> r(default_loop->length());
    for (size_t j = 0, n = 0; j != r.size(); j++, n += default_loop->width()) {
      Miller hkl;
      for (int i = 0; i != 3; ++i)
        hkl[i] = cif::as_int(default_loop->values[n + hkl_idx[i]]);
      r[j] = cell.calculate_1_d2(hkl);
    }
    return r;
  }

  std::vector<double> make_d_vector() const {
    std::vector<double> vec = make_1_d2_vector();
    for (double& d : vec)
      d = 1.0 / std::sqrt(d);
    return vec;
  }
};

// moves blocks from the argument to the return value
inline
std::vector<ReflnBlock> as_refln_blocks(std::vector<cif::Block>&& blocks) {
  std::vector<ReflnBlock> r;
  r.reserve(blocks.size());
  for (cif::Block& block : blocks)
    r.emplace_back(std::move(block));
  blocks.clear();
  // Some blocks miss space group tag, try to fill it in.
  const SpaceGroup* first_sg = nullptr;
  for (ReflnBlock& rblock : r)
    if (!first_sg)
      first_sg = rblock.spacegroup;
    else if (!rblock.spacegroup)
      rblock.spacegroup = first_sg;
  return r;
}

// Get the first (merged) block with required labels.
// Optionally, block name can be specified.
inline ReflnBlock get_refln_block(std::vector<cif::Block>&& blocks,
                                  const std::vector<std::string>& labels,
                                  const char* block_name=nullptr) {
  const SpaceGroup* first_sg = nullptr;
  for (cif::Block& block : blocks) {
    if (!first_sg)
      if (const std::string* hm = impl::find_spacegroup_hm_value(block)) {
        first_sg = find_spacegroup_by_name(cif::as_string(*hm));
        if (first_sg && first_sg->ext == 'H') {
          UnitCell cell;
          impl::set_cell_from_mmcif(block, cell);
          first_sg = find_spacegroup_by_name(cif::as_string(*hm),
                                             cell.alpha, cell.gamma);
        }
      }
    if (block_name && block.name != block_name)
      continue;
    if (cif::Loop* loop = block.find_loop("_refln.index_h").get_loop())
      if (std::all_of(labels.begin(), labels.end(),
            [&](const std::string& s) { return loop->has_tag("_refln."+s); })) {
        ReflnBlock rblock(std::move(block));
        if (!rblock.spacegroup && first_sg)
          rblock.spacegroup = first_sg;
        return rblock;
      }
  }
  fail("Required block or tags not found in the SF-mmCIF file.");
}

inline ReflnBlock hkl_cif_as_refln_block(cif::Block& block) {
  ReflnBlock rb;
  rb.block.swap(block);
  rb.entry_id = rb.block.name;
  impl::set_cell_from_mmcif(rb.block, rb.cell, /*mmcif=*/false);
  const char* hm_tag = "_symmetry_space_group_name_H-M";
  if (const std::string* hm = block.find_value(hm_tag))
    rb.spacegroup = find_spacegroup_by_name(cif::as_string(*hm),
                                            rb.cell.alpha, rb.cell.gamma);
  rb.cell.set_cell_images_from_spacegroup(rb.spacegroup);
  rb.refln_loop = rb.block.find_loop("_refln_index_h").get_loop();
  rb.default_loop = rb.refln_loop;
  return rb;
}

// Abstraction of data source, cf. MtzDataProxy.
struct ReflnDataProxy {
  const ReflnBlock& rb_;
  std::array<size_t,3> hkl_cols_;
  explicit ReflnDataProxy(const ReflnBlock& rb)
    : rb_(rb), hkl_cols_(rb_.get_hkl_column_indices()) {}
  size_t stride() const { return loop().tags.size(); }
  size_t size() const { return loop().values.size(); }
  using num_type = double;
  double get_num(size_t n) const { return cif::as_number(loop().values[n]); }
  const UnitCell& unit_cell() const { return rb_.cell; }
  const SpaceGroup* spacegroup() const { return rb_.spacegroup; }
  Miller get_hkl(size_t offset) const {
    return {{get_int(offset + hkl_cols_[0]),
             get_int(offset + hkl_cols_[1]),
             get_int(offset + hkl_cols_[2])}};
  }
  size_t column_index(const std::string& label) const { return rb_.get_column_index(label); }
private:
  const cif::Loop& loop() const { rb_.check_ok(); return *rb_.default_loop; }
  int get_int(size_t n) const { return cif::as_int(loop().values[n]); }
};

inline ReflnDataProxy data_proxy(const ReflnBlock& rb) { return ReflnDataProxy(rb); }

} // namespace gemmi
#endif
<commit_msg>refln: fix hkl_cif_as_refln_block<commit_after>// Copyright 2019 Global Phasing Ltd.
//
// Reads reflection data from the mmCIF format.

#ifndef GEMMI_REFLN_HPP_
#define GEMMI_REFLN_HPP_

#include <array>
#include "cifdoc.hpp"
#include "fail.hpp"       // for fail
#include "mmcif_impl.hpp" // for set_cell_from_mmcif, read_spacegroup_from_block
#include "numb.hpp"       // for as_number
#include "symmetry.hpp"   // for SpaceGroup
#include "unitcell.hpp"   // for UnitCell

namespace gemmi {

struct ReflnBlock {
  cif::Block block;
  std::string entry_id;
  UnitCell cell;
  const SpaceGroup* spacegroup = nullptr;
  double wavelength;
  cif::Loop* refln_loop = nullptr;
  cif::Loop* diffrn_refln_loop = nullptr;
  cif::Loop* default_loop = nullptr;

  ReflnBlock() = default;
  ReflnBlock(ReflnBlock&& rblock_) = default;
  ReflnBlock(cif::Block&& block_) : block(block_) {
    entry_id = cif::as_string(block.find_value("_entry.id"));
    impl::set_cell_from_mmcif(block, cell);
    if (const std::string* hm = impl::find_spacegroup_hm_value(block))
      spacegroup = find_spacegroup_by_name(cif::as_string(*hm),
                                           cell.alpha, cell.gamma);
    cell.set_cell_images_from_spacegroup(spacegroup);
    const char* wave_tag = "_diffrn_radiation_wavelength.wavelength";
    cif::Column wave_col = block.find_values(wave_tag);
    wavelength = wave_col.length() == 1 ? cif::as_number(wave_col[0]) : 0.;
    refln_loop = block.find_loop("_refln.index_h").get_loop();
    diffrn_refln_loop = block.find_loop("_diffrn_refln.index_h").get_loop();
    default_loop = refln_loop ? refln_loop : diffrn_refln_loop;
  }
  ReflnBlock& operator=(ReflnBlock&&) = default;
  ReflnBlock& operator=(const ReflnBlock& o) {
    block = o.block;
    entry_id = o.entry_id;
    cell = o.cell;
    spacegroup = o.spacegroup;
    wavelength = o.wavelength;
    if (o.refln_loop)
      refln_loop = block.find_loop("_refln.index_h").get_loop();
    if (o.diffrn_refln_loop)
      diffrn_refln_loop = block.find_loop("_diffrn_refln.index_h").get_loop();
    default_loop = refln_loop ? refln_loop : diffrn_refln_loop;
    return *this;
  }

  bool ok() const { return default_loop != nullptr; }
  void check_ok() const { if (!ok()) fail("Invalid ReflnBlock"); }

  // position after "_refln." or "_diffrn_refln."
  size_t tag_offset() const { return refln_loop ? 7 : 14; }

  void use_unmerged(bool unmerged) {
    default_loop = unmerged ? diffrn_refln_loop : refln_loop;
  }
  bool is_unmerged() const { return ok() && default_loop == diffrn_refln_loop; }

  std::vector<std::string> column_labels() const {
    check_ok();
    std::vector<std::string> labels(default_loop->tags.size());
    for (size_t i = 0; i != labels.size(); ++i)
      labels[i].assign(default_loop->tags[i], tag_offset(), std::string::npos);
    return labels;
  }

  int find_column_index(const std::string& tag) const {
    if (!ok())
      return -1;
    size_t name_pos = tag_offset();
    for (int i = 0; i != (int) default_loop->tags.size(); ++i)
      if (default_loop->tags[i].compare(name_pos, std::string::npos, tag) == 0)
        return i;
    return -1;
  }

  size_t get_column_index(const std::string& tag) const {
    int idx = find_column_index(tag);
    if (idx == -1)
      fail("Column not found: " + tag);
    return idx;
  }

  template<typename T>
  std::vector<T> make_vector(const std::string& tag, T null) const {
    size_t n = get_column_index(tag);
    std::vector<T> v(default_loop->length());
    for (size_t j = 0; j != v.size(); n += default_loop->width(), ++j)
      v[j] = cif::as_any(default_loop->values[n], null);
    return v;
  }

  std::array<size_t,3> get_hkl_column_indices() const {
    return {{get_column_index("index_h"),
             get_column_index("index_k"),
             get_column_index("index_l")}};
  }

  std::vector<Miller> make_miller_vector() const {
    auto hkl_idx = get_hkl_column_indices();
    std::vector<Miller> v(default_loop->length());
    for (size_t j = 0, n = 0; j != v.size(); j++, n += default_loop->width())
      for (int i = 0; i != 3; ++i)
        v[j][i] = cif::as_int(default_loop->values[n + hkl_idx[i]]);
    return v;
  }

  std::vector<double> make_1_d2_vector() const {
    if (!cell.is_crystal() || cell.a <= 0)
      fail("Unit cell is not known");
    auto hkl_idx = get_hkl_column_indices();
    std::vector<double> r(default_loop->length());
    for (size_t j = 0, n = 0; j != r.size(); j++, n += default_loop->width()) {
      Miller hkl;
      for (int i = 0; i != 3; ++i)
        hkl[i] = cif::as_int(default_loop->values[n + hkl_idx[i]]);
      r[j] = cell.calculate_1_d2(hkl);
    }
    return r;
  }

  std::vector<double> make_d_vector() const {
    std::vector<double> vec = make_1_d2_vector();
    for (double& d : vec)
      d = 1.0 / std::sqrt(d);
    return vec;
  }
};

// moves blocks from the argument to the return value
inline
std::vector<ReflnBlock> as_refln_blocks(std::vector<cif::Block>&& blocks) {
  std::vector<ReflnBlock> r;
  r.reserve(blocks.size());
  for (cif::Block& block : blocks)
    r.emplace_back(std::move(block));
  blocks.clear();
  // Some blocks miss space group tag, try to fill it in.
  const SpaceGroup* first_sg = nullptr;
  for (ReflnBlock& rblock : r)
    if (!first_sg)
      first_sg = rblock.spacegroup;
    else if (!rblock.spacegroup)
      rblock.spacegroup = first_sg;
  return r;
}

// Get the first (merged) block with required labels.
// Optionally, block name can be specified.
inline ReflnBlock get_refln_block(std::vector<cif::Block>&& blocks,
                                  const std::vector<std::string>& labels,
                                  const char* block_name=nullptr) {
  const SpaceGroup* first_sg = nullptr;
  for (cif::Block& block : blocks) {
    if (!first_sg)
      if (const std::string* hm = impl::find_spacegroup_hm_value(block)) {
        first_sg = find_spacegroup_by_name(cif::as_string(*hm));
        if (first_sg && first_sg->ext == 'H') {
          UnitCell cell;
          impl::set_cell_from_mmcif(block, cell);
          first_sg = find_spacegroup_by_name(cif::as_string(*hm),
                                             cell.alpha, cell.gamma);
        }
      }
    if (block_name && block.name != block_name)
      continue;
    if (cif::Loop* loop = block.find_loop("_refln.index_h").get_loop())
      if (std::all_of(labels.begin(), labels.end(),
            [&](const std::string& s) { return loop->has_tag("_refln."+s); })) {
        ReflnBlock rblock(std::move(block));
        if (!rblock.spacegroup && first_sg)
          rblock.spacegroup = first_sg;
        return rblock;
      }
  }
  fail("Required block or tags not found in the SF-mmCIF file.");
}

inline ReflnBlock hkl_cif_as_refln_block(cif::Block& block) {
  ReflnBlock rb;
  rb.block.swap(block);
  rb.entry_id = rb.block.name;
  impl::set_cell_from_mmcif(rb.block, rb.cell, /*mmcif=*/false);
  const char* hm_tag = "_symmetry_space_group_name_H-M";
  if (const std::string* hm = rb.block.find_value(hm_tag))
    rb.spacegroup = find_spacegroup_by_name(cif::as_string(*hm),
                                            rb.cell.alpha, rb.cell.gamma);
  rb.cell.set_cell_images_from_spacegroup(rb.spacegroup);
  rb.refln_loop = rb.block.find_loop("_refln_index_h").get_loop();
  rb.default_loop = rb.refln_loop;
  return rb;
}

// Abstraction of data source, cf. MtzDataProxy.
struct ReflnDataProxy {
  const ReflnBlock& rb_;
  std::array<size_t,3> hkl_cols_;
  explicit ReflnDataProxy(const ReflnBlock& rb)
    : rb_(rb), hkl_cols_(rb_.get_hkl_column_indices()) {}
  size_t stride() const { return loop().tags.size(); }
  size_t size() const { return loop().values.size(); }
  using num_type = double;
  double get_num(size_t n) const { return cif::as_number(loop().values[n]); }
  const UnitCell& unit_cell() const { return rb_.cell; }
  const SpaceGroup* spacegroup() const { return rb_.spacegroup; }
  Miller get_hkl(size_t offset) const {
    return {{get_int(offset + hkl_cols_[0]),
             get_int(offset + hkl_cols_[1]),
             get_int(offset + hkl_cols_[2])}};
  }
  size_t column_index(const std::string& label) const { return rb_.get_column_index(label); }
private:
  const cif::Loop& loop() const { rb_.check_ok(); return *rb_.default_loop; }
  int get_int(size_t n) const { return cif::as_int(loop().values[n]); }
};

inline ReflnDataProxy data_proxy(const ReflnBlock& rb) { return ReflnDataProxy(rb); }

} // namespace gemmi
#endif
<|endoftext|>


<commit_before>#pragma once

#include "concat_common.hh"
#include "string_view.hh"

class InplaceBuffBase {
public:
	size_t size = 0;

protected:
	size_t max_size_;
	char* p_;

public:
	/**
	 * @brief Changes buffer's size and max_size if needed, but in the latter
	 *   case all the data are lost
	 *
	 * @param n new buffer's size
	 */
	void lossy_resize(size_t n) {
		if (n > max_size_) {
			max_size_ = std::max(max_size_ << 1, n);
			deallocate();
			try {
				p_ = new char[max_size_];
			} catch (...) {
				p_ = (char*)&p_ + sizeof(p_);
				max_size_ = 0;
				throw;
			}
		}

		size = n;
	}

	/**
	 * @brief Changes buffer's size and max_size if needed, preserves data
	 *
	 * @param n new buffer's size
	 */
	constexpr void resize(size_t n) {
		if (n > max_size_) {
			size_t new_ms = std::max(max_size_ << 1, n);
			char* new_p = new char[new_ms];
			std::copy(p_, p_ + size, new_p);
			deallocate();

			p_ = new_p;
			max_size_ = new_ms;
		}

		size = n;
	}

	constexpr void clear() noexcept { size = 0; }

	constexpr char* begin() noexcept { return data(); }

	constexpr const char* begin() const noexcept { return data(); }

	constexpr char* end() noexcept { return data() + size; }

	constexpr const char* end() const noexcept { return data() + size; }

	constexpr const char* cbegin() const noexcept { return data(); }

	constexpr const char* cend() const noexcept { return data() + size; }

	constexpr char* data() noexcept { return p_; }

	constexpr const char* data() const noexcept { return p_; }

	constexpr size_t max_size() const noexcept { return max_size_; }

	constexpr char& front() noexcept { return (*this)[0]; }

	constexpr char front() const noexcept { return (*this)[0]; }

	constexpr char& back() noexcept { return (*this)[size - 1]; }

	constexpr char back() const noexcept { return (*this)[size - 1]; }

	constexpr char& operator[](size_t i) noexcept { return p_[i]; }

	constexpr char operator[](size_t i) const noexcept { return p_[i]; }

	constexpr operator StringView() const& noexcept { return {data(), size}; }

	// Do not allow to create StringView from a temporary object
	constexpr operator StringView() const&& = delete;

	// Do not allow to create StringBase<char> from a temporary object
	operator StringBase<char>() & noexcept { return {data(), size}; }

	operator StringBase<char>() && = delete;

	std::string to_string() const { return {data(), size}; }

	constexpr CStringView to_cstr() & {
		resize(size + 1);
		(*this)[--size] = '\0';
		return {data(), size};
	}

	// Do not allow to create CStringView of a temporary object
	constexpr CStringView to_cstr() && = delete;

	constexpr InplaceBuffBase(size_t s, size_t max_s, char* p) noexcept
	   : size(s), max_size_(max_s), p_(p) {}

protected:
	constexpr InplaceBuffBase(const InplaceBuffBase&) noexcept = default;
	constexpr InplaceBuffBase(InplaceBuffBase&&) noexcept = default;
	InplaceBuffBase& operator=(const InplaceBuffBase&) noexcept = default;
	InplaceBuffBase& operator=(InplaceBuffBase&&) noexcept = default;

	bool is_allocated() const noexcept {
		// This is not pretty but works...
		return (reinterpret_cast<const std::byte*>(p_) -
		           reinterpret_cast<const std::byte*>(&p_) !=
		        sizeof p_);
	}

	void deallocate() noexcept {
		if (is_allocated())
			delete[] p_;
	}

public:
	~InplaceBuffBase() { deallocate(); }

	template <class... Args,
	          std::enable_if_t<(is_string_argument<Args> and ...), int> = 0>
	constexpr InplaceBuffBase& append(Args&&... args) {
		[this](auto&&... str) {
			size_t k = size, final_len = (size + ... + string_length(str));
			resize(final_len);
			auto append_impl = [&](auto&& s) {
				auto sl = string_length(s);
				std::copy(::data(s), ::data(s) + sl, data() + k);
				k += sl;
			};
			(void)append_impl; // Fix GCC warning
			(append_impl(std::forward<decltype(str)>(str)), ...);
		}(stringify(std::forward<Args>(args))...);

		return *this;
	}
};

template <size_t N>
class InplaceBuff : protected InplaceBuffBase {
private:
	std::array<char, N> a_;

	template <size_t M>
	friend class InplaceBuff;

	static_assert(N > 0, "Needed for accessing the array's 0-th element");

	using InplaceBuffBase::is_allocated;

public:
	static constexpr size_t max_static_size = N;

	constexpr InplaceBuff() noexcept : InplaceBuffBase(0, N, nullptr) {
		p_ = &a_[0];
	}

	constexpr explicit InplaceBuff(size_t n)
	   : InplaceBuffBase(n, std::max(N, n), nullptr) {
		p_ = (n <= N ? &a_[0] : new char[n]);
	}

	template <class T, std::enable_if_t<not std::is_integral_v<std::remove_cv_t<
	                                       std::remove_reference_t<T>>>,
	                                    int> = 0>
	constexpr explicit InplaceBuff(T&& str) : InplaceBuff(string_length(str)) {
		std::copy(::data(str), ::data(str) + size, p_);
	}

	constexpr InplaceBuff(const InplaceBuff& ibuff) : InplaceBuff(ibuff.size) {
		std::copy(ibuff.data(), ibuff.data() + ibuff.size, data());
	}

	InplaceBuff(InplaceBuff&& ibuff) noexcept
	   : InplaceBuffBase(ibuff.size, std::max(N, ibuff.max_size_), ibuff.p_) {
		if (ibuff.is_allocated()) {
			p_ = ibuff.p_;
			ibuff.size = 0;
			ibuff.max_size_ = N;
			ibuff.p_ = &ibuff.a_[0];

		} else {
			p_ = &a_[0];
			std::copy(ibuff.data(), ibuff.data() + ibuff.size, p_);
			ibuff.size = 0;
		}
	}

	// Used to unify constructors, as constructor taking one argument is
	// explicit
	template <class... Args,
	          std::enable_if_t<(is_string_argument<Args> and ...), int> = 0>
	constexpr InplaceBuff(std::in_place_t, Args&&... args) : InplaceBuff() {
		append(std::forward<Args>(args)...);
	}

	template <
	   class Arg1, class Arg2, class... Args,
	   std::enable_if_t<
	      not std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg1>>,
	                         std::in_place_t>,
	      int> = 0>
	constexpr InplaceBuff(Arg1&& arg1, Arg2&& arg2, Args&&... args)
	   : InplaceBuff(std::in_place, std::forward<Arg1>(arg1),
	                 std::forward<Arg2>(arg2), std::forward<Args>(args)...) {}

	template <size_t M, std::enable_if_t<M != N, int> = 0>
	constexpr InplaceBuff(const InplaceBuff<M>& ibuff)
	   : InplaceBuff(ibuff.size) {
		std::copy(ibuff.data(), ibuff.data() + ibuff.size, data());
	}

	template <size_t M, std::enable_if_t<M != N, int> = 0>
	InplaceBuff(InplaceBuff<M>&& ibuff) noexcept
	   : InplaceBuffBase(ibuff.size, N, ibuff.p_) {
		if (ibuff.size <= N) {
			p_ = &a_[0];
			// max_size_ = N;
			std::copy(ibuff.data(), ibuff.data() + ibuff.size, p_);
			// Deallocate ibuff memory
			if (ibuff.is_allocated())
				delete[] std::exchange(ibuff.p_, nullptr);

		} else if (ibuff.is_allocated()) {
			p_ = ibuff.p_; // Steal the allocated string
			max_size_ = ibuff.max_size_;
		} else {
			// N < ibuff.size <= M
			p_ = new char[ibuff.size];
			max_size_ = ibuff.size;
			std::copy(ibuff.data(), ibuff.data() + ibuff.size, p_);
		}

		// Take care of the ibuff's state
		ibuff.size = 0;
		ibuff.max_size_ = M;
		ibuff.p_ = &ibuff.a_[0];
	}

	template <class T>
	constexpr InplaceBuff& operator=(T&& str) {
		auto len = string_length(str);
		lossy_resize(len);
		std::copy(::data(str), ::data(str) + len, data());
		return *this;
	}

	constexpr InplaceBuff& operator=(const InplaceBuff& ibuff) {
		lossy_resize(ibuff.size);
		std::copy(ibuff.data(), ibuff.data() + ibuff.size, data());
		return *this;
	}

	template <size_t M, std::enable_if_t<M != N, int> = 0>
	constexpr InplaceBuff& operator=(const InplaceBuff<M>& ibuff) {
		lossy_resize(ibuff.size);
		std::copy(ibuff.data(), ibuff.data() + ibuff.size, data());
		return *this;
	}

private:
	template <size_t M>
	InplaceBuff& assign_move_impl(InplaceBuff<M>&& ibuff) {
		if (ibuff.is_allocated() and ibuff.max_size() >= max_size()) {
			// Steal the allocated string
			if (is_allocated())
				delete[] p_;

			p_ = ibuff.p_;
			size = ibuff.size;
			max_size_ = ibuff.max_size_;

		} else {
			*this = ibuff; // Copy data
			if (ibuff.is_allocated())
				delete[] ibuff.p_;
		}

		// Take care of the ibuff's state
		ibuff.p_ = &ibuff.a_[0];
		ibuff.size = 0;
		ibuff.max_size_ = M;

		return *this;
	}

public:
	constexpr InplaceBuff& operator=(InplaceBuff&& ibuff) noexcept {
		return assign_move_impl(std::move(ibuff));
	}

	template <size_t M, std::enable_if_t<M != N, int> = 0>
	constexpr InplaceBuff& operator=(InplaceBuff<M>&& ibuff) noexcept {
		return assign_move_impl(std::move(ibuff));
	}

	using InplaceBuffBase::append;
	using InplaceBuffBase::back;
	using InplaceBuffBase::begin;
	using InplaceBuffBase::cbegin;
	using InplaceBuffBase::cend;
	using InplaceBuffBase::clear;
	using InplaceBuffBase::data;
	using InplaceBuffBase::end;
	using InplaceBuffBase::front;
	using InplaceBuffBase::lossy_resize;
	using InplaceBuffBase::max_size;
	using InplaceBuffBase::operator StringBase<char>;
	using InplaceBuffBase::operator StringView;
	using InplaceBuffBase::operator[];
	using InplaceBuffBase::resize;
	using InplaceBuffBase::size;
	using InplaceBuffBase::to_cstr;
	using InplaceBuffBase::to_string;
};

template <size_t N>
std::string& operator+=(std::string& str, const InplaceBuff<N>& ibs) {
	return str.append(ibs.data(), ibs.size);
}

// This function allows @p str to be converted to StringView, but
// keep in mind that if any StringView or alike value generated from the result
// of this function cannot be saved to a variable! -- it would (and probably
// will) cause use-after-free error, because @p str will be already deleted when
// the initialization is done
template <size_t N>
constexpr StringView
intentional_unsafe_string_view(const InplaceBuff<N>&& str) noexcept {
	return StringView(static_cast<const InplaceBuff<N>&>(str));
}

// This function allows @p str to be converted to CStringView, but
// keep in mind that if any StringView or alike value generated from the result
// of this function cannot be saved to a variable! -- it would (and probably
// will) cause use-after-free error, because @p str will be already deleted when
// the initialization is done
template <size_t N>
constexpr CStringView
intentional_unsafe_cstring_view(InplaceBuff<N>&& str) noexcept {
	return static_cast<InplaceBuff<N>&>(str).to_cstr();
}

template <size_t T>
constexpr auto string_length(const InplaceBuff<T>& buff)
   -> decltype(buff.size) {
	return buff.size;
}

template <size_t N, class... Args,
          std::enable_if_t<(is_string_argument<Args> and ...), int> = 0>
InplaceBuff<N>& back_insert(InplaceBuff<N>& buff, Args&&... args) {
	buff.append(std::forward<Args>(args)...);
	return buff;
}
<commit_msg>inplace_buff.hh: made InplaceBuffBase usable from outside InplaceBuff<> and also fixed UB<commit_after>#pragma once

#include "concat_common.hh"
#include "string_view.hh"

class InplaceBuffBase {
public:
	size_t size = 0;

protected:
	size_t max_size_;
	char* p_;
	char* p_value_when_unallocated_;

public:
	/**
	 * @brief Changes buffer's size and max_size if needed, but in the latter
	 *   case all the data are lost
	 *
	 * @param n new buffer's size
	 */
	void lossy_resize(size_t n) {
		if (n > max_size_) {
			max_size_ = std::max(max_size_ << 1, n);
			deallocate();
			try {
				p_ = new char[max_size_];
			} catch (...) {
				p_ = (char*)&p_ + sizeof(p_);
				max_size_ = 0;
				throw;
			}
		}

		size = n;
	}

	/**
	 * @brief Changes buffer's size and max_size if needed, preserves data
	 *
	 * @param n new buffer's size
	 */
	constexpr void resize(size_t n) {
		if (n > max_size_) {
			size_t new_ms = std::max(max_size_ << 1, n);
			char* new_p = new char[new_ms];
			std::copy(p_, p_ + size, new_p);
			deallocate();

			p_ = new_p;
			max_size_ = new_ms;
		}

		size = n;
	}

	constexpr void clear() noexcept { size = 0; }

	constexpr char* begin() noexcept { return data(); }

	constexpr const char* begin() const noexcept { return data(); }

	constexpr char* end() noexcept { return data() + size; }

	constexpr const char* end() const noexcept { return data() + size; }

	constexpr const char* cbegin() const noexcept { return data(); }

	constexpr const char* cend() const noexcept { return data() + size; }

	constexpr char* data() noexcept { return p_; }

	constexpr const char* data() const noexcept { return p_; }

	constexpr size_t max_size() const noexcept { return max_size_; }

	constexpr char& front() noexcept { return (*this)[0]; }

	constexpr char front() const noexcept { return (*this)[0]; }

	constexpr char& back() noexcept { return (*this)[size - 1]; }

	constexpr char back() const noexcept { return (*this)[size - 1]; }

	constexpr char& operator[](size_t i) noexcept { return p_[i]; }

	constexpr char operator[](size_t i) const noexcept { return p_[i]; }

	constexpr operator StringView() const& noexcept { return {data(), size}; }

	// Do not allow to create StringView from a temporary object
	constexpr operator StringView() const&& = delete;

	// Do not allow to create StringBase<char> from a temporary object
	operator StringBase<char>() & noexcept { return {data(), size}; }

	operator StringBase<char>() && = delete;

	std::string to_string() const { return {data(), size}; }

	constexpr CStringView to_cstr() & {
		resize(size + 1);
		(*this)[--size] = '\0';
		return {data(), size};
	}

	// Do not allow to create CStringView of a temporary object
	constexpr CStringView to_cstr() && = delete;

protected:
	constexpr InplaceBuffBase(size_t s, size_t max_s, char* p,
	                          char* p_value_when_unallocated) noexcept
	   : size(s), max_size_(max_s), p_(p),
	     p_value_when_unallocated_(p_value_when_unallocated) {}

	constexpr InplaceBuffBase(const InplaceBuffBase&) noexcept = default;
	constexpr InplaceBuffBase(InplaceBuffBase&&) noexcept = default;
	InplaceBuffBase& operator=(const InplaceBuffBase&) noexcept = default;
	InplaceBuffBase& operator=(InplaceBuffBase&&) noexcept = default;

	bool is_allocated() const noexcept {
		return (p_ != p_value_when_unallocated_);
	}

	void deallocate() noexcept {
		if (is_allocated())
			delete[] p_;
	}

public:
	virtual ~InplaceBuffBase() { deallocate(); }

	template <class... Args,
	          std::enable_if_t<(is_string_argument<Args> and ...), int> = 0>
	constexpr InplaceBuffBase& append(Args&&... args) {
		[this](auto&&... str) {
			size_t k = size, final_len = (size + ... + string_length(str));
			resize(final_len);
			auto append_impl = [&](auto&& s) {
				auto sl = string_length(s);
				std::copy(::data(s), ::data(s) + sl, data() + k);
				k += sl;
			};
			(void)append_impl; // Fix GCC warning
			(append_impl(std::forward<decltype(str)>(str)), ...);
		}(stringify(std::forward<Args>(args))...);

		return *this;
	}
};

template <size_t N>
class InplaceBuff : public InplaceBuffBase {
private:
	std::array<char, N> a_;

	template <size_t M>
	friend class InplaceBuff;

	static_assert(N > 0, "Needed for accessing the array's 0-th element");

public:
	static constexpr size_t max_static_size = N;

	constexpr InplaceBuff() noexcept : InplaceBuffBase(0, N, nullptr, nullptr) {
		p_ = a_.data();
		p_value_when_unallocated_ = a_.data();
	}

	constexpr explicit InplaceBuff(size_t n)
	   : InplaceBuffBase(n, std::max(N, n), nullptr, nullptr) {
		p_ = (n <= N ? a_.data() : new char[n]);
		p_value_when_unallocated_ = a_.data();
	}

	constexpr InplaceBuff(const InplaceBuff& ibuff) : InplaceBuff(ibuff.size) {
		std::copy(ibuff.data(), ibuff.data() + ibuff.size, data());
	}

	InplaceBuff(InplaceBuff&& ibuff) noexcept
	   : InplaceBuffBase(ibuff.size, std::max(N, ibuff.max_size_), ibuff.p_,
	                     nullptr) {
		p_value_when_unallocated_ = a_.data();
		if (ibuff.is_allocated()) {
			p_ = ibuff.p_;
			ibuff.size = 0;
			ibuff.max_size_ = N;
			ibuff.p_ = ibuff.a_.data();

		} else {
			p_ = a_.data();
			std::copy(ibuff.data(), ibuff.data() + ibuff.size, p_);
			ibuff.size = 0;
		}
	}

	template <class T, std::enable_if_t<not std::is_integral_v<std::remove_cv_t<
	                                       std::remove_reference_t<T>>>,
	                                    int> = 0>
	constexpr explicit InplaceBuff(T&& str) : InplaceBuff(string_length(str)) {
		std::copy(::data(str), ::data(str) + size, p_);
	}

	// Used to unify constructors, as constructor taking one argument is
	// explicit
	template <class... Args,
	          std::enable_if_t<(is_string_argument<Args> and ...), int> = 0>
	constexpr InplaceBuff(std::in_place_t, Args&&... args) : InplaceBuff() {
		append(std::forward<Args>(args)...);
	}

	template <
	   class Arg1, class Arg2, class... Args,
	   std::enable_if_t<
	      not std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg1>>,
	                         std::in_place_t>,
	      int> = 0>
	constexpr InplaceBuff(Arg1&& arg1, Arg2&& arg2, Args&&... args)
	   : InplaceBuff(std::in_place, std::forward<Arg1>(arg1),
	                 std::forward<Arg2>(arg2), std::forward<Args>(args)...) {}

	template <size_t M, std::enable_if_t<M != N, int> = 0>
	constexpr InplaceBuff(const InplaceBuff<M>& ibuff)
	   : InplaceBuff(ibuff.size) {
		std::copy(ibuff.data(), ibuff.data() + ibuff.size, data());
	}

	template <size_t M, std::enable_if_t<M != N, int> = 0>
	InplaceBuff(InplaceBuff<M>&& ibuff) noexcept
	   : InplaceBuffBase(ibuff.size, N, ibuff.p_, nullptr) {
		p_value_when_unallocated_ = a_.data();
		if (ibuff.size <= N) {
			p_ = a_.data();
			// max_size_ = N;
			std::copy(ibuff.data(), ibuff.data() + ibuff.size, p_);
			// Deallocate ibuff memory
			if (ibuff.is_allocated())
				delete[] std::exchange(ibuff.p_, nullptr);

		} else if (ibuff.is_allocated()) {
			p_ = ibuff.p_; // Steal the allocated string
			max_size_ = ibuff.max_size_;
		} else {
			// N < ibuff.size <= M
			p_ = new char[ibuff.size];
			max_size_ = ibuff.size;
			std::copy(ibuff.data(), ibuff.data() + ibuff.size, p_);
		}

		// Take care of the ibuff's state
		ibuff.size = 0;
		ibuff.max_size_ = M;
		ibuff.p_ = ibuff.a_.data();
	}

	~InplaceBuff() { assert(p_value_when_unallocated_ == a_.data()); }

	constexpr InplaceBuff& operator=(const InplaceBuff& ibuff) {
		lossy_resize(ibuff.size);
		std::copy(ibuff.data(), ibuff.data() + ibuff.size, data());
		return *this;
	}

	constexpr InplaceBuff& operator=(InplaceBuff&& ibuff) noexcept {
		return assign_move_impl(std::move(ibuff));
	}

	template <class T>
	constexpr InplaceBuff& operator=(T&& str) {
		auto len = string_length(str);
		lossy_resize(len);
		std::copy(::data(str), ::data(str) + len, data());
		return *this;
	}

	template <size_t M, std::enable_if_t<M != N, int> = 0>
	constexpr InplaceBuff& operator=(const InplaceBuff<M>& ibuff) {
		lossy_resize(ibuff.size);
		std::copy(ibuff.data(), ibuff.data() + ibuff.size, data());
		return *this;
	}

	template <size_t M, std::enable_if_t<M != N, int> = 0>
	constexpr InplaceBuff& operator=(InplaceBuff<M>&& ibuff) noexcept {
		return assign_move_impl(std::move(ibuff));
	}

private:
	template <size_t M>
	InplaceBuff& assign_move_impl(InplaceBuff<M>&& ibuff) {
		if (ibuff.is_allocated() and ibuff.max_size() >= max_size()) {
			// Steal the allocated string
			if (is_allocated())
				delete[] p_;

			p_ = ibuff.p_;
			size = ibuff.size;
			max_size_ = ibuff.max_size_;

		} else {
			*this = ibuff; // Copy data
			if (ibuff.is_allocated())
				delete[] ibuff.p_;
		}

		// Take care of the ibuff's state
		ibuff.p_ = ibuff.a_.data();
		ibuff.size = 0;
		ibuff.max_size_ = M;

		return *this;
	}
};

template <size_t N>
std::string& operator+=(std::string& str, const InplaceBuff<N>& ibs) {
	return str.append(ibs.data(), ibs.size);
}

// This function allows @p str to be converted to StringView, but
// keep in mind that if any StringView or alike value generated from the result
// of this function cannot be saved to a variable! -- it would (and probably
// will) cause use-after-free error, because @p str will be already deleted when
// the initialization is done
template <size_t N>
constexpr StringView
intentional_unsafe_string_view(const InplaceBuff<N>&& str) noexcept {
	return StringView(static_cast<const InplaceBuff<N>&>(str));
}

// This function allows @p str to be converted to CStringView, but
// keep in mind that if any StringView or alike value generated from the result
// of this function cannot be saved to a variable! -- it would (and probably
// will) cause use-after-free error, because @p str will be already deleted when
// the initialization is done
template <size_t N>
constexpr CStringView
intentional_unsafe_cstring_view(InplaceBuff<N>&& str) noexcept {
	return static_cast<InplaceBuff<N>&>(str).to_cstr();
}

template <size_t T>
constexpr auto string_length(const InplaceBuff<T>& buff)
   -> decltype(buff.size) {
	return buff.size;
}

template <size_t N, class... Args,
          std::enable_if_t<(is_string_argument<Args> and ...), int> = 0>
InplaceBuff<N>& back_insert(InplaceBuff<N>& buff, Args&&... args) {
	buff.append(std::forward<Args>(args)...);
	return buff;
}
<|endoftext|>